]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: stats/cli: add support for "set table key" to enter values
authorWilly Tarreau <w@1wt.eu>
Wed, 6 Jun 2012 23:03:16 +0000 (01:03 +0200)
committerWilly Tarreau <w@1wt.eu>
Sun, 2 Sep 2012 19:51:07 +0000 (21:51 +0200)
This is used to enter values for stick tables. The most likely usage
is to set gpc0 for a specific IP address in order to block traffic
for abusers without having to reload. Since all data types are
supported, other usages are possible (eg: replace a users's assigned
server).

doc/configuration.txt
include/proto/dumpstats.h
src/dumpstats.c

index d13ab3a2d96db324f2ca914ee7f5903caaef6943..3fa6dabbc5f804bf7cf91ea222c2c4329c5711ff 100644 (file)
@@ -10262,6 +10262,13 @@ set rate-limit connections global <value>
   applies to all frontends and the change has an immediate effect. The value
   is passed in number of connections per second.
 
+set table <table> key <key> data.<data_type> <value>
+  Create or update a stick-table entry in the table. If the key is not present,
+  an entry is inserted. See stick-table in section 4.2 to find all possible
+  values for <data_type>. The most likely use consists in dynamically entering
+  entries for source IP addresses, with a flag in gpc0 to dynamically block an
+  IP address or affect its quality of service.
+
 set timeout cli <delay>
   Change the CLI interface timeout for current connection. This can be useful
   during long debugging sessions where the user needs to constantly inspect
index 319ab48ec89fcddf322e9edc4a724af7647f3436..449ddc183919bf117aa494e99444f49d9796ac88 100644 (file)
@@ -54,6 +54,7 @@
 #define STAT_CLI_O_ERR  7   /* dump errors */
 #define STAT_CLI_O_TAB  8   /* dump tables */
 #define STAT_CLI_O_CLR  9   /* clear tables */
+#define STAT_CLI_O_SET  10  /* set entries in tables */
 
 extern struct si_applet http_stats_applet;
 
index f32e4c57edb47b7bc880ccc1fca16004b83feac0..a125242c1852ae8bb6d1e2aa1fb240a1b0ed2e59 100644 (file)
@@ -80,6 +80,7 @@ static const char stats_sock_usage_msg[] =
        "  show table [id]: report table usage stats or dump this table's contents\n"
        "  get weight     : report a server's current weight\n"
        "  set weight     : change a server's weight\n"
+       "  set table [id] : update or create a table entry's data\n"
        "  set timeout    : change a timeout setting\n"
        "  set maxconn    : change a maxconn setting\n"
        "  set rate-limit : change a rate limiting value\n"
@@ -513,6 +514,10 @@ static void stats_sock_table_key_request(struct stream_interface *si, char **arg
        uint32_t uint32_key;
        unsigned char ip6_key[sizeof(struct in6_addr)];
        struct chunk msg;
+       long long value;
+       int data_type;
+       void *ptr;
+       struct freq_ctr_period *frqp;
 
        si->applet.st0 = STAT_CLI_OUTPUT;
 
@@ -600,6 +605,66 @@ static void stats_sock_table_key_request(struct stream_interface *si, char **arg
                stksess_kill(&px->table, ts);
                break;
 
+       case STAT_CLI_O_SET:
+               if (strncmp(args[5], "data.", 5) != 0) {
+                       si->applet.ctx.cli.msg = "\"data.<type>\" followed by a value expected\n";
+                       si->applet.st0 = STAT_CLI_PRINT;
+                       return;
+               }
+
+               data_type = stktable_get_data_type(args[5] + 5);
+               if (data_type < 0) {
+                       si->applet.ctx.cli.msg = "Unknown data type\n";
+                       si->applet.st0 = STAT_CLI_PRINT;
+                       return;
+               }
+
+               if (!px->table.data_ofs[data_type]) {
+                       si->applet.ctx.cli.msg = "Data type not stored in this table\n";
+                       si->applet.st0 = STAT_CLI_PRINT;
+                       return;
+               }
+
+               if (!*args[6] || strl2llrc(args[6], strlen(args[6]), &value) != 0) {
+                       si->applet.ctx.cli.msg = "Require a valid integer value to store\n";
+                       si->applet.st0 = STAT_CLI_PRINT;
+                       return;
+               }
+
+               if (ts)
+                       stktable_touch(&px->table, ts, 1);
+               else {
+                       ts = stksess_new(&px->table, &static_table_key);
+                       if (!ts) {
+                               /* don't delete an entry which is currently referenced */
+                               si->applet.ctx.cli.msg = "Unable to allocate a new entry\n";
+                               si->applet.st0 = STAT_CLI_PRINT;
+                               return;
+                       }
+                       stktable_store(&px->table, ts, 1);
+               }
+
+               ptr = stktable_data_ptr(&px->table, ts, data_type);
+               switch (stktable_data_types[data_type].std_type) {
+               case STD_T_SINT:
+                       stktable_data_cast(ptr, std_t_sint) = value;
+                       break;
+               case STD_T_UINT:
+                       stktable_data_cast(ptr, std_t_uint) = value;
+                       break;
+               case STD_T_ULL:
+                       stktable_data_cast(ptr, std_t_ull) = value;
+                       break;
+               case STD_T_FRQP:
+                       /* We only reset the previous value so that it slowly fades out */
+                       frqp = &stktable_data_cast(ptr, std_t_frqp);
+                       frqp->curr_tick = now_ms;
+                       frqp->prev_ctr = value;
+                       frqp->curr_ctr = 0;
+                       break;
+               }
+               break;
+
        default:
                si->applet.ctx.cli.msg = "Unknown action\n";
                si->applet.st0 = STAT_CLI_PRINT;
@@ -607,8 +672,14 @@ static void stats_sock_table_key_request(struct stream_interface *si, char **arg
        }
 }
 
-static void stats_sock_table_data_request(struct stream_interface *si, char **args)
+static void stats_sock_table_data_request(struct stream_interface *si, char **args, int action)
 {
+       if (action != STAT_CLI_O_TAB) {
+               si->applet.ctx.cli.msg = "content-based lookup is only supported with the \"show\" action";
+               si->applet.st0 = STAT_CLI_PRINT;
+               return;
+       }
+
        /* condition on stored data value */
        si->applet.ctx.table.data_type = stktable_get_data_type(args[3] + 5);
        if (si->applet.ctx.table.data_type < 0) {
@@ -663,7 +734,7 @@ static void stats_sock_table_request(struct stream_interface *si, char **args, i
        if (strcmp(args[3], "key") == 0)
                stats_sock_table_key_request(si, args, action);
        else if (strncmp(args[3], "data.", 5) == 0)
-               stats_sock_table_data_request(si, args);
+               stats_sock_table_data_request(si, args, action);
        else if (*args[3])
                goto err_args;
 
@@ -1171,6 +1242,9 @@ static int stats_sock_parse_request(struct stream_interface *si, char *line)
                                return 1;
                        }
                }
+               else if (strcmp(args[1], "table") == 0) {
+                       stats_sock_table_request(si, args, STAT_CLI_O_SET);
+               }
                else { /* unknown "set" parameter */
                        return 0;
                }