blob: ec5e81f8f901163957d08921bd1c34cbcc134ef8 [file] [log] [blame]
/***
* 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 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->uuid.u64[0] = ha_random64();
retptr->uuid.u64[1] = ha_random64();
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));
(void)snprintf(retptr->uuid.s, sizeof(retptr->uuid.s), "%08x-%04hx-%04hx-%04hx-%012" PRIx64,
retptr->uuid.time_low,
retptr->uuid.time_mid,
(uint16_t)((retptr->uuid.time_hi_and_version & UINT16_C(0xfff)) | UINT16_C(0x4000)),
(uint16_t)(retptr->uuid.clock_seq | UINT16_C(0x8000)),
(uint64_t)retptr->uuid.node);
if (flt_ot_var_register(FTL_OT_VAR_UUID, err) != -1)
(void)flt_ot_var_set(s, FTL_OT_VAR_UUID, retptr->uuid.s, SMP_OPT_DIR_REQ, err);
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);
(void)flt_ot_vars_unset(rt_ctx->stream, FLT_OT_VARS_SCOPE, ctx->id, ctx->smp_opt_dir, NULL);
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
*/