From: Amaury Denoyelle Date: Tue, 27 Sep 2022 12:22:09 +0000 (+0200) Subject: MINOR: quic: extract datagram parsing code X-Git-Tag: v2.8-dev1~197 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=8687b63c69f359e0938e939a6c4ca61a42e43446;p=thirdparty%2Fhaproxy.git MINOR: quic: extract datagram parsing code 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. --- diff --git a/include/haproxy/quic_conn.h b/include/haproxy/quic_conn.h index 6b2b70b221..47e256ef2d 100644 --- a/include/haproxy/quic_conn.h +++ b/include/haproxy/quic_conn.h @@ -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 */ diff --git a/include/haproxy/quic_sock.h b/include/haproxy/quic_sock.h index b69b98474e..eeec932237 100644 --- a/include/haproxy/quic_sock.h +++ b/include/haproxy/quic_sock.h @@ -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); diff --git a/src/quic_conn.c b/src/quic_conn.c index 8bf19e7bcf..2dd21b9fd2 100644 --- a/src/quic_conn.c +++ b/src/quic_conn.c @@ -7242,99 +7242,110 @@ static void __quic_conn_deinit(void) } REGISTER_POST_DEINIT(__quic_conn_deinit); -/* Read all the QUIC packets found in from QUIC connection with - * as owner calling function. - * Return the number of bytes read if succeeded, -1 if not. +/* Handle a new 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, must be set + * to the connection instance.
  • 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, will be NULL. This + * function will thus retrieve the connection from the CID tree or allocate a + * new one if possible.
  • 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 as first octet. diff --git a/src/quic_sock.c b/src/quic_sock.c index 2ac60eac71..10e8b3f9cc 100644 --- a/src/quic_sock.c +++ b/src/quic_sock.c @@ -36,8 +36,11 @@ #include #include #include +#include #include +#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 and deliver it to the * correct datagram handler. * Return 1 if a correct datagram could be found, 0 if not.