]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: quic: extract datagram parsing code
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Tue, 27 Sep 2022 12:22:09 +0000 (14:22 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Fri, 2 Dec 2022 13:45:43 +0000 (14:45 +0100)
Extract individual datagram parsing code outside of datagrams list loop
in quic_lstnr_dghdlr(). This is moved in a new function named
quic_dgram_parse().

To complete this change, quic_lstnr_dghdlr() has been moved into
quic_sock source file : it belongs to QUIC socket lower layer and is
directly called by quic_sock_fd_iocb().

This commit will ease implementation of quic-conn owned socket.
New function quic_dgram_parse() will be easily usable after a receive
operation done on quic-conn IO-cb.

This should be backported up to 2.7.

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

index 6b2b70b221057994951d999f572bcd42eed1d672..47e256ef2d64d4b784069c5a8bf8b6eda9652c2f 100644 (file)
@@ -743,7 +743,6 @@ void chunk_frm_appendf(struct buffer *buf, const struct quic_frame *frm);
 void quic_set_connection_close(struct quic_conn *qc, const struct quic_err err);
 void quic_set_tls_alert(struct quic_conn *qc, int alert);
 int quic_set_app_ops(struct quic_conn *qc, const unsigned char *alpn, size_t alpn_len);
-struct task *quic_lstnr_dghdlr(struct task *t, void *ctx, unsigned int state);
 int quic_get_dgram_dcid(unsigned char *buf, const unsigned char *end,
                         unsigned char **dcid, size_t *dcid_len);
 int qc_send_mux(struct quic_conn *qc, struct list *frms);
@@ -756,5 +755,8 @@ void qc_check_close_on_released_mux(struct quic_conn *qc);
 
 void quic_conn_release(struct quic_conn *qc);
 
+int quic_dgram_parse(struct quic_dgram *dgram, struct quic_conn *qc,
+                     struct listener *li);
+
 #endif /* USE_QUIC */
 #endif /* _HAPROXY_QUIC_CONN_H */
index b69b98474e622563377da823a6f5a0951dce5ba6..eeec932237ad4ae40ae949bbf6ad48fb19571c3e 100644 (file)
@@ -39,6 +39,8 @@ int quic_sock_get_src(struct connection *conn, struct sockaddr *addr, socklen_t
 int quic_sock_get_dst(struct connection *conn, struct sockaddr *addr, socklen_t len);
 int quic_sock_accepting_conn(const struct receiver *rx);
 struct connection *quic_sock_accept_conn(struct listener *l, int *status);
+
+struct task *quic_lstnr_dghdlr(struct task *t, void *ctx, unsigned int state);
 void quic_sock_fd_iocb(int fd);
 int qc_snd_buf(struct quic_conn *qc, const struct buffer *buf, size_t count,
                int flags);
index 8bf19e7bcf88da2337055a679865cf796f25518f..2dd21b9fd2e4adf582643b09896a89480e00db98 100644 (file)
@@ -7242,99 +7242,110 @@ static void __quic_conn_deinit(void)
 }
 REGISTER_POST_DEINIT(__quic_conn_deinit);
 
-/* Read all the QUIC packets found in <buf> from QUIC connection with <owner>
- * as owner calling <func> function.
- * Return the number of bytes read if succeeded, -1 if not.
+/* Handle a new <dgram> received. Parse each QUIC packets and copied their
+ * content to a quic-conn instance. The datagram content can be released after
+ * this function.
+ *
+ * If datagram has been received on a quic-conn owned FD, <from_qc> must be set
+ * to the connection instance. <li> is the attached listener. The caller is
+ * responsible to ensure that the first packet is destined to this connection
+ * by comparing CIDs.
+ *
+ * If datagram has been received on a receiver FD, <from_qc> will be NULL. This
+ * function will thus retrieve the connection from the CID tree or allocate a
+ * new one if possible. <li> is the listener attached to the receiver.
+ *
+ * Returns 0 on success else non-zero. If an error happens, some packets from
+ * the datagram may not have been parsed.
  */
-struct task *quic_lstnr_dghdlr(struct task *t, void *ctx, unsigned int state)
+int quic_dgram_parse(struct quic_dgram *dgram, struct quic_conn *from_qc,
+                     struct listener *li)
 {
-       unsigned char *pos;
-       const unsigned char *end;
-       struct quic_dghdlr *dghdlr = ctx;
-       struct quic_dgram *dgram;
+       struct quic_rx_packet *pkt;
+       struct quic_conn *qc = NULL;
+       unsigned char *pos, *end;
        struct list *tasklist_head = NULL;
-       int max_dgrams = global.tune.maxpollevents;
 
        TRACE_ENTER(QUIC_EV_CONN_LPKT);
 
-       while ((dgram = MT_LIST_POP(&dghdlr->dgrams, typeof(dgram), handler_list))) {
-               pos = dgram->buf;
-               end = pos + dgram->len;
-               do {
-                       struct quic_rx_packet *pkt;
-                       struct quic_conn *qc;
-
-                       /* TODO replace zalloc -> alloc. */
-                       pkt = pool_zalloc(pool_head_quic_rx_packet);
-                       if (!pkt) {
-                               TRACE_ERROR("RX packet allocation failed", QUIC_EV_CONN_LPKT);
-                               /* TODO count lost datagram. */
-                               goto leave;
-                       }
-
-                       pkt->version = NULL;
-                       pkt->pn_offset = 0;
-
-                       /* Set flag if pkt is the first one in dgram. */
-                       if (pos == dgram->buf)
-                               pkt->flags |= QUIC_FL_RX_PACKET_DGRAM_FIRST;
+       pos = dgram->buf;
+       end = pos + dgram->len;
+       do {
+               /* TODO replace zalloc -> alloc. */
+               pkt = pool_zalloc(pool_head_quic_rx_packet);
+               if (!pkt) {
+                       TRACE_ERROR("RX packet allocation failed", QUIC_EV_CONN_LPKT);
+                       goto err;
+               }
 
-                       LIST_INIT(&pkt->qc_rx_pkt_list);
-                       pkt->time_received = now_ms;
-                       quic_rx_packet_refinc(pkt);
-                       if (quic_rx_pkt_parse(pkt, pos, end, dgram, dgram->owner))
-                               goto next;
+               pkt->version = NULL;
+               pkt->pn_offset = 0;
 
-                       qc = quic_rx_pkt_retrieve_conn(pkt, dgram, dgram->owner);
-                       if (!qc)
-                               goto next;
+               /* Set flag if pkt is the first one in dgram. */
+               if (pos == dgram->buf)
+                       pkt->flags |= QUIC_FL_RX_PACKET_DGRAM_FIRST;
 
-                       BUG_ON(dgram->qc && dgram->qc != qc);
-                       dgram->qc = qc;
+               LIST_INIT(&pkt->qc_rx_pkt_list);
+               pkt->time_received = now_ms;
+               quic_rx_packet_refinc(pkt);
+               if (quic_rx_pkt_parse(pkt, pos, end, dgram, li))
+                       goto next;
 
-                       if (qc_rx_check_closing(qc, pkt)) {
+               /* Search quic-conn instance for first packet of the datagram.
+                * quic_rx_packet_parse() is responsible to discard packets
+                * with different DCID as the first one in the same datagram.
+                */
+               if (!qc) {
+                       qc = from_qc ? from_qc : quic_rx_pkt_retrieve_conn(pkt, dgram, li);
+                       /* qc is NULL if receiving a non Initial packet for an
+                        * unknown connection.
+                        */
+                       if (!qc) {
                                /* Skip the entire datagram. */
                                pkt->len = end - pos;
                                goto next;
                        }
 
-                       qc_rx_pkt_handle(qc, pkt, dgram, pos, &tasklist_head);
+                       dgram->qc = qc;
+               }
 
- next:
-                       pos += pkt->len;
-                       quic_rx_packet_refdec(pkt);
+               if (qc_rx_check_closing(qc, pkt)) {
+                       /* Skip the entire datagram. */
+                       pkt->len = end - pos;
+                       goto next;
+               }
 
-                       /* Free rejected packets */
-                       if (!pkt->refcnt) {
-                               BUG_ON(LIST_INLIST(&pkt->qc_rx_pkt_list));
-                               pool_free(pool_head_quic_rx_packet, pkt);
-                       }
-               } while (pos < end);
+               qc_rx_pkt_handle(qc, pkt, dgram, pos, &tasklist_head);
 
-               /* Increasing the received bytes counter by the UDP datagram length
-                * if this datagram could be associated to a connection.
-                */
-               if (dgram->qc)
-                       dgram->qc->rx.bytes += dgram->len;
+ next:
+               pos += pkt->len;
+               quic_rx_packet_refdec(pkt);
 
-               /* Mark this datagram as consumed */
-               HA_ATOMIC_STORE(&dgram->buf, NULL);
+               /* Free rejected packets */
+               if (!pkt->refcnt) {
+                       BUG_ON(LIST_INLIST(&pkt->qc_rx_pkt_list));
+                       pool_free(pool_head_quic_rx_packet, pkt);
+               }
+       } while (pos < end);
 
-               if (--max_dgrams <= 0)
-                       goto stop_here;
-       }
+       /* Increasing the received bytes counter by the UDP datagram length
+        * if this datagram could be associated to a connection.
+        */
+       if (dgram->qc)
+               dgram->qc->rx.bytes += dgram->len;
 
-       TRACE_LEAVE(QUIC_EV_CONN_LPKT);
+       /* This must never happen. */
+       BUG_ON(pos > end);
+       BUG_ON(pos < end || pos > dgram->buf + dgram->len);
+       /* Mark this datagram as consumed */
+       HA_ATOMIC_STORE(&dgram->buf, NULL);
 
-       return t;
+       TRACE_LEAVE(QUIC_EV_CONN_LPKT);
+       return 0;
 
- stop_here:
-       /* too much work done at once, come back here later */
-       if (!MT_LIST_ISEMPTY(&dghdlr->dgrams))
-               tasklet_wakeup((struct tasklet *)t);
- leave:
+ err:
        TRACE_LEAVE(QUIC_EV_CONN_LPKT);
-       return t;
+       return -1;
 }
 
 /* Retrieve the DCID from a QUIC datagram or packet with <buf> as first octet.
index 2ac60eac715e889d99e0208b8de9e632887163bb..10e8b3f9cc8697da37583c07e2d1f285e3bfe6f6 100644 (file)
 #include <haproxy/session.h>
 #include <haproxy/stats-t.h>
 #include <haproxy/task.h>
+#include <haproxy/trace.h>
 #include <haproxy/tools.h>
 
+#define TRACE_SOURCE    &trace_quic
+
 /* Retrieve a connection's source address. Returns -1 on failure. */
 int quic_sock_get_src(struct connection *conn, struct sockaddr *addr, socklen_t len)
 {
@@ -160,6 +163,37 @@ struct connection *quic_sock_accept_conn(struct listener *l, int *status)
        return NULL;
 }
 
+/* QUIC datagrams handler task. */
+struct task *quic_lstnr_dghdlr(struct task *t, void *ctx, unsigned int state)
+{
+       struct quic_dghdlr *dghdlr = ctx;
+       struct quic_dgram *dgram;
+       int max_dgrams = global.tune.maxpollevents;
+
+       TRACE_ENTER(QUIC_EV_CONN_LPKT);
+
+       while ((dgram = MT_LIST_POP(&dghdlr->dgrams, typeof(dgram), handler_list))) {
+               if (quic_dgram_parse(dgram, NULL, dgram->owner)) {
+                       /* TODO should we requeue the datagram ? */
+                       break;
+               }
+
+               if (--max_dgrams <= 0)
+                       goto stop_here;
+       }
+
+       TRACE_LEAVE(QUIC_EV_CONN_LPKT);
+       return t;
+
+ stop_here:
+       /* too much work done at once, come back here later */
+       if (!MT_LIST_ISEMPTY(&dghdlr->dgrams))
+               tasklet_wakeup((struct tasklet *)t);
+
+       TRACE_LEAVE(QUIC_EV_CONN_LPKT);
+       return t;
+}
+
 /* Retrieve the DCID from the datagram found in <buf> and deliver it to the
  * correct datagram handler.
  * Return 1 if a correct datagram could be found, 0 if not.