From 02c82b21afa8c5a7255a236b48591029f8f5f4cc Mon Sep 17 00:00:00 2001
From: Anthony Rossi <41394064+anrossi@users.noreply.github.com>
Date: Mon, 20 Jan 2025 20:16:21 -0800
Subject: [PATCH 01/13] Add support for setting TypeOfService/TrafficClass on
connections
---
docs/Settings.md | 1 +
src/core/connection.c | 58 ++++++++++++
src/core/connection.h | 6 ++
src/inc/msquic.h | 1 +
src/inc/quic_datapath.h | 19 ++++
src/platform/datapath_epoll.c | 94 +++++++++++++++++++
src/platform/datapath_raw.c | 14 ++-
src/platform/datapath_raw.h | 2 +
src/platform/datapath_raw_linux.c | 1 +
src/platform/datapath_raw_socket.c | 15 +--
src/platform/datapath_raw_win.c | 1 +
src/platform/datapath_winkernel.c | 143 ++++++++++++++++++++++++++++-
src/platform/datapath_winuser.c | 132 ++++++++++++++++++++++++++
src/platform/datapath_xplat.c | 19 ++++
src/platform/platform_internal.h | 14 +++
15 files changed, 511 insertions(+), 9 deletions(-)
diff --git a/docs/Settings.md b/docs/Settings.md
index 9df659b894..21f94492d8 100644
--- a/docs/Settings.md
+++ b/docs/Settings.md
@@ -177,6 +177,7 @@ These parameters are accessed by calling [GetParam](./api/GetParam.md) or [SetPa
| `QUIC_PARAM_CONN_STATISTICS_V2`
22 | QUIC_STATISTICS_V2 | Get-only | Connection-level statistics, version 2. |
| `QUIC_PARAM_CONN_STATISTICS_V2_PLAT`
23 | QUIC_STATISTICS_V2 | Get-only | Connection-level statistics with platform-specific time format, version 2. |
| `QUIC_PARAM_CONN_ORIG_DEST_CID`
24 | uint8_t[] | Get-only | The original destination connection ID used by the client to connect to the server. |
+| `QUIC_PARAM_CONN_TYPE_OF_SERVICE`
25 | uint8_t | Both | The value put in the Type of Service/Traffic Class field on packets sent from this connection. |
### QUIC_PARAM_CONN_STATISTICS_V2
diff --git a/src/core/connection.c b/src/core/connection.c
index b59d19ba45..60ee3a95cb 100644
--- a/src/core/connection.c
+++ b/src/core/connection.c
@@ -1837,6 +1837,7 @@ QuicConnStart(
UdpConfig.Flags = Connection->State.ShareBinding ? CXPLAT_SOCKET_FLAG_SHARE : 0;
UdpConfig.InterfaceIndex = Connection->State.LocalInterfaceSet ? (uint32_t)Path->Route.LocalAddress.Ipv6.sin6_scope_id : 0, // NOLINT(google-readability-casting)
UdpConfig.PartitionIndex = QuicPartitionIdGetIndex(Connection->PartitionID);
+ UdpConfig.TypeOfService = Connection->TypeOfService;
#ifdef QUIC_COMPARTMENT_ID
UdpConfig.CompartmentId = Configuration->CompartmentId;
#endif
@@ -6218,6 +6219,7 @@ QuicConnParamSet(
UdpConfig.RemoteAddress = &Connection->Paths[0].Route.RemoteAddress;
UdpConfig.Flags = Connection->State.ShareBinding ? CXPLAT_SOCKET_FLAG_SHARE : 0;
UdpConfig.InterfaceIndex = 0;
+ UdpConfig.TypeOfService = Connection->TypeOfService;
#ifdef QUIC_COMPARTMENT_ID
UdpConfig.CompartmentId = Connection->Configuration->CompartmentId;
#endif
@@ -6623,6 +6625,34 @@ QuicConnParamSet(
return QUIC_STATUS_SUCCESS;
}
+ case QUIC_PARAM_CONN_TYPE_OF_SERVICE:
+ {
+ if (BufferLength != sizeof(uint8_t) || Buffer == NULL) {
+ Status = QUIC_STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ uint8_t TypeOfService = 0;
+ CxPlatCopyMemory(&TypeOfService, Buffer, BufferLength);
+
+ if (TypeOfService > CXPLAT_MAX_TYPE_OF_SERVICE) {
+ Status = QUIC_STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ Connection->TypeOfService = TypeOfService;
+
+ if (Connection->State.Started) {
+ Status =
+ CxPlatSocketSetTypeOfService(
+ Connection->Paths[0].Binding->Socket,
+ TypeOfService);
+ } else {
+ Status = QUIC_STATUS_SUCCESS;
+ }
+ break;
+ }
+
//
// Private
//
@@ -7207,27 +7237,55 @@ QuicConnParamGet(
}
case QUIC_PARAM_CONN_ORIG_DEST_CID:
+
if (Connection->OrigDestCID == NULL) {
Status = QUIC_STATUS_INVALID_STATE;
break;
}
+
if (*BufferLength < Connection->OrigDestCID->Length) {
Status = QUIC_STATUS_BUFFER_TOO_SMALL;
*BufferLength = Connection->OrigDestCID->Length;
break;
}
+
if (Buffer == NULL) {
Status = QUIC_STATUS_INVALID_PARAMETER;
break;
}
+
CxPlatCopyMemory(
Buffer,
Connection->OrigDestCID->Data,
Connection->OrigDestCID->Length);
+
//
// Tell app how much buffer we copied.
//
*BufferLength = Connection->OrigDestCID->Length;
+
+ Status = QUIC_STATUS_SUCCESS;
+ break;
+
+ case QUIC_PARAM_CONN_TYPE_OF_SERVICE:
+
+ if (*BufferLength < sizeof(Connection->TypeOfService)) {
+ Status = QUIC_STATUS_BUFFER_TOO_SMALL;
+ *BufferLength = sizeof(Connection->TypeOfService);
+ break;
+ }
+
+ if (Buffer == NULL) {
+ Status = QUIC_STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ CxPlatCopyMemory(
+ Buffer,
+ &Connection->TypeOfService,
+ sizeof(Connection->TypeOfService));
+
+ *BufferLength = sizeof(Connection->TypeOfService);
Status = QUIC_STATUS_SUCCESS;
break;
diff --git a/src/core/connection.h b/src/core/connection.h
index c754115f52..dd2229a580 100644
--- a/src/core/connection.h
+++ b/src/core/connection.h
@@ -462,6 +462,12 @@ typedef struct QUIC_CONNECTION {
//
uint8_t PeerReorderingThreshold;
+ //
+ // Type of Service value to set on the socket when the connection is started.
+ // Default value of 0.
+ //
+ uint8_t TypeOfService;
+
//
// The ACK frequency sequence number we are currently using to send.
//
diff --git a/src/inc/msquic.h b/src/inc/msquic.h
index b8dc5471db..4022b5ccab 100644
--- a/src/inc/msquic.h
+++ b/src/inc/msquic.h
@@ -923,6 +923,7 @@ typedef struct QUIC_SCHANNEL_CREDENTIAL_ATTRIBUTE_W {
#define QUIC_PARAM_CONN_STATISTICS_V2 0x05000016 // QUIC_STATISTICS_V2
#define QUIC_PARAM_CONN_STATISTICS_V2_PLAT 0x05000017 // QUIC_STATISTICS_V2
#define QUIC_PARAM_CONN_ORIG_DEST_CID 0x05000018 // uint8_t[]
+#define QUIC_PARAM_CONN_TYPE_OF_SERVICE 0x50000019 // uint8_t
//
// Parameters for TLS.
diff --git a/src/inc/quic_datapath.h b/src/inc/quic_datapath.h
index 9975f762a1..c5a6df64c6 100644
--- a/src/inc/quic_datapath.h
+++ b/src/inc/quic_datapath.h
@@ -58,6 +58,12 @@ typedef enum CXPLAT_ECN_TYPE {
//
#define CXPLAT_ECN_FROM_TOS(ToS) (CXPLAT_ECN_TYPE)((ToS) & 0x3)
+//
+// Define the maximum type of service value allowed.
+// Note: this is without the ECN bits included
+//
+#define CXPLAT_MAX_TYPE_OF_SERVICE 63
+
//
// The maximum IP MTU this implementation supports for QUIC.
//
@@ -444,6 +450,7 @@ CxPlatDataPathUpdateConfig(
#define CXPLAT_DATAPATH_FEATURE_TCP 0x0020
#define CXPLAT_DATAPATH_FEATURE_RAW 0x0040
#define CXPLAT_DATAPATH_FEATURE_TTL 0x0080
+#define CXPLAT_DATAPATH_FEATURE_TYPE_OF_SERVICE 0x0100
//
// Queries the currently supported features of the datapath.
@@ -544,6 +551,7 @@ typedef struct CXPLAT_UDP_CONFIG {
#ifdef QUIC_OWNING_PROCESS
QUIC_PROCESS OwningProcess; // Kernel client-only
#endif
+ uint8_t TypeOfService; // Default 0. Optional.
// used for RAW datapath
uint8_t CibirIdLength; // CIBIR ID length. Value of 0 indicates CIBIR isn't used
@@ -646,6 +654,17 @@ CxPlatSocketGetRemoteAddress(
_Out_ QUIC_ADDR* Address
);
+//
+// Sets TypeOfService on the socket. May fail if insufficient privileges exist
+// to set the desired value on the socket.
+//
+_IRQL_requires_max_(PASSIVE_LEVEL)
+QUIC_STATUS
+CxPlatSocketSetTypeOfService(
+ _In_ CXPLAT_SOCKET* Socket,
+ _In_ uint8_t TypeOfService
+ );
+
//
// Queries a raw socket availability.
//
diff --git a/src/platform/datapath_epoll.c b/src/platform/datapath_epoll.c
index 925880b36a..226d127624 100644
--- a/src/platform/datapath_epoll.c
+++ b/src/platform/datapath_epoll.c
@@ -340,6 +340,7 @@ CxPlatDataPathCalculateFeatureSupport(
Datapath->Features |= CXPLAT_DATAPATH_FEATURE_TCP;
Datapath->Features |= CXPLAT_DATAPATH_FEATURE_TTL;
+ Datapath->Features |= CXPLAT_DATAPATH_FEATURE_TYPE_OF_SERVICE;
}
void
@@ -887,6 +888,45 @@ CxPlatSocketContextInitialize(
goto Exit;
}
+ if (Config->TypeOfService != 0) {
+ Option = Config->TypeOfService;
+ Result =
+ setsockopt(
+ SocketContext->SocketFd,
+ IPPROTO_IP,
+ IP_TOS,
+ (const void*)&Option,
+ sizeof(Option));
+ if (Result == SOCKET_ERROR) {
+ Status = errno;
+ QuicTraceEvent(
+ DatapathErrorStatus,
+ "[data][%p] ERROR, %u, %s.",
+ Binding,
+ Status,
+ "setsockopt(IP_TOS) failed");
+ goto Exit;
+ }
+
+ Option = Config->TypeOfService;
+ Result =
+ setsockopt(
+ SocketContext->SocketFd,
+ IPPROTO_IPV6,
+ IPV6_TCLASS,
+ (const void*)&Option,
+ sizeof(Option));
+ if (Result == SOCKET_ERROR) {
+ Status = errno;
+ QuicTraceEvent(
+ DatapathErrorStatus,
+ "[data][%p] ERROR, %u, %s.",
+ Binding,
+ Status,
+ "setsockopt(IPV6_TCLASS) failed");
+ goto Exit;
+ }
+ }
#ifdef UDP_GRO
if (SocketContext->DatapathPartition->Datapath->Features & CXPLAT_DATAPATH_FEATURE_RECV_COALESCING) {
@@ -2455,6 +2495,60 @@ SocketSend(
}
}
+_IRQL_requires_max_(PASSIVE_LEVEL)
+QUIC_STATUS
+SocketSetTypeOfService(
+ _In_ CXPLAT_SOCKET* Socket,
+ _In_ uint8_t TypeOfService
+ )
+{
+ const uint16_t SocketCount = Socket->NumPerProcessorSockets ? (uint16_t)CxPlatProcCount() : 1;
+ QUIC_STATUS Status = QUIC_STATUS_SUCCESS;
+ for (uint16_t i = 0; i < SocketCount; i++) {
+ CXPLAT_SOCKET_CONTEXT* SocketContext = &Socket->SocketContexts[i];
+ int Option = TypeOfService;
+ int if (Config->TypeOfService != 0) {
+ Option = Config->TypeOfService;
+ Result =
+ setsockopt(
+ SocketContext->SocketFd,
+ IPPROTO_IP,
+ IP_TOS,
+ (const void*)&Option,
+ sizeof(Option));
+ if (Result == SOCKET_ERROR) {
+ Status = errno;
+ QuicTraceEvent(
+ DatapathErrorStatus,
+ "[data][%p] ERROR, %u, %s.",
+ Binding,
+ Status,
+ "setsockopt(IP_TOS) failed");
+ break;
+ }
+
+ Option = TypeOfService;
+ Result =
+ setsockopt(
+ SocketContext->SocketFd,
+ IPPROTO_IPV6,
+ IPV6_TCLASS,
+ (const void*)&Option,
+ sizeof(Option));
+ if (Result == SOCKET_ERROR) {
+ Status = errno;
+ QuicTraceEvent(
+ DatapathErrorStatus,
+ "[data][%p] ERROR, %u, %s.",
+ Binding,
+ Status,
+ "setsockopt(IPV6_TCLASS) failed");
+ break;
+ }
+ }
+ }
+ return Status;
+}
//
// This is defined and used instead of CMSG_NXTHDR because (1) we've already
// done the work to ensure the necessary space is available and (2) CMSG_NXTHDR
diff --git a/src/platform/datapath_raw.c b/src/platform/datapath_raw.c
index 57f342d91e..f594a3042f 100644
--- a/src/platform/datapath_raw.c
+++ b/src/platform/datapath_raw.c
@@ -371,7 +371,7 @@ RawSocketSend(
const CXPLAT_INTERFACE* Interface = CxPlatDpRawGetInterfaceFromQueue(Route->Queue);
CxPlatFramingWriteHeaders(
- Socket, Route, &SendData->Buffer, SendData->ECN,
+ Socket, Route, &SendData->Buffer, SendData->ECN, Socket->TypeOfService,
Interface->OffloadStatus.Transmit.NetworkLayerXsum,
Interface->OffloadStatus.Transmit.TransportLayerXsum,
Route->TcpState.SequenceNumber,
@@ -380,3 +380,15 @@ RawSocketSend(
CxPlatDpRawTxEnqueue(SendData);
return QUIC_STATUS_SUCCESS;
}
+
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+QUIC_STATUS
+RawSocketSetTypeOfService(
+ _In_ CXPLAT_SOCKET_RAW* Socket,
+ _In_ uint8_t TypeOfService
+ )
+{
+ Socket->TypeOfService = TypeOfService;
+ return QUIC_STATUS_SUCCESS;
+}
diff --git a/src/platform/datapath_raw.h b/src/platform/datapath_raw.h
index f54adc03a0..57a2a274b6 100644
--- a/src/platform/datapath_raw.h
+++ b/src/platform/datapath_raw.h
@@ -265,6 +265,7 @@ typedef struct CXPLAT_SOCKET_RAW {
SOCKET AuxSocket;
BOOLEAN Wildcard; // Using a wildcard local address. Optimization
// to avoid always reading LocalAddress.
+ uint8_t TypeOfService; // IP TypeOfService/IPv6 Traffic Class value. Default 0.
uint8_t CibirIdLength; // CIBIR ID length. Value of 0 indicates CIBIR isn't used
uint8_t CibirIdOffsetSrc; // CIBIR ID offset in source CID
uint8_t CibirIdOffsetDst; // CIBIR ID offset in destination CID
@@ -377,6 +378,7 @@ CxPlatFramingWriteHeaders(
_In_ const CXPLAT_ROUTE* Route,
_Inout_ QUIC_BUFFER* Buffer,
_In_ CXPLAT_ECN_TYPE ECN,
+ _In_ uint8_t TypeOfService,
_In_ BOOLEAN SkipNetworkLayerXsum,
_In_ BOOLEAN SkipTransportLayerXsum,
_In_ uint32_t TcpSeqNum,
diff --git a/src/platform/datapath_raw_linux.c b/src/platform/datapath_raw_linux.c
index 02fbf05dd4..139f202929 100644
--- a/src/platform/datapath_raw_linux.c
+++ b/src/platform/datapath_raw_linux.c
@@ -117,6 +117,7 @@ RawSocketCreateUdp(
NewSocket->CibirIdLength = Config->CibirIdLength;
NewSocket->CibirIdOffsetSrc = Config->CibirIdOffsetSrc;
NewSocket->CibirIdOffsetDst = Config->CibirIdOffsetDst;
+ NewSocket->TypeOfService = Config->TypeOfService;
NewSocket->AuxSocket = INVALID_SOCKET;
NewSocket->UseTcp = Raw->UseTcp;
if (Config->CibirIdLength) {
diff --git a/src/platform/datapath_raw_socket.c b/src/platform/datapath_raw_socket.c
index 48f448e92d..da9d26aadb 100644
--- a/src/platform/datapath_raw_socket.c
+++ b/src/platform/datapath_raw_socket.c
@@ -558,7 +558,7 @@ CxPlatDpRawSocketAckFin(
TCP_HEADER* ReceivedTcpHeader = (TCP_HEADER*)(Packet->Buffer - Packet->ReservedEx);
CxPlatFramingWriteHeaders(
- Socket, Route, &SendData->Buffer, SendData->ECN,
+ Socket, Route, &SendData->Buffer, SendData->ECN, Socket->TypeOfService,
Interface->OffloadStatus.Transmit.NetworkLayerXsum,
Interface->OffloadStatus.Transmit.TransportLayerXsum,
ReceivedTcpHeader->AckNumber,
@@ -599,7 +599,7 @@ CxPlatDpRawSocketAckSyn(
CASTED_CLOG_BYTEARRAY(sizeof(Route->LocalAddress), &Route->LocalAddress));
CxPlatFramingWriteHeaders(
- Socket, Route, &SendData->Buffer, SendData->ECN,
+ Socket, Route, &SendData->Buffer, SendData->ECN, Socket->TypeOfService,
Interface->OffloadStatus.Transmit.NetworkLayerXsum,
Interface->OffloadStatus.Transmit.TransportLayerXsum,
ReceivedTcpHeader->AckNumber,
@@ -619,7 +619,7 @@ CxPlatDpRawSocketAckSyn(
CASTED_CLOG_BYTEARRAY(sizeof(Route->RemoteAddress), &Route->RemoteAddress),
CASTED_CLOG_BYTEARRAY(sizeof(Route->LocalAddress), &Route->LocalAddress));
CxPlatFramingWriteHeaders(
- Socket, Route, &SendData->Buffer, SendData->ECN,
+ Socket, Route, &SendData->Buffer, SendData->ECN, Socket->TypeOfService,
Interface->OffloadStatus.Transmit.NetworkLayerXsum,
Interface->OffloadStatus.Transmit.TransportLayerXsum,
CxPlatByteSwapUint32(CxPlatByteSwapUint32(ReceivedTcpHeader->AckNumber) + 1),
@@ -642,7 +642,7 @@ CxPlatDpRawSocketAckSyn(
CASTED_CLOG_BYTEARRAY(sizeof(Route->RemoteAddress), &Route->RemoteAddress),
CASTED_CLOG_BYTEARRAY(sizeof(Route->LocalAddress), &Route->LocalAddress));
CxPlatFramingWriteHeaders(
- Socket, Route, &SendData->Buffer, SendData->ECN,
+ Socket, Route, &SendData->Buffer, SendData->ECN, Socket->TypeOfService,
Interface->OffloadStatus.Transmit.NetworkLayerXsum,
Interface->OffloadStatus.Transmit.TransportLayerXsum,
ReceivedTcpHeader->AckNumber,
@@ -678,7 +678,7 @@ CxPlatDpRawSocketSyn(
CXPLAT_DBG_ASSERT(Route->Queue != NULL);
const CXPLAT_INTERFACE* Interface = CxPlatDpRawGetInterfaceFromQueue(Route->Queue);
CxPlatFramingWriteHeaders(
- Socket, Route, &SendData->Buffer, SendData->ECN,
+ Socket, Route, &SendData->Buffer, SendData->ECN, Socket->TypeOfService,
Interface->OffloadStatus.Transmit.NetworkLayerXsum,
Interface->OffloadStatus.Transmit.TransportLayerXsum,
Route->TcpState.SequenceNumber, 0, TH_SYN);
@@ -692,6 +692,7 @@ CxPlatFramingWriteHeaders(
_In_ const CXPLAT_ROUTE* Route,
_Inout_ QUIC_BUFFER* Buffer,
_In_ CXPLAT_ECN_TYPE ECN,
+ _In_ uint8_t TypeOfService,
_In_ BOOLEAN SkipNetworkLayerXsum,
_In_ BOOLEAN SkipTransportLayerXsum,
_In_ uint32_t TcpSeqNum,
@@ -751,7 +752,7 @@ CxPlatFramingWriteHeaders(
if (Family == QUIC_ADDRESS_FAMILY_INET) {
IPV4_HEADER* IPv4 = (IPV4_HEADER*)(Transport - sizeof(IPV4_HEADER));
IPv4->VersionAndHeaderLength = IPV4_DEFAULT_VERHLEN;
- IPv4->TypeOfService = 0;
+ IPv4->TypeOfService = TypeOfService;
IPv4->EcnField = ECN;
IPv4->TotalLength = htons(sizeof(IPV4_HEADER) + TransportLength + (uint16_t)Buffer->Length);
IPv4->Identification = 0;
@@ -799,7 +800,7 @@ CxPlatFramingWriteHeaders(
} VersionClassEcnFlow = {0};
VersionClassEcnFlow.Version = IPV6_VERSION;
- VersionClassEcnFlow.Class = 0;
+ VersionClassEcnFlow.Class = TypeOfService;
VersionClassEcnFlow.EcnField = ECN;
VersionClassEcnFlow.Flow = (uint32_t)(uintptr_t)Socket;
diff --git a/src/platform/datapath_raw_win.c b/src/platform/datapath_raw_win.c
index d3f01926cd..fc4dba366d 100644
--- a/src/platform/datapath_raw_win.c
+++ b/src/platform/datapath_raw_win.c
@@ -118,6 +118,7 @@ RawSocketCreateUdp(
Socket->CibirIdLength = Config->CibirIdLength;
Socket->CibirIdOffsetSrc = Config->CibirIdOffsetSrc;
Socket->CibirIdOffsetDst = Config->CibirIdOffsetDst;
+ Socket->TypeOfService = Config->TypeOfService;
Socket->AuxSocket = INVALID_SOCKET;
if (Config->CibirIdLength) {
memcpy(Socket->CibirId, Config->CibirId, Config->CibirIdLength);
diff --git a/src/platform/datapath_winkernel.c b/src/platform/datapath_winkernel.c
index 57d7862ea3..cf2326732d 100644
--- a/src/platform/datapath_winkernel.c
+++ b/src/platform/datapath_winkernel.c
@@ -471,7 +471,7 @@ CxPlatDataPathQuerySockoptSupport(
Datapath->WskProviderNpi.Dispatch->
WskSocket(
Datapath->WskProviderNpi.Client,
- AF_INET,
+ AF_INET6,
SOCK_DGRAM,
IPPROTO_UDP,
WSK_FLAG_BASIC_SOCKET,
@@ -600,6 +600,54 @@ CxPlatDataPathQuerySockoptSupport(
} while (FALSE);
+ do {
+ DWORD TypeOfService = 1; // Lower Effort
+
+ IoReuseIrp(Irp, STATUS_SUCCESS);
+ IoSetCompletionRoutine(
+ Irp,
+ CxPlatDataPathIoCompletion,
+ &CompletionEvent,
+ TRUE,
+ TRUE,
+ TRUE);
+ CxPlatEventReset(CompletionEvent);
+
+ Status =
+ Dispatch->WskControlSocket(
+ UdpSocket,
+ WskSetOption,
+ IPV6_TCLASS,
+ IPPROTO_IPV6,
+ sizeof(TypeOfService),
+ &TypeOfService,
+ 0,
+ NULL,
+ &OutputSizeReturned,
+ Irp);
+ if (Status == STATUS_PENDING) {
+ CxPlatEventWaitForever(CompletionEvent);
+ } else if (QUIC_FAILED(Status)) {
+ QuicTraceLogWarning(
+ DatapathTestSetIpv6TrafficClassFailed,
+ "[data] Test setting IPV6_TCLASS failed, 0x%x",
+ Status);
+ break;
+ }
+
+ Status = Irp->IoStatus.Status;
+ if (QUIC_FAILED(Status)) {
+ QuicTraceLogWarning(
+ DatapathTestSetIpv6TrafficClassFailedAsync,
+ "[data] Test setting IPV6_TCLASS failed (async), 0x%x",
+ Status);
+ break;
+ }
+
+ Datapath->Features |= CXPLAT_DATAPATH_FEATURE_TYPE_OF_SERVICE;
+
+ } while (FALSE);
+
//
// Some USO/URO bug blocks TTL feature support on Windows Server 2022.
//
@@ -1552,6 +1600,47 @@ SocketCreateUdp(
}
}
+ if ((Datapath->Features & CXPLAT_DATAPATH_FEATURE_TYPE_OF_SERVICE) &&
+ Config->TypeOfService != 0) {
+ Option = Config->TypeOfService;
+ Status =
+ CxPlatDataPathSetControlSocket(
+ Binding,
+ WskSetOption,
+ IP_TOS,
+ IPPROTO_IP,
+ sizeof(Option),
+ &Option);
+ if (QUIC_FAILED(Status)) {
+ QuicTraceEvent(
+ DatapathErrorStatus,
+ "[data][%p] ERROR, %u, %s.",
+ Binding,
+ Status,
+ "Set IP_TOS");
+ goto Error;
+ }
+
+ Option = Config->TypeOfService;
+ Status =
+ CxPlatDataPathSetControlSocket(
+ Binding,
+ WskSetOption,
+ IPV6_TCLASS,
+ IPPROTO_IPV6,
+ sizeof(Option),
+ &Option);
+ if (QUIC_FAILED(Status)) {
+ QuicTraceEvent(
+ DatapathErrorStatus,
+ "[data][%p] ERROR, %u, %s.",
+ Binding,
+ Status,
+ "Set IPV6_TCLASS");
+ goto Error;
+ }
+ }
+
if (Datapath->Features & CXPLAT_DATAPATH_FEATURE_RECV_COALESCING) {
Option = MAX_URO_PAYLOAD_LENGTH;
Status =
@@ -2959,6 +3048,58 @@ SocketSend(
}
}
+_IRQL_requires_max_(PASSIVE_LEVEL)
+QUIC_STATUS
+SocketSetTypeOfService(
+ _In_ CXPLAT_SOCKET* Socket,
+ _In_ uint8_t TypeOfService
+ )
+{
+ QUIC_STATUS Status = QUIC_STATUS_SUCCESS;
+
+ uint32_t Option = TypeOfService;
+ Status =
+ CxPlatDataPathSetControlSocket(
+ Socket,
+ WskSetOption,
+ IP_TOS,
+ IPPROTO_IP,
+ sizeof(Option),
+ &Option);
+ if (QUIC_FAILED(Status)) {
+ QuicTraceEvent(
+ DatapathErrorStatus,
+ "[data][%p] ERROR, %u, %s.",
+ Binding,
+ Status,
+ "Set IP_TOS");
+ goto Error;
+ }
+
+ Option = Config->TypeOfService;
+ Status =
+ CxPlatDataPathSetControlSocket(
+ Socket,
+ WskSetOption,
+ IPV6_TCLASS,
+ IPPROTO_IPV6,
+ sizeof(Option),
+ &Option);
+ if (QUIC_FAILED(Status)) {
+ QuicTraceEvent(
+ DatapathErrorStatus,
+ "[data][%p] ERROR, %u, %s.",
+ Binding,
+ Status,
+ "Set IPV6_TCLASS");
+ goto Error;
+ }
+
+Error:
+
+ return Status;
+}
+
_IRQL_requires_max_(DISPATCH_LEVEL)
QUIC_STATUS
CxPlatSocketGetTcpStatistics(
diff --git a/src/platform/datapath_winuser.c b/src/platform/datapath_winuser.c
index 946ceaf271..c02745064d 100644
--- a/src/platform/datapath_winuser.c
+++ b/src/platform/datapath_winuser.c
@@ -701,6 +701,41 @@ CxPlatDataPathQuerySockoptSupport(
}
}
+{
+ //
+ // Test ToS support with IPv6, because IPv4 just fails silently.
+ //
+ SOCKET Udpv6Socket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+ if (UdpSocket == INVALID_SOCKET) {
+ int WsaError = WSAGetLastError();
+ QuicTraceLogWarning(
+ DatapathOpenUdpv6SocketFailed,
+ "[data] UDPv6 helper socket failed to open, 0x%x",
+ WsaError);
+ goto Error;
+ }
+
+ DWORD TypeOfService = 1; // Lower Effort
+ OptionLength = sizeof(TypeOfService);
+ Result =
+ setsockopt(
+ Udpv6Socket,
+ IPPROTO_IPV6,
+ IPV6_TCLASS,
+ (char*)&TypeOfService,
+ sizeof(TypeOfService));
+ if (Result != NO_ERROR) {
+ int WsaError = WSAGetLastError();
+ QuicTraceLogWarning(
+ DatapathTestSetIpv6TrafficClassFailed,
+ "[data] Test setting IPV6_TCLASS failed, 0x%x",
+ WsaError);
+ } else {
+ Datapath->Features |= CXPLAT_DATAPATH_FEATURE_TYPE_OF_SERVICE;
+ }
+ closesocket(Udpv6Socket);
+}
+
//
// Some USO/URO bug blocks TTL feature support on Windows Server 2022.
//
@@ -1729,6 +1764,49 @@ SocketCreateUdp(
}
}
+ if ((Datapath->Features & CXPLAT_DATAPATH_FEATURE_TYPE_OF_SERVICE) &&
+ Config->TypeOfService != 0) {
+ Option = Config->TypeOfService;
+ Result =
+ setsockopt(
+ SocketProc->Socket,
+ IPPROTO_IP,
+ IP_TOS,
+ (char*)&Option,
+ sizeof(Option));
+ if (Result == SOCKET_ERROR) {
+ int WsaError = WSAGetLastError();
+ QuicTraceEvent(
+ DatapathErrorStatus,
+ "[data][%p] ERROR, %u, %s.",
+ Socket,
+ WsaError,
+ "Set IP_TOS");
+ Status = HRESULT_FROM_WIN32(WsaError);
+ goto Error;
+ }
+
+ Option = Config->TypeOfService;
+ Result =
+ setsockopt(
+ SocketProc->Socket,
+ IPPROTO_IPV6,
+ IPV6_TCLASS,
+ (char*)&Option,
+ sizeof(Option));
+ if (Result == SOCKET_ERROR) {
+ int WsaError = WSAGetLastError();
+ QuicTraceEvent(
+ DatapathErrorStatus,
+ "[data][%p] ERROR, %u, %s.",
+ Socket,
+ WsaError,
+ "Set IPV6_TCLASS");
+ Status = HRESULT_FROM_WIN32(WsaError);
+ goto Error;
+ }
+ }
+
//
// The socket is shared by multiple endpoints, so increase the receive
// buffer size.
@@ -4632,6 +4710,60 @@ SocketSend(
}
}
+_IRQL_requires_max_(PASSIVE_LEVEL)
+QUIC_STATUS
+SocketSetTypeOfService(
+ _In_ CXPLAT_SOCKET* Socket,
+ _In_ uint8_t TypeOfService
+ )
+{
+ const uint16_t SocketCount = Socket->NumPerProcessorSockets ? (uint16_t)CxPlatProcCount() : 1;
+ QUIC_STATUS Status = QUIC_STATUS_SUCCESS;
+ for (uint16_t i = 0; i < SocketCount; i++) {
+ CXPLAT_SOCKET_PROC* SocketProc = &Socket->PerProcSockets[i];
+ int Option = TypeOfService;
+ int Result =
+ setsockopt(
+ SocketProc->Socket,
+ IPPROTO_IP,
+ IP_TOS,
+ (char*)&Option,
+ sizeof(Option));
+ if (Result == SOCKET_ERROR) {
+ int WsaError = WSAGetLastError();
+ QuicTraceEvent(
+ DatapathErrorStatus,
+ "[data][%p] ERROR, %u, %s.",
+ Socket,
+ WsaError,
+ "Set IP_TOS");
+ Status = HRESULT_FROM_WIN32(WsaError);
+ break;
+ }
+
+ Option = TypeOfService;
+ Result =
+ setsockopt(
+ SocketProc->Socket,
+ IPPROTO_IPV6,
+ IPV6_TCLASS,
+ (char*)&Option,
+ sizeof(Option));
+ if (Result == SOCKET_ERROR) {
+ int WsaError = WSAGetLastError();
+ QuicTraceEvent(
+ DatapathErrorStatus,
+ "[data][%p] ERROR, %u, %s.",
+ Socket,
+ WsaError,
+ "Set IPV6_TCLASS");
+ Status = HRESULT_FROM_WIN32(WsaError);
+ break;
+ }
+ }
+ return Status;
+}
+
void
CxPlatDataPathSocketProcessQueuedSend(
_In_ CXPLAT_SEND_DATA* SendData
diff --git a/src/platform/datapath_xplat.c b/src/platform/datapath_xplat.c
index c68ccb4047..1014a1b640 100644
--- a/src/platform/datapath_xplat.c
+++ b/src/platform/datapath_xplat.c
@@ -251,6 +251,25 @@ CxPlatSocketGetRemoteAddress(
*Address = Socket->RemoteAddress;
}
+_IRQL_requires_max_(PASSIVE_LEVEL)
+QUIC_STATUS
+CxPlatSocketSetTypeOfService(
+ _In_ CXPLAT_SOCKET* Socket,
+ _In_ uint8_t TypeOfService
+ )
+{
+ QUIC_STATUS Status;
+ if (Socket->RawSocketAvailable) {
+ Status = RawSocketSetTypeOfService(CxPlatSocketToRaw(Socket), TypeOfService);
+ if (QUIC_FAILED(Status)) {
+ return Status;
+ }
+ }
+ Status = SocketSetTypeOfService(Socket, TypeOfService);
+
+ return Status;
+}
+
_IRQL_requires_max_(DISPATCH_LEVEL)
BOOLEAN
CxPlatSocketRawSocketAvailable(
diff --git a/src/platform/platform_internal.h b/src/platform/platform_internal.h
index 4930ceb614..803fb381f6 100644
--- a/src/platform/platform_internal.h
+++ b/src/platform/platform_internal.h
@@ -1152,6 +1152,13 @@ SocketSend(
_In_ CXPLAT_SEND_DATA* SendData
);
+_IRQL_requires_max_(PASSIVE_LEVEL)
+QUIC_STATUS
+SocketSetTypeOfService(
+ _In_ CXPLAT_SOCKET* Socket,
+ _In_ uint8_t TypeOfService
+ );
+
CXPLAT_SOCKET*
CxPlatRawToSocket(
_In_ CXPLAT_SOCKET_RAW* Socket
@@ -1278,6 +1285,13 @@ RawSocketSend(
_In_ CXPLAT_SEND_DATA* SendData
);
+_IRQL_requires_max_(DISPATCH_LEVEL)
+QUIC_STATUS
+RawSocketSetTypeOfService(
+ _In_ CXPLAT_SOCKET_RAW* Socket,
+ _In_ uint8_t TypeOfService
+ );
+
void
RawResolveRouteComplete(
_In_ void* Context,
From 35949c1b57416b40f4953d6bc9a7df4cb04cdb05 Mon Sep 17 00:00:00 2001
From: Anthony Rossi <41394064+anrossi@users.noreply.github.com>
Date: Mon, 20 Jan 2025 20:27:19 -0800
Subject: [PATCH 02/13] Update generated files
---
src/cs/lib/msquic_generated.cs | 3 ++
.../linux/datapath_winkernel.c.clog.h | 36 +++++++++++++
.../linux/datapath_winkernel.c.clog.h.lttng.h | 38 ++++++++++++++
src/generated/linux/datapath_winuser.c.clog.h | 36 +++++++++++++
.../linux/datapath_winuser.c.clog.h.lttng.h | 38 ++++++++++++++
src/manifest/clog.sidecar | 51 +++++++++++++++++++
6 files changed, 202 insertions(+)
diff --git a/src/cs/lib/msquic_generated.cs b/src/cs/lib/msquic_generated.cs
index 3e6f9d96b7..0e567f1aff 100644
--- a/src/cs/lib/msquic_generated.cs
+++ b/src/cs/lib/msquic_generated.cs
@@ -3447,6 +3447,9 @@ internal static unsafe partial class MsQuic
[NativeTypeName("#define QUIC_PARAM_CONN_ORIG_DEST_CID 0x05000018")]
internal const uint QUIC_PARAM_CONN_ORIG_DEST_CID = 0x05000018;
+ [NativeTypeName("#define QUIC_PARAM_CONN_TYPE_OF_SERVICE 0x50000019")]
+ internal const uint QUIC_PARAM_CONN_TYPE_OF_SERVICE = 0x50000019;
+
[NativeTypeName("#define QUIC_PARAM_TLS_HANDSHAKE_INFO 0x06000000")]
internal const uint QUIC_PARAM_TLS_HANDSHAKE_INFO = 0x06000000;
diff --git a/src/generated/linux/datapath_winkernel.c.clog.h b/src/generated/linux/datapath_winkernel.c.clog.h
index 4e2479cf34..fa75a3704b 100644
--- a/src/generated/linux/datapath_winkernel.c.clog.h
+++ b/src/generated/linux/datapath_winkernel.c.clog.h
@@ -213,6 +213,42 @@ tracepoint(CLOG_DATAPATH_WINKERNEL_C, DatapathQueryRecvMaxCoalescedSizeFailedAsy
+/*----------------------------------------------------------
+// Decoder Ring for DatapathTestSetIpv6TrafficClassFailed
+// [data] Test setting IPV6_TCLASS failed, 0x%x
+// QuicTraceLogWarning(
+ DatapathTestSetIpv6TrafficClassFailed,
+ "[data] Test setting IPV6_TCLASS failed, 0x%x",
+ Status);
+// arg2 = arg2 = Status = arg2
+----------------------------------------------------------*/
+#ifndef _clog_3_ARGS_TRACE_DatapathTestSetIpv6TrafficClassFailed
+#define _clog_3_ARGS_TRACE_DatapathTestSetIpv6TrafficClassFailed(uniqueId, encoded_arg_string, arg2)\
+tracepoint(CLOG_DATAPATH_WINKERNEL_C, DatapathTestSetIpv6TrafficClassFailed , arg2);\
+
+#endif
+
+
+
+
+/*----------------------------------------------------------
+// Decoder Ring for DatapathTestSetIpv6TrafficClassFailedAsync
+// [data] Test setting IPV6_TCLASS failed (async), 0x%x
+// QuicTraceLogWarning(
+ DatapathTestSetIpv6TrafficClassFailedAsync,
+ "[data] Test setting IPV6_TCLASS failed (async), 0x%x",
+ Status);
+// arg2 = arg2 = Status = arg2
+----------------------------------------------------------*/
+#ifndef _clog_3_ARGS_TRACE_DatapathTestSetIpv6TrafficClassFailedAsync
+#define _clog_3_ARGS_TRACE_DatapathTestSetIpv6TrafficClassFailedAsync(uniqueId, encoded_arg_string, arg2)\
+tracepoint(CLOG_DATAPATH_WINKERNEL_C, DatapathTestSetIpv6TrafficClassFailedAsync , arg2);\
+
+#endif
+
+
+
+
/*----------------------------------------------------------
// Decoder Ring for DatapathDropEmptyMdl
// [%p] Dropping datagram with empty mdl.
diff --git a/src/generated/linux/datapath_winkernel.c.clog.h.lttng.h b/src/generated/linux/datapath_winkernel.c.clog.h.lttng.h
index 6efeb61ee7..704051c779 100644
--- a/src/generated/linux/datapath_winkernel.c.clog.h.lttng.h
+++ b/src/generated/linux/datapath_winkernel.c.clog.h.lttng.h
@@ -191,6 +191,44 @@ TRACEPOINT_EVENT(CLOG_DATAPATH_WINKERNEL_C, DatapathQueryRecvMaxCoalescedSizeFai
+/*----------------------------------------------------------
+// Decoder Ring for DatapathTestSetIpv6TrafficClassFailed
+// [data] Test setting IPV6_TCLASS failed, 0x%x
+// QuicTraceLogWarning(
+ DatapathTestSetIpv6TrafficClassFailed,
+ "[data] Test setting IPV6_TCLASS failed, 0x%x",
+ Status);
+// arg2 = arg2 = Status = arg2
+----------------------------------------------------------*/
+TRACEPOINT_EVENT(CLOG_DATAPATH_WINKERNEL_C, DatapathTestSetIpv6TrafficClassFailed,
+ TP_ARGS(
+ unsigned int, arg2),
+ TP_FIELDS(
+ ctf_integer(unsigned int, arg2, arg2)
+ )
+)
+
+
+
+/*----------------------------------------------------------
+// Decoder Ring for DatapathTestSetIpv6TrafficClassFailedAsync
+// [data] Test setting IPV6_TCLASS failed (async), 0x%x
+// QuicTraceLogWarning(
+ DatapathTestSetIpv6TrafficClassFailedAsync,
+ "[data] Test setting IPV6_TCLASS failed (async), 0x%x",
+ Status);
+// arg2 = arg2 = Status = arg2
+----------------------------------------------------------*/
+TRACEPOINT_EVENT(CLOG_DATAPATH_WINKERNEL_C, DatapathTestSetIpv6TrafficClassFailedAsync,
+ TP_ARGS(
+ unsigned int, arg2),
+ TP_FIELDS(
+ ctf_integer(unsigned int, arg2, arg2)
+ )
+)
+
+
+
/*----------------------------------------------------------
// Decoder Ring for DatapathDropEmptyMdl
// [%p] Dropping datagram with empty mdl.
diff --git a/src/generated/linux/datapath_winuser.c.clog.h b/src/generated/linux/datapath_winuser.c.clog.h
index c285e4e96b..b26f8b70b0 100644
--- a/src/generated/linux/datapath_winuser.c.clog.h
+++ b/src/generated/linux/datapath_winuser.c.clog.h
@@ -123,6 +123,42 @@ tracepoint(CLOG_DATAPATH_WINUSER_C, DatapathQueryRecvMaxCoalescedSizeFailed , ar
+/*----------------------------------------------------------
+// Decoder Ring for DatapathOpenUdpv6SocketFailed
+// [data] UDPv6 helper socket failed to open, 0x%x
+// QuicTraceLogWarning(
+ DatapathOpenUdpv6SocketFailed,
+ "[data] UDPv6 helper socket failed to open, 0x%x",
+ WsaError);
+// arg2 = arg2 = WsaError = arg2
+----------------------------------------------------------*/
+#ifndef _clog_3_ARGS_TRACE_DatapathOpenUdpv6SocketFailed
+#define _clog_3_ARGS_TRACE_DatapathOpenUdpv6SocketFailed(uniqueId, encoded_arg_string, arg2)\
+tracepoint(CLOG_DATAPATH_WINUSER_C, DatapathOpenUdpv6SocketFailed , arg2);\
+
+#endif
+
+
+
+
+/*----------------------------------------------------------
+// Decoder Ring for DatapathTestSetIpv6TrafficClassFailed
+// [data] Test setting IPV6_TCLASS failed, 0x%x
+// QuicTraceLogWarning(
+ DatapathTestSetIpv6TrafficClassFailed,
+ "[data] Test setting IPV6_TCLASS failed, 0x%x",
+ WsaError);
+// arg2 = arg2 = WsaError = arg2
+----------------------------------------------------------*/
+#ifndef _clog_3_ARGS_TRACE_DatapathTestSetIpv6TrafficClassFailed
+#define _clog_3_ARGS_TRACE_DatapathTestSetIpv6TrafficClassFailed(uniqueId, encoded_arg_string, arg2)\
+tracepoint(CLOG_DATAPATH_WINUSER_C, DatapathTestSetIpv6TrafficClassFailed , arg2);\
+
+#endif
+
+
+
+
/*----------------------------------------------------------
// Decoder Ring for DatapathRecvEmpty
// [data][%p] Dropping datagram with empty payload.
diff --git a/src/generated/linux/datapath_winuser.c.clog.h.lttng.h b/src/generated/linux/datapath_winuser.c.clog.h.lttng.h
index 6af0327b8e..bcd390782c 100644
--- a/src/generated/linux/datapath_winuser.c.clog.h.lttng.h
+++ b/src/generated/linux/datapath_winuser.c.clog.h.lttng.h
@@ -96,6 +96,44 @@ TRACEPOINT_EVENT(CLOG_DATAPATH_WINUSER_C, DatapathQueryRecvMaxCoalescedSizeFaile
+/*----------------------------------------------------------
+// Decoder Ring for DatapathOpenUdpv6SocketFailed
+// [data] UDPv6 helper socket failed to open, 0x%x
+// QuicTraceLogWarning(
+ DatapathOpenUdpv6SocketFailed,
+ "[data] UDPv6 helper socket failed to open, 0x%x",
+ WsaError);
+// arg2 = arg2 = WsaError = arg2
+----------------------------------------------------------*/
+TRACEPOINT_EVENT(CLOG_DATAPATH_WINUSER_C, DatapathOpenUdpv6SocketFailed,
+ TP_ARGS(
+ unsigned int, arg2),
+ TP_FIELDS(
+ ctf_integer(unsigned int, arg2, arg2)
+ )
+)
+
+
+
+/*----------------------------------------------------------
+// Decoder Ring for DatapathTestSetIpv6TrafficClassFailed
+// [data] Test setting IPV6_TCLASS failed, 0x%x
+// QuicTraceLogWarning(
+ DatapathTestSetIpv6TrafficClassFailed,
+ "[data] Test setting IPV6_TCLASS failed, 0x%x",
+ WsaError);
+// arg2 = arg2 = WsaError = arg2
+----------------------------------------------------------*/
+TRACEPOINT_EVENT(CLOG_DATAPATH_WINUSER_C, DatapathTestSetIpv6TrafficClassFailed,
+ TP_ARGS(
+ unsigned int, arg2),
+ TP_FIELDS(
+ ctf_integer(unsigned int, arg2, arg2)
+ )
+)
+
+
+
/*----------------------------------------------------------
// Decoder Ring for DatapathRecvEmpty
// [data][%p] Dropping datagram with empty payload.
diff --git a/src/manifest/clog.sidecar b/src/manifest/clog.sidecar
index 907d055946..be36e869b4 100644
--- a/src/manifest/clog.sidecar
+++ b/src/manifest/clog.sidecar
@@ -2695,6 +2695,18 @@
],
"macroName": "QuicTraceLogWarning"
},
+ "DatapathOpenUdpv6SocketFailed": {
+ "ModuleProperites": {},
+ "TraceString": "[data] UDPv6 helper socket failed to open, 0x%x",
+ "UniqueId": "DatapathOpenUdpv6SocketFailed",
+ "splitArgs": [
+ {
+ "DefinationEncoding": "x",
+ "MacroVariableName": "arg2"
+ }
+ ],
+ "macroName": "QuicTraceLogWarning"
+ },
"DatapathQueryRecvMaxCoalescedSizeFailed": {
"ModuleProperites": {},
"TraceString": "[data] Query for UDP_RECV_MAX_COALESCED_SIZE failed, 0x%x",
@@ -3027,6 +3039,30 @@
],
"macroName": "QuicTraceLogVerbose"
},
+ "DatapathTestSetIpv6TrafficClassFailed": {
+ "ModuleProperites": {},
+ "TraceString": "[data] Test setting IPV6_TCLASS failed, 0x%x",
+ "UniqueId": "DatapathTestSetIpv6TrafficClassFailed",
+ "splitArgs": [
+ {
+ "DefinationEncoding": "x",
+ "MacroVariableName": "arg2"
+ }
+ ],
+ "macroName": "QuicTraceLogWarning"
+ },
+ "DatapathTestSetIpv6TrafficClassFailedAsync": {
+ "ModuleProperites": {},
+ "TraceString": "[data] Test setting IPV6_TCLASS failed (async), 0x%x",
+ "UniqueId": "DatapathTestSetIpv6TrafficClassFailedAsync",
+ "splitArgs": [
+ {
+ "DefinationEncoding": "x",
+ "MacroVariableName": "arg2"
+ }
+ ],
+ "macroName": "QuicTraceLogWarning"
+ },
"DatapathTooLarge": {
"ModuleProperites": {},
"TraceString": "[data][%p] Received larger than expected datagram from %!ADDR!",
@@ -14199,6 +14235,11 @@
"TraceID": "DatapathOpenUdpSocketFailedAsync",
"EncodingString": "[data] UDP send segmentation helper socket failed to open (async), 0x%x"
},
+ {
+ "UniquenessHash": "9af95ba3-6d62-261f-fb94-75465f7084ff",
+ "TraceID": "DatapathOpenUdpv6SocketFailed",
+ "EncodingString": "[data] UDPv6 helper socket failed to open, 0x%x"
+ },
{
"UniquenessHash": "1ba702fe-3407-9bab-a2bf-4f694b478ac0",
"TraceID": "DatapathQueryRecvMaxCoalescedSizeFailed",
@@ -14294,6 +14335,16 @@
"TraceID": "DatapathTcpAuxBinding",
"EncodingString": "[data][%p] Binding TCP socket to %s"
},
+ {
+ "UniquenessHash": "576dad43-cdc4-7cbc-817e-f8831afa4980",
+ "TraceID": "DatapathTestSetIpv6TrafficClassFailed",
+ "EncodingString": "[data] Test setting IPV6_TCLASS failed, 0x%x"
+ },
+ {
+ "UniquenessHash": "bac8baf4-caa7-65ff-f815-8e27065cc9ed",
+ "TraceID": "DatapathTestSetIpv6TrafficClassFailedAsync",
+ "EncodingString": "[data] Test setting IPV6_TCLASS failed (async), 0x%x"
+ },
{
"UniquenessHash": "a07c9538-e6d7-3c41-1367-ce58f2df4d9e",
"TraceID": "DatapathTooLarge",
From 6bc1acc679a539a0a9ee32cf325657282bc3b110 Mon Sep 17 00:00:00 2001
From: Anthony Rossi <41394064+anrossi@users.noreply.github.com>
Date: Fri, 24 Jan 2025 18:55:59 -0800
Subject: [PATCH 03/13] Switch to Ancillary Data
---
docs/Settings.md | 2 +-
src/core/connection.c | 33 +++----
src/core/connection.h | 4 +-
src/core/packet_builder.c | 3 +-
src/cs/lib/msquic_generated.cs | 4 +-
src/inc/msquic.h | 2 +-
src/inc/quic_datapath.h | 22 ++---
src/platform/datapath_epoll.c | 99 +--------------------
src/platform/datapath_kqueue.c | 3 +-
src/platform/datapath_raw.c | 14 +--
src/platform/datapath_raw.h | 3 +-
src/platform/datapath_raw_linux.c | 1 -
src/platform/datapath_raw_socket.c | 20 ++---
src/platform/datapath_raw_win.c | 1 -
src/platform/datapath_raw_xdp_linux.c | 1 +
src/platform/datapath_winkernel.c | 109 ++++-------------------
src/platform/datapath_winuser.c | 121 +++++---------------------
src/platform/datapath_xplat.c | 19 ----
src/platform/platform_internal.h | 19 ++--
19 files changed, 89 insertions(+), 391 deletions(-)
diff --git a/docs/Settings.md b/docs/Settings.md
index 21f94492d8..58bba26008 100644
--- a/docs/Settings.md
+++ b/docs/Settings.md
@@ -177,7 +177,7 @@ These parameters are accessed by calling [GetParam](./api/GetParam.md) or [SetPa
| `QUIC_PARAM_CONN_STATISTICS_V2`
22 | QUIC_STATISTICS_V2 | Get-only | Connection-level statistics, version 2. |
| `QUIC_PARAM_CONN_STATISTICS_V2_PLAT`
23 | QUIC_STATISTICS_V2 | Get-only | Connection-level statistics with platform-specific time format, version 2. |
| `QUIC_PARAM_CONN_ORIG_DEST_CID`
24 | uint8_t[] | Get-only | The original destination connection ID used by the client to connect to the server. |
-| `QUIC_PARAM_CONN_TYPE_OF_SERVICE`
25 | uint8_t | Both | The value put in the Type of Service/Traffic Class field on packets sent from this connection. |
+| `QUIC_PARAM_CONN_DSCP`
25 | uint8_t | Both | The value put in the Type of Service/Traffic Class field on packets sent from this connection. |
### QUIC_PARAM_CONN_STATISTICS_V2
diff --git a/src/core/connection.c b/src/core/connection.c
index 60ee3a95cb..e58ad9974c 100644
--- a/src/core/connection.c
+++ b/src/core/connection.c
@@ -1837,7 +1837,6 @@ QuicConnStart(
UdpConfig.Flags = Connection->State.ShareBinding ? CXPLAT_SOCKET_FLAG_SHARE : 0;
UdpConfig.InterfaceIndex = Connection->State.LocalInterfaceSet ? (uint32_t)Path->Route.LocalAddress.Ipv6.sin6_scope_id : 0, // NOLINT(google-readability-casting)
UdpConfig.PartitionIndex = QuicPartitionIdGetIndex(Connection->PartitionID);
- UdpConfig.TypeOfService = Connection->TypeOfService;
#ifdef QUIC_COMPARTMENT_ID
UdpConfig.CompartmentId = Configuration->CompartmentId;
#endif
@@ -6219,7 +6218,6 @@ QuicConnParamSet(
UdpConfig.RemoteAddress = &Connection->Paths[0].Route.RemoteAddress;
UdpConfig.Flags = Connection->State.ShareBinding ? CXPLAT_SOCKET_FLAG_SHARE : 0;
UdpConfig.InterfaceIndex = 0;
- UdpConfig.TypeOfService = Connection->TypeOfService;
#ifdef QUIC_COMPARTMENT_ID
UdpConfig.CompartmentId = Connection->Configuration->CompartmentId;
#endif
@@ -6625,31 +6623,24 @@ QuicConnParamSet(
return QUIC_STATUS_SUCCESS;
}
- case QUIC_PARAM_CONN_TYPE_OF_SERVICE:
+ case QUIC_PARAM_CONN_DSCP:
{
if (BufferLength != sizeof(uint8_t) || Buffer == NULL) {
Status = QUIC_STATUS_INVALID_PARAMETER;
break;
}
- uint8_t TypeOfService = 0;
- CxPlatCopyMemory(&TypeOfService, Buffer, BufferLength);
+ uint8_t DSCP = 0;
+ CxPlatCopyMemory(&DSCP, Buffer, BufferLength);
- if (TypeOfService > CXPLAT_MAX_TYPE_OF_SERVICE) {
+ if (DSCP > CXPLAT_MAX_DSCP) {
Status = QUIC_STATUS_INVALID_PARAMETER;
break;
}
- Connection->TypeOfService = TypeOfService;
+ Connection->DSCP = DSCP;
- if (Connection->State.Started) {
- Status =
- CxPlatSocketSetTypeOfService(
- Connection->Paths[0].Binding->Socket,
- TypeOfService);
- } else {
- Status = QUIC_STATUS_SUCCESS;
- }
+ Status = QUIC_STATUS_SUCCESS;
break;
}
@@ -7267,11 +7258,11 @@ QuicConnParamGet(
Status = QUIC_STATUS_SUCCESS;
break;
- case QUIC_PARAM_CONN_TYPE_OF_SERVICE:
+ case QUIC_PARAM_CONN_DSCP:
- if (*BufferLength < sizeof(Connection->TypeOfService)) {
+ if (*BufferLength < sizeof(Connection->DSCP)) {
Status = QUIC_STATUS_BUFFER_TOO_SMALL;
- *BufferLength = sizeof(Connection->TypeOfService);
+ *BufferLength = sizeof(Connection->DSCP);
break;
}
@@ -7282,10 +7273,10 @@ QuicConnParamGet(
CxPlatCopyMemory(
Buffer,
- &Connection->TypeOfService,
- sizeof(Connection->TypeOfService));
+ &Connection->DSCP,
+ sizeof(Connection->DSCP));
- *BufferLength = sizeof(Connection->TypeOfService);
+ *BufferLength = sizeof(Connection->DSCP);
Status = QUIC_STATUS_SUCCESS;
break;
diff --git a/src/core/connection.h b/src/core/connection.h
index dd2229a580..0b3dcc5017 100644
--- a/src/core/connection.h
+++ b/src/core/connection.h
@@ -463,10 +463,10 @@ typedef struct QUIC_CONNECTION {
uint8_t PeerReorderingThreshold;
//
- // Type of Service value to set on the socket when the connection is started.
+ // DSCP value to set on all sends from this connection.
// Default value of 0.
//
- uint8_t TypeOfService;
+ uint8_t DSCP;
//
// The ACK frequency sequence number we are currently using to send.
diff --git a/src/core/packet_builder.c b/src/core/packet_builder.c
index 9d380fa09a..05eb49286c 100644
--- a/src/core/packet_builder.c
+++ b/src/core/packet_builder.c
@@ -265,7 +265,8 @@ QuicPacketBuilderPrepare(
DatagramSize),
Builder->EcnEctSet ? CXPLAT_ECN_ECT_0 : CXPLAT_ECN_NON_ECT,
Builder->Connection->Registration->ExecProfile == QUIC_EXECUTION_PROFILE_TYPE_MAX_THROUGHPUT ?
- CXPLAT_SEND_FLAGS_MAX_THROUGHPUT : CXPLAT_SEND_FLAGS_NONE
+ CXPLAT_SEND_FLAGS_MAX_THROUGHPUT : CXPLAT_SEND_FLAGS_NONE,
+ Connection->DSCP
};
Builder->SendData =
CxPlatSendDataAlloc(Builder->Path->Binding->Socket, &SendConfig);
diff --git a/src/cs/lib/msquic_generated.cs b/src/cs/lib/msquic_generated.cs
index 0e567f1aff..e725408c40 100644
--- a/src/cs/lib/msquic_generated.cs
+++ b/src/cs/lib/msquic_generated.cs
@@ -3447,8 +3447,8 @@ internal static unsafe partial class MsQuic
[NativeTypeName("#define QUIC_PARAM_CONN_ORIG_DEST_CID 0x05000018")]
internal const uint QUIC_PARAM_CONN_ORIG_DEST_CID = 0x05000018;
- [NativeTypeName("#define QUIC_PARAM_CONN_TYPE_OF_SERVICE 0x50000019")]
- internal const uint QUIC_PARAM_CONN_TYPE_OF_SERVICE = 0x50000019;
+ [NativeTypeName("#define QUIC_PARAM_CONN_DSCP 0x50000019")]
+ internal const uint QUIC_PARAM_CONN_DSCP = 0x50000019;
[NativeTypeName("#define QUIC_PARAM_TLS_HANDSHAKE_INFO 0x06000000")]
internal const uint QUIC_PARAM_TLS_HANDSHAKE_INFO = 0x06000000;
diff --git a/src/inc/msquic.h b/src/inc/msquic.h
index 4022b5ccab..79e96b5199 100644
--- a/src/inc/msquic.h
+++ b/src/inc/msquic.h
@@ -923,7 +923,7 @@ typedef struct QUIC_SCHANNEL_CREDENTIAL_ATTRIBUTE_W {
#define QUIC_PARAM_CONN_STATISTICS_V2 0x05000016 // QUIC_STATISTICS_V2
#define QUIC_PARAM_CONN_STATISTICS_V2_PLAT 0x05000017 // QUIC_STATISTICS_V2
#define QUIC_PARAM_CONN_ORIG_DEST_CID 0x05000018 // uint8_t[]
-#define QUIC_PARAM_CONN_TYPE_OF_SERVICE 0x50000019 // uint8_t
+#define QUIC_PARAM_CONN_DSCP 0x50000019 // uint8_t
//
// Parameters for TLS.
diff --git a/src/inc/quic_datapath.h b/src/inc/quic_datapath.h
index c5a6df64c6..ec52c85d97 100644
--- a/src/inc/quic_datapath.h
+++ b/src/inc/quic_datapath.h
@@ -58,11 +58,16 @@ typedef enum CXPLAT_ECN_TYPE {
//
#define CXPLAT_ECN_FROM_TOS(ToS) (CXPLAT_ECN_TYPE)((ToS) & 0x3)
+//
+// Helper to get the DSCP value from the Type of Service field of received data.
+//
+#define CXPLAT_DSCP_FROM_TOS(ToS) (uint8_t)((ToS) >> 2)
+
//
// Define the maximum type of service value allowed.
// Note: this is without the ECN bits included
//
-#define CXPLAT_MAX_TYPE_OF_SERVICE 63
+#define CXPLAT_MAX_DSCP 63
//
// The maximum IP MTU this implementation supports for QUIC.
@@ -450,7 +455,7 @@ CxPlatDataPathUpdateConfig(
#define CXPLAT_DATAPATH_FEATURE_TCP 0x0020
#define CXPLAT_DATAPATH_FEATURE_RAW 0x0040
#define CXPLAT_DATAPATH_FEATURE_TTL 0x0080
-#define CXPLAT_DATAPATH_FEATURE_TYPE_OF_SERVICE 0x0100
+#define CXPLAT_DATAPATH_FEATURE_DSCP 0x0100
//
// Queries the currently supported features of the datapath.
@@ -551,7 +556,6 @@ typedef struct CXPLAT_UDP_CONFIG {
#ifdef QUIC_OWNING_PROCESS
QUIC_PROCESS OwningProcess; // Kernel client-only
#endif
- uint8_t TypeOfService; // Default 0. Optional.
// used for RAW datapath
uint8_t CibirIdLength; // CIBIR ID length. Value of 0 indicates CIBIR isn't used
@@ -654,17 +658,6 @@ CxPlatSocketGetRemoteAddress(
_Out_ QUIC_ADDR* Address
);
-//
-// Sets TypeOfService on the socket. May fail if insufficient privileges exist
-// to set the desired value on the socket.
-//
-_IRQL_requires_max_(PASSIVE_LEVEL)
-QUIC_STATUS
-CxPlatSocketSetTypeOfService(
- _In_ CXPLAT_SOCKET* Socket,
- _In_ uint8_t TypeOfService
- );
-
//
// Queries a raw socket availability.
//
@@ -694,6 +687,7 @@ typedef struct CXPLAT_SEND_CONFIG {
uint16_t MaxPacketSize;
uint8_t ECN; // CXPLAT_ECN_TYPE
uint8_t Flags; // CXPLAT_SEND_FLAGS
+ uint8_t DSCP;
} CXPLAT_SEND_CONFIG;
//
diff --git a/src/platform/datapath_epoll.c b/src/platform/datapath_epoll.c
index 226d127624..4601181cf9 100644
--- a/src/platform/datapath_epoll.c
+++ b/src/platform/datapath_epoll.c
@@ -340,7 +340,7 @@ CxPlatDataPathCalculateFeatureSupport(
Datapath->Features |= CXPLAT_DATAPATH_FEATURE_TCP;
Datapath->Features |= CXPLAT_DATAPATH_FEATURE_TTL;
- Datapath->Features |= CXPLAT_DATAPATH_FEATURE_TYPE_OF_SERVICE;
+ Datapath->Features |= CXPLAT_DATAPATH_FEATURE_DSCP;
}
void
@@ -888,46 +888,6 @@ CxPlatSocketContextInitialize(
goto Exit;
}
- if (Config->TypeOfService != 0) {
- Option = Config->TypeOfService;
- Result =
- setsockopt(
- SocketContext->SocketFd,
- IPPROTO_IP,
- IP_TOS,
- (const void*)&Option,
- sizeof(Option));
- if (Result == SOCKET_ERROR) {
- Status = errno;
- QuicTraceEvent(
- DatapathErrorStatus,
- "[data][%p] ERROR, %u, %s.",
- Binding,
- Status,
- "setsockopt(IP_TOS) failed");
- goto Exit;
- }
-
- Option = Config->TypeOfService;
- Result =
- setsockopt(
- SocketContext->SocketFd,
- IPPROTO_IPV6,
- IPV6_TCLASS,
- (const void*)&Option,
- sizeof(Option));
- if (Result == SOCKET_ERROR) {
- Status = errno;
- QuicTraceEvent(
- DatapathErrorStatus,
- "[data][%p] ERROR, %u, %s.",
- Binding,
- Status,
- "setsockopt(IPV6_TCLASS) failed");
- goto Exit;
- }
- }
-
#ifdef UDP_GRO
if (SocketContext->DatapathPartition->Datapath->Features & CXPLAT_DATAPATH_FEATURE_RECV_COALESCING) {
Option = TRUE;
@@ -2304,6 +2264,7 @@ SendDataAlloc(
SendData->AlreadySentCount = 0;
SendData->ControlBufferLength = 0;
SendData->ECN = Config->ECN;
+ SendData->DSCP = Config->DSCP;
SendData->Flags = Config->Flags;
SendData->OnConnectedSocket = Socket->Connected;
SendData->SegmentationSupported =
@@ -2495,60 +2456,6 @@ SocketSend(
}
}
-_IRQL_requires_max_(PASSIVE_LEVEL)
-QUIC_STATUS
-SocketSetTypeOfService(
- _In_ CXPLAT_SOCKET* Socket,
- _In_ uint8_t TypeOfService
- )
-{
- const uint16_t SocketCount = Socket->NumPerProcessorSockets ? (uint16_t)CxPlatProcCount() : 1;
- QUIC_STATUS Status = QUIC_STATUS_SUCCESS;
- for (uint16_t i = 0; i < SocketCount; i++) {
- CXPLAT_SOCKET_CONTEXT* SocketContext = &Socket->SocketContexts[i];
- int Option = TypeOfService;
- int if (Config->TypeOfService != 0) {
- Option = Config->TypeOfService;
- Result =
- setsockopt(
- SocketContext->SocketFd,
- IPPROTO_IP,
- IP_TOS,
- (const void*)&Option,
- sizeof(Option));
- if (Result == SOCKET_ERROR) {
- Status = errno;
- QuicTraceEvent(
- DatapathErrorStatus,
- "[data][%p] ERROR, %u, %s.",
- Binding,
- Status,
- "setsockopt(IP_TOS) failed");
- break;
- }
-
- Option = TypeOfService;
- Result =
- setsockopt(
- SocketContext->SocketFd,
- IPPROTO_IPV6,
- IPV6_TCLASS,
- (const void*)&Option,
- sizeof(Option));
- if (Result == SOCKET_ERROR) {
- Status = errno;
- QuicTraceEvent(
- DatapathErrorStatus,
- "[data][%p] ERROR, %u, %s.",
- Binding,
- Status,
- "setsockopt(IPV6_TCLASS) failed");
- break;
- }
- }
- }
- return Status;
-}
//
// This is defined and used instead of CMSG_NXTHDR because (1) we've already
// done the work to ensure the necessary space is available and (2) CMSG_NXTHDR
@@ -2572,7 +2479,7 @@ CxPlatSendDataPopulateAncillaryData(
CMsg->cmsg_level = SendData->LocalAddress.Ip.sa_family == AF_INET ? IPPROTO_IP : IPPROTO_IPV6;
CMsg->cmsg_type = SendData->LocalAddress.Ip.sa_family == AF_INET ? IP_TOS : IPV6_TCLASS;
CMsg->cmsg_len = CMSG_LEN(sizeof(int));
- *(int*)CMSG_DATA(CMsg) = SendData->ECN;
+ *(int*)CMSG_DATA(CMsg) = SendData->ECN | (SendData->DSCP << 2);
if (!SendData->OnConnectedSocket) {
if (SendData->LocalAddress.Ip.sa_family == AF_INET) {
diff --git a/src/platform/datapath_kqueue.c b/src/platform/datapath_kqueue.c
index 0bb64fa330..cd4e4554ca 100644
--- a/src/platform/datapath_kqueue.c
+++ b/src/platform/datapath_kqueue.c
@@ -1626,6 +1626,7 @@ CxPlatSendDataAlloc(
CxPlatZeroMemory(SendData, sizeof(*SendData));
SendData->Owner = SocketContext->DatapathPartition;
SendData->ECN = Config->ECN;
+ SendData->DSCP = Config->DSCP;
SendData->SegmentSize =
(Socket->Datapath->Features & CXPLAT_DATAPATH_FEATURE_SEND_SEGMENTATION)
? Config->MaxPacketSize : 0;
@@ -1981,7 +1982,7 @@ CxPlatSocketSendInternal(
CMsg->cmsg_level = RemoteAddress->Ip.sa_family == QUIC_ADDRESS_FAMILY_INET ? IPPROTO_IP : IPPROTO_IPV6;
CMsg->cmsg_type = RemoteAddress->Ip.sa_family == QUIC_ADDRESS_FAMILY_INET ? IP_TOS : IPV6_TCLASS;
CMsg->cmsg_len = CMSG_LEN(sizeof(int));
- *(int *)CMSG_DATA(CMsg) = SendData->ECN;
+ *(int *)CMSG_DATA(CMsg) = SendData->ECN | (SendData->DSCP << 2);
if (!SocketContext->Binding->Connected) {
Mhdr.msg_name = &MappedRemoteAddress;
diff --git a/src/platform/datapath_raw.c b/src/platform/datapath_raw.c
index f594a3042f..e860e40c1d 100644
--- a/src/platform/datapath_raw.c
+++ b/src/platform/datapath_raw.c
@@ -371,7 +371,7 @@ RawSocketSend(
const CXPLAT_INTERFACE* Interface = CxPlatDpRawGetInterfaceFromQueue(Route->Queue);
CxPlatFramingWriteHeaders(
- Socket, Route, &SendData->Buffer, SendData->ECN, Socket->TypeOfService,
+ Socket, Route, &SendData->Buffer, SendData->ECN, SendData->DSCP,
Interface->OffloadStatus.Transmit.NetworkLayerXsum,
Interface->OffloadStatus.Transmit.TransportLayerXsum,
Route->TcpState.SequenceNumber,
@@ -380,15 +380,3 @@ RawSocketSend(
CxPlatDpRawTxEnqueue(SendData);
return QUIC_STATUS_SUCCESS;
}
-
-
-_IRQL_requires_max_(DISPATCH_LEVEL)
-QUIC_STATUS
-RawSocketSetTypeOfService(
- _In_ CXPLAT_SOCKET_RAW* Socket,
- _In_ uint8_t TypeOfService
- )
-{
- Socket->TypeOfService = TypeOfService;
- return QUIC_STATUS_SUCCESS;
-}
diff --git a/src/platform/datapath_raw.h b/src/platform/datapath_raw.h
index 57a2a274b6..c980eee3e9 100644
--- a/src/platform/datapath_raw.h
+++ b/src/platform/datapath_raw.h
@@ -265,7 +265,6 @@ typedef struct CXPLAT_SOCKET_RAW {
SOCKET AuxSocket;
BOOLEAN Wildcard; // Using a wildcard local address. Optimization
// to avoid always reading LocalAddress.
- uint8_t TypeOfService; // IP TypeOfService/IPv6 Traffic Class value. Default 0.
uint8_t CibirIdLength; // CIBIR ID length. Value of 0 indicates CIBIR isn't used
uint8_t CibirIdOffsetSrc; // CIBIR ID offset in source CID
uint8_t CibirIdOffsetDst; // CIBIR ID offset in destination CID
@@ -378,7 +377,7 @@ CxPlatFramingWriteHeaders(
_In_ const CXPLAT_ROUTE* Route,
_Inout_ QUIC_BUFFER* Buffer,
_In_ CXPLAT_ECN_TYPE ECN,
- _In_ uint8_t TypeOfService,
+ _In_ uint8_t DSCP,
_In_ BOOLEAN SkipNetworkLayerXsum,
_In_ BOOLEAN SkipTransportLayerXsum,
_In_ uint32_t TcpSeqNum,
diff --git a/src/platform/datapath_raw_linux.c b/src/platform/datapath_raw_linux.c
index 139f202929..02fbf05dd4 100644
--- a/src/platform/datapath_raw_linux.c
+++ b/src/platform/datapath_raw_linux.c
@@ -117,7 +117,6 @@ RawSocketCreateUdp(
NewSocket->CibirIdLength = Config->CibirIdLength;
NewSocket->CibirIdOffsetSrc = Config->CibirIdOffsetSrc;
NewSocket->CibirIdOffsetDst = Config->CibirIdOffsetDst;
- NewSocket->TypeOfService = Config->TypeOfService;
NewSocket->AuxSocket = INVALID_SOCKET;
NewSocket->UseTcp = Raw->UseTcp;
if (Config->CibirIdLength) {
diff --git a/src/platform/datapath_raw_socket.c b/src/platform/datapath_raw_socket.c
index da9d26aadb..3dda7a7f18 100644
--- a/src/platform/datapath_raw_socket.c
+++ b/src/platform/datapath_raw_socket.c
@@ -297,7 +297,7 @@ CxPlatDpRawParseIPv4(
return;
}
- Packet->TypeOfService = IP->EcnField;
+ Packet->TypeOfService = IP->TypeOfServiceAndEcnField;
Packet->HopLimitTTL = IP->TimeToLive;
Packet->Route->RemoteAddress.Ipv4.sin_family = AF_INET;
CxPlatCopyMemory(&Packet->Route->RemoteAddress.Ipv4.sin_addr, IP->Source, sizeof(IP->Source));
@@ -366,7 +366,7 @@ CxPlatDpRawParseIPv6(
} VersionClassEcnFlow;
VersionClassEcnFlow.Value = CxPlatByteSwapUint32(IP->VersionClassEcnFlow);
- Packet->TypeOfService = (uint8_t)VersionClassEcnFlow.EcnField;
+ Packet->TypeOfService = ((uint8_t)VersionClassEcnFlow.EcnField) | (((uint8_t)VersionClassEcnFlow.Class) << 2);
Packet->HopLimitTTL = IP->HopLimit;
Packet->Route->RemoteAddress.Ipv6.sin6_family = AF_INET6;
CxPlatCopyMemory(&Packet->Route->RemoteAddress.Ipv6.sin6_addr, IP->Source, sizeof(IP->Source));
@@ -558,7 +558,7 @@ CxPlatDpRawSocketAckFin(
TCP_HEADER* ReceivedTcpHeader = (TCP_HEADER*)(Packet->Buffer - Packet->ReservedEx);
CxPlatFramingWriteHeaders(
- Socket, Route, &SendData->Buffer, SendData->ECN, Socket->TypeOfService,
+ Socket, Route, &SendData->Buffer, SendData->ECN, SendData->DSCP,
Interface->OffloadStatus.Transmit.NetworkLayerXsum,
Interface->OffloadStatus.Transmit.TransportLayerXsum,
ReceivedTcpHeader->AckNumber,
@@ -599,7 +599,7 @@ CxPlatDpRawSocketAckSyn(
CASTED_CLOG_BYTEARRAY(sizeof(Route->LocalAddress), &Route->LocalAddress));
CxPlatFramingWriteHeaders(
- Socket, Route, &SendData->Buffer, SendData->ECN, Socket->TypeOfService,
+ Socket, Route, &SendData->Buffer, SendData->ECN, SendData->DSCP,
Interface->OffloadStatus.Transmit.NetworkLayerXsum,
Interface->OffloadStatus.Transmit.TransportLayerXsum,
ReceivedTcpHeader->AckNumber,
@@ -619,7 +619,7 @@ CxPlatDpRawSocketAckSyn(
CASTED_CLOG_BYTEARRAY(sizeof(Route->RemoteAddress), &Route->RemoteAddress),
CASTED_CLOG_BYTEARRAY(sizeof(Route->LocalAddress), &Route->LocalAddress));
CxPlatFramingWriteHeaders(
- Socket, Route, &SendData->Buffer, SendData->ECN, Socket->TypeOfService,
+ Socket, Route, &SendData->Buffer, SendData->ECN, SendData->DSCP,
Interface->OffloadStatus.Transmit.NetworkLayerXsum,
Interface->OffloadStatus.Transmit.TransportLayerXsum,
CxPlatByteSwapUint32(CxPlatByteSwapUint32(ReceivedTcpHeader->AckNumber) + 1),
@@ -642,7 +642,7 @@ CxPlatDpRawSocketAckSyn(
CASTED_CLOG_BYTEARRAY(sizeof(Route->RemoteAddress), &Route->RemoteAddress),
CASTED_CLOG_BYTEARRAY(sizeof(Route->LocalAddress), &Route->LocalAddress));
CxPlatFramingWriteHeaders(
- Socket, Route, &SendData->Buffer, SendData->ECN, Socket->TypeOfService,
+ Socket, Route, &SendData->Buffer, SendData->ECN, SendData->DSCP,
Interface->OffloadStatus.Transmit.NetworkLayerXsum,
Interface->OffloadStatus.Transmit.TransportLayerXsum,
ReceivedTcpHeader->AckNumber,
@@ -678,7 +678,7 @@ CxPlatDpRawSocketSyn(
CXPLAT_DBG_ASSERT(Route->Queue != NULL);
const CXPLAT_INTERFACE* Interface = CxPlatDpRawGetInterfaceFromQueue(Route->Queue);
CxPlatFramingWriteHeaders(
- Socket, Route, &SendData->Buffer, SendData->ECN, Socket->TypeOfService,
+ Socket, Route, &SendData->Buffer, SendData->ECN, SendData->DSCP,
Interface->OffloadStatus.Transmit.NetworkLayerXsum,
Interface->OffloadStatus.Transmit.TransportLayerXsum,
Route->TcpState.SequenceNumber, 0, TH_SYN);
@@ -692,7 +692,7 @@ CxPlatFramingWriteHeaders(
_In_ const CXPLAT_ROUTE* Route,
_Inout_ QUIC_BUFFER* Buffer,
_In_ CXPLAT_ECN_TYPE ECN,
- _In_ uint8_t TypeOfService,
+ _In_ uint8_t DSCP,
_In_ BOOLEAN SkipNetworkLayerXsum,
_In_ BOOLEAN SkipTransportLayerXsum,
_In_ uint32_t TcpSeqNum,
@@ -752,7 +752,7 @@ CxPlatFramingWriteHeaders(
if (Family == QUIC_ADDRESS_FAMILY_INET) {
IPV4_HEADER* IPv4 = (IPV4_HEADER*)(Transport - sizeof(IPV4_HEADER));
IPv4->VersionAndHeaderLength = IPV4_DEFAULT_VERHLEN;
- IPv4->TypeOfService = TypeOfService;
+ IPv4->TypeOfService = DSCP;
IPv4->EcnField = ECN;
IPv4->TotalLength = htons(sizeof(IPV4_HEADER) + TransportLength + (uint16_t)Buffer->Length);
IPv4->Identification = 0;
@@ -800,7 +800,7 @@ CxPlatFramingWriteHeaders(
} VersionClassEcnFlow = {0};
VersionClassEcnFlow.Version = IPV6_VERSION;
- VersionClassEcnFlow.Class = TypeOfService;
+ VersionClassEcnFlow.Class = DSCP;
VersionClassEcnFlow.EcnField = ECN;
VersionClassEcnFlow.Flow = (uint32_t)(uintptr_t)Socket;
diff --git a/src/platform/datapath_raw_win.c b/src/platform/datapath_raw_win.c
index fc4dba366d..d3f01926cd 100644
--- a/src/platform/datapath_raw_win.c
+++ b/src/platform/datapath_raw_win.c
@@ -118,7 +118,6 @@ RawSocketCreateUdp(
Socket->CibirIdLength = Config->CibirIdLength;
Socket->CibirIdOffsetSrc = Config->CibirIdOffsetSrc;
Socket->CibirIdOffsetDst = Config->CibirIdOffsetDst;
- Socket->TypeOfService = Config->TypeOfService;
Socket->AuxSocket = INVALID_SOCKET;
if (Config->CibirIdLength) {
memcpy(Socket->CibirId, Config->CibirId, Config->CibirIdLength);
diff --git a/src/platform/datapath_raw_xdp_linux.c b/src/platform/datapath_raw_xdp_linux.c
index 14471f91eb..0b45c993fe 100644
--- a/src/platform/datapath_raw_xdp_linux.c
+++ b/src/platform/datapath_raw_xdp_linux.c
@@ -1070,6 +1070,7 @@ CxPlatDpRawTxAlloc(
Packet->Buffer.Length = Config->MaxPacketSize;
Packet->Buffer.Buffer = &Packet->FrameBuffer[HeaderBackfill.AllLayer];
Packet->ECN = Config->ECN;
+ Packet->DSCP = Config->DSCP;
Packet->UmemRelativeAddr = BaseAddr;
Packet->DatapathType = Config->Route->DatapathType = CXPLAT_DATAPATH_TYPE_RAW;
}
diff --git a/src/platform/datapath_winkernel.c b/src/platform/datapath_winkernel.c
index cf2326732d..50813b20f6 100644
--- a/src/platform/datapath_winkernel.c
+++ b/src/platform/datapath_winkernel.c
@@ -644,7 +644,7 @@ CxPlatDataPathQuerySockoptSupport(
break;
}
- Datapath->Features |= CXPLAT_DATAPATH_FEATURE_TYPE_OF_SERVICE;
+ Datapath->Features |= CXPLAT_DATAPATH_FEATURE_DSCP;
} while (FALSE);
@@ -1600,47 +1600,6 @@ SocketCreateUdp(
}
}
- if ((Datapath->Features & CXPLAT_DATAPATH_FEATURE_TYPE_OF_SERVICE) &&
- Config->TypeOfService != 0) {
- Option = Config->TypeOfService;
- Status =
- CxPlatDataPathSetControlSocket(
- Binding,
- WskSetOption,
- IP_TOS,
- IPPROTO_IP,
- sizeof(Option),
- &Option);
- if (QUIC_FAILED(Status)) {
- QuicTraceEvent(
- DatapathErrorStatus,
- "[data][%p] ERROR, %u, %s.",
- Binding,
- Status,
- "Set IP_TOS");
- goto Error;
- }
-
- Option = Config->TypeOfService;
- Status =
- CxPlatDataPathSetControlSocket(
- Binding,
- WskSetOption,
- IPV6_TCLASS,
- IPPROTO_IPV6,
- sizeof(Option),
- &Option);
- if (QUIC_FAILED(Status)) {
- QuicTraceEvent(
- DatapathErrorStatus,
- "[data][%p] ERROR, %u, %s.",
- Binding,
- Status,
- "Set IPV6_TCLASS");
- goto Error;
- }
- }
-
if (Datapath->Features & CXPLAT_DATAPATH_FEATURE_RECV_COALESCING) {
Option = MAX_URO_PAYLOAD_LENGTH;
Status =
@@ -2528,6 +2487,7 @@ SendDataAlloc(
if (SendData != NULL) {
SendData->Owner = ProcContext;
SendData->ECN = Config->ECN;
+ SendData->DSCP = Config->DSCP;
SendData->WskBufs = NULL;
SendData->TailBuf = NULL;
SendData->TotalSize = 0;
@@ -2970,6 +2930,7 @@ SocketSend(
BYTE CMsgBuffer[
WSA_CMSG_SPACE(sizeof(IN6_PKTINFO)) + // IP_PKTINFO
WSA_CMSG_SPACE(sizeof(INT)) + // IP_ECN
+ WSA_CMSG_SPACE(sizeof(INT)) + // IP_TOS/IPV6_TCLASS
WSA_CMSG_SPACE(sizeof(*SegmentSize)) // UDP_SEND_MSG_SIZE
];
PWSACMSGHDR CMsg = (PWSACMSGHDR)CMsgBuffer;
@@ -3012,6 +2973,18 @@ SocketSend(
*(PINT)WSA_CMSG_DATA(CMsg) = SendData->ECN;
}
+ if (Binding->Datapath->Features & CXPLAT_DATAPATH_FEATURE_DSCP) {
+ CMsg = (PWSACMSGHDR)&CMsgBuffer[CMsgLen];
+ CMsgLen += WSA_CMSG_SPACE(sizeof(INT));
+ CMsg->cmsg_level =
+ Route->LocalAddress.si_family == QUIC_ADDRESS_FAMILY_INET ?
+ IPPROTO_IP : IPPROTO_IPV6;
+ CMsg->cmsg_type =
+ Route->LocalAddress.si_family == QUIC_ADDRESS_FAMILY_INET ?
+ IP_TOS : IPV6_TCLASS;
+ CMsg->cmsg_len = WSA_CMSG_LEN(sizeof(INT));
+ }
+
if (SendData->SegmentSize > 0) {
CMsg = (PWSACMSGHDR)&CMsgBuffer[CMsgLen];
CMsgLen += WSA_CMSG_SPACE(sizeof(*SegmentSize));
@@ -3048,58 +3021,6 @@ SocketSend(
}
}
-_IRQL_requires_max_(PASSIVE_LEVEL)
-QUIC_STATUS
-SocketSetTypeOfService(
- _In_ CXPLAT_SOCKET* Socket,
- _In_ uint8_t TypeOfService
- )
-{
- QUIC_STATUS Status = QUIC_STATUS_SUCCESS;
-
- uint32_t Option = TypeOfService;
- Status =
- CxPlatDataPathSetControlSocket(
- Socket,
- WskSetOption,
- IP_TOS,
- IPPROTO_IP,
- sizeof(Option),
- &Option);
- if (QUIC_FAILED(Status)) {
- QuicTraceEvent(
- DatapathErrorStatus,
- "[data][%p] ERROR, %u, %s.",
- Binding,
- Status,
- "Set IP_TOS");
- goto Error;
- }
-
- Option = Config->TypeOfService;
- Status =
- CxPlatDataPathSetControlSocket(
- Socket,
- WskSetOption,
- IPV6_TCLASS,
- IPPROTO_IPV6,
- sizeof(Option),
- &Option);
- if (QUIC_FAILED(Status)) {
- QuicTraceEvent(
- DatapathErrorStatus,
- "[data][%p] ERROR, %u, %s.",
- Binding,
- Status,
- "Set IPV6_TCLASS");
- goto Error;
- }
-
-Error:
-
- return Status;
-}
-
_IRQL_requires_max_(DISPATCH_LEVEL)
QUIC_STATUS
CxPlatSocketGetTcpStatistics(
diff --git a/src/platform/datapath_winuser.c b/src/platform/datapath_winuser.c
index c02745064d..7c67b768f3 100644
--- a/src/platform/datapath_winuser.c
+++ b/src/platform/datapath_winuser.c
@@ -274,6 +274,7 @@ typedef struct CXPLAT_SEND_DATA {
RIO_CMSG_BASE_SIZE +
WSA_CMSG_SPACE(sizeof(IN6_PKTINFO)) + // IP_PKTINFO
WSA_CMSG_SPACE(sizeof(INT)) + // IP_ECN
+ WSA_CMSG_SPACE(sizeof(INT)) + // IP_TOS/IPV6_TCLASS
WSA_CMSG_SPACE(sizeof(DWORD)) // UDP_SEND_MSG_SIZE
];
@@ -731,7 +732,7 @@ CxPlatDataPathQuerySockoptSupport(
"[data] Test setting IPV6_TCLASS failed, 0x%x",
WsaError);
} else {
- Datapath->Features |= CXPLAT_DATAPATH_FEATURE_TYPE_OF_SERVICE;
+ Datapath->Features |= CXPLAT_DATAPATH_FEATURE_DSCP;
}
closesocket(Udpv6Socket);
}
@@ -1764,49 +1765,6 @@ SocketCreateUdp(
}
}
- if ((Datapath->Features & CXPLAT_DATAPATH_FEATURE_TYPE_OF_SERVICE) &&
- Config->TypeOfService != 0) {
- Option = Config->TypeOfService;
- Result =
- setsockopt(
- SocketProc->Socket,
- IPPROTO_IP,
- IP_TOS,
- (char*)&Option,
- sizeof(Option));
- if (Result == SOCKET_ERROR) {
- int WsaError = WSAGetLastError();
- QuicTraceEvent(
- DatapathErrorStatus,
- "[data][%p] ERROR, %u, %s.",
- Socket,
- WsaError,
- "Set IP_TOS");
- Status = HRESULT_FROM_WIN32(WsaError);
- goto Error;
- }
-
- Option = Config->TypeOfService;
- Result =
- setsockopt(
- SocketProc->Socket,
- IPPROTO_IPV6,
- IPV6_TCLASS,
- (char*)&Option,
- sizeof(Option));
- if (Result == SOCKET_ERROR) {
- int WsaError = WSAGetLastError();
- QuicTraceEvent(
- DatapathErrorStatus,
- "[data][%p] ERROR, %u, %s.",
- Socket,
- WsaError,
- "Set IPV6_TCLASS");
- Status = HRESULT_FROM_WIN32(WsaError);
- goto Error;
- }
- }
-
//
// The socket is shared by multiple endpoints, so increase the receive
// buffer size.
@@ -4082,6 +4040,7 @@ SendDataAlloc(
SendData->Owner = DatapathProc;
SendData->SendDataPool = SendDataPool;
SendData->ECN = Config->ECN;
+ SendData->DSCP = Config->DSCP;
SendData->SendFlags = Config->Flags;
SendData->SegmentSize =
(Socket->Type != CXPLAT_SOCKET_UDP ||
@@ -4569,6 +4528,16 @@ CxPlatSocketSendInline(
CMsg->cmsg_len = WSA_CMSG_LEN(sizeof(INT));
*(PINT)WSA_CMSG_DATA(CMsg) = SendData->ECN;
+ if (Socket->Datapath->Features & CXPLAT_DATAPATH_FEATURE_DSCP) {
+ WSAMhdr.Control.len += WSA_CMSG_SPACE(sizeof(INT));
+ CMsg = WSA_CMSG_NXTHDR(&WSAMhdr, CMsg);
+ CXPLAT_DBG_ASSERT(CMsg != NULL);
+ CMsg->cmsg_level = IPPROTO_IP;
+ CMsg->cmsg_type = IP_TOS;
+ CMsg->cmsg_len = WSA_CMSG_LEN(sizeof(INT));
+ *(PINT)WSA_CMSG_DATA(CMsg) = SendData->DSCP;
+ }
+
} else {
if (!Socket->HasFixedRemoteAddress) {
@@ -4589,6 +4558,16 @@ CxPlatSocketSendInline(
CMsg->cmsg_type = IPV6_ECN;
CMsg->cmsg_len = WSA_CMSG_LEN(sizeof(INT));
*(PINT)WSA_CMSG_DATA(CMsg) = SendData->ECN;
+
+ if (Socket->Datapath->Features & CXPLAT_DATAPATH_FEATURE_DSCP) {
+ WSAMhdr.Control.len += WSA_CMSG_SPACE(sizeof(INT));
+ CMsg = WSA_CMSG_NXTHDR(&WSAMhdr, CMsg);
+ CXPLAT_DBG_ASSERT(CMsg != NULL);
+ CMsg->cmsg_level = IPPROTO_IPV6;
+ CMsg->cmsg_type = IPV6_TCLASS;
+ CMsg->cmsg_len = WSA_CMSG_LEN(sizeof(INT));
+ *(PINT)WSA_CMSG_DATA(CMsg) = SendData->DSCP;
+ }
}
if (SendData->SegmentSize > 0) {
@@ -4710,60 +4689,6 @@ SocketSend(
}
}
-_IRQL_requires_max_(PASSIVE_LEVEL)
-QUIC_STATUS
-SocketSetTypeOfService(
- _In_ CXPLAT_SOCKET* Socket,
- _In_ uint8_t TypeOfService
- )
-{
- const uint16_t SocketCount = Socket->NumPerProcessorSockets ? (uint16_t)CxPlatProcCount() : 1;
- QUIC_STATUS Status = QUIC_STATUS_SUCCESS;
- for (uint16_t i = 0; i < SocketCount; i++) {
- CXPLAT_SOCKET_PROC* SocketProc = &Socket->PerProcSockets[i];
- int Option = TypeOfService;
- int Result =
- setsockopt(
- SocketProc->Socket,
- IPPROTO_IP,
- IP_TOS,
- (char*)&Option,
- sizeof(Option));
- if (Result == SOCKET_ERROR) {
- int WsaError = WSAGetLastError();
- QuicTraceEvent(
- DatapathErrorStatus,
- "[data][%p] ERROR, %u, %s.",
- Socket,
- WsaError,
- "Set IP_TOS");
- Status = HRESULT_FROM_WIN32(WsaError);
- break;
- }
-
- Option = TypeOfService;
- Result =
- setsockopt(
- SocketProc->Socket,
- IPPROTO_IPV6,
- IPV6_TCLASS,
- (char*)&Option,
- sizeof(Option));
- if (Result == SOCKET_ERROR) {
- int WsaError = WSAGetLastError();
- QuicTraceEvent(
- DatapathErrorStatus,
- "[data][%p] ERROR, %u, %s.",
- Socket,
- WsaError,
- "Set IPV6_TCLASS");
- Status = HRESULT_FROM_WIN32(WsaError);
- break;
- }
- }
- return Status;
-}
-
void
CxPlatDataPathSocketProcessQueuedSend(
_In_ CXPLAT_SEND_DATA* SendData
diff --git a/src/platform/datapath_xplat.c b/src/platform/datapath_xplat.c
index 1014a1b640..c68ccb4047 100644
--- a/src/platform/datapath_xplat.c
+++ b/src/platform/datapath_xplat.c
@@ -251,25 +251,6 @@ CxPlatSocketGetRemoteAddress(
*Address = Socket->RemoteAddress;
}
-_IRQL_requires_max_(PASSIVE_LEVEL)
-QUIC_STATUS
-CxPlatSocketSetTypeOfService(
- _In_ CXPLAT_SOCKET* Socket,
- _In_ uint8_t TypeOfService
- )
-{
- QUIC_STATUS Status;
- if (Socket->RawSocketAvailable) {
- Status = RawSocketSetTypeOfService(CxPlatSocketToRaw(Socket), TypeOfService);
- if (QUIC_FAILED(Status)) {
- return Status;
- }
- }
- Status = SocketSetTypeOfService(Socket, TypeOfService);
-
- return Status;
-}
-
_IRQL_requires_max_(DISPATCH_LEVEL)
BOOLEAN
CxPlatSocketRawSocketAvailable(
diff --git a/src/platform/platform_internal.h b/src/platform/platform_internal.h
index 803fb381f6..78e2350c04 100644
--- a/src/platform/platform_internal.h
+++ b/src/platform/platform_internal.h
@@ -98,6 +98,11 @@ typedef struct CXPLAT_SEND_DATA_COMMON {
//
uint8_t ECN; // CXPLAT_ECN_TYPE
+ //
+ // The DSCP value to use for this send.
+ //
+ uint8_t DSCP;
+
//
// The total buffer size for WsaBuffers.
//
@@ -1152,13 +1157,6 @@ SocketSend(
_In_ CXPLAT_SEND_DATA* SendData
);
-_IRQL_requires_max_(PASSIVE_LEVEL)
-QUIC_STATUS
-SocketSetTypeOfService(
- _In_ CXPLAT_SOCKET* Socket,
- _In_ uint8_t TypeOfService
- );
-
CXPLAT_SOCKET*
CxPlatRawToSocket(
_In_ CXPLAT_SOCKET_RAW* Socket
@@ -1285,13 +1283,6 @@ RawSocketSend(
_In_ CXPLAT_SEND_DATA* SendData
);
-_IRQL_requires_max_(DISPATCH_LEVEL)
-QUIC_STATUS
-RawSocketSetTypeOfService(
- _In_ CXPLAT_SOCKET_RAW* Socket,
- _In_ uint8_t TypeOfService
- );
-
void
RawResolveRouteComplete(
_In_ void* Context,
From de34f350182b819ccb59df36ac16f00481231a09 Mon Sep 17 00:00:00 2001
From: Anthony Rossi <41394064+anrossi@users.noreply.github.com>
Date: Sat, 25 Jan 2025 17:39:00 -0800
Subject: [PATCH 04/13] Zero out new DSCP struct member and see if tests pass
---
src/core/binding.c | 2 +-
src/perf/lib/Tcp.cpp | 2 +-
src/platform/datapath_raw_socket.c | 6 +++---
src/platform/pcp.c | 4 ++--
src/platform/unittest/DataPathTest.cpp | 20 ++++++++++----------
src/test/lib/QuicDrill.cpp | 2 +-
src/tools/attack/attack.cpp | 4 ++--
src/tools/lb/loadbalancer.cpp | 2 +-
src/tools/recvfuzz/recvfuzz.cpp | 2 +-
9 files changed, 22 insertions(+), 22 deletions(-)
diff --git a/src/core/binding.c b/src/core/binding.c
index 348e1228d0..22f03f5f62 100644
--- a/src/core/binding.c
+++ b/src/core/binding.c
@@ -803,7 +803,7 @@ QuicBindingProcessStatelessOperation(
Binding,
OperationType);
- CXPLAT_SEND_CONFIG SendConfig = { RecvPacket->Route, 0, CXPLAT_ECN_NON_ECT, 0 };
+ CXPLAT_SEND_CONFIG SendConfig = { RecvPacket->Route, 0, CXPLAT_ECN_NON_ECT, 0, 0 };
CXPLAT_SEND_DATA* SendData = CxPlatSendDataAlloc(Binding->Socket, &SendConfig);
if (SendData == NULL) {
QuicTraceEvent(
diff --git a/src/perf/lib/Tcp.cpp b/src/perf/lib/Tcp.cpp
index 9d71308c5c..fd328b1651 100644
--- a/src/perf/lib/Tcp.cpp
+++ b/src/perf/lib/Tcp.cpp
@@ -1088,7 +1088,7 @@ QUIC_BUFFER* TcpConnection::NewSendBuffer()
return nullptr;
}
if (!BatchedSendData) {
- CXPLAT_SEND_CONFIG SendConfig = { &Route, TLS_BLOCK_SIZE, CXPLAT_ECN_NON_ECT, 0 };
+ CXPLAT_SEND_CONFIG SendConfig = { &Route, TLS_BLOCK_SIZE, CXPLAT_ECN_NON_ECT, 0, 0 };
BatchedSendData = CxPlatSendDataAlloc(Socket, &SendConfig);
if (!BatchedSendData) { return nullptr; }
}
diff --git a/src/platform/datapath_raw_socket.c b/src/platform/datapath_raw_socket.c
index 3dda7a7f18..fddf2e733a 100644
--- a/src/platform/datapath_raw_socket.c
+++ b/src/platform/datapath_raw_socket.c
@@ -538,7 +538,7 @@ CxPlatDpRawSocketAckFin(
CXPLAT_DBG_ASSERT(Socket->UseTcp);
CXPLAT_ROUTE* Route = Packet->Route;
- CXPLAT_SEND_CONFIG SendConfig = { Route, 0, CXPLAT_ECN_NON_ECT, 0 };
+ CXPLAT_SEND_CONFIG SendConfig = { Route, 0, CXPLAT_ECN_NON_ECT, 0, 0 };
CXPLAT_SEND_DATA *SendData = CxPlatSendDataAlloc(CxPlatRawToSocket(Socket), &SendConfig);
if (SendData == NULL) {
return;
@@ -577,7 +577,7 @@ CxPlatDpRawSocketAckSyn(
CXPLAT_DBG_ASSERT(Socket->UseTcp);
CXPLAT_ROUTE* Route = Packet->Route;
- CXPLAT_SEND_CONFIG SendConfig = { Route, 0, CXPLAT_ECN_NON_ECT, 0 };
+ CXPLAT_SEND_CONFIG SendConfig = { Route, 0, CXPLAT_ECN_NON_ECT, 0, 0 };
CXPLAT_SEND_DATA *SendData = CxPlatSendDataAlloc(CxPlatRawToSocket(Socket), &SendConfig);
if (SendData == NULL) {
return;
@@ -660,7 +660,7 @@ CxPlatDpRawSocketSyn(
)
{
CXPLAT_DBG_ASSERT(Socket->UseTcp);
- CXPLAT_SEND_CONFIG SendConfig = { (CXPLAT_ROUTE*)Route, 0, CXPLAT_ECN_NON_ECT, 0 };
+ CXPLAT_SEND_CONFIG SendConfig = { (CXPLAT_ROUTE*)Route, 0, CXPLAT_ECN_NON_ECT, 0, 0 };
CXPLAT_SEND_DATA *SendData = CxPlatSendDataAlloc(CxPlatRawToSocket(Socket), &SendConfig);
if (SendData == NULL) {
return;
diff --git a/src/platform/pcp.c b/src/platform/pcp.c
index b91e6a54f6..e090b0bb17 100644
--- a/src/platform/pcp.c
+++ b/src/platform/pcp.c
@@ -391,7 +391,7 @@ CxPlatPcpSendMapRequestInternal(
QUIC_ADDR LocalMappedAddress;
CxPlatConvertToMappedV6(&Route.LocalAddress, &LocalMappedAddress);
- CXPLAT_SEND_CONFIG SendConfig = { &Route, PCP_MAP_REQUEST_SIZE, CXPLAT_ECN_NON_ECT, 0 };
+ CXPLAT_SEND_CONFIG SendConfig = { &Route, PCP_MAP_REQUEST_SIZE, CXPLAT_ECN_NON_ECT, 0, 0 };
CXPLAT_SEND_DATA* SendData = CxPlatSendDataAlloc(Socket, &SendConfig);
if (SendData == NULL) {
return QUIC_STATUS_OUT_OF_MEMORY;
@@ -483,7 +483,7 @@ CxPlatPcpSendPeerRequestInternal(
QUIC_ADDR RemotePeerMappedAddress;
CxPlatConvertToMappedV6(RemotePeerAddress, &RemotePeerMappedAddress);
- CXPLAT_SEND_CONFIG SendConfig = { &Route, PCP_MAP_REQUEST_SIZE, CXPLAT_ECN_NON_ECT, 0 };
+ CXPLAT_SEND_CONFIG SendConfig = { &Route, PCP_MAP_REQUEST_SIZE, CXPLAT_ECN_NON_ECT, 0, 0 };
CXPLAT_SEND_DATA* SendData = CxPlatSendDataAlloc(Socket, &SendConfig);
if (SendData == NULL) {
return QUIC_STATUS_OUT_OF_MEMORY;
diff --git a/src/platform/unittest/DataPathTest.cpp b/src/platform/unittest/DataPathTest.cpp
index f64d11e0c5..3772e518b3 100644
--- a/src/platform/unittest/DataPathTest.cpp
+++ b/src/platform/unittest/DataPathTest.cpp
@@ -303,7 +303,7 @@ struct DataPathTest : public ::testing::TestWithParam
ASSERT_EQ((CXPLAT_ECN_TYPE)RecvData->TypeOfService, RecvContext->EcnType);
- CXPLAT_SEND_CONFIG SendConfig = { RecvData->Route, 0, (uint8_t)RecvContext->EcnType, 0 };
+ CXPLAT_SEND_CONFIG SendConfig = { RecvData->Route, 0, (uint8_t)RecvContext->EcnType, 0, 0 };
auto ServerSendData = CxPlatSendDataAlloc(Socket, &SendConfig);
ASSERT_NE(nullptr, ServerSendData);
auto ServerBuffer = CxPlatSendDataAllocBuffer(ServerSendData, ExpectedDataSize);
@@ -803,7 +803,7 @@ TEST_P(DataPathTest, UdpData)
VERIFY_QUIC_SUCCESS(Client.GetInitStatus());
ASSERT_NE(nullptr, Client.Socket);
- CXPLAT_SEND_CONFIG SendConfig = { &Client.Route, 0, CXPLAT_ECN_NON_ECT, 0 };
+ CXPLAT_SEND_CONFIG SendConfig = { &Client.Route, 0, CXPLAT_ECN_NON_ECT, 0, 0 };
auto ClientSendData = CxPlatSendDataAlloc(Client, &SendConfig);
ASSERT_NE(nullptr, ClientSendData);
auto ClientBuffer = CxPlatSendDataAllocBuffer(ClientSendData, ExpectedDataSize);
@@ -841,7 +841,7 @@ TEST_P(DataPathTest, UdpDataPolling)
VERIFY_QUIC_SUCCESS(Client.GetInitStatus());
ASSERT_NE(nullptr, Client.Socket);
- CXPLAT_SEND_CONFIG SendConfig = { &Client.Route, 0, CXPLAT_ECN_NON_ECT, 0 };
+ CXPLAT_SEND_CONFIG SendConfig = { &Client.Route, 0, CXPLAT_ECN_NON_ECT, 0, 0 };
auto ClientSendData = CxPlatSendDataAlloc(Client, &SendConfig);
ASSERT_NE(nullptr, ClientSendData);
auto ClientBuffer = CxPlatSendDataAllocBuffer(ClientSendData, ExpectedDataSize);
@@ -879,7 +879,7 @@ TEST_P(DataPathTest, UdpDataRebind)
VERIFY_QUIC_SUCCESS(Client.GetInitStatus());
ASSERT_NE(nullptr, Client.Socket);
- CXPLAT_SEND_CONFIG SendConfig = { &Client.Route, 0, CXPLAT_ECN_NON_ECT, 0 };
+ CXPLAT_SEND_CONFIG SendConfig = { &Client.Route, 0, CXPLAT_ECN_NON_ECT, 0, 0 };
auto ClientSendData = CxPlatSendDataAlloc(Client, &SendConfig);
ASSERT_NE(nullptr, ClientSendData);
auto ClientBuffer = CxPlatSendDataAllocBuffer(ClientSendData, ExpectedDataSize);
@@ -896,7 +896,7 @@ TEST_P(DataPathTest, UdpDataRebind)
VERIFY_QUIC_SUCCESS(Client.GetInitStatus());
ASSERT_NE(nullptr, Client.Socket);
- CXPLAT_SEND_CONFIG SendConfig = { &Client.Route, 0, CXPLAT_ECN_NON_ECT, 0 };
+ CXPLAT_SEND_CONFIG SendConfig = { &Client.Route, 0, CXPLAT_ECN_NON_ECT, 0, 0 };
auto ClientSendData = CxPlatSendDataAlloc(Client, &SendConfig);
ASSERT_NE(nullptr, ClientSendData);
auto ClientBuffer = CxPlatSendDataAllocBuffer(ClientSendData, ExpectedDataSize);
@@ -935,7 +935,7 @@ TEST_P(DataPathTest, UdpDataECT0)
VERIFY_QUIC_SUCCESS(Client.GetInitStatus());
ASSERT_NE(nullptr, Client.Socket);
- CXPLAT_SEND_CONFIG SendConfig = { &Client.Route, 0, CXPLAT_ECN_ECT_0, 0 };
+ CXPLAT_SEND_CONFIG SendConfig = { &Client.Route, 0, CXPLAT_ECN_ECT_0, 0, 0 };
auto ClientSendData = CxPlatSendDataAlloc(Client, &SendConfig);
ASSERT_NE(nullptr, ClientSendData);
auto ClientBuffer = CxPlatSendDataAllocBuffer(ClientSendData, ExpectedDataSize);
@@ -984,7 +984,7 @@ TEST_P(DataPathTest, UdpShareClientSocket)
CxPlatSocket Client2(Datapath, &clientAddress, &serverAddress.SockAddr, &RecvContext, CXPLAT_SOCKET_FLAG_SHARE);
VERIFY_QUIC_SUCCESS(Client2.GetInitStatus());
- CXPLAT_SEND_CONFIG SendConfig = { &Client1.Route, 0, CXPLAT_ECN_NON_ECT, 0 };
+ CXPLAT_SEND_CONFIG SendConfig = { &Client1.Route, 0, CXPLAT_ECN_NON_ECT, 0, 0 };
auto ClientSendData = CxPlatSendDataAlloc(Client1, &SendConfig);
ASSERT_NE(nullptr, ClientSendData);
auto ClientBuffer = CxPlatSendDataAllocBuffer(ClientSendData, ExpectedDataSize);
@@ -996,7 +996,7 @@ TEST_P(DataPathTest, UdpShareClientSocket)
ASSERT_TRUE(CxPlatEventWaitWithTimeout(RecvContext.ClientCompletion, 2000));
CxPlatEventReset(RecvContext.ClientCompletion);
- CXPLAT_SEND_CONFIG SendConfig2 = { &Client2.Route, 0, CXPLAT_ECN_NON_ECT, 0 };
+ CXPLAT_SEND_CONFIG SendConfig2 = { &Client2.Route, 0, CXPLAT_ECN_NON_ECT, 0, 0 };
ClientSendData = CxPlatSendDataAlloc(Client2, &SendConfig2);
ASSERT_NE(nullptr, ClientSendData);
ClientBuffer = CxPlatSendDataAllocBuffer(ClientSendData, ExpectedDataSize);
@@ -1211,7 +1211,7 @@ TEST_P(DataPathTest, TcpDataClient)
ASSERT_TRUE(CxPlatEventWaitWithTimeout(ListenerContext.AcceptEvent, 500));
ASSERT_NE(nullptr, ListenerContext.Server);
- CXPLAT_SEND_CONFIG SendConfig = { &Client.Route, 0, CXPLAT_ECN_NON_ECT, 0 };
+ CXPLAT_SEND_CONFIG SendConfig = { &Client.Route, 0, CXPLAT_ECN_NON_ECT, 0, 0 };
auto SendData = CxPlatSendDataAlloc(Client, &SendConfig);
ASSERT_NE(nullptr, SendData);
auto SendBuffer = CxPlatSendDataAllocBuffer(SendData, ExpectedDataSize);
@@ -1256,7 +1256,7 @@ TEST_P(DataPathTest, TcpDataServer)
CXPLAT_ROUTE Route = Listener.Route;
Route.RemoteAddress = Client.GetLocalAddress();
- CXPLAT_SEND_CONFIG SendConfig = { &Route, 0, CXPLAT_ECN_NON_ECT, 0 };
+ CXPLAT_SEND_CONFIG SendConfig = { &Route, 0, CXPLAT_ECN_NON_ECT, 0, 0 };
auto SendData = CxPlatSendDataAlloc(ListenerContext.Server, &SendConfig);
ASSERT_NE(nullptr, SendData);
auto SendBuffer = CxPlatSendDataAllocBuffer(SendData, ExpectedDataSize);
diff --git a/src/test/lib/QuicDrill.cpp b/src/test/lib/QuicDrill.cpp
index 407f0f2caf..ccc51dcd5d 100644
--- a/src/test/lib/QuicDrill.cpp
+++ b/src/test/lib/QuicDrill.cpp
@@ -205,7 +205,7 @@ struct DrillSender {
CxPlatSocketGetLocalAddress(Binding, &Route.LocalAddress);
Route.RemoteAddress = ServerAddress;
- CXPLAT_SEND_CONFIG SendConfig = { &Route, DatagramLength, CXPLAT_ECN_NON_ECT, 0 };
+ CXPLAT_SEND_CONFIG SendConfig = { &Route, DatagramLength, CXPLAT_ECN_NON_ECT, 0, 0 };
CXPLAT_SEND_DATA* SendData = CxPlatSendDataAlloc(Binding, &SendConfig);
diff --git a/src/tools/attack/attack.cpp b/src/tools/attack/attack.cpp
index 92428cec6f..c6da0c094d 100644
--- a/src/tools/attack/attack.cpp
+++ b/src/tools/attack/attack.cpp
@@ -173,7 +173,7 @@ void RunAttackRandom(CXPLAT_SOCKET* Binding, uint16_t DatagramLength, bool Valid
continue;
}
- CXPLAT_SEND_CONFIG SendConfig = {&Route, DatagramLength, CXPLAT_ECN_NON_ECT, 0 };
+ CXPLAT_SEND_CONFIG SendConfig = {&Route, DatagramLength, CXPLAT_ECN_NON_ECT, 0, 0 };
CXPLAT_SEND_DATA* SendData = CxPlatSendDataAlloc(Binding, &SendConfig);
if (SendData == nullptr) {
continue;
@@ -288,7 +288,7 @@ void RunAttackValidInitial(CXPLAT_SOCKET* Binding)
continue;
}
- CXPLAT_SEND_CONFIG SendConfig = {&Route, DatagramLength, CXPLAT_ECN_NON_ECT, 0 };
+ CXPLAT_SEND_CONFIG SendConfig = {&Route, DatagramLength, CXPLAT_ECN_NON_ECT, 0, 0 };
CXPLAT_SEND_DATA* SendData = CxPlatSendDataAlloc(Binding, &SendConfig);
if (SendData == nullptr) {
continue;
diff --git a/src/tools/lb/loadbalancer.cpp b/src/tools/lb/loadbalancer.cpp
index e87ec0cc20..77be480eef 100644
--- a/src/tools/lb/loadbalancer.cpp
+++ b/src/tools/lb/loadbalancer.cpp
@@ -66,7 +66,7 @@ struct LbInterface {
Route.LocalAddress = LocalAddress;
Route.RemoteAddress = *PeerAddress;
CXPLAT_SEND_DATA* Send = nullptr;
- CXPLAT_SEND_CONFIG SendConfig = { &Route, MAX_UDP_PAYLOAD_LENGTH, CXPLAT_ECN_NON_ECT, 0 };
+ CXPLAT_SEND_CONFIG SendConfig = { &Route, MAX_UDP_PAYLOAD_LENGTH, CXPLAT_ECN_NON_ECT, 0, 0 };
while (RecvDataChain) {
if (!Send) {
Send = CxPlatSendDataAlloc(Socket, &SendConfig);
diff --git a/src/tools/recvfuzz/recvfuzz.cpp b/src/tools/recvfuzz/recvfuzz.cpp
index 178fb00e97..32a99246de 100644
--- a/src/tools/recvfuzz/recvfuzz.cpp
+++ b/src/tools/recvfuzz/recvfuzz.cpp
@@ -591,7 +591,7 @@ void sendPacket(
bool fuzzing = true,
TlsContext* ClientContext = nullptr) {
const uint16_t DatagramLength = QUIC_MIN_INITIAL_LENGTH;
- CXPLAT_SEND_CONFIG SendConfig = { &Route, DatagramLength, CXPLAT_ECN_NON_ECT, 0 };
+ CXPLAT_SEND_CONFIG SendConfig = { &Route, DatagramLength, CXPLAT_ECN_NON_ECT, 0, 0 };
CXPLAT_SEND_DATA* SendData = CxPlatSendDataAlloc(Binding, &SendConfig);
if (!SendData) {
printf("CxPlatSendDataAlloc failed\n");
From fe5a6f3ca37d01192920bf9c77cab10f710aa38d Mon Sep 17 00:00:00 2001
From: Anthony Rossi <41394064+anrossi@users.noreply.github.com>
Date: Sat, 25 Jan 2025 20:20:57 -0800
Subject: [PATCH 05/13] Add tests for Dscp send support.
---
docs/Settings.md | 2 +-
src/platform/datapath_raw_socket.c | 2 +-
src/platform/unittest/DataPathTest.cpp | 40 ++++++++++++++++++++------
3 files changed, 34 insertions(+), 10 deletions(-)
diff --git a/docs/Settings.md b/docs/Settings.md
index 58bba26008..8d6d947245 100644
--- a/docs/Settings.md
+++ b/docs/Settings.md
@@ -177,7 +177,7 @@ These parameters are accessed by calling [GetParam](./api/GetParam.md) or [SetPa
| `QUIC_PARAM_CONN_STATISTICS_V2`
22 | QUIC_STATISTICS_V2 | Get-only | Connection-level statistics, version 2. |
| `QUIC_PARAM_CONN_STATISTICS_V2_PLAT`
23 | QUIC_STATISTICS_V2 | Get-only | Connection-level statistics with platform-specific time format, version 2. |
| `QUIC_PARAM_CONN_ORIG_DEST_CID`
24 | uint8_t[] | Get-only | The original destination connection ID used by the client to connect to the server. |
-| `QUIC_PARAM_CONN_DSCP`
25 | uint8_t | Both | The value put in the Type of Service/Traffic Class field on packets sent from this connection. |
+| `QUIC_PARAM_CONN_DSCP`
25 | uint8_t | Both | The DiffServ Code Point put in the DiffServ field (formerly TypeOfService/TrafficClass) on packets sent from this connection. |
### QUIC_PARAM_CONN_STATISTICS_V2
diff --git a/src/platform/datapath_raw_socket.c b/src/platform/datapath_raw_socket.c
index fddf2e733a..d53ca7bf31 100644
--- a/src/platform/datapath_raw_socket.c
+++ b/src/platform/datapath_raw_socket.c
@@ -366,7 +366,7 @@ CxPlatDpRawParseIPv6(
} VersionClassEcnFlow;
VersionClassEcnFlow.Value = CxPlatByteSwapUint32(IP->VersionClassEcnFlow);
- Packet->TypeOfService = ((uint8_t)VersionClassEcnFlow.EcnField) | (((uint8_t)VersionClassEcnFlow.Class) << 2);
+ Packet->TypeOfService = ((uint8_t)VersionClassEcnFlow.EcnField) | (uint8_t)(VersionClassEcnFlow.Class << 2);
Packet->HopLimitTTL = IP->HopLimit;
Packet->Route->RemoteAddress.Ipv6.sin6_family = AF_INET6;
CxPlatCopyMemory(&Packet->Route->RemoteAddress.Ipv6.sin6_addr, IP->Source, sizeof(IP->Source));
diff --git a/src/platform/unittest/DataPathTest.cpp b/src/platform/unittest/DataPathTest.cpp
index 3772e518b3..34668517a9 100644
--- a/src/platform/unittest/DataPathTest.cpp
+++ b/src/platform/unittest/DataPathTest.cpp
@@ -86,7 +86,9 @@ struct UdpRecvContext {
QUIC_ADDR DestinationAddress;
CXPLAT_EVENT ClientCompletion;
CXPLAT_ECN_TYPE EcnType {CXPLAT_ECN_NON_ECT};
+ uint8_t Dscp{0};
bool TtlSupported;
+ bool DscpSupported;
UdpRecvContext() {
CxPlatEventInitialize(&ClientCompletion, FALSE, FALSE);
}
@@ -299,11 +301,17 @@ struct DataPathTest : public ::testing::TestWithParam
ASSERT_EQ(0, RecvData->HopLimitTTL);
}
+ if (RecvContext->DscpSupported) {
+ ASSERT_EQ(CXPLAT_DSCP_FROM_TOS(RecvData->TypeOfService), RecvContext->Dscp);
+ } else {
+ ASSERT_EQ(CXPLAT_DSCP_FROM_TOS(RecvData->TypeOfService), 0);
+ }
+
if (RecvData->Route->LocalAddress.Ipv4.sin_port == RecvContext->DestinationAddress.Ipv4.sin_port) {
- ASSERT_EQ((CXPLAT_ECN_TYPE)RecvData->TypeOfService, RecvContext->EcnType);
+ ASSERT_EQ(CXPLAT_ECN_FROM_TOS(RecvData->TypeOfService), RecvContext->EcnType);
- CXPLAT_SEND_CONFIG SendConfig = { RecvData->Route, 0, (uint8_t)RecvContext->EcnType, 0, 0 };
+ CXPLAT_SEND_CONFIG SendConfig = { RecvData->Route, 0, (uint8_t)RecvContext->EcnType, 0, RecvContext->Dscp };
auto ServerSendData = CxPlatSendDataAlloc(Socket, &SendConfig);
ASSERT_NE(nullptr, ServerSendData);
auto ServerBuffer = CxPlatSendDataAllocBuffer(ServerSendData, ExpectedDataSize);
@@ -782,9 +790,12 @@ TEST_P(DataPathTest, UdpData)
UdpRecvContext RecvContext;
CxPlatDataPath Datapath(&UdpRecvCallbacks);
RecvContext.TtlSupported = Datapath.IsSupported(CXPLAT_DATAPATH_FEATURE_TTL);
+ RecvContext.DscpSupported = Datapath.IsSupported(CXPLAT_DATAPATH_FEATURE_DSCP);
VERIFY_QUIC_SUCCESS(Datapath.GetInitStatus());
ASSERT_NE(nullptr, Datapath.Datapath);
+ RecvContext.Dscp = RecvContext.DscpSupported ? 1 : 0;
+
auto unspecAddress = GetNewUnspecAddr();
CxPlatSocket Server(Datapath, &unspecAddress.SockAddr, nullptr, &RecvContext);
while (Server.GetInitStatus() == QUIC_STATUS_ADDRESS_IN_USE) {
@@ -803,7 +814,7 @@ TEST_P(DataPathTest, UdpData)
VERIFY_QUIC_SUCCESS(Client.GetInitStatus());
ASSERT_NE(nullptr, Client.Socket);
- CXPLAT_SEND_CONFIG SendConfig = { &Client.Route, 0, CXPLAT_ECN_NON_ECT, 0, 0 };
+ CXPLAT_SEND_CONFIG SendConfig = { &Client.Route, 0, CXPLAT_ECN_NON_ECT, 0, RecvContext.Dscp };
auto ClientSendData = CxPlatSendDataAlloc(Client, &SendConfig);
ASSERT_NE(nullptr, ClientSendData);
auto ClientBuffer = CxPlatSendDataAllocBuffer(ClientSendData, ExpectedDataSize);
@@ -820,9 +831,12 @@ TEST_P(DataPathTest, UdpDataPolling)
UdpRecvContext RecvContext;
CxPlatDataPath Datapath(&UdpRecvCallbacks, nullptr, 0, &Config);
RecvContext.TtlSupported = Datapath.IsSupported(CXPLAT_DATAPATH_FEATURE_TTL);
+ RecvContext.DscpSupported = Datapath.IsSupported(CXPLAT_DATAPATH_FEATURE_DSCP);
VERIFY_QUIC_SUCCESS(Datapath.GetInitStatus());
ASSERT_NE(nullptr, Datapath.Datapath);
+ RecvContext.Dscp = RecvContext.DscpSupported ? 1 : 0;
+
auto unspecAddress = GetNewUnspecAddr();
CxPlatSocket Server(Datapath, &unspecAddress.SockAddr, nullptr, &RecvContext);
while (Server.GetInitStatus() == QUIC_STATUS_ADDRESS_IN_USE) {
@@ -841,7 +855,7 @@ TEST_P(DataPathTest, UdpDataPolling)
VERIFY_QUIC_SUCCESS(Client.GetInitStatus());
ASSERT_NE(nullptr, Client.Socket);
- CXPLAT_SEND_CONFIG SendConfig = { &Client.Route, 0, CXPLAT_ECN_NON_ECT, 0, 0 };
+ CXPLAT_SEND_CONFIG SendConfig = { &Client.Route, 0, CXPLAT_ECN_NON_ECT, 0, RecvContext.Dscp };
auto ClientSendData = CxPlatSendDataAlloc(Client, &SendConfig);
ASSERT_NE(nullptr, ClientSendData);
auto ClientBuffer = CxPlatSendDataAllocBuffer(ClientSendData, ExpectedDataSize);
@@ -857,9 +871,12 @@ TEST_P(DataPathTest, UdpDataRebind)
UdpRecvContext RecvContext;
CxPlatDataPath Datapath(&UdpRecvCallbacks);
RecvContext.TtlSupported = Datapath.IsSupported(CXPLAT_DATAPATH_FEATURE_TTL);
+ RecvContext.DscpSupported = Datapath.IsSupported(CXPLAT_DATAPATH_FEATURE_DSCP);
VERIFY_QUIC_SUCCESS(Datapath.GetInitStatus());
ASSERT_NE(nullptr, Datapath.Datapath);
+ RecvContext.Dscp = RecvContext.DscpSupported ? 1 : 0;
+
auto unspecAddress = GetNewUnspecAddr();
CxPlatSocket Server(Datapath, &unspecAddress.SockAddr, nullptr, &RecvContext);
while (Server.GetInitStatus() == QUIC_STATUS_ADDRESS_IN_USE) {
@@ -879,7 +896,7 @@ TEST_P(DataPathTest, UdpDataRebind)
VERIFY_QUIC_SUCCESS(Client.GetInitStatus());
ASSERT_NE(nullptr, Client.Socket);
- CXPLAT_SEND_CONFIG SendConfig = { &Client.Route, 0, CXPLAT_ECN_NON_ECT, 0, 0 };
+ CXPLAT_SEND_CONFIG SendConfig = { &Client.Route, 0, CXPLAT_ECN_NON_ECT, 0, RecvContext.Dscp };
auto ClientSendData = CxPlatSendDataAlloc(Client, &SendConfig);
ASSERT_NE(nullptr, ClientSendData);
auto ClientBuffer = CxPlatSendDataAllocBuffer(ClientSendData, ExpectedDataSize);
@@ -914,9 +931,12 @@ TEST_P(DataPathTest, UdpDataECT0)
RecvContext.EcnType = CXPLAT_ECN_ECT_0;
CxPlatDataPath Datapath(&UdpRecvCallbacks);
RecvContext.TtlSupported = Datapath.IsSupported(CXPLAT_DATAPATH_FEATURE_TTL);
+ RecvContext.DscpSupported = Datapath.IsSupported(CXPLAT_DATAPATH_FEATURE_DSCP);
VERIFY_QUIC_SUCCESS(Datapath.GetInitStatus());
ASSERT_NE(nullptr, Datapath.Datapath);
+ RecvContext.Dscp = RecvContext.DscpSupported ? 1 : 0;
+
auto unspecAddress = GetNewUnspecAddr();
CxPlatSocket Server(Datapath, &unspecAddress.SockAddr, nullptr, &RecvContext);
while (Server.GetInitStatus() == QUIC_STATUS_ADDRESS_IN_USE) {
@@ -935,7 +955,7 @@ TEST_P(DataPathTest, UdpDataECT0)
VERIFY_QUIC_SUCCESS(Client.GetInitStatus());
ASSERT_NE(nullptr, Client.Socket);
- CXPLAT_SEND_CONFIG SendConfig = { &Client.Route, 0, CXPLAT_ECN_ECT_0, 0, 0 };
+ CXPLAT_SEND_CONFIG SendConfig = { &Client.Route, 0, CXPLAT_ECN_ECT_0, 0, RecvContext.Dscp };
auto ClientSendData = CxPlatSendDataAlloc(Client, &SendConfig);
ASSERT_NE(nullptr, ClientSendData);
auto ClientBuffer = CxPlatSendDataAllocBuffer(ClientSendData, ExpectedDataSize);
@@ -951,6 +971,7 @@ TEST_P(DataPathTest, UdpShareClientSocket)
UdpRecvContext RecvContext;
CxPlatDataPath Datapath(&UdpRecvCallbacks);
RecvContext.TtlSupported = Datapath.IsSupported(CXPLAT_DATAPATH_FEATURE_TTL);
+ RecvContext.DscpSupported = Datapath.IsSupported(CXPLAT_DATAPATH_FEATURE_DSCP);
VERIFY_QUIC_SUCCESS(Datapath.GetInitStatus());
ASSERT_NE(nullptr, Datapath.Datapath);
// TODO: Linux XDP (duonic) to support port sharing
@@ -959,6 +980,8 @@ TEST_P(DataPathTest, UdpShareClientSocket)
return;
}
+ RecvContext.Dscp = RecvContext.DscpSupported ? 1 : 0;
+
auto serverAddress = GetNewLocalAddr();
CxPlatSocket Server1(Datapath, &serverAddress.SockAddr, nullptr, &RecvContext);
while (Server1.GetInitStatus() == QUIC_STATUS_ADDRESS_IN_USE) {
@@ -984,7 +1007,7 @@ TEST_P(DataPathTest, UdpShareClientSocket)
CxPlatSocket Client2(Datapath, &clientAddress, &serverAddress.SockAddr, &RecvContext, CXPLAT_SOCKET_FLAG_SHARE);
VERIFY_QUIC_SUCCESS(Client2.GetInitStatus());
- CXPLAT_SEND_CONFIG SendConfig = { &Client1.Route, 0, CXPLAT_ECN_NON_ECT, 0, 0 };
+ CXPLAT_SEND_CONFIG SendConfig = { &Client1.Route, 0, CXPLAT_ECN_NON_ECT, 0, RecvContext.Dscp };
auto ClientSendData = CxPlatSendDataAlloc(Client1, &SendConfig);
ASSERT_NE(nullptr, ClientSendData);
auto ClientBuffer = CxPlatSendDataAllocBuffer(ClientSendData, ExpectedDataSize);
@@ -996,7 +1019,7 @@ TEST_P(DataPathTest, UdpShareClientSocket)
ASSERT_TRUE(CxPlatEventWaitWithTimeout(RecvContext.ClientCompletion, 2000));
CxPlatEventReset(RecvContext.ClientCompletion);
- CXPLAT_SEND_CONFIG SendConfig2 = { &Client2.Route, 0, CXPLAT_ECN_NON_ECT, 0, 0 };
+ CXPLAT_SEND_CONFIG SendConfig2 = { &Client2.Route, 0, CXPLAT_ECN_NON_ECT, 0, RecvContext.Dscp };
ClientSendData = CxPlatSendDataAlloc(Client2, &SendConfig2);
ASSERT_NE(nullptr, ClientSendData);
ClientBuffer = CxPlatSendDataAllocBuffer(ClientSendData, ExpectedDataSize);
@@ -1035,6 +1058,7 @@ TEST_P(DataPathTest, MultiBindListenerSingleProcessor) {
QUIC_EXECUTION_CONFIG Config = { QUIC_EXECUTION_CONFIG_FLAG_NO_IDEAL_PROC, UINT32_MAX, 1, 0 };
CxPlatDataPath Datapath(&UdpRecvCallbacks, nullptr, 0, &Config);
RecvContext.TtlSupported = Datapath.IsSupported(CXPLAT_DATAPATH_FEATURE_TTL);
+ RecvContext.DscpSupported = Datapath.IsSupported(CXPLAT_DATAPATH_FEATURE_DSCP);
auto ServerAddress = GetNewLocalAddr();
CxPlatSocket Server1(Datapath, &ServerAddress.SockAddr, nullptr, &RecvContext);
From 35eff608ac9fb3399b65d4876d9e587293637005 Mon Sep 17 00:00:00 2001
From: Anthony Rossi <41394064+anrossi@users.noreply.github.com>
Date: Sun, 26 Jan 2025 16:41:12 -0800
Subject: [PATCH 06/13] Fix failing tests, and collect ToS/TClass on Windows
for validation
---
src/platform/datapath_raw_xdp_win.c | 1 +
src/platform/datapath_winkernel.c | 24 ++++++++++++------------
src/platform/datapath_winuser.c | 26 +++++++++++++-------------
src/platform/unittest/DataPathTest.cpp | 2 +-
4 files changed, 27 insertions(+), 26 deletions(-)
diff --git a/src/platform/datapath_raw_xdp_win.c b/src/platform/datapath_raw_xdp_win.c
index c2178bfaf9..3fac60e6e2 100644
--- a/src/platform/datapath_raw_xdp_win.c
+++ b/src/platform/datapath_raw_xdp_win.c
@@ -1618,6 +1618,7 @@ CxPlatDpRawTxAlloc(
Packet->Buffer.Length = Config->MaxPacketSize;
Packet->Buffer.Buffer = &Packet->FrameBuffer[HeaderBackfill.AllLayer];
Packet->ECN = Config->ECN;
+ Packet->DSCP = Config->DSCP;
Packet->DatapathType = Config->Route->DatapathType = CXPLAT_DATAPATH_TYPE_RAW;
}
diff --git a/src/platform/datapath_winkernel.c b/src/platform/datapath_winkernel.c
index 50813b20f6..d933b80a18 100644
--- a/src/platform/datapath_winkernel.c
+++ b/src/platform/datapath_winkernel.c
@@ -1489,7 +1489,7 @@ SocketCreateUdp(
CxPlatDataPathSetControlSocket(
Binding,
WskSetOption,
- IPV6_ECN,
+ IPV6_RECVTCLASS,
IPPROTO_IPV6,
sizeof(Option),
&Option);
@@ -1499,7 +1499,7 @@ SocketCreateUdp(
"[data][%p] ERROR, %u, %s.",
Binding,
Status,
- "Set IPV6_ECN");
+ "Set IPV6_RECVTCLASS");
goto Error;
}
@@ -1508,7 +1508,7 @@ SocketCreateUdp(
CxPlatDataPathSetControlSocket(
Binding,
WskSetOption,
- IP_ECN,
+ IP_RECVTOS,
IPPROTO_IP,
sizeof(Option),
&Option);
@@ -1518,7 +1518,7 @@ SocketCreateUdp(
"[data][%p] ERROR, %u, %s.",
Binding,
Status,
- "Set IP_ECN");
+ "Set IP_RECVTOS");
goto Error;
}
@@ -2070,7 +2070,7 @@ CxPlatDataPathSocketReceive(
SOCKADDR_INET LocalAddr = { 0 };
SOCKADDR_INET RemoteAddr;
UINT16 MessageLength = 0;
- INT ECN = 0;
+ INT TOS = 0;
INT HopLimitTTL = 0;
//
@@ -2100,9 +2100,9 @@ CxPlatDataPathSocketReceive(
IsUnreachableError = TRUE;
break;
}
- } else if (CMsg->cmsg_type == IPV6_ECN) {
- ECN = *(PINT)WSA_CMSG_DATA(CMsg);
- CXPLAT_DBG_ASSERT(ECN < UINT8_MAX);
+ } else if (CMsg->cmsg_type == IPV6_TCLASS) {
+ TOS = *(PINT)WSA_CMSG_DATA(CMsg);
+ CXPLAT_DBG_ASSERT(TOS <= UINT8_MAX);
} else if (CMsg->cmsg_type == IPV6_HOPLIMIT) {
HopLimitTTL = *(PINT)WSA_CMSG_DATA(CMsg);
CXPLAT_DBG_ASSERT(HopLimitTTL < 256);
@@ -2123,9 +2123,9 @@ CxPlatDataPathSocketReceive(
IsUnreachableError = TRUE;
break;
}
- } else if (CMsg->cmsg_type == IP_ECN) {
- ECN = *(PINT)WSA_CMSG_DATA(CMsg);
- CXPLAT_DBG_ASSERT(ECN < UINT8_MAX);
+ } else if (CMsg->cmsg_type == IP_TOS) {
+ TOS = *(PINT)WSA_CMSG_DATA(CMsg);
+ CXPLAT_DBG_ASSERT(TOS <= UINT8_MAX);
} else if (CMsg->cmsg_type == IP_TTL) {
HopLimitTTL = *(PINT)WSA_CMSG_DATA(CMsg);
CXPLAT_DBG_ASSERT(HopLimitTTL < 256);
@@ -2295,7 +2295,7 @@ CxPlatDataPathSocketReceive(
Datagram->IoBlock = IoBlock;
Datagram->Data.Next = NULL;
Datagram->Data.PartitionIndex = (uint16_t)(CurProcNumber % Binding->Datapath->ProcCount);
- Datagram->Data.TypeOfService = (uint8_t)ECN;
+ Datagram->Data.TypeOfService = (uint8_t)TOS;
Datagram->Data.HopLimitTTL = (uint8_t)HopLimitTTL;
Datagram->Data.Allocated = TRUE;
Datagram->Data.QueuedOnConnection = FALSE;
diff --git a/src/platform/datapath_winuser.c b/src/platform/datapath_winuser.c
index 7c67b768f3..690114a286 100644
--- a/src/platform/datapath_winuser.c
+++ b/src/platform/datapath_winuser.c
@@ -163,7 +163,7 @@ typedef struct DATAPATH_RX_IO_BLOCK {
RIO_CMSG_BASE_SIZE +
WSA_CMSG_SPACE(sizeof(IN6_PKTINFO)) + // IP_PKTINFO
WSA_CMSG_SPACE(sizeof(DWORD)) + // UDP_COALESCED_INFO
- WSA_CMSG_SPACE(sizeof(INT)) + // IP_ECN
+ WSA_CMSG_SPACE(sizeof(INT)) + // IP_TOS
WSA_CMSG_SPACE(sizeof(INT)) // IP_HOP_LIMIT
];
@@ -1688,7 +1688,7 @@ SocketCreateUdp(
setsockopt(
SocketProc->Socket,
IPPROTO_IPV6,
- IPV6_ECN,
+ IPV6_RECVTCLASS,
(char*)&Option,
sizeof(Option));
if (Result == SOCKET_ERROR) {
@@ -1698,7 +1698,7 @@ SocketCreateUdp(
"[data][%p] ERROR, %u, %s.",
Socket,
WsaError,
- "Set IPV6_ECN");
+ "Set IPV6_RECVTCLASS");
Status = HRESULT_FROM_WIN32(WsaError);
goto Error;
}
@@ -1708,7 +1708,7 @@ SocketCreateUdp(
setsockopt(
SocketProc->Socket,
IPPROTO_IP,
- IP_ECN,
+ IP_RECVTOS,
(char*)&Option,
sizeof(Option));
if (Result == SOCKET_ERROR) {
@@ -1718,7 +1718,7 @@ SocketCreateUdp(
"[data][%p] ERROR, %u, %s.",
Socket,
WsaError,
- "Set IP_ECN");
+ "Set IP_RECVTOS");
Status = HRESULT_FROM_WIN32(WsaError);
goto Error;
}
@@ -3463,7 +3463,7 @@ CxPlatDataPathUdpRecvComplete(
UINT16 MessageLength = NumberOfBytesTransferred;
ULONG MessageCount = 0;
BOOLEAN IsCoalesced = FALSE;
- INT ECN = 0;
+ INT TOS = 0;
INT HopLimitTTL = 0;
if (SocketProc->Parent->UseRio) {
PRIO_CMSG_BUFFER RioRcvMsg = (PRIO_CMSG_BUFFER)IoBlock->ControlBuf;
@@ -3484,9 +3484,9 @@ CxPlatDataPathUdpRecvComplete(
CxPlatConvertFromMappedV6(LocalAddr, LocalAddr);
LocalAddr->Ipv6.sin6_scope_id = PktInfo6->ipi6_ifindex;
FoundLocalAddr = TRUE;
- } else if (CMsg->cmsg_type == IPV6_ECN) {
- ECN = *(PINT)WSA_CMSG_DATA(CMsg);
- CXPLAT_DBG_ASSERT(ECN < UINT8_MAX);
+ } else if (CMsg->cmsg_type == IPV6_TCLASS) {
+ TOS = *(PINT)WSA_CMSG_DATA(CMsg);
+ CXPLAT_DBG_ASSERT(TOS <= UINT8_MAX);
} else if (CMsg->cmsg_type == IPV6_HOPLIMIT) {
HopLimitTTL = *(PINT)WSA_CMSG_DATA(CMsg);
CXPLAT_DBG_ASSERT(HopLimitTTL < 256);
@@ -3500,9 +3500,9 @@ CxPlatDataPathUdpRecvComplete(
LocalAddr->Ipv4.sin_port = SocketProc->Parent->LocalAddress.Ipv6.sin6_port;
LocalAddr->Ipv6.sin6_scope_id = PktInfo->ipi_ifindex;
FoundLocalAddr = TRUE;
- } else if (CMsg->cmsg_type == IP_ECN) {
- ECN = *(PINT)WSA_CMSG_DATA(CMsg);
- CXPLAT_DBG_ASSERT(ECN < UINT8_MAX);
+ } else if (CMsg->cmsg_type == IP_TOS) {
+ TOS = *(PINT)WSA_CMSG_DATA(CMsg);
+ CXPLAT_DBG_ASSERT(TOS <= UINT8_MAX);
} else if (CMsg->cmsg_type == IP_TTL) {
HopLimitTTL = *(PINT)WSA_CMSG_DATA(CMsg);
CXPLAT_DBG_ASSERT(HopLimitTTL < 256);
@@ -3563,7 +3563,7 @@ CxPlatDataPathUdpRecvComplete(
Datagram->Route = &IoBlock->Route;
Datagram->PartitionIndex =
SocketProc->DatapathProc->PartitionIndex % SocketProc->DatapathProc->Datapath->PartitionCount;
- Datagram->TypeOfService = (uint8_t)ECN;
+ Datagram->TypeOfService = (uint8_t)TOS;
Datagram->HopLimitTTL = (uint8_t) HopLimitTTL;
Datagram->Allocated = TRUE;
Datagram->Route->DatapathType = Datagram->DatapathType = CXPLAT_DATAPATH_TYPE_NORMAL;
diff --git a/src/platform/unittest/DataPathTest.cpp b/src/platform/unittest/DataPathTest.cpp
index 34668517a9..cbe8df2c90 100644
--- a/src/platform/unittest/DataPathTest.cpp
+++ b/src/platform/unittest/DataPathTest.cpp
@@ -913,7 +913,7 @@ TEST_P(DataPathTest, UdpDataRebind)
VERIFY_QUIC_SUCCESS(Client.GetInitStatus());
ASSERT_NE(nullptr, Client.Socket);
- CXPLAT_SEND_CONFIG SendConfig = { &Client.Route, 0, CXPLAT_ECN_NON_ECT, 0, 0 };
+ CXPLAT_SEND_CONFIG SendConfig = { &Client.Route, 0, CXPLAT_ECN_NON_ECT, 0, RecvContext.Dscp };
auto ClientSendData = CxPlatSendDataAlloc(Client, &SendConfig);
ASSERT_NE(nullptr, ClientSendData);
auto ClientBuffer = CxPlatSendDataAllocBuffer(ClientSendData, ExpectedDataSize);
From 2ea4426b7a9f8d80ac2e6df2fa0f5ab32d73caf1 Mon Sep 17 00:00:00 2001
From: Anthony Rossi <41394064+anrossi@users.noreply.github.com>
Date: Thu, 30 Jan 2025 18:33:55 -0800
Subject: [PATCH 07/13] Remove change to collect TOS on Windows platforms on
receive. Address comments.
---
docs/Settings.md | 2 +-
src/core/connection.c | 8 ++---
src/cs/lib/msquic_generated.cs | 4 +--
src/inc/msquic.h | 2 +-
src/inc/quic_datapath.h | 20 ++++++++++--
src/perf/lib/Tcp.cpp | 2 +-
src/platform/datapath_epoll.c | 2 +-
src/platform/datapath_raw.c | 2 +-
src/platform/datapath_raw_socket.c | 6 ++--
src/platform/datapath_winkernel.c | 20 ++++++------
src/platform/datapath_winuser.c | 34 ++++++++++----------
src/platform/pcp.c | 4 +--
src/platform/unittest/DataPathTest.cpp | 44 +++++++++++++-------------
src/test/lib/QuicDrill.cpp | 2 +-
src/tools/attack/attack.cpp | 4 +--
src/tools/lb/loadbalancer.cpp | 2 +-
src/tools/recvfuzz/recvfuzz.cpp | 2 +-
17 files changed, 87 insertions(+), 73 deletions(-)
diff --git a/docs/Settings.md b/docs/Settings.md
index 8d6d947245..0a71f1eddf 100644
--- a/docs/Settings.md
+++ b/docs/Settings.md
@@ -177,7 +177,7 @@ These parameters are accessed by calling [GetParam](./api/GetParam.md) or [SetPa
| `QUIC_PARAM_CONN_STATISTICS_V2`
22 | QUIC_STATISTICS_V2 | Get-only | Connection-level statistics, version 2. |
| `QUIC_PARAM_CONN_STATISTICS_V2_PLAT`
23 | QUIC_STATISTICS_V2 | Get-only | Connection-level statistics with platform-specific time format, version 2. |
| `QUIC_PARAM_CONN_ORIG_DEST_CID`
24 | uint8_t[] | Get-only | The original destination connection ID used by the client to connect to the server. |
-| `QUIC_PARAM_CONN_DSCP`
25 | uint8_t | Both | The DiffServ Code Point put in the DiffServ field (formerly TypeOfService/TrafficClass) on packets sent from this connection. |
+| `QUIC_PARAM_CONN_SEND_DSCP`
25 | uint8_t | Both | The DiffServ Code Point put in the DiffServ field (formerly TypeOfService/TrafficClass) on packets sent from this connection. |
### QUIC_PARAM_CONN_STATISTICS_V2
diff --git a/src/core/connection.c b/src/core/connection.c
index e58ad9974c..9bc8ce31ec 100644
--- a/src/core/connection.c
+++ b/src/core/connection.c
@@ -6623,15 +6623,13 @@ QuicConnParamSet(
return QUIC_STATUS_SUCCESS;
}
- case QUIC_PARAM_CONN_DSCP:
- {
+ case QUIC_PARAM_CONN_SEND_DSCP: {
if (BufferLength != sizeof(uint8_t) || Buffer == NULL) {
Status = QUIC_STATUS_INVALID_PARAMETER;
break;
}
- uint8_t DSCP = 0;
- CxPlatCopyMemory(&DSCP, Buffer, BufferLength);
+ uint8_t DSCP = *(uint8_t*)Buffer;
if (DSCP > CXPLAT_MAX_DSCP) {
Status = QUIC_STATUS_INVALID_PARAMETER;
@@ -7258,7 +7256,7 @@ QuicConnParamGet(
Status = QUIC_STATUS_SUCCESS;
break;
- case QUIC_PARAM_CONN_DSCP:
+ case QUIC_PARAM_CONN_SEND_DSCP:
if (*BufferLength < sizeof(Connection->DSCP)) {
Status = QUIC_STATUS_BUFFER_TOO_SMALL;
diff --git a/src/cs/lib/msquic_generated.cs b/src/cs/lib/msquic_generated.cs
index e725408c40..38ffde0fbd 100644
--- a/src/cs/lib/msquic_generated.cs
+++ b/src/cs/lib/msquic_generated.cs
@@ -3447,8 +3447,8 @@ internal static unsafe partial class MsQuic
[NativeTypeName("#define QUIC_PARAM_CONN_ORIG_DEST_CID 0x05000018")]
internal const uint QUIC_PARAM_CONN_ORIG_DEST_CID = 0x05000018;
- [NativeTypeName("#define QUIC_PARAM_CONN_DSCP 0x50000019")]
- internal const uint QUIC_PARAM_CONN_DSCP = 0x50000019;
+ [NativeTypeName("#define QUIC_PARAM_CONN_SEND_DSCP 0x50000019")]
+ internal const uint QUIC_PARAM_CONN_SEND_DSCP = 0x50000019;
[NativeTypeName("#define QUIC_PARAM_TLS_HANDSHAKE_INFO 0x06000000")]
internal const uint QUIC_PARAM_TLS_HANDSHAKE_INFO = 0x06000000;
diff --git a/src/inc/msquic.h b/src/inc/msquic.h
index 79e96b5199..b2ffbf1704 100644
--- a/src/inc/msquic.h
+++ b/src/inc/msquic.h
@@ -923,7 +923,7 @@ typedef struct QUIC_SCHANNEL_CREDENTIAL_ATTRIBUTE_W {
#define QUIC_PARAM_CONN_STATISTICS_V2 0x05000016 // QUIC_STATISTICS_V2
#define QUIC_PARAM_CONN_STATISTICS_V2_PLAT 0x05000017 // QUIC_STATISTICS_V2
#define QUIC_PARAM_CONN_ORIG_DEST_CID 0x05000018 // uint8_t[]
-#define QUIC_PARAM_CONN_DSCP 0x50000019 // uint8_t
+#define QUIC_PARAM_CONN_SEND_DSCP 0x50000019 // uint8_t
//
// Parameters for TLS.
diff --git a/src/inc/quic_datapath.h b/src/inc/quic_datapath.h
index ec52c85d97..a3c88f4039 100644
--- a/src/inc/quic_datapath.h
+++ b/src/inc/quic_datapath.h
@@ -53,6 +53,22 @@ typedef enum CXPLAT_ECN_TYPE {
} CXPLAT_ECN_TYPE;
+//
+// Different DiffServ Code Points
+//
+typedef enum CXPLAT_DSCP_TYPE {
+
+ CXPLAT_DSCP_CS0 = 0,
+ CXPLAT_DSCP_LE = 1,
+ CXPLAT_DSCP_CS1 = 8,
+ CXPLAT_DSCP_CS2 = 16,
+ CXPLAT_DSCP_CS3 = 24,
+ CXPLAT_DSCP_CS4 = 32,
+ CXPLAT_DSCP_CS5 = 40,
+ CXPLAT_DSCP_EF = 46,
+
+} CXPLAT_DSCP_TYPE;
+
//
// Helper to get the ECN type from the Type of Service field of received data.
//
@@ -455,7 +471,7 @@ CxPlatDataPathUpdateConfig(
#define CXPLAT_DATAPATH_FEATURE_TCP 0x0020
#define CXPLAT_DATAPATH_FEATURE_RAW 0x0040
#define CXPLAT_DATAPATH_FEATURE_TTL 0x0080
-#define CXPLAT_DATAPATH_FEATURE_DSCP 0x0100
+#define CXPLAT_DATAPATH_FEATURE_SEND_DSCP 0x0100
//
// Queries the currently supported features of the datapath.
@@ -687,7 +703,7 @@ typedef struct CXPLAT_SEND_CONFIG {
uint16_t MaxPacketSize;
uint8_t ECN; // CXPLAT_ECN_TYPE
uint8_t Flags; // CXPLAT_SEND_FLAGS
- uint8_t DSCP;
+ uint8_t DSCP; // CXPLAT_DSCP_TYPE
} CXPLAT_SEND_CONFIG;
//
diff --git a/src/perf/lib/Tcp.cpp b/src/perf/lib/Tcp.cpp
index fd328b1651..a48be7eb4c 100644
--- a/src/perf/lib/Tcp.cpp
+++ b/src/perf/lib/Tcp.cpp
@@ -1088,7 +1088,7 @@ QUIC_BUFFER* TcpConnection::NewSendBuffer()
return nullptr;
}
if (!BatchedSendData) {
- CXPLAT_SEND_CONFIG SendConfig = { &Route, TLS_BLOCK_SIZE, CXPLAT_ECN_NON_ECT, 0, 0 };
+ CXPLAT_SEND_CONFIG SendConfig = { &Route, TLS_BLOCK_SIZE, CXPLAT_ECN_NON_ECT, 0, CXPLAT_DSCP_CS0 };
BatchedSendData = CxPlatSendDataAlloc(Socket, &SendConfig);
if (!BatchedSendData) { return nullptr; }
}
diff --git a/src/platform/datapath_epoll.c b/src/platform/datapath_epoll.c
index 4601181cf9..37f8101ff4 100644
--- a/src/platform/datapath_epoll.c
+++ b/src/platform/datapath_epoll.c
@@ -340,7 +340,7 @@ CxPlatDataPathCalculateFeatureSupport(
Datapath->Features |= CXPLAT_DATAPATH_FEATURE_TCP;
Datapath->Features |= CXPLAT_DATAPATH_FEATURE_TTL;
- Datapath->Features |= CXPLAT_DATAPATH_FEATURE_DSCP;
+ Datapath->Features |= CXPLAT_DATAPATH_FEATURE_SEND_DSCP;
}
void
diff --git a/src/platform/datapath_raw.c b/src/platform/datapath_raw.c
index e860e40c1d..19c3d35336 100644
--- a/src/platform/datapath_raw.c
+++ b/src/platform/datapath_raw.c
@@ -150,7 +150,7 @@ RawDataPathGetSupportedFeatures(
)
{
UNREFERENCED_PARAMETER(Datapath);
- return CXPLAT_DATAPATH_FEATURE_RAW | CXPLAT_DATAPATH_FEATURE_TTL;
+ return CXPLAT_DATAPATH_FEATURE_RAW | CXPLAT_DATAPATH_FEATURE_TTL | CXPLAT_DATAPATH_FEATURE_SEND_DSCP;
}
_IRQL_requires_max_(DISPATCH_LEVEL)
diff --git a/src/platform/datapath_raw_socket.c b/src/platform/datapath_raw_socket.c
index d53ca7bf31..1e82cc38af 100644
--- a/src/platform/datapath_raw_socket.c
+++ b/src/platform/datapath_raw_socket.c
@@ -538,7 +538,7 @@ CxPlatDpRawSocketAckFin(
CXPLAT_DBG_ASSERT(Socket->UseTcp);
CXPLAT_ROUTE* Route = Packet->Route;
- CXPLAT_SEND_CONFIG SendConfig = { Route, 0, CXPLAT_ECN_NON_ECT, 0, 0 };
+ CXPLAT_SEND_CONFIG SendConfig = { Route, 0, CXPLAT_ECN_NON_ECT, 0, CXPLAT_DSCP_CS0 };
CXPLAT_SEND_DATA *SendData = CxPlatSendDataAlloc(CxPlatRawToSocket(Socket), &SendConfig);
if (SendData == NULL) {
return;
@@ -577,7 +577,7 @@ CxPlatDpRawSocketAckSyn(
CXPLAT_DBG_ASSERT(Socket->UseTcp);
CXPLAT_ROUTE* Route = Packet->Route;
- CXPLAT_SEND_CONFIG SendConfig = { Route, 0, CXPLAT_ECN_NON_ECT, 0, 0 };
+ CXPLAT_SEND_CONFIG SendConfig = { Route, 0, CXPLAT_ECN_NON_ECT, 0, CXPLAT_DSCP_CS0 };
CXPLAT_SEND_DATA *SendData = CxPlatSendDataAlloc(CxPlatRawToSocket(Socket), &SendConfig);
if (SendData == NULL) {
return;
@@ -660,7 +660,7 @@ CxPlatDpRawSocketSyn(
)
{
CXPLAT_DBG_ASSERT(Socket->UseTcp);
- CXPLAT_SEND_CONFIG SendConfig = { (CXPLAT_ROUTE*)Route, 0, CXPLAT_ECN_NON_ECT, 0, 0 };
+ CXPLAT_SEND_CONFIG SendConfig = { (CXPLAT_ROUTE*)Route, 0, CXPLAT_ECN_NON_ECT, 0, CXPLAT_DSCP_CS0 };
CXPLAT_SEND_DATA *SendData = CxPlatSendDataAlloc(CxPlatRawToSocket(Socket), &SendConfig);
if (SendData == NULL) {
return;
diff --git a/src/platform/datapath_winkernel.c b/src/platform/datapath_winkernel.c
index d933b80a18..8517d7aaf1 100644
--- a/src/platform/datapath_winkernel.c
+++ b/src/platform/datapath_winkernel.c
@@ -644,7 +644,7 @@ CxPlatDataPathQuerySockoptSupport(
break;
}
- Datapath->Features |= CXPLAT_DATAPATH_FEATURE_DSCP;
+ Datapath->Features |= CXPLAT_DATAPATH_FEATURE_SEND_DSCP;
} while (FALSE);
@@ -2070,7 +2070,7 @@ CxPlatDataPathSocketReceive(
SOCKADDR_INET LocalAddr = { 0 };
SOCKADDR_INET RemoteAddr;
UINT16 MessageLength = 0;
- INT TOS = 0;
+ INT ECN = 0;
INT HopLimitTTL = 0;
//
@@ -2100,9 +2100,9 @@ CxPlatDataPathSocketReceive(
IsUnreachableError = TRUE;
break;
}
- } else if (CMsg->cmsg_type == IPV6_TCLASS) {
- TOS = *(PINT)WSA_CMSG_DATA(CMsg);
- CXPLAT_DBG_ASSERT(TOS <= UINT8_MAX);
+ } else if (CMsg->cmsg_type == IPV6_ECN) {
+ ECN = *(PINT)WSA_CMSG_DATA(CMsg);
+ CXPLAT_DBG_ASSERT(ECN < UINT8_MAX);
} else if (CMsg->cmsg_type == IPV6_HOPLIMIT) {
HopLimitTTL = *(PINT)WSA_CMSG_DATA(CMsg);
CXPLAT_DBG_ASSERT(HopLimitTTL < 256);
@@ -2123,9 +2123,9 @@ CxPlatDataPathSocketReceive(
IsUnreachableError = TRUE;
break;
}
- } else if (CMsg->cmsg_type == IP_TOS) {
- TOS = *(PINT)WSA_CMSG_DATA(CMsg);
- CXPLAT_DBG_ASSERT(TOS <= UINT8_MAX);
+ } else if (CMsg->cmsg_type == IP_ECN) {
+ ECN = *(PINT)WSA_CMSG_DATA(CMsg);
+ CXPLAT_DBG_ASSERT(ECN < UINT8_MAX);
} else if (CMsg->cmsg_type == IP_TTL) {
HopLimitTTL = *(PINT)WSA_CMSG_DATA(CMsg);
CXPLAT_DBG_ASSERT(HopLimitTTL < 256);
@@ -2295,7 +2295,7 @@ CxPlatDataPathSocketReceive(
Datagram->IoBlock = IoBlock;
Datagram->Data.Next = NULL;
Datagram->Data.PartitionIndex = (uint16_t)(CurProcNumber % Binding->Datapath->ProcCount);
- Datagram->Data.TypeOfService = (uint8_t)TOS;
+ Datagram->Data.TypeOfService = (uint8_t)ECN;
Datagram->Data.HopLimitTTL = (uint8_t)HopLimitTTL;
Datagram->Data.Allocated = TRUE;
Datagram->Data.QueuedOnConnection = FALSE;
@@ -2973,7 +2973,7 @@ SocketSend(
*(PINT)WSA_CMSG_DATA(CMsg) = SendData->ECN;
}
- if (Binding->Datapath->Features & CXPLAT_DATAPATH_FEATURE_DSCP) {
+ if (Binding->Datapath->Features & CXPLAT_DATAPATH_FEATURE_SEND_DSCP) {
CMsg = (PWSACMSGHDR)&CMsgBuffer[CMsgLen];
CMsgLen += WSA_CMSG_SPACE(sizeof(INT));
CMsg->cmsg_level =
diff --git a/src/platform/datapath_winuser.c b/src/platform/datapath_winuser.c
index 690114a286..cabb43c929 100644
--- a/src/platform/datapath_winuser.c
+++ b/src/platform/datapath_winuser.c
@@ -163,7 +163,7 @@ typedef struct DATAPATH_RX_IO_BLOCK {
RIO_CMSG_BASE_SIZE +
WSA_CMSG_SPACE(sizeof(IN6_PKTINFO)) + // IP_PKTINFO
WSA_CMSG_SPACE(sizeof(DWORD)) + // UDP_COALESCED_INFO
- WSA_CMSG_SPACE(sizeof(INT)) + // IP_TOS
+ WSA_CMSG_SPACE(sizeof(INT)) + // IP_ECN
WSA_CMSG_SPACE(sizeof(INT)) // IP_HOP_LIMIT
];
@@ -274,7 +274,7 @@ typedef struct CXPLAT_SEND_DATA {
RIO_CMSG_BASE_SIZE +
WSA_CMSG_SPACE(sizeof(IN6_PKTINFO)) + // IP_PKTINFO
WSA_CMSG_SPACE(sizeof(INT)) + // IP_ECN
- WSA_CMSG_SPACE(sizeof(INT)) + // IP_TOS/IPV6_TCLASS
+ WSA_CMSG_SPACE(sizeof(INT)) + // IP_TOS
WSA_CMSG_SPACE(sizeof(DWORD)) // UDP_SEND_MSG_SIZE
];
@@ -732,7 +732,7 @@ CxPlatDataPathQuerySockoptSupport(
"[data] Test setting IPV6_TCLASS failed, 0x%x",
WsaError);
} else {
- Datapath->Features |= CXPLAT_DATAPATH_FEATURE_DSCP;
+ Datapath->Features |= CXPLAT_DATAPATH_FEATURE_SEND_DSCP;
}
closesocket(Udpv6Socket);
}
@@ -1688,7 +1688,7 @@ SocketCreateUdp(
setsockopt(
SocketProc->Socket,
IPPROTO_IPV6,
- IPV6_RECVTCLASS,
+ IPV6_ECN,
(char*)&Option,
sizeof(Option));
if (Result == SOCKET_ERROR) {
@@ -1698,7 +1698,7 @@ SocketCreateUdp(
"[data][%p] ERROR, %u, %s.",
Socket,
WsaError,
- "Set IPV6_RECVTCLASS");
+ "Set IPV6_ECN");
Status = HRESULT_FROM_WIN32(WsaError);
goto Error;
}
@@ -1708,7 +1708,7 @@ SocketCreateUdp(
setsockopt(
SocketProc->Socket,
IPPROTO_IP,
- IP_RECVTOS,
+ IP_ECN,
(char*)&Option,
sizeof(Option));
if (Result == SOCKET_ERROR) {
@@ -1718,7 +1718,7 @@ SocketCreateUdp(
"[data][%p] ERROR, %u, %s.",
Socket,
WsaError,
- "Set IP_RECVTOS");
+ "Set IP_ECN");
Status = HRESULT_FROM_WIN32(WsaError);
goto Error;
}
@@ -3463,7 +3463,7 @@ CxPlatDataPathUdpRecvComplete(
UINT16 MessageLength = NumberOfBytesTransferred;
ULONG MessageCount = 0;
BOOLEAN IsCoalesced = FALSE;
- INT TOS = 0;
+ INT ECN = 0;
INT HopLimitTTL = 0;
if (SocketProc->Parent->UseRio) {
PRIO_CMSG_BUFFER RioRcvMsg = (PRIO_CMSG_BUFFER)IoBlock->ControlBuf;
@@ -3484,9 +3484,9 @@ CxPlatDataPathUdpRecvComplete(
CxPlatConvertFromMappedV6(LocalAddr, LocalAddr);
LocalAddr->Ipv6.sin6_scope_id = PktInfo6->ipi6_ifindex;
FoundLocalAddr = TRUE;
- } else if (CMsg->cmsg_type == IPV6_TCLASS) {
- TOS = *(PINT)WSA_CMSG_DATA(CMsg);
- CXPLAT_DBG_ASSERT(TOS <= UINT8_MAX);
+ } else if (CMsg->cmsg_type == IPV6_ECN) {
+ ECN = *(PINT)WSA_CMSG_DATA(CMsg);
+ CXPLAT_DBG_ASSERT(ECN < UINT8_MAX);
} else if (CMsg->cmsg_type == IPV6_HOPLIMIT) {
HopLimitTTL = *(PINT)WSA_CMSG_DATA(CMsg);
CXPLAT_DBG_ASSERT(HopLimitTTL < 256);
@@ -3500,9 +3500,9 @@ CxPlatDataPathUdpRecvComplete(
LocalAddr->Ipv4.sin_port = SocketProc->Parent->LocalAddress.Ipv6.sin6_port;
LocalAddr->Ipv6.sin6_scope_id = PktInfo->ipi_ifindex;
FoundLocalAddr = TRUE;
- } else if (CMsg->cmsg_type == IP_TOS) {
- TOS = *(PINT)WSA_CMSG_DATA(CMsg);
- CXPLAT_DBG_ASSERT(TOS <= UINT8_MAX);
+ } else if (CMsg->cmsg_type == IP_ECN) {
+ ECN = *(PINT)WSA_CMSG_DATA(CMsg);
+ CXPLAT_DBG_ASSERT(ECN < UINT8_MAX);
} else if (CMsg->cmsg_type == IP_TTL) {
HopLimitTTL = *(PINT)WSA_CMSG_DATA(CMsg);
CXPLAT_DBG_ASSERT(HopLimitTTL < 256);
@@ -3563,7 +3563,7 @@ CxPlatDataPathUdpRecvComplete(
Datagram->Route = &IoBlock->Route;
Datagram->PartitionIndex =
SocketProc->DatapathProc->PartitionIndex % SocketProc->DatapathProc->Datapath->PartitionCount;
- Datagram->TypeOfService = (uint8_t)TOS;
+ Datagram->TypeOfService = (uint8_t)ECN;
Datagram->HopLimitTTL = (uint8_t) HopLimitTTL;
Datagram->Allocated = TRUE;
Datagram->Route->DatapathType = Datagram->DatapathType = CXPLAT_DATAPATH_TYPE_NORMAL;
@@ -4528,7 +4528,7 @@ CxPlatSocketSendInline(
CMsg->cmsg_len = WSA_CMSG_LEN(sizeof(INT));
*(PINT)WSA_CMSG_DATA(CMsg) = SendData->ECN;
- if (Socket->Datapath->Features & CXPLAT_DATAPATH_FEATURE_DSCP) {
+ if (Socket->Datapath->Features & CXPLAT_DATAPATH_FEATURE_SEND_DSCP) {
WSAMhdr.Control.len += WSA_CMSG_SPACE(sizeof(INT));
CMsg = WSA_CMSG_NXTHDR(&WSAMhdr, CMsg);
CXPLAT_DBG_ASSERT(CMsg != NULL);
@@ -4559,7 +4559,7 @@ CxPlatSocketSendInline(
CMsg->cmsg_len = WSA_CMSG_LEN(sizeof(INT));
*(PINT)WSA_CMSG_DATA(CMsg) = SendData->ECN;
- if (Socket->Datapath->Features & CXPLAT_DATAPATH_FEATURE_DSCP) {
+ if (Socket->Datapath->Features & CXPLAT_DATAPATH_FEATURE_SEND_DSCP) {
WSAMhdr.Control.len += WSA_CMSG_SPACE(sizeof(INT));
CMsg = WSA_CMSG_NXTHDR(&WSAMhdr, CMsg);
CXPLAT_DBG_ASSERT(CMsg != NULL);
diff --git a/src/platform/pcp.c b/src/platform/pcp.c
index e090b0bb17..b86d7c24a6 100644
--- a/src/platform/pcp.c
+++ b/src/platform/pcp.c
@@ -391,7 +391,7 @@ CxPlatPcpSendMapRequestInternal(
QUIC_ADDR LocalMappedAddress;
CxPlatConvertToMappedV6(&Route.LocalAddress, &LocalMappedAddress);
- CXPLAT_SEND_CONFIG SendConfig = { &Route, PCP_MAP_REQUEST_SIZE, CXPLAT_ECN_NON_ECT, 0, 0 };
+ CXPLAT_SEND_CONFIG SendConfig = { &Route, PCP_MAP_REQUEST_SIZE, CXPLAT_ECN_NON_ECT, 0, CXPLAT_DSCP_CS0 };
CXPLAT_SEND_DATA* SendData = CxPlatSendDataAlloc(Socket, &SendConfig);
if (SendData == NULL) {
return QUIC_STATUS_OUT_OF_MEMORY;
@@ -483,7 +483,7 @@ CxPlatPcpSendPeerRequestInternal(
QUIC_ADDR RemotePeerMappedAddress;
CxPlatConvertToMappedV6(RemotePeerAddress, &RemotePeerMappedAddress);
- CXPLAT_SEND_CONFIG SendConfig = { &Route, PCP_MAP_REQUEST_SIZE, CXPLAT_ECN_NON_ECT, 0, 0 };
+ CXPLAT_SEND_CONFIG SendConfig = { &Route, PCP_MAP_REQUEST_SIZE, CXPLAT_ECN_NON_ECT, 0, CXPLAT_DSCP_CS0 };
CXPLAT_SEND_DATA* SendData = CxPlatSendDataAlloc(Socket, &SendConfig);
if (SendData == NULL) {
return QUIC_STATUS_OUT_OF_MEMORY;
diff --git a/src/platform/unittest/DataPathTest.cpp b/src/platform/unittest/DataPathTest.cpp
index cbe8df2c90..7afbbefa4f 100644
--- a/src/platform/unittest/DataPathTest.cpp
+++ b/src/platform/unittest/DataPathTest.cpp
@@ -86,7 +86,7 @@ struct UdpRecvContext {
QUIC_ADDR DestinationAddress;
CXPLAT_EVENT ClientCompletion;
CXPLAT_ECN_TYPE EcnType {CXPLAT_ECN_NON_ECT};
- uint8_t Dscp{0};
+ CXPLAT_DSCP_TYPE Dscp {CXPLAT_DSCP_CS0};
bool TtlSupported;
bool DscpSupported;
UdpRecvContext() {
@@ -311,7 +311,7 @@ struct DataPathTest : public ::testing::TestWithParam
ASSERT_EQ(CXPLAT_ECN_FROM_TOS(RecvData->TypeOfService), RecvContext->EcnType);
- CXPLAT_SEND_CONFIG SendConfig = { RecvData->Route, 0, (uint8_t)RecvContext->EcnType, 0, RecvContext->Dscp };
+ CXPLAT_SEND_CONFIG SendConfig = { RecvData->Route, 0, (uint8_t)RecvContext->EcnType, 0, (uint8_t)RecvContext->Dscp };
auto ServerSendData = CxPlatSendDataAlloc(Socket, &SendConfig);
ASSERT_NE(nullptr, ServerSendData);
auto ServerBuffer = CxPlatSendDataAllocBuffer(ServerSendData, ExpectedDataSize);
@@ -790,11 +790,11 @@ TEST_P(DataPathTest, UdpData)
UdpRecvContext RecvContext;
CxPlatDataPath Datapath(&UdpRecvCallbacks);
RecvContext.TtlSupported = Datapath.IsSupported(CXPLAT_DATAPATH_FEATURE_TTL);
- RecvContext.DscpSupported = Datapath.IsSupported(CXPLAT_DATAPATH_FEATURE_DSCP);
+ RecvContext.DscpSupported = Datapath.IsSupported(CXPLAT_DATAPATH_FEATURE_SEND_DSCP);
VERIFY_QUIC_SUCCESS(Datapath.GetInitStatus());
ASSERT_NE(nullptr, Datapath.Datapath);
- RecvContext.Dscp = RecvContext.DscpSupported ? 1 : 0;
+ RecvContext.Dscp = RecvContext.DscpSupported ? CXPLAT_DSCP_LE : CXPLAT_DSCP_CS0;
auto unspecAddress = GetNewUnspecAddr();
CxPlatSocket Server(Datapath, &unspecAddress.SockAddr, nullptr, &RecvContext);
@@ -814,7 +814,7 @@ TEST_P(DataPathTest, UdpData)
VERIFY_QUIC_SUCCESS(Client.GetInitStatus());
ASSERT_NE(nullptr, Client.Socket);
- CXPLAT_SEND_CONFIG SendConfig = { &Client.Route, 0, CXPLAT_ECN_NON_ECT, 0, RecvContext.Dscp };
+ CXPLAT_SEND_CONFIG SendConfig = { &Client.Route, 0, CXPLAT_ECN_NON_ECT, 0, (uint8_t)RecvContext.Dscp };
auto ClientSendData = CxPlatSendDataAlloc(Client, &SendConfig);
ASSERT_NE(nullptr, ClientSendData);
auto ClientBuffer = CxPlatSendDataAllocBuffer(ClientSendData, ExpectedDataSize);
@@ -831,11 +831,11 @@ TEST_P(DataPathTest, UdpDataPolling)
UdpRecvContext RecvContext;
CxPlatDataPath Datapath(&UdpRecvCallbacks, nullptr, 0, &Config);
RecvContext.TtlSupported = Datapath.IsSupported(CXPLAT_DATAPATH_FEATURE_TTL);
- RecvContext.DscpSupported = Datapath.IsSupported(CXPLAT_DATAPATH_FEATURE_DSCP);
+ RecvContext.DscpSupported = Datapath.IsSupported(CXPLAT_DATAPATH_FEATURE_SEND_DSCP);
VERIFY_QUIC_SUCCESS(Datapath.GetInitStatus());
ASSERT_NE(nullptr, Datapath.Datapath);
- RecvContext.Dscp = RecvContext.DscpSupported ? 1 : 0;
+ RecvContext.Dscp = RecvContext.DscpSupported ? CXPLAT_DSCP_LE : CXPLAT_DSCP_CS0;
auto unspecAddress = GetNewUnspecAddr();
CxPlatSocket Server(Datapath, &unspecAddress.SockAddr, nullptr, &RecvContext);
@@ -855,7 +855,7 @@ TEST_P(DataPathTest, UdpDataPolling)
VERIFY_QUIC_SUCCESS(Client.GetInitStatus());
ASSERT_NE(nullptr, Client.Socket);
- CXPLAT_SEND_CONFIG SendConfig = { &Client.Route, 0, CXPLAT_ECN_NON_ECT, 0, RecvContext.Dscp };
+ CXPLAT_SEND_CONFIG SendConfig = { &Client.Route, 0, CXPLAT_ECN_NON_ECT, 0, (uint8_t)RecvContext.Dscp };
auto ClientSendData = CxPlatSendDataAlloc(Client, &SendConfig);
ASSERT_NE(nullptr, ClientSendData);
auto ClientBuffer = CxPlatSendDataAllocBuffer(ClientSendData, ExpectedDataSize);
@@ -871,11 +871,11 @@ TEST_P(DataPathTest, UdpDataRebind)
UdpRecvContext RecvContext;
CxPlatDataPath Datapath(&UdpRecvCallbacks);
RecvContext.TtlSupported = Datapath.IsSupported(CXPLAT_DATAPATH_FEATURE_TTL);
- RecvContext.DscpSupported = Datapath.IsSupported(CXPLAT_DATAPATH_FEATURE_DSCP);
+ RecvContext.DscpSupported = Datapath.IsSupported(CXPLAT_DATAPATH_FEATURE_SEND_DSCP);
VERIFY_QUIC_SUCCESS(Datapath.GetInitStatus());
ASSERT_NE(nullptr, Datapath.Datapath);
- RecvContext.Dscp = RecvContext.DscpSupported ? 1 : 0;
+ RecvContext.Dscp = RecvContext.DscpSupported ? CXPLAT_DSCP_LE : CXPLAT_DSCP_CS0;
auto unspecAddress = GetNewUnspecAddr();
CxPlatSocket Server(Datapath, &unspecAddress.SockAddr, nullptr, &RecvContext);
@@ -896,7 +896,7 @@ TEST_P(DataPathTest, UdpDataRebind)
VERIFY_QUIC_SUCCESS(Client.GetInitStatus());
ASSERT_NE(nullptr, Client.Socket);
- CXPLAT_SEND_CONFIG SendConfig = { &Client.Route, 0, CXPLAT_ECN_NON_ECT, 0, RecvContext.Dscp };
+ CXPLAT_SEND_CONFIG SendConfig = { &Client.Route, 0, CXPLAT_ECN_NON_ECT, 0, (uint8_t)RecvContext.Dscp };
auto ClientSendData = CxPlatSendDataAlloc(Client, &SendConfig);
ASSERT_NE(nullptr, ClientSendData);
auto ClientBuffer = CxPlatSendDataAllocBuffer(ClientSendData, ExpectedDataSize);
@@ -913,7 +913,7 @@ TEST_P(DataPathTest, UdpDataRebind)
VERIFY_QUIC_SUCCESS(Client.GetInitStatus());
ASSERT_NE(nullptr, Client.Socket);
- CXPLAT_SEND_CONFIG SendConfig = { &Client.Route, 0, CXPLAT_ECN_NON_ECT, 0, RecvContext.Dscp };
+ CXPLAT_SEND_CONFIG SendConfig = { &Client.Route, 0, CXPLAT_ECN_NON_ECT, 0, (uint8_t)RecvContext.Dscp };
auto ClientSendData = CxPlatSendDataAlloc(Client, &SendConfig);
ASSERT_NE(nullptr, ClientSendData);
auto ClientBuffer = CxPlatSendDataAllocBuffer(ClientSendData, ExpectedDataSize);
@@ -931,11 +931,11 @@ TEST_P(DataPathTest, UdpDataECT0)
RecvContext.EcnType = CXPLAT_ECN_ECT_0;
CxPlatDataPath Datapath(&UdpRecvCallbacks);
RecvContext.TtlSupported = Datapath.IsSupported(CXPLAT_DATAPATH_FEATURE_TTL);
- RecvContext.DscpSupported = Datapath.IsSupported(CXPLAT_DATAPATH_FEATURE_DSCP);
+ RecvContext.DscpSupported = Datapath.IsSupported(CXPLAT_DATAPATH_FEATURE_SEND_DSCP);
VERIFY_QUIC_SUCCESS(Datapath.GetInitStatus());
ASSERT_NE(nullptr, Datapath.Datapath);
- RecvContext.Dscp = RecvContext.DscpSupported ? 1 : 0;
+ RecvContext.Dscp = RecvContext.DscpSupported ? CXPLAT_DSCP_LE : CXPLAT_DSCP_CS0;
auto unspecAddress = GetNewUnspecAddr();
CxPlatSocket Server(Datapath, &unspecAddress.SockAddr, nullptr, &RecvContext);
@@ -955,7 +955,7 @@ TEST_P(DataPathTest, UdpDataECT0)
VERIFY_QUIC_SUCCESS(Client.GetInitStatus());
ASSERT_NE(nullptr, Client.Socket);
- CXPLAT_SEND_CONFIG SendConfig = { &Client.Route, 0, CXPLAT_ECN_ECT_0, 0, RecvContext.Dscp };
+ CXPLAT_SEND_CONFIG SendConfig = { &Client.Route, 0, CXPLAT_ECN_ECT_0, 0, (uint8_t)RecvContext.Dscp };
auto ClientSendData = CxPlatSendDataAlloc(Client, &SendConfig);
ASSERT_NE(nullptr, ClientSendData);
auto ClientBuffer = CxPlatSendDataAllocBuffer(ClientSendData, ExpectedDataSize);
@@ -971,7 +971,7 @@ TEST_P(DataPathTest, UdpShareClientSocket)
UdpRecvContext RecvContext;
CxPlatDataPath Datapath(&UdpRecvCallbacks);
RecvContext.TtlSupported = Datapath.IsSupported(CXPLAT_DATAPATH_FEATURE_TTL);
- RecvContext.DscpSupported = Datapath.IsSupported(CXPLAT_DATAPATH_FEATURE_DSCP);
+ RecvContext.DscpSupported = Datapath.IsSupported(CXPLAT_DATAPATH_FEATURE_SEND_DSCP);
VERIFY_QUIC_SUCCESS(Datapath.GetInitStatus());
ASSERT_NE(nullptr, Datapath.Datapath);
// TODO: Linux XDP (duonic) to support port sharing
@@ -980,7 +980,7 @@ TEST_P(DataPathTest, UdpShareClientSocket)
return;
}
- RecvContext.Dscp = RecvContext.DscpSupported ? 1 : 0;
+ RecvContext.Dscp = RecvContext.DscpSupported ? CXPLAT_DSCP_LE : CXPLAT_DSCP_CS0;
auto serverAddress = GetNewLocalAddr();
CxPlatSocket Server1(Datapath, &serverAddress.SockAddr, nullptr, &RecvContext);
@@ -1007,7 +1007,7 @@ TEST_P(DataPathTest, UdpShareClientSocket)
CxPlatSocket Client2(Datapath, &clientAddress, &serverAddress.SockAddr, &RecvContext, CXPLAT_SOCKET_FLAG_SHARE);
VERIFY_QUIC_SUCCESS(Client2.GetInitStatus());
- CXPLAT_SEND_CONFIG SendConfig = { &Client1.Route, 0, CXPLAT_ECN_NON_ECT, 0, RecvContext.Dscp };
+ CXPLAT_SEND_CONFIG SendConfig = { &Client1.Route, 0, CXPLAT_ECN_NON_ECT, 0, (uint8_t)RecvContext.Dscp };
auto ClientSendData = CxPlatSendDataAlloc(Client1, &SendConfig);
ASSERT_NE(nullptr, ClientSendData);
auto ClientBuffer = CxPlatSendDataAllocBuffer(ClientSendData, ExpectedDataSize);
@@ -1019,7 +1019,7 @@ TEST_P(DataPathTest, UdpShareClientSocket)
ASSERT_TRUE(CxPlatEventWaitWithTimeout(RecvContext.ClientCompletion, 2000));
CxPlatEventReset(RecvContext.ClientCompletion);
- CXPLAT_SEND_CONFIG SendConfig2 = { &Client2.Route, 0, CXPLAT_ECN_NON_ECT, 0, RecvContext.Dscp };
+ CXPLAT_SEND_CONFIG SendConfig2 = { &Client2.Route, 0, CXPLAT_ECN_NON_ECT, 0, (uint8_t)RecvContext.Dscp };
ClientSendData = CxPlatSendDataAlloc(Client2, &SendConfig2);
ASSERT_NE(nullptr, ClientSendData);
ClientBuffer = CxPlatSendDataAllocBuffer(ClientSendData, ExpectedDataSize);
@@ -1058,7 +1058,7 @@ TEST_P(DataPathTest, MultiBindListenerSingleProcessor) {
QUIC_EXECUTION_CONFIG Config = { QUIC_EXECUTION_CONFIG_FLAG_NO_IDEAL_PROC, UINT32_MAX, 1, 0 };
CxPlatDataPath Datapath(&UdpRecvCallbacks, nullptr, 0, &Config);
RecvContext.TtlSupported = Datapath.IsSupported(CXPLAT_DATAPATH_FEATURE_TTL);
- RecvContext.DscpSupported = Datapath.IsSupported(CXPLAT_DATAPATH_FEATURE_DSCP);
+ RecvContext.DscpSupported = Datapath.IsSupported(CXPLAT_DATAPATH_FEATURE_SEND_DSCP);
auto ServerAddress = GetNewLocalAddr();
CxPlatSocket Server1(Datapath, &ServerAddress.SockAddr, nullptr, &RecvContext);
@@ -1235,7 +1235,7 @@ TEST_P(DataPathTest, TcpDataClient)
ASSERT_TRUE(CxPlatEventWaitWithTimeout(ListenerContext.AcceptEvent, 500));
ASSERT_NE(nullptr, ListenerContext.Server);
- CXPLAT_SEND_CONFIG SendConfig = { &Client.Route, 0, CXPLAT_ECN_NON_ECT, 0, 0 };
+ CXPLAT_SEND_CONFIG SendConfig = { &Client.Route, 0, CXPLAT_ECN_NON_ECT, 0, CXPLAT_DSCP_CS0 };
auto SendData = CxPlatSendDataAlloc(Client, &SendConfig);
ASSERT_NE(nullptr, SendData);
auto SendBuffer = CxPlatSendDataAllocBuffer(SendData, ExpectedDataSize);
@@ -1280,7 +1280,7 @@ TEST_P(DataPathTest, TcpDataServer)
CXPLAT_ROUTE Route = Listener.Route;
Route.RemoteAddress = Client.GetLocalAddress();
- CXPLAT_SEND_CONFIG SendConfig = { &Route, 0, CXPLAT_ECN_NON_ECT, 0, 0 };
+ CXPLAT_SEND_CONFIG SendConfig = { &Route, 0, CXPLAT_ECN_NON_ECT, 0, CXPLAT_DSCP_CS0 };
auto SendData = CxPlatSendDataAlloc(ListenerContext.Server, &SendConfig);
ASSERT_NE(nullptr, SendData);
auto SendBuffer = CxPlatSendDataAllocBuffer(SendData, ExpectedDataSize);
diff --git a/src/test/lib/QuicDrill.cpp b/src/test/lib/QuicDrill.cpp
index ccc51dcd5d..4276a84f94 100644
--- a/src/test/lib/QuicDrill.cpp
+++ b/src/test/lib/QuicDrill.cpp
@@ -205,7 +205,7 @@ struct DrillSender {
CxPlatSocketGetLocalAddress(Binding, &Route.LocalAddress);
Route.RemoteAddress = ServerAddress;
- CXPLAT_SEND_CONFIG SendConfig = { &Route, DatagramLength, CXPLAT_ECN_NON_ECT, 0, 0 };
+ CXPLAT_SEND_CONFIG SendConfig = { &Route, DatagramLength, CXPLAT_ECN_NON_ECT, 0, CXPLAT_DSCP_CS0 };
CXPLAT_SEND_DATA* SendData = CxPlatSendDataAlloc(Binding, &SendConfig);
diff --git a/src/tools/attack/attack.cpp b/src/tools/attack/attack.cpp
index c6da0c094d..66e80da649 100644
--- a/src/tools/attack/attack.cpp
+++ b/src/tools/attack/attack.cpp
@@ -173,7 +173,7 @@ void RunAttackRandom(CXPLAT_SOCKET* Binding, uint16_t DatagramLength, bool Valid
continue;
}
- CXPLAT_SEND_CONFIG SendConfig = {&Route, DatagramLength, CXPLAT_ECN_NON_ECT, 0, 0 };
+ CXPLAT_SEND_CONFIG SendConfig = {&Route, DatagramLength, CXPLAT_ECN_NON_ECT, 0, CXPLAT_DSCP_CS0 };
CXPLAT_SEND_DATA* SendData = CxPlatSendDataAlloc(Binding, &SendConfig);
if (SendData == nullptr) {
continue;
@@ -288,7 +288,7 @@ void RunAttackValidInitial(CXPLAT_SOCKET* Binding)
continue;
}
- CXPLAT_SEND_CONFIG SendConfig = {&Route, DatagramLength, CXPLAT_ECN_NON_ECT, 0, 0 };
+ CXPLAT_SEND_CONFIG SendConfig = {&Route, DatagramLength, CXPLAT_ECN_NON_ECT, 0, CXPLAT_DSCP_CS0 };
CXPLAT_SEND_DATA* SendData = CxPlatSendDataAlloc(Binding, &SendConfig);
if (SendData == nullptr) {
continue;
diff --git a/src/tools/lb/loadbalancer.cpp b/src/tools/lb/loadbalancer.cpp
index 77be480eef..c95ac4e6f6 100644
--- a/src/tools/lb/loadbalancer.cpp
+++ b/src/tools/lb/loadbalancer.cpp
@@ -66,7 +66,7 @@ struct LbInterface {
Route.LocalAddress = LocalAddress;
Route.RemoteAddress = *PeerAddress;
CXPLAT_SEND_DATA* Send = nullptr;
- CXPLAT_SEND_CONFIG SendConfig = { &Route, MAX_UDP_PAYLOAD_LENGTH, CXPLAT_ECN_NON_ECT, 0, 0 };
+ CXPLAT_SEND_CONFIG SendConfig = { &Route, MAX_UDP_PAYLOAD_LENGTH, CXPLAT_ECN_NON_ECT, 0, CXPLAT_DSCP_CS0 };
while (RecvDataChain) {
if (!Send) {
Send = CxPlatSendDataAlloc(Socket, &SendConfig);
diff --git a/src/tools/recvfuzz/recvfuzz.cpp b/src/tools/recvfuzz/recvfuzz.cpp
index 32a99246de..45a972d6a2 100644
--- a/src/tools/recvfuzz/recvfuzz.cpp
+++ b/src/tools/recvfuzz/recvfuzz.cpp
@@ -591,7 +591,7 @@ void sendPacket(
bool fuzzing = true,
TlsContext* ClientContext = nullptr) {
const uint16_t DatagramLength = QUIC_MIN_INITIAL_LENGTH;
- CXPLAT_SEND_CONFIG SendConfig = { &Route, DatagramLength, CXPLAT_ECN_NON_ECT, 0, 0 };
+ CXPLAT_SEND_CONFIG SendConfig = { &Route, DatagramLength, CXPLAT_ECN_NON_ECT, 0, CXPLAT_DSCP_CS0 };
CXPLAT_SEND_DATA* SendData = CxPlatSendDataAlloc(Binding, &SendConfig);
if (!SendData) {
printf("CxPlatSendDataAlloc failed\n");
From 098f9e623bda587937c4adde96671a6a09e1c24c Mon Sep 17 00:00:00 2001
From: Anthony Rossi <41394064+anrossi@users.noreply.github.com>
Date: Mon, 3 Feb 2025 19:17:14 -0800
Subject: [PATCH 08/13] Fix winkernel and add test for the API setting.
---
src/core/binding.c | 2 +-
src/core/connection.c | 10 ++-
src/cs/lib/msquic_generated.cs | 4 +-
src/generated/linux/connection.c.clog.h | 20 +++++
.../linux/connection.c.clog.h.lttng.h | 23 ++++++
src/inc/msquic.h | 2 +-
src/manifest/clog.sidecar | 21 +++++
src/platform/datapath_winkernel.c | 10 ++-
src/platform/datapath_winuser.c | 4 +-
src/test/lib/ApiTest.cpp | 78 +++++++++++++++++++
10 files changed, 162 insertions(+), 12 deletions(-)
diff --git a/src/core/binding.c b/src/core/binding.c
index 22f03f5f62..c62c967392 100644
--- a/src/core/binding.c
+++ b/src/core/binding.c
@@ -803,7 +803,7 @@ QuicBindingProcessStatelessOperation(
Binding,
OperationType);
- CXPLAT_SEND_CONFIG SendConfig = { RecvPacket->Route, 0, CXPLAT_ECN_NON_ECT, 0, 0 };
+ CXPLAT_SEND_CONFIG SendConfig = { RecvPacket->Route, 0, CXPLAT_ECN_NON_ECT, 0, CXPLAT_DSCP_CS0 };
CXPLAT_SEND_DATA* SendData = CxPlatSendDataAlloc(Binding->Socket, &SendConfig);
if (SendData == NULL) {
QuicTraceEvent(
diff --git a/src/core/connection.c b/src/core/connection.c
index 9bc8ce31ec..11eb95bb24 100644
--- a/src/core/connection.c
+++ b/src/core/connection.c
@@ -6638,6 +6638,12 @@ QuicConnParamSet(
Connection->DSCP = DSCP;
+ QuicTraceLogConnInfo(
+ ConnDscpSet,
+ Connection,
+ "Connection DSCP set to %hhu",
+ Connection->DSCP);
+
Status = QUIC_STATUS_SUCCESS;
break;
}
@@ -7258,9 +7264,9 @@ QuicConnParamGet(
case QUIC_PARAM_CONN_SEND_DSCP:
- if (*BufferLength < sizeof(Connection->DSCP)) {
+ if (*BufferLength < sizeof(uint8_t)) {
Status = QUIC_STATUS_BUFFER_TOO_SMALL;
- *BufferLength = sizeof(Connection->DSCP);
+ *BufferLength = sizeof(uint8_t);
break;
}
diff --git a/src/cs/lib/msquic_generated.cs b/src/cs/lib/msquic_generated.cs
index 38ffde0fbd..b545481b5d 100644
--- a/src/cs/lib/msquic_generated.cs
+++ b/src/cs/lib/msquic_generated.cs
@@ -3447,8 +3447,8 @@ internal static unsafe partial class MsQuic
[NativeTypeName("#define QUIC_PARAM_CONN_ORIG_DEST_CID 0x05000018")]
internal const uint QUIC_PARAM_CONN_ORIG_DEST_CID = 0x05000018;
- [NativeTypeName("#define QUIC_PARAM_CONN_SEND_DSCP 0x50000019")]
- internal const uint QUIC_PARAM_CONN_SEND_DSCP = 0x50000019;
+ [NativeTypeName("#define QUIC_PARAM_CONN_SEND_DSCP 0x05000019")]
+ internal const uint QUIC_PARAM_CONN_SEND_DSCP = 0x05000019;
[NativeTypeName("#define QUIC_PARAM_TLS_HANDSHAKE_INFO 0x06000000")]
internal const uint QUIC_PARAM_TLS_HANDSHAKE_INFO = 0x06000000;
diff --git a/src/generated/linux/connection.c.clog.h b/src/generated/linux/connection.c.clog.h
index 181deaaa58..aea2726bfb 100644
--- a/src/generated/linux/connection.c.clog.h
+++ b/src/generated/linux/connection.c.clog.h
@@ -838,6 +838,26 @@ tracepoint(CLOG_CONNECTION_C, CibirIdSet , arg1, arg3, arg4);\
+/*----------------------------------------------------------
+// Decoder Ring for ConnDscpSet
+// [conn][%p] Connection DSCP set to %hhu
+// QuicTraceLogConnInfo(
+ ConnDscpSet,
+ Connection,
+ "Connection DSCP set to %hhu",
+ Connection->DSCP);
+// arg1 = arg1 = Connection = arg1
+// arg3 = arg3 = Connection->DSCP = arg3
+----------------------------------------------------------*/
+#ifndef _clog_4_ARGS_TRACE_ConnDscpSet
+#define _clog_4_ARGS_TRACE_ConnDscpSet(uniqueId, arg1, encoded_arg_string, arg3)\
+tracepoint(CLOG_CONNECTION_C, ConnDscpSet , arg1, arg3);\
+
+#endif
+
+
+
+
/*----------------------------------------------------------
// Decoder Ring for ApplySettings
// [conn][%p] Applying new settings
diff --git a/src/generated/linux/connection.c.clog.h.lttng.h b/src/generated/linux/connection.c.clog.h.lttng.h
index 8cef04d1cc..6d059961ec 100644
--- a/src/generated/linux/connection.c.clog.h.lttng.h
+++ b/src/generated/linux/connection.c.clog.h.lttng.h
@@ -899,6 +899,29 @@ TRACEPOINT_EVENT(CLOG_CONNECTION_C, CibirIdSet,
+/*----------------------------------------------------------
+// Decoder Ring for ConnDscpSet
+// [conn][%p] Connection DSCP set to %hhu
+// QuicTraceLogConnInfo(
+ ConnDscpSet,
+ Connection,
+ "Connection DSCP set to %hhu",
+ Connection->DSCP);
+// arg1 = arg1 = Connection = arg1
+// arg3 = arg3 = Connection->DSCP = arg3
+----------------------------------------------------------*/
+TRACEPOINT_EVENT(CLOG_CONNECTION_C, ConnDscpSet,
+ TP_ARGS(
+ const void *, arg1,
+ unsigned char, arg3),
+ TP_FIELDS(
+ ctf_integer_hex(uint64_t, arg1, (uint64_t)arg1)
+ ctf_integer(unsigned char, arg3, arg3)
+ )
+)
+
+
+
/*----------------------------------------------------------
// Decoder Ring for ApplySettings
// [conn][%p] Applying new settings
diff --git a/src/inc/msquic.h b/src/inc/msquic.h
index b2ffbf1704..b3cb7398fe 100644
--- a/src/inc/msquic.h
+++ b/src/inc/msquic.h
@@ -923,7 +923,7 @@ typedef struct QUIC_SCHANNEL_CREDENTIAL_ATTRIBUTE_W {
#define QUIC_PARAM_CONN_STATISTICS_V2 0x05000016 // QUIC_STATISTICS_V2
#define QUIC_PARAM_CONN_STATISTICS_V2_PLAT 0x05000017 // QUIC_STATISTICS_V2
#define QUIC_PARAM_CONN_ORIG_DEST_CID 0x05000018 // uint8_t[]
-#define QUIC_PARAM_CONN_SEND_DSCP 0x50000019 // uint8_t
+#define QUIC_PARAM_CONN_SEND_DSCP 0x05000019 // uint8_t
//
// Parameters for TLS.
diff --git a/src/manifest/clog.sidecar b/src/manifest/clog.sidecar
index be36e869b4..dd9ee30625 100644
--- a/src/manifest/clog.sidecar
+++ b/src/manifest/clog.sidecar
@@ -1251,6 +1251,22 @@
],
"macroName": "QuicTraceEvent"
},
+ "ConnDscpSet": {
+ "ModuleProperites": {},
+ "TraceString": "[conn][%p] Connection DSCP set to %hhu",
+ "UniqueId": "ConnDscpSet",
+ "splitArgs": [
+ {
+ "DefinationEncoding": "p",
+ "MacroVariableName": "arg1"
+ },
+ {
+ "DefinationEncoding": "hhu",
+ "MacroVariableName": "arg3"
+ }
+ ],
+ "macroName": "QuicTraceLogConnInfo"
+ },
"ConnEcnCapable": {
"ModuleProperites": {},
"TraceString": "[conn][%p] Ecn: IsCapable=%hu",
@@ -13820,6 +13836,11 @@
"TraceID": "ConnDropPacketEx",
"EncodingString": "[conn][%p] DROP packet Value=%llu Dst=%!ADDR! Src=%!ADDR! Reason=%s."
},
+ {
+ "UniquenessHash": "c753358e-985b-ee38-30e0-cc6cebbe5526",
+ "TraceID": "ConnDscpSet",
+ "EncodingString": "[conn][%p] Connection DSCP set to %hhu"
+ },
{
"UniquenessHash": "9c10f710-84bf-766d-0da5-9e31796cf450",
"TraceID": "ConnEcnCapable",
diff --git a/src/platform/datapath_winkernel.c b/src/platform/datapath_winkernel.c
index 8517d7aaf1..5dfa34ca8a 100644
--- a/src/platform/datapath_winkernel.c
+++ b/src/platform/datapath_winkernel.c
@@ -1489,7 +1489,7 @@ SocketCreateUdp(
CxPlatDataPathSetControlSocket(
Binding,
WskSetOption,
- IPV6_RECVTCLASS,
+ IPV6_ECN,
IPPROTO_IPV6,
sizeof(Option),
&Option);
@@ -1499,7 +1499,7 @@ SocketCreateUdp(
"[data][%p] ERROR, %u, %s.",
Binding,
Status,
- "Set IPV6_RECVTCLASS");
+ "Set IPV6_ECN");
goto Error;
}
@@ -1508,7 +1508,7 @@ SocketCreateUdp(
CxPlatDataPathSetControlSocket(
Binding,
WskSetOption,
- IP_RECVTOS,
+ IP_ECN,
IPPROTO_IP,
sizeof(Option),
&Option);
@@ -1518,7 +1518,7 @@ SocketCreateUdp(
"[data][%p] ERROR, %u, %s.",
Binding,
Status,
- "Set IP_RECVTOS");
+ "Set IP_ECN");
goto Error;
}
@@ -2983,6 +2983,8 @@ SocketSend(
Route->LocalAddress.si_family == QUIC_ADDRESS_FAMILY_INET ?
IP_TOS : IPV6_TCLASS;
CMsg->cmsg_len = WSA_CMSG_LEN(sizeof(INT));
+
+ *(PINT)WSA_CMSG_DATA(CMsg) = SendData->ECN | (SendData->DSCP << 2);
}
if (SendData->SegmentSize > 0) {
diff --git a/src/platform/datapath_winuser.c b/src/platform/datapath_winuser.c
index cabb43c929..60595b5405 100644
--- a/src/platform/datapath_winuser.c
+++ b/src/platform/datapath_winuser.c
@@ -4535,7 +4535,7 @@ CxPlatSocketSendInline(
CMsg->cmsg_level = IPPROTO_IP;
CMsg->cmsg_type = IP_TOS;
CMsg->cmsg_len = WSA_CMSG_LEN(sizeof(INT));
- *(PINT)WSA_CMSG_DATA(CMsg) = SendData->DSCP;
+ *(PINT)WSA_CMSG_DATA(CMsg) = SendData->ECN | (SendData->DSCP << 2);
}
} else {
@@ -4566,7 +4566,7 @@ CxPlatSocketSendInline(
CMsg->cmsg_level = IPPROTO_IPV6;
CMsg->cmsg_type = IPV6_TCLASS;
CMsg->cmsg_len = WSA_CMSG_LEN(sizeof(INT));
- *(PINT)WSA_CMSG_DATA(CMsg) = SendData->DSCP;
+ *(PINT)WSA_CMSG_DATA(CMsg) = SendData->ECN | (SendData->DSCP << 2);
}
}
diff --git a/src/test/lib/ApiTest.cpp b/src/test/lib/ApiTest.cpp
index 71bda9c8ef..be89924888 100644
--- a/src/test/lib/ApiTest.cpp
+++ b/src/test/lib/ApiTest.cpp
@@ -4521,6 +4521,83 @@ void QuicTest_QUIC_PARAM_CONN_ORIG_DEST_CID(MsQuicRegistration& Registration, Ms
}
}
+void QuicTest_QUIC_PARAM_CONN_SEND_DSCP(MsQuicRegistration& Registration)
+{
+ TestScopeLogger LogScope0("QUIC_PARAM_CONN_SEND_DSCP");
+ {
+ TestScopeLogger LogScope1("SetParam null buffer");
+ MsQuicConnection Connection(Registration);
+ TEST_QUIC_SUCCEEDED(Connection.GetInitStatus());
+ uint8_t Dummy = 0;
+ TEST_QUIC_STATUS(
+ QUIC_STATUS_INVALID_PARAMETER,
+ Connection.SetParam(
+ QUIC_PARAM_CONN_SEND_DSCP,
+ sizeof(Dummy),
+ nullptr));
+ }
+ {
+ TestScopeLogger LogScope1("SetParam zero length");
+ MsQuicConnection Connection(Registration);
+ TEST_QUIC_SUCCEEDED(Connection.GetInitStatus());
+ uint8_t Dummy = 0;
+ TEST_QUIC_STATUS(
+ QUIC_STATUS_INVALID_PARAMETER,
+ Connection.SetParam(
+ QUIC_PARAM_CONN_SEND_DSCP,
+ 0,
+ &Dummy));
+ }
+ {
+ TestScopeLogger LogScope1("SetParam non-DSCP number");
+ MsQuicConnection Connection(Registration);
+ TEST_QUIC_SUCCEEDED(Connection.GetInitStatus());
+ uint8_t Dummy = 64;
+ TEST_QUIC_STATUS(
+ QUIC_STATUS_INVALID_PARAMETER,
+ Connection.SetParam(
+ QUIC_PARAM_CONN_SEND_DSCP,
+ sizeof(Dummy),
+ &Dummy));
+ Dummy = 255;
+ TEST_QUIC_STATUS(
+ QUIC_STATUS_INVALID_PARAMETER,
+ Connection.SetParam(
+ QUIC_PARAM_CONN_SEND_DSCP,
+ sizeof(Dummy),
+ &Dummy));
+ }
+ {
+ TestScopeLogger LogScope1("GetParam Default");
+ MsQuicConnection Connection(Registration);
+ TEST_QUIC_SUCCEEDED(Connection.GetInitStatus());
+ uint8_t Dscp = 0;
+ SimpleGetParamTest(Connection.Handle, QUIC_PARAM_CONN_SEND_DSCP, sizeof(Dscp), &Dscp);
+ }
+ {
+ TestScopeLogger LogScope1("SetParam/GetParam Valid DSCP");
+ MsQuicConnection Connection(Registration);
+ TEST_QUIC_SUCCEEDED(Connection.GetInitStatus());
+ uint8_t Dscp = CXPLAT_DSCP_LE;
+ uint8_t GetValue = 0;
+ TEST_QUIC_STATUS(
+ QUIC_STATUS_SUCCESS,
+ Connection.SetParam(
+ QUIC_PARAM_CONN_SEND_DSCP,
+ sizeof(Dscp),
+ &Dscp));
+ uint32_t BufferSize = sizeof(GetValue);
+ TEST_QUIC_STATUS(
+ QUIC_STATUS_SUCCESS,
+ Connection.GetParam(
+ QUIC_PARAM_CONN_SEND_DSCP,
+ &BufferSize,
+ &GetValue));
+ TEST_EQUAL(BufferSize, sizeof(GetValue));
+ TEST_EQUAL(GetValue, Dscp);
+ }
+}
+
void QuicTestConnectionParam()
{
MsQuicAlpn Alpn("MsQuicTest");
@@ -4554,6 +4631,7 @@ void QuicTestConnectionParam()
QuicTest_QUIC_PARAM_CONN_STATISTICS_V2(Registration);
QuicTest_QUIC_PARAM_CONN_STATISTICS_V2_PLAT(Registration);
QuicTest_QUIC_PARAM_CONN_ORIG_DEST_CID(Registration, ClientConfiguration);
+ QuicTest_QUIC_PARAM_CONN_SEND_DSCP(Registration);
}
//
From 7fc999be78770070e80c03b2e70a542c3166d887 Mon Sep 17 00:00:00 2001
From: Anthony Rossi <41394064+anrossi@users.noreply.github.com>
Date: Mon, 3 Feb 2025 21:44:04 -0800
Subject: [PATCH 09/13] Add coverage for NULL buffer to GetParam tests
---
src/test/lib/TestHelpers.h | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/src/test/lib/TestHelpers.h b/src/test/lib/TestHelpers.h
index d4a04f9d58..f077d16fcc 100644
--- a/src/test/lib/TestHelpers.h
+++ b/src/test/lib/TestHelpers.h
@@ -194,6 +194,17 @@ void SimpleGetParamTest(HQUIC Handle, uint32_t Param, size_t ExpectedLength, voi
}
}
+ //
+ // Call with correct length now, but NULL buffer for added coverage.
+ //
+ TEST_QUIC_STATUS(
+ QUIC_STATUS_INVALID_PARAMETER,
+ MsQuic->GetParam(
+ Handle,
+ Param,
+ &Length,
+ nullptr));
+
Length = (uint32_t)ExpectedLength; // Only query the expected size, which might be less.
void* Value = CXPLAT_ALLOC_NONPAGED(Length, QUIC_POOL_TEST);
if (Value == nullptr) {
From cc4d4f8098d85ca3070525a8f6d55f8d017c7ca2 Mon Sep 17 00:00:00 2001
From: Anthony Rossi <41394064+anrossi@users.noreply.github.com>
Date: Tue, 4 Feb 2025 13:40:50 -0800
Subject: [PATCH 10/13] Only set IP_ECN when IP_TOS isn't supported. Only set
ECN or TOS when ECN and DSCP are non-default
---
src/platform/datapath_raw_socket.c | 2 +-
src/platform/datapath_winkernel.c | 52 ++++++++++++++++--------------
src/platform/datapath_winuser.c | 37 +++++++++++----------
3 files changed, 48 insertions(+), 43 deletions(-)
diff --git a/src/platform/datapath_raw_socket.c b/src/platform/datapath_raw_socket.c
index 1e82cc38af..9641ea9109 100644
--- a/src/platform/datapath_raw_socket.c
+++ b/src/platform/datapath_raw_socket.c
@@ -366,7 +366,7 @@ CxPlatDpRawParseIPv6(
} VersionClassEcnFlow;
VersionClassEcnFlow.Value = CxPlatByteSwapUint32(IP->VersionClassEcnFlow);
- Packet->TypeOfService = ((uint8_t)VersionClassEcnFlow.EcnField) | (uint8_t)(VersionClassEcnFlow.Class << 2);
+ Packet->TypeOfService = (uint8_t)(VersionClassEcnFlow.EcnField | (VersionClassEcnFlow.Class << 2));
Packet->HopLimitTTL = IP->HopLimit;
Packet->Route->RemoteAddress.Ipv6.sin6_family = AF_INET6;
CxPlatCopyMemory(&Packet->Route->RemoteAddress.Ipv6.sin6_addr, IP->Source, sizeof(IP->Source));
diff --git a/src/platform/datapath_winkernel.c b/src/platform/datapath_winkernel.c
index 5dfa34ca8a..6f0ef59759 100644
--- a/src/platform/datapath_winkernel.c
+++ b/src/platform/datapath_winkernel.c
@@ -2929,8 +2929,7 @@ SocketSend(
//
BYTE CMsgBuffer[
WSA_CMSG_SPACE(sizeof(IN6_PKTINFO)) + // IP_PKTINFO
- WSA_CMSG_SPACE(sizeof(INT)) + // IP_ECN
- WSA_CMSG_SPACE(sizeof(INT)) + // IP_TOS/IPV6_TCLASS
+ WSA_CMSG_SPACE(sizeof(INT)) + // IP_ECN or IP_TOS
WSA_CMSG_SPACE(sizeof(*SegmentSize)) // UDP_SEND_MSG_SIZE
];
PWSACMSGHDR CMsg = (PWSACMSGHDR)CMsgBuffer;
@@ -2961,30 +2960,33 @@ SocketSend(
}
}
- if (SendData->ECN != CXPLAT_ECN_NON_ECT) {
- CMsg = (PWSACMSGHDR)&CMsgBuffer[CMsgLen];
- CMsgLen += WSA_CMSG_SPACE(sizeof(INT));
- CMsg->cmsg_level =
- Route->LocalAddress.si_family == QUIC_ADDRESS_FAMILY_INET ?
- IPPROTO_IP : IPPROTO_IPV6;
- CMsg->cmsg_type = IP_ECN; // == IPV6_ECN
- CMsg->cmsg_len = WSA_CMSG_LEN(sizeof(INT));
-
- *(PINT)WSA_CMSG_DATA(CMsg) = SendData->ECN;
- }
-
if (Binding->Datapath->Features & CXPLAT_DATAPATH_FEATURE_SEND_DSCP) {
- CMsg = (PWSACMSGHDR)&CMsgBuffer[CMsgLen];
- CMsgLen += WSA_CMSG_SPACE(sizeof(INT));
- CMsg->cmsg_level =
- Route->LocalAddress.si_family == QUIC_ADDRESS_FAMILY_INET ?
- IPPROTO_IP : IPPROTO_IPV6;
- CMsg->cmsg_type =
- Route->LocalAddress.si_family == QUIC_ADDRESS_FAMILY_INET ?
- IP_TOS : IPV6_TCLASS;
- CMsg->cmsg_len = WSA_CMSG_LEN(sizeof(INT));
-
- *(PINT)WSA_CMSG_DATA(CMsg) = SendData->ECN | (SendData->DSCP << 2);
+ if (SendData->ECN != CXPLAT_ECN_NON_ECT || SendData->DSCP != CXPLAT_DSCP_CS0) {
+ CMsg = (PWSACMSGHDR)&CMsgBuffer[CMsgLen];
+ CMsgLen += WSA_CMSG_SPACE(sizeof(INT));
+ if (Route->LocalAddress.si_family == QUIC_ADDRESS_FAMILY_INET) {
+ CMsg->cmsg_level = IPPROTO_IP;
+ CMsg->cmsg_type = IP_TOS;
+ } else {
+ CMsg->cmsg_level = IPPROTO_IPV6;
+ CMsg->cmsg_type = IPV6_TCLASS;
+ }
+ CMsg->cmsg_len = WSA_CMSG_LEN(sizeof(INT));
+
+ *(PINT)WSA_CMSG_DATA(CMsg) = SendData->ECN | (SendData->DSCP << 2);
+ }
+ } else {
+ if (SendData->ECN != CXPLAT_ECN_NON_ECT) {
+ CMsg = (PWSACMSGHDR)&CMsgBuffer[CMsgLen];
+ CMsgLen += WSA_CMSG_SPACE(sizeof(INT));
+ CMsg->cmsg_level =
+ Route->LocalAddress.si_family == QUIC_ADDRESS_FAMILY_INET ?
+ IPPROTO_IP : IPPROTO_IPV6;
+ CMsg->cmsg_type = IP_ECN; // == IPV6_ECN
+ CMsg->cmsg_len = WSA_CMSG_LEN(sizeof(INT));
+
+ *(PINT)WSA_CMSG_DATA(CMsg) = SendData->ECN;
+ }
}
if (SendData->SegmentSize > 0) {
diff --git a/src/platform/datapath_winuser.c b/src/platform/datapath_winuser.c
index 60595b5405..8a292a6c96 100644
--- a/src/platform/datapath_winuser.c
+++ b/src/platform/datapath_winuser.c
@@ -273,8 +273,7 @@ typedef struct CXPLAT_SEND_DATA {
char CtrlBuf[
RIO_CMSG_BASE_SIZE +
WSA_CMSG_SPACE(sizeof(IN6_PKTINFO)) + // IP_PKTINFO
- WSA_CMSG_SPACE(sizeof(INT)) + // IP_ECN
- WSA_CMSG_SPACE(sizeof(INT)) + // IP_TOS
+ WSA_CMSG_SPACE(sizeof(INT)) + // IP_ECN or IP_TOS
WSA_CMSG_SPACE(sizeof(DWORD)) // UDP_SEND_MSG_SIZE
];
@@ -4520,22 +4519,26 @@ CxPlatSocketSendInline(
PktInfo->ipi_addr = LocalAddress->Ipv4.sin_addr;
}
- WSAMhdr.Control.len += WSA_CMSG_SPACE(sizeof(INT));
- CMsg = WSA_CMSG_NXTHDR(&WSAMhdr, CMsg);
- CXPLAT_DBG_ASSERT(CMsg != NULL);
- CMsg->cmsg_level = IPPROTO_IP;
- CMsg->cmsg_type = IP_ECN;
- CMsg->cmsg_len = WSA_CMSG_LEN(sizeof(INT));
- *(PINT)WSA_CMSG_DATA(CMsg) = SendData->ECN;
-
if (Socket->Datapath->Features & CXPLAT_DATAPATH_FEATURE_SEND_DSCP) {
- WSAMhdr.Control.len += WSA_CMSG_SPACE(sizeof(INT));
- CMsg = WSA_CMSG_NXTHDR(&WSAMhdr, CMsg);
- CXPLAT_DBG_ASSERT(CMsg != NULL);
- CMsg->cmsg_level = IPPROTO_IP;
- CMsg->cmsg_type = IP_TOS;
- CMsg->cmsg_len = WSA_CMSG_LEN(sizeof(INT));
- *(PINT)WSA_CMSG_DATA(CMsg) = SendData->ECN | (SendData->DSCP << 2);
+ if (SendData->ECN != CXPLAT_ECN_NON_ECT || SendData->DSCP != CXPLAT_DSCP_CS0) {
+ WSAMhdr.Control.len += WSA_CMSG_SPACE(sizeof(INT));
+ CMsg = WSA_CMSG_NXTHDR(&WSAMhdr, CMsg);
+ CXPLAT_DBG_ASSERT(CMsg != NULL);
+ CMsg->cmsg_level = IPPROTO_IP;
+ CMsg->cmsg_type = IP_TOS;
+ CMsg->cmsg_len = WSA_CMSG_LEN(sizeof(INT));
+ *(PINT)WSA_CMSG_DATA(CMsg) = SendData->ECN | (SendData->DSCP << 2);
+ }
+ } else {
+ if (SendData->ECN != CXPLAT_ECN_NON_ECT) {
+ WSAMhdr.Control.len += WSA_CMSG_SPACE(sizeof(INT));
+ CMsg = WSA_CMSG_NXTHDR(&WSAMhdr, CMsg);
+ CXPLAT_DBG_ASSERT(CMsg != NULL);
+ CMsg->cmsg_level = IPPROTO_IP;
+ CMsg->cmsg_type = IP_ECN;
+ CMsg->cmsg_len = WSA_CMSG_LEN(sizeof(INT));
+ *(PINT)WSA_CMSG_DATA(CMsg) = SendData->ECN;
+ }
}
} else {
From ac7b03eafde326ee4fec79b107b841e6c42f2d74 Mon Sep 17 00:00:00 2001
From: Anthony Rossi <41394064+anrossi@users.noreply.github.com>
Date: Tue, 4 Feb 2025 21:40:29 -0800
Subject: [PATCH 11/13] Also only set ECN/DSCP when they are non-default for
IPv6. Fix test failure.
---
src/platform/datapath_winuser.c | 41 +++++++++++++++++++++------------
1 file changed, 26 insertions(+), 15 deletions(-)
diff --git a/src/platform/datapath_winuser.c b/src/platform/datapath_winuser.c
index 8a292a6c96..f857e43e71 100644
--- a/src/platform/datapath_winuser.c
+++ b/src/platform/datapath_winuser.c
@@ -4554,22 +4554,26 @@ CxPlatSocketSendInline(
PktInfo6->ipi6_addr = LocalAddress->Ipv6.sin6_addr;
}
- WSAMhdr.Control.len += WSA_CMSG_SPACE(sizeof(INT));
- CMsg = WSA_CMSG_NXTHDR(&WSAMhdr, CMsg);
- CXPLAT_DBG_ASSERT(CMsg != NULL);
- CMsg->cmsg_level = IPPROTO_IPV6;
- CMsg->cmsg_type = IPV6_ECN;
- CMsg->cmsg_len = WSA_CMSG_LEN(sizeof(INT));
- *(PINT)WSA_CMSG_DATA(CMsg) = SendData->ECN;
-
if (Socket->Datapath->Features & CXPLAT_DATAPATH_FEATURE_SEND_DSCP) {
- WSAMhdr.Control.len += WSA_CMSG_SPACE(sizeof(INT));
- CMsg = WSA_CMSG_NXTHDR(&WSAMhdr, CMsg);
- CXPLAT_DBG_ASSERT(CMsg != NULL);
- CMsg->cmsg_level = IPPROTO_IPV6;
- CMsg->cmsg_type = IPV6_TCLASS;
- CMsg->cmsg_len = WSA_CMSG_LEN(sizeof(INT));
- *(PINT)WSA_CMSG_DATA(CMsg) = SendData->ECN | (SendData->DSCP << 2);
+ if (SendData->ECN != CXPLAT_ECN_NON_ECT || SendData->DSCP != CXPLAT_DSCP_CS0) {
+ WSAMhdr.Control.len += WSA_CMSG_SPACE(sizeof(INT));
+ CMsg = WSA_CMSG_NXTHDR(&WSAMhdr, CMsg);
+ CXPLAT_DBG_ASSERT(CMsg != NULL);
+ CMsg->cmsg_level = IPPROTO_IPV6;
+ CMsg->cmsg_type = IPV6_TCLASS;
+ CMsg->cmsg_len = WSA_CMSG_LEN(sizeof(INT));
+ *(PINT)WSA_CMSG_DATA(CMsg) = SendData->ECN | (SendData->DSCP << 2);
+ }
+ } else {
+ if (SendData->ECN != CXPLAT_ECN_NON_ECT) {
+ WSAMhdr.Control.len += WSA_CMSG_SPACE(sizeof(INT));
+ CMsg = WSA_CMSG_NXTHDR(&WSAMhdr, CMsg);
+ CXPLAT_DBG_ASSERT(CMsg != NULL);
+ CMsg->cmsg_level = IPPROTO_IPV6;
+ CMsg->cmsg_type = IPV6_ECN;
+ CMsg->cmsg_len = WSA_CMSG_LEN(sizeof(INT));
+ *(PINT)WSA_CMSG_DATA(CMsg) = SendData->ECN;
+ }
}
}
@@ -4583,6 +4587,13 @@ CxPlatSocketSendInline(
*(PDWORD)WSA_CMSG_DATA(CMsg) = SendData->SegmentSize;
}
+ //
+ // Windows' networking stack doesn't like a non-NULL Control.buf when len is 0.
+ //
+ if (WSAMhdr.Control.len == 0) {
+ WSAMhdr.Control.buf = NULL;
+ }
+
if (Socket->Type == CXPLAT_SOCKET_UDP && Socket->UseRio) {
CxPlatSocketSendWithRio(SendData, &WSAMhdr);
return;
From 2106861a0787e6b70f24253cd4bcc4361a79d60d Mon Sep 17 00:00:00 2001
From: Anthony Rossi <41394064+anrossi@users.noreply.github.com>
Date: Wed, 5 Feb 2025 10:49:47 -0800
Subject: [PATCH 12/13] Update Rust FFI
---
src/ffi/win_bindings.rs | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/ffi/win_bindings.rs b/src/ffi/win_bindings.rs
index d6ac54efcb..94db1d63c6 100644
--- a/src/ffi/win_bindings.rs
+++ b/src/ffi/win_bindings.rs
@@ -193,6 +193,7 @@ pub const QUIC_PARAM_CONN_TLS_SECRETS: u32 = 83886099;
pub const QUIC_PARAM_CONN_STATISTICS_V2: u32 = 83886102;
pub const QUIC_PARAM_CONN_STATISTICS_V2_PLAT: u32 = 83886103;
pub const QUIC_PARAM_CONN_ORIG_DEST_CID: u32 = 83886104;
+pub const QUIC_PARAM_CONN_SEND_DSCP: u32 = 83886105;
pub const QUIC_PARAM_TLS_HANDSHAKE_INFO: u32 = 100663296;
pub const QUIC_PARAM_TLS_NEGOTIATED_ALPN: u32 = 100663297;
pub const QUIC_PARAM_TLS_SCHANNEL_CONTEXT_ATTRIBUTE_W: u32 = 117440512;
From 4d0a580b4ae191e66a9aadbae078de26a0753a89 Mon Sep 17 00:00:00 2001
From: Anthony Rossi <41394064+anrossi@users.noreply.github.com>
Date: Wed, 5 Feb 2025 10:54:18 -0800
Subject: [PATCH 13/13] Update Linux Rust FFI
---
src/ffi/linux_bindings.rs | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/ffi/linux_bindings.rs b/src/ffi/linux_bindings.rs
index bca39d7655..35b5a86a8e 100644
--- a/src/ffi/linux_bindings.rs
+++ b/src/ffi/linux_bindings.rs
@@ -199,6 +199,7 @@ pub const QUIC_PARAM_CONN_TLS_SECRETS: u32 = 83886099;
pub const QUIC_PARAM_CONN_STATISTICS_V2: u32 = 83886102;
pub const QUIC_PARAM_CONN_STATISTICS_V2_PLAT: u32 = 83886103;
pub const QUIC_PARAM_CONN_ORIG_DEST_CID: u32 = 83886104;
+pub const QUIC_PARAM_CONN_SEND_DSCP: u32 = 83886105;
pub const QUIC_PARAM_TLS_HANDSHAKE_INFO: u32 = 100663296;
pub const QUIC_PARAM_TLS_NEGOTIATED_ALPN: u32 = 100663297;
pub const QUIC_PARAM_STREAM_ID: u32 = 134217728;