/*** * 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" #define FLT_OT_GROUP_DEF(a,b,c) { a, b, c }, const struct flt_ot_group_data flt_ot_group_data[] = { FLT_OT_GROUP_DEFINES }; #undef FLT_OT_GROUP_DEF /*** * NAME * flt_ot_group_action - * * ARGUMENTS * rule - * px - * sess - * s - * opts - * * DESCRIPTION * This is the action_ptr callback of a rule associated to the * FLT_OT_ACTION_GROUP action. * * RETURN VALUE * The function returns ACT_RET_CONT if processing is finished (with error or * not), otherwise, it returns ACT_RET_YIELD if the action is in progress. */ static enum act_return flt_ot_group_action(struct act_rule *rule, struct proxy *px, struct session *sess, struct stream *s, int opts) { const struct filter *filter; const struct flt_conf *fconf; const struct flt_ot_conf *conf; const struct flt_ot_conf_group *conf_group; const struct flt_ot_runtime_context *rt_ctx = NULL; const struct flt_ot_conf_ph *ph_scope; char *err = NULL; int i, rc; FLT_OT_FUNC("%p, %p, %p, %p, %d", rule, px, sess, s, opts); FLT_OT_DBG(3, "from: %d, arg.act %p:{ %p %p %p %p }", rule->from, &(rule->arg.act), rule->arg.act.p[0], rule->arg.act.p[1], rule->arg.act.p[2], rule->arg.act.p[3]); fconf = rule->arg.act.p[FLT_OT_ARG_FLT_CONF]; conf = rule->arg.act.p[FLT_OT_ARG_CONF]; conf_group = ((const struct flt_ot_conf_ph *)(rule->arg.act.p[FLT_OT_ARG_GROUP]))->ptr; if ((fconf == NULL) || (conf == NULL) || (conf_group == NULL)) { FLT_OT_LOG(LOG_ERR, FLT_OT_ACTION_GROUP ": internal error, invalid group action"); FLT_OT_RETURN_EX(ACT_RET_CONT, enum act_return, "%d"); } if (conf->tracer->flag_disabled) { FLT_OT_DBG(1, "filter '%s' disabled, group action '%s' ignored", conf->id, conf_group->id); FLT_OT_RETURN_EX(ACT_RET_CONT, enum act_return, "%d"); } /* Find the OpenTracing filter instance from the current stream. */ list_for_each_entry(filter, &(s->strm_flt.filters), list) if (filter->config == fconf) { rt_ctx = filter->ctx; break; } if (rt_ctx == NULL) { FLT_OT_DBG(1, "cannot find filter, probably not attached to the stream"); FLT_OT_RETURN_EX(ACT_RET_CONT, enum act_return, "%d"); } else if (flt_ot_is_disabled(filter FLT_OT_DBG_ARGS(, -1))) { FLT_OT_RETURN_EX(ACT_RET_CONT, enum act_return, "%d"); } else { FLT_OT_DBG(3, "run group '%s'", conf_group->id); FLT_OT_DBG_CONF_GROUP("run group ", conf_group); } /* * Check the value of rule->from; in case it is incorrect, * report an error. */ for (i = 0; i < FLT_OT_TABLESIZE(flt_ot_group_data); i++) if (flt_ot_group_data[i].act_from == rule->from) break; if (i >= FLT_OT_TABLESIZE(flt_ot_group_data)) { FLT_OT_LOG(LOG_ERR, FLT_OT_ACTION_GROUP ": internal error, invalid rule->from=%d", rule->from); FLT_OT_RETURN_EX(ACT_RET_CONT, enum act_return, "%d"); } list_for_each_entry(ph_scope, &(conf_group->ph_scopes), list) { rc = flt_ot_scope_run(s, rt_ctx->filter, &(s->res), ph_scope->ptr, NULL, SMP_OPT_DIR_RES, &err); if ((rc == FLT_OT_RET_ERROR) && (opts & ACT_OPT_FINAL)) { /* XXX */ } } FLT_OT_RETURN_EX(ACT_RET_CONT, enum act_return, "%d"); } /*** * NAME * flt_ot_group_check - * * ARGUMENTS * rule - * px - * err - * * DESCRIPTION * This is the check_ptr callback of a rule associated to the * FLT_OT_ACTION_GROUP action. * * RETURN VALUE * The function returns 1 in success case, otherwise, * it returns 0 and err is filled. */ static int flt_ot_group_check(struct act_rule *rule, struct proxy *px, char **err) { struct flt_conf *fconf_tmp, *fconf = NULL; struct flt_ot_conf *conf; struct flt_ot_conf_ph *ph_group; const char *filter_id; const char *group_id; bool flag_found = 0; int i; FLT_OT_FUNC("%p, %p, %p:%p", rule, px, FLT_OT_DPTR_ARGS(err)); filter_id = rule->arg.act.p[FLT_OT_ARG_FILTER_ID]; group_id = rule->arg.act.p[FLT_OT_ARG_GROUP_ID]; FLT_OT_DBG(2, "checking filter_id='%s', group_id='%s'", filter_id, group_id); /* * Check the value of rule->from; in case it is incorrect, * report an error. */ for (i = 0; i < FLT_OT_TABLESIZE(flt_ot_group_data); i++) if (flt_ot_group_data[i].act_from == rule->from) break; if (i >= FLT_OT_TABLESIZE(flt_ot_group_data)) { FLT_OT_ERR("internal error, unexpected rule->from=%d, please report this bug!", rule->from); FLT_OT_RETURN_INT(0); } /* * Try to find the OpenTracing filter by checking all filters * for the proxy . */ list_for_each_entry(fconf_tmp, &(px->filter_configs), list) { conf = fconf_tmp->conf; if (fconf_tmp->id != ot_flt_id) { /* This is not an OpenTracing filter. */ continue; } else if (strcmp(conf->id, filter_id) == 0) { /* This is the good filter ID. */ fconf = fconf_tmp; break; } } if (fconf == NULL) { FLT_OT_ERR("unable to find the OpenTracing filter '%s' used by the " FLT_OT_ACTION_GROUP " '%s'", filter_id, group_id); FLT_OT_RETURN_INT(0); } /* * Attempt to find if the group is defined in the OpenTracing filter * configuration. */ list_for_each_entry(ph_group, &(conf->tracer->ph_groups), list) if (strcmp(ph_group->id, group_id) == 0) { flag_found = 1; break; } if (!flag_found) { FLT_OT_ERR("unable to find group '%s' in the OpenTracing filter '%s' configuration", group_id, filter_id); FLT_OT_RETURN_INT(0); } FLT_OT_FREE_CLEAR(rule->arg.act.p[FLT_OT_ARG_FILTER_ID]); FLT_OT_FREE_CLEAR(rule->arg.act.p[FLT_OT_ARG_GROUP_ID]); rule->arg.act.p[FLT_OT_ARG_FLT_CONF] = fconf; rule->arg.act.p[FLT_OT_ARG_CONF] = conf; rule->arg.act.p[FLT_OT_ARG_GROUP] = ph_group; FLT_OT_RETURN_INT(1); } /*** * NAME * flt_ot_group_release - * * ARGUMENTS * rule - * * DESCRIPTION * This is the release_ptr callback of a rule associated to the * FLT_OT_ACTION_GROUP action. * * RETURN VALUE * This function does not return a value. */ static void flt_ot_group_release(struct act_rule *rule) { FLT_OT_FUNC("%p", rule); FLT_OT_RETURN(); } /*** * NAME * flt_ot_group_parse - * * ARGUMENTS * args - * cur_arg - * px - * rule - * err - * * DESCRIPTION * - * * RETURN VALUE * Returns ACT_RET_PRS_ERR if an error occurs, ACT_RET_PRS_OK otherwise. */ static enum act_parse_ret flt_ot_group_parse(const char **args, int *cur_arg, struct proxy *px, struct act_rule *rule, char **err) { FLT_OT_FUNC("%p, %p, %p, %p, %p:%p", args, cur_arg, px, rule, FLT_OT_DPTR_ARGS(err)); if (!FLT_OT_ARG_ISVALID(*cur_arg) || !FLT_OT_ARG_ISVALID(*cur_arg + 1) || (FLT_OT_ARG_ISVALID(*cur_arg + 2) && (strcmp(args[*cur_arg + 2], FLT_OT_CONDITION_IF) != 0) && (strcmp(args[*cur_arg + 2], FLT_OT_CONDITION_UNLESS) != 0))) { FLT_OT_ERR("expects: [{ if | unless } ...]"); FLT_OT_RETURN_EX(ACT_RET_PRS_ERR, enum act_parse_ret, "%d"); } /* Copy the OpenTracing filter id. */ rule->arg.act.p[FLT_OT_ARG_FILTER_ID] = FLT_OT_STRDUP(args[*cur_arg]); if (rule->arg.act.p[FLT_OT_ARG_FILTER_ID] == NULL) { FLT_OT_ERR("%s : out of memory", args[*cur_arg]); FLT_OT_RETURN_EX(ACT_RET_PRS_ERR, enum act_parse_ret, "%d"); } /* Copy the OpenTracing group id. */ rule->arg.act.p[FLT_OT_ARG_GROUP_ID] = FLT_OT_STRDUP(args[*cur_arg + 1]); if (rule->arg.act.p[FLT_OT_ARG_GROUP_ID] == NULL) { FLT_OT_ERR("%s : out of memory", args[*cur_arg + 1]); FLT_OT_FREE_CLEAR(rule->arg.act.p[FLT_OT_ARG_FILTER_ID]); FLT_OT_RETURN_EX(ACT_RET_PRS_ERR, enum act_parse_ret, "%d"); } rule->action = ACT_CUSTOM; rule->action_ptr = flt_ot_group_action; rule->check_ptr = flt_ot_group_check; rule->release_ptr = flt_ot_group_release; *cur_arg += 2; FLT_OT_RETURN_EX(ACT_RET_PRS_OK, enum act_parse_ret, "%d"); } static struct action_kw_list tcp_req_action_kws = { ILH, { { FLT_OT_ACTION_GROUP, flt_ot_group_parse }, { /* END */ }, } }; INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_action_kws); static struct action_kw_list tcp_res_action_kws = { ILH, { { FLT_OT_ACTION_GROUP, flt_ot_group_parse }, { /* END */ }, } }; INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_action_kws); static struct action_kw_list http_req_action_kws = { ILH, { { FLT_OT_ACTION_GROUP, flt_ot_group_parse }, { /* END */ }, } }; INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_action_kws); static struct action_kw_list http_res_action_kws = { ILH, { { FLT_OT_ACTION_GROUP, flt_ot_group_parse }, { /* END */ }, } }; INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_action_kws); static struct action_kw_list http_after_res_actions_kws = { ILH, { { FLT_OT_ACTION_GROUP, flt_ot_group_parse }, { /* END */ }, } }; INITCALL1(STG_REGISTER, http_after_res_keywords_register, &http_after_res_actions_kws); /* * Local variables: * c-indent-level: 8 * c-basic-offset: 8 * End: * * vi: noexpandtab shiftwidth=8 tabstop=8 */