From 8b950f40fab9231845d2d735289dad349f6cc449 Mon Sep 17 00:00:00 2001 From: Amaury Denoyelle Date: Tue, 20 Feb 2024 10:44:48 +0100 Subject: [PATCH] MINOR: quic: only use sendmsg() syscall variant This patch is the direct followup of the previous one : MINOR: quic: remove sendto() usage variant This finalizes qc_snd_buf() simplification by removing send() syscall usage for quic-conn owned socket. Syscall invocation is merged in a single code location to the sendmsg() variant. The only difference for owned socket is that destination address for sendmsg() is set to NULL. This usage is documented in man 2 sendmsg as valid for connected sockets. This allows maximum performance by avoiding unnecessary lookups on kernel socket address tables. As the previous patch, no functional change should happen here. However, it will be simpler to extend qc_snd_buf() for GSO usage. --- include/haproxy/quic_sock.h | 8 ++++ src/quic_sock.c | 84 ++++++++++++++++++++----------------- 2 files changed, 54 insertions(+), 38 deletions(-) diff --git a/include/haproxy/quic_sock.h b/include/haproxy/quic_sock.h index 531cf62a0..723614752 100644 --- a/include/haproxy/quic_sock.h +++ b/include/haproxy/quic_sock.h @@ -72,6 +72,14 @@ static inline char qc_test_fd(struct quic_conn *qc) return qc->fd >= 0; } +/* Returns active socket for connection. This may be its owned connection + * socket or the listener one as a fallback. + */ +static inline int qc_fd(struct quic_conn *qc) +{ + return qc_test_fd(qc) ? qc->fd : qc->li->rx.fd; +} + /* Try to increment handshake current counter. If listener limit is * reached, incrementation is rejected and 0 is returned. */ diff --git a/src/quic_sock.c b/src/quic_sock.c index 45f6bb85c..6d80b0450 100644 --- a/src/quic_sock.c +++ b/src/quic_sock.c @@ -661,49 +661,57 @@ int qc_snd_buf(struct quic_conn *qc, const struct buffer *buf, size_t sz, int flags) { ssize_t ret; + struct msghdr msg; + struct iovec vec; + struct cmsghdr *cmsg __maybe_unused = NULL; + + union { +#ifdef IP_PKTINFO + char buf[CMSG_SPACE(sizeof(struct in_pktinfo))]; +#endif /* IP_PKTINFO */ +#ifdef IPV6_RECVPKTINFO + char buf6[CMSG_SPACE(sizeof(struct in6_pktinfo))]; +#endif /* IPV6_RECVPKTINFO */ + char bufaddr[CMSG_SPACE(sizeof(struct in_addr))]; + struct cmsghdr align; + } ancillary_data; + + vec.iov_base = b_peek(buf, b_head_ofs(buf)); + vec.iov_len = sz; + + /* man 2 sendmsg + * + * The msg_name field is used on an unconnected socket to specify the + * target address for a datagram. It points to a buffer containing the + * address; the msg_namelen field should be set to the size of the + * address. For a connected socket, these fields should be specified + * as NULL and 0, respectively. + */ + if (!qc_test_fd(qc)) { + msg.msg_name = &qc->peer_addr; + msg.msg_namelen = get_addr_len(&qc->peer_addr); + } + else { + msg.msg_name = NULL; + msg.msg_namelen = 0; + } + + msg.msg_iov = &vec; + msg.msg_iovlen = 1; + msg.msg_control = NULL; + msg.msg_controllen = 0; if (qc_test_fd(qc) && !fd_send_ready(qc->fd)) return 0; + /* Set source address when using listener socket if possible. */ + if (!qc_test_fd(qc) && is_addr(&qc->local_addr)) { + msg.msg_control = ancillary_data.bufaddr; + cmsg_set_saddr(&msg, &cmsg, &qc->local_addr); + } + do { - if (qc_test_fd(qc)) { - ret = send(qc->fd, b_peek(buf, b_head_ofs(buf)), sz, - MSG_DONTWAIT | MSG_NOSIGNAL); - } - else { - struct msghdr msg; - struct iovec vec; - struct cmsghdr *cmsg __maybe_unused = NULL; - - union { -#ifdef IP_PKTINFO - char buf[CMSG_SPACE(sizeof(struct in_pktinfo))]; -#endif /* IP_PKTINFO */ -#ifdef IPV6_RECVPKTINFO - char buf6[CMSG_SPACE(sizeof(struct in6_pktinfo))]; -#endif /* IPV6_RECVPKTINFO */ - char bufaddr[CMSG_SPACE(sizeof(struct in_addr))]; - struct cmsghdr align; - } ancillary_data; - - vec.iov_base = b_peek(buf, b_head_ofs(buf)); - vec.iov_len = sz; - - msg.msg_name = &qc->peer_addr; - msg.msg_namelen = get_addr_len(&qc->peer_addr); - msg.msg_iov = &vec; - msg.msg_iovlen = 1; - msg.msg_control = NULL; - msg.msg_controllen = 0; - - /* Set source address for listener socket if known. */ - if (is_addr(&qc->local_addr)) { - msg.msg_control = ancillary_data.bufaddr; - cmsg_set_saddr(&msg, &cmsg, &qc->local_addr); - } - - ret = sendmsg(qc->li->rx.fd, &msg, MSG_DONTWAIT|MSG_NOSIGNAL); - } + ret = sendmsg(qc_fd(qc), &msg, MSG_DONTWAIT|MSG_NOSIGNAL); } while (ret < 0 && errno == EINTR); if (ret < 0) {