blob: 462c86577d41437ec164b3b824c4454e3ff72a44 [file] [log] [blame]
Miroslav Zagorac70230c62020-12-09 16:54:31 +01001/***
2 * Copyright 2020 HAProxy Technologies
3 *
4 * This file is part of the HAProxy OpenTracing filter.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
20#include "include.h"
21
22
23static struct pool_head *pool_head_ot_scope_span = NULL;
24static struct pool_head *pool_head_ot_scope_context = NULL;
25static struct pool_head *pool_head_ot_runtime_context = NULL;
26
27#ifdef USE_POOL_OT_SCOPE_SPAN
28REGISTER_POOL(&pool_head_ot_scope_span, "ot_scope_span", sizeof(struct flt_ot_scope_span));
29#endif
30#ifdef USE_POOL_OT_SCOPE_CONTEXT
31REGISTER_POOL(&pool_head_ot_scope_context, "ot_scope_context", sizeof(struct flt_ot_scope_context));
32#endif
33#ifdef USE_POOL_OT_RUNTIME_CONTEXT
34REGISTER_POOL(&pool_head_ot_runtime_context, "ot_runtime_context", sizeof(struct flt_ot_runtime_context));
35#endif
36
37
38#ifdef DEBUG_OT
39
40/***
41 * NAME
42 * flt_ot_pools_info -
43 *
44 * ARGUMENTS
45 * This function takes no arguments.
46 *
47 * DESCRIPTION
48 * -
49 *
50 * RETURN VALUE
51 * This function does not return a value.
52 */
53void flt_ot_pools_info(void)
54{
55 /*
56 * In case we have some error in the configuration file,
57 * it is possible that this pool was not initialized.
58 */
59#ifdef USE_POOL_BUFFER
60 FLT_OT_DBG(2, "sizeof_pool(buffer) = %u", FLT_OT_DEREF(pool_head_buffer, size, 0));
61#endif
62#ifdef USE_TRASH_CHUNK
63 FLT_OT_DBG(2, "sizeof_pool(trash) = %u", FLT_OT_DEREF(pool_head_trash, size, 0));
64#endif
65
66#ifdef USE_POOL_OT_SCOPE_SPAN
67 FLT_OT_DBG(2, "sizeof_pool(ot_scope_span) = %u", pool_head_ot_scope_span->size);
68#endif
69#ifdef USE_POOL_OT_SCOPE_CONTEXT
70 FLT_OT_DBG(2, "sizeof_pool(ot_scope_context) = %u", pool_head_ot_scope_context->size);
71#endif
72#ifdef USE_POOL_OT_RUNTIME_CONTEXT
73 FLT_OT_DBG(2, "sizeof_pool(ot_runtime_context) = %u", pool_head_ot_runtime_context->size);
74#endif
75}
76
77#endif /* DEBUG_OT */
78
79
80/***
81 * NAME
82 * flt_ot_runtime_context_init -
83 *
84 * ARGUMENTS
85 * s -
86 * f -
87 * err -
88 *
89 * DESCRIPTION
90 * -
91 *
92 * RETURN VALUE
93 * -
94 */
95struct flt_ot_runtime_context *flt_ot_runtime_context_init(struct stream *s, struct filter *f, char **err)
96{
97 const struct flt_ot_conf *conf = FLT_OT_CONF(f);
98 struct flt_ot_runtime_context *retptr = NULL;
99
100 FLT_OT_FUNC("%p, %p, %p:%p", s, f, FLT_OT_DPTR_ARGS(err));
101
102 retptr = flt_ot_pool_alloc(pool_head_ot_runtime_context, sizeof(*retptr), 1, err);
103 if (retptr == NULL)
104 FLT_OT_RETURN(retptr);
105
106 retptr->stream = s;
107 retptr->filter = f;
108 retptr->uuid.u64[0] = ha_random64();
109 retptr->uuid.u64[1] = ha_random64();
110 retptr->flag_harderr = conf->tracer->flag_harderr;
111 retptr->flag_disabled = conf->tracer->flag_disabled;
112 retptr->logging = conf->tracer->logging;
113 LIST_INIT(&(retptr->spans));
114 LIST_INIT(&(retptr->contexts));
115
116 (void)snprintf(retptr->uuid.s, sizeof(retptr->uuid.s), "%08x-%04hx-%04hx-%04hx-%012" PRIx64,
117 retptr->uuid.time_low,
118 retptr->uuid.time_mid,
119 (retptr->uuid.time_hi_and_version & UINT16_C(0xfff)) | UINT16_C(0x4000),
120 retptr->uuid.clock_seq | UINT16_C(0x8000),
121 (uint64_t)retptr->uuid.node);
122
123 if (flt_ot_var_register(FTL_OT_VAR_UUID, err) != -1)
124 (void)flt_ot_var_set(s, FTL_OT_VAR_UUID, retptr->uuid.s, SMP_OPT_DIR_REQ, err);
125
126 FLT_OT_DBG_RUNTIME_CONTEXT("session context: ", retptr);
127
128 FLT_OT_RETURN(retptr);
129}
130
131
132/***
133 * NAME
134 * flt_ot_runtime_context_free -
135 *
136 * ARGUMENTS
137 * f -
138 *
139 * DESCRIPTION
140 * -
141 *
142 * RETURN VALUE
143 * This function does not return a value.
144 */
145void flt_ot_runtime_context_free(struct filter *f)
146{
147 struct flt_ot_runtime_context *rt_ctx = f->ctx;
148
149 FLT_OT_FUNC("%p", f);
150
151 if (rt_ctx == NULL)
152 FLT_OT_RETURN();
153
154 FLT_OT_DBG_RUNTIME_CONTEXT("session context: ", rt_ctx);
155
156 if (!LIST_ISEMPTY(&(rt_ctx->spans))) {
157 struct timespec ts;
158 struct flt_ot_scope_span *span, *span_back;
159
160 /* All spans should be completed at the same time. */
161 (void)clock_gettime(CLOCK_MONOTONIC, &ts);
162
163 list_for_each_entry_safe(span, span_back, &(rt_ctx->spans), list) {
164 ot_span_finish(&(span->span), &ts, NULL, NULL, NULL);
165 flt_ot_scope_span_free(&span);
166 }
167 }
168
169 if (!LIST_ISEMPTY(&(rt_ctx->contexts))) {
170 struct flt_ot_scope_context *ctx, *ctx_back;
171
172 list_for_each_entry_safe(ctx, ctx_back, &(rt_ctx->contexts), list)
173 flt_ot_scope_context_free(&ctx);
174 }
175
176 flt_ot_pool_free(pool_head_ot_runtime_context, &(f->ctx));
177
178 FLT_OT_RETURN();
179}
180
181
182/***
183 * NAME
184 * flt_ot_scope_span_init -
185 *
186 * ARGUMENTS
187 * rt_ctx -
188 * id -
189 * id_len -
190 * ref_type -
191 * ref_id -
192 * ref_id_len -
193 * dir -
194 * err -
195 *
196 * DESCRIPTION
197 * -
198 *
199 * RETURN VALUE
200 * -
201 */
202struct 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)
203{
204 struct otc_span *ref_span = NULL;
205 struct otc_span_context *ref_ctx = NULL;
206 struct flt_ot_scope_span *span, *retptr = NULL;
207 struct flt_ot_scope_context *ctx;
208
209 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));
210
211 if ((rt_ctx == NULL) || (id == NULL))
212 FLT_OT_RETURN(retptr);
213
214 list_for_each_entry(span, &(rt_ctx->spans), list)
215 if ((span->id_len == id_len) && (memcmp(span->id, id, id_len) == 0)) {
216 FLT_OT_DBG(2, "found span %p", span);
217
218 FLT_OT_RETURN(span);
219 }
220
221 if (ref_id != NULL) {
222 list_for_each_entry(span, &(rt_ctx->spans), list)
223 if ((span->id_len == ref_id_len) && (memcmp(span->id, ref_id, ref_id_len) == 0)) {
224 ref_span = span->span;
225
226 break;
227 }
228
229 if (ref_span != NULL) {
230 FLT_OT_DBG(2, "found referenced span %p", span);
231 } else {
232 list_for_each_entry(ctx, &(rt_ctx->contexts), list)
233 if ((ctx->id_len == ref_id_len) && (memcmp(ctx->id, ref_id, ref_id_len) == 0)) {
234 ref_ctx = ctx->context;
235
236 break;
237 }
238
239 if (ref_ctx != NULL) {
240 FLT_OT_DBG(2, "found referenced context %p", ctx);
241 } else {
242 FLT_OT_ERR("cannot find referenced span/context '%s'", ref_id);
243
244 FLT_OT_RETURN(retptr);
245 }
246 }
247 }
248
249 retptr = flt_ot_pool_alloc(pool_head_ot_scope_span, sizeof(*retptr), 1, err);
250 if (retptr == NULL)
251 FLT_OT_RETURN(retptr);
252
253 retptr->id = id;
254 retptr->id_len = id_len;
255 retptr->smp_opt_dir = dir;
256 retptr->ref_type = ref_type;
257 retptr->ref_span = ref_span;
258 retptr->ref_ctx = ref_ctx;
259 LIST_ADD(&(rt_ctx->spans), &(retptr->list));
260
261 FLT_OT_DBG_SCOPE_SPAN("new span ", retptr);
262
263 FLT_OT_RETURN(retptr);
264}
265
266
267/***
268 * NAME
269 * flt_ot_scope_span_free -
270 *
271 * ARGUMENTS
272 * ptr -
273 *
274 * DESCRIPTION
275 * -
276 *
277 * RETURN VALUE
278 * This function does not return a value.
279 */
280void flt_ot_scope_span_free(struct flt_ot_scope_span **ptr)
281{
282 FLT_OT_FUNC("%p:%p", FLT_OT_DPTR_ARGS(ptr));
283
284 if ((ptr == NULL) || (*ptr == NULL))
285 FLT_OT_RETURN();
286
287 FLT_OT_DBG_SCOPE_SPAN("", *ptr);
288
289 /* If the span is still active, do nothing. */
290 if ((*ptr)->span != NULL) {
291 FLT_OT_DBG(2, "cannot finish active span");
292
293 FLT_OT_RETURN();
294 }
295
296 FLT_OT_LIST_DEL(&((*ptr)->list));
297 flt_ot_pool_free(pool_head_ot_scope_span, (void **)ptr);
298
299 FLT_OT_RETURN();
300}
301
302
303/***
304 * NAME
305 * flt_ot_scope_context_init -
306 *
307 * ARGUMENTS
308 * rt_ctx -
309 * tracer -
310 * id -
311 * id_len -
312 * text_map -
313 * dir -
314 * err -
315 *
316 * DESCRIPTION
317 * -
318 *
319 * RETURN VALUE
320 * -
321 */
322struct 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)
323{
324 struct otc_http_headers_reader reader;
325 struct otc_span_context *span_ctx;
326 struct flt_ot_scope_context *retptr = NULL;
327
328 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));
329
330 if ((rt_ctx == NULL) || (tracer == NULL) || (id == NULL) || (text_map == NULL))
331 FLT_OT_RETURN(retptr);
332
333 list_for_each_entry(retptr, &(rt_ctx->contexts), list)
334 if ((retptr->id_len == id_len) && (memcmp(retptr->id, id, id_len) == 0)) {
335 FLT_OT_DBG(2, "found context %p", retptr);
336
337 FLT_OT_RETURN(retptr);
338 }
339
340 retptr = flt_ot_pool_alloc(pool_head_ot_scope_context, sizeof(*retptr), 1, err);
341 if (retptr == NULL)
342 FLT_OT_RETURN(retptr);
343
344 span_ctx = ot_extract_http_headers(tracer, &reader, text_map, err);
345 if (span_ctx == NULL) {
346 flt_ot_scope_context_free(&retptr);
347
348 FLT_OT_RETURN(retptr);
349 }
350
351 retptr->id = id;
352 retptr->id_len = id_len;
353 retptr->smp_opt_dir = dir;
354 retptr->context = span_ctx;
355 LIST_ADD(&(rt_ctx->contexts), &(retptr->list));
356
357 FLT_OT_DBG_SCOPE_CONTEXT("new context ", retptr);
358
359 FLT_OT_RETURN(retptr);
360}
361
362
363/***
364 * NAME
365 * flt_ot_scope_context_free -
366 *
367 * ARGUMENTS
368 * ptr -
369 *
370 * DESCRIPTION
371 * -
372 *
373 * RETURN VALUE
374 * This function does not return a value.
375 */
376void flt_ot_scope_context_free(struct flt_ot_scope_context **ptr)
377{
378 FLT_OT_FUNC("%p:%p", FLT_OT_DPTR_ARGS(ptr));
379
380 if ((ptr == NULL) || (*ptr == NULL))
381 FLT_OT_RETURN();
382
383 FLT_OT_DBG_SCOPE_CONTEXT("", *ptr);
384
385 if ((*ptr)->context != NULL)
386 (*ptr)->context->destroy(&((*ptr)->context));
387
388 FLT_OT_LIST_DEL(&((*ptr)->list));
389 flt_ot_pool_free(pool_head_ot_scope_context, (void **)ptr);
390
391 FLT_OT_RETURN();
392}
393
394
395/***
396 * NAME
397 * flt_ot_scope_data_free -
398 *
399 * ARGUMENTS
400 * ptr -
401 *
402 * DESCRIPTION
403 * -
404 *
405 * RETURN VALUE
406 * This function does not return a value.
407 */
408void flt_ot_scope_data_free(struct flt_ot_scope_data *ptr)
409{
410 int i;
411
412 FLT_OT_FUNC("%p", ptr);
413
414 if (ptr == NULL)
415 FLT_OT_RETURN();
416
417 FLT_OT_DBG_SCOPE_DATA("", ptr);
418
419 for (i = 0; i < ptr->num_tags; i++)
420 if (ptr->tags[i].value.type == otc_value_string)
421 FLT_OT_FREE_VOID(ptr->tags[i].value.value.string_value);
422 otc_text_map_destroy(&(ptr->baggage), OTC_TEXT_MAP_FREE_VALUE);
423 for (i = 0; i < ptr->num_log_fields; i++)
424 if (ptr->log_fields[i].value.type == otc_value_string)
425 FLT_OT_FREE_VOID(ptr->log_fields[i].value.value.string_value);
426
427 (void)memset(ptr, 0, sizeof(*ptr));
428
429 FLT_OT_RETURN();
430}
431
432
433/***
434 * NAME
435 * flt_ot_scope_finish_mark -
436 *
437 * ARGUMENTS
438 * rt_ctx -
439 * id -
440 * id_len -
441 *
442 * DESCRIPTION
443 * -
444 *
445 * RETURN VALUE
446 * -
447 */
448int flt_ot_scope_finish_mark(const struct flt_ot_runtime_context *rt_ctx, const char *id, size_t id_len)
449{
450 struct flt_ot_scope_span *span;
451 struct flt_ot_scope_context *ctx;
452 int span_cnt = 0, ctx_cnt = 0, retval;
453
454 FLT_OT_FUNC("%p, \"%s\", %zu", rt_ctx, id, id_len);
455
456 if (FLT_OT_STR_CMP(FLT_OT_SCOPE_SPAN_FINISH_ALL, id, id_len)) {
457 list_for_each_entry(span, &(rt_ctx->spans), list) {
458 span->flag_finish = 1;
459 span_cnt++;
460 }
461
462 list_for_each_entry(ctx, &(rt_ctx->contexts), list) {
463 ctx->flag_finish = 1;
464 ctx_cnt++;
465 }
466
467 FLT_OT_DBG(2, "marked %d span(s), %d context(s)", span_cnt, ctx_cnt);
468 }
469 else if (FLT_OT_STR_CMP(FLT_OT_SCOPE_SPAN_FINISH_REQ, id, id_len)) {
470 list_for_each_entry(span, &(rt_ctx->spans), list)
471 if (span->smp_opt_dir == SMP_OPT_DIR_REQ) {
472 span->flag_finish = 1;
473 span_cnt++;
474 }
475
476 list_for_each_entry(ctx, &(rt_ctx->contexts), list)
477 if (ctx->smp_opt_dir == SMP_OPT_DIR_REQ) {
478 ctx->flag_finish = 1;
479 span_cnt++;
480 }
481
482 FLT_OT_DBG(2, "marked REQuest channel %d span(s), %d context(s)", span_cnt, ctx_cnt);
483 }
484 else if (FLT_OT_STR_CMP(FLT_OT_SCOPE_SPAN_FINISH_RES, id, id_len)) {
485 list_for_each_entry(span, &(rt_ctx->spans), list)
486 if (span->smp_opt_dir == SMP_OPT_DIR_RES) {
487 span->flag_finish = 1;
488 span_cnt++;
489 }
490
491 list_for_each_entry(ctx, &(rt_ctx->contexts), list)
492 if (ctx->smp_opt_dir == SMP_OPT_DIR_RES) {
493 ctx->flag_finish = 1;
494 ctx_cnt++;
495 }
496
497 FLT_OT_DBG(2, "marked RESponse channel %d span(s), %d context(s)", span_cnt, ctx_cnt);
498 }
499 else {
500 list_for_each_entry(span, &(rt_ctx->spans), list)
501 if ((span->id_len == id_len) && (memcmp(span->id, id, id_len) == 0)) {
502 span->flag_finish = 1;
503 span_cnt++;
504
505 break;
506 }
507
508 list_for_each_entry(ctx, &(rt_ctx->contexts), list)
509 if ((ctx->id_len == id_len) && (memcmp(ctx->id, id, id_len) == 0)) {
510 ctx->flag_finish = 1;
511 ctx_cnt++;
512
513 break;
514 }
515
516 if (span_cnt > 0)
517 FLT_OT_DBG(2, "marked span '%s'", id);
518 if (ctx_cnt > 0)
519 FLT_OT_DBG(2, "marked context '%s'", id);
520 if ((span_cnt + ctx_cnt) == 0)
521 FLT_OT_DBG(2, "cannot find span/context '%s'", id);
522 }
523
524 retval = span_cnt + ctx_cnt;
525
526 FLT_OT_RETURN(retval);
527}
528
529
530/***
531 * NAME
532 * flt_ot_scope_finish_marked -
533 *
534 * ARGUMENTS
535 * rt_ctx -
536 * ts_finish -
537 *
538 * DESCRIPTION
539 * Finish marked spans.
540 *
541 * RETURN VALUE
542 * This function does not return a value.
543 */
544void flt_ot_scope_finish_marked(const struct flt_ot_runtime_context *rt_ctx, const struct timespec *ts_finish)
545{
546 struct flt_ot_scope_span *span;
547 struct flt_ot_scope_context *ctx;
548
549 FLT_OT_FUNC("%p, %p", rt_ctx, ts_finish);
550
551 list_for_each_entry(span, &(rt_ctx->spans), list)
552 if (span->flag_finish) {
553 FLT_OT_DBG_SCOPE_SPAN("finishing span ", span);
554
555 ot_span_finish(&(span->span), ts_finish, NULL, NULL, NULL);
556
557 span->flag_finish = 0;
558 }
559
560 list_for_each_entry(ctx, &(rt_ctx->contexts), list)
561 if (ctx->flag_finish) {
562 FLT_OT_DBG_SCOPE_CONTEXT("finishing context ", ctx);
563
564 if (ctx->context != NULL)
565 ctx->context->destroy(&(ctx->context));
566
567 ctx->flag_finish = 0;
568 }
569
570 FLT_OT_RETURN();
571}
572
573
574/***
575 * NAME
576 * flt_ot_scope_free_unused -
577 *
578 * ARGUMENTS
579 * rt_ctx -
580 * chn -
581 *
582 * DESCRIPTION
583 * -
584 *
585 * RETURN VALUE
586 * This function does not return a value.
587 */
588void flt_ot_scope_free_unused(struct flt_ot_runtime_context *rt_ctx, struct channel *chn)
589{
590 FLT_OT_FUNC("%p", rt_ctx);
591
592 if (rt_ctx == NULL)
593 FLT_OT_RETURN();
594
595 if (!LIST_ISEMPTY(&(rt_ctx->spans))) {
596 struct flt_ot_scope_span *span, *span_back;
597
598 list_for_each_entry_safe(span, span_back, &(rt_ctx->spans), list)
599 if (span->span == NULL)
600 flt_ot_scope_span_free(&span);
601 }
602
603 if (!LIST_ISEMPTY(&(rt_ctx->contexts))) {
604 struct flt_ot_scope_context *ctx, *ctx_back;
605
606 list_for_each_entry_safe(ctx, ctx_back, &(rt_ctx->contexts), list)
607 if (ctx->context == NULL) {
608 /*
609 * All headers and variables associated with
610 * the context in question should be deleted.
611 */
612 (void)flt_ot_http_headers_remove(chn, ctx->id, NULL);
613 (void)flt_ot_vars_unset(rt_ctx->stream, FLT_OT_VARS_SCOPE, ctx->id, ctx->smp_opt_dir, NULL);
614
615 flt_ot_scope_context_free(&ctx);
616 }
617 }
618
619 FLT_OT_DBG_RUNTIME_CONTEXT("session context: ", rt_ctx);
620
621 FLT_OT_RETURN();
622}
623
624/*
625 * Local variables:
626 * c-indent-level: 8
627 * c-basic-offset: 8
628 * End:
629 *
630 * vi: noexpandtab shiftwidth=8 tabstop=8
631 */