blob: 52b872dcc25302d346d9feb2d294572d3552905a [file] [log] [blame]
/***
* 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
*/