quic: enable UDP GRO

Closes #14012
This commit is contained in:
Tatsuhiro Tsujikawa 2024-06-25 18:51:03 +09:00 committed by Daniel Stenberg
parent 411af83010
commit a571afc02e
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
2 changed files with 102 additions and 11 deletions

View File

@ -35,6 +35,9 @@
#elif defined(HAVE_NETINET_TCP_H)
#include <netinet/tcp.h>
#endif
#ifdef HAVE_NETINET_UDP_H
#include <netinet/udp.h>
#endif
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
@ -1852,6 +1855,9 @@ static CURLcode cf_udp_setup_quic(struct Curl_cfilter *cf,
{
struct cf_socket_ctx *ctx = cf->ctx;
int rc;
int one = 1;
(void)one;
/* QUIC needs a connected socket, nonblocking */
DEBUGASSERT(ctx->sock != CURL_SOCKET_BAD);
@ -1892,6 +1898,13 @@ static CURLcode cf_udp_setup_quic(struct Curl_cfilter *cf,
}
#endif
}
#if defined(UDP_GRO) && (defined(HAVE_SENDMMSG) || defined(HAVE_SENDMSG)) && \
((defined(USE_NGTCP2) && defined(USE_NGHTTP3)) || defined(USE_QUICHE))
(void)setsockopt(ctx->sock, IPPROTO_UDP, UDP_GRO, &one,
(socklen_t)sizeof(one));
#endif
return CURLE_OK;
}

View File

@ -36,6 +36,9 @@
#include "curl_setup.h"
#ifdef HAVE_NETINET_UDP_H
#include <netinet/udp.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
@ -329,6 +332,36 @@ CURLcode vquic_send_tail_split(struct Curl_cfilter *cf, struct Curl_easy *data,
return vquic_flush(cf, data, qctx);
}
#if defined(HAVE_SENDMMSG) || defined(HAVE_SENDMSG)
static size_t msghdr_get_udp_gro(struct msghdr *msg)
{
uint16_t gso_size = 0;
#ifdef UDP_GRO
struct cmsghdr *cmsg;
/* Workaround musl CMSG_NXTHDR issue */
#ifndef __GLIBC__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wsign-compare"
#pragma clang diagnostic ignored "-Wcast-align"
#endif
for(cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
#ifndef __GLIBC__
#pragma clang diagnostic pop
#endif
if(cmsg->cmsg_level == SOL_UDP && cmsg->cmsg_type == UDP_GRO) {
memcpy(&gso_size, CMSG_DATA(cmsg), sizeof(gso_size));
break;
}
}
#endif
(void)msg;
return gso_size;
}
#endif
#ifdef HAVE_SENDMMSG
static CURLcode recvmmsg_packets(struct Curl_cfilter *cf,
struct Curl_easy *data,
@ -339,12 +372,16 @@ static CURLcode recvmmsg_packets(struct Curl_cfilter *cf,
#define MMSG_NUM 64
struct iovec msg_iov[MMSG_NUM];
struct mmsghdr mmsg[MMSG_NUM];
uint8_t msg_ctrl[MMSG_NUM * CMSG_SPACE(sizeof(uint16_t))];
uint8_t bufs[MMSG_NUM][2*1024];
struct sockaddr_storage remote_addr[MMSG_NUM];
size_t total_nread, pkts;
int mcount, i, n;
char errstr[STRERROR_LEN];
CURLcode result = CURLE_OK;
size_t gso_size;
size_t pktlen;
size_t offset, to;
DEBUGASSERT(max_pkts > 0);
pkts = 0;
@ -359,6 +396,8 @@ static CURLcode recvmmsg_packets(struct Curl_cfilter *cf,
mmsg[i].msg_hdr.msg_iovlen = 1;
mmsg[i].msg_hdr.msg_name = &remote_addr[i];
mmsg[i].msg_hdr.msg_namelen = sizeof(remote_addr[i]);
mmsg[i].msg_hdr.msg_control = &msg_ctrl[i];
mmsg[i].msg_hdr.msg_controllen = CMSG_SPACE(sizeof(uint16_t));
}
while((mcount = recvmmsg(qctx->sockfd, mmsg, n, 0, NULL)) == -1 &&
@ -385,14 +424,30 @@ static CURLcode recvmmsg_packets(struct Curl_cfilter *cf,
}
CURL_TRC_CF(data, cf, "recvmmsg() -> %d packets", mcount);
pkts += mcount;
for(i = 0; i < mcount; ++i) {
total_nread += mmsg[i].msg_len;
result = recv_cb(bufs[i], mmsg[i].msg_len,
mmsg[i].msg_hdr.msg_name, mmsg[i].msg_hdr.msg_namelen,
0, userp);
if(result)
goto out;
gso_size = msghdr_get_udp_gro(&mmsg[i].msg_hdr);
if(gso_size == 0) {
gso_size = mmsg[i].msg_len;
}
for(offset = 0; offset < mmsg[i].msg_len; offset = to) {
++pkts;
to = offset + gso_size;
if(to > mmsg[i].msg_len) {
pktlen = mmsg[i].msg_len - offset;
}
else {
pktlen = gso_size;
}
result = recv_cb(bufs[i] + offset, pktlen, mmsg[i].msg_hdr.msg_name,
mmsg[i].msg_hdr.msg_namelen, 0, userp);
if(result)
goto out;
}
}
}
@ -418,6 +473,10 @@ static CURLcode recvmsg_packets(struct Curl_cfilter *cf,
ssize_t nread;
char errstr[STRERROR_LEN];
CURLcode result = CURLE_OK;
uint8_t msg_ctrl[CMSG_SPACE(sizeof(uint16_t))];
size_t gso_size;
size_t pktlen;
size_t offset, to;
msg_iov.iov_base = buf;
msg_iov.iov_len = (int)sizeof(buf);
@ -425,11 +484,13 @@ static CURLcode recvmsg_packets(struct Curl_cfilter *cf,
memset(&msg, 0, sizeof(msg));
msg.msg_iov = &msg_iov;
msg.msg_iovlen = 1;
msg.msg_control = msg_ctrl;
DEBUGASSERT(max_pkts > 0);
for(pkts = 0, total_nread = 0; pkts < max_pkts;) {
msg.msg_name = &remote_addr;
msg.msg_namelen = sizeof(remote_addr);
msg.msg_controllen = sizeof(msg_ctrl);
while((nread = recvmsg(qctx->sockfd, &msg, 0)) == -1 &&
SOCKERRNO == EINTR)
;
@ -452,12 +513,29 @@ static CURLcode recvmsg_packets(struct Curl_cfilter *cf,
goto out;
}
++pkts;
total_nread += (size_t)nread;
result = recv_cb(buf, (size_t)nread, msg.msg_name, msg.msg_namelen,
0, userp);
if(result)
goto out;
gso_size = msghdr_get_udp_gro(&msg);
if(gso_size == 0) {
gso_size = (size_t)nread;
}
for(offset = 0; offset < (size_t)nread; offset = to) {
++pkts;
to = offset + gso_size;
if(to > (size_t)nread) {
pktlen = (size_t)nread - offset;
}
else {
pktlen = gso_size;
}
result =
recv_cb(buf + offset, pktlen, msg.msg_name, msg.msg_namelen, 0, userp);
if(result)
goto out;
}
}
out: