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;