Skip to content

Commit

Permalink
Alter IP_TOS socket call for ECN based on platform. Fixes guitar fail…
Browse files Browse the repository at this point in the history
…ure. 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
  • Loading branch information
martinduke authored and copybara-github committed Mar 9, 2023
1 parent 01ee322 commit 3add075
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 7 deletions.
21 changes: 21 additions & 0 deletions quiche/common/platform/api/quiche_udp_socket_platform_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand All @@ -20,6 +22,25 @@ inline bool GetGooglePacketHeadersFromControlMessage(

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_
2 changes: 2 additions & 0 deletions quiche/quic/core/quic_flags_list.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ QUIC_FLAG(quic_reloadable_flag_quic_check_retire_cid_with_next_cid_sequence_numb
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.
Expand Down
2 changes: 1 addition & 1 deletion quiche/quic/core/quic_packet_writer.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ struct QUIC_EXPORT_PRIVATE PerPacketOptions {
// 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
Expand Down
29 changes: 23 additions & 6 deletions quiche/quic/core/quic_udp_socket_posix.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -664,18 +664,35 @@ WriteResult QuicUdpSocketApi::WritePacket(
}
#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;
Expand Down

0 comments on commit 3add075

Please sign in to comment.