mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-07 07:37:02 +02:00
MEDIUM: quic: use quic-conn socket for reception
Try to use the quic-conn socket for reception if it is allocated. For this, the socket is inserted in the fdtab. This will call the new handler quic_conn_io_cb() which is responsible to process the recv() system call. It will reuse datagram dispatch for simplicity. However, this is guaranteed to be called on the quic-conn thread, so it will be more efficient to use a dedicated buffer. This will be implemented in another commit. This patch should improve performance by reducing contention on the receiver socket. However, more gain can be obtained when the datagram dispatch operation will be skipped. Older quic_sock_fd_iocb() is renamed to quic_lstnr_sock_fd_iocb() to emphasize its usage for the receiver socket. 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
dc0dcb394b
commit
5b41486b7f
@ -221,6 +221,7 @@ enum quic_pkt_type {
|
||||
#define QUIC_EV_CONN_IDLE_TIMER (1ULL << 45)
|
||||
#define QUIC_EV_CONN_SUB (1ULL << 46)
|
||||
#define QUIC_EV_CONN_ELEVELSEL (1ULL << 47)
|
||||
#define QUIC_EV_CONN_RCV (1ULL << 48)
|
||||
|
||||
/* Similar to kernel min()/max() definitions. */
|
||||
#define QUIC_MIN(a, b) ({ \
|
||||
|
@ -42,7 +42,7 @@ 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);
|
||||
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);
|
||||
|
||||
|
@ -96,7 +96,7 @@ struct protocol proto_quic4 = {
|
||||
.rx_disable = sock_disable,
|
||||
.rx_unbind = sock_unbind,
|
||||
.rx_listening = quic_sock_accepting_conn,
|
||||
.default_iocb = quic_sock_fd_iocb,
|
||||
.default_iocb = quic_lstnr_sock_fd_iocb,
|
||||
.receivers = LIST_HEAD_INIT(proto_quic4.receivers),
|
||||
.nb_receivers = 0,
|
||||
};
|
||||
@ -136,7 +136,7 @@ struct protocol proto_quic6 = {
|
||||
.rx_disable = sock_disable,
|
||||
.rx_unbind = sock_unbind,
|
||||
.rx_listening = quic_sock_accepting_conn,
|
||||
.default_iocb = quic_sock_fd_iocb,
|
||||
.default_iocb = quic_lstnr_sock_fd_iocb,
|
||||
.receivers = LIST_HEAD_INIT(proto_quic6.receivers),
|
||||
.nb_receivers = 0,
|
||||
};
|
||||
|
@ -165,6 +165,7 @@ static const struct trace_event quic_trace_events[] = {
|
||||
{ .mask = QUIC_EV_TRANSP_PARAMS, .name = "transport_params", .desc = "transport parameters"},
|
||||
{ .mask = QUIC_EV_CONN_IDLE_TIMER, .name = "idle_timer", .desc = "idle timer task"},
|
||||
{ .mask = QUIC_EV_CONN_SUB, .name = "xprt_sub", .desc = "RX/TX subcription or unsubscription to QUIC xprt"},
|
||||
{ .mask = QUIC_EV_CONN_RCV, .name = "conn_recv", .desc = "RX on connection" },
|
||||
{ /* end */ }
|
||||
};
|
||||
|
||||
@ -672,6 +673,13 @@ static void quic_trace(enum trace_level level, uint64_t mask, const struct trace
|
||||
chunk_appendf(&trace_buf, " next_level=%c", quic_enc_level_char(*next_level));
|
||||
|
||||
}
|
||||
|
||||
if (mask & QUIC_EV_CONN_RCV) {
|
||||
const struct quic_dgram *dgram = a2;
|
||||
|
||||
if (dgram)
|
||||
chunk_appendf(&trace_buf, " dgram.len=%zu", dgram->len);
|
||||
}
|
||||
}
|
||||
if (mask & QUIC_EV_CONN_LPKT) {
|
||||
const struct quic_rx_packet *pkt = a2;
|
||||
|
@ -39,6 +39,9 @@
|
||||
#include <haproxy/task.h>
|
||||
#include <haproxy/trace.h>
|
||||
#include <haproxy/tools.h>
|
||||
#include <haproxy/trace.h>
|
||||
|
||||
#define TRACE_SOURCE &trace_quic
|
||||
|
||||
#define TRACE_SOURCE &trace_quic
|
||||
|
||||
@ -383,7 +386,7 @@ static ssize_t quic_recv(int fd, void *out, size_t len,
|
||||
/* Function called on a read event from a listening socket. It tries
|
||||
* to handle as many connections as possible.
|
||||
*/
|
||||
void quic_sock_fd_iocb(int fd)
|
||||
void quic_lstnr_sock_fd_iocb(int fd)
|
||||
{
|
||||
ssize_t ret;
|
||||
struct quic_receiver_buf *rxbuf;
|
||||
@ -481,6 +484,89 @@ void quic_sock_fd_iocb(int fd)
|
||||
MT_LIST_APPEND(&l->rx.rxbuf_list, &rxbuf->rxbuf_el);
|
||||
}
|
||||
|
||||
/* FD-owned quic-conn socket callback. */
|
||||
static void quic_conn_sock_fd_iocb(int fd)
|
||||
{
|
||||
struct quic_conn *qc;
|
||||
|
||||
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;
|
||||
|
||||
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.
|
||||
* The caller must ensure there is at least <sz> bytes in this buffer.
|
||||
*
|
||||
@ -602,6 +688,8 @@ void qc_alloc_fd(struct quic_conn *qc, const struct sockaddr_storage *src,
|
||||
|
||||
qc->fd = fd;
|
||||
fd_set_nonblock(fd);
|
||||
fd_insert(fd, qc, quic_conn_sock_fd_iocb, tgid, ti->ltid_bit);
|
||||
fd_want_recv(fd);
|
||||
|
||||
return;
|
||||
|
||||
@ -613,8 +701,10 @@ void qc_alloc_fd(struct quic_conn *qc, const struct sockaddr_storage *src,
|
||||
/* Release socket file-descriptor specific for QUIC connection <qc>. */
|
||||
void qc_release_fd(struct quic_conn *qc)
|
||||
{
|
||||
if (qc_test_fd(qc))
|
||||
if (qc_test_fd(qc)) {
|
||||
fd_delete(qc->fd);
|
||||
qc->fd = DEAD_FD_MAGIC;
|
||||
}
|
||||
}
|
||||
|
||||
/*********************** QUIC accept queue management ***********************/
|
||||
|
Loading…
Reference in New Issue
Block a user