Skip to content

Commit 7c9fdd9

Browse files
committed
MEDIUM: quic: move receive out of FD handler to quic-conn io-cb
This change is the second part for reception on QUIC connection socket. All operations inside the FD handler has been delayed to quic-conn tasklet via the new function qc_rcv_buf(). With this change, buffer management on reception has been simplified. It is now possible to use a local buffer inside qc_rcv_buf() instead of quic_receiver_buf(). This change is part of quic-conn owned socket implementation. It may be backported to 2.7 after a period of observation.
1 parent 5b41486 commit 7c9fdd9

File tree

4 files changed

+134
-74
lines changed

4 files changed

+134
-74
lines changed

include/haproxy/quic_conn.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -743,6 +743,7 @@ void chunk_frm_appendf(struct buffer *buf, const struct quic_frame *frm);
743743
void quic_set_connection_close(struct quic_conn *qc, const struct quic_err err);
744744
void quic_set_tls_alert(struct quic_conn *qc, int alert);
745745
int quic_set_app_ops(struct quic_conn *qc, const unsigned char *alpn, size_t alpn_len);
746+
int qc_check_dcid(struct quic_conn *qc, unsigned char *dcid, size_t dcid_len);
746747
int quic_get_dgram_dcid(unsigned char *buf, const unsigned char *end,
747748
unsigned char **dcid, size_t *dcid_len);
748749
int qc_send_mux(struct quic_conn *qc, struct list *frms);

include/haproxy/quic_sock.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ struct task *quic_lstnr_dghdlr(struct task *t, void *ctx, unsigned int state);
4545
void quic_lstnr_sock_fd_iocb(int fd);
4646
int qc_snd_buf(struct quic_conn *qc, const struct buffer *buf, size_t count,
4747
int flags);
48+
int qc_rcv_buf(struct quic_conn *qc);
4849

4950
/* Set default value for <qc> socket as uninitialized. */
5051
static inline void qc_init_fd(struct quic_conn *qc)

src/quic_conn.c

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4310,6 +4310,9 @@ struct task *quic_conn_app_io_cb(struct task *t, void *context, unsigned int sta
43104310
TRACE_ENTER(QUIC_EV_CONN_IO_CB, qc);
43114311
TRACE_STATE("connection handshake state", QUIC_EV_CONN_IO_CB, qc, &qc->state);
43124312

4313+
if (qc_test_fd(qc))
4314+
qc_rcv_buf(qc);
4315+
43134316
/* Retranmissions */
43144317
if (qc->flags & QUIC_FL_CONN_RETRANS_NEEDED) {
43154318
TRACE_STATE("retransmission needed", QUIC_EV_CONN_IO_CB, qc);
@@ -4393,7 +4396,10 @@ struct task *quic_conn_io_cb(struct task *t, void *context, unsigned int state)
43934396
zero_rtt = st < QUIC_HS_ST_COMPLETE &&
43944397
quic_tls_has_rx_sec(eqel) &&
43954398
(!LIST_ISEMPTY(&eqel->rx.pqpkts) || qc_el_rx_pkts(eqel));
4396-
start:
4399+
4400+
if (qc_test_fd(qc))
4401+
qc_rcv_buf(qc);
4402+
43974403
if (st >= QUIC_HS_ST_COMPLETE &&
43984404
qc_el_rx_pkts(&qc->els[QUIC_TLS_ENC_LEVEL_HANDSHAKE])) {
43994405
TRACE_DEVEL("remaining Handshake packets", QUIC_EV_CONN_PHPKTS, qc);
@@ -7422,6 +7428,37 @@ int quic_dgram_parse(struct quic_dgram *dgram, struct quic_conn *from_qc,
74227428
return -1;
74237429
}
74247430

7431+
/* Check if connection ID <dcid> of length <dcid_len> belongs to <qc> local
7432+
* CIDs. This can be used to determine if a datagram is addressed to the right
7433+
* connection instance.
7434+
*
7435+
* Returns a boolean value.
7436+
*/
7437+
int qc_check_dcid(struct quic_conn *qc, unsigned char *dcid, size_t dcid_len)
7438+
{
7439+
struct ebmb_node *node;
7440+
struct quic_connection_id *id;
7441+
7442+
/* For ODCID, address is concatenated to it after qc.odcid.len so this
7443+
* comparison is safe.
7444+
*/
7445+
if ((qc->scid.len == dcid_len &&
7446+
memcmp(qc->scid.data, dcid, dcid_len) == 0) ||
7447+
(qc->odcid.len == dcid_len &&
7448+
memcmp(qc->odcid.data, dcid, dcid_len)) == 0) {
7449+
return 1;
7450+
}
7451+
7452+
node = ebmb_lookup(&quic_dghdlrs[tid].cids, dcid, dcid_len);
7453+
if (node) {
7454+
id = ebmb_entry(node, struct quic_connection_id, node);
7455+
if (qc == id->qc)
7456+
return 1;
7457+
}
7458+
7459+
return 0;
7460+
}
7461+
74257462
/* Retrieve the DCID from a QUIC datagram or packet with <buf> as first octet.
74267463
* Returns 1 if succeeded, 0 if not.
74277464
*/

src/quic_sock.c

Lines changed: 94 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <haproxy/api.h>
2323
#include <haproxy/buf.h>
2424
#include <haproxy/connection.h>
25+
#include <haproxy/dynbuf.h>
2526
#include <haproxy/fd.h>
2627
#include <haproxy/freq_ctr.h>
2728
#include <haproxy/global-t.h>
@@ -487,84 +488,14 @@ void quic_lstnr_sock_fd_iocb(int fd)
487488
/* FD-owned quic-conn socket callback. */
488489
static void quic_conn_sock_fd_iocb(int fd)
489490
{
490-
struct quic_conn *qc;
491+
struct quic_conn *qc = fdtab[fd].owner;
491492

492-
struct sockaddr_storage saddr = {0}, daddr = {0};
493-
struct quic_receiver_buf *rxbuf;
494-
struct quic_transport_params *params;
495-
struct quic_dgram *new_dgram;
496-
struct buffer *buf;
497-
size_t max_sz;
498-
size_t cspace;
499-
unsigned char *dgram_buf;
500-
struct listener *l;
501-
ssize_t ret = 0;
502-
503-
qc = fdtab[fd].owner;
504-
l = qc->li;
505493
TRACE_ENTER(QUIC_EV_CONN_RCV, qc);
506494

507-
new_dgram = NULL;
508-
rxbuf = MT_LIST_POP(&l->rx.rxbuf_list, typeof(rxbuf), rxbuf_el);
509-
if (!rxbuf)
510-
return;
511-
512-
buf = &rxbuf->buf;
513-
new_dgram = quic_rxbuf_purge_dgrams(rxbuf);
514-
515-
params = &l->bind_conf->quic_params;
516-
max_sz = params->max_udp_payload_size;
517-
cspace = b_contig_space(buf);
518-
if (cspace < max_sz) {
519-
struct quic_dgram *dgram;
520-
521-
/* Do no mark <buf> as full, and do not try to consume it
522-
* if the contiguous remaining space is not at the end
523-
*/
524-
if (b_tail(buf) + cspace < b_wrap(buf))
525-
goto end;
526-
527-
/* Allocate a fake datagram, without data to locate
528-
* the end of the RX buffer (required during purging).
529-
*/
530-
dgram = pool_alloc(pool_head_quic_dgram);
531-
if (!dgram)
532-
goto end;
533-
534-
/* Initialize only the useful members of this fake datagram. */
535-
dgram->buf = NULL;
536-
dgram->len = cspace;
537-
/* Append this datagram only to the RX buffer list. It will
538-
* not be treated by any datagram handler.
539-
*/
540-
LIST_APPEND(&rxbuf->dgram_list, &dgram->recv_list);
541-
542-
/* Consume the remaining space */
543-
b_add(buf, cspace);
544-
if (b_contig_space(buf) < max_sz)
545-
goto end;
546-
}
547-
548-
dgram_buf = (unsigned char *)b_tail(buf);
549-
ret = quic_recv(qc->fd, dgram_buf, max_sz,
550-
(struct sockaddr *)&saddr, sizeof(saddr),
551-
(struct sockaddr *)&daddr, sizeof(daddr),
552-
get_net_port(&qc->local_addr));
553-
if (ret <= 0)
554-
goto end;
555-
556-
b_add(buf, ret);
557-
if (!quic_lstnr_dgram_dispatch(dgram_buf, ret, l, &qc->peer_addr, &qc->local_addr,
558-
new_dgram, &rxbuf->dgram_list)) {
559-
b_del(buf, ret);
560-
}
561-
new_dgram = NULL;
495+
tasklet_wakeup_after(NULL, qc->wait_event.tasklet);
496+
fd_stop_recv(fd);
562497

563-
end:
564-
pool_free(pool_head_quic_dgram, new_dgram);
565-
MT_LIST_APPEND(&l->rx.rxbuf_list, &rxbuf->rxbuf_el);
566498
TRACE_LEAVE(QUIC_EV_CONN_RCV, qc);
567-
return;
568499
}
569500

570501
/* Send a datagram stored into <buf> buffer with <sz> as size.
@@ -627,6 +558,96 @@ int qc_snd_buf(struct quic_conn *qc, const struct buffer *buf, size_t sz,
627558
return 0;
628559
}
629560

561+
/* Receive datagram on <qc> FD-owned socket.
562+
*
563+
* Returns the total number of bytes read or a negative value on error.
564+
*/
565+
int qc_rcv_buf(struct quic_conn *qc)
566+
{
567+
struct sockaddr_storage saddr = {0}, daddr = {0};
568+
struct quic_transport_params *params;
569+
struct quic_dgram *new_dgram = NULL;
570+
struct buffer buf = BUF_NULL;
571+
size_t max_sz;
572+
unsigned char *dgram_buf;
573+
struct listener *l;
574+
ssize_t ret = 0;
575+
576+
/* Do not call this if quic-conn FD is uninitialized. */
577+
BUG_ON(qc->fd < 0);
578+
579+
TRACE_ENTER(QUIC_EV_CONN_RCV, qc);
580+
l = qc->li;
581+
582+
params = &l->bind_conf->quic_params;
583+
max_sz = params->max_udp_payload_size;
584+
585+
do {
586+
if (!b_alloc(&buf))
587+
break; /* TODO subscribe for memory again available. */
588+
589+
b_reset(&buf);
590+
BUG_ON(b_contig_space(&buf) < max_sz);
591+
592+
/* Allocate datagram on first loop or after requeuing. */
593+
if (!new_dgram && !(new_dgram = pool_alloc(pool_head_quic_dgram)))
594+
break; /* TODO subscribe for memory again available. */
595+
596+
dgram_buf = (unsigned char *)b_tail(&buf);
597+
ret = quic_recv(qc->fd, dgram_buf, max_sz,
598+
(struct sockaddr *)&saddr, sizeof(saddr),
599+
(struct sockaddr *)&daddr, sizeof(daddr),
600+
get_net_port(&qc->local_addr));
601+
if (ret <= 0) {
602+
/* Subscribe FD for future reception. */
603+
fd_want_recv(qc->fd);
604+
break;
605+
}
606+
607+
b_add(&buf, ret);
608+
609+
new_dgram->buf = dgram_buf;
610+
new_dgram->len = ret;
611+
new_dgram->dcid_len = 0;
612+
new_dgram->dcid = NULL;
613+
new_dgram->saddr = saddr;
614+
new_dgram->daddr = daddr;
615+
new_dgram->qc = NULL; /* set later via quic_dgram_parse() */
616+
617+
TRACE_DEVEL("read datagram", QUIC_EV_CONN_RCV, qc, new_dgram);
618+
619+
if (!quic_get_dgram_dcid(new_dgram->buf,
620+
new_dgram->buf + new_dgram->len,
621+
&new_dgram->dcid, &new_dgram->dcid_len)) {
622+
continue;
623+
}
624+
625+
if (!qc_check_dcid(qc, new_dgram->dcid, new_dgram->dcid_len)) {
626+
/* Datagram received by error on the connection FD, dispatch it
627+
* to its associated quic-conn.
628+
*
629+
* TODO count redispatch datagrams.
630+
*/
631+
TRACE_STATE("wrong datagram on quic-conn socket, prepare to requeue it", QUIC_EV_CONN_RCV, qc);
632+
ABORT_NOW();
633+
}
634+
635+
quic_dgram_parse(new_dgram, qc, qc->li);
636+
/* A datagram must always be consumed after quic_parse_dgram(). */
637+
BUG_ON(new_dgram->buf);
638+
} while (ret > 0);
639+
640+
pool_free(pool_head_quic_dgram, new_dgram);
641+
642+
if (b_size(&buf)) {
643+
b_free(&buf);
644+
offer_buffers(NULL, 1);
645+
}
646+
647+
TRACE_LEAVE(QUIC_EV_CONN_RCV, qc);
648+
return ret;
649+
}
650+
630651
/* Allocate a socket file-descriptor specific for QUIC connection <qc>.
631652
* Endpoint addresses are specified by the two following arguments : <src> is
632653
* the local address and <dst> is the remote one.

0 commit comments

Comments
 (0)