CLEANUP: stick-table/cli: take the "show table" context definition out of the appctx

This makes use of the generic command context allocation so that the
appctx doesn't have to declare a specific one anymore. The context is
created during parsing. The code also uses st2 which deserves being
addressed in separate commit.
This commit is contained in:
Willy Tarreau 2022-05-03 11:35:07 +02:00
parent 0fd8f0e236
commit 3c69e08e96
2 changed files with 82 additions and 74 deletions

View File

@ -149,15 +149,6 @@ struct appctx {
int iid, type, sid; /* proxy id, type and service id if bounding of stats is enabled */ int iid, type, sid; /* proxy id, type and service id if bounding of stats is enabled */
int st_code; /* the status code returned by an action */ int st_code; /* the status code returned by an action */
} stats; } stats;
struct {
void *target; /* table we want to dump, or NULL for all */
struct stktable *t; /* table being currently dumped (first if NULL) */
struct stksess *entry; /* last entry we were trying to dump (or first if NULL) */
long long value[STKTABLE_FILTER_LEN]; /* value to compare against */
signed char data_type[STKTABLE_FILTER_LEN]; /* type of data to compare, or -1 if none */
signed char data_op[STKTABLE_FILTER_LEN]; /* operator (STD_OP_*) when data_type set */
char action; /* action on the table : one of STK_CLI_ACT_* */
} table;
struct { struct {
unsigned int display_flags; unsigned int display_flags;
struct pat_ref *ref; struct pat_ref *ref;

View File

@ -19,6 +19,7 @@
#include <import/ebistree.h> #include <import/ebistree.h>
#include <haproxy/api.h> #include <haproxy/api.h>
#include <haproxy/applet.h>
#include <haproxy/arg.h> #include <haproxy/arg.h>
#include <haproxy/cfgparse.h> #include <haproxy/cfgparse.h>
#include <haproxy/cli.h> #include <haproxy/cli.h>
@ -4386,6 +4387,16 @@ static int table_dump_entry_to_buffer(struct buffer *msg,
return 1; return 1;
} }
/* appctx context used by the "show table" command */
struct show_table_ctx {
void *target; /* table we want to dump, or NULL for all */
struct stktable *t; /* table being currently dumped (first if NULL) */
struct stksess *entry; /* last entry we were trying to dump (or first if NULL) */
long long value[STKTABLE_FILTER_LEN]; /* value to compare against */
signed char data_type[STKTABLE_FILTER_LEN]; /* type of data to compare, or -1 if none */
signed char data_op[STKTABLE_FILTER_LEN]; /* operator (STD_OP_*) when data_type set */
char action; /* action on the table : one of STK_CLI_ACT_* */
};
/* Processes a single table entry matching a specific key passed in argument. /* Processes a single table entry matching a specific key passed in argument.
* returns 0 if wants to be called again, 1 if has ended processing. * returns 0 if wants to be called again, 1 if has ended processing.
@ -4393,7 +4404,8 @@ static int table_dump_entry_to_buffer(struct buffer *msg,
static int table_process_entry_per_key(struct appctx *appctx, char **args) static int table_process_entry_per_key(struct appctx *appctx, char **args)
{ {
struct conn_stream *cs = appctx->owner; struct conn_stream *cs = appctx->owner;
struct stktable *t = appctx->ctx.table.target; struct show_table_ctx *ctx = appctx->svcctx;
struct stktable *t = ctx->target;
struct stksess *ts; struct stksess *ts;
uint32_t uint32_key; uint32_t uint32_key;
unsigned char ip6_key[sizeof(struct in6_addr)]; unsigned char ip6_key[sizeof(struct in6_addr)];
@ -4436,7 +4448,7 @@ static int table_process_entry_per_key(struct appctx *appctx, char **args)
static_table_key.key_len = strlen(args[4]); static_table_key.key_len = strlen(args[4]);
break; break;
default: default:
switch (appctx->ctx.table.action) { switch (ctx->action) {
case STK_CLI_ACT_SHOW: case STK_CLI_ACT_SHOW:
return cli_err(appctx, "Showing keys from tables of type other than ip, ipv6, string and integer is not supported\n"); return cli_err(appctx, "Showing keys from tables of type other than ip, ipv6, string and integer is not supported\n");
case STK_CLI_ACT_CLR: case STK_CLI_ACT_CLR:
@ -4452,7 +4464,7 @@ static int table_process_entry_per_key(struct appctx *appctx, char **args)
if (!cli_has_level(appctx, ACCESS_LVL_OPER)) if (!cli_has_level(appctx, ACCESS_LVL_OPER))
return 1; return 1;
switch (appctx->ctx.table.action) { switch (ctx->action) {
case STK_CLI_ACT_SHOW: case STK_CLI_ACT_SHOW:
ts = stktable_lookup_key(t, &static_table_key); ts = stktable_lookup_key(t, &static_table_key);
if (!ts) if (!ts)
@ -4564,28 +4576,29 @@ static int table_process_entry_per_key(struct appctx *appctx, char **args)
*/ */
static int table_prepare_data_request(struct appctx *appctx, char **args) static int table_prepare_data_request(struct appctx *appctx, char **args)
{ {
struct show_table_ctx *ctx = appctx->svcctx;
int i; int i;
char *err = NULL; char *err = NULL;
if (appctx->ctx.table.action != STK_CLI_ACT_SHOW && appctx->ctx.table.action != STK_CLI_ACT_CLR) if (ctx->action != STK_CLI_ACT_SHOW && ctx->action != STK_CLI_ACT_CLR)
return cli_err(appctx, "content-based lookup is only supported with the \"show\" and \"clear\" actions\n"); return cli_err(appctx, "content-based lookup is only supported with the \"show\" and \"clear\" actions\n");
for (i = 0; i < STKTABLE_FILTER_LEN; i++) { for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
if (i > 0 && !*args[3+3*i]) // number of filter entries can be less than STKTABLE_FILTER_LEN if (i > 0 && !*args[3+3*i]) // number of filter entries can be less than STKTABLE_FILTER_LEN
break; break;
/* condition on stored data value */ /* condition on stored data value */
appctx->ctx.table.data_type[i] = stktable_get_data_type(args[3+3*i] + 5); ctx->data_type[i] = stktable_get_data_type(args[3+3*i] + 5);
if (appctx->ctx.table.data_type[i] < 0) if (ctx->data_type[i] < 0)
return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Unknown data type\n", i + 1)); return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Unknown data type\n", i + 1));
if (!((struct stktable *)appctx->ctx.table.target)->data_ofs[appctx->ctx.table.data_type[i]]) if (!((struct stktable *)ctx->target)->data_ofs[ctx->data_type[i]])
return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Data type not stored in this table\n", i + 1)); return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Data type not stored in this table\n", i + 1));
appctx->ctx.table.data_op[i] = get_std_op(args[4+3*i]); ctx->data_op[i] = get_std_op(args[4+3*i]);
if (appctx->ctx.table.data_op[i] < 0) if (ctx->data_op[i] < 0)
return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Require and operator among \"eq\", \"ne\", \"le\", \"ge\", \"lt\", \"gt\"\n", i + 1)); return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Require and operator among \"eq\", \"ne\", \"le\", \"ge\", \"lt\", \"gt\"\n", i + 1));
if (!*args[5+3*i] || strl2llrc(args[5+3*i], strlen(args[5+3*i]), &appctx->ctx.table.value[i]) != 0) if (!*args[5+3*i] || strl2llrc(args[5+3*i], strlen(args[5+3*i]), &ctx->value[i]) != 0)
return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Require a valid integer value to compare against\n", i + 1)); return cli_dynerr(appctx, memprintf(&err, "Filter entry #%i: Require a valid integer value to compare against\n", i + 1));
} }
@ -4600,21 +4613,22 @@ static int table_prepare_data_request(struct appctx *appctx, char **args)
/* returns 0 if wants to be called, 1 if has ended processing */ /* returns 0 if wants to be called, 1 if has ended processing */
static int cli_parse_table_req(char **args, char *payload, struct appctx *appctx, void *private) static int cli_parse_table_req(char **args, char *payload, struct appctx *appctx, void *private)
{ {
struct show_table_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
int i; int i;
for (i = 0; i < STKTABLE_FILTER_LEN; i++) for (i = 0; i < STKTABLE_FILTER_LEN; i++)
appctx->ctx.table.data_type[i] = -1; ctx->data_type[i] = -1;
appctx->ctx.table.target = NULL; ctx->target = NULL;
appctx->ctx.table.entry = NULL; ctx->entry = NULL;
appctx->ctx.table.action = (long)private; // keyword argument, one of STK_CLI_ACT_* ctx->action = (long)private; // keyword argument, one of STK_CLI_ACT_*
if (*args[2]) { if (*args[2]) {
appctx->ctx.table.target = stktable_find_by_name(args[2]); ctx->target = stktable_find_by_name(args[2]);
if (!appctx->ctx.table.target) if (!ctx->target)
return cli_err(appctx, "No such table\n"); return cli_err(appctx, "No such table\n");
} }
else { else {
if (appctx->ctx.table.action != STK_CLI_ACT_SHOW) if (ctx->action != STK_CLI_ACT_SHOW)
goto err_args; goto err_args;
return 0; return 0;
} }
@ -4629,7 +4643,7 @@ static int cli_parse_table_req(char **args, char *payload, struct appctx *appctx
return 0; return 0;
err_args: err_args:
switch (appctx->ctx.table.action) { switch (ctx->action) {
case STK_CLI_ACT_SHOW: case STK_CLI_ACT_SHOW:
return cli_err(appctx, "Optional argument only supports \"data.<store_data_type>\" <operator> <value> and key <key>\n"); return cli_err(appctx, "Optional argument only supports \"data.<store_data_type>\" <operator> <value> and key <key>\n");
case STK_CLI_ACT_CLR: case STK_CLI_ACT_CLR:
@ -4647,11 +4661,12 @@ err_args:
*/ */
static int cli_io_handler_table(struct appctx *appctx) static int cli_io_handler_table(struct appctx *appctx)
{ {
struct show_table_ctx *ctx = appctx->svcctx;
struct conn_stream *cs = appctx->owner; struct conn_stream *cs = appctx->owner;
struct stream *s = __cs_strm(cs); struct stream *s = __cs_strm(cs);
struct ebmb_node *eb; struct ebmb_node *eb;
int skip_entry; int skip_entry;
int show = appctx->ctx.table.action == STK_CLI_ACT_SHOW; int show = ctx->action == STK_CLI_ACT_SHOW;
/* /*
* We have 3 possible states in appctx->st2 : * We have 3 possible states in appctx->st2 :
@ -4668,7 +4683,7 @@ static int cli_io_handler_table(struct appctx *appctx)
if (unlikely(cs_ic(cs)->flags & (CF_WRITE_ERROR|CF_SHUTW))) { if (unlikely(cs_ic(cs)->flags & (CF_WRITE_ERROR|CF_SHUTW))) {
/* in case of abort, remove any refcount we might have set on an entry */ /* in case of abort, remove any refcount we might have set on an entry */
if (appctx->st2 == STAT_ST_LIST) { if (appctx->st2 == STAT_ST_LIST) {
stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry, 1); stksess_kill_if_expired(ctx->t, ctx->entry, 1);
} }
return 1; return 1;
} }
@ -4678,50 +4693,50 @@ static int cli_io_handler_table(struct appctx *appctx)
while (appctx->st2 != STAT_ST_FIN) { while (appctx->st2 != STAT_ST_FIN) {
switch (appctx->st2) { switch (appctx->st2) {
case STAT_ST_INIT: case STAT_ST_INIT:
appctx->ctx.table.t = appctx->ctx.table.target; ctx->t = ctx->target;
if (!appctx->ctx.table.t) if (!ctx->t)
appctx->ctx.table.t = stktables_list; ctx->t = stktables_list;
appctx->ctx.table.entry = NULL; ctx->entry = NULL;
appctx->st2 = STAT_ST_INFO; appctx->st2 = STAT_ST_INFO;
break; break;
case STAT_ST_INFO: case STAT_ST_INFO:
if (!appctx->ctx.table.t || if (!ctx->t ||
(appctx->ctx.table.target && (ctx->target &&
appctx->ctx.table.t != appctx->ctx.table.target)) { ctx->t != ctx->target)) {
appctx->st2 = STAT_ST_END; appctx->st2 = STAT_ST_END;
break; break;
} }
if (appctx->ctx.table.t->size) { if (ctx->t->size) {
if (show && !table_dump_head_to_buffer(&trash, cs, appctx->ctx.table.t, appctx->ctx.table.target)) if (show && !table_dump_head_to_buffer(&trash, cs, ctx->t, ctx->target))
return 0; return 0;
if (appctx->ctx.table.target && if (ctx->target &&
(strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) >= ACCESS_LVL_OPER) { (strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) >= ACCESS_LVL_OPER) {
/* dump entries only if table explicitly requested */ /* dump entries only if table explicitly requested */
HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock); HA_SPIN_LOCK(STK_TABLE_LOCK, &ctx->t->lock);
eb = ebmb_first(&appctx->ctx.table.t->keys); eb = ebmb_first(&ctx->t->keys);
if (eb) { if (eb) {
appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key); ctx->entry = ebmb_entry(eb, struct stksess, key);
appctx->ctx.table.entry->ref_cnt++; ctx->entry->ref_cnt++;
appctx->st2 = STAT_ST_LIST; appctx->st2 = STAT_ST_LIST;
HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock); HA_SPIN_UNLOCK(STK_TABLE_LOCK, &ctx->t->lock);
break; break;
} }
HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock); HA_SPIN_UNLOCK(STK_TABLE_LOCK, &ctx->t->lock);
} }
} }
appctx->ctx.table.t = appctx->ctx.table.t->next; ctx->t = ctx->t->next;
break; break;
case STAT_ST_LIST: case STAT_ST_LIST:
skip_entry = 0; skip_entry = 0;
HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock); HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ctx->entry->lock);
if (appctx->ctx.table.data_type[0] >= 0) { if (ctx->data_type[0] >= 0) {
/* we're filtering on some data contents */ /* we're filtering on some data contents */
void *ptr; void *ptr;
int dt, i; int dt, i;
@ -4730,11 +4745,11 @@ static int cli_io_handler_table(struct appctx *appctx)
for (i = 0; i < STKTABLE_FILTER_LEN; i++) { for (i = 0; i < STKTABLE_FILTER_LEN; i++) {
if (appctx->ctx.table.data_type[i] == -1) if (ctx->data_type[i] == -1)
break; break;
dt = appctx->ctx.table.data_type[i]; dt = ctx->data_type[i];
ptr = stktable_data_ptr(appctx->ctx.table.t, ptr = stktable_data_ptr(ctx->t,
appctx->ctx.table.entry, ctx->entry,
dt); dt);
data = 0; data = 0;
@ -4750,12 +4765,12 @@ static int cli_io_handler_table(struct appctx *appctx)
break; break;
case STD_T_FRQP: case STD_T_FRQP:
data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp), data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
appctx->ctx.table.t->data_arg[dt].u); ctx->t->data_arg[dt].u);
break; break;
} }
op = appctx->ctx.table.data_op[i]; op = ctx->data_op[i];
value = appctx->ctx.table.value[i]; value = ctx->value[i];
/* skip the entry if the data does not match the test and the value */ /* skip the entry if the data does not match the test and the value */
if ((data < value && if ((data < value &&
@ -4771,38 +4786,38 @@ static int cli_io_handler_table(struct appctx *appctx)
} }
if (show && !skip_entry && if (show && !skip_entry &&
!table_dump_entry_to_buffer(&trash, cs, appctx->ctx.table.t, appctx->ctx.table.entry)) { !table_dump_entry_to_buffer(&trash, cs, ctx->t, ctx->entry)) {
HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock); HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ctx->entry->lock);
return 0; return 0;
} }
HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock); HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ctx->entry->lock);
HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock); HA_SPIN_LOCK(STK_TABLE_LOCK, &ctx->t->lock);
appctx->ctx.table.entry->ref_cnt--; ctx->entry->ref_cnt--;
eb = ebmb_next(&appctx->ctx.table.entry->key); eb = ebmb_next(&ctx->entry->key);
if (eb) { if (eb) {
struct stksess *old = appctx->ctx.table.entry; struct stksess *old = ctx->entry;
appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key); ctx->entry = ebmb_entry(eb, struct stksess, key);
if (show) if (show)
__stksess_kill_if_expired(appctx->ctx.table.t, old); __stksess_kill_if_expired(ctx->t, old);
else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt) else if (!skip_entry && !ctx->entry->ref_cnt)
__stksess_kill(appctx->ctx.table.t, old); __stksess_kill(ctx->t, old);
appctx->ctx.table.entry->ref_cnt++; ctx->entry->ref_cnt++;
HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock); HA_SPIN_UNLOCK(STK_TABLE_LOCK, &ctx->t->lock);
break; break;
} }
if (show) if (show)
__stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry); __stksess_kill_if_expired(ctx->t, ctx->entry);
else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt) else if (!skip_entry && !ctx->entry->ref_cnt)
__stksess_kill(appctx->ctx.table.t, appctx->ctx.table.entry); __stksess_kill(ctx->t, ctx->entry);
HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock); HA_SPIN_UNLOCK(STK_TABLE_LOCK, &ctx->t->lock);
appctx->ctx.table.t = appctx->ctx.table.t->next; ctx->t = ctx->t->next;
appctx->st2 = STAT_ST_INFO; appctx->st2 = STAT_ST_INFO;
break; break;
@ -4816,8 +4831,10 @@ static int cli_io_handler_table(struct appctx *appctx)
static void cli_release_show_table(struct appctx *appctx) static void cli_release_show_table(struct appctx *appctx)
{ {
struct show_table_ctx *ctx = appctx->svcctx;
if (appctx->st2 == STAT_ST_LIST) { if (appctx->st2 == STAT_ST_LIST) {
stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry, 1); stksess_kill_if_expired(ctx->t, ctx->entry, 1);
} }
} }