]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: quic: define quic-socket bind setting
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Tue, 3 Oct 2023 12:16:26 +0000 (14:16 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Tue, 3 Oct 2023 14:49:26 +0000 (16:49 +0200)
Define a new bind option quic-socket :
  quic-socket [ connection | listener ]

This new setting works in conjunction with the existing configuration
global tune.quic.socket-owner and reuse the same semantics.

The purpose of this setting is to allow to disable connection socket
usage on listener instances individually. This will notably be useful
when needing to deactivating it when encountered a fatal permission
error on bind() at runtime.

doc/configuration.txt
include/haproxy/listener-t.h
include/haproxy/quic_sock-t.h
src/cfgparse-quic.c
src/listener.c
src/quic_conn.c

index e98f571f36ec1fcec388c6be9356237414a273f3..cd15e93aa2d4d1f23540dc41ef412518923b35e2 100644 (file)
@@ -3470,10 +3470,10 @@ tune.quic.retry-threshold <number>
   See https://www.rfc-editor.org/rfc/rfc9000.html#section-8.1.2 for more
   information about QUIC retry.
 
-tune.quic.socket-owner { listener | connection }
-  Specifies how QUIC connections will use socket for receive/send operations.
-  Connections can share listener socket or each connection can allocate its
-  own socket.
+tune.quic.socket-owner { connection | listener }
+  Specifies globally how QUIC connections will use socket for receive/send
+  operations. Connections can share listener socket or each connection can
+  allocate its own socket.
 
   When default "connection" value is set, a dedicated socket will be allocated
   by every QUIC connections. This option is the preferred one to achieve the
@@ -3493,6 +3493,12 @@ tune.quic.socket-owner { listener | connection }
   a higher CPU usage if listeners are shared across a lot of threads or a
   large number of QUIC connections can be used simultaneously.
 
+  This setting is applied in conjunction with each "quic-socket" bind options.
+  If "connection" mode is used on global tuning, it will be activated for each
+  listener, unless its bind option is set to "listener". However, if "listener"
+  is used globally, it will be forced on every listener instance, regardless of
+  their individual configuration.
+
 tune.rcvbuf.client <number>
 tune.rcvbuf.server <number>
   Forces the kernel socket receive buffer size on the client or the server side
@@ -15520,6 +15526,11 @@ quic-force-retry
   See https://www.rfc-editor.org/rfc/rfc9000.html#section-8.1.2 for more
   information about QUIC retry.
 
+quic-socket [ connection | listener ]
+  This QUIC specific setting allows to define the socket allocation mode for
+  the specific listeners. See "tune.quic.socket-owner" for a full description
+  of its usage.
+
 shards <number> | by-thread | by-group
   In multi-threaded mode, on operating systems supporting multiple listeners on
   the same IP:port, this will automatically create this number of multiple
index 8e02799a41e037534f767c5a5eac45b0e7ffb8c1..8c66dd00c1c261f50753488dd5fa36dbba7c4055 100644 (file)
@@ -30,6 +30,7 @@
 #include <haproxy/api-t.h>
 #include <haproxy/obj_type-t.h>
 #include <haproxy/quic_cc-t.h>
+#include <haproxy/quic_sock-t.h>
 #include <haproxy/quic_tp-t.h>
 #include <haproxy/receiver-t.h>
 #include <haproxy/stats-t.h>
@@ -183,6 +184,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 */
+       enum quic_sock_mode quic_mode;     /* QUIC socket allocation strategy */
 #endif
        struct proxy *frontend;    /* the frontend all these listeners belong to, or NULL */
        const struct mux_proto_list *mux_proto; /* the mux to use for all incoming connections (specified by the "proto" keyword) */
index 5a79b69b0d96f269a2fd849fd2708e60eb070387..364fdd1bf5998df9f85f05f0a0f568bfd68c7f39 100644 (file)
@@ -2,6 +2,12 @@
 #define _HAPROXY_QUIC_SOCK_T_H
 #ifdef USE_QUIC
 
+/* QUIC socket allocation strategy. */
+enum quic_sock_mode {
+       QUIC_SOCK_MODE_CONN,  /* Use a dedicated socket per connection. */
+       QUIC_SOCK_MODE_LSTNR, /* Multiplex connections over listener socket. */
+};
+
 /* QUIC connection accept queue. One per thread. */
 struct quic_accept_queue {
        struct mt_list listeners; /* QUIC listeners with at least one connection ready to be accepted on this queue */
index c8cb7d9630c133d863bb111bea5b056d48b212c5..a49a468236b5c6667f2726fad8ff6e1c304ab9e4 100644 (file)
@@ -50,9 +50,34 @@ static int bind_parse_quic_cc_algo(char **args, int cur_arg, struct proxy *px,
        return 0;
 }
 
+static int bind_parse_quic_socket(char **args, int cur_arg, struct proxy *px,
+                                  struct bind_conf *conf, char **err)
+{
+       char *arg;
+       if (!*args[cur_arg + 1]) {
+               memprintf(err, "'%s' : missing argument, use either connection or listener.", args[cur_arg]);
+               return ERR_ALERT | ERR_FATAL;
+       }
+
+       arg = args[cur_arg + 1];
+       if (strcmp(arg, "connection") == 0) {
+               conf->quic_mode = QUIC_SOCK_MODE_CONN;
+       }
+       else if (strcmp(arg, "listener") == 0) {
+               conf->quic_mode = QUIC_SOCK_MODE_LSTNR;
+       }
+       else {
+               memprintf(err, "'%s' : unknown argument, use either connection or listener.", args[cur_arg]);
+               return ERR_ALERT | ERR_FATAL;
+       }
+
+       return 0;
+}
+
 static struct bind_kw_list bind_kws = { "QUIC", { }, {
        { "quic-force-retry", bind_parse_quic_force_retry, 0 },
        { "quic-cc-algo", bind_parse_quic_cc_algo, 1 },
+       { "quic-socket", bind_parse_quic_socket, 1 },
        { NULL, NULL, 0 },
 }};
 
index 434291476bff9a12866d2dbfddd27570a93511b6..da483702ed7194c84ec054a0ef7c373374518fa1 100644 (file)
@@ -1947,6 +1947,10 @@ struct bind_conf *bind_conf_alloc(struct proxy *fe, const char *file,
        HA_RWLOCK_INIT(&bind_conf->sni_lock);
        bind_conf->sni_ctx = EB_ROOT;
        bind_conf->sni_w_ctx = EB_ROOT;
+#endif
+#ifdef USE_QUIC
+       /* Use connection socket for QUIC by default. */
+       bind_conf->quic_mode = QUIC_SOCK_MODE_CONN;
 #endif
        LIST_INIT(&bind_conf->listeners);
 
index 051c9da579eb42d46c696560dd8f119a455d04e5..a2d28c7b049358f2079171da44e4e244b2086930 100644 (file)
@@ -1264,7 +1264,8 @@ struct quic_conn *qc_new_conn(const struct quic_version *qv, int ipv4,
 
        conn_id->qc = qc;
 
-       if ((global.tune.options & GTUNE_QUIC_SOCK_PER_CONN) &&
+       if (l->bind_conf->quic_mode == QUIC_SOCK_MODE_CONN &&
+           (global.tune.options & GTUNE_QUIC_SOCK_PER_CONN) &&
            is_addr(local_addr)) {
                TRACE_USER("Allocate a socket for QUIC connection", QUIC_EV_CONN_INIT, qc);
                qc_alloc_fd(qc, local_addr, peer_addr);