diff options
Diffstat (limited to 'addons/ot/src/scope.c')
-rw-r--r-- | addons/ot/src/scope.c | 634 |
1 files changed, 634 insertions, 0 deletions
diff --git a/addons/ot/src/scope.c b/addons/ot/src/scope.c new file mode 100644 index 0000000..efe8fe2 --- /dev/null +++ b/addons/ot/src/scope.c @@ -0,0 +1,634 @@ +/*** + * Copyright 2020 HAProxy Technologies + * + * This file is part of the HAProxy OpenTracing filter. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "include.h" + + +static struct pool_head *pool_head_ot_scope_span __read_mostly = NULL; +static struct pool_head *pool_head_ot_scope_context __read_mostly = NULL; +static struct pool_head *pool_head_ot_runtime_context __read_mostly = NULL; + +#ifdef USE_POOL_OT_SCOPE_SPAN +REGISTER_POOL(&pool_head_ot_scope_span, "ot_scope_span", sizeof(struct flt_ot_scope_span)); +#endif +#ifdef USE_POOL_OT_SCOPE_CONTEXT +REGISTER_POOL(&pool_head_ot_scope_context, "ot_scope_context", sizeof(struct flt_ot_scope_context)); +#endif +#ifdef USE_POOL_OT_RUNTIME_CONTEXT +REGISTER_POOL(&pool_head_ot_runtime_context, "ot_runtime_context", sizeof(struct flt_ot_runtime_context)); +#endif + + +#ifdef DEBUG_OT + +/*** + * NAME + * flt_ot_pools_info - + * + * ARGUMENTS + * This function takes no arguments. + * + * DESCRIPTION + * - + * + * RETURN VALUE + * This function does not return a value. + */ +void flt_ot_pools_info(void) +{ + /* + * In case we have some error in the configuration file, + * it is possible that this pool was not initialized. + */ +#ifdef USE_POOL_BUFFER + FLT_OT_DBG(2, "sizeof_pool(buffer) = %u", FLT_OT_DEREF(pool_head_buffer, size, 0)); +#endif +#ifdef USE_TRASH_CHUNK + FLT_OT_DBG(2, "sizeof_pool(trash) = %u", FLT_OT_DEREF(pool_head_trash, size, 0)); +#endif + +#ifdef USE_POOL_OT_SCOPE_SPAN + FLT_OT_DBG(2, "sizeof_pool(ot_scope_span) = %u", pool_head_ot_scope_span->size); +#endif +#ifdef USE_POOL_OT_SCOPE_CONTEXT + FLT_OT_DBG(2, "sizeof_pool(ot_scope_context) = %u", pool_head_ot_scope_context->size); +#endif +#ifdef USE_POOL_OT_RUNTIME_CONTEXT + FLT_OT_DBG(2, "sizeof_pool(ot_runtime_context) = %u", pool_head_ot_runtime_context->size); +#endif +} + +#endif /* DEBUG_OT */ + + +/*** + * NAME + * flt_ot_runtime_context_init - + * + * ARGUMENTS + * s - + * f - + * err - + * + * DESCRIPTION + * - + * + * RETURN VALUE + * - + */ +struct flt_ot_runtime_context *flt_ot_runtime_context_init(struct stream *s, struct filter *f, char **err) +{ + const struct flt_ot_conf *conf = FLT_OT_CONF(f); + struct buffer uuid; + struct flt_ot_runtime_context *retptr = NULL; + + FLT_OT_FUNC("%p, %p, %p:%p", s, f, FLT_OT_DPTR_ARGS(err)); + + retptr = flt_ot_pool_alloc(pool_head_ot_runtime_context, sizeof(*retptr), 1, err); + if (retptr == NULL) + FLT_OT_RETURN_PTR(retptr); + + retptr->stream = s; + retptr->filter = f; + retptr->flag_harderr = conf->tracer->flag_harderr; + retptr->flag_disabled = conf->tracer->flag_disabled; + retptr->logging = conf->tracer->logging; + LIST_INIT(&(retptr->spans)); + LIST_INIT(&(retptr->contexts)); + + uuid = b_make(retptr->uuid, sizeof(retptr->uuid), 0, 0); + ha_generate_uuid(&uuid); + +#ifdef USE_OT_VARS + /* + * The HAProxy variable 'sess.ot.uuid' is registered here, + * after which its value is set to runtime context UUID. + */ + if (flt_ot_var_register(FLT_OT_VAR_UUID, err) != -1) + (void)flt_ot_var_set(s, FLT_OT_VAR_UUID, retptr->uuid, SMP_OPT_DIR_REQ, err); +#endif + + FLT_OT_DBG_RUNTIME_CONTEXT("session context: ", retptr); + + FLT_OT_RETURN_PTR(retptr); +} + + +/*** + * NAME + * flt_ot_runtime_context_free - + * + * ARGUMENTS + * f - + * + * DESCRIPTION + * - + * + * RETURN VALUE + * This function does not return a value. + */ +void flt_ot_runtime_context_free(struct filter *f) +{ + struct flt_ot_runtime_context *rt_ctx = f->ctx; + + FLT_OT_FUNC("%p", f); + + if (rt_ctx == NULL) + FLT_OT_RETURN(); + + FLT_OT_DBG_RUNTIME_CONTEXT("session context: ", rt_ctx); + + if (!LIST_ISEMPTY(&(rt_ctx->spans))) { + struct timespec ts; + struct flt_ot_scope_span *span, *span_back; + + /* All spans should be completed at the same time. */ + (void)clock_gettime(CLOCK_MONOTONIC, &ts); + + list_for_each_entry_safe(span, span_back, &(rt_ctx->spans), list) { + ot_span_finish(&(span->span), &ts, NULL, NULL, NULL); + flt_ot_scope_span_free(&span); + } + } + + if (!LIST_ISEMPTY(&(rt_ctx->contexts))) { + struct flt_ot_scope_context *ctx, *ctx_back; + + list_for_each_entry_safe(ctx, ctx_back, &(rt_ctx->contexts), list) + flt_ot_scope_context_free(&ctx); + } + + flt_ot_pool_free(pool_head_ot_runtime_context, &(f->ctx)); + + FLT_OT_RETURN(); +} + + +/*** + * NAME + * flt_ot_scope_span_init - + * + * ARGUMENTS + * rt_ctx - + * id - + * id_len - + * ref_type - + * ref_id - + * ref_id_len - + * dir - + * err - + * + * DESCRIPTION + * - + * + * RETURN VALUE + * - + */ +struct flt_ot_scope_span *flt_ot_scope_span_init(struct flt_ot_runtime_context *rt_ctx, const char *id, size_t id_len, otc_span_reference_type_t ref_type, const char *ref_id, size_t ref_id_len, uint dir, char **err) +{ + struct otc_span *ref_span = NULL; + struct otc_span_context *ref_ctx = NULL; + struct flt_ot_scope_span *span, *retptr = NULL; + struct flt_ot_scope_context *ctx; + + FLT_OT_FUNC("%p, \"%s\", %zu, %d, \"%s\", %zu, %u, %p:%p", rt_ctx, id, id_len, ref_type, ref_id, ref_id_len, dir, FLT_OT_DPTR_ARGS(err)); + + if ((rt_ctx == NULL) || (id == NULL)) + FLT_OT_RETURN_PTR(retptr); + + list_for_each_entry(span, &(rt_ctx->spans), list) + if ((span->id_len == id_len) && (memcmp(span->id, id, id_len) == 0)) { + FLT_OT_DBG(2, "found span %p", span); + + FLT_OT_RETURN_PTR(span); + } + + if (ref_id != NULL) { + list_for_each_entry(span, &(rt_ctx->spans), list) + if ((span->id_len == ref_id_len) && (memcmp(span->id, ref_id, ref_id_len) == 0)) { + ref_span = span->span; + + break; + } + + if (ref_span != NULL) { + FLT_OT_DBG(2, "found referenced span %p", span); + } else { + list_for_each_entry(ctx, &(rt_ctx->contexts), list) + if ((ctx->id_len == ref_id_len) && (memcmp(ctx->id, ref_id, ref_id_len) == 0)) { + ref_ctx = ctx->context; + + break; + } + + if (ref_ctx != NULL) { + FLT_OT_DBG(2, "found referenced context %p", ctx); + } else { + FLT_OT_ERR("cannot find referenced span/context '%s'", ref_id); + + FLT_OT_RETURN_PTR(retptr); + } + } + } + + retptr = flt_ot_pool_alloc(pool_head_ot_scope_span, sizeof(*retptr), 1, err); + if (retptr == NULL) + FLT_OT_RETURN_PTR(retptr); + + retptr->id = id; + retptr->id_len = id_len; + retptr->smp_opt_dir = dir; + retptr->ref_type = ref_type; + retptr->ref_span = ref_span; + retptr->ref_ctx = ref_ctx; + LIST_INSERT(&(rt_ctx->spans), &(retptr->list)); + + FLT_OT_DBG_SCOPE_SPAN("new span ", retptr); + + FLT_OT_RETURN_PTR(retptr); +} + + +/*** + * NAME + * flt_ot_scope_span_free - + * + * ARGUMENTS + * ptr - + * + * DESCRIPTION + * - + * + * RETURN VALUE + * This function does not return a value. + */ +void flt_ot_scope_span_free(struct flt_ot_scope_span **ptr) +{ + FLT_OT_FUNC("%p:%p", FLT_OT_DPTR_ARGS(ptr)); + + if ((ptr == NULL) || (*ptr == NULL)) + FLT_OT_RETURN(); + + FLT_OT_DBG_SCOPE_SPAN("", *ptr); + + /* If the span is still active, do nothing. */ + if ((*ptr)->span != NULL) { + FLT_OT_DBG(2, "cannot finish active span"); + + FLT_OT_RETURN(); + } + + FLT_OT_LIST_DEL(&((*ptr)->list)); + flt_ot_pool_free(pool_head_ot_scope_span, (void **)ptr); + + FLT_OT_RETURN(); +} + + +/*** + * NAME + * flt_ot_scope_context_init - + * + * ARGUMENTS + * rt_ctx - + * tracer - + * id - + * id_len - + * text_map - + * dir - + * err - + * + * DESCRIPTION + * - + * + * RETURN VALUE + * - + */ +struct flt_ot_scope_context *flt_ot_scope_context_init(struct flt_ot_runtime_context *rt_ctx, struct otc_tracer *tracer, const char *id, size_t id_len, const struct otc_text_map *text_map, uint dir, char **err) +{ + struct otc_http_headers_reader reader; + struct otc_span_context *span_ctx; + struct flt_ot_scope_context *retptr = NULL; + + FLT_OT_FUNC("%p, %p, \"%s\", %zu, %p, %u, %p:%p", rt_ctx, tracer, id, id_len, text_map, dir, FLT_OT_DPTR_ARGS(err)); + + if ((rt_ctx == NULL) || (tracer == NULL) || (id == NULL) || (text_map == NULL)) + FLT_OT_RETURN_PTR(retptr); + + list_for_each_entry(retptr, &(rt_ctx->contexts), list) + if ((retptr->id_len == id_len) && (memcmp(retptr->id, id, id_len) == 0)) { + FLT_OT_DBG(2, "found context %p", retptr); + + FLT_OT_RETURN_PTR(retptr); + } + + retptr = flt_ot_pool_alloc(pool_head_ot_scope_context, sizeof(*retptr), 1, err); + if (retptr == NULL) + FLT_OT_RETURN_PTR(retptr); + + span_ctx = ot_extract_http_headers(tracer, &reader, text_map, err); + if (span_ctx == NULL) { + flt_ot_scope_context_free(&retptr); + + FLT_OT_RETURN_PTR(retptr); + } + + retptr->id = id; + retptr->id_len = id_len; + retptr->smp_opt_dir = dir; + retptr->context = span_ctx; + LIST_INSERT(&(rt_ctx->contexts), &(retptr->list)); + + FLT_OT_DBG_SCOPE_CONTEXT("new context ", retptr); + + FLT_OT_RETURN_PTR(retptr); +} + + +/*** + * NAME + * flt_ot_scope_context_free - + * + * ARGUMENTS + * ptr - + * + * DESCRIPTION + * - + * + * RETURN VALUE + * This function does not return a value. + */ +void flt_ot_scope_context_free(struct flt_ot_scope_context **ptr) +{ + FLT_OT_FUNC("%p:%p", FLT_OT_DPTR_ARGS(ptr)); + + if ((ptr == NULL) || (*ptr == NULL)) + FLT_OT_RETURN(); + + FLT_OT_DBG_SCOPE_CONTEXT("", *ptr); + + if ((*ptr)->context != NULL) + (*ptr)->context->destroy(&((*ptr)->context)); + + FLT_OT_LIST_DEL(&((*ptr)->list)); + flt_ot_pool_free(pool_head_ot_scope_context, (void **)ptr); + + FLT_OT_RETURN(); +} + + +/*** + * NAME + * flt_ot_scope_data_free - + * + * ARGUMENTS + * ptr - + * + * DESCRIPTION + * - + * + * RETURN VALUE + * This function does not return a value. + */ +void flt_ot_scope_data_free(struct flt_ot_scope_data *ptr) +{ + int i; + + FLT_OT_FUNC("%p", ptr); + + if (ptr == NULL) + FLT_OT_RETURN(); + + FLT_OT_DBG_SCOPE_DATA("", ptr); + + for (i = 0; i < ptr->num_tags; i++) + if (ptr->tags[i].value.type == otc_value_string) + FLT_OT_FREE_VOID(ptr->tags[i].value.value.string_value); + otc_text_map_destroy(&(ptr->baggage), OTC_TEXT_MAP_FREE_VALUE); + for (i = 0; i < ptr->num_log_fields; i++) + if (ptr->log_fields[i].value.type == otc_value_string) + FLT_OT_FREE_VOID(ptr->log_fields[i].value.value.string_value); + + (void)memset(ptr, 0, sizeof(*ptr)); + + FLT_OT_RETURN(); +} + + +/*** + * NAME + * flt_ot_scope_finish_mark - + * + * ARGUMENTS + * rt_ctx - + * id - + * id_len - + * + * DESCRIPTION + * - + * + * RETURN VALUE + * - + */ +int flt_ot_scope_finish_mark(const struct flt_ot_runtime_context *rt_ctx, const char *id, size_t id_len) +{ + struct flt_ot_scope_span *span; + struct flt_ot_scope_context *ctx; + int span_cnt = 0, ctx_cnt = 0, retval; + + FLT_OT_FUNC("%p, \"%s\", %zu", rt_ctx, id, id_len); + + if (FLT_OT_STR_CMP(FLT_OT_SCOPE_SPAN_FINISH_ALL, id, id_len)) { + list_for_each_entry(span, &(rt_ctx->spans), list) { + span->flag_finish = 1; + span_cnt++; + } + + list_for_each_entry(ctx, &(rt_ctx->contexts), list) { + ctx->flag_finish = 1; + ctx_cnt++; + } + + FLT_OT_DBG(2, "marked %d span(s), %d context(s)", span_cnt, ctx_cnt); + } + else if (FLT_OT_STR_CMP(FLT_OT_SCOPE_SPAN_FINISH_REQ, id, id_len)) { + list_for_each_entry(span, &(rt_ctx->spans), list) + if (span->smp_opt_dir == SMP_OPT_DIR_REQ) { + span->flag_finish = 1; + span_cnt++; + } + + list_for_each_entry(ctx, &(rt_ctx->contexts), list) + if (ctx->smp_opt_dir == SMP_OPT_DIR_REQ) { + ctx->flag_finish = 1; + span_cnt++; + } + + FLT_OT_DBG(2, "marked REQuest channel %d span(s), %d context(s)", span_cnt, ctx_cnt); + } + else if (FLT_OT_STR_CMP(FLT_OT_SCOPE_SPAN_FINISH_RES, id, id_len)) { + list_for_each_entry(span, &(rt_ctx->spans), list) + if (span->smp_opt_dir == SMP_OPT_DIR_RES) { + span->flag_finish = 1; + span_cnt++; + } + + list_for_each_entry(ctx, &(rt_ctx->contexts), list) + if (ctx->smp_opt_dir == SMP_OPT_DIR_RES) { + ctx->flag_finish = 1; + ctx_cnt++; + } + + FLT_OT_DBG(2, "marked RESponse channel %d span(s), %d context(s)", span_cnt, ctx_cnt); + } + else { + list_for_each_entry(span, &(rt_ctx->spans), list) + if ((span->id_len == id_len) && (memcmp(span->id, id, id_len) == 0)) { + span->flag_finish = 1; + span_cnt++; + + break; + } + + list_for_each_entry(ctx, &(rt_ctx->contexts), list) + if ((ctx->id_len == id_len) && (memcmp(ctx->id, id, id_len) == 0)) { + ctx->flag_finish = 1; + ctx_cnt++; + + break; + } + + if (span_cnt > 0) + FLT_OT_DBG(2, "marked span '%s'", id); + if (ctx_cnt > 0) + FLT_OT_DBG(2, "marked context '%s'", id); + if ((span_cnt + ctx_cnt) == 0) + FLT_OT_DBG(2, "cannot find span/context '%s'", id); + } + + retval = span_cnt + ctx_cnt; + + FLT_OT_RETURN_INT(retval); +} + + +/*** + * NAME + * flt_ot_scope_finish_marked - + * + * ARGUMENTS + * rt_ctx - + * ts_finish - + * + * DESCRIPTION + * Finish marked spans. + * + * RETURN VALUE + * This function does not return a value. + */ +void flt_ot_scope_finish_marked(const struct flt_ot_runtime_context *rt_ctx, const struct timespec *ts_finish) +{ + struct flt_ot_scope_span *span; + struct flt_ot_scope_context *ctx; + + FLT_OT_FUNC("%p, %p", rt_ctx, ts_finish); + + list_for_each_entry(span, &(rt_ctx->spans), list) + if (span->flag_finish) { + FLT_OT_DBG_SCOPE_SPAN("finishing span ", span); + + ot_span_finish(&(span->span), ts_finish, NULL, NULL, NULL); + + span->flag_finish = 0; + } + + list_for_each_entry(ctx, &(rt_ctx->contexts), list) + if (ctx->flag_finish) { + FLT_OT_DBG_SCOPE_CONTEXT("finishing context ", ctx); + + if (ctx->context != NULL) + ctx->context->destroy(&(ctx->context)); + + ctx->flag_finish = 0; + } + + FLT_OT_RETURN(); +} + + +/*** + * NAME + * flt_ot_scope_free_unused - + * + * ARGUMENTS + * rt_ctx - + * chn - + * + * DESCRIPTION + * - + * + * RETURN VALUE + * This function does not return a value. + */ +void flt_ot_scope_free_unused(struct flt_ot_runtime_context *rt_ctx, struct channel *chn) +{ + FLT_OT_FUNC("%p", rt_ctx); + + if (rt_ctx == NULL) + FLT_OT_RETURN(); + + if (!LIST_ISEMPTY(&(rt_ctx->spans))) { + struct flt_ot_scope_span *span, *span_back; + + list_for_each_entry_safe(span, span_back, &(rt_ctx->spans), list) + if (span->span == NULL) + flt_ot_scope_span_free(&span); + } + + if (!LIST_ISEMPTY(&(rt_ctx->contexts))) { + struct flt_ot_scope_context *ctx, *ctx_back; + + list_for_each_entry_safe(ctx, ctx_back, &(rt_ctx->contexts), list) + if (ctx->context == NULL) { + /* + * All headers and variables associated with + * the context in question should be deleted. + */ + (void)flt_ot_http_headers_remove(chn, ctx->id, NULL); +#ifdef USE_OT_VARS + (void)flt_ot_vars_unset(rt_ctx->stream, FLT_OT_VARS_SCOPE, ctx->id, ctx->smp_opt_dir, NULL); +#endif + + flt_ot_scope_context_free(&ctx); + } + } + + FLT_OT_DBG_RUNTIME_CONTEXT("session context: ", rt_ctx); + + FLT_OT_RETURN(); +} + +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * End: + * + * vi: noexpandtab shiftwidth=8 tabstop=8 + */ |