Miroslav Zagorac | 70230c6 | 2020-12-09 16:54:31 +0100 | [diff] [blame] | 1 | /*** |
| 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 | #define FLT_OT_EVENT_DEF(a,b,c,d,e,f) { AN_##b##_##a, SMP_OPT_DIR_##b, SMP_VAL_FE_##c, SMP_VAL_BE_##d, e, f }, |
| 24 | const struct flt_ot_event_data flt_ot_event_data[FLT_OT_EVENT_MAX] = { FLT_OT_EVENT_DEFINES }; |
| 25 | #undef FLT_OT_EVENT_DEF |
| 26 | |
| 27 | |
| 28 | /*** |
| 29 | * NAME |
| 30 | * flt_ot_scope_run_span - |
| 31 | * |
| 32 | * ARGUMENTS |
| 33 | * s - |
| 34 | * f - |
| 35 | * chn - |
| 36 | * dir - |
| 37 | * span - |
| 38 | * data - |
| 39 | * conf_span - |
| 40 | * ts - |
| 41 | * err - |
| 42 | * |
| 43 | * DESCRIPTION |
| 44 | * - |
| 45 | * |
| 46 | * RETURN VALUE |
| 47 | * Returns a negative value if an error occurs, 0 if it needs to wait, |
| 48 | * any other value otherwise. |
| 49 | */ |
| 50 | static int flt_ot_scope_run_span(struct stream *s, struct filter *f, struct channel *chn, uint dir, struct flt_ot_scope_span *span, struct flt_ot_scope_data *data, const struct flt_ot_conf_span *conf_span, const struct timespec *ts, char **err) |
| 51 | { |
| 52 | struct flt_ot_conf *conf = FLT_OT_CONF(f); |
| 53 | int retval = FLT_OT_RET_OK; |
| 54 | |
| 55 | FLT_OT_FUNC("%p, %p, %p, %u, %p, %p, %p, %p, %p:%p", s, f, chn, dir, span, data, conf_span, ts, FLT_OT_DPTR_ARGS(err)); |
| 56 | |
| 57 | if (span == NULL) |
| 58 | FLT_OT_RETURN(retval); |
| 59 | |
| 60 | if (span->span == NULL) { |
| 61 | span->span = ot_span_init(conf->tracer->tracer, span->id, ts, NULL, span->ref_type, FLT_OT_DEREF(span->ref_ctx, idx, -1), span->ref_span, data->tags, data->num_tags, err); |
| 62 | if (span->span == NULL) |
| 63 | retval = FLT_OT_RET_ERROR; |
| 64 | } |
| 65 | else if (data->num_tags > 0) |
| 66 | if (ot_span_tag(span->span, data->tags, data->num_tags) == -1) |
| 67 | retval = FLT_OT_RET_ERROR; |
| 68 | |
| 69 | if ((span->span != NULL) && (data->baggage != NULL)) |
| 70 | if (ot_span_set_baggage(span->span, data->baggage) == -1) |
| 71 | retval = FLT_OT_RET_ERROR; |
| 72 | |
| 73 | if ((span->span != NULL) && (data->num_log_fields > 0)) |
| 74 | if (ot_span_log(span->span, data->log_fields, data->num_log_fields) == -1) |
| 75 | retval = FLT_OT_RET_ERROR; |
| 76 | |
| 77 | if ((span->span != NULL) && (conf_span->ctx_id != NULL)) { |
| 78 | struct otc_http_headers_writer writer; |
| 79 | struct otc_text_map *text_map = NULL; |
| 80 | struct otc_span_context *span_ctx; |
| 81 | |
| 82 | span_ctx = ot_inject_http_headers(conf->tracer->tracer, span->span, &writer, err); |
| 83 | if (span_ctx != NULL) { |
| 84 | int i = 0; |
| 85 | |
| 86 | if (conf_span->ctx_flags & (FLT_OT_CTX_USE_VARS | FLT_OT_CTX_USE_HEADERS)) { |
| 87 | for (text_map = &(writer.text_map); i < text_map->count; i++) { |
| 88 | if (!(conf_span->ctx_flags & FLT_OT_CTX_USE_VARS)) |
| 89 | /* Do nothing. */; |
| 90 | else if (flt_ot_var_register(FLT_OT_VARS_SCOPE, conf_span->ctx_id, text_map->key[i], err) == -1) |
| 91 | retval = FLT_OT_RET_ERROR; |
| 92 | else if (flt_ot_var_set(s, FLT_OT_VARS_SCOPE, conf_span->ctx_id, text_map->key[i], text_map->value[i], dir, err) == -1) |
| 93 | retval = FLT_OT_RET_ERROR; |
| 94 | |
| 95 | if (!(conf_span->ctx_flags & FLT_OT_CTX_USE_HEADERS)) |
| 96 | /* Do nothing. */; |
| 97 | else if (flt_ot_http_header_set(chn, conf_span->ctx_id, text_map->key[i], text_map->value[i], err) == -1) |
| 98 | retval = FLT_OT_RET_ERROR; |
| 99 | } |
| 100 | } |
| 101 | |
| 102 | span_ctx->destroy(&span_ctx); |
| 103 | otc_text_map_destroy(&text_map, OTC_TEXT_MAP_FREE_KEY | OTC_TEXT_MAP_FREE_VALUE); |
| 104 | } |
| 105 | } |
| 106 | |
| 107 | FLT_OT_RETURN(retval); |
| 108 | } |
| 109 | |
| 110 | |
| 111 | /*** |
| 112 | * NAME |
| 113 | * flt_ot_scope_run - |
| 114 | * |
| 115 | * ARGUMENTS |
| 116 | * s - |
| 117 | * f - |
| 118 | * chn - |
| 119 | * conf_scope - |
| 120 | * ts - |
| 121 | * dir - |
| 122 | * err - |
| 123 | * |
| 124 | * DESCRIPTION |
| 125 | * - |
| 126 | * |
| 127 | * RETURN VALUE |
| 128 | * Returns a negative value if an error occurs, 0 if it needs to wait, |
| 129 | * any other value otherwise. |
| 130 | */ |
| 131 | int flt_ot_scope_run(struct stream *s, struct filter *f, struct channel *chn, struct flt_ot_conf_scope *conf_scope, const struct timespec *ts, uint dir, char **err) |
| 132 | { |
| 133 | struct flt_ot_conf *conf = FLT_OT_CONF(f); |
| 134 | struct flt_ot_conf_context *conf_ctx; |
| 135 | struct flt_ot_conf_span *conf_span; |
| 136 | struct flt_ot_conf_str *finish; |
| 137 | struct timespec ts_now; |
| 138 | int retval = FLT_OT_RET_OK; |
| 139 | |
| 140 | FLT_OT_FUNC("%p, %p, %p, %p, %p, %u, %p:%p", s, f, chn, conf_scope, ts, dir, FLT_OT_DPTR_ARGS(err)); |
| 141 | |
| 142 | FLT_OT_DBG(3, "channel: %s, mode: %s (%s)", flt_ot_chn_label(chn), flt_ot_pr_mode(s), flt_ot_stream_pos(s)); |
| 143 | FLT_OT_DBG(3, "run scope '%s' %d", conf_scope->id, conf_scope->event); |
| 144 | FLT_OT_DBG_CONF_SCOPE("run scope ", conf_scope); |
| 145 | |
| 146 | if (ts == NULL) { |
| 147 | (void)clock_gettime(CLOCK_MONOTONIC, &ts_now); |
| 148 | |
| 149 | ts = &ts_now; |
| 150 | } |
| 151 | |
| 152 | if (conf_scope->cond != NULL) { |
| 153 | enum acl_test_res res; |
| 154 | int rc; |
| 155 | |
| 156 | res = acl_exec_cond(conf_scope->cond, s->be, s->sess, s, dir | SMP_OPT_FINAL); |
| 157 | rc = acl_pass(res); |
| 158 | if (conf_scope->cond->pol == ACL_COND_UNLESS) |
| 159 | rc = !rc; |
| 160 | |
| 161 | FLT_OT_DBG(3, "the ACL rule %s", rc ? "matches" : "does not match"); |
| 162 | |
| 163 | /* |
| 164 | * If the rule does not match, the current scope is skipped. |
| 165 | * |
| 166 | * If it is a root span, further processing of the session is |
| 167 | * disabled. As soon as the first span is encountered which |
| 168 | * is marked as root, further search is interrupted. |
| 169 | */ |
| 170 | if (!rc) { |
| 171 | list_for_each_entry(conf_span, &(conf_scope->spans), list) |
| 172 | if (conf_span->flag_root) { |
| 173 | FLT_OT_DBG(0, "session disabled"); |
| 174 | |
| 175 | FLT_OT_RT_CTX(f->ctx)->flag_disabled = 1; |
| 176 | |
| 177 | _HA_ATOMIC_ADD(conf->cnt.disabled + 0, 1); |
| 178 | |
| 179 | break; |
| 180 | } |
| 181 | |
| 182 | FLT_OT_RETURN(retval); |
| 183 | } |
| 184 | } |
| 185 | |
| 186 | list_for_each_entry(conf_ctx, &(conf_scope->contexts), list) { |
| 187 | struct otc_text_map *text_map; |
| 188 | |
| 189 | FLT_OT_DBG(3, "run context '%s' -> '%s'", conf_scope->id, conf_ctx->id); |
| 190 | FLT_OT_DBG_CONF_CONTEXT("run context ", conf_ctx); |
| 191 | |
| 192 | /* |
| 193 | * The OpenTracing context is read from the HTTP header |
| 194 | * or from HAProxy variables. |
| 195 | */ |
| 196 | if (conf_ctx->flags & FLT_OT_CTX_USE_HEADERS) |
| 197 | text_map = flt_ot_http_headers_get(chn, conf_ctx->id, conf_ctx->id_len, err); |
| 198 | else |
| 199 | text_map = flt_ot_vars_get(s, FLT_OT_VARS_SCOPE, conf_ctx->id, dir, err); |
| 200 | |
| 201 | if (text_map != NULL) { |
| 202 | if (flt_ot_scope_context_init(f->ctx, conf->tracer->tracer, conf_ctx->id, conf_ctx->id_len, text_map, dir, err) == NULL) |
| 203 | retval = FLT_OT_RET_ERROR; |
| 204 | |
| 205 | otc_text_map_destroy(&text_map, OTC_TEXT_MAP_FREE_KEY | OTC_TEXT_MAP_FREE_VALUE); |
| 206 | } else { |
| 207 | retval = FLT_OT_RET_ERROR; |
| 208 | } |
| 209 | } |
| 210 | |
| 211 | list_for_each_entry(conf_span, &(conf_scope->spans), list) { |
| 212 | struct flt_ot_scope_data data; |
| 213 | struct flt_ot_scope_span *span; |
| 214 | struct flt_ot_conf_sample *sample; |
| 215 | |
| 216 | FLT_OT_DBG(3, "run span '%s' -> '%s'", conf_scope->id, conf_span->id); |
| 217 | FLT_OT_DBG_CONF_SPAN("run span ", conf_span); |
| 218 | |
| 219 | (void)memset(&data, 0, sizeof(data)); |
| 220 | |
| 221 | span = flt_ot_scope_span_init(f->ctx, conf_span->id, conf_span->id_len, conf_span->ref_type, conf_span->ref_id, conf_span->ref_id_len, dir, err); |
| 222 | if (span == NULL) |
| 223 | retval = FLT_OT_RET_ERROR; |
| 224 | |
| 225 | list_for_each_entry(sample, &(conf_span->tags), list) { |
| 226 | FLT_OT_DBG(3, "adding tag '%s' -> '%s'", sample->key, sample->value); |
| 227 | |
| 228 | if (flt_ot_sample_add(s, dir, sample, &data, FLT_OT_EVENT_SAMPLE_TAG, err) == FLT_OT_RET_ERROR) |
| 229 | retval = FLT_OT_RET_ERROR; |
| 230 | } |
| 231 | |
| 232 | list_for_each_entry(sample, &(conf_span->logs), list) { |
| 233 | FLT_OT_DBG(3, "adding log '%s' -> '%s'", sample->key, sample->value); |
| 234 | |
| 235 | if (flt_ot_sample_add(s, dir, sample, &data, FLT_OT_EVENT_SAMPLE_LOG, err) == FLT_OT_RET_ERROR) |
| 236 | retval = FLT_OT_RET_ERROR; |
| 237 | } |
| 238 | |
| 239 | list_for_each_entry(sample, &(conf_span->baggages), list) { |
| 240 | FLT_OT_DBG(3, "adding baggage '%s' -> '%s'", sample->key, sample->value); |
| 241 | |
| 242 | if (flt_ot_sample_add(s, dir, sample, &data, FLT_OT_EVENT_SAMPLE_BAGGAGE, err) == FLT_OT_RET_ERROR) |
| 243 | retval = FLT_OT_RET_ERROR; |
| 244 | } |
| 245 | |
| 246 | if (retval != FLT_OT_RET_ERROR) |
| 247 | if (flt_ot_scope_run_span(s, f, chn, dir, span, &data, conf_span, ts, err) == FLT_OT_RET_ERROR) |
| 248 | retval = FLT_OT_RET_ERROR; |
| 249 | |
| 250 | flt_ot_scope_data_free(&data); |
| 251 | } |
| 252 | |
| 253 | list_for_each_entry(finish, &(conf_scope->finish), list) |
| 254 | if (flt_ot_scope_finish_mark(f->ctx, finish->str, finish->str_len) == -1) |
| 255 | retval = FLT_OT_RET_ERROR; |
| 256 | |
| 257 | flt_ot_scope_finish_marked(f->ctx, ts); |
| 258 | flt_ot_scope_free_unused(f->ctx, chn); |
| 259 | |
| 260 | FLT_OT_RETURN(retval); |
| 261 | } |
| 262 | |
| 263 | |
| 264 | /*** |
| 265 | * NAME |
| 266 | * flt_ot_event_run - |
| 267 | * |
| 268 | * ARGUMENTS |
| 269 | * s - |
| 270 | * f - |
| 271 | * chn - |
| 272 | * event - |
| 273 | * err - |
| 274 | * |
| 275 | * DESCRIPTION |
| 276 | * - |
| 277 | * |
| 278 | * RETURN VALUE |
| 279 | * Returns a negative value if an error occurs, 0 if it needs to wait, |
| 280 | * any other value otherwise. |
| 281 | */ |
| 282 | int flt_ot_event_run(struct stream *s, struct filter *f, struct channel *chn, int event, char **err) |
| 283 | { |
| 284 | struct flt_ot_conf *conf = FLT_OT_CONF(f); |
| 285 | struct flt_ot_conf_scope *conf_scope; |
| 286 | struct timespec ts; |
| 287 | int retval = FLT_OT_RET_OK; |
| 288 | |
| 289 | FLT_OT_FUNC("%p, %p, %p, %d, %p:%p", s, f, chn, event, FLT_OT_DPTR_ARGS(err)); |
| 290 | |
| 291 | FLT_OT_DBG(3, "channel: %s, mode: %s (%s)", flt_ot_chn_label(chn), flt_ot_pr_mode(s), flt_ot_stream_pos(s)); |
| 292 | FLT_OT_DBG(3, "run event '%s' %d", flt_ot_event_data[event].name, event); |
| 293 | |
| 294 | #ifdef DEBUG_OT |
| 295 | _HA_ATOMIC_ADD(conf->cnt.event[event].htx + (htx_is_empty(htxbuf(&(chn->buf))) ? 1 : 0), 1); |
| 296 | #endif |
| 297 | |
| 298 | FLT_OT_RT_CTX(f->ctx)->analyzers |= flt_ot_event_data[event].an_bit; |
| 299 | |
| 300 | /* All spans should be created/completed at the same time. */ |
| 301 | (void)clock_gettime(CLOCK_MONOTONIC, &ts); |
| 302 | |
| 303 | /* |
| 304 | * It is possible that there are defined multiple scopes that use the |
| 305 | * same event. Therefore, there must not be a 'break' here, ie an |
| 306 | * exit from the 'for' loop. |
| 307 | */ |
| 308 | list_for_each_entry(conf_scope, &(conf->scopes), list) { |
| 309 | if (conf_scope->event != event) |
| 310 | /* Do nothing. */; |
| 311 | else if (!conf_scope->flag_used) |
| 312 | FLT_OT_DBG(3, "scope '%s' %d not used", conf_scope->id, conf_scope->event); |
| 313 | else if (flt_ot_scope_run(s, f, chn, conf_scope, &ts, flt_ot_event_data[event].smp_opt_dir, err) == FLT_OT_RET_ERROR) |
| 314 | retval = FLT_OT_RET_ERROR; |
| 315 | } |
| 316 | |
| 317 | flt_ot_vars_dump(s); |
| 318 | flt_ot_http_headers_dump(chn); |
| 319 | |
| 320 | FLT_OT_DBG(3, "event = %d, chn = %p, s->req = %p, s->res = %p", event, chn, &(s->req), &(s->res)); |
| 321 | |
| 322 | FLT_OT_RETURN(retval); |
| 323 | } |
| 324 | |
| 325 | /* |
| 326 | * Local variables: |
| 327 | * c-indent-level: 8 |
| 328 | * c-basic-offset: 8 |
| 329 | * End: |
| 330 | * |
| 331 | * vi: noexpandtab shiftwidth=8 tabstop=8 |
| 332 | */ |