mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-07 07:37:02 +02:00
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.
This commit is contained in:
parent
5b41486b7f
commit
7c9fdd9c3a
@ -743,6 +743,7 @@ 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);
|
||||
int qc_check_dcid(struct quic_conn *qc, unsigned char *dcid, size_t dcid_len);
|
||||
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);
|
||||
|
@ -45,6 +45,7 @@ struct task *quic_lstnr_dghdlr(struct task *t, void *ctx, unsigned int state);
|
||||
void quic_lstnr_sock_fd_iocb(int fd);
|
||||
int qc_snd_buf(struct quic_conn *qc, const struct buffer *buf, size_t count,
|
||||
int flags);
|
||||
int qc_rcv_buf(struct quic_conn *qc);
|
||||
|
||||
/* Set default value for <qc> socket as uninitialized. */
|
||||
static inline void qc_init_fd(struct quic_conn *qc)
|
||||
|
@ -4310,6 +4310,9 @@ struct task *quic_conn_app_io_cb(struct task *t, void *context, unsigned int sta
|
||||
TRACE_ENTER(QUIC_EV_CONN_IO_CB, qc);
|
||||
TRACE_STATE("connection handshake state", QUIC_EV_CONN_IO_CB, qc, &qc->state);
|
||||
|
||||
if (qc_test_fd(qc))
|
||||
qc_rcv_buf(qc);
|
||||
|
||||
/* Retranmissions */
|
||||
if (qc->flags & QUIC_FL_CONN_RETRANS_NEEDED) {
|
||||
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)
|
||||
zero_rtt = st < QUIC_HS_ST_COMPLETE &&
|
||||
quic_tls_has_rx_sec(eqel) &&
|
||||
(!LIST_ISEMPTY(&eqel->rx.pqpkts) || qc_el_rx_pkts(eqel));
|
||||
start:
|
||||
|
||||
if (qc_test_fd(qc))
|
||||
qc_rcv_buf(qc);
|
||||
|
||||
if (st >= QUIC_HS_ST_COMPLETE &&
|
||||
qc_el_rx_pkts(&qc->els[QUIC_TLS_ENC_LEVEL_HANDSHAKE])) {
|
||||
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,
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check if connection ID <dcid> of length <dcid_len> belongs to <qc> local
|
||||
* CIDs. This can be used to determine if a datagram is addressed to the right
|
||||
* connection instance.
|
||||
*
|
||||
* Returns a boolean value.
|
||||
*/
|
||||
int qc_check_dcid(struct quic_conn *qc, unsigned char *dcid, size_t dcid_len)
|
||||
{
|
||||
struct ebmb_node *node;
|
||||
struct quic_connection_id *id;
|
||||
|
||||
/* For ODCID, address is concatenated to it after qc.odcid.len so this
|
||||
* comparison is safe.
|
||||
*/
|
||||
if ((qc->scid.len == dcid_len &&
|
||||
memcmp(qc->scid.data, dcid, dcid_len) == 0) ||
|
||||
(qc->odcid.len == dcid_len &&
|
||||
memcmp(qc->odcid.data, dcid, dcid_len)) == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
node = ebmb_lookup(&quic_dghdlrs[tid].cids, dcid, dcid_len);
|
||||
if (node) {
|
||||
id = ebmb_entry(node, struct quic_connection_id, node);
|
||||
if (qc == id->qc)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Retrieve the DCID from a QUIC datagram or packet with <buf> as first octet.
|
||||
* Returns 1 if succeeded, 0 if not.
|
||||
*/
|
||||
|
167
src/quic_sock.c
167
src/quic_sock.c
@ -22,6 +22,7 @@
|
||||
#include <haproxy/api.h>
|
||||
#include <haproxy/buf.h>
|
||||
#include <haproxy/connection.h>
|
||||
#include <haproxy/dynbuf.h>
|
||||
#include <haproxy/fd.h>
|
||||
#include <haproxy/freq_ctr.h>
|
||||
#include <haproxy/global-t.h>
|
||||
@ -487,84 +488,14 @@ void quic_lstnr_sock_fd_iocb(int fd)
|
||||
/* FD-owned quic-conn socket callback. */
|
||||
static void quic_conn_sock_fd_iocb(int fd)
|
||||
{
|
||||
struct quic_conn *qc;
|
||||
struct quic_conn *qc = fdtab[fd].owner;
|
||||
|
||||
struct sockaddr_storage saddr = {0}, daddr = {0};
|
||||
struct quic_receiver_buf *rxbuf;
|
||||
struct quic_transport_params *params;
|
||||
struct quic_dgram *new_dgram;
|
||||
struct buffer *buf;
|
||||
size_t max_sz;
|
||||
size_t cspace;
|
||||
unsigned char *dgram_buf;
|
||||
struct listener *l;
|
||||
ssize_t ret = 0;
|
||||
|
||||
qc = fdtab[fd].owner;
|
||||
l = qc->li;
|
||||
TRACE_ENTER(QUIC_EV_CONN_RCV, qc);
|
||||
|
||||
new_dgram = NULL;
|
||||
rxbuf = MT_LIST_POP(&l->rx.rxbuf_list, typeof(rxbuf), rxbuf_el);
|
||||
if (!rxbuf)
|
||||
return;
|
||||
tasklet_wakeup_after(NULL, qc->wait_event.tasklet);
|
||||
fd_stop_recv(fd);
|
||||
|
||||
buf = &rxbuf->buf;
|
||||
new_dgram = quic_rxbuf_purge_dgrams(rxbuf);
|
||||
|
||||
params = &l->bind_conf->quic_params;
|
||||
max_sz = params->max_udp_payload_size;
|
||||
cspace = b_contig_space(buf);
|
||||
if (cspace < max_sz) {
|
||||
struct quic_dgram *dgram;
|
||||
|
||||
/* Do no mark <buf> as full, and do not try to consume it
|
||||
* if the contiguous remaining space is not at the end
|
||||
*/
|
||||
if (b_tail(buf) + cspace < b_wrap(buf))
|
||||
goto end;
|
||||
|
||||
/* Allocate a fake datagram, without data to locate
|
||||
* the end of the RX buffer (required during purging).
|
||||
*/
|
||||
dgram = pool_alloc(pool_head_quic_dgram);
|
||||
if (!dgram)
|
||||
goto end;
|
||||
|
||||
/* Initialize only the useful members of this fake datagram. */
|
||||
dgram->buf = NULL;
|
||||
dgram->len = cspace;
|
||||
/* Append this datagram only to the RX buffer list. It will
|
||||
* not be treated by any datagram handler.
|
||||
*/
|
||||
LIST_APPEND(&rxbuf->dgram_list, &dgram->recv_list);
|
||||
|
||||
/* Consume the remaining space */
|
||||
b_add(buf, cspace);
|
||||
if (b_contig_space(buf) < max_sz)
|
||||
goto end;
|
||||
}
|
||||
|
||||
dgram_buf = (unsigned char *)b_tail(buf);
|
||||
ret = quic_recv(qc->fd, dgram_buf, max_sz,
|
||||
(struct sockaddr *)&saddr, sizeof(saddr),
|
||||
(struct sockaddr *)&daddr, sizeof(daddr),
|
||||
get_net_port(&qc->local_addr));
|
||||
if (ret <= 0)
|
||||
goto end;
|
||||
|
||||
b_add(buf, ret);
|
||||
if (!quic_lstnr_dgram_dispatch(dgram_buf, ret, l, &qc->peer_addr, &qc->local_addr,
|
||||
new_dgram, &rxbuf->dgram_list)) {
|
||||
b_del(buf, ret);
|
||||
}
|
||||
new_dgram = NULL;
|
||||
|
||||
end:
|
||||
pool_free(pool_head_quic_dgram, new_dgram);
|
||||
MT_LIST_APPEND(&l->rx.rxbuf_list, &rxbuf->rxbuf_el);
|
||||
TRACE_LEAVE(QUIC_EV_CONN_RCV, qc);
|
||||
return;
|
||||
}
|
||||
|
||||
/* 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,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Receive datagram on <qc> FD-owned socket.
|
||||
*
|
||||
* Returns the total number of bytes read or a negative value on error.
|
||||
*/
|
||||
int qc_rcv_buf(struct quic_conn *qc)
|
||||
{
|
||||
struct sockaddr_storage saddr = {0}, daddr = {0};
|
||||
struct quic_transport_params *params;
|
||||
struct quic_dgram *new_dgram = NULL;
|
||||
struct buffer buf = BUF_NULL;
|
||||
size_t max_sz;
|
||||
unsigned char *dgram_buf;
|
||||
struct listener *l;
|
||||
ssize_t ret = 0;
|
||||
|
||||
/* Do not call this if quic-conn FD is uninitialized. */
|
||||
BUG_ON(qc->fd < 0);
|
||||
|
||||
TRACE_ENTER(QUIC_EV_CONN_RCV, qc);
|
||||
l = qc->li;
|
||||
|
||||
params = &l->bind_conf->quic_params;
|
||||
max_sz = params->max_udp_payload_size;
|
||||
|
||||
do {
|
||||
if (!b_alloc(&buf))
|
||||
break; /* TODO subscribe for memory again available. */
|
||||
|
||||
b_reset(&buf);
|
||||
BUG_ON(b_contig_space(&buf) < max_sz);
|
||||
|
||||
/* Allocate datagram on first loop or after requeuing. */
|
||||
if (!new_dgram && !(new_dgram = pool_alloc(pool_head_quic_dgram)))
|
||||
break; /* TODO subscribe for memory again available. */
|
||||
|
||||
dgram_buf = (unsigned char *)b_tail(&buf);
|
||||
ret = quic_recv(qc->fd, dgram_buf, max_sz,
|
||||
(struct sockaddr *)&saddr, sizeof(saddr),
|
||||
(struct sockaddr *)&daddr, sizeof(daddr),
|
||||
get_net_port(&qc->local_addr));
|
||||
if (ret <= 0) {
|
||||
/* Subscribe FD for future reception. */
|
||||
fd_want_recv(qc->fd);
|
||||
break;
|
||||
}
|
||||
|
||||
b_add(&buf, ret);
|
||||
|
||||
new_dgram->buf = dgram_buf;
|
||||
new_dgram->len = ret;
|
||||
new_dgram->dcid_len = 0;
|
||||
new_dgram->dcid = NULL;
|
||||
new_dgram->saddr = saddr;
|
||||
new_dgram->daddr = daddr;
|
||||
new_dgram->qc = NULL; /* set later via quic_dgram_parse() */
|
||||
|
||||
TRACE_DEVEL("read datagram", QUIC_EV_CONN_RCV, qc, new_dgram);
|
||||
|
||||
if (!quic_get_dgram_dcid(new_dgram->buf,
|
||||
new_dgram->buf + new_dgram->len,
|
||||
&new_dgram->dcid, &new_dgram->dcid_len)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!qc_check_dcid(qc, new_dgram->dcid, new_dgram->dcid_len)) {
|
||||
/* Datagram received by error on the connection FD, dispatch it
|
||||
* to its associated quic-conn.
|
||||
*
|
||||
* TODO count redispatch datagrams.
|
||||
*/
|
||||
TRACE_STATE("wrong datagram on quic-conn socket, prepare to requeue it", QUIC_EV_CONN_RCV, qc);
|
||||
ABORT_NOW();
|
||||
}
|
||||
|
||||
quic_dgram_parse(new_dgram, qc, qc->li);
|
||||
/* A datagram must always be consumed after quic_parse_dgram(). */
|
||||
BUG_ON(new_dgram->buf);
|
||||
} while (ret > 0);
|
||||
|
||||
pool_free(pool_head_quic_dgram, new_dgram);
|
||||
|
||||
if (b_size(&buf)) {
|
||||
b_free(&buf);
|
||||
offer_buffers(NULL, 1);
|
||||
}
|
||||
|
||||
TRACE_LEAVE(QUIC_EV_CONN_RCV, qc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* 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.
|
||||
|
Loading…
Reference in New Issue
Block a user