]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: stick-table: handle arrays of standard types into stick-tables
authorEmeric Brun <ebrun@haproxy.com>
Wed, 30 Jun 2021 16:01:02 +0000 (18:01 +0200)
committerWilly Tarreau <w@1wt.eu>
Tue, 6 Jul 2021 05:24:42 +0000 (07:24 +0200)
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.

include/haproxy/errors.h
include/haproxy/stick_table-t.h
include/haproxy/stick_table.h
src/cfgparse.c
src/stick_table.c

index bebad844af37fe21ad8637c77ff109cd071960ed..e9ad588357a697fe73f96fde4f0dabc8cf13111b 100644 (file)
@@ -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 */
 };
 
 
index f09956aaf21145da220de4b504104baa4ff3bb0f..89d1b2a2a3f0690b22736f380a95a207f8bb982f 100644 (file)
@@ -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;
index 4dffe2a854309e9b5647eaaa8cc86061817a851d..ff172f45845dc90082c11f25a2adbb0566c1003f 100644 (file)
@@ -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)
 {
index aa07a2fd10e1edd74cfc57362be89367a5f59f29..6bf8e6d59c63d111accff76c28d7c03230e85d6a 100644 (file)
@@ -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;
index 73c8fc184fa99d94abb4e7e1aa3d49430db10e41..349e138c8f50db683a17b0a6ed29082dd985c513 100644 (file)
@@ -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