mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-10 00:57:02 +02:00
MINOR: quic: split and rename qc_lstnr_pkt_rcv()
This change is the following of qc_lstnr_pkt_rcv() refactoring. This function has finally been split into several ones. The first half is renamed quic_rx_pkt_parse(). This function is responsible to parse a QUIC packet header and calculate the packet length. QUIC connection retrieval has been extracted and is now called directly by quic_lstnr_dghdlr(). The second half of qc_lstnr_pkt_rcv() is renamed to qc_rx_pkt_handle(). This function is responsible to copy a QUIC packet content to a quic-conn receive buffer. A third function named qc_rx_check_closing() is responsible to detect if the connection is already in closing state. As this requires to drop the whole datagram, it seems justified to be in a separate function. This change has no functional impact. It is part of a refactoring series on qc_lstnr_pkt_rcv(). The objective is to facilitate the integration of FD-owned quic-conn socket patches. This should be backported up to 2.6.
This commit is contained in:
parent
449b1a8f55
commit
982896961c
167
src/quic_conn.c
167
src/quic_conn.c
@ -6039,38 +6039,29 @@ static struct quic_conn *quic_rx_pkt_retrieve_conn(struct quic_rx_packet *pkt,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parse a QUIC packet from UDP datagram found in <buf> buffer with <end> the
|
/* Parse a QUIC packet starting at <buf>. Data won't be read after <end> even
|
||||||
* end of this buffer past one byte and populate <pkt> RX packet structure
|
* if the packet is incomplete. This function will populate fields of <pkt>
|
||||||
* with the information collected from the packet.
|
* instance, most notably its length. <dgram> is the UDP datagram which
|
||||||
* This function sets ->len <pkt> field value to the end of the packet past one
|
* contains the parsed packet. <l> is the listener instance on which it was
|
||||||
* byte to enable the caller to run this function again to continue to parse
|
* received.
|
||||||
* the remaining QUIC packets carried by the datagram.
|
*
|
||||||
* Note that this function always sets this ->len value. If a paquet could
|
* Returns 0 on success else non-zero. Packet length is guaranteed to be set to
|
||||||
* not be correctly found, ->len value will be set to the remaining number
|
* the real packet value or to cover all data between <buf> and <end> : this is
|
||||||
* bytes in the datagram to entirely consume this latter.
|
* useful to reject a whole datagram.
|
||||||
*/
|
*/
|
||||||
static void qc_lstnr_pkt_rcv(unsigned char *buf, const unsigned char *end,
|
static int quic_rx_pkt_parse(struct quic_rx_packet *pkt,
|
||||||
struct quic_rx_packet *pkt,
|
unsigned char *buf, const unsigned char *end,
|
||||||
struct quic_dgram *dgram,
|
struct quic_dgram *dgram, struct listener *l)
|
||||||
struct list **tasklist_head)
|
|
||||||
{
|
{
|
||||||
unsigned char *beg;
|
const unsigned char *beg = buf;
|
||||||
struct quic_conn *qc;
|
|
||||||
struct listener *l;
|
|
||||||
struct proxy *prx;
|
struct proxy *prx;
|
||||||
struct quic_counters *prx_counters;
|
struct quic_counters *prx_counters;
|
||||||
int drop_no_conn = 0, long_header = 0, io_cb_wakeup = 0;
|
int drop_no_conn = 0, long_header = 0;
|
||||||
size_t b_cspace;
|
|
||||||
struct quic_enc_level *qel;
|
|
||||||
uint32_t version;
|
uint32_t version;
|
||||||
const struct quic_version *qv = NULL;
|
const struct quic_version *qv = NULL;
|
||||||
|
|
||||||
TRACE_ENTER(QUIC_EV_CONN_LPKT);
|
TRACE_ENTER(QUIC_EV_CONN_LPKT);
|
||||||
|
|
||||||
beg = buf;
|
|
||||||
qc = NULL;
|
|
||||||
qel = NULL;
|
|
||||||
l = dgram->owner;
|
|
||||||
prx = l->bind_conf->frontend;
|
prx = l->bind_conf->frontend;
|
||||||
prx_counters = EXTRA_COUNTERS_GET(prx->extra_counters_fe, &quic_stats_module);
|
prx_counters = EXTRA_COUNTERS_GET(prx->extra_counters_fe, &quic_stats_module);
|
||||||
/* This ist only to please to traces and distinguish the
|
/* This ist only to please to traces and distinguish the
|
||||||
@ -6248,34 +6239,75 @@ static void qc_lstnr_pkt_rcv(unsigned char *buf, const unsigned char *end,
|
|||||||
pkt->len = end - beg;
|
pkt->len = end - beg;
|
||||||
}
|
}
|
||||||
|
|
||||||
qc = quic_rx_pkt_retrieve_conn(pkt, dgram, dgram->owner);
|
TRACE_LEAVE(QUIC_EV_CONN_LPKT, NULL, pkt, NULL, qv);
|
||||||
if (!qc) {
|
return 0;
|
||||||
size_t pktlen = end - buf;
|
|
||||||
TRACE_PROTO("Packet dropped", QUIC_EV_CONN_LPKT, NULL, pkt, &pktlen);
|
|
||||||
if (global.cluster_secret && !send_stateless_reset(l, &dgram->saddr, pkt))
|
|
||||||
TRACE_ERROR("stateless reset not sent", QUIC_EV_CONN_LPKT, qc);
|
|
||||||
goto drop;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (qc->flags & QUIC_FL_CONN_CLOSING) {
|
drop_no_conn:
|
||||||
if (++qc->nb_pkt_since_cc >= qc->nb_pkt_for_cc) {
|
if (drop_no_conn)
|
||||||
qc->flags |= QUIC_FL_CONN_IMMEDIATE_CLOSE;
|
HA_ATOMIC_INC(&prx_counters->dropped_pkt);
|
||||||
qc->nb_pkt_for_cc++;
|
TRACE_LEAVE(QUIC_EV_CONN_LPKT, NULL, pkt);
|
||||||
qc->nb_pkt_since_cc = 0;
|
|
||||||
}
|
return -1;
|
||||||
/* Skip the entire datagram */
|
|
||||||
|
drop:
|
||||||
|
HA_ATOMIC_INC(&prx_counters->dropped_pkt);
|
||||||
|
|
||||||
|
err:
|
||||||
|
if (!pkt->len)
|
||||||
pkt->len = end - beg;
|
pkt->len = end - beg;
|
||||||
TRACE_STATE("Closing state connection",
|
TRACE_LEAVE(QUIC_EV_CONN_LPKT, NULL, pkt, NULL, qv);
|
||||||
QUIC_EV_CONN_LPKT, pkt->qc, NULL, NULL, qv);
|
return -1;
|
||||||
goto drop;
|
}
|
||||||
|
|
||||||
|
/* Check if received packet <pkt> should be drop due to <qc> already in closing
|
||||||
|
* state. This can be true if a CONNECTION_CLOSE has already been emitted for
|
||||||
|
* this connection.
|
||||||
|
*
|
||||||
|
* Returns false if connection is not in closing state else true. The caller
|
||||||
|
* should drop the whole datagram in the last case to not mess up <qc>
|
||||||
|
* CONNECTION_CLOSE rate limit counter.
|
||||||
|
*/
|
||||||
|
static int qc_rx_check_closing(struct quic_conn *qc,
|
||||||
|
struct quic_rx_packet *pkt)
|
||||||
|
{
|
||||||
|
if (!(qc->flags & QUIC_FL_CONN_CLOSING))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
TRACE_STATE("Closing state connection", QUIC_EV_CONN_LPKT, qc, NULL, NULL, pkt->version);
|
||||||
|
|
||||||
|
/* Check if CONNECTION_CLOSE rate reemission is reached. */
|
||||||
|
if (++qc->nb_pkt_since_cc >= qc->nb_pkt_for_cc) {
|
||||||
|
qc->flags |= QUIC_FL_CONN_IMMEDIATE_CLOSE;
|
||||||
|
qc->nb_pkt_for_cc++;
|
||||||
|
qc->nb_pkt_since_cc = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* When multiple QUIC packets are coalesced on the same UDP datagram,
|
return 1;
|
||||||
* they must have the same DCID.
|
}
|
||||||
*
|
|
||||||
* This check must be done after the final update to pkt.len to
|
/* Handle a parsed packet <pkt> by the connection <qc>. Data will be copied
|
||||||
* properly drop the packet on failure.
|
* into <qc> receive buffer after header protection removal procedure.
|
||||||
*/
|
*
|
||||||
|
* <dgram> must be set to the datagram which contains the QUIC packet. <beg>
|
||||||
|
* must point to packet buffer first byte.
|
||||||
|
*
|
||||||
|
* <tasklist_head> may be non-NULL when the caller treat several datagrams for
|
||||||
|
* different quic-conn. In this case, each quic-conn tasklet will be appended
|
||||||
|
* to it in order to be woken up after the current task.
|
||||||
|
*
|
||||||
|
* The caller can safely removed the packet data. If packet refcount was not
|
||||||
|
* incremented by this function, it means that the connection did not handled
|
||||||
|
* it and it should be freed by the caller.
|
||||||
|
*/
|
||||||
|
static void qc_rx_pkt_handle(struct quic_conn *qc, struct quic_rx_packet *pkt,
|
||||||
|
struct quic_dgram *dgram, unsigned char *beg,
|
||||||
|
struct list **tasklist_head)
|
||||||
|
{
|
||||||
|
const struct quic_version *qv = pkt->version;
|
||||||
|
struct quic_enc_level *qel = NULL;
|
||||||
|
size_t b_cspace;
|
||||||
|
int io_cb_wakeup = 1;
|
||||||
|
|
||||||
if (pkt->flags & QUIC_FL_RX_PACKET_DGRAM_FIRST &&
|
if (pkt->flags & QUIC_FL_RX_PACKET_DGRAM_FIRST &&
|
||||||
!quic_peer_validated_addr(qc) &&
|
!quic_peer_validated_addr(qc) &&
|
||||||
qc->flags & QUIC_FL_CONN_ANTI_AMPLIFICATION_REACHED) {
|
qc->flags & QUIC_FL_CONN_ANTI_AMPLIFICATION_REACHED) {
|
||||||
@ -6289,8 +6321,6 @@ static void qc_lstnr_pkt_rcv(unsigned char *buf, const unsigned char *end,
|
|||||||
io_cb_wakeup = 1;
|
io_cb_wakeup = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
dgram->qc = qc;
|
|
||||||
|
|
||||||
if (qc->flags & QUIC_FL_CONN_IMMEDIATE_CLOSE) {
|
if (qc->flags & QUIC_FL_CONN_IMMEDIATE_CLOSE) {
|
||||||
TRACE_PROTO("Connection error",
|
TRACE_PROTO("Connection error",
|
||||||
QUIC_EV_CONN_LPKT, qc, NULL, NULL, qv);
|
QUIC_EV_CONN_LPKT, qc, NULL, NULL, qv);
|
||||||
@ -6305,7 +6335,7 @@ static void qc_lstnr_pkt_rcv(unsigned char *buf, const unsigned char *end,
|
|||||||
if (b_tail(&qc->rx.buf) + b_cspace < b_wrap(&qc->rx.buf)) {
|
if (b_tail(&qc->rx.buf) + b_cspace < b_wrap(&qc->rx.buf)) {
|
||||||
TRACE_PROTO("Packet dropped",
|
TRACE_PROTO("Packet dropped",
|
||||||
QUIC_EV_CONN_LPKT, qc, NULL, NULL, qv);
|
QUIC_EV_CONN_LPKT, qc, NULL, NULL, qv);
|
||||||
HA_ATOMIC_INC(&prx_counters->dropped_pkt_bufoverrun);
|
HA_ATOMIC_INC(&qc->prx_counters->dropped_pkt_bufoverrun);
|
||||||
goto drop_no_conn;
|
goto drop_no_conn;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6318,7 +6348,7 @@ static void qc_lstnr_pkt_rcv(unsigned char *buf, const unsigned char *end,
|
|||||||
if (b_contig_space(&qc->rx.buf) < pkt->len) {
|
if (b_contig_space(&qc->rx.buf) < pkt->len) {
|
||||||
TRACE_PROTO("Too big packet",
|
TRACE_PROTO("Too big packet",
|
||||||
QUIC_EV_CONN_LPKT, qc, pkt, &pkt->len, qv);
|
QUIC_EV_CONN_LPKT, qc, pkt, &pkt->len, qv);
|
||||||
HA_ATOMIC_INC(&prx_counters->dropped_pkt_bufoverrun);
|
HA_ATOMIC_INC(&qc->prx_counters->dropped_pkt_bufoverrun);
|
||||||
goto drop_no_conn;
|
goto drop_no_conn;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -6332,24 +6362,15 @@ static void qc_lstnr_pkt_rcv(unsigned char *buf, const unsigned char *end,
|
|||||||
if (pkt->aad_len)
|
if (pkt->aad_len)
|
||||||
qc_pkt_insert(qc, pkt, qel);
|
qc_pkt_insert(qc, pkt, qel);
|
||||||
out:
|
out:
|
||||||
/* Wake up the connection packet handler task from here only if all
|
|
||||||
* the contexts have been initialized, especially the mux context
|
|
||||||
* conn_ctx->conn->ctx. Note that this is ->start xprt callback which
|
|
||||||
* will start it if these contexts for the connection are not already
|
|
||||||
* initialized.
|
|
||||||
*/
|
|
||||||
*tasklist_head = tasklet_wakeup_after(*tasklist_head,
|
*tasklist_head = tasklet_wakeup_after(*tasklist_head,
|
||||||
qc->wait_event.tasklet);
|
qc->wait_event.tasklet);
|
||||||
|
|
||||||
drop_no_conn:
|
drop_no_conn:
|
||||||
if (drop_no_conn)
|
|
||||||
HA_ATOMIC_INC(&prx_counters->dropped_pkt);
|
|
||||||
TRACE_LEAVE(QUIC_EV_CONN_LPKT, qc ? qc : NULL, pkt, NULL, qv);
|
TRACE_LEAVE(QUIC_EV_CONN_LPKT, qc ? qc : NULL, pkt, NULL, qv);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
drop:
|
drop:
|
||||||
HA_ATOMIC_INC(&prx_counters->dropped_pkt);
|
HA_ATOMIC_INC(&qc->prx_counters->dropped_pkt);
|
||||||
err:
|
err:
|
||||||
/* Wakeup the I/O handler callback if the PTO timer must be armed.
|
/* Wakeup the I/O handler callback if the PTO timer must be armed.
|
||||||
* This cannot be done by this thread.
|
* This cannot be done by this thread.
|
||||||
@ -6357,9 +6378,6 @@ static void qc_lstnr_pkt_rcv(unsigned char *buf, const unsigned char *end,
|
|||||||
if (io_cb_wakeup)
|
if (io_cb_wakeup)
|
||||||
tasklet_wakeup(qc->wait_event.tasklet);
|
tasklet_wakeup(qc->wait_event.tasklet);
|
||||||
|
|
||||||
/* If length not found, consume the entire datagram */
|
|
||||||
if (!pkt->len)
|
|
||||||
pkt->len = end - beg;
|
|
||||||
TRACE_LEAVE(QUIC_EV_CONN_LPKT, qc ? qc : NULL, pkt, NULL, qv);
|
TRACE_LEAVE(QUIC_EV_CONN_LPKT, qc ? qc : NULL, pkt, NULL, qv);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7214,6 +7232,7 @@ struct task *quic_lstnr_dghdlr(struct task *t, void *ctx, unsigned int state)
|
|||||||
end = pos + dgram->len;
|
end = pos + dgram->len;
|
||||||
do {
|
do {
|
||||||
struct quic_rx_packet *pkt;
|
struct quic_rx_packet *pkt;
|
||||||
|
struct quic_conn *qc;
|
||||||
|
|
||||||
/* TODO replace zalloc -> alloc. */
|
/* TODO replace zalloc -> alloc. */
|
||||||
pkt = pool_zalloc(pool_head_quic_rx_packet);
|
pkt = pool_zalloc(pool_head_quic_rx_packet);
|
||||||
@ -7233,7 +7252,25 @@ struct task *quic_lstnr_dghdlr(struct task *t, void *ctx, unsigned int state)
|
|||||||
LIST_INIT(&pkt->qc_rx_pkt_list);
|
LIST_INIT(&pkt->qc_rx_pkt_list);
|
||||||
pkt->time_received = now_ms;
|
pkt->time_received = now_ms;
|
||||||
quic_rx_packet_refinc(pkt);
|
quic_rx_packet_refinc(pkt);
|
||||||
qc_lstnr_pkt_rcv(pos, end, pkt, dgram, &tasklist_head);
|
if (quic_rx_pkt_parse(pkt, pos, end, dgram, dgram->owner))
|
||||||
|
goto next;
|
||||||
|
|
||||||
|
qc = quic_rx_pkt_retrieve_conn(pkt, dgram, dgram->owner);
|
||||||
|
if (!qc)
|
||||||
|
goto next;
|
||||||
|
|
||||||
|
BUG_ON(dgram->qc && dgram->qc != qc);
|
||||||
|
dgram->qc = qc;
|
||||||
|
|
||||||
|
if (qc_rx_check_closing(qc, pkt)) {
|
||||||
|
/* Skip the entire datagram. */
|
||||||
|
pkt->len = end - pos;
|
||||||
|
goto next;
|
||||||
|
}
|
||||||
|
|
||||||
|
qc_rx_pkt_handle(qc, pkt, dgram, pos, &tasklist_head);
|
||||||
|
|
||||||
|
next:
|
||||||
pos += pkt->len;
|
pos += pkt->len;
|
||||||
quic_rx_packet_refdec(pkt);
|
quic_rx_packet_refdec(pkt);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user