diff --git a/.github/workflows/netperf.yml b/.github/workflows/netperf.yml index fa8d19c7a0..c9fa0608ae 100644 --- a/.github/workflows/netperf.yml +++ b/.github/workflows/netperf.yml @@ -53,7 +53,7 @@ jobs: runs-on: windows-latest steps: - name: Run NetPerf Workflow - timeout-minutes: 90 + timeout-minutes: 120 shell: pwsh run: | $url = "https://raw.githubusercontent.com/microsoft/netperf/main/run-workflow.ps1" diff --git a/src/core/connection.c b/src/core/connection.c index adb3f66697..3dc7b4145f 100644 --- a/src/core/connection.c +++ b/src/core/connection.c @@ -5638,6 +5638,9 @@ QuicConnRecvDatagrams( if (!IsDeferred) { Connection->Stats.Recv.TotalBytes += Packet->BufferLength; + if (Connection->Stats.Handshake.HandshakeHopLimitTTL == 0) { + Connection->Stats.Handshake.HandshakeHopLimitTTL = Packet->HopLimitTTL; + } QuicConnLogInFlowStats(Connection); if (!CurrentPath->IsPeerValidated) { @@ -6823,6 +6826,10 @@ QuicConnGetV2Statistics( Stats->SendEcnCongestionCount = Connection->Stats.Send.EcnCongestionCount; } + if (STATISTICS_HAS_FIELD(*StatsLength, HandshakeHopLimitTTL)) { + Stats->HandshakeHopLimitTTL = Connection->Stats.Handshake.HandshakeHopLimitTTL; + } + *StatsLength = CXPLAT_MIN(*StatsLength, sizeof(QUIC_STATISTICS_V2)); return QUIC_STATUS_SUCCESS; diff --git a/src/core/connection.h b/src/core/connection.h index bfff21972a..5a88b33dc9 100644 --- a/src/core/connection.h +++ b/src/core/connection.h @@ -275,6 +275,7 @@ typedef struct QUIC_CONN_STATS { uint32_t ClientFlight1Bytes; // Sum of TLS payloads uint32_t ServerFlight1Bytes; // Sum of TLS payloads uint32_t ClientFlight2Bytes; // Sum of TLS payloads + uint8_t HandshakeHopLimitTTL; // TTL value in the initial packet of the handshake. } Handshake; struct { diff --git a/src/inc/msquic.h b/src/inc/msquic.h index 5582f83c2e..f360bbb84e 100644 --- a/src/inc/msquic.h +++ b/src/inc/msquic.h @@ -556,6 +556,8 @@ typedef struct QUIC_STATISTICS_V2 { uint32_t SendEcnCongestionCount; // Number of congestion events caused by ECN. + uint8_t HandshakeHopLimitTTL; // The TTL value in the initial packet of the handshake. + // N.B. New fields must be appended to end } QUIC_STATISTICS_V2; diff --git a/src/inc/quic_datapath.h b/src/inc/quic_datapath.h index a5dd6a335c..9975f762a1 100644 --- a/src/inc/quic_datapath.h +++ b/src/inc/quic_datapath.h @@ -222,6 +222,11 @@ typedef struct CXPLAT_RECV_DATA { // uint8_t TypeOfService; + // + // TTL Hoplimit field of the IP header of the received packet on handshake. + // + uint8_t HopLimitTTL; + // // Flags. // @@ -438,6 +443,7 @@ CxPlatDataPathUpdateConfig( #define CXPLAT_DATAPATH_FEATURE_PORT_RESERVATIONS 0x0010 #define CXPLAT_DATAPATH_FEATURE_TCP 0x0020 #define CXPLAT_DATAPATH_FEATURE_RAW 0x0040 +#define CXPLAT_DATAPATH_FEATURE_TTL 0x0080 // // Queries the currently supported features of the datapath. diff --git a/src/platform/datapath_epoll.c b/src/platform/datapath_epoll.c index 08522c952f..f206e561da 100644 --- a/src/platform/datapath_epoll.c +++ b/src/platform/datapath_epoll.c @@ -199,8 +199,9 @@ typedef struct CXPLAT_SEND_DATA { } CXPLAT_SEND_DATA; typedef struct CXPLAT_RECV_MSG_CONTROL_BUFFER { - char Data[CMSG_SPACE(sizeof(struct in6_pktinfo)) + - 2 * CMSG_SPACE(sizeof(int))]; + char Data[CMSG_SPACE(sizeof(struct in6_pktinfo)) + // IP_PKTINFO + 2 * CMSG_SPACE(sizeof(int)) // TOS + + CMSG_SPACE(sizeof(int))]; // IP_TTL } CXPLAT_RECV_MSG_CONTROL_BUFFER; #ifdef DEBUG @@ -344,6 +345,10 @@ CxPlatDataPathCalculateFeatureSupport( } Datapath->Features |= CXPLAT_DATAPATH_FEATURE_TCP; + // + // TTL should always be available / enabled on Linux. + // + Datapath->Features |= CXPLAT_DATAPATH_FEATURE_TTL; } void @@ -853,6 +858,52 @@ CxPlatSocketContextInitialize( goto Exit; } + // + // TTL should always be available / enabled on Linux. + // + + // + // On Linux, IP_HOPLIMIT does not exist. So we will use IP_RECVTTL, IPV6_RECVHOPLIMIT instead. + // + Option = TRUE; + Result = + setsockopt( + SocketContext->SocketFd, + IPPROTO_IP, + IP_RECVTTL, + (const void*)&Option, + sizeof(Option)); + if (Result == SOCKET_ERROR) { + Status = errno; + QuicTraceEvent( + DatapathErrorStatus, + "[data][%p] ERROR, %u, %s.", + Binding, + Status, + "setsockopt(IP_RECVTTL) failed"); + goto Exit; + } + + Option = TRUE; + Result = + setsockopt( + SocketContext->SocketFd, + IPPROTO_IPV6, + IPV6_RECVHOPLIMIT, + (const void*)&Option, + sizeof(Option)); + if (Result == SOCKET_ERROR) { + Status = errno; + QuicTraceEvent( + DatapathErrorStatus, + "[data][%p] ERROR, %u, %s.", + Binding, + Status, + "setsockopt(IPV6_RECVHOPLIMIT) failed"); + goto Exit; + } + + #ifdef UDP_GRO if (SocketContext->DatapathPartition->Datapath->Features & CXPLAT_DATAPATH_FEATURE_RECV_COALESCING) { Option = TRUE; @@ -1782,8 +1833,9 @@ CxPlatSocketContextRecvComplete( BytesTransferred += RecvMsgHdr[CurrentMessage].msg_len; uint8_t TOS = 0; + int HopLimitTTL = 0; uint16_t SegmentLength = 0; - BOOLEAN FoundLocalAddr = FALSE, FoundTOS = FALSE; + BOOLEAN FoundLocalAddr = FALSE, FoundTOS = FALSE, FoundTTL = FALSE; QUIC_ADDR* LocalAddr = &IoBlock->Route.LocalAddress; QUIC_ADDR* RemoteAddr = &IoBlock->Route.RemoteAddress; CxPlatConvertFromMappedV6(RemoteAddr, RemoteAddr); @@ -1808,6 +1860,11 @@ CxPlatSocketContextRecvComplete( CXPLAT_DBG_ASSERT_CMSG(CMsg, uint8_t); TOS = *(uint8_t*)CMSG_DATA(CMsg); FoundTOS = TRUE; + } else if (CMsg->cmsg_type == IPV6_HOPLIMIT) { + HopLimitTTL = *CMSG_DATA(CMsg); + CXPLAT_DBG_ASSERT(HopLimitTTL < 256); + CXPLAT_DBG_ASSERT(HopLimitTTL > 0); + FoundTTL = TRUE; } else { CXPLAT_DBG_ASSERT(FALSE); } @@ -1816,6 +1873,11 @@ CxPlatSocketContextRecvComplete( CXPLAT_DBG_ASSERT_CMSG(CMsg, uint8_t); TOS = *(uint8_t*)CMSG_DATA(CMsg); FoundTOS = TRUE; + } else if (CMsg->cmsg_type == IP_TTL) { + HopLimitTTL = *CMSG_DATA(CMsg); + CXPLAT_DBG_ASSERT(HopLimitTTL < 256); + CXPLAT_DBG_ASSERT(HopLimitTTL > 0); + FoundTTL = TRUE; } else { CXPLAT_DBG_ASSERT(FALSE); } @@ -1833,6 +1895,10 @@ CxPlatSocketContextRecvComplete( CXPLAT_FRE_ASSERT(FoundLocalAddr); CXPLAT_FRE_ASSERT(FoundTOS); + // + // TTL should always be available/enabled on Linux. + // + CXPLAT_FRE_ASSERT(FoundTTL); QuicTraceEvent( DatapathRecv, @@ -1872,6 +1938,7 @@ CxPlatSocketContextRecvComplete( } RecvData->PartitionIndex = SocketContext->DatapathPartition->PartitionIndex; RecvData->TypeOfService = TOS; + RecvData->HopLimitTTL = (uint8_t)HopLimitTTL; RecvData->Allocated = TRUE; RecvData->Route->DatapathType = RecvData->DatapathType = CXPLAT_DATAPATH_TYPE_USER; RecvData->QueuedOnConnection = FALSE; diff --git a/src/platform/datapath_kqueue.c b/src/platform/datapath_kqueue.c index 12aabccb68..329a5f9705 100644 --- a/src/platform/datapath_kqueue.c +++ b/src/platform/datapath_kqueue.c @@ -577,6 +577,9 @@ CxPlatDataPathGetSupportedFeatures( _In_ CXPLAT_DATAPATH* Datapath ) { + // + // Intentionally not enabling Feature_TTL on MacOS for now. + // return Datapath->Features; } @@ -1127,6 +1130,7 @@ CxPlatSocketContextRecvComplete( RecvPacket->Route->Queue = SocketContext; RecvPacket->TypeOfService = 0; + RecvPacket->HopLimitTTL = 0; // TODO: We are not supporting this on MacOS (yet) unless there's a business need. struct cmsghdr *CMsg; for (CMsg = CMSG_FIRSTHDR(&SocketContext->RecvMsgHdr); diff --git a/src/platform/datapath_raw.c b/src/platform/datapath_raw.c index f9b827eafd..2aeb6cdb60 100644 --- a/src/platform/datapath_raw.c +++ b/src/platform/datapath_raw.c @@ -150,7 +150,10 @@ RawDataPathGetSupportedFeatures( ) { UNREFERENCED_PARAMETER(Datapath); - return CXPLAT_DATAPATH_FEATURE_RAW; + // + // TTL should always be available / enabled for XDP. + // + return CXPLAT_DATAPATH_FEATURE_RAW | CXPLAT_DATAPATH_FEATURE_TTL; } _IRQL_requires_max_(DISPATCH_LEVEL) diff --git a/src/platform/datapath_raw_socket.c b/src/platform/datapath_raw_socket.c index e0a31c07da..9368a7bcd0 100644 --- a/src/platform/datapath_raw_socket.c +++ b/src/platform/datapath_raw_socket.c @@ -298,6 +298,7 @@ CxPlatDpRawParseIPv4( } Packet->TypeOfService = IP->EcnField; + Packet->HopLimitTTL = IP->TimeToLive; Packet->Route->RemoteAddress.Ipv4.sin_family = AF_INET; CxPlatCopyMemory(&Packet->Route->RemoteAddress.Ipv4.sin_addr, IP->Source, sizeof(IP->Source)); Packet->Route->LocalAddress.Ipv4.sin_family = AF_INET; @@ -366,6 +367,7 @@ CxPlatDpRawParseIPv6( VersionClassEcnFlow.Value = CxPlatByteSwapUint32(IP->VersionClassEcnFlow); Packet->TypeOfService = (uint8_t)VersionClassEcnFlow.EcnField; + Packet->HopLimitTTL = IP->HopLimit; Packet->Route->RemoteAddress.Ipv6.sin6_family = AF_INET6; CxPlatCopyMemory(&Packet->Route->RemoteAddress.Ipv6.sin6_addr, IP->Source, sizeof(IP->Source)); Packet->Route->LocalAddress.Ipv6.sin6_family = AF_INET6; diff --git a/src/platform/datapath_winkernel.c b/src/platform/datapath_winkernel.c index 111b72890e..9099615389 100644 --- a/src/platform/datapath_winkernel.c +++ b/src/platform/datapath_winkernel.c @@ -10,6 +10,7 @@ --*/ #include "platform_internal.h" + #ifdef QUIC_CLOG #include "datapath_winkernel.c.clog.h" #endif @@ -765,6 +766,25 @@ CxPlatDataPathQuerySockoptSupport( } while (FALSE); + do { + RTL_OSVERSIONINFOW osInfo; + RtlZeroMemory(&osInfo, sizeof(osInfo)); + osInfo.dwOSVersionInfoSize = sizeof(osInfo); + NTSTATUS status = RtlGetVersion(&osInfo); + if (NT_SUCCESS(status)) { + DWORD BuildNumber = osInfo.dwBuildNumber; + // + // Some USO/URO bug blocks TTL feature support on Windows Server 2022. + // + if (BuildNumber == 20348) { + break; + } + } else { + break; + } + Datapath->Features |= CXPLAT_DATAPATH_FEATURE_TTL; + } while (FALSE); + Error: if (UdpSocket != NULL) { @@ -1672,6 +1692,46 @@ CxPlatSocketCreateUdp( goto Error; } + if (Datapath->Features & CXPLAT_DATAPATH_FEATURE_TTL) { + Option = TRUE; + Status = + CxPlatDataPathSetControlSocket( + Binding, + WskSetOption, + IP_HOPLIMIT, + IPPROTO_IP, + sizeof(Option), + &Option); + if (QUIC_FAILED(Status)) { + QuicTraceEvent( + DatapathErrorStatus, + "[data][%p] ERROR, %u, %s.", + Binding, + Status, + "Set IP_HOPLIMIT"); + goto Error; + } + + Option = TRUE; + Status = + CxPlatDataPathSetControlSocket( + Binding, + WskSetOption, + IPV6_HOPLIMIT, + IPPROTO_IPV6, + sizeof(Option), + &Option); + if (QUIC_FAILED(Status)) { + QuicTraceEvent( + DatapathErrorStatus, + "[data][%p] ERROR, %u, %s.", + Binding, + Status, + "Set IPV6_HOPLIMIT"); + goto Error; + } + } + if (Datapath->Features & CXPLAT_DATAPATH_FEATURE_RECV_COALESCING) { Option = MAX_URO_PAYLOAD_LENGTH; Status = @@ -2200,6 +2260,7 @@ CxPlatDataPathSocketReceive( SOCKADDR_INET RemoteAddr; UINT16 MessageLength = 0; INT ECN = 0; + INT HopLimitTTL = 0; // // Parse the ancillary data for all the per datagram information that we @@ -2231,6 +2292,10 @@ CxPlatDataPathSocketReceive( } 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); + CXPLAT_DBG_ASSERT(HopLimitTTL > 0); } } else if (CMsg->cmsg_level == IPPROTO_IP) { if (CMsg->cmsg_type == IP_PKTINFO) { @@ -2250,6 +2315,10 @@ CxPlatDataPathSocketReceive( } 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); + CXPLAT_DBG_ASSERT(HopLimitTTL > 0); } } else if (CMsg->cmsg_level == IPPROTO_UDP) { if (CMsg->cmsg_type == UDP_COALESCED_INFO) { @@ -2416,6 +2485,7 @@ CxPlatDataPathSocketReceive( Datagram->Data.Next = NULL; Datagram->Data.PartitionIndex = (uint16_t)(CurProcNumber % Binding->Datapath->ProcCount); Datagram->Data.TypeOfService = (uint8_t)ECN; + 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 bfaafb947d..be8f1f84a4 100644 --- a/src/platform/datapath_winuser.c +++ b/src/platform/datapath_winuser.c @@ -153,7 +153,8 @@ 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_ECN + WSA_CMSG_SPACE(sizeof(INT)) // IP_HOP_LIMIT ]; } DATAPATH_RX_IO_BLOCK; @@ -558,6 +559,12 @@ CxPlatDataPathQueryRssScalabilityInfo( } } +// +// To determine the OS version, we are going to use RtlGetVersion API +// since GetVersion call can be shimmed on Win8.1+. +// +typedef LONG (WINAPI *FuncRtlGetVersion)(RTL_OSVERSIONINFOW *); + QUIC_STATUS CxPlatDataPathQuerySockoptSupport( _Inout_ CXPLAT_DATAPATH* Datapath @@ -734,6 +741,28 @@ CxPlatDataPathQuerySockoptSupport( Datapath->Features |= CXPLAT_DATAPATH_FEATURE_RECV_COALESCING; } } + // + // TODO: This "TTL_FEATURE check" code works, and mirrors the approach for Kernel mode. + // However, it is considered a "hack" and we should determine whether or not + // the current release story fits this current workaround. + // + HMODULE NtDllHandle = LoadLibraryA("ntdll.dll"); + if (NtDllHandle) { + FuncRtlGetVersion VersionFunc = (FuncRtlGetVersion)GetProcAddress(NtDllHandle, "RtlGetVersion"); + if (VersionFunc) { + RTL_OSVERSIONINFOW VersionInfo = {0}; + VersionInfo.dwOSVersionInfoSize = sizeof(VersionInfo); + if ((*VersionFunc)(&VersionInfo) == 0) { + // + // Some USO/URO bug blocks TTL feature support on Windows Server 2022. + // + if (VersionInfo.dwBuildNumber != 20348) { + Datapath->Features |= CXPLAT_DATAPATH_FEATURE_TTL; + } + } + } + FreeLibrary(NtDllHandle); + } Datapath->Features |= CXPLAT_DATAPATH_FEATURE_TCP; @@ -746,12 +775,6 @@ CxPlatDataPathQuerySockoptSupport( return Status; } -// -// To determine the OS version, we are going to use RtlGetVersion API -// since GetVersion call can be shimmed on Win8.1+. -// -typedef LONG (WINAPI *FuncRtlGetVersion)(RTL_OSVERSIONINFOW *); - _IRQL_requires_max_(PASSIVE_LEVEL) QUIC_STATUS DataPathInitialize( @@ -1403,6 +1426,48 @@ SocketCreateUdp( goto Error; } + if (Datapath->Features & CXPLAT_DATAPATH_FEATURE_TTL) { + Option = TRUE; + Result = + setsockopt( + SocketProc->Socket, + IPPROTO_IP, + IP_HOPLIMIT, + (char*)&Option, + sizeof(Option)); + if (Result == SOCKET_ERROR) { + int WsaError = WSAGetLastError(); + QuicTraceEvent( + DatapathErrorStatus, + "[data][%p] ERROR, %u, %s.", + Socket, + WsaError, + "Set IP_HOPLIMIT"); + Status = HRESULT_FROM_WIN32(WsaError); + goto Error; + } + + Option = TRUE; + Result = + setsockopt( + SocketProc->Socket, + IPPROTO_IPV6, + IPV6_HOPLIMIT, + (char*)&Option, + sizeof(Option)); + if (Result == SOCKET_ERROR) { + int WsaError = WSAGetLastError(); + QuicTraceEvent( + DatapathErrorStatus, + "[data][%p] ERROR, %u, %s.", + Socket, + WsaError, + "Set IPV6_HOPLIMIT"); + Status = HRESULT_FROM_WIN32(WsaError); + goto Error; + } + } + // // The socket is shared by multiple endpoints, so increase the receive // buffer size. @@ -3103,7 +3168,7 @@ CxPlatDataPathUdpRecvComplete( ULONG MessageCount = 0; BOOLEAN IsCoalesced = FALSE; INT ECN = 0; - + INT HopLimitTTL = 0; if (SocketProc->Parent->UseRio) { PRIO_CMSG_BUFFER RioRcvMsg = (PRIO_CMSG_BUFFER)IoBlock->ControlBuf; IoBlock->WsaMsgHdr.Control.buf = IoBlock->ControlBuf + RIO_CMSG_BASE_SIZE; @@ -3126,6 +3191,10 @@ CxPlatDataPathUdpRecvComplete( } 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); + CXPLAT_DBG_ASSERT(HopLimitTTL > 0); } } else if (CMsg->cmsg_level == IPPROTO_IP) { if (CMsg->cmsg_type == IP_PKTINFO) { @@ -3138,6 +3207,10 @@ CxPlatDataPathUdpRecvComplete( } 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); + CXPLAT_DBG_ASSERT(HopLimitTTL > 0); } } else if (CMsg->cmsg_level == IPPROTO_UDP) { if (CMsg->cmsg_type == UDP_COALESCED_INFO) { @@ -3195,6 +3268,7 @@ CxPlatDataPathUdpRecvComplete( Datagram->PartitionIndex = SocketProc->DatapathProc->PartitionIndex % SocketProc->DatapathProc->Datapath->PartitionCount; Datagram->TypeOfService = (uint8_t)ECN; + Datagram->HopLimitTTL = (uint8_t) HopLimitTTL; Datagram->Allocated = TRUE; Datagram->Route->DatapathType = Datagram->DatapathType = CXPLAT_DATAPATH_TYPE_USER; Datagram->QueuedOnConnection = FALSE; diff --git a/src/platform/unittest/DataPathTest.cpp b/src/platform/unittest/DataPathTest.cpp index 33906ba672..f64d11e0c5 100644 --- a/src/platform/unittest/DataPathTest.cpp +++ b/src/platform/unittest/DataPathTest.cpp @@ -86,6 +86,7 @@ struct UdpRecvContext { QUIC_ADDR DestinationAddress; CXPLAT_EVENT ClientCompletion; CXPLAT_ECN_TYPE EcnType {CXPLAT_ECN_NON_ECT}; + bool TtlSupported; UdpRecvContext() { CxPlatEventInitialize(&ClientCompletion, FALSE, FALSE); } @@ -286,13 +287,18 @@ struct DataPathTest : public ::testing::TestWithParam { UdpRecvContext* RecvContext = (UdpRecvContext*)Context; ASSERT_NE(nullptr, RecvContext); - CXPLAT_RECV_DATA* RecvData = RecvDataChain; while (RecvData != NULL) { ASSERT_EQ(RecvData->BufferLength, ExpectedDataSize); ASSERT_EQ(0, memcmp(RecvData->Buffer, ExpectedData, ExpectedDataSize)); + if (RecvContext->TtlSupported) { + ASSERT_TRUE(RecvData->HopLimitTTL > 0); + } else { + ASSERT_EQ(0, RecvData->HopLimitTTL); + } + if (RecvData->Route->LocalAddress.Ipv4.sin_port == RecvContext->DestinationAddress.Ipv4.sin_port) { ASSERT_EQ((CXPLAT_ECN_TYPE)RecvData->TypeOfService, RecvContext->EcnType); @@ -775,6 +781,7 @@ TEST_P(DataPathTest, UdpData) { UdpRecvContext RecvContext; CxPlatDataPath Datapath(&UdpRecvCallbacks); + RecvContext.TtlSupported = Datapath.IsSupported(CXPLAT_DATAPATH_FEATURE_TTL); VERIFY_QUIC_SUCCESS(Datapath.GetInitStatus()); ASSERT_NE(nullptr, Datapath.Datapath); @@ -812,6 +819,7 @@ TEST_P(DataPathTest, UdpDataPolling) QUIC_EXECUTION_CONFIG Config = { QUIC_EXECUTION_CONFIG_FLAG_NONE, UINT32_MAX, 0 }; UdpRecvContext RecvContext; CxPlatDataPath Datapath(&UdpRecvCallbacks, nullptr, 0, &Config); + RecvContext.TtlSupported = Datapath.IsSupported(CXPLAT_DATAPATH_FEATURE_TTL); VERIFY_QUIC_SUCCESS(Datapath.GetInitStatus()); ASSERT_NE(nullptr, Datapath.Datapath); @@ -848,6 +856,7 @@ TEST_P(DataPathTest, UdpDataRebind) { UdpRecvContext RecvContext; CxPlatDataPath Datapath(&UdpRecvCallbacks); + RecvContext.TtlSupported = Datapath.IsSupported(CXPLAT_DATAPATH_FEATURE_TTL); VERIFY_QUIC_SUCCESS(Datapath.GetInitStatus()); ASSERT_NE(nullptr, Datapath.Datapath); @@ -904,6 +913,7 @@ TEST_P(DataPathTest, UdpDataECT0) UdpRecvContext RecvContext; RecvContext.EcnType = CXPLAT_ECN_ECT_0; CxPlatDataPath Datapath(&UdpRecvCallbacks); + RecvContext.TtlSupported = Datapath.IsSupported(CXPLAT_DATAPATH_FEATURE_TTL); VERIFY_QUIC_SUCCESS(Datapath.GetInitStatus()); ASSERT_NE(nullptr, Datapath.Datapath); @@ -940,6 +950,7 @@ TEST_P(DataPathTest, UdpShareClientSocket) { UdpRecvContext RecvContext; CxPlatDataPath Datapath(&UdpRecvCallbacks); + RecvContext.TtlSupported = Datapath.IsSupported(CXPLAT_DATAPATH_FEATURE_TTL); VERIFY_QUIC_SUCCESS(Datapath.GetInitStatus()); ASSERT_NE(nullptr, Datapath.Datapath); // TODO: Linux XDP (duonic) to support port sharing @@ -1001,6 +1012,7 @@ TEST_P(DataPathTest, UdpShareClientSocket) TEST_P(DataPathTest, MultiBindListener) { UdpRecvContext RecvContext; CxPlatDataPath Datapath(&UdpRecvCallbacks); + RecvContext.TtlSupported = Datapath.IsSupported(CXPLAT_DATAPATH_FEATURE_TTL); if (!(Datapath.GetSupportedFeatures() & CXPLAT_DATAPATH_FEATURE_PORT_RESERVATIONS)) { std::cout << "SKIP: Port Reservations Feature Unsupported" << std::endl; return; @@ -1022,6 +1034,7 @@ TEST_P(DataPathTest, MultiBindListenerSingleProcessor) { UdpRecvContext RecvContext; 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); auto ServerAddress = GetNewLocalAddr(); CxPlatSocket Server1(Datapath, &ServerAddress.SockAddr, nullptr, &RecvContext); diff --git a/src/test/lib/HandshakeTest.cpp b/src/test/lib/HandshakeTest.cpp index 71cddd74c5..edb6e714d8 100644 --- a/src/test/lib/HandshakeTest.cpp +++ b/src/test/lib/HandshakeTest.cpp @@ -317,6 +317,13 @@ QuicTestConnect( } TEST_TRUE(Client.GetIsConnected()); + // After handshake, check and see if we have cached the TTL of the handshake packet. + if (QuitTestIsFeatureSupported(CXPLAT_DATAPATH_FEATURE_TTL)) { + TEST_TRUE(Client.GetStatistics().HandshakeHopLimitTTL > 0); + } else { + TEST_EQUAL(Client.GetStatistics().HandshakeHopLimitTTL, 0); + } + TEST_NOT_EQUAL(nullptr, Server); Server->SetSslKeyLogFilePath(); if (!Server->WaitForConnectionComplete()) {