mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-04-22 15:05:51 +00:00
MEDIUM: cli: Allow multiple filter entries for "show table"
For complex stick tables with many entries/columns, it can be beneficial to filter using multiple criteria. The maximum number of filter entries can be controlled by defining STKTABLE_FILTER_LEN during build time. This patch can be backported to older releases.
This commit is contained in:
parent
016797f6ab
commit
1a693fc2fd
@ -2569,7 +2569,7 @@ show table
|
|||||||
>>> # table: front_pub, type: ip, size:204800, used:171454
|
>>> # table: front_pub, type: ip, size:204800, used:171454
|
||||||
>>> # table: back_rdp, type: ip, size:204800, used:0
|
>>> # table: back_rdp, type: ip, size:204800, used:0
|
||||||
|
|
||||||
show table <name> [ data.<type> <operator> <value> ] | [ key <key> ]
|
show table <name> [ data.<type> <operator> <value> [data.<type> ...]] | [ key <key> ]
|
||||||
Dump contents of stick-table <name>. In this mode, a first line of generic
|
Dump contents of stick-table <name>. In this mode, a first line of generic
|
||||||
information about the table is reported as with "show table", then all
|
information about the table is reported as with "show table", then all
|
||||||
entries are dumped. Since this can be quite heavy, it is possible to specify
|
entries are dumped. Since this can be quite heavy, it is possible to specify
|
||||||
@ -2588,6 +2588,8 @@ show table <name> [ data.<type> <operator> <value> ] | [ key <key> ]
|
|||||||
- lt : match entries whose data is less than this value
|
- lt : match entries whose data is less than this value
|
||||||
- gt : match entries whose data is greater than this value
|
- gt : match entries whose data is greater than this value
|
||||||
|
|
||||||
|
In this form, you can use multiple data filter entries, up to a maximum
|
||||||
|
defined during build time (4 by default).
|
||||||
|
|
||||||
When the key form is used the entry <key> is shown. The key must be of the
|
When the key form is used the entry <key> is shown. The key must be of the
|
||||||
same type as the table, which currently is limited to IPv4, IPv6, integer,
|
same type as the table, which currently is limited to IPv4, IPv6, integer,
|
||||||
|
@ -116,6 +116,11 @@
|
|||||||
#define STKTABLE_EXTRA_DATA_TYPES 0
|
#define STKTABLE_EXTRA_DATA_TYPES 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// max # of stick-table filter entries that can be used during dump
|
||||||
|
#ifndef STKTABLE_FILTER_LEN
|
||||||
|
#define STKTABLE_FILTER_LEN 4
|
||||||
|
#endif
|
||||||
|
|
||||||
// max # of loops we can perform around a read() which succeeds.
|
// max # of loops we can perform around a read() which succeeds.
|
||||||
// It's very frequent that the system returns a few TCP segments at a time.
|
// It's very frequent that the system returns a few TCP segments at a time.
|
||||||
#ifndef MAX_READ_POLL_LOOPS
|
#ifndef MAX_READ_POLL_LOOPS
|
||||||
|
@ -150,9 +150,9 @@ struct appctx {
|
|||||||
void *target; /* table we want to dump, or NULL for all */
|
void *target; /* table we want to dump, or NULL for all */
|
||||||
struct stktable *t; /* table being currently dumped (first if NULL) */
|
struct stktable *t; /* table being currently dumped (first if NULL) */
|
||||||
struct stksess *entry; /* last entry we were trying to dump (or first if NULL) */
|
struct stksess *entry; /* last entry we were trying to dump (or first if NULL) */
|
||||||
long long value; /* value to compare against */
|
long long value[STKTABLE_FILTER_LEN]; /* value to compare against */
|
||||||
signed char data_type; /* 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; /* operator (STD_OP_*) when data_type set */
|
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_* */
|
char action; /* action on the table : one of STK_CLI_ACT_* */
|
||||||
} table;
|
} table;
|
||||||
struct {
|
struct {
|
||||||
|
@ -39,7 +39,6 @@ static int class_listener_ref;
|
|||||||
static int class_regex_ref;
|
static int class_regex_ref;
|
||||||
static int class_stktable_ref;
|
static int class_stktable_ref;
|
||||||
|
|
||||||
#define MAX_STK_FILTER_LEN 4
|
|
||||||
#define STATS_LEN (MAX((int)ST_F_TOTAL_FIELDS, (int)INF_TOTAL_FIELDS))
|
#define STATS_LEN (MAX((int)ST_F_TOTAL_FIELDS, (int)INF_TOTAL_FIELDS))
|
||||||
|
|
||||||
static THREAD_LOCAL struct field stats[STATS_LEN];
|
static THREAD_LOCAL struct field stats[STATS_LEN];
|
||||||
@ -682,7 +681,7 @@ int hlua_stktable_dump(lua_State *L)
|
|||||||
int op;
|
int op;
|
||||||
int dt;
|
int dt;
|
||||||
long long val;
|
long long val;
|
||||||
struct stk_filter filter[MAX_STK_FILTER_LEN];
|
struct stk_filter filter[STKTABLE_FILTER_LEN];
|
||||||
int filter_count = 0;
|
int filter_count = 0;
|
||||||
int i;
|
int i;
|
||||||
int skip_entry;
|
int skip_entry;
|
||||||
@ -700,8 +699,8 @@ int hlua_stktable_dump(lua_State *L)
|
|||||||
while (lua_next(L, 2) != 0) {
|
while (lua_next(L, 2) != 0) {
|
||||||
int entry_idx = 0;
|
int entry_idx = 0;
|
||||||
|
|
||||||
if (filter_count >= MAX_STK_FILTER_LEN)
|
if (filter_count >= STKTABLE_FILTER_LEN)
|
||||||
return hlua_error(L, "Filter table too large (len > %d)", MAX_STK_FILTER_LEN);
|
return hlua_error(L, "Filter table too large (len > %d)", STKTABLE_FILTER_LEN);
|
||||||
|
|
||||||
if (lua_type(L, -1) != LUA_TTABLE || lua_rawlen(L, -1) != 3)
|
if (lua_type(L, -1) != LUA_TTABLE || lua_rawlen(L, -1) != 3)
|
||||||
return hlua_error(L, "Filter table entry must be a triplet: {\"data_col\", \"op\", val} (entry #%d)", filter_count + 1);
|
return hlua_error(L, "Filter table entry must be a triplet: {\"data_col\", \"op\", val} (entry #%d)", filter_count + 1);
|
||||||
|
@ -3600,23 +3600,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)
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
if (appctx->ctx.table.action != STK_CLI_ACT_SHOW && appctx->ctx.table.action != STK_CLI_ACT_CLR)
|
if (appctx->ctx.table.action != STK_CLI_ACT_SHOW && appctx->ctx.table.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++) {
|
||||||
|
if (i > 0 && !*args[3+3*i]) // number of filter entries can be less than STKTABLE_FILTER_LEN
|
||||||
|
break;
|
||||||
/* condition on stored data value */
|
/* condition on stored data value */
|
||||||
appctx->ctx.table.data_type = stktable_get_data_type(args[3] + 5);
|
appctx->ctx.table.data_type[i] = stktable_get_data_type(args[3+3*i] + 5);
|
||||||
if (appctx->ctx.table.data_type < 0)
|
if (appctx->ctx.table.data_type[i] < 0)
|
||||||
return cli_err(appctx, "Unknown data type\n");
|
return cli_err(appctx, "Unknown data type\n");
|
||||||
|
|
||||||
if (!((struct stktable *)appctx->ctx.table.target)->data_ofs[appctx->ctx.table.data_type])
|
if (!((struct stktable *)appctx->ctx.table.target)->data_ofs[appctx->ctx.table.data_type[i]])
|
||||||
return cli_err(appctx, "Data type not stored in this table\n");
|
return cli_err(appctx, "Data type not stored in this table\n");
|
||||||
|
|
||||||
appctx->ctx.table.data_op = get_std_op(args[4]);
|
appctx->ctx.table.data_op[i] = get_std_op(args[4+3*i]);
|
||||||
if (appctx->ctx.table.data_op < 0)
|
if (appctx->ctx.table.data_op < 0)
|
||||||
return cli_err(appctx, "Require and operator among \"eq\", \"ne\", \"le\", \"ge\", \"lt\", \"gt\"\n");
|
return cli_err(appctx, "Require and operator among \"eq\", \"ne\", \"le\", \"ge\", \"lt\", \"gt\"\n");
|
||||||
|
|
||||||
if (!*args[5] || strl2llrc(args[5], strlen(args[5]), &appctx->ctx.table.value) != 0)
|
if (!*args[5] || strl2llrc(args[5+3*i], strlen(args[5+3*i]), &appctx->ctx.table.value[i]) != 0)
|
||||||
return cli_err(appctx, "Require a valid integer value to compare against\n");
|
return cli_err(appctx, "Require a valid integer value to compare against\n");
|
||||||
|
}
|
||||||
|
|
||||||
/* OK we're done, all the fields are set */
|
/* OK we're done, all the fields are set */
|
||||||
return 0;
|
return 0;
|
||||||
@ -3625,7 +3631,10 @@ 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)
|
||||||
{
|
{
|
||||||
appctx->ctx.table.data_type = -1;
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < STKTABLE_FILTER_LEN; i++)
|
||||||
|
appctx->ctx.table.data_type[i] = -1;
|
||||||
appctx->ctx.table.target = NULL;
|
appctx->ctx.table.target = NULL;
|
||||||
appctx->ctx.table.entry = NULL;
|
appctx->ctx.table.entry = NULL;
|
||||||
appctx->ctx.table.action = (long)private; // keyword argument, one of STK_CLI_ACT_*
|
appctx->ctx.table.action = (long)private; // keyword argument, one of STK_CLI_ACT_*
|
||||||
@ -3672,7 +3681,6 @@ static int cli_io_handler_table(struct appctx *appctx)
|
|||||||
struct stream_interface *si = appctx->owner;
|
struct stream_interface *si = appctx->owner;
|
||||||
struct stream *s = si_strm(si);
|
struct stream *s = si_strm(si);
|
||||||
struct ebmb_node *eb;
|
struct ebmb_node *eb;
|
||||||
int dt;
|
|
||||||
int skip_entry;
|
int skip_entry;
|
||||||
int show = appctx->ctx.table.action == STK_CLI_ACT_SHOW;
|
int show = appctx->ctx.table.action == STK_CLI_ACT_SHOW;
|
||||||
|
|
||||||
@ -3744,13 +3752,18 @@ static int cli_io_handler_table(struct appctx *appctx)
|
|||||||
|
|
||||||
HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
|
HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
|
||||||
|
|
||||||
if (appctx->ctx.table.data_type >= 0) {
|
if (appctx->ctx.table.data_type[0] >= 0) {
|
||||||
/* we're filtering on some data contents */
|
/* we're filtering on some data contents */
|
||||||
void *ptr;
|
void *ptr;
|
||||||
long long data;
|
int dt;
|
||||||
|
signed char op;
|
||||||
|
long long data, value;
|
||||||
|
|
||||||
|
|
||||||
dt = appctx->ctx.table.data_type;
|
for (int i = 0; i < STKTABLE_FILTER_LEN; i++) {
|
||||||
|
if (appctx->ctx.table.data_type[i] == -1)
|
||||||
|
break;
|
||||||
|
dt = appctx->ctx.table.data_type[i];
|
||||||
ptr = stktable_data_ptr(appctx->ctx.table.t,
|
ptr = stktable_data_ptr(appctx->ctx.table.t,
|
||||||
appctx->ctx.table.entry,
|
appctx->ctx.table.entry,
|
||||||
dt);
|
dt);
|
||||||
@ -3772,20 +3785,20 @@ static int cli_io_handler_table(struct appctx *appctx)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
op = appctx->ctx.table.data_op[i];
|
||||||
|
value = appctx->ctx.table.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 < appctx->ctx.table.value &&
|
if ((data < value &&
|
||||||
(appctx->ctx.table.data_op == STD_OP_EQ ||
|
(op == STD_OP_EQ || op == STD_OP_GT || op == STD_OP_GE)) ||
|
||||||
appctx->ctx.table.data_op == STD_OP_GT ||
|
(data == value &&
|
||||||
appctx->ctx.table.data_op == STD_OP_GE)) ||
|
(op == STD_OP_NE || op == STD_OP_GT || op == STD_OP_LT)) ||
|
||||||
(data == appctx->ctx.table.value &&
|
(data > value &&
|
||||||
(appctx->ctx.table.data_op == STD_OP_NE ||
|
(op == STD_OP_EQ || op == STD_OP_LT || op == STD_OP_LE))) {
|
||||||
appctx->ctx.table.data_op == STD_OP_GT ||
|
|
||||||
appctx->ctx.table.data_op == STD_OP_LT)) ||
|
|
||||||
(data > appctx->ctx.table.value &&
|
|
||||||
(appctx->ctx.table.data_op == STD_OP_EQ ||
|
|
||||||
appctx->ctx.table.data_op == STD_OP_LT ||
|
|
||||||
appctx->ctx.table.data_op == STD_OP_LE)))
|
|
||||||
skip_entry = 1;
|
skip_entry = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (show && !skip_entry &&
|
if (show && !skip_entry &&
|
||||||
|
Loading…
Reference in New Issue
Block a user