diff options
Diffstat (limited to 'addons/ot/src/group.c')
-rw-r--r-- | addons/ot/src/group.c | 354 |
1 files changed, 354 insertions, 0 deletions
diff --git a/addons/ot/src/group.c b/addons/ot/src/group.c new file mode 100644 index 0000000..52b872d --- /dev/null +++ b/addons/ot/src/group.c @@ -0,0 +1,354 @@ +/*** + * 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 <px>. + */ + 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: <filter-id> <group-id> [{ 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 + */ |