mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-07 07:37:02 +02:00
MEDIUM: stick-table: handle arrays of standard types into stick-tables
This patch provides the code to handle arrays of some standard types (SINT, UINT, ULL and FRQP) in stick table. This way we could define new "array" data types. Note: the number of elements of an array was limited to 100 to put a limit and to ensure that an encoded update message will continue to fit into a buffer when the peer protocol will handle such data types.
This commit is contained in:
parent
0e3457b63a
commit
c64a2a307c
@ -60,6 +60,7 @@ enum {
|
||||
PE_ARG_INVC, /* invalid char in argument (pointer not provided) */
|
||||
PE_ARG_INVC_PTR, /* invalid char in argument (pointer provided) */
|
||||
PE_ARG_NOT_FOUND, /* argument references something not found */
|
||||
PE_ARG_VALUE_OOR, /* argument value is out of range */
|
||||
};
|
||||
|
||||
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include <haproxy/freq_ctr-t.h>
|
||||
#include <haproxy/thread-t.h>
|
||||
|
||||
#define STKTABLE_MAX_DT_ARRAY_SIZE 100
|
||||
|
||||
/* The types of extra data we can store in a stick table */
|
||||
enum {
|
||||
@ -125,6 +126,7 @@ struct stktable_data_type {
|
||||
const char *name; /* name of the data type */
|
||||
int std_type; /* standard type we can use for this data, STD_T_* */
|
||||
int arg_type; /* type of optional argument, ARG_T_* */
|
||||
int is_array;
|
||||
};
|
||||
|
||||
/* stick table keyword type */
|
||||
@ -185,6 +187,7 @@ struct stktable {
|
||||
int expire; /* time to live for sticky sessions (milliseconds) */
|
||||
int data_size; /* the size of the data that is prepended *before* stksess */
|
||||
int data_ofs[STKTABLE_DATA_TYPES]; /* negative offsets of present data types, or 0 if absent */
|
||||
unsigned int data_nbelem[STKTABLE_DATA_TYPES]; /* to store nb_elem in case of array types */
|
||||
union {
|
||||
int i;
|
||||
unsigned int u;
|
||||
|
@ -136,7 +136,7 @@ static inline int stktable_type_size(int type)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stktable_alloc_data_type(struct stktable *t, int type, const char *sa);
|
||||
int stktable_alloc_data_type(struct stktable *t, int type, const char *sa, const char *sa2);
|
||||
|
||||
/* return pointer for data type <type> in sticky session <ts> of table <t>, all
|
||||
* of which must exist (otherwise use stktable_data_ptr() if unsure).
|
||||
@ -163,6 +163,31 @@ static inline void *stktable_data_ptr(struct stktable *t, struct stksess *ts, in
|
||||
return __stktable_data_ptr(t, ts, type);
|
||||
}
|
||||
|
||||
/* return pointer on the element of index <idx> from the array data type <type>
|
||||
* in sticky session <ts> of table <t>, or NULL if either <ts> is NULL
|
||||
* or this element is not stored because this type is not stored or
|
||||
* requested index is greater than the number of elements of the array.
|
||||
* Note: this function is also usable on non array types, they are
|
||||
* considered as array of size 1, so a call with <idx> at 0
|
||||
* as the same behavior than 'stktable_data_ptr'.
|
||||
*/
|
||||
static inline void *stktable_data_ptr_idx(struct stktable *t, struct stksess *ts, int type, unsigned int idx)
|
||||
{
|
||||
if (type >= STKTABLE_DATA_TYPES)
|
||||
return NULL;
|
||||
|
||||
if (!t->data_ofs[type]) /* type not stored */
|
||||
return NULL;
|
||||
|
||||
if (!ts)
|
||||
return NULL;
|
||||
|
||||
if (t->data_nbelem[type] <= idx)
|
||||
return NULL;
|
||||
|
||||
return __stktable_data_ptr(t, ts, type) + idx*stktable_type_size(stktable_data_types[type].std_type);
|
||||
}
|
||||
|
||||
/* kill an entry if it's expired and its ref_cnt is zero */
|
||||
static inline int __stksess_kill_if_expired(struct stktable *t, struct stksess *ts)
|
||||
{
|
||||
|
@ -3028,8 +3028,8 @@ int check_config_validity()
|
||||
else {
|
||||
ha_free(&mrule->table.name);
|
||||
mrule->table.t = target;
|
||||
stktable_alloc_data_type(target, STKTABLE_DT_SERVER_ID, NULL);
|
||||
stktable_alloc_data_type(target, STKTABLE_DT_SERVER_KEY, NULL);
|
||||
stktable_alloc_data_type(target, STKTABLE_DT_SERVER_ID, NULL, NULL);
|
||||
stktable_alloc_data_type(target, STKTABLE_DT_SERVER_KEY, NULL, NULL);
|
||||
if (!in_proxies_list(target->proxies_list, curproxy)) {
|
||||
curproxy->next_stkt_ref = target->proxies_list;
|
||||
target->proxies_list = curproxy;
|
||||
@ -3062,8 +3062,8 @@ int check_config_validity()
|
||||
else {
|
||||
ha_free(&mrule->table.name);
|
||||
mrule->table.t = target;
|
||||
stktable_alloc_data_type(target, STKTABLE_DT_SERVER_ID, NULL);
|
||||
stktable_alloc_data_type(target, STKTABLE_DT_SERVER_KEY, NULL);
|
||||
stktable_alloc_data_type(target, STKTABLE_DT_SERVER_ID, NULL, NULL);
|
||||
stktable_alloc_data_type(target, STKTABLE_DT_SERVER_KEY, NULL, NULL);
|
||||
if (!in_proxies_list(target->proxies_list, curproxy)) {
|
||||
curproxy->next_stkt_ref = target->proxies_list;
|
||||
target->proxies_list = curproxy;
|
||||
|
@ -708,14 +708,18 @@ int stktable_parse_type(char **args, int *myidx, unsigned long *type, size_t *ke
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* reserve some space for data type <type>, and associate argument at <sa> if
|
||||
* not NULL. Returns PE_NONE (0) if OK or an error code among :
|
||||
/* reserve some space for data type <type>, there is 2 optionnals
|
||||
* argument at <sa> and <sa2> to configure this data type and
|
||||
* they can be NULL if unused for a given type.
|
||||
* Returns PE_NONE (0) if OK or an error code among :
|
||||
* - PE_ENUM_OOR if <type> does not exist
|
||||
* - PE_EXIST if <type> is already registered
|
||||
* - PE_ARG_NOT_USE if <sa> was provided but not expected
|
||||
* - PE_ARG_MISSING if <sa> was expected but not provided
|
||||
* - PE_ARG_NOT_USE if <sa>/<sa2> was provided but not expected
|
||||
* - PE_ARG_MISSING if <sa>/<sa2> was expected but not provided
|
||||
* - PE_ARG_VALUE_OOR if type is an array and <sa> it out of array size range.
|
||||
*/
|
||||
int stktable_alloc_data_type(struct stktable *t, int type, const char *sa)
|
||||
int stktable_alloc_data_type(struct stktable *t, int type, const char *sa, const char *sa2)
|
||||
|
||||
{
|
||||
if (type >= STKTABLE_DATA_TYPES)
|
||||
return PE_ENUM_OOR;
|
||||
@ -724,6 +728,17 @@ int stktable_alloc_data_type(struct stktable *t, int type, const char *sa)
|
||||
/* already allocated */
|
||||
return PE_EXIST;
|
||||
|
||||
t->data_nbelem[type] = 1;
|
||||
if (stktable_data_types[type].is_array) {
|
||||
/* arrays take their element count on first argument */
|
||||
if (!sa)
|
||||
return PE_ARG_MISSING;
|
||||
t->data_nbelem[type] = atoi(sa);
|
||||
if (!t->data_nbelem[type] || (t->data_nbelem[type] > STKTABLE_MAX_DT_ARRAY_SIZE))
|
||||
return PE_ARG_VALUE_OOR;
|
||||
sa = sa2;
|
||||
}
|
||||
|
||||
switch (stktable_data_types[type].arg_type) {
|
||||
case ARG_T_NONE:
|
||||
if (sa)
|
||||
@ -743,7 +758,7 @@ int stktable_alloc_data_type(struct stktable *t, int type, const char *sa)
|
||||
break;
|
||||
}
|
||||
|
||||
t->data_size += stktable_type_size(stktable_data_types[type].std_type);
|
||||
t->data_size += t->data_nbelem[type] * stktable_type_size(stktable_data_types[type].std_type);
|
||||
t->data_ofs[type] = -t->data_size;
|
||||
return PE_NONE;
|
||||
}
|
||||
@ -860,7 +875,7 @@ int parse_stick_table(const char *file, int linenum, char **args,
|
||||
}
|
||||
else if (strcmp(args[idx], "store") == 0) {
|
||||
int type, err;
|
||||
char *cw, *nw, *sa;
|
||||
char *cw, *nw, *sa, *sa2;
|
||||
|
||||
idx++;
|
||||
nw = args[idx];
|
||||
@ -868,6 +883,7 @@ int parse_stick_table(const char *file, int linenum, char **args,
|
||||
/* the "store" keyword supports a comma-separated list */
|
||||
cw = nw;
|
||||
sa = NULL; /* store arg */
|
||||
sa2 = NULL;
|
||||
while (*nw && *nw != ',') {
|
||||
if (*nw == '(') {
|
||||
*nw = 0;
|
||||
@ -879,6 +895,10 @@ int parse_stick_table(const char *file, int linenum, char **args,
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
if (*nw == ',') {
|
||||
*nw = '\0';
|
||||
sa2 = nw + 1;
|
||||
}
|
||||
nw++;
|
||||
}
|
||||
*nw = '\0';
|
||||
@ -895,7 +915,7 @@ int parse_stick_table(const char *file, int linenum, char **args,
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = stktable_alloc_data_type(t, type, sa);
|
||||
err = stktable_alloc_data_type(t, type, sa, sa2);
|
||||
switch (err) {
|
||||
case PE_NONE: break;
|
||||
case PE_EXIST:
|
||||
@ -915,6 +935,11 @@ int parse_stick_table(const char *file, int linenum, char **args,
|
||||
file, linenum, args[0], cw);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
case PE_ARG_VALUE_OOR:
|
||||
ha_alert("parsing [%s:%d] : %s: array size is out of allowed range (1-%d) for store option '%s'.\n",
|
||||
file, linenum, args[0], STKTABLE_MAX_DT_ARRAY_SIZE, cw);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
|
||||
default:
|
||||
ha_alert("parsing [%s:%d] : %s: error when processing store option '%s'.\n",
|
||||
@ -3614,6 +3639,53 @@ static int table_dump_entry_to_buffer(struct buffer *msg,
|
||||
|
||||
if (t->data_ofs[dt] == 0)
|
||||
continue;
|
||||
if (stktable_data_types[dt].is_array) {
|
||||
char tmp[16] = {};
|
||||
const char *name_pfx = stktable_data_types[dt].name;
|
||||
const char *name_sfx = NULL;
|
||||
unsigned int idx = 0;
|
||||
int i = 0;
|
||||
|
||||
/* split name to show index before first _ of the name
|
||||
* for example: 'gpc3_rate' if array name is 'gpc_rate'.
|
||||
*/
|
||||
for (i = 0 ; i < (sizeof(tmp) - 1); i++) {
|
||||
if (!name_pfx[i])
|
||||
break;
|
||||
if (name_pfx[i] == '_') {
|
||||
name_pfx = &tmp[0];
|
||||
name_sfx = &stktable_data_types[dt].name[i];
|
||||
break;
|
||||
}
|
||||
tmp[i] = name_pfx[i];
|
||||
}
|
||||
|
||||
ptr = stktable_data_ptr_idx(t, entry, dt, idx);
|
||||
while (ptr) {
|
||||
if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
|
||||
chunk_appendf(msg, " %s%u%s(%u)=", name_pfx, idx, name_sfx ? name_sfx : "", t->data_arg[dt].u);
|
||||
else
|
||||
chunk_appendf(msg, " %s%u%s=", name_pfx, idx, name_sfx ? name_sfx : "");
|
||||
switch (stktable_data_types[dt].std_type) {
|
||||
case STD_T_SINT:
|
||||
chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
|
||||
break;
|
||||
case STD_T_UINT:
|
||||
chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
|
||||
break;
|
||||
case STD_T_ULL:
|
||||
chunk_appendf(msg, "%llu", stktable_data_cast(ptr, std_t_ull));
|
||||
break;
|
||||
case STD_T_FRQP:
|
||||
chunk_appendf(msg, "%u",
|
||||
read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
|
||||
t->data_arg[dt].u));
|
||||
break;
|
||||
}
|
||||
ptr = stktable_data_ptr_idx(t, entry, dt, ++idx);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
|
||||
chunk_appendf(msg, " %s(%u)=", stktable_data_types[dt].name, t->data_arg[dt].u);
|
||||
else
|
||||
|
Loading…
Reference in New Issue
Block a user