]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: quic: Add a max window parameter to congestion control algorithms
authorFrédéric Lécaille <flecaille@haproxy.com>
Mon, 13 Nov 2023 14:50:53 +0000 (15:50 +0100)
committerFrédéric Lécaille <flecaille@haproxy.com>
Mon, 13 Nov 2023 16:53:18 +0000 (17:53 +0100)
Add a new ->max_cwnd member to bind_conf struct to store the maximum
congestion control window value for each QUIC binding.
Modify the "quic-cc-algo" keyword parsing to add an optional parameter
to its value: the maximum congestion window value between parentheses
as follows:

      ex: quic-cc-algo cubic(10m)

This value must be bounded, greater than 10k and smaller than 1g.

include/haproxy/listener-t.h
src/cfgparse-quic.c
src/listener.c

index 93856db55a81dbff87610d448a346aa00a77e8e8..c1ab05111c34b2218e6a51a6a4f65030204275a1 100644 (file)
@@ -186,6 +186,7 @@ struct bind_conf {
 #ifdef USE_QUIC
        struct quic_transport_params quic_params; /* QUIC transport parameters. */
        struct quic_cc_algo *quic_cc_algo; /* QUIC control congestion algorithm */
+       size_t max_cwnd;                   /* QUIC maximumu congestion control window size (kB) */
        enum quic_sock_mode quic_mode;     /* QUIC socket allocation strategy */
 #endif
        struct proxy *frontend;    /* the frontend all these listeners belong to, or NULL */
index a49a468236b5c6667f2726fad8ff6e1c304ab9e4..6ca83c8123a25e42d11df40c10ce9d52c9e5ad6b 100644 (file)
@@ -1,3 +1,4 @@
+#include <errno.h>
 #include <string.h>
 
 #include <haproxy/api.h>
@@ -20,34 +21,89 @@ static int bind_parse_quic_cc_algo(char **args, int cur_arg, struct proxy *px,
                                    struct bind_conf *conf, char **err)
 {
        struct quic_cc_algo *cc_algo;
+       const char *newreno = "newrno";
+       const char *cubic = "cubic";
+       const char *nocc = "nocc";
+       const char *algo = NULL;
        char *arg;
 
        if (!*args[cur_arg + 1]) {
                memprintf(err, "'%s' : missing control congestion algorithm", args[cur_arg]);
-               return ERR_ALERT | ERR_FATAL;
+               goto fail;
        }
 
        arg = args[cur_arg + 1];
-       if (strcmp(arg, "newreno") == 0)
-           cc_algo = &quic_cc_algo_nr;
-       else if (strcmp(arg, "cubic") == 0)
-           cc_algo = &quic_cc_algo_cubic;
-       else if (strlen(arg) >= 6 && strncmp(arg, "nocc-", 5) == 0) {
+       if (strncmp(arg, newreno, strlen(newreno)) == 0) {
+               /* newreno */
+               algo = newreno;
+               cc_algo = &quic_cc_algo_nr;
+               arg += strlen(newreno);
+       }
+       else if (strncmp(arg, cubic, strlen(cubic)) == 0) {
+               /* cubic */
+               algo = cubic;
+               cc_algo = &quic_cc_algo_cubic;
+               arg += strlen(cubic);
+       }
+       else if (strncmp(arg, nocc, strlen(nocc)) == 0) {
+               /* nocc */
                if (!experimental_directives_allowed) {
-                       ha_alert("'%s' algo is experimental, must be allowed via a global 'expose-experimental-directives'\n", arg);
-                       return ERR_ALERT | ERR_FATAL;
+                       ha_alert("'%s' algo is experimental, must be allowed via a global "
+                                "'expose-experimental-directives'\n", arg);
+                       goto fail;
                }
 
-           cc_algo = &quic_cc_algo_nocc;
-           quic_cc_nocc_fixed_cwnd = atoi(arg + 5);
+               algo = nocc;
+               cc_algo = &quic_cc_algo_nocc;
+               arg += strlen(nocc);
        }
        else {
-               memprintf(err, "'%s' : unknown control congestion algorithm", args[cur_arg]);
-               return ERR_ALERT | ERR_FATAL;
+               memprintf(err, "'%s' : unknown control congestion algorithm", args[cur_arg + 1]);
+               goto fail;
+       }
+
+       if (*arg++ == '(') {
+               unsigned long cwnd;
+               char *end_opt;
+
+               errno = 0;
+               cwnd = strtoul(arg, &end_opt, 0);
+               if (end_opt == arg || errno != 0) {
+                       memprintf(err, "'%s' : could not parse congestion window value", args[cur_arg + 1]);
+                       goto fail;
+               }
+
+               if (*end_opt == 'k') {
+                       cwnd <<= 10;
+                       end_opt++;
+               }
+               else if (*end_opt == 'm') {
+                       cwnd <<= 20;
+                       end_opt++;
+               }
+               else if (*end_opt == 'g') {
+                       memprintf(err, "'%s' : should be smaller than 1g", args[cur_arg + 1]);
+                       goto fail;
+               }
+
+               if (*end_opt != ')') {
+                       memprintf(err, "'%s' : expects %s(<max window>)", args[cur_arg + 1], algo);
+                       goto fail;
+               }
+
+               if (cwnd < 10240 || cwnd >= (4UL << 30)) {
+                       memprintf(err, "'%s' : should be greater than 10k and smaller than 4g", args[cur_arg + 1]);
+                       goto fail;
+               }
+
+               conf->max_cwnd = cwnd;
        }
 
        conf->quic_cc_algo = cc_algo;
        return 0;
+
+ fail:
+       return ERR_ALERT | ERR_FATAL;
 }
 
 static int bind_parse_quic_socket(char **args, int cur_arg, struct proxy *px,
index 64d3aa038f7f8b94fdfe8d020bf4480b1643212e..bde09cc70d2de5dc4ef6ee8cf1a3bc53c9b87ad4 100644 (file)
@@ -1954,6 +1954,8 @@ struct bind_conf *bind_conf_alloc(struct proxy *fe, const char *file,
 #ifdef USE_QUIC
        /* Use connection socket for QUIC by default. */
        bind_conf->quic_mode = QUIC_SOCK_MODE_CONN;
+       bind_conf->max_cwnd =
+               global.tune.bufsize * global.tune.quic_streams_buf;
 #endif
        LIST_INIT(&bind_conf->listeners);