MINOR: quic: allocate a socket per quic-conn

Allocate quic-conn owned socket if possible. This requires that this is
activated in haproxy configuration. Also, this is done only if local
address is known so it depends on the support of IP_PKTINFO.

For the moment this socket is not used. This causes QUIC support to be
broken as received datagram are not read. This commit will be completed
by a following patch to support recv operation on the newly allocated
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:
Amaury Denoyelle 2022-10-24 17:08:43 +02:00
parent 511ddd5785
commit 40909dfec5
4 changed files with 109 additions and 0 deletions

View File

@ -625,6 +625,8 @@ struct quic_conn {
const struct quic_version *negotiated_version;
/* Negotiated version Initial TLS context */
struct quic_tls_ctx negotiated_ictx;
/* Connection owned socket FD. */
int fd;
/* QUIC transport parameters TLS extension */
int tps_tls_ext;
/* Thread ID this connection is attached to */

View File

@ -32,6 +32,7 @@
#include <haproxy/api.h>
#include <haproxy/connection-t.h>
#include <haproxy/listener-t.h>
#include <haproxy/quic_conn-t.h>
#include <haproxy/quic_sock-t.h>
int quic_session_accept(struct connection *cli_conn);
@ -45,6 +46,24 @@ void quic_sock_fd_iocb(int fd);
int qc_snd_buf(struct quic_conn *qc, const struct buffer *buf, size_t count,
int flags);
/* Set default value for <qc> socket as uninitialized. */
static inline void qc_init_fd(struct quic_conn *qc)
{
qc->fd = -1;
}
/* Returns true if <qc> socket is initialized else false. */
static inline char qc_test_fd(struct quic_conn *qc)
{
/* quic-conn socket should not be accessed once it has been released. */
BUG_ON(qc->fd == DEAD_FD_MAGIC);
return qc->fd >= 0;
}
void qc_alloc_fd(struct quic_conn *qc, const struct sockaddr_storage *src,
const struct sockaddr_storage *dst);
void qc_release_fd(struct quic_conn *qc);
void quic_accept_push_qc(struct quic_conn *qc);
#endif /* USE_QUIC */

View File

@ -4817,6 +4817,15 @@ static struct quic_conn *qc_new_conn(const struct quic_version *qv, int ipv4,
goto err;
}
if ((global.tune.options & GTUNE_QUIC_SOCK_PER_CONN) &&
is_addr(local_addr)) {
TRACE_USER("Allocate a socket for QUIC connection", QUIC_EV_CONN_INIT, qc);
qc_alloc_fd(qc, local_addr, peer_addr);
}
else {
qc_init_fd(qc);
}
/* insert the allocated CID in the receiver datagram handler tree */
if (server)
ebmb_insert(&quic_dghdlrs[tid].cids, &icid->node, icid->cid.len);
@ -4936,6 +4945,9 @@ void quic_conn_release(struct quic_conn *qc)
/* We must not free the quic-conn if the MUX is still allocated. */
BUG_ON(qc->mux_state == QC_MUX_READY);
/* Close quic-conn socket fd. */
qc_release_fd(qc);
/* in the unlikely (but possible) case the connection was just added to
* the accept_list we must delete it from there.
*/

View File

@ -27,6 +27,7 @@
#include <haproxy/global-t.h>
#include <haproxy/list.h>
#include <haproxy/listener.h>
#include <haproxy/log.h>
#include <haproxy/pool.h>
#include <haproxy/proto_quic.h>
#include <haproxy/proxy-t.h>
@ -531,6 +532,81 @@ int qc_snd_buf(struct quic_conn *qc, const struct buffer *buf, size_t sz,
return 0;
}
/* 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.
*
* Return the socket FD or a negative error code. On error, socket is marked as
* uninitialized.
*/
void qc_alloc_fd(struct quic_conn *qc, const struct sockaddr_storage *src,
const struct sockaddr_storage *dst)
{
struct proxy *p = qc->li->bind_conf->frontend;
int fd = -1;
int ret;
/* Must not happen. */
BUG_ON(src->ss_family != dst->ss_family);
qc_init_fd(qc);
fd = socket(src->ss_family, SOCK_DGRAM, 0);
if (fd < 0)
goto err;
if (fd >= global.maxsock) {
send_log(p, LOG_EMERG,
"Proxy %s reached the configured maximum connection limit. Please check the global 'maxconn' value.\n",
p->id);
goto err;
}
ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
if (ret < 0)
goto err;
switch (src->ss_family) {
case AF_INET:
#if defined(IP_PKTINFO)
ret = setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one));
#elif defined(IP_RECVDSTADDR)
ret = setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &one, sizeof(one));
#endif /* IP_PKTINFO || IP_RECVDSTADDR */
break;
case AF_INET6:
#ifdef IPV6_RECVPKTINFO
ret = setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one));
#endif
break;
}
if (ret < 0)
goto err;
ret = bind(fd, (struct sockaddr *)src, get_addr_len(src));
if (ret < 0)
goto err;
ret = connect(fd, (struct sockaddr *)dst, get_addr_len(dst));
if (ret < 0)
goto err;
qc->fd = fd;
fd_set_nonblock(fd);
return;
err:
if (fd >= 0)
close(fd);
}
/* Release socket file-descriptor specific for QUIC connection <qc>. */
void qc_release_fd(struct quic_conn *qc)
{
if (qc_test_fd(qc))
qc->fd = DEAD_FD_MAGIC;
}
/*********************** QUIC accept queue management ***********************/
/* per-thread accept queues */