Internal change
PiperOrigin-RevId: 465087216
diff --git a/quiche/quic/core/quic_udp_socket.h b/quiche/quic/core/quic_udp_socket.h
index 441ceef..6e3199d 100644
--- a/quiche/quic/core/quic_udp_socket.h
+++ b/quiche/quic/core/quic_udp_socket.h
@@ -15,6 +15,10 @@
#include "quiche/quic/platform/api/quic_ip_address.h"
#include "quiche/quic/platform/api/quic_socket_address.h"
+#ifndef UDP_GRO
+#define UDP_GRO 104
+#endif
+
namespace quic {
using QuicUdpSocketFd = SocketFd;
@@ -31,6 +35,7 @@
TTL, // Read & Write
GOOGLE_PACKET_HEADER, // Read
NUM_BITS,
+ IS_GRO, // Read
};
static_assert(static_cast<size_t>(QuicUdpPacketInfoBit::NUM_BITS) <=
BitMask64::NumBits(),
@@ -70,6 +75,13 @@
bitmask_.Set(QuicUdpPacketInfoBit::DROPPED_PACKETS);
}
+ void set_gso_size(size_t gso_size) {
+ gso_size_ = gso_size;
+ bitmask_.Set(QuicUdpPacketInfoBit::IS_GRO);
+ }
+
+ size_t gso_size() { return gso_size_; }
+
const QuicIpAddress& self_v4_ip() const {
QUICHE_DCHECK(HasValue(QuicUdpPacketInfoBit::V4_SELF_IP));
return self_v4_ip_;
@@ -147,6 +159,7 @@
QuicWallTime receive_timestamp_ = QuicWallTime::Zero();
int ttl_;
BufferSpan google_packet_headers_;
+ size_t gso_size_ = 0;
};
// QuicUdpSocketApi provides a minimal set of apis for sending and receiving
diff --git a/quiche/quic/core/quic_udp_socket_posix.cc b/quiche/quic/core/quic_udp_socket_posix.cc
index 8a7fa77..f6eac60 100644
--- a/quiche/quic/core/quic_udp_socket_posix.cc
+++ b/quiche/quic/core/quic_udp_socket_posix.cc
@@ -83,6 +83,13 @@
void PopulatePacketInfoFromControlMessage(struct cmsghdr* cmsg,
QuicUdpPacketInfo* packet_info,
BitMask64 packet_info_interested) {
+#ifdef SOL_UDP
+ if (packet_info_interested.IsSet(QuicUdpPacketInfoBit::IS_GRO) &&
+ cmsg->cmsg_level == SOL_UDP && cmsg->cmsg_type == UDP_GRO) {
+ packet_info->set_gso_size(*reinterpret_cast<uint16_t*>(CMSG_DATA(cmsg)));
+ }
+#endif
+
#if defined(__linux__) && defined(SO_RXQ_OVFL)
if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SO_RXQ_OVFL) {
if (packet_info_interested.IsSet(QuicUdpPacketInfoBit::DROPPED_PACKETS)) {
@@ -427,87 +434,102 @@
BitMask64 packet_info_interested,
ReadPacketResults* results) {
#if defined(__linux__) && !defined(__ANDROID__)
- // Use recvmmsg.
- size_t hdrs_size = sizeof(mmsghdr) * results->size();
- mmsghdr* hdrs = static_cast<mmsghdr*>(alloca(hdrs_size));
- memset(hdrs, 0, hdrs_size);
-
- struct TempPerPacketData {
- iovec iov;
- sockaddr_storage raw_peer_address;
- };
- TempPerPacketData* packet_data_array = static_cast<TempPerPacketData*>(
- alloca(sizeof(TempPerPacketData) * results->size()));
-
- for (size_t i = 0; i < results->size(); ++i) {
- (*results)[i].ok = false;
-
- msghdr* hdr = &hdrs[i].msg_hdr;
- TempPerPacketData* packet_data = &packet_data_array[i];
- packet_data->iov.iov_base = (*results)[i].packet_buffer.buffer;
- packet_data->iov.iov_len = (*results)[i].packet_buffer.buffer_len;
-
- hdr->msg_name = &packet_data->raw_peer_address;
- hdr->msg_namelen = sizeof(sockaddr_storage);
- hdr->msg_iov = &packet_data->iov;
- hdr->msg_iovlen = 1;
- hdr->msg_flags = 0;
- hdr->msg_control = (*results)[i].control_buffer.buffer;
- hdr->msg_controllen = (*results)[i].control_buffer.buffer_len;
-
- QUICHE_DCHECK_GE(hdr->msg_controllen, kMinCmsgSpaceForRead);
- }
- // If MSG_TRUNC is set on Linux, recvmmsg will return the real packet size in
- // |hdrs[i].msg_len| even if packet buffer is too small to receive it.
- int packets_read = recvmmsg(fd, hdrs, results->size(), MSG_TRUNC, nullptr);
- if (packets_read <= 0) {
- const int error_num = errno;
- if (error_num != EAGAIN) {
- QUIC_LOG_FIRST_N(ERROR, 100)
- << "Error reading packets: " << strerror(error_num);
+ if (packet_info_interested.IsSet(QuicUdpPacketInfoBit::IS_GRO)) {
+ size_t num_packets = 0;
+ for (ReadPacketResult& result : *results) {
+ result.ok = false;
}
- return 0;
- }
+ for (ReadPacketResult& result : *results) {
+ ReadPacket(fd, packet_info_interested, &result);
+ if (!result.ok) {
+ break;
+ }
+ ++num_packets;
+ }
+ return num_packets;
+ } else {
+ // Use recvmmsg.
+ size_t hdrs_size = sizeof(mmsghdr) * results->size();
+ mmsghdr* hdrs = static_cast<mmsghdr*>(alloca(hdrs_size));
+ memset(hdrs, 0, hdrs_size);
- for (int i = 0; i < packets_read; ++i) {
- if (hdrs[i].msg_len == 0) {
- continue;
+ struct TempPerPacketData {
+ iovec iov;
+ sockaddr_storage raw_peer_address;
+ };
+ TempPerPacketData* packet_data_array = static_cast<TempPerPacketData*>(
+ alloca(sizeof(TempPerPacketData) * results->size()));
+
+ for (size_t i = 0; i < results->size(); ++i) {
+ (*results)[i].ok = false;
+
+ msghdr* hdr = &hdrs[i].msg_hdr;
+ TempPerPacketData* packet_data = &packet_data_array[i];
+ packet_data->iov.iov_base = (*results)[i].packet_buffer.buffer;
+ packet_data->iov.iov_len = (*results)[i].packet_buffer.buffer_len;
+
+ hdr->msg_name = &packet_data->raw_peer_address;
+ hdr->msg_namelen = sizeof(sockaddr_storage);
+ hdr->msg_iov = &packet_data->iov;
+ hdr->msg_iovlen = 1;
+ hdr->msg_flags = 0;
+ hdr->msg_control = (*results)[i].control_buffer.buffer;
+ hdr->msg_controllen = (*results)[i].control_buffer.buffer_len;
+
+ QUICHE_DCHECK_GE(hdr->msg_controllen, kMinCmsgSpaceForRead);
+ }
+ // If MSG_TRUNC is set on Linux, recvmmsg will return the real packet size
+ // in |hdrs[i].msg_len| even if packet buffer is too small to receive it.
+ int packets_read = recvmmsg(fd, hdrs, results->size(), MSG_TRUNC, nullptr);
+ if (packets_read <= 0) {
+ const int error_num = errno;
+ if (error_num != EAGAIN) {
+ QUIC_LOG_FIRST_N(ERROR, 100)
+ << "Error reading packets: " << strerror(error_num);
+ }
+ return 0;
}
- msghdr& hdr = hdrs[i].msg_hdr;
- if (ABSL_PREDICT_FALSE(hdr.msg_flags & MSG_CTRUNC)) {
- QUIC_BUG(quic_bug_10751_4) << "Control buffer too small. size:"
- << (*results)[i].control_buffer.buffer_len
- << ", need:" << hdr.msg_controllen;
- continue;
- }
+ for (int i = 0; i < packets_read; ++i) {
+ if (hdrs[i].msg_len == 0) {
+ continue;
+ }
- if (ABSL_PREDICT_FALSE(hdr.msg_flags & MSG_TRUNC)) {
- QUIC_LOG_FIRST_N(WARNING, 100)
- << "Received truncated QUIC packet: buffer size:"
- << (*results)[i].packet_buffer.buffer_len
- << " packet size:" << hdrs[i].msg_len;
- continue;
- }
+ msghdr& hdr = hdrs[i].msg_hdr;
+ if (ABSL_PREDICT_FALSE(hdr.msg_flags & MSG_CTRUNC)) {
+ QUIC_BUG(quic_bug_10751_4) << "Control buffer too small. size:"
+ << (*results)[i].control_buffer.buffer_len
+ << ", need:" << hdr.msg_controllen;
+ continue;
+ }
- (*results)[i].ok = true;
- (*results)[i].packet_buffer.buffer_len = hdrs[i].msg_len;
+ if (ABSL_PREDICT_FALSE(hdr.msg_flags & MSG_TRUNC)) {
+ QUIC_LOG_FIRST_N(WARNING, 100)
+ << "Received truncated QUIC packet: buffer size:"
+ << (*results)[i].packet_buffer.buffer_len
+ << " packet size:" << hdrs[i].msg_len;
+ continue;
+ }
- QuicUdpPacketInfo* packet_info = &(*results)[i].packet_info;
- if (packet_info_interested.IsSet(QuicUdpPacketInfoBit::PEER_ADDRESS)) {
- packet_info->SetPeerAddress(
- QuicSocketAddress(packet_data_array[i].raw_peer_address));
- }
+ (*results)[i].ok = true;
+ (*results)[i].packet_buffer.buffer_len = hdrs[i].msg_len;
- if (hdr.msg_controllen > 0) {
- for (struct cmsghdr* cmsg = CMSG_FIRSTHDR(&hdr); cmsg != nullptr;
- cmsg = CMSG_NXTHDR(&hdr, cmsg)) {
- PopulatePacketInfoFromControlMessage(cmsg, packet_info,
- packet_info_interested);
+ QuicUdpPacketInfo* packet_info = &(*results)[i].packet_info;
+ if (packet_info_interested.IsSet(QuicUdpPacketInfoBit::PEER_ADDRESS)) {
+ packet_info->SetPeerAddress(
+ QuicSocketAddress(packet_data_array[i].raw_peer_address));
+ }
+
+ if (hdr.msg_controllen > 0) {
+ for (struct cmsghdr* cmsg = CMSG_FIRSTHDR(&hdr); cmsg != nullptr;
+ cmsg = CMSG_NXTHDR(&hdr, cmsg)) {
+ PopulatePacketInfoFromControlMessage(cmsg, packet_info,
+ packet_info_interested);
+ }
}
}
+ return packets_read;
}
- return packets_read;
#else
size_t num_packets = 0;
for (ReadPacketResult& result : *results) {