mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-07 15:47:01 +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_connection_close(struct quic_conn *qc, const struct quic_err err);
|
||||||
void quic_set_tls_alert(struct quic_conn *qc, int alert);
|
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 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,
|
int quic_get_dgram_dcid(unsigned char *buf, const unsigned char *end,
|
||||||
unsigned char **dcid, size_t *dcid_len);
|
unsigned char **dcid, size_t *dcid_len);
|
||||||
int qc_send_mux(struct quic_conn *qc, struct list *frms);
|
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);
|
void quic_lstnr_sock_fd_iocb(int fd);
|
||||||
int qc_snd_buf(struct quic_conn *qc, const struct buffer *buf, size_t count,
|
int qc_snd_buf(struct quic_conn *qc, const struct buffer *buf, size_t count,
|
||||||
int flags);
|
int flags);
|
||||||
|
int qc_rcv_buf(struct quic_conn *qc);
|
||||||
|
|
||||||
/* Set default value for <qc> socket as uninitialized. */
|
/* Set default value for <qc> socket as uninitialized. */
|
||||||
static inline void qc_init_fd(struct quic_conn *qc)
|
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_ENTER(QUIC_EV_CONN_IO_CB, qc);
|
||||||
TRACE_STATE("connection handshake state", QUIC_EV_CONN_IO_CB, qc, &qc->state);
|
TRACE_STATE("connection handshake state", QUIC_EV_CONN_IO_CB, qc, &qc->state);
|
||||||
|
|
||||||
|
if (qc_test_fd(qc))
|
||||||
|
qc_rcv_buf(qc);
|
||||||
|
|
||||||
/* Retranmissions */
|
/* Retranmissions */
|
||||||
if (qc->flags & QUIC_FL_CONN_RETRANS_NEEDED) {
|
if (qc->flags & QUIC_FL_CONN_RETRANS_NEEDED) {
|
||||||
TRACE_STATE("retransmission needed", QUIC_EV_CONN_IO_CB, qc);
|
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 &&
|
zero_rtt = st < QUIC_HS_ST_COMPLETE &&
|
||||||
quic_tls_has_rx_sec(eqel) &&
|
quic_tls_has_rx_sec(eqel) &&
|
||||||
(!LIST_ISEMPTY(&eqel->rx.pqpkts) || qc_el_rx_pkts(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 &&
|
if (st >= QUIC_HS_ST_COMPLETE &&
|
||||||
qc_el_rx_pkts(&qc->els[QUIC_TLS_ENC_LEVEL_HANDSHAKE])) {
|
qc_el_rx_pkts(&qc->els[QUIC_TLS_ENC_LEVEL_HANDSHAKE])) {
|
||||||
TRACE_DEVEL("remaining Handshake packets", QUIC_EV_CONN_PHPKTS, qc);
|
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;
|
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.
|
/* Retrieve the DCID from a QUIC datagram or packet with <buf> as first octet.
|
||||||
* Returns 1 if succeeded, 0 if not.
|
* 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/api.h>
|
||||||
#include <haproxy/buf.h>
|
#include <haproxy/buf.h>
|
||||||
#include <haproxy/connection.h>
|
#include <haproxy/connection.h>
|
||||||
|
#include <haproxy/dynbuf.h>
|
||||||
#include <haproxy/fd.h>
|
#include <haproxy/fd.h>
|
||||||
#include <haproxy/freq_ctr.h>
|
#include <haproxy/freq_ctr.h>
|
||||||
#include <haproxy/global-t.h>
|
#include <haproxy/global-t.h>
|
||||||
@ -487,84 +488,14 @@ void quic_lstnr_sock_fd_iocb(int fd)
|
|||||||
/* FD-owned quic-conn socket callback. */
|
/* FD-owned quic-conn socket callback. */
|
||||||
static void quic_conn_sock_fd_iocb(int fd)
|
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);
|
TRACE_ENTER(QUIC_EV_CONN_RCV, qc);
|
||||||
|
|
||||||
new_dgram = NULL;
|
tasklet_wakeup_after(NULL, qc->wait_event.tasklet);
|
||||||
rxbuf = MT_LIST_POP(&l->rx.rxbuf_list, typeof(rxbuf), rxbuf_el);
|
fd_stop_recv(fd);
|
||||||
if (!rxbuf)
|
|
||||||
return;
|
|
||||||
|
|
||||||
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);
|
TRACE_LEAVE(QUIC_EV_CONN_RCV, qc);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Send a datagram stored into <buf> buffer with <sz> as size.
|
/* 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;
|
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>.
|
/* Allocate a socket file-descriptor specific for QUIC connection <qc>.
|
||||||
* Endpoint addresses are specified by the two following arguments : <src> is
|
* Endpoint addresses are specified by the two following arguments : <src> is
|
||||||
* the local address and <dst> is the remote one.
|
* the local address and <dst> is the remote one.
|
||||||
|
Loading…
Reference in New Issue
Block a user