MINOR: stktable: support optional index for array types in {set, clear, show} table commands

As discussed in GH #2286, {set, clear, show} table commands were unable
to deal with array types such as gpt, because they handled such types as
a non-array types, thus only the first entry (ie: gpt[0]) was considered.

In this patch we add an extra logic around array-types handling so that
it is possible to specify an array index right after the type, like this:

  set table peer/table key mykey data.gpt[2] value
  # where 2 is the entry index that we want to access

If no index is specified, then it implicitly defaults to 0 to mimic
previous behavior.
This commit is contained in:
Aurelien DARRAGON 2024-12-19 16:38:28 +01:00
parent c0dc7769d4
commit e8b7337d86
2 changed files with 44 additions and 10 deletions

View File

@ -1869,6 +1869,9 @@ clear table <table> [ data.<type> <operator> <value> ] | [ key <key> ] |
the entry cannot be matched using the key due to empty key or incompatible the entry cannot be matched using the key due to empty key or incompatible
characters on the cli. characters on the cli.
If data.<type> is an array type, "[]" may be used to access a specific
index in the array, like so: data.gpt[1]
Example : Example :
$ echo "show table http_proxy" | socat stdio /tmp/sock1 $ echo "show table http_proxy" | socat stdio /tmp/sock1
>>> # table: http_proxy, type: ip, size:204800, used:2 >>> # table: http_proxy, type: ip, size:204800, used:2
@ -2625,6 +2628,9 @@ set table <table> ptr <ptr> [data.<data_type> <value>]*
pointer may be relevant if the entry cannot be matched using the key due to pointer may be relevant if the entry cannot be matched using the key due to
empty key or incompatible characters on the cli. empty key or incompatible characters on the cli.
If data.<data_type> is an array type, "[]" may be used to access a specific
index in the array, like so: data.gpt[1]
set timeout cli <delay> set timeout cli <delay>
Change the CLI interface timeout for current connection. This can be useful Change the CLI interface timeout for current connection. This can be useful
during long debugging sessions where the user needs to constantly inspect during long debugging sessions where the user needs to constantly inspect
@ -3862,6 +3868,9 @@ show table <name> [ data.<type> <operator> <value> [data.<type> ...]] |
the entry cannot be matched using the key due empty key or incompatible the entry cannot be matched using the key due empty key or incompatible
characters on the cli. characters on the cli.
If data.<type> is an array type, "[]" may be used to access a specific
index in the array, like so: data.gpt[1]
Example : Example :
$ echo "show table http_proxy" | socat stdio /tmp/sock1 $ echo "show table http_proxy" | socat stdio /tmp/sock1
>>> # table: http_proxy, type: ip, size:204800, used:2 >>> # table: http_proxy, type: ip, size:204800, used:2

View File

@ -5281,6 +5281,7 @@ struct show_table_ctx {
long long value[STKTABLE_FILTER_LEN]; /* value to compare against */ 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_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 */ signed char data_op[STKTABLE_FILTER_LEN]; /* operator (STD_OP_*) when data_type set */
unsigned int data_idx[STKTABLE_FILTER_LEN]; /* index of data to consider for array types */
enum { enum {
STATE_NEXT = 0, /* px points to next table, entry=NULL */ STATE_NEXT = 0, /* px points to next table, entry=NULL */
STATE_DUMP, /* px points to curr table, entry is valid, refcount held */ STATE_DUMP, /* px points to curr table, entry is valid, refcount held */
@ -5355,6 +5356,8 @@ static int table_process_entry(struct appctx *appctx, struct stksess *ts, char *
case STK_CLI_ACT_SET: case STK_CLI_ACT_SET:
HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock); HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
for (cur_arg = 5; *args[cur_arg]; cur_arg += 2) { for (cur_arg = 5; *args[cur_arg]; cur_arg += 2) {
unsigned int idx;
if (strncmp(args[cur_arg], "data.", 5) != 0) { if (strncmp(args[cur_arg], "data.", 5) != 0) {
cli_err(appctx, "\"data.<type>\" followed by a value expected\n"); cli_err(appctx, "\"data.<type>\" followed by a value expected\n");
HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock); HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
@ -5362,7 +5365,7 @@ static int table_process_entry(struct appctx *appctx, struct stksess *ts, char *
return 1; return 1;
} }
data_type = stktable_get_data_type(args[cur_arg] + 5); data_type = stktable_get_data_type_idx(args[cur_arg] + 5, &idx);
if (data_type < 0) { if (data_type < 0) {
cli_err(appctx, "Unknown data type\n"); cli_err(appctx, "Unknown data type\n");
HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock); HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
@ -5384,6 +5387,16 @@ static int table_process_entry(struct appctx *appctx, struct stksess *ts, char *
return 1; return 1;
} }
if (stktable_data_types[data_type].is_array) {
ptr = stktable_data_ptr_idx(t, ts, data_type, idx);
if (!ptr) {
cli_err(appctx, "index out of range in this data array\n");
HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
stktable_touch_local(t, ts, 1);
return 1;
}
}
else
ptr = __stktable_data_ptr(t, ts, data_type); ptr = __stktable_data_ptr(t, ts, data_type);
switch (stktable_data_types[data_type].std_type) { switch (stktable_data_types[data_type].std_type) {
@ -5515,7 +5528,7 @@ static int table_prepare_data_request(struct appctx *appctx, char **args)
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 */
ctx->data_type[i] = stktable_get_data_type(args[3+3*i] + 5); ctx->data_type[i] = stktable_get_data_type_idx(args[3+3*i] + 5, &ctx->data_idx[i]);
if (ctx->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));
@ -5670,6 +5683,17 @@ static int cli_io_handler_table(struct appctx *appctx)
if (ctx->data_type[i] == -1) if (ctx->data_type[i] == -1)
break; break;
dt = ctx->data_type[i]; dt = ctx->data_type[i];
if (stktable_data_types[dt].is_array) {
ptr = stktable_data_ptr_idx(ctx->t,
ctx->entry,
dt, ctx->data_idx[i]);
if (!ptr) {
/* index out of range */
skip_entry = 1;
break;
}
}
else {
ptr = stktable_data_ptr(ctx->t, ptr = stktable_data_ptr(ctx->t,
ctx->entry, ctx->entry,
dt); dt);
@ -5677,6 +5701,7 @@ static int cli_io_handler_table(struct appctx *appctx)
* type is both valid and stored * type is both valid and stored
*/ */
BUG_ON(!ptr); BUG_ON(!ptr);
}
data = 0; data = 0;
switch (stktable_data_types[dt].std_type) { switch (stktable_data_types[dt].std_type) {