summaryrefslogtreecommitdiffstats
path: root/addons/ot/src/scope.c
diff options
context:
space:
mode:
Diffstat (limited to 'addons/ot/src/scope.c')
-rw-r--r--addons/ot/src/scope.c634
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
+ */