Alter IP_TOS socket call for ECN based on platform. Fixes guitar failure. Respect existing DSCP configuration when setting ECN. Protected by FLAGS_quic_restart_flag_quic_gfe_socket_factory_ecn_sockets, --quic_restart_flag_quic_gfe_socket_factory_ecn_sockets. PiperOrigin-RevId: 515378267
diff --git a/quiche/common/platform/api/quiche_udp_socket_platform_api.h b/quiche/common/platform/api/quiche_udp_socket_platform_api.h index 30ae2d5..a426c14 100644 --- a/quiche/common/platform/api/quiche_udp_socket_platform_api.h +++ b/quiche/common/platform/api/quiche_udp_socket_platform_api.h
@@ -6,6 +6,8 @@ #define QUICHE_COMMON_PLATFORM_API_QUICHE_UDP_SOCKET_PLATFORM_API_H_ #include "quiche_platform_impl/quiche_udp_socket_platform_impl.h" +#include "quiche/quic/core/quic_types.h" +#include "quiche/common/quiche_ip_address_family.h" namespace quiche { @@ -20,6 +22,25 @@ inline void SetGoogleSocketOptions(int fd) { SetGoogleSocketOptionsImpl(fd); } +// Retrieves the IP TOS byte for |fd| and |address_family|, based on the correct +// sockopt for the platform, replaces the two ECN bits of that byte with the +// value in |ecn_codepoint|. +// The result is stored in |value| in the proper format to set the TOS byte +// using a cmsg. |value| must point to memory of size |value_len|. Stores the +// correct cmsg type to use in |type|. +// Returns 0 on success. Returns EINVAL if |address_family| is neither IP_V4 nor +// IP_V6, or if |value_len| is not large enough to store the appropriately +// formatted argument. If getting the socket option fails, returns the +// associated error code. +inline int GetEcnCmsgArgsPreserveDscp( + const int fd, const quiche::IpAddressFamily address_family, + quic::QuicEcnCodepoint ecn_codepoint, int& type, void* value, + socklen_t& value_len) { + return GetEcnCmsgArgsPreserveDscpImpl( + fd, ToPlatformAddressFamily(address_family), + static_cast<uint8_t>(ecn_codepoint), type, value, value_len); +} + } // namespace quiche #endif // QUICHE_COMMON_PLATFORM_API_QUICHE_UDP_SOCKET_PLATFORM_API_H_
diff --git a/quiche/quic/core/quic_flags_list.h b/quiche/quic/core/quic_flags_list.h index ced3670..7a96366 100644 --- a/quiche/quic/core/quic_flags_list.h +++ b/quiche/quic/core/quic_flags_list.h
@@ -83,6 +83,8 @@ QUIC_FLAG(quic_reloadable_flag_quic_conservative_cwnd_and_pacing_gains, false) // If true, when TicketCrypter fails to encrypt a session ticket, quic::TlsServerHandshaker will send a placeholder ticket, instead of an empty one, to the client. QUIC_FLAG(quic_reloadable_flag_quic_send_placeholder_ticket_when_encrypt_ticket_fails, true) +// When true, check what sockopt is used to set the IP TOS byte on the platform. +QUIC_FLAG(quic_restart_flag_quic_platform_tos_sockopt, false) // When true, defaults to BBR congestion control instead of Cubic. QUIC_FLAG(quic_reloadable_flag_quic_default_to_bbr, false) // When true, quiche UDP sockets report Explicit Congestion Notification (ECN) [RFC3168, RFC9330] results.
diff --git a/quiche/quic/core/quic_packet_writer.h b/quiche/quic/core/quic_packet_writer.h index 5ebbfe0..3e6cb21 100644 --- a/quiche/quic/core/quic_packet_writer.h +++ b/quiche/quic/core/quic_packet_writer.h
@@ -35,7 +35,7 @@ // Whether it is allowed to send this packet without |release_time_delay|. bool allow_burst = false; // ECN codepoint to use when sending this packet. - QuicEcnCodepoint ecn_codepoint; + QuicEcnCodepoint ecn_codepoint = ECN_NOT_ECT; }; // An interface between writers and the entity managing the
diff --git a/quiche/quic/core/quic_udp_socket_posix.cc b/quiche/quic/core/quic_udp_socket_posix.cc index d1d5177..26d4ef4 100644 --- a/quiche/quic/core/quic_udp_socket_posix.cc +++ b/quiche/quic/core/quic_udp_socket_posix.cc
@@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "quiche/quic/core/quic_types.h" #if defined(__APPLE__) && !defined(__APPLE_USE_RFC_3542) // This must be defined before including any system headers. #define __APPLE_USE_RFC_3542 @@ -20,7 +21,6 @@ #include "quiche/quic/core/quic_udp_socket.h" #include "quiche/quic/platform/api/quic_bug_tracker.h" #include "quiche/quic/platform/api/quic_flag_utils.h" -#include "quiche/quic/platform/api/quic_ip_address_family.h" #include "quiche/quic/platform/api/quic_udp_socket_platform_api.h" #if defined(__APPLE__) && !defined(__APPLE_USE_RFC_3542) @@ -664,18 +664,35 @@ } #endif + // TODO(b/270584616): This code block might go away when full support for + // marking ECN is implemented. if (packet_info.HasValue(QuicUdpPacketInfoBit::ECN)) { int cmsg_level = packet_info.peer_address().host().IsIPv4() ? IPPROTO_IP : IPPROTO_IPV6; - int cmsg_type = - packet_info.peer_address().host().IsIPv4() ? IP_TOS : IPV6_TCLASS; + int cmsg_type; + unsigned char value_buf[20]; + socklen_t value_len = sizeof(value_buf); + if (GetQuicRestartFlag(quic_platform_tos_sockopt)) { + QUIC_RESTART_FLAG_COUNT(quic_platform_tos_sockopt); + if (GetEcnCmsgArgsPreserveDscp( + fd, packet_info.peer_address().host().address_family(), + packet_info.ecn_codepoint(), cmsg_type, value_buf, + value_len) != 0) { + QUIC_LOG_FIRST_N(ERROR, 100) + << "Could not get ECN msg type for this platform."; + return WriteResult(WRITE_STATUS_ERROR, EINVAL); + } + } else { + cmsg_type = (cmsg_level == IPPROTO_IP) ? IP_TOS : IPV6_TCLASS; + *(int*)value_buf = static_cast<int>(packet_info.ecn_codepoint()); + value_len = sizeof(int); + } if (!NextCmsg(&hdr, control_buffer, sizeof(control_buffer), cmsg_level, - cmsg_type, sizeof(int), &cmsg)) { + cmsg_type, value_len, &cmsg)) { QUIC_LOG_FIRST_N(ERROR, 100) << "Not enough buffer to set ECN."; return WriteResult(WRITE_STATUS_ERROR, EINVAL); } - *reinterpret_cast<int*>(CMSG_DATA(cmsg)) = - static_cast<int>(packet_info.ecn_codepoint()); + memcpy(CMSG_DATA(cmsg), value_buf, value_len); } int rc;