blob: 3adc5a3002b8cebad51204310149cdeadea78c40 [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
23#ifdef DEBUG_OT
24
25/***
26 * NAME
27 * flt_ot_args_dump -
28 *
29 * ARGUMENTS
30 * args -
31 *
32 * DESCRIPTION
33 * -
34 *
35 * RETURN VALUE
36 * This function does not return a value.
37 */
38void flt_ot_args_dump(char **args)
39{
40 int i, n;
41
42 for (n = 1; FLT_OT_ARG_ISVALID(n); n++);
43
44 (void)fprintf(stderr, FLT_OT_DBG_FMT("%.*sargs[%d]: { '%s' "), dbg_indent_level, FLT_OT_DBG_INDENT, n, args[0]);
45
46 for (i = 1; FLT_OT_ARG_ISVALID(i); i++)
47 (void)fprintf(stderr, "'%s' ", args[i]);
48
49 (void)fprintf(stderr, "}\n");
50}
51
52
53/***
54 * NAME
55 * flt_ot_filters_dump -
56 *
57 * ARGUMENTS
58 * This function takes no arguments.
59 *
60 * DESCRIPTION
61 * -
62 *
63 * RETURN VALUE
64 * This function does not return a value.
65 */
66void flt_ot_filters_dump(void)
67{
68 struct flt_conf *fconf;
69 struct proxy *px;
70
71 FLT_OT_FUNC("");
72
73 for (px = proxies_list; px != NULL; px = px->next) {
74 FLT_OT_DBG(2, "proxy '%s'", px->id);
75
76 list_for_each_entry(fconf, &(px->filter_configs), list)
77 if (fconf->id == ot_flt_id) {
78 struct flt_ot_conf *conf = fconf->conf;
79
80 FLT_OT_DBG(2, " OT filter '%s'", conf->id);
81 }
82 }
83
84 FLT_OT_RETURN();
85}
86
87
88/***
89 * NAME
90 * flt_ot_chn_label -
91 *
92 * ARGUMENTS
93 * chn -
94 *
95 * DESCRIPTION
96 * -
97 *
98 * RETURN VALUE
99 * -
100 */
101const char *flt_ot_chn_label(const struct channel *chn)
102{
103 return (chn->flags & CF_ISRESP) ? "RESponse" : "REQuest";
104}
105
106
107/***
108 * NAME
109 * flt_ot_pr_mode -
110 *
111 * ARGUMENTS
112 * s -
113 *
114 * DESCRIPTION
115 * -
116 *
117 * RETURN VALUE
118 * -
119 */
120const char *flt_ot_pr_mode(const struct stream *s)
121{
122 struct proxy *px = (s->flags & SF_BE_ASSIGNED) ? s->be : strm_fe(s);
123
124 return (px->mode == PR_MODE_HTTP) ? "HTTP" : "TCP";
125}
126
127
128/***
129 * NAME
130 * flt_ot_stream_pos -
131 *
132 * ARGUMENTS
133 * s -
134 *
135 * DESCRIPTION
136 * -
137 *
138 * RETURN VALUE
139 * -
140 */
141const char *flt_ot_stream_pos(const struct stream *s)
142{
143 return (s->flags & SF_BE_ASSIGNED) ? "backend" : "frontend";
144}
145
146
147/***
148 * NAME
149 * flt_ot_type -
150 *
151 * ARGUMENTS
152 * f -
153 *
154 * DESCRIPTION
155 * -
156 *
157 * RETURN VALUE
158 * -
159 */
160const char *flt_ot_type(const struct filter *f)
161{
162 return (f->flags & FLT_FL_IS_BACKEND_FILTER) ? "backend" : "frontend";
163}
164
165
166/***
167 * NAME
168 * flt_ot_analyzer -
169 *
170 * ARGUMENTS
171 * an_bit -
172 *
173 * DESCRIPTION
174 * -
175 *
176 * RETURN VALUE
177 * -
178 */
179const char *flt_ot_analyzer(uint an_bit)
180{
181#define FLT_OT_AN_DEF(a) { a, #a },
182 static const struct {
183 uint an_bit;
184 const char *str;
185 } flt_ot_an[] = { FLT_OT_AN_DEFINES };
186#undef FLT_OT_AN_DEF
187 const char *retptr = "invalid an_bit";
188 int i;
189
190 for (i = 0; i < FLT_OT_TABLESIZE(flt_ot_an); i++)
191 if (flt_ot_an[i].an_bit == an_bit) {
192 retptr = flt_ot_an[i].str;
193
194 break;
195 }
196
197 return retptr;
198}
199
200
201/***
202 * NAME
203 * flt_ot_str_hex -
204 *
205 * ARGUMENTS
206 * data -
207 * size -
208 *
209 * DESCRIPTION
210 * -
211 *
212 * RETURN VALUE
213 * -
214 */
215const char *flt_ot_str_hex(const void *data, size_t size)
216{
217 static THREAD_LOCAL char retbuf[BUFSIZ];
218 const uint8_t *ptr = data;
219 size_t i;
220
221 if (data == NULL)
222 return "(null)";
223 else if (size == 0)
224 return "()";
225
226 for (i = 0, size <<= 1; (i < (sizeof(retbuf) - 2)) && (i < size); ptr++) {
227 retbuf[i++] = FLT_OT_NIBBLE_TO_HEX(*ptr >> 4);
228 retbuf[i++] = FLT_OT_NIBBLE_TO_HEX(*ptr & 0x0f);
229 }
230
231 retbuf[i] = '\0';
232
233 return retbuf;
234}
235
236
237/***
238 * NAME
239 * flt_ot_str_ctrl -
240 *
241 * ARGUMENTS
242 * data -
243 * size -
244 *
245 * DESCRIPTION
246 * -
247 *
248 * RETURN VALUE
249 * -
250 */
251const char *flt_ot_str_ctrl(const void *data, size_t size)
252{
253 static THREAD_LOCAL char retbuf[BUFSIZ];
254 const uint8_t *ptr = data;
255 size_t i, n = 0;
256
257 if (data == NULL)
258 return "(null)";
259 else if (size == 0)
260 return "()";
261
262 for (i = 0; (n < (sizeof(retbuf) - 1)) && (i < size); i++)
263 retbuf[n++] = ((ptr[i] >= 0x20) && (ptr[i] <= 0x7e)) ? ptr[i] : '.';
264
265 retbuf[n] = '\0';
266
267 return retbuf;
268}
269
270
271/***
272 * NAME
273 * flt_ot_list_debug -
274 *
275 * ARGUMENTS
276 * head -
277 *
278 * DESCRIPTION
279 * -
280 *
281 * RETURN VALUE
282 * -
283 */
284const char *flt_ot_list_debug(const struct list *head)
285{
286 FLT_OT_BUFFER_THR(retbuf, 4, 64, retptr);
287
288 if ((head == NULL) || LIST_ISEMPTY(head)) {
289 (void)strncpy(retptr, (head == NULL) ? "{ null list }" : "{ empty list }", sizeof(retbuf[0]));
290 }
291 else if (head->p == head->n) {
292 (void)snprintf(retptr, sizeof(retbuf[0]), "{ %p * 1 }", head->p);
293 }
294 else {
295 const struct list *ptr;
296 size_t count = 0;
297
298 for (ptr = head->n; ptr != head; ptr = ptr->n, count++);
299
300 (void)snprintf(retptr, sizeof(retbuf[0]), "{ %p %p %zu }", head->p, head->n, count);
301 }
302
303 return (retptr);
304}
305
306#endif /* DEBUG_OT */
307
308
309/***
310 * NAME
311 * flt_ot_chunk_add -
312 *
313 * ARGUMENTS
314 * chk -
315 * src -
316 * n -
317 * err -
318 *
319 * DESCRIPTION
320 * -
321 *
322 * RETURN VALUE
323 * -
324 */
325ssize_t flt_ot_chunk_add(struct buffer *chk, const void *src, size_t n, char **err)
326{
327 FLT_OT_FUNC("%p, %p, %zu, %p:%p", chk, src, n, FLT_OT_DPTR_ARGS(err));
328
329 if ((chk == NULL) || (src == NULL))
330 FLT_OT_RETURN(-1);
331
332 if (chk->area == NULL)
333 chunk_init(chk, FLT_OT_CALLOC(1, global.tune.bufsize), global.tune.bufsize);
334
335 if (chk->area == NULL) {
336 FLT_OT_ERR("out of memory");
337
338 FLT_OT_RETURN(-1);
339 }
340 else if (n > (chk->size - chk->data)) {
341 FLT_OT_ERR("chunk size too small");
342
343 FLT_OT_RETURN(-1);
344 }
345
346 (void)memcpy(chk->area + chk->data, src, n);
347 chk->data += n;
348
349 FLT_OT_RETURN(chk->data);
350}
351
352
353/***
354 * NAME
355 * flt_ot_args_count -
356 *
357 * ARGUMENTS
358 * args -
359 *
360 * DESCRIPTION
361 * -
362 *
363 * RETURN VALUE
364 * -
365 */
366int flt_ot_args_count(char **args)
367{
368 int retval = 0;
369
370 if (args != NULL)
371 for ( ; FLT_OT_ARG_ISVALID(retval); retval++);
372
373 return retval;
374}
375
376
377/***
378 * NAME
379 * flt_ot_args_to_str -
380 *
381 * ARGUMENTS
382 * args -
383 * idx -
384 * str -
385 *
386 * DESCRIPTION
387 * -
388 *
389 * RETURN VALUE
390 * This function does not return a value.
391 */
392void flt_ot_args_to_str(char **args, int idx, char **str)
393{
394 int i;
395
396 if ((args == NULL) || (*args == NULL))
397 return;
398
399 for (i = idx; FLT_OT_ARG_ISVALID(i); i++)
400 (void)memprintf(str, "%s%s%s", (*str == NULL) ? "" : *str, (i == idx) ? "" : " ", args[i]);
401}
402
403
404/***
405 * NAME
406 * flt_ot_strtod -
407 *
408 * ARGUMENTS
409 * nptr -
410 * limit_min -
411 * limit_max -
412 * err -
413 *
414 * DESCRIPTION
415 * -
416 *
417 * RETURN VALUE
418 * -
419 */
420double flt_ot_strtod(const char *nptr, double limit_min, double limit_max, char **err)
421{
422 char *endptr = NULL;
423 double retval;
424
425 errno = 0;
426
427 retval = strtod(nptr, &endptr);
428 if ((errno != 0) || FLT_OT_STR_ISVALID(endptr))
429 FLT_OT_ERR("'%s' : invalid value", nptr);
430 else if (!FLT_OT_IN_RANGE(retval, limit_min, limit_max))
431 FLT_OT_ERR("'%s' : value out of range [%.2f, %.2f]", nptr, limit_min, limit_max);
432
433 return retval;
434}
435
436
437/***
438 * NAME
439 * flt_ot_strtoll -
440 *
441 * ARGUMENTS
442 * nptr -
443 * limit_min -
444 * limit_max -
445 * err -
446 *
447 * DESCRIPTION
448 * -
449 *
450 * RETURN VALUE
451 * -
452 */
453int64_t flt_ot_strtoll(const char *nptr, int64_t limit_min, int64_t limit_max, char **err)
454{
455 char *endptr = NULL;
456 int64_t retval;
457
458 errno = 0;
459
460 retval = strtoll(nptr, &endptr, 0);
461 if ((errno != 0) || FLT_OT_STR_ISVALID(endptr))
462 FLT_OT_ERR("'%s' : invalid value", nptr);
463 else if (!FLT_OT_IN_RANGE(retval, limit_min, limit_max))
464 FLT_OT_ERR("'%s' : value out of range [%" PRId64 ", %" PRId64 "]", nptr, limit_min, limit_max);
465
466 return retval;
467}
468
469
470/***
471 * NAME
472 * flt_ot_sample_to_str -
473 *
474 * ARGUMENTS
475 * data -
476 * value -
477 * size -
478 * err -
479 *
480 * DESCRIPTION
481 * -
482 *
483 * RETURN VALUE
484 * -
485 */
486int flt_ot_sample_to_str(const struct sample_data *data, char *value, size_t size, char **err)
487{
488 int retval = -1;
489
490 FLT_OT_FUNC("%p, %p, %zu, %p:%p", data, value, size, FLT_OT_DPTR_ARGS(err));
491
492 if ((data == NULL) || (value == NULL) || (size == 0))
493 FLT_OT_RETURN(retval);
494
495 *value = '\0';
496
497 if (data->type == SMP_T_ANY) {
498 FLT_OT_ERR("invalid sample data type %d", data->type);
499 }
500 else if (data->type == SMP_T_BOOL) {
501 value[0] = data->u.sint ? '1' : '0';
502 value[1] = '\0';
503
504 retval = 1;
505 }
506 else if (data->type == SMP_T_SINT) {
507 retval = snprintf(value, size, "%lld", data->u.sint);
508 }
509 else if (data->type == SMP_T_ADDR) {
510 /* This type is never used to qualify a sample. */
511 }
512 else if (data->type == SMP_T_IPV4) {
513 if (INET_ADDRSTRLEN > size)
514 FLT_OT_ERR("sample data size too large");
515 else if (inet_ntop(AF_INET, &(data->u.ipv4), value, INET_ADDRSTRLEN) == NULL)
516 FLT_OT_ERR("invalid IPv4 address");
517 else
518 retval = strlen(value);
519 }
520 else if (data->type == SMP_T_IPV6) {
521 if (INET6_ADDRSTRLEN > size)
522 FLT_OT_ERR("sample data size too large");
523 else if (inet_ntop(AF_INET6, &(data->u.ipv6), value, INET6_ADDRSTRLEN) == NULL)
524 FLT_OT_ERR("invalid IPv6 address");
525 else
526 retval = strlen(value);
527 }
528 else if (data->type == SMP_T_STR) {
529 if (data->u.str.data >= size) {
530 FLT_OT_ERR("sample data size too large");
531 }
532 else if (data->u.str.data > 0) {
533 retval = data->u.str.data;
534
535 (void)strncat(value, data->u.str.area, retval);
536 }
537 else {
538 /*
539 * There is no content to add but we will still return
540 * the correct status.
541 */
542 retval = 0;
543 }
544 }
545 else if (data->type == SMP_T_BIN) {
546 FLT_OT_ERR("invalid sample data type %d", data->type);
547 }
548 else if (data->type != SMP_T_METH) {
549 FLT_OT_ERR("invalid sample data type %d", data->type);
550 }
551 else if (data->u.meth.meth == HTTP_METH_OPTIONS) {
552 retval = FLT_OT_STR_SIZE(HTTP_METH_STR_OPTIONS);
553
554 (void)memcpy(value, HTTP_METH_STR_OPTIONS, retval + 1);
555 }
556 else if (data->u.meth.meth == HTTP_METH_GET) {
557 retval = FLT_OT_STR_SIZE(HTTP_METH_STR_GET);
558
559 (void)memcpy(value, HTTP_METH_STR_GET, retval + 1);
560 }
561 else if (data->u.meth.meth == HTTP_METH_HEAD) {
562 retval = FLT_OT_STR_SIZE(HTTP_METH_STR_HEAD);
563
564 (void)memcpy(value, HTTP_METH_STR_HEAD, retval + 1);
565 }
566 else if (data->u.meth.meth == HTTP_METH_POST) {
567 retval = FLT_OT_STR_SIZE(HTTP_METH_STR_POST);
568
569 (void)memcpy(value, HTTP_METH_STR_POST, retval + 1);
570 }
571 else if (data->u.meth.meth == HTTP_METH_PUT) {
572 retval = FLT_OT_STR_SIZE(HTTP_METH_STR_PUT);
573
574 (void)memcpy(value, HTTP_METH_STR_PUT, retval + 1);
575 }
576 else if (data->u.meth.meth == HTTP_METH_DELETE) {
577 retval = FLT_OT_STR_SIZE(HTTP_METH_STR_DELETE);
578
579 (void)memcpy(value, HTTP_METH_STR_DELETE, retval + 1);
580 }
581 else if (data->u.meth.meth == HTTP_METH_TRACE) {
582 retval = FLT_OT_STR_SIZE(HTTP_METH_STR_TRACE);
583
584 (void)memcpy(value, HTTP_METH_STR_TRACE, retval + 1);
585 }
586 else if (data->u.meth.meth == HTTP_METH_CONNECT) {
587 retval = FLT_OT_STR_SIZE(HTTP_METH_STR_CONNECT);
588
589 (void)memcpy(value, HTTP_METH_STR_CONNECT, retval + 1);
590 }
591 else if (data->u.meth.meth == HTTP_METH_OTHER) {
592 if (data->u.meth.str.data >= size) {
593 FLT_OT_ERR("sample data size too large");
594 } else {
595 retval = data->u.meth.str.data;
596
597 (void)strncat(value, data->u.meth.str.area, retval);
598 }
599 }
600 else {
601 FLT_OT_ERR("invalid HTTP method");
602 }
603
604 FLT_OT_RETURN(retval);
605}
606
607
608/***
609 * NAME
610 * flt_ot_sample_to_value -
611 *
612 * ARGUMENTS
613 * key -
614 * data -
615 * value -
616 * err -
617 *
618 * DESCRIPTION
619 * -
620 *
621 * RETURN VALUE
622 * -
623 */
624int flt_ot_sample_to_value(const char *key, const struct sample_data *data, struct otc_value *value, char **err)
625{
626 int retval = -1;
627
628 FLT_OT_FUNC("\"%s\", %p, %p, %p:%p", key, data, value, FLT_OT_DPTR_ARGS(err));
629
630 if ((data == NULL) || (value == NULL))
631 FLT_OT_RETURN(retval);
632
633 if (data->type == SMP_T_BOOL) {
634 value->type = otc_value_bool;
635 value->value.bool_value = data->u.sint ? 1 : 0;
636
637 retval = sizeof(value->value.bool_value);
638 }
639 else if (data->type == SMP_T_SINT) {
640 value->type = otc_value_int64;
641 value->value.int64_value = data->u.sint;
642
643 retval = sizeof(value->value.int64_value);
644 }
645 else {
646 value->type = otc_value_string;
647 value->value.string_value = FLT_OT_MALLOC(global.tune.bufsize);
648
649 if (value->value.string_value == NULL)
650 FLT_OT_ERR("out of memory");
651 else
652 retval = flt_ot_sample_to_str(data, (char *)value->value.string_value, global.tune.bufsize, err);
653 }
654
655 FLT_OT_RETURN(retval);
656}
657
658
659/***
660 * NAME
661 * flt_ot_sample_add -
662 *
663 * ARGUMENTS
664 * s -
665 * dir -
666 * sample -
667 * data -
668 * type -
669 * err -
670 *
671 * DESCRIPTION
672 * -
673 *
674 * RETURN VALUE
675 * Returns a negative value if an error occurs, 0 if it needs to wait,
676 * any other value otherwise.
677 */
678int flt_ot_sample_add(struct stream *s, uint dir, struct flt_ot_conf_sample *sample, struct flt_ot_scope_data *data, int type, char **err)
679{
680 const struct flt_ot_conf_sample_expr *expr;
681 struct sample smp;
682 struct otc_value value;
683 struct buffer buffer;
684 int idx = 0, rc, retval = FLT_OT_RET_OK;
685
686 FLT_OT_FUNC("%p, %u, %p, %p, %d, %p:%p", s, dir, data, sample, type, FLT_OT_DPTR_ARGS(err));
687
688 FLT_OT_DBG_CONF_SAMPLE("sample ", sample);
689
690 (void)memset(&buffer, 0, sizeof(buffer));
691
692 list_for_each_entry(expr, &(sample->exprs), list) {
693 FLT_OT_DBG_CONF_SAMPLE_EXPR("sample expression ", expr);
694
695 (void)memset(&smp, 0, sizeof(smp));
696
697 /*
698 * If we have only one expression to process, then the data
699 * type that is the result of the expression is converted to
700 * an equivalent data type (if possible) that is written to
701 * the tracer.
702 *
703 * If conversion is not possible, or if we have multiple
704 * expressions to process, then the result is converted to
705 * a string and as such sent to the tracer.
706 */
707 if (sample_process(s->be, s->sess, s, dir | SMP_OPT_FINAL, expr->expr, &smp) != NULL) {
708 FLT_OT_DBG(3, "data type %d: '%s'", smp.data.type, expr->value);
709 } else {
710 FLT_OT_DBG(2, "WARNING: failed to fetch '%s' value", expr->value);
711
712 /*
713 * In case the fetch failed, we will set the result
714 * (sample) to an empty static string.
715 */
716 (void)memset(&(smp.data), 0, sizeof(smp.data));
717 smp.data.type = SMP_T_STR;
718 smp.data.u.str.area = "";
719 }
720
721 if ((sample->num_exprs == 1) && (type == FLT_OT_EVENT_SAMPLE_TAG)) {
722 if (flt_ot_sample_to_value(sample->key, &(smp.data), &value, err) == -1)
723 retval = FLT_OT_RET_ERROR;
724 } else {
725 if (buffer.area == NULL) {
726 chunk_init(&buffer, FLT_OT_CALLOC(1, global.tune.bufsize), global.tune.bufsize);
727 if (buffer.area == NULL) {
728 FLT_OT_ERR("out of memory");
729
730 retval = FLT_OT_RET_ERROR;
731
732 break;
733 }
734 }
735
736 rc = flt_ot_sample_to_str(&(smp.data), buffer.area + buffer.data, buffer.size - buffer.data, err);
737 if (rc == -1) {
738 retval = FLT_OT_RET_ERROR;
739 } else {
740 buffer.data += rc;
741
742 if (sample->num_exprs == ++idx) {
743 value.type = otc_value_string;
744 value.value.string_value = buffer.area;
745 }
746 }
747 }
748 }
749
750 if (retval == FLT_OT_RET_ERROR) {
751 /* Do nothing. */
752 }
753 else if (type == FLT_OT_EVENT_SAMPLE_TAG) {
754 struct otc_tag *tag = data->tags + data->num_tags++;
755
756 tag->key = sample->key;
757 (void)memcpy(&(tag->value), &value, sizeof(tag->value));
758 }
759 else if (type == FLT_OT_EVENT_SAMPLE_LOG) {
760 struct otc_log_field *log_field = data->log_fields + data->num_log_fields++;
761
762 log_field->key = sample->key;
763 (void)memcpy(&(log_field->value), &value, sizeof(log_field->value));
764 }
765 else {
766 if (data->baggage == NULL)
767 data->baggage = otc_text_map_new(NULL, FLT_OT_MAXBAGGAGES);
768
769 if (data->baggage == NULL) {
770 FLT_OT_ERR("out of memory");
771
772 retval = FLT_OT_RET_ERROR;
773 }
774 else if (otc_text_map_add(data->baggage, sample->key, 0, value.value.string_value, 0, 0) == -1) {
775 FLT_OT_ERR("out of memory");
776
777 retval = FLT_OT_RET_ERROR;
778 }
779 else
780 FLT_OT_DBG(3, "baggage[%zu]: '%s' -> '%s'", data->baggage->count - 1, data->baggage->key[data->baggage->count - 1], data->baggage->value[data->baggage->count - 1]);
781 }
782
783 FLT_OT_RETURN(retval);
784}
785
786/*
787 * Local variables:
788 * c-indent-level: 8
789 * c-basic-offset: 8
790 * End:
791 *
792 * vi: noexpandtab shiftwidth=8 tabstop=8
793 */