]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: quic: allocate a socket per quic-conn
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Mon, 24 Oct 2022 15:08:43 +0000 (17:08 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Fri, 2 Dec 2022 13:45:43 +0000 (14:45 +0100)
Allocate quic-conn owned socket if possible. This requires that this is
activated in haproxy configuration. Also, this is done only if local
address is known so it depends on the support of IP_PKTINFO.

For the moment this socket is not used. This causes QUIC support to be
broken as received datagram are not read. This commit will be completed
by a following patch to support recv operation on the newly allocated
socket.

This change is part of quic-conn owned socket implementation.
It may be backported to 2.7 after a period of observation.

include/haproxy/quic_conn-t.h
include/haproxy/quic_sock.h
src/quic_conn.c
src/quic_sock.c

index 119adf88c8e06665e2d036942d3cf8081b70ea60..1a4571d2bbfe83ea7c9f03484ce6c2da31280d29 100644 (file)
@@ -625,6 +625,8 @@ struct quic_conn {
        const struct quic_version *negotiated_version;
        /* Negotiated version Initial TLS context */
        struct quic_tls_ctx negotiated_ictx;
+       /* Connection owned socket FD. */
+       int fd;
        /* QUIC transport parameters TLS extension */
        int tps_tls_ext;
        /* Thread ID this connection is attached to */
index eeec932237ad4ae40ae949bbf6ad48fb19571c3e..2788a230553f1437067db202f07f7aa7ec0ee39b 100644 (file)
@@ -32,6 +32,7 @@
 #include <haproxy/api.h>
 #include <haproxy/connection-t.h>
 #include <haproxy/listener-t.h>
+#include <haproxy/quic_conn-t.h>
 #include <haproxy/quic_sock-t.h>
 
 int quic_session_accept(struct connection *cli_conn);
@@ -45,6 +46,24 @@ void quic_sock_fd_iocb(int fd);
 int qc_snd_buf(struct quic_conn *qc, const struct buffer *buf, size_t count,
                int flags);
 
+/* Set default value for <qc> socket as uninitialized. */
+static inline void qc_init_fd(struct quic_conn *qc)
+{
+       qc->fd = -1;
+}
+
+/* Returns true if <qc> socket is initialized else false. */
+static inline char qc_test_fd(struct quic_conn *qc)
+{
+       /* quic-conn socket should not be accessed once it has been released. */
+       BUG_ON(qc->fd == DEAD_FD_MAGIC);
+       return qc->fd >= 0;
+}
+
+void qc_alloc_fd(struct quic_conn *qc, const struct sockaddr_storage *src,
+                 const struct sockaddr_storage *dst);
+void qc_release_fd(struct quic_conn *qc);
+
 void quic_accept_push_qc(struct quic_conn *qc);
 
 #endif /* USE_QUIC */
index 5a011eb5f8f18c44f2359a7d957011c13fa8d4e5..5c48b55d390ddbdcfd1c3d7d1cb37af810645998 100644 (file)
@@ -4817,6 +4817,15 @@ static struct quic_conn *qc_new_conn(const struct quic_version *qv, int ipv4,
                goto err;
        }
 
+       if ((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);
+       }
+       else {
+               qc_init_fd(qc);
+       }
+
        /* insert the allocated CID in the receiver datagram handler tree */
        if (server)
                ebmb_insert(&quic_dghdlrs[tid].cids, &icid->node, icid->cid.len);
@@ -4936,6 +4945,9 @@ void quic_conn_release(struct quic_conn *qc)
        /* We must not free the quic-conn if the MUX is still allocated. */
        BUG_ON(qc->mux_state == QC_MUX_READY);
 
+       /* Close quic-conn socket fd. */
+       qc_release_fd(qc);
+
        /* in the unlikely (but possible) case the connection was just added to
         * the accept_list we must delete it from there.
         */
index 10e8b3f9cc8697da37583c07e2d1f285e3bfe6f6..bce8a1b1aedcd56bb59ce00f84c84a0357b88a3b 100644 (file)
@@ -27,6 +27,7 @@
 #include <haproxy/global-t.h>
 #include <haproxy/list.h>
 #include <haproxy/listener.h>
+#include <haproxy/log.h>
 #include <haproxy/pool.h>
 #include <haproxy/proto_quic.h>
 #include <haproxy/proxy-t.h>
@@ -531,6 +532,81 @@ int qc_snd_buf(struct quic_conn *qc, const struct buffer *buf, size_t sz,
        return 0;
 }
 
+/* Allocate a socket file-descriptor specific for QUIC connection <qc>.
+ * Endpoint addresses are specified by the two following arguments : <src> is
+ * the local address and <dst> is the remote one.
+ *
+ * Return the socket FD or a negative error code. On error, socket is marked as
+ * uninitialized.
+ */
+void qc_alloc_fd(struct quic_conn *qc, const struct sockaddr_storage *src,
+                 const struct sockaddr_storage *dst)
+{
+       struct proxy *p = qc->li->bind_conf->frontend;
+       int fd = -1;
+       int ret;
+
+       /* Must not happen. */
+       BUG_ON(src->ss_family != dst->ss_family);
+
+       qc_init_fd(qc);
+
+       fd = socket(src->ss_family, SOCK_DGRAM, 0);
+       if (fd < 0)
+               goto err;
+
+       if (fd >= global.maxsock) {
+               send_log(p, LOG_EMERG,
+                        "Proxy %s reached the configured maximum connection limit. Please check the global 'maxconn' value.\n",
+                        p->id);
+               goto err;
+       }
+
+       ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
+       if (ret < 0)
+               goto err;
+
+       switch (src->ss_family) {
+       case AF_INET:
+#if defined(IP_PKTINFO)
+               ret = setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one));
+#elif defined(IP_RECVDSTADDR)
+               ret = setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &one, sizeof(one));
+#endif /* IP_PKTINFO || IP_RECVDSTADDR */
+               break;
+       case AF_INET6:
+#ifdef IPV6_RECVPKTINFO
+               ret = setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one));
+#endif
+               break;
+       }
+       if (ret < 0)
+               goto err;
+
+       ret = bind(fd, (struct sockaddr *)src, get_addr_len(src));
+       if (ret < 0)
+               goto err;
+
+       ret = connect(fd, (struct sockaddr *)dst, get_addr_len(dst));
+       if (ret < 0)
+               goto err;
+
+       qc->fd = fd;
+       fd_set_nonblock(fd);
+
+       return;
+
+ err:
+       if (fd >= 0)
+               close(fd);
+}
+
+/* Release socket file-descriptor specific for QUIC connection <qc>. */
+void qc_release_fd(struct quic_conn *qc)
+{
+       if (qc_test_fd(qc))
+               qc->fd = DEAD_FD_MAGIC;
+}
 
 /*********************** QUIC accept queue management ***********************/
 /* per-thread accept queues */