MEDIUM: stick-table: Stop handling stick-tables as proxies.

This patch adds the support for the "table" line parsing in "peers" sections
to declare stick-table in such sections. This also prevents the user from having
to declare dummy backends sections with a unique stick-table inside.
Even if still supported, this usage will become deprecated.

To do so, the ->table member of proxy struct which is a stktable struct is replaced
by a pointer to a stktable struct allocated at parsing time in src/cfgparse-listen.c
for the dummy stick-table backends and in src/cfgparse.c for "peers" sections.
This has an impact on the code for stick-table sample converters and on the stickiness
rules parsers which first store the name of the dummy before resolving the rules.
This patch replaces proxy_tbl_by_name() calls by stktable_find_by_name() calls
to lookup for stick-tables stored in "stktable_by_name" ebtree at parsing time.
There is only one remaining place where proxy_tbl_by_name() is used: src/hlua.c.

At several places in the code we relied on the fact that ->size member of stick-table
was equal to zero to consider the stick-table was present by not configured,
this do not make sense anymore as ->table member of struct proxyis fow now on a pointer.
These tests are replaced by a test on ->table value itself.

In "peers" section we do not have to temporary store the name of the section the
stick-table are attached to because this name is obviously already known just after
having entered this "peers" section.

About the CLI stick-table I/O handler, the pointer to proxy struct is replaced by
a pointer to a stktable struct.
This commit is contained in:
Frdric Lcaille 2019-03-14 07:07:41 +01:00 committed by Willy Tarreau
parent f92da38222
commit 1b8e68e89a
14 changed files with 267 additions and 175 deletions

View File

@ -28,9 +28,13 @@
#include <common/time.h>
#include <types/stick_table.h>
extern struct stktable *stktables_list;
#define stktable_data_size(type) (sizeof(((union stktable_data*)0)->type))
#define stktable_data_cast(ptr, type) ((union stktable_data*)(ptr))->type
void stktable_store_name(struct stktable *t);
struct stktable *stktable_find_by_name(const char *name);
struct stksess *stksess_new(struct stktable *t, struct stktable_key *key);
void stksess_setkey(struct stktable *t, struct stksess *ts, struct stktable_key *key);
void stksess_free(struct stktable *t, struct stksess *ts);

View File

@ -144,7 +144,7 @@ struct appctx {
} errors;
struct {
void *target; /* table we want to dump, or NULL for all */
struct proxy *proxy; /* 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) */
long long value; /* value to compare against */
signed char data_type; /* type of data to compare, or -1 if none */

View File

@ -30,6 +30,7 @@
#include <types/vars.h>
#include <types/protocol_buffers.h>
#include <types/stick_table.h>
/* encoding of each arg type : up to 31 types are supported */
#define ARGT_BITS 5
@ -99,6 +100,7 @@ union arg_data {
struct in6_addr ipv6;
struct proxy *prx; /* used for fe, be, tables */
struct server *srv;
struct stktable *t;
struct userlist *usr;
struct map_descriptor *map;
struct my_regex *reg;

View File

@ -11,6 +11,7 @@
#include <types/proto_http.h>
#include <types/proxy.h>
#include <types/server.h>
#include <types/stick_table.h>
#define CLASS_CORE "Core"
#define CLASS_TXN "TXN"

View File

@ -416,7 +416,7 @@ struct proxy {
struct fe_counters fe_counters; /* frontend statistics counters */
struct list listener_queue; /* list of the temporarily limited listeners because of lack of a proxy resource */
struct stktable table; /* table for storing sticking streams */
struct stktable *table; /* table for storing sticking streams */
struct task *task; /* the associated task, mandatory to manage rate limiting, stopping and resource shortage, NULL if disabled */
struct list tcpcheck_rules; /* tcp-check send / expect rules */

View File

@ -152,6 +152,7 @@ struct stktable {
const char *file; /* The file where the stick-table is declared. */
int line; /* The line in this <file> the stick-table is declared. */
} conf;
struct ebpt_node name; /* Stick-table are lookup by name here. */
struct eb_root keys; /* head of sticky session tree */
struct eb_root exps; /* head of sticky session expiration tree */
struct eb_root updates; /* head of sticky updates sequence tree */

View File

@ -30,37 +30,34 @@
*/
int check_trk_action(struct act_rule *rule, struct proxy *px, char **err)
{
struct proxy *target;
struct stktable *target;
if (rule->arg.trk_ctr.table.n)
target = proxy_tbl_by_name(rule->arg.trk_ctr.table.n);
target = stktable_find_by_name(rule->arg.trk_ctr.table.n);
else
target = px;
target = px->table;
if (!target) {
memprintf(err, "unable to find table '%s' referenced by track-sc%d",
rule->arg.trk_ctr.table.n, trk_idx(rule->action));
rule->arg.trk_ctr.table.n ? rule->arg.trk_ctr.table.n : px->id,
trk_idx(rule->action));
return 0;
}
else if (target->table.size == 0) {
memprintf(err, "table '%s' used but not configured",
rule->arg.trk_ctr.table.n ? rule->arg.trk_ctr.table.n : px->id);
return 0;
}
else if (!stktable_compatible_sample(rule->arg.trk_ctr.expr, target->table.type)) {
if (!stktable_compatible_sample(rule->arg.trk_ctr.expr, target->type)) {
memprintf(err, "stick-table '%s' uses a type incompatible with the 'track-sc%d' rule",
rule->arg.trk_ctr.table.n ? rule->arg.trk_ctr.table.n : px->id,
trk_idx(rule->action));
return 0;
}
else if (px->bind_proc & ~target->bind_proc) {
else if (target->proxy && (px->bind_proc & ~target->proxy->bind_proc)) {
memprintf(err, "stick-table '%s' referenced by 'track-sc%d' rule not present on all processes covered by proxy '%s'",
target->id, trk_idx(rule->action), px->id);
return 0;
}
else {
free(rule->arg.trk_ctr.table.n);
rule->arg.trk_ctr.table.t = &target->table;
rule->arg.trk_ctr.table.t = target;
/* Note: if we decide to enhance the track-sc syntax, we may be
* able to pass a list of counters to track and allocate them
* right here using stktable_alloc_data_type().

View File

@ -1711,7 +1711,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
LIST_ADDQ(&curproxy->persist_rules, &rule->list);
}
else if (!strcmp(args[0], "stick-table")) {
struct proxy *other;
struct stktable *other;
if (curproxy == &defproxy) {
ha_alert("parsing [%s:%d] : 'stick-table' is not supported in 'defaults' section.\n",
@ -1720,20 +1720,35 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
goto out;
}
other = proxy_tbl_by_name(curproxy->id);
other = stktable_find_by_name(curproxy->id);
if (other) {
ha_alert("parsing [%s:%d] : stick-table name '%s' conflicts with table declared in %s '%s' at %s:%d.\n",
file, linenum, curproxy->id, proxy_type_str(other), other->id, other->conf.file, other->conf.line);
file, linenum, curproxy->id,
other->proxy ? proxy_cap_str(other->proxy->cap) : "peers",
other->proxy ? other->id : other->peers.p->id,
other->conf.file, other->conf.line);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
err_code |= parse_stick_table(file, linenum, args, &curproxy->table, curproxy->id, NULL);
curproxy->table = calloc(1, sizeof *curproxy->table);
if (!curproxy->table) {
ha_alert("parsing [%s:%d]: '%s %s' : memory allocation failed\n",
file, linenum, args[0], args[1]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
err_code |= parse_stick_table(file, linenum, args, curproxy->table, curproxy->id, NULL);
if (err_code & ERR_FATAL)
goto out;
/* Store the proxy in the stick-table. */
curproxy->table->proxy = curproxy;
stktable_store_name(curproxy->table);
curproxy->table->next = stktables_list;
stktables_list = curproxy->table;
}
else if (!strcmp(args[0], "stick")) {
struct sticking_rule *rule;

View File

@ -856,7 +856,45 @@ int cfg_parse_peers(const char *file, int linenum, char **args, int kwm)
l->default_target = curpeers->peers_fe->default_target;
l->options |= LI_O_UNLIMITED; /* don't make the peers subject to global limits */
global.maxsock++; /* for the listening socket */
} /* neither "peer" nor "peers" */
}
else if (!strcmp(args[0], "table")) {
struct stktable *t, *other;
char *id;
/* Line number and peer ID are updated only if this peer is the local one. */
if (init_peers_frontend(file, -1, NULL, curpeers) != 0) {
err_code |= ERR_ALERT | ERR_ABORT;
goto out;
}
other = stktable_find_by_name(args[1]);
if (other) {
ha_alert("parsing [%s:%d] : stick-table name '%s' conflicts with table declared in %s '%s' at %s:%d.\n",
file, linenum, args[1],
other->proxy ? proxy_cap_str(other->proxy->cap) : "peers",
other->proxy ? other->id : other->peers.p->id,
other->conf.file, other->conf.line);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
t = calloc(1, sizeof *t);
id = strdup(args[1]);
if (!t || !id) {
ha_alert("parsing [%s:%d]: '%s %s' : memory allocation failed\n",
file, linenum, args[0], args[1]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
err_code |= parse_stick_table(file, linenum, args, t, id, curpeers);
if (err_code & ERR_FATAL)
goto out;
stktable_store_name(t);
t->next = stktables_list;
stktables_list = t;
}
else if (!strcmp(args[0], "disabled")) { /* disables this peers section */
curpeers->state = PR_STSTOPPED;
}
@ -2171,6 +2209,7 @@ int check_config_validity()
{
int cfgerr = 0;
struct proxy *curproxy = NULL;
struct stktable *t;
struct server *newsrv = NULL;
int err_code = 0;
unsigned int next_pxid = 1;
@ -2261,8 +2300,8 @@ int check_config_validity()
if (curproxy->state == PR_STSTOPPED) {
/* ensure we don't keep listeners uselessly bound */
stop_proxy(curproxy);
free((void *)curproxy->table.peers.name);
curproxy->table.peers.p = NULL;
free((void *)curproxy->table->peers.name);
curproxy->table->peers.p = NULL;
continue;
}
@ -2624,79 +2663,69 @@ int check_config_validity()
/* find the target table for 'stick' rules */
list_for_each_entry(mrule, &curproxy->sticking_rules, list) {
struct proxy *target;
struct stktable *target;
curproxy->be_req_ana |= AN_REQ_STICKING_RULES;
if (mrule->flags & STK_IS_STORE)
curproxy->be_rsp_ana |= AN_RES_STORE_RULES;
if (mrule->table.name)
target = proxy_tbl_by_name(mrule->table.name);
target = stktable_find_by_name(mrule->table.name);
else
target = curproxy;
target = curproxy->table;
if (!target) {
ha_alert("Proxy '%s': unable to find stick-table '%s'.\n",
curproxy->id, mrule->table.name);
cfgerr++;
}
else if (target->table.size == 0) {
ha_alert("Proxy '%s': stick-table '%s' used but not configured.\n",
curproxy->id, mrule->table.name ? mrule->table.name : curproxy->id);
cfgerr++;
}
else if (!stktable_compatible_sample(mrule->expr, target->table.type)) {
else if (!stktable_compatible_sample(mrule->expr, target->type)) {
ha_alert("Proxy '%s': type of fetch not usable with type of stick-table '%s'.\n",
curproxy->id, mrule->table.name ? mrule->table.name : curproxy->id);
cfgerr++;
}
else if (curproxy->bind_proc & ~target->bind_proc) {
else if (target->proxy && curproxy->bind_proc & ~target->proxy->bind_proc) {
ha_alert("Proxy '%s': stick-table '%s' referenced 'stick-store' rule not present on all processes covered by proxy '%s'.\n",
curproxy->id, target->id, curproxy->id);
cfgerr++;
}
else {
free((void *)mrule->table.name);
mrule->table.t = &(target->table);
stktable_alloc_data_type(&target->table, STKTABLE_DT_SERVER_ID, NULL);
mrule->table.t = target;
stktable_alloc_data_type(target, STKTABLE_DT_SERVER_ID, NULL);
}
}
/* find the target table for 'store response' rules */
list_for_each_entry(mrule, &curproxy->storersp_rules, list) {
struct proxy *target;
struct stktable *target;
curproxy->be_rsp_ana |= AN_RES_STORE_RULES;
if (mrule->table.name)
target = proxy_tbl_by_name(mrule->table.name);
target = stktable_find_by_name(mrule->table.name);
else
target = curproxy;
target = curproxy->table;
if (!target) {
ha_alert("Proxy '%s': unable to find store table '%s'.\n",
curproxy->id, mrule->table.name);
cfgerr++;
}
else if (target->table.size == 0) {
ha_alert("Proxy '%s': stick-table '%s' used but not configured.\n",
curproxy->id, mrule->table.name ? mrule->table.name : curproxy->id);
cfgerr++;
}
else if (!stktable_compatible_sample(mrule->expr, target->table.type)) {
else if (!stktable_compatible_sample(mrule->expr, target->type)) {
ha_alert("Proxy '%s': type of fetch not usable with type of stick-table '%s'.\n",
curproxy->id, mrule->table.name ? mrule->table.name : curproxy->id);
cfgerr++;
}
else if (curproxy->bind_proc & ~target->bind_proc) {
else if (target->proxy && (curproxy->bind_proc & ~target->proxy->bind_proc)) {
ha_alert("Proxy '%s': stick-table '%s' referenced 'stick-store' rule not present on all processes covered by proxy '%s'.\n",
curproxy->id, target->id, curproxy->id);
cfgerr++;
}
else {
free((void *)mrule->table.name);
mrule->table.t = &(target->table);
stktable_alloc_data_type(&target->table, STKTABLE_DT_SERVER_ID, NULL);
mrule->table.t = target;
stktable_alloc_data_type(target, STKTABLE_DT_SERVER_ID, NULL);
}
}
@ -2760,32 +2789,32 @@ int check_config_validity()
LIST_INIT(&curproxy->block_rules);
}
if (curproxy->table.peers.name) {
if (curproxy->table && curproxy->table->peers.name) {
struct peers *curpeers;
for (curpeers = cfg_peers; curpeers; curpeers = curpeers->next) {
if (strcmp(curpeers->id, curproxy->table.peers.name) == 0) {
free((void *)curproxy->table.peers.name);
curproxy->table.peers.p = curpeers;
if (strcmp(curpeers->id, curproxy->table->peers.name) == 0) {
free((void *)curproxy->table->peers.name);
curproxy->table->peers.p = curpeers;
break;
}
}
if (!curpeers) {
ha_alert("Proxy '%s': unable to find sync peers '%s'.\n",
curproxy->id, curproxy->table.peers.name);
free((void *)curproxy->table.peers.name);
curproxy->table.peers.p = NULL;
curproxy->id, curproxy->table->peers.name);
free((void *)curproxy->table->peers.name);
curproxy->table->peers.p = NULL;
cfgerr++;
}
else if (curpeers->state == PR_STSTOPPED) {
/* silently disable this peers section */
curproxy->table.peers.p = NULL;
curproxy->table->peers.p = NULL;
}
else if (!curpeers->peers_fe) {
ha_alert("Proxy '%s': unable to find local peer '%s' in peers section '%s'.\n",
curproxy->id, localpeer, curpeers->id);
curproxy->table.peers.p = NULL;
curproxy->table->peers.p = NULL;
cfgerr++;
}
}
@ -3829,8 +3858,8 @@ out_uri_auth_compat:
/* compute the required process bindings for the peers */
for (curproxy = proxies_list; curproxy; curproxy = curproxy->next)
if (curproxy->table.peers.p)
curproxy->table.peers.p->peers_fe->bind_proc |= curproxy->bind_proc;
if (curproxy->table && curproxy->table->peers.p)
curproxy->table->peers.p->peers_fe->bind_proc |= curproxy->bind_proc;
if (cfg_peers) {
struct peers *curpeers = cfg_peers, **last;
@ -3920,15 +3949,24 @@ out_uri_auth_compat:
}
}
for (t = stktables_list; t; t = t->next) {
if (t->proxy)
continue;
if (!stktable_init(t)) {
ha_alert("Proxy '%s': failed to initialize stick-table.\n", t->id);
cfgerr++;
}
}
/* initialize stick-tables on backend capable proxies. This must not
* be done earlier because the data size may be discovered while parsing
* other proxies.
*/
for (curproxy = proxies_list; curproxy; curproxy = curproxy->next) {
if (curproxy->state == PR_STSTOPPED)
if (curproxy->state == PR_STSTOPPED || !curproxy->table)
continue;
if (!stktable_init(&curproxy->table)) {
if (!stktable_init(curproxy->table)) {
ha_alert("Proxy '%s': failed to initialize stick-table.\n", curproxy->id);
cfgerr++;
}

View File

@ -2369,7 +2369,7 @@ void deinit(void)
pool_destroy(p->req_cap_pool);
pool_destroy(p->rsp_cap_pool);
pool_destroy(p->table.pool);
pool_destroy(p->table->pool);
p0 = p;
p = p->next;

View File

@ -1269,9 +1269,9 @@ int hlua_fcn_new_proxy(lua_State *L, struct proxy *px)
}
lua_settable(L, -3);
if (px->table.id) {
if (px->table && px->table->id) {
lua_pushstring(L, "stktable");
hlua_fcn_new_stktable(L, &px->table);
hlua_fcn_new_stktable(L, px->table);
lua_settable(L, -3);
}

View File

@ -587,7 +587,7 @@ struct proxy *proxy_find_by_id(int id, int cap, int table)
if ((px->cap & cap) != cap)
continue;
if (table && !px->table.size)
if (table && (!px->table || !px->table->size))
continue;
return px;
@ -620,7 +620,7 @@ struct proxy *proxy_find_by_name(const char *name, int cap, int table)
if ((curproxy->cap & cap) != cap)
continue;
if (table && !curproxy->table.size)
if (table && (!curproxy->table || !curproxy->table->size))
continue;
return curproxy;
@ -993,12 +993,12 @@ struct task *manage_proxy(struct task *t, void *context, unsigned short state)
* be in neither list. Any entry being dumped will have ref_cnt > 0.
* However we protect tables that are being synced to peers.
*/
if (unlikely(stopping && p->state == PR_STSTOPPED && p->table.current)) {
if (!p->table.syncing) {
stktable_trash_oldest(&p->table, p->table.current);
if (unlikely(stopping && p->state == PR_STSTOPPED && p->table && p->table->current)) {
if (!p->table->syncing) {
stktable_trash_oldest(p->table, p->table->current);
pool_gc(NULL);
}
if (p->table.current) {
if (p->table->current) {
/* some entries still remain, let's recheck in one second */
next = tick_first(next, tick_add(now_ms, 1000));
}
@ -1138,8 +1138,8 @@ void soft_stop(void)
/* Note: do not wake up stopped proxies' task nor their tables'
* tasks as these ones might point to already released entries.
*/
if (p->table.size && p->table.sync_task)
task_wakeup(p->table.sync_task, TASK_WOKEN_MSG);
if (p->table && p->table->size && p->table->sync_task)
task_wakeup(p->table->sync_task, TASK_WOKEN_MSG);
if (p->task)
task_wakeup(p->task, TASK_WOKEN_MSG);

View File

@ -1109,7 +1109,8 @@ int smp_resolve_args(struct proxy *p)
list_for_each_entry_safe(cur, bak, &p->conf.args.list, list) {
struct proxy *px;
struct server *srv;
char *pname, *sname;
struct stktable *t;
char *pname, *sname, *stktname;
char *err;
arg = cur->arg;
@ -1244,30 +1245,35 @@ int smp_resolve_args(struct proxy *p)
break;
case ARGT_TAB:
if (arg->data.str.data) {
pname = arg->data.str.area;
px = proxy_tbl_by_name(pname);
if (!arg->data.str.data) {
ha_alert("parsing [%s:%d] : missing table name in arg %d of %s%s%s%s '%s' %s proxy '%s'.\n",
cur->file, cur->line,
cur->arg_pos + 1, conv_pre, conv_ctx, conv_pos, ctx, cur->kw, where, p->id);
cfgerr++;
continue;
}
if (!px) {
stktname = arg->data.str.area;
t = stktable_find_by_name(stktname);
if (!t) {
ha_alert("parsing [%s:%d] : unable to find table '%s' referenced in arg %d of %s%s%s%s '%s' %s proxy '%s'.\n",
cur->file, cur->line, pname,
cur->file, cur->line, stktname,
cur->arg_pos + 1, conv_pre, conv_ctx, conv_pos, ctx, cur->kw, where, p->id);
cfgerr++;
break;
}
if (!px->table.size) {
if (!t->size) {
ha_alert("parsing [%s:%d] : no table in proxy '%s' referenced in arg %d of %s%s%s%s '%s' %s proxy '%s'.\n",
cur->file, cur->line, pname,
cur->file, cur->line, stktname,
cur->arg_pos + 1, conv_pre, conv_ctx, conv_pos, ctx, cur->kw, where, p->id);
cfgerr++;
break;
}
if (p->bind_proc & ~px->bind_proc) {
if (t->proxy && (p->bind_proc & ~t->proxy->bind_proc)) {
ha_alert("parsing [%s:%d] : stick-table '%s' not present on all processes covered by proxy '%s'.\n",
cur->file, cur->line, px->id, p->id);
cur->file, cur->line, t->proxy->id, p->id);
cfgerr++;
break;
}
@ -1275,7 +1281,7 @@ int smp_resolve_args(struct proxy *p)
free(arg->data.str.area);
arg->data.str.area = NULL;
arg->unresolved = 0;
arg->data.prx = px;
arg->data.t = t;
break;
case ARGT_USR:

View File

@ -47,7 +47,36 @@
/* structure used to return a table key built from a sample */
static THREAD_LOCAL struct stktable_key static_table_key;
struct stktable *stktables_list;
struct eb_root stktable_by_name = EB_ROOT;
#define round_ptr_size(i) (((i) + (sizeof(void *) - 1)) &~ (sizeof(void *) - 1))
/* This function inserts stktable <t> into the tree of known stick-table.
* The stick-table ID is used as the storing key so it must already have
* been initialized.
*/
void stktable_store_name(struct stktable *t)
{
t->name.key = t->id;
ebis_insert(&stktable_by_name, &t->name);
}
struct stktable *stktable_find_by_name(const char *name)
{
struct ebpt_node *node;
struct stktable *t;
node = ebis_lookup(&stktable_by_name, name);
if (node) {
t = container_of(node, struct stktable, name);
if (!strcmp(t->id, name))
return t;
}
return NULL;
}
/*
* Free an allocated sticky session <ts>, and decrease sticky sessions counter
* in table <t>.
@ -1063,7 +1092,7 @@ static int sample_conv_in_table(const struct arg *arg_p, struct sample *smp, voi
struct stktable_key *key;
struct stksess *ts;
t = &arg_p[0].data.prx->table;
t = arg_p[0].data.t;
key = smp_to_stkey(smp, t);
if (!key)
@ -1091,7 +1120,7 @@ static int sample_conv_table_bytes_in_rate(const struct arg *arg_p, struct sampl
struct stksess *ts;
void *ptr;
t = &arg_p[0].data.prx->table;
t = arg_p[0].data.t;
key = smp_to_stkey(smp, t);
if (!key)
@ -1128,7 +1157,7 @@ static int sample_conv_table_conn_cnt(const struct arg *arg_p, struct sample *sm
struct stksess *ts;
void *ptr;
t = &arg_p[0].data.prx->table;
t = arg_p[0].data.t;
key = smp_to_stkey(smp, t);
if (!key)
@ -1164,7 +1193,7 @@ static int sample_conv_table_conn_cur(const struct arg *arg_p, struct sample *sm
struct stksess *ts;
void *ptr;
t = &arg_p[0].data.prx->table;
t = arg_p[0].data.t;
key = smp_to_stkey(smp, t);
if (!key)
@ -1200,7 +1229,7 @@ static int sample_conv_table_conn_rate(const struct arg *arg_p, struct sample *s
struct stksess *ts;
void *ptr;
t = &arg_p[0].data.prx->table;
t = arg_p[0].data.t;
key = smp_to_stkey(smp, t);
if (!key)
@ -1237,7 +1266,7 @@ static int sample_conv_table_bytes_out_rate(const struct arg *arg_p, struct samp
struct stksess *ts;
void *ptr;
t = &arg_p[0].data.prx->table;
t = arg_p[0].data.t;
key = smp_to_stkey(smp, t);
if (!key)
@ -1274,7 +1303,7 @@ static int sample_conv_table_gpt0(const struct arg *arg_p, struct sample *smp, v
struct stksess *ts;
void *ptr;
t = &arg_p[0].data.prx->table;
t = arg_p[0].data.t;
key = smp_to_stkey(smp, t);
if (!key)
@ -1310,7 +1339,7 @@ static int sample_conv_table_gpc0(const struct arg *arg_p, struct sample *smp, v
struct stksess *ts;
void *ptr;
t = &arg_p[0].data.prx->table;
t = arg_p[0].data.t;
key = smp_to_stkey(smp, t);
if (!key)
@ -1346,7 +1375,7 @@ static int sample_conv_table_gpc0_rate(const struct arg *arg_p, struct sample *s
struct stksess *ts;
void *ptr;
t = &arg_p[0].data.prx->table;
t = arg_p[0].data.t;
key = smp_to_stkey(smp, t);
if (!key)
@ -1383,7 +1412,7 @@ static int sample_conv_table_gpc1(const struct arg *arg_p, struct sample *smp, v
struct stksess *ts;
void *ptr;
t = &arg_p[0].data.prx->table;
t = arg_p[0].data.t;
key = smp_to_stkey(smp, t);
if (!key)
@ -1419,7 +1448,7 @@ static int sample_conv_table_gpc1_rate(const struct arg *arg_p, struct sample *s
struct stksess *ts;
void *ptr;
t = &arg_p[0].data.prx->table;
t = arg_p[0].data.t;
key = smp_to_stkey(smp, t);
if (!key)
@ -1456,7 +1485,7 @@ static int sample_conv_table_http_err_cnt(const struct arg *arg_p, struct sample
struct stksess *ts;
void *ptr;
t = &arg_p[0].data.prx->table;
t = arg_p[0].data.t;
key = smp_to_stkey(smp, t);
if (!key)
@ -1492,7 +1521,7 @@ static int sample_conv_table_http_err_rate(const struct arg *arg_p, struct sampl
struct stksess *ts;
void *ptr;
t = &arg_p[0].data.prx->table;
t = arg_p[0].data.t;
key = smp_to_stkey(smp, t);
if (!key)
@ -1529,7 +1558,7 @@ static int sample_conv_table_http_req_cnt(const struct arg *arg_p, struct sample
struct stksess *ts;
void *ptr;
t = &arg_p[0].data.prx->table;
t = arg_p[0].data.t;
key = smp_to_stkey(smp, t);
if (!key)
@ -1565,7 +1594,7 @@ static int sample_conv_table_http_req_rate(const struct arg *arg_p, struct sampl
struct stksess *ts;
void *ptr;
t = &arg_p[0].data.prx->table;
t = arg_p[0].data.t;
key = smp_to_stkey(smp, t);
if (!key)
@ -1602,7 +1631,7 @@ static int sample_conv_table_kbytes_in(const struct arg *arg_p, struct sample *s
struct stksess *ts;
void *ptr;
t = &arg_p[0].data.prx->table;
t = arg_p[0].data.t;
key = smp_to_stkey(smp, t);
if (!key)
@ -1638,7 +1667,7 @@ static int sample_conv_table_kbytes_out(const struct arg *arg_p, struct sample *
struct stksess *ts;
void *ptr;
t = &arg_p[0].data.prx->table;
t = arg_p[0].data.t;
key = smp_to_stkey(smp, t);
if (!key)
@ -1674,7 +1703,7 @@ static int sample_conv_table_server_id(const struct arg *arg_p, struct sample *s
struct stksess *ts;
void *ptr;
t = &arg_p[0].data.prx->table;
t = arg_p[0].data.t;
key = smp_to_stkey(smp, t);
if (!key)
@ -1710,7 +1739,7 @@ static int sample_conv_table_sess_cnt(const struct arg *arg_p, struct sample *sm
struct stksess *ts;
void *ptr;
t = &arg_p[0].data.prx->table;
t = arg_p[0].data.t;
key = smp_to_stkey(smp, t);
if (!key)
@ -1746,7 +1775,7 @@ static int sample_conv_table_sess_rate(const struct arg *arg_p, struct sample *s
struct stksess *ts;
void *ptr;
t = &arg_p[0].data.prx->table;
t = arg_p[0].data.t;
key = smp_to_stkey(smp, t);
if (!key)
@ -1782,7 +1811,7 @@ static int sample_conv_table_trackers(const struct arg *arg_p, struct sample *sm
struct stktable_key *key;
struct stksess *ts;
t = &arg_p[0].data.prx->table;
t = arg_p[0].data.t;
key = smp_to_stkey(smp, t);
if (!key)
@ -2062,7 +2091,7 @@ smp_fetch_table_cnt(const struct arg *args, struct sample *smp, const char *kw,
{
smp->flags = SMP_F_VOL_TEST;
smp->data.type = SMP_T_SINT;
smp->data.u.sint = args->data.prx->table.current;
smp->data.u.sint = args->data.t->current;
return 1;
}
@ -2072,12 +2101,12 @@ smp_fetch_table_cnt(const struct arg *args, struct sample *smp, const char *kw,
static int
smp_fetch_table_avl(const struct arg *args, struct sample *smp, const char *kw, void *private)
{
struct proxy *px;
struct stktable *t;
px = args->data.prx;
t = args->data.t;
smp->flags = SMP_F_VOL_TEST;
smp->data.type = SMP_T_SINT;
smp->data.u.sint = px->table.size - px->table.current;
smp->data.u.sint = t->size - t->current;
return 1;
}
@ -2125,11 +2154,11 @@ smp_fetch_sc_stkctr(struct session *sess, struct stream *strm, const struct arg
return NULL;
/* Converts into key. */
key = smp_to_stkey(&smp, &args->data.prx->table);
key = smp_to_stkey(&smp, args->data.t);
if (!key)
return NULL;
stkctr->table = &args->data.prx->table;
stkctr->table = args->data.t;
stkctr_set_entry(stkctr, stktable_lookup_key(stkctr->table, key));
return stkctr;
}
@ -2154,7 +2183,7 @@ smp_fetch_sc_stkctr(struct session *sess, struct stream *strm, const struct arg
if (unlikely(args[arg].type == ARGT_TAB)) {
/* an alternate table was specified, let's look up the same key there */
stkctr->table = &args[arg].data.prx->table;
stkctr->table = args[arg].data.t;
stkctr_set_entry(stkctr, stktable_lookup(stkctr->table, stksess));
return stkctr;
}
@ -2187,11 +2216,11 @@ smp_create_src_stkctr(struct session *sess, struct stream *strm, const struct ar
return NULL;
/* Converts into key. */
key = smp_to_stkey(&smp, &args->data.prx->table);
key = smp_to_stkey(&smp, args->data.t);
if (!key)
return NULL;
stkctr->table = &args->data.prx->table;
stkctr->table = args->data.t;
stkctr_set_entry(stkctr, stktable_get_entry(stkctr->table, key));
return stkctr;
}
@ -2709,7 +2738,7 @@ smp_fetch_src_updt_conn_cnt(const struct arg *args, struct sample *smp, const ch
struct stksess *ts;
struct stktable_key *key;
void *ptr;
struct proxy *px;
struct stktable *t;
if (!conn)
return 0;
@ -2719,17 +2748,17 @@ smp_fetch_src_updt_conn_cnt(const struct arg *args, struct sample *smp, const ch
return 0;
/* Converts into key. */
key = smp_to_stkey(smp, &args->data.prx->table);
key = smp_to_stkey(smp, args->data.t);
if (!key)
return 0;
px = args->data.prx;
t = args->data.t;
if ((ts = stktable_get_entry(&px->table, key)) == NULL)
if ((ts = stktable_get_entry(t, key)) == NULL)
/* entry does not exist and could not be created */
return 0;
ptr = stktable_data_ptr(&px->table, ts, STKTABLE_DT_CONN_CNT);
ptr = stktable_data_ptr(t, ts, STKTABLE_DT_CONN_CNT);
if (!ptr) {
return 0; /* parameter not stored in this table */
}
@ -2744,7 +2773,7 @@ smp_fetch_src_updt_conn_cnt(const struct arg *args, struct sample *smp, const ch
smp->flags = SMP_F_VOL_TEST;
stktable_touch_local(&px->table, ts, 1);
stktable_touch_local(t, ts, 1);
/* Touch was previously performed by stktable_update_key */
return 1;
@ -3229,12 +3258,12 @@ enum {
*/
static int table_dump_head_to_buffer(struct buffer *msg,
struct stream_interface *si,
struct proxy *proxy, struct proxy *target)
struct stktable *t, struct stktable *target)
{
struct stream *s = si_strm(si);
chunk_appendf(msg, "# table: %s, type: %s, size:%d, used:%d\n",
proxy->id, stktable_types[proxy->table.type].kw, proxy->table.size, proxy->table.current);
t->id, stktable_types[t->type].kw, t->size, t->current);
/* any other information should be dumped here */
@ -3255,32 +3284,32 @@ static int table_dump_head_to_buffer(struct buffer *msg,
*/
static int table_dump_entry_to_buffer(struct buffer *msg,
struct stream_interface *si,
struct proxy *proxy, struct stksess *entry)
struct stktable *t, struct stksess *entry)
{
int dt;
chunk_appendf(msg, "%p:", entry);
if (proxy->table.type == SMP_T_IPV4) {
if (t->type == SMP_T_IPV4) {
char addr[INET_ADDRSTRLEN];
inet_ntop(AF_INET, (const void *)&entry->key.key, addr, sizeof(addr));
chunk_appendf(msg, " key=%s", addr);
}
else if (proxy->table.type == SMP_T_IPV6) {
else if (t->type == SMP_T_IPV6) {
char addr[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, (const void *)&entry->key.key, addr, sizeof(addr));
chunk_appendf(msg, " key=%s", addr);
}
else if (proxy->table.type == SMP_T_SINT) {
else if (t->type == SMP_T_SINT) {
chunk_appendf(msg, " key=%u", *(unsigned int *)entry->key.key);
}
else if (proxy->table.type == SMP_T_STR) {
else if (t->type == SMP_T_STR) {
chunk_appendf(msg, " key=");
dump_text(msg, (const char *)entry->key.key, proxy->table.key_size);
dump_text(msg, (const char *)entry->key.key, t->key_size);
}
else {
chunk_appendf(msg, " key=");
dump_binary(msg, (const char *)entry->key.key, proxy->table.key_size);
dump_binary(msg, (const char *)entry->key.key, t->key_size);
}
chunk_appendf(msg, " use=%d exp=%d", entry->ref_cnt - 1, tick_remain(now_ms, entry->expire));
@ -3288,14 +3317,14 @@ static int table_dump_entry_to_buffer(struct buffer *msg,
for (dt = 0; dt < STKTABLE_DATA_TYPES; dt++) {
void *ptr;
if (proxy->table.data_ofs[dt] == 0)
if (t->data_ofs[dt] == 0)
continue;
if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
chunk_appendf(msg, " %s(%d)=", stktable_data_types[dt].name, proxy->table.data_arg[dt].u);
chunk_appendf(msg, " %s(%d)=", stktable_data_types[dt].name, t->data_arg[dt].u);
else
chunk_appendf(msg, " %s=", stktable_data_types[dt].name);
ptr = stktable_data_ptr(&proxy->table, entry, dt);
ptr = stktable_data_ptr(t, entry, dt);
switch (stktable_data_types[dt].std_type) {
case STD_T_SINT:
chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
@ -3309,7 +3338,7 @@ static int table_dump_entry_to_buffer(struct buffer *msg,
case STD_T_FRQP:
chunk_appendf(msg, "%d",
read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
proxy->table.data_arg[dt].u));
t->data_arg[dt].u));
break;
}
}
@ -3330,7 +3359,7 @@ static int table_dump_entry_to_buffer(struct buffer *msg,
static int table_process_entry_per_key(struct appctx *appctx, char **args)
{
struct stream_interface *si = appctx->owner;
struct proxy *px = appctx->ctx.table.target;
struct stktable *t = appctx->ctx.table.target;
struct stksess *ts;
uint32_t uint32_key;
unsigned char ip6_key[sizeof(struct in6_addr)];
@ -3347,7 +3376,7 @@ static int table_process_entry_per_key(struct appctx *appctx, char **args)
return 1;
}
switch (px->table.type) {
switch (t->type) {
case SMP_T_IPV4:
uint32_key = htonl(inetaddr_host(args[4]));
static_table_key.key = &uint32_key;
@ -3408,30 +3437,30 @@ static int table_process_entry_per_key(struct appctx *appctx, char **args)
switch (appctx->ctx.table.action) {
case STK_CLI_ACT_SHOW:
ts = stktable_lookup_key(&px->table, &static_table_key);
ts = stktable_lookup_key(t, &static_table_key);
if (!ts)
return 1;
chunk_reset(&trash);
if (!table_dump_head_to_buffer(&trash, si, px, px)) {
stktable_release(&px->table, ts);
if (!table_dump_head_to_buffer(&trash, si, t, t)) {
stktable_release(t, ts);
return 0;
}
HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &ts->lock);
if (!table_dump_entry_to_buffer(&trash, si, px, ts)) {
if (!table_dump_entry_to_buffer(&trash, si, t, ts)) {
HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
stktable_release(&px->table, ts);
stktable_release(t, ts);
return 0;
}
HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &ts->lock);
stktable_release(&px->table, ts);
stktable_release(t, ts);
break;
case STK_CLI_ACT_CLR:
ts = stktable_lookup_key(&px->table, &static_table_key);
ts = stktable_lookup_key(t, &static_table_key);
if (!ts)
return 1;
if (!stksess_kill(&px->table, ts, 1)) {
if (!stksess_kill(t, ts, 1)) {
/* don't delete an entry which is currently referenced */
appctx->ctx.cli.severity = LOG_ERR;
appctx->ctx.cli.msg = "Entry currently in use, cannot remove\n";
@ -3442,7 +3471,7 @@ static int table_process_entry_per_key(struct appctx *appctx, char **args)
break;
case STK_CLI_ACT_SET:
ts = stktable_get_entry(&px->table, &static_table_key);
ts = stktable_get_entry(t, &static_table_key);
if (!ts) {
/* don't delete an entry which is currently referenced */
appctx->ctx.cli.severity = LOG_ERR;
@ -3458,7 +3487,7 @@ static int table_process_entry_per_key(struct appctx *appctx, char **args)
appctx->ctx.cli.msg = "\"data.<type>\" followed by a value expected\n";
appctx->st0 = CLI_ST_PRINT;
HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
stktable_touch_local(&px->table, ts, 1);
stktable_touch_local(t, ts, 1);
return 1;
}
@ -3468,16 +3497,16 @@ static int table_process_entry_per_key(struct appctx *appctx, char **args)
appctx->ctx.cli.msg = "Unknown data type\n";
appctx->st0 = CLI_ST_PRINT;
HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
stktable_touch_local(&px->table, ts, 1);
stktable_touch_local(t, ts, 1);
return 1;
}
if (!px->table.data_ofs[data_type]) {
if (!t->data_ofs[data_type]) {
appctx->ctx.cli.severity = LOG_ERR;
appctx->ctx.cli.msg = "Data type not stored in this table\n";
appctx->st0 = CLI_ST_PRINT;
HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
stktable_touch_local(&px->table, ts, 1);
stktable_touch_local(t, ts, 1);
return 1;
}
@ -3486,11 +3515,11 @@ static int table_process_entry_per_key(struct appctx *appctx, char **args)
appctx->ctx.cli.msg = "Require a valid integer value to store\n";
appctx->st0 = CLI_ST_PRINT;
HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
stktable_touch_local(&px->table, ts, 1);
stktable_touch_local(t, ts, 1);
return 1;
}
ptr = stktable_data_ptr(&px->table, ts, data_type);
ptr = stktable_data_ptr(t, ts, data_type);
switch (stktable_data_types[data_type].std_type) {
case STD_T_SINT:
@ -3520,7 +3549,7 @@ static int table_process_entry_per_key(struct appctx *appctx, char **args)
}
}
HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
stktable_touch_local(&px->table, ts, 1);
stktable_touch_local(t, ts, 1);
break;
default:
@ -3553,7 +3582,7 @@ static int table_prepare_data_request(struct appctx *appctx, char **args)
return 1;
}
if (!((struct proxy *)appctx->ctx.table.target)->table.data_ofs[appctx->ctx.table.data_type]) {
if (!((struct proxy *)appctx->ctx.table.target)->table->data_ofs[appctx->ctx.table.data_type]) {
appctx->ctx.cli.severity = LOG_ERR;
appctx->ctx.cli.msg = "Data type not stored in this table\n";
appctx->st0 = CLI_ST_PRINT;
@ -3584,12 +3613,11 @@ static int cli_parse_table_req(char **args, char *payload, struct appctx *appctx
{
appctx->ctx.table.data_type = -1;
appctx->ctx.table.target = NULL;
appctx->ctx.table.proxy = NULL;
appctx->ctx.table.entry = NULL;
appctx->ctx.table.action = (long)private; // keyword argument, one of STK_CLI_ACT_*
if (*args[2]) {
appctx->ctx.table.target = proxy_tbl_by_name(args[2]);
appctx->ctx.table.target = stktable_find_by_name(args[2]);
if (!appctx->ctx.table.target) {
appctx->ctx.cli.severity = LOG_ERR;
appctx->ctx.cli.msg = "No such table\n";
@ -3663,7 +3691,7 @@ static int cli_io_handler_table(struct appctx *appctx)
if (unlikely(si_ic(si)->flags & (CF_WRITE_ERROR|CF_SHUTW))) {
/* in case of abort, remove any refcount we might have set on an entry */
if (appctx->st2 == STAT_ST_LIST) {
stksess_kill_if_expired(&appctx->ctx.table.proxy->table, appctx->ctx.table.entry, 1);
stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry, 1);
}
return 1;
}
@ -3673,42 +3701,42 @@ static int cli_io_handler_table(struct appctx *appctx)
while (appctx->st2 != STAT_ST_FIN) {
switch (appctx->st2) {
case STAT_ST_INIT:
appctx->ctx.table.proxy = appctx->ctx.table.target;
if (!appctx->ctx.table.proxy)
appctx->ctx.table.proxy = proxies_list;
appctx->ctx.table.t = appctx->ctx.table.target;
if (!appctx->ctx.table.t)
appctx->ctx.table.t = stktables_list;
appctx->ctx.table.entry = NULL;
appctx->st2 = STAT_ST_INFO;
break;
case STAT_ST_INFO:
if (!appctx->ctx.table.proxy ||
if (!appctx->ctx.table.t ||
(appctx->ctx.table.target &&
appctx->ctx.table.proxy != appctx->ctx.table.target)) {
appctx->ctx.table.t != appctx->ctx.table.target)) {
appctx->st2 = STAT_ST_END;
break;
}
if (appctx->ctx.table.proxy->table.size) {
if (show && !table_dump_head_to_buffer(&trash, si, appctx->ctx.table.proxy, appctx->ctx.table.target))
if (appctx->ctx.table.t->size) {
if (show && !table_dump_head_to_buffer(&trash, si, appctx->ctx.table.t, appctx->ctx.table.target))
return 0;
if (appctx->ctx.table.target &&
(strm_li(s)->bind_conf->level & ACCESS_LVL_MASK) >= ACCESS_LVL_OPER) {
/* dump entries only if table explicitly requested */
HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
eb = ebmb_first(&appctx->ctx.table.proxy->table.keys);
HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
eb = ebmb_first(&appctx->ctx.table.t->keys);
if (eb) {
appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
appctx->ctx.table.entry->ref_cnt++;
appctx->st2 = STAT_ST_LIST;
HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
break;
}
HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
}
}
appctx->ctx.table.proxy = appctx->ctx.table.proxy->next;
appctx->ctx.table.t = appctx->ctx.table.t->next;
break;
case STAT_ST_LIST:
@ -3723,7 +3751,7 @@ static int cli_io_handler_table(struct appctx *appctx)
dt = appctx->ctx.table.data_type;
ptr = stktable_data_ptr(&appctx->ctx.table.proxy->table,
ptr = stktable_data_ptr(appctx->ctx.table.t,
appctx->ctx.table.entry,
dt);
@ -3740,7 +3768,7 @@ static int cli_io_handler_table(struct appctx *appctx)
break;
case STD_T_FRQP:
data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
appctx->ctx.table.proxy->table.data_arg[dt].u);
appctx->ctx.table.t->data_arg[dt].u);
break;
}
@ -3761,14 +3789,14 @@ static int cli_io_handler_table(struct appctx *appctx)
}
if (show && !skip_entry &&
!table_dump_entry_to_buffer(&trash, si, appctx->ctx.table.proxy, appctx->ctx.table.entry)) {
!table_dump_entry_to_buffer(&trash, si, appctx->ctx.table.t, appctx->ctx.table.entry)) {
HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
return 0;
}
HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &appctx->ctx.table.entry->lock);
HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
HA_SPIN_LOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
appctx->ctx.table.entry->ref_cnt--;
eb = ebmb_next(&appctx->ctx.table.entry->key);
@ -3776,23 +3804,23 @@ static int cli_io_handler_table(struct appctx *appctx)
struct stksess *old = appctx->ctx.table.entry;
appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
if (show)
__stksess_kill_if_expired(&appctx->ctx.table.proxy->table, old);
__stksess_kill_if_expired(appctx->ctx.table.t, old);
else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
__stksess_kill(&appctx->ctx.table.proxy->table, old);
__stksess_kill(appctx->ctx.table.t, old);
appctx->ctx.table.entry->ref_cnt++;
HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
break;
}
if (show)
__stksess_kill_if_expired(&appctx->ctx.table.proxy->table, appctx->ctx.table.entry);
__stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry);
else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
__stksess_kill(&appctx->ctx.table.proxy->table, appctx->ctx.table.entry);
__stksess_kill(appctx->ctx.table.t, appctx->ctx.table.entry);
HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.proxy->table.lock);
HA_SPIN_UNLOCK(STK_TABLE_LOCK, &appctx->ctx.table.t->lock);
appctx->ctx.table.proxy = appctx->ctx.table.proxy->next;
appctx->ctx.table.t = appctx->ctx.table.t->next;
appctx->st2 = STAT_ST_INFO;
break;
@ -3807,7 +3835,7 @@ static int cli_io_handler_table(struct appctx *appctx)
static void cli_release_show_table(struct appctx *appctx)
{
if (appctx->st2 == STAT_ST_LIST) {
stksess_kill_if_expired(&appctx->ctx.table.proxy->table, appctx->ctx.table.entry, 1);
stksess_kill_if_expired(appctx->ctx.table.t, appctx->ctx.table.entry, 1);
}
}