diff --git a/scripts/clog.inputs b/scripts/clog.inputs index 0b3a68f323..516c9cc168 100644 --- a/scripts/clog.inputs +++ b/scripts/clog.inputs @@ -45,6 +45,8 @@ ../src/core/packet_space.c ../src/core/registration.c ../src/core/send.c +../src/core/pathid_set.c +../src/core/pathid.c ../src/core/path.c ../src/core/settings.c ../src/core/connection.c @@ -82,6 +84,7 @@ ../src/bin/static/empty.c ../src/core/operation.h ../src/core/stream.h +../src/core/pathid.h ../src/core/connection.h ../src/test/lib/TestHelpers.h ../src/test/lib/TestStream.cpp diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 2c875e9423..5f8eaf932b 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -31,6 +31,8 @@ set(SOURCES packet.c packet_builder.c packet_space.c + pathid_set.c + pathid.c path.c range.c recv_buffer.c diff --git a/src/core/ack_tracker.c b/src/core/ack_tracker.c index 5ba46d3810..58d5d1f07a 100644 --- a/src/core/ack_tracker.c +++ b/src/core/ack_tracker.c @@ -290,6 +290,7 @@ QuicAckTrackerAckFrameEncode( _Inout_ QUIC_PACKET_BUILDER* Builder ) { + QUIC_PACKET_SPACE* PacketSpace = QuicAckTrackerGetPacketSpace(Tracker); CXPLAT_DBG_ASSERT(QuicAckTrackerHasPacketsToAck(Tracker)); const uint64_t Timestamp = CxPlatTimeUs64(); @@ -310,6 +311,9 @@ QuicAckTrackerAckFrameEncode( } if (!QuicAckFrameEncode( + PacketSpace->Connection->State.MultipathNegotiated && + Builder->EncryptLevel == QUIC_ENCRYPT_LEVEL_1_RTT, + PacketSpace->PathID->ID, &Tracker->PacketNumbersToAck, AckDelay, Tracker->NonZeroRecvECN ? diff --git a/src/core/bbr.c b/src/core/bbr.c index e92b5c28c0..fb6403ab14 100644 --- a/src/core/bbr.c +++ b/src/core/bbr.c @@ -217,7 +217,7 @@ BbrCongestionControlGetCongestionWindow( ) { const QUIC_CONGESTION_CONTROL_BBR* Bbr = &Cc->Bbr; - QUIC_CONNECTION* Connection = QuicCongestionControlGetConnection(Cc); + QUIC_CONNECTION* Connection = QuicCongestionControlGetPathID(Cc)->Connection; const uint16_t DatagramPayloadLength = QuicPathGetDatagramPayloadSize(&Connection->Paths[0]); @@ -279,16 +279,16 @@ BbrCongestionControlIsAppLimited( _IRQL_requires_max_(DISPATCH_LEVEL) void QuicConnLogBbr( - _In_ QUIC_CONNECTION* const Connection + _In_ QUIC_PATHID* const PathID ) { - QUIC_CONGESTION_CONTROL* Cc = &Connection->CongestionControl; + QUIC_CONGESTION_CONTROL* Cc = &PathID->CongestionControl; QUIC_CONGESTION_CONTROL_BBR* Bbr = &Cc->Bbr; QuicTraceEvent( ConnBbr, "[conn][%p] BBR: State=%u RState=%u CongestionWindow=%u BytesInFlight=%u BytesInFlightMax=%u MinRttEst=%lu EstBw=%lu AppLimited=%u", - Connection, + PathID->Connection, Bbr->BbrState, Bbr->RecoveryState, BbrCongestionControlGetCongestionWindow(Cc), @@ -307,7 +307,8 @@ BbrCongestionControlIndicateConnectionEvent( ) { const QUIC_CONGESTION_CONTROL_BBR* Bbr = &Cc->Bbr; - const QUIC_PATH* Path = &Connection->Paths[0]; + const QUIC_PATHID* PathID = QuicCongestionControlGetPathID(Cc); + const QUIC_PATH* Path = PathID->Path; QUIC_CONNECTION_EVENT Event; Event.Type = QUIC_CONNECTION_EVENT_NETWORK_STATISTICS; Event.NETWORK_STATISTICS.BytesInFlight = Bbr->BytesInFlight; @@ -345,8 +346,9 @@ BbrCongestionControlLogOutFlowStatus( _In_ const QUIC_CONGESTION_CONTROL* Cc ) { - const QUIC_CONNECTION* Connection = QuicCongestionControlGetConnection(Cc); - const QUIC_PATH* Path = &Connection->Paths[0]; + const QUIC_PATHID* PathID = QuicCongestionControlGetPathID(Cc); + const QUIC_CONNECTION* Connection = PathID->Connection; + const QUIC_PATH* Path = PathID->Path; const QUIC_CONGESTION_CONTROL_BBR* Bbr = &Cc->Bbr; QuicTraceEvent( @@ -373,8 +375,9 @@ BbrCongestionControlUpdateBlockedState( _In_ BOOLEAN PreviousCanSendState ) { - QUIC_CONNECTION* Connection = QuicCongestionControlGetConnection(Cc); - QuicConnLogOutFlowStats(Connection); + QUIC_PATHID* PathID = QuicCongestionControlGetPathID(Cc); + QUIC_CONNECTION* Connection = PathID->Connection; + QuicConnLogOutFlowStats(PathID); if (PreviousCanSendState != BbrCongestionControlCanSend(Cc)) { if (PreviousCanSendState) { @@ -436,7 +439,7 @@ BbrCongestionControlOnDataSent( Bbr->BytesInFlight += NumRetransmittableBytes; if (Bbr->BytesInFlightMax < Bbr->BytesInFlight) { Bbr->BytesInFlightMax = Bbr->BytesInFlight; - QuicSendBufferConnectionAdjust(QuicCongestionControlGetConnection(Cc)); + QuicSendBufferConnectionAdjust(QuicCongestionControlGetPathID(Cc)->Connection); } if (Bbr->Exemptions > 0) { @@ -471,10 +474,10 @@ BbrCongestionControlUpdateRecoveryWindow( ) { QUIC_CONGESTION_CONTROL_BBR* Bbr = &Cc->Bbr; - QUIC_CONNECTION* Connection = QuicCongestionControlGetConnection(Cc); + QUIC_PATHID* PathID = QuicCongestionControlGetPathID(Cc); const uint16_t DatagramPayloadLength = - QuicPathGetDatagramPayloadSize(&Connection->Paths[0]); + QuicPathGetDatagramPayloadSize(PathID->Path); CXPLAT_DBG_ASSERT(Bbr->RecoveryState != RECOVERY_STATE_NOT_RECOVERY); @@ -500,13 +503,13 @@ BbrCongestionControlHandleAckInProbeRtt( ) { QUIC_CONGESTION_CONTROL_BBR* Bbr = &Cc->Bbr; - QUIC_CONNECTION* Connection = QuicCongestionControlGetConnection(Cc); + QUIC_PATHID* PathID = QuicCongestionControlGetPathID(Cc); Bbr->BandwidthFilter.AppLimited = TRUE; Bbr->BandwidthFilter.AppLimitedExitTarget = LargestSentPacketNumber; const uint16_t DatagramPayloadLength = - QuicPathGetDatagramPayloadSize(&Connection->Paths[0]); + QuicPathGetDatagramPayloadSize(PathID->Path); if (!Bbr->ProbeRttEndTimeValid && Bbr->BytesInFlight < BbrCongestionControlGetCongestionWindow(Cc) + DatagramPayloadLength) { @@ -608,7 +611,8 @@ BbrCongestionControlGetSendAllowance( _In_ BOOLEAN TimeSinceLastSendValid ) { - QUIC_CONNECTION* Connection = QuicCongestionControlGetConnection(Cc); + QUIC_PATHID* PathID = QuicCongestionControlGetPathID(Cc); + QUIC_CONNECTION* Connection = PathID->Connection; QUIC_CONGESTION_CONTROL_BBR* Bbr = &Cc->Bbr; uint64_t BandwidthEst = BbrCongestionControlGetBandwidth(Cc); @@ -693,7 +697,8 @@ BbrCongestionControlSetSendQuantum( ) { QUIC_CONGESTION_CONTROL_BBR *Bbr = &Cc->Bbr; - QUIC_CONNECTION* Connection = QuicCongestionControlGetConnection(Cc); + QUIC_PATHID* PathID = QuicCongestionControlGetPathID(Cc); + QUIC_CONNECTION* Connection = PathID->Connection; uint64_t Bandwidth = BbrCongestionControlGetBandwidth(Cc); @@ -720,7 +725,8 @@ BbrCongestionControlUpdateCongestionWindow( ) { QUIC_CONGESTION_CONTROL_BBR *Bbr = &Cc->Bbr; - QUIC_CONNECTION* Connection = QuicCongestionControlGetConnection(Cc); + QUIC_PATHID* PathID = QuicCongestionControlGetPathID(Cc); + QUIC_CONNECTION* Connection = PathID->Connection; if (Bbr->BbrState == BBR_STATE_PROBE_RTT) { return; @@ -751,7 +757,7 @@ BbrCongestionControlUpdateCongestionWindow( Bbr->CongestionWindow = CXPLAT_MAX(CongestionWindow, MinCongestionWindow); - QuicConnLogBbr(QuicCongestionControlGetConnection(Cc)); + QuicConnLogBbr(PathID); } _IRQL_requires_max_(DISPATCH_LEVEL) @@ -764,7 +770,8 @@ BbrCongestionControlOnDataAcknowledged( QUIC_CONGESTION_CONTROL_BBR* Bbr = &Cc->Bbr; BOOLEAN PreviousCanSendState = BbrCongestionControlCanSend(Cc); - QUIC_CONNECTION* Connection = QuicCongestionControlGetConnection(Cc); + QUIC_PATHID* PathID = QuicCongestionControlGetPathID(Cc); + QUIC_CONNECTION* Connection = PathID->Connection; if (AckEvent->IsImplicit) { BbrCongestionControlUpdateCongestionWindow( @@ -897,7 +904,8 @@ BbrCongestionControlOnDataLost( ) { QUIC_CONGESTION_CONTROL_BBR *Bbr = &Cc->Bbr; - QUIC_CONNECTION* Connection = QuicCongestionControlGetConnection(Cc); + QUIC_PATHID* PathID = QuicCongestionControlGetPathID(Cc); + QUIC_CONNECTION* Connection = PathID->Connection; const uint16_t DatagramPayloadLength = QuicPathGetDatagramPayloadSize(&Connection->Paths[0]); @@ -948,7 +956,7 @@ BbrCongestionControlOnDataLost( } BbrCongestionControlUpdateBlockedState(Cc, PreviousCanSendState); - QuicConnLogBbr(QuicCongestionControlGetConnection(Cc)); + QuicConnLogBbr(PathID); } _IRQL_requires_max_(DISPATCH_LEVEL) @@ -969,8 +977,9 @@ BbrCongestionControlSetAppLimited( { QUIC_CONGESTION_CONTROL_BBR *Bbr = &Cc->Bbr; - QUIC_CONNECTION* Connection = QuicCongestionControlGetConnection(Cc); - uint64_t LargestSentPacketNumber = Connection->LossDetection.LargestSentPacketNumber; + QUIC_PATHID* PathID = QuicCongestionControlGetPathID(Cc); + QUIC_CONNECTION* Connection = PathID->Connection; + uint64_t LargestSentPacketNumber = Connection->Paths[0].PathID->LossDetection.LargestSentPacketNumber; if (Bbr->BytesInFlight > BbrCongestionControlGetCongestionWindow(Cc)) { return; @@ -989,7 +998,8 @@ BbrCongestionControlReset( { QUIC_CONGESTION_CONTROL_BBR* Bbr = &Cc->Bbr; - QUIC_CONNECTION* Connection = QuicCongestionControlGetConnection(Cc); + QUIC_PATHID* PathID = QuicCongestionControlGetPathID(Cc); + QUIC_CONNECTION* Connection = PathID->Connection; const uint16_t DatagramPayloadLength = QuicPathGetDatagramPayloadSize(&Connection->Paths[0]); @@ -1046,7 +1056,7 @@ BbrCongestionControlReset( Bbr->BandwidthFilter.AppLimitedExitTarget = 0; BbrCongestionControlLogOutFlowStatus(Cc); - QuicConnLogBbr(Connection); + QuicConnLogBbr(PathID); } @@ -1081,7 +1091,8 @@ BbrCongestionControlInitialize( QUIC_CONGESTION_CONTROL_BBR* Bbr = &Cc->Bbr; - QUIC_CONNECTION* Connection = QuicCongestionControlGetConnection(Cc); + QUIC_PATHID* PathID = QuicCongestionControlGetPathID(Cc); + QUIC_CONNECTION* Connection = PathID->Connection; const uint16_t DatagramPayloadLength = QuicPathGetDatagramPayloadSize(&Connection->Paths[0]); @@ -1141,6 +1152,6 @@ BbrCongestionControlInitialize( .AppLimitedExitTarget = 0, }; - QuicConnLogOutFlowStats(Connection); - QuicConnLogBbr(Connection); + QuicConnLogOutFlowStats(PathID); + QuicConnLogBbr(PathID); } diff --git a/src/core/binding.c b/src/core/binding.c index 348e1228d0..01063560d9 100644 --- a/src/core/binding.c +++ b/src/core/binding.c @@ -560,46 +560,121 @@ _IRQL_requires_max_(DISPATCH_LEVEL) BOOLEAN QuicBindingAddSourceConnectionID( _In_ QUIC_BINDING* Binding, - _In_ QUIC_CID_HASH_ENTRY* SourceCid + _In_ QUIC_CID_SLIST_ENTRY* SourceCid ) { return QuicLookupAddLocalCid(&Binding->Lookup, SourceCid, NULL); } +_IRQL_requires_max_(DISPATCH_LEVEL) +BOOLEAN +QuicBindingAddAllSourceConnectionIDs( + _In_ QUIC_BINDING* Binding, + _In_ QUIC_CONNECTION* Connection + ) +{ + BOOLEAN Success = TRUE; + + QUIC_PATHID* PathIDs[QUIC_ACTIVE_PATH_ID_LIMIT]; + uint8_t PathIDCount = QUIC_ACTIVE_PATH_ID_LIMIT; + QuicPathIDSetGetPathIDs(&Connection->PathIDs, PathIDs, &PathIDCount); + + for (uint8_t i = 0; i < PathIDCount; i++) { + if (Success) { + for (CXPLAT_SLIST_ENTRY* Link = PathIDs[i]->SourceCids.Next; + Link != NULL; + Link = Link->Next) { + + QUIC_CID_SLIST_ENTRY* Entry = + CXPLAT_CONTAINING_RECORD( + Link, + QUIC_CID_SLIST_ENTRY, + Link); + if (!QuicBindingAddSourceConnectionID(Binding, Entry)) { + Success = FALSE; + break; + } + } + } + QuicPathIDRelease(PathIDs[i], QUIC_PATHID_REF_LOOKUP); + } + + return Success; +} + + _IRQL_requires_max_(DISPATCH_LEVEL) void QuicBindingRemoveSourceConnectionID( _In_ QUIC_BINDING* Binding, - _In_ QUIC_CID_HASH_ENTRY* SourceCid, - _In_ CXPLAT_SLIST_ENTRY** Entry + _In_ QUIC_CID_HASH_ENTRY* SourceCid ) { - QuicLookupRemoveLocalCid(&Binding->Lookup, SourceCid, Entry); + QuicLookupRemoveLocalCid(&Binding->Lookup, SourceCid); } _IRQL_requires_max_(DISPATCH_LEVEL) void -QuicBindingRemoveConnection( +QuicBindingRemoveAllSourceConnectionIDs( _In_ QUIC_BINDING* Binding, _In_ QUIC_CONNECTION* Connection ) { - if (Connection->RemoteHashEntry != NULL) { - QuicLookupRemoveRemoteHash(&Binding->Lookup, Connection->RemoteHashEntry); + QUIC_PATHID* PathIDs[QUIC_ACTIVE_PATH_ID_LIMIT]; + uint8_t PathIDCount = QUIC_ACTIVE_PATH_ID_LIMIT; + QuicPathIDSetGetPathIDs(&Connection->PathIDs, PathIDs, &PathIDCount); + + for (uint8_t i = 0; i < PathIDCount; i++) { + CXPLAT_SLIST_ENTRY EntriesToFree = {0}; + + for (CXPLAT_SLIST_ENTRY* Link = PathIDs[i]->SourceCids.Next; + Link != NULL; + Link = Link->Next) { + + QUIC_CID_SLIST_ENTRY* Entry = + CXPLAT_CONTAINING_RECORD( + Link, + QUIC_CID_SLIST_ENTRY, + Link); + + CXPLAT_SLIST_ENTRY** Link1 = &Entry->HashEntries.Next; + while (*Link1 != NULL) { + QUIC_CID_HASH_ENTRY* Entry1 = + CXPLAT_CONTAINING_RECORD( + *Link1, + QUIC_CID_HASH_ENTRY, + Link); + if (Entry1->Binding == Binding) { + QuicBindingRemoveSourceConnectionID(Binding, Entry1); + *Link1 = (*Link1)->Next; + CxPlatListPushEntry(&EntriesToFree, &Entry1->Link); + } else { + Link1 = &(*Link1)->Next; + } + } + } + + while (EntriesToFree.Next != NULL) { + QUIC_CID_HASH_ENTRY* Entry = + CXPLAT_CONTAINING_RECORD( + CxPlatListPopEntry(&EntriesToFree), + QUIC_CID_HASH_ENTRY, + Link); + CXPLAT_FREE(Entry, QUIC_POOL_CIDHASH); + } + + QuicPathIDRelease(PathIDs[i], QUIC_PATHID_REF_LOOKUP); } - QuicLookupRemoveLocalCids(&Binding->Lookup, Connection); } _IRQL_requires_max_(DISPATCH_LEVEL) void -QuicBindingMoveSourceConnectionIDs( - _In_ QUIC_BINDING* BindingSrc, - _In_ QUIC_BINDING* BindingDest, - _In_ QUIC_CONNECTION* Connection +QuicBindingRemoveRemoteHash( + _In_ QUIC_BINDING* Binding, + _In_ QUIC_REMOTE_HASH_ENTRY* RemoteHashEntry ) { - QuicLookupMoveLocalConnectionIDs( - &BindingSrc->Lookup, &BindingDest->Lookup, Connection); + QuicLookupRemoveRemoteHash(&Binding->Lookup, RemoteHashEntry); } _IRQL_requires_max_(DISPATCH_LEVEL) @@ -1281,11 +1356,11 @@ QuicBindingCreateConnection( } BOOLEAN BindingRefAdded = FALSE; - CXPLAT_DBG_ASSERT(NewConnection->SourceCids.Next != NULL); - QUIC_CID_HASH_ENTRY* SourceCid = + CXPLAT_DBG_ASSERT(NewConnection->Paths[0].PathID->SourceCids.Next != NULL); + QUIC_CID_SLIST_ENTRY* SourceCid = CXPLAT_CONTAINING_RECORD( - NewConnection->SourceCids.Next, - QUIC_CID_HASH_ENTRY, + NewConnection->Paths[0].PathID->SourceCids.Next, + QUIC_CID_SLIST_ENTRY, Link); QuicConnAddRef(NewConnection, QUIC_CONN_REF_LOOKUP_RESULT); @@ -1320,6 +1395,8 @@ QuicBindingCreateConnection( } goto Exit; } + CXPLAT_DBG_ASSERT(NewConnection->RemoteHashEntry != NULL); + NewConnection->RemoteHashEntry->Binding = Binding; QuicWorkerQueueConnection(NewConnection->Worker, NewConnection); @@ -1352,8 +1429,8 @@ QuicBindingCreateConnection( #pragma warning(pop) } else { - NewConnection->SourceCids.Next = NULL; - CXPLAT_FREE(SourceCid, QUIC_POOL_CIDHASH); + NewConnection->Paths[0].PathID->SourceCids.Next = NULL; + CXPLAT_FREE(SourceCid, QUIC_POOL_CIDSLIST); QuicConnRelease(NewConnection, QUIC_CONN_REF_LOOKUP_RESULT); #pragma prefast(suppress:6001, "SAL doesn't understand ref counts") QuicConnRelease(NewConnection, QUIC_CONN_REF_HANDLE_OWNER); @@ -1454,14 +1531,16 @@ QuicBindingDeliverPackets( QuicLookupFindConnectionByLocalCid( &Binding->Lookup, Packets->DestCid, - Packets->DestCidLen); + Packets->DestCidLen, + &Packets->PathId); } else { Connection = QuicLookupFindConnectionByRemoteHash( &Binding->Lookup, &Packets->Route->RemoteAddress, Packets->SourceCidLen, - Packets->SourceCid); + Packets->SourceCid, + &Packets->PathId); } if (Connection == NULL) { diff --git a/src/core/binding.h b/src/core/binding.h index bdf61c3cb6..d9ffab79fb 100644 --- a/src/core/binding.h +++ b/src/core/binding.h @@ -46,6 +46,7 @@ typedef struct QUIC_RX_PACKET { // uint64_t PacketNumber; + uint32_t PathId; // // Represents the sender side's timestamp (in us) from the start of their // epoch. @@ -373,7 +374,18 @@ _IRQL_requires_max_(DISPATCH_LEVEL) BOOLEAN QuicBindingAddSourceConnectionID( _In_ QUIC_BINDING* Binding, - _In_ QUIC_CID_HASH_ENTRY* SourceCid + _In_ QUIC_CID_SLIST_ENTRY* SourceCid + ); + +// +// Attempts to insert all the connection's new source CIDs into the binding's +// lookup table. +// +_IRQL_requires_max_(DISPATCH_LEVEL) +BOOLEAN +QuicBindingAddAllSourceConnectionIDs( + _In_ QUIC_BINDING* Binding, + _In_ QUIC_CONNECTION* Connection ); // @@ -383,30 +395,24 @@ _IRQL_requires_max_(DISPATCH_LEVEL) void QuicBindingRemoveSourceConnectionID( _In_ QUIC_BINDING* Binding, - _In_ QUIC_CID_HASH_ENTRY* SourceCid, - _In_ CXPLAT_SLIST_ENTRY** Entry + _In_ QUIC_CID_HASH_ENTRY* SourceCid ); // -// Removes all the connection's source CIDs from the binding's lookup table. +// Removes all the source CIDs from the binding's lookup table. // _IRQL_requires_max_(DISPATCH_LEVEL) void -QuicBindingRemoveConnection( +QuicBindingRemoveAllSourceConnectionIDs( _In_ QUIC_BINDING* Binding, _In_ QUIC_CONNECTION* Connection ); -// -// Moves all the connections source CIDs from the one binding's lookup table to -// another. -// _IRQL_requires_max_(DISPATCH_LEVEL) void -QuicBindingMoveSourceConnectionIDs( - _In_ QUIC_BINDING* BindingSrc, - _In_ QUIC_BINDING* BindingDest, - _In_ QUIC_CONNECTION* Connection +QuicBindingRemoveRemoteHash( + _In_ QUIC_BINDING* Binding, + _In_ QUIC_REMOTE_HASH_ENTRY* RemoteHashEntry ); // @@ -516,3 +522,16 @@ QuicRetryTokenDecrypt( CxPlatDispatchLockRelease(&MsQuicLib.StatelessRetryKeysLock); return QUIC_SUCCEEDED(Status); } + +// +// Helper to get the owning QUIC_BINDING for the lookup module. +// +inline +_Ret_notnull_ +QUIC_BINDING* +QuicLookupGetBinding( + _In_ QUIC_LOOKUP* Lookup + ) +{ + return CXPLAT_CONTAINING_RECORD(Lookup, QUIC_BINDING, Lookup); +} diff --git a/src/core/cid.h b/src/core/cid.h index 845c7a960b..557d52625e 100644 --- a/src/core/cid.h +++ b/src/core/cid.h @@ -163,12 +163,22 @@ typedef struct QUIC_CID_LIST_ENTRY { #define QUIC_CID_VALIDATE_NULL(Conn, Cid) UNREFERENCED_PARAMETER(Cid) #endif +typedef struct QUIC_CID_SLIST_ENTRY { + + CXPLAT_SLIST_ENTRY Link; + QUIC_PATHID* PathID; + CXPLAT_SLIST_ENTRY HashEntries; + QUIC_CID CID; + +} QUIC_CID_SLIST_ENTRY; + typedef struct QUIC_CID_HASH_ENTRY { CXPLAT_HASHTABLE_ENTRY Entry; CXPLAT_SLIST_ENTRY Link; - QUIC_CONNECTION* Connection; - QUIC_CID CID; + QUIC_PATHID* PathID; + QUIC_BINDING* Binding; + QUIC_CID_SLIST_ENTRY* CID; } QUIC_CID_HASH_ENTRY; @@ -178,18 +188,19 @@ typedef struct QUIC_CID_HASH_ENTRY { // inline _Success_(return != NULL) -QUIC_CID_HASH_ENTRY* +QUIC_CID_SLIST_ENTRY* QuicCidNewNullSource( - _In_ QUIC_CONNECTION* Connection + _In_ QUIC_PATHID* PathID ) { - QUIC_CID_HASH_ENTRY* Entry = - (QUIC_CID_HASH_ENTRY*)CXPLAT_ALLOC_NONPAGED( - sizeof(QUIC_CID_HASH_ENTRY), - QUIC_POOL_CIDHASH); + QUIC_CID_SLIST_ENTRY* Entry = + (QUIC_CID_SLIST_ENTRY*)CXPLAT_ALLOC_NONPAGED( + sizeof(QUIC_CID_SLIST_ENTRY), + QUIC_POOL_CIDSLIST); if (Entry != NULL) { - Entry->Connection = Connection; + Entry->PathID = PathID; + Entry->HashEntries.Next = NULL; CxPlatZeroMemory(&Entry->CID, sizeof(Entry->CID)); } @@ -201,23 +212,24 @@ QuicCidNewNullSource( // inline _Success_(return != NULL) -QUIC_CID_HASH_ENTRY* +QUIC_CID_SLIST_ENTRY* QuicCidNewSource( - _In_ QUIC_CONNECTION* Connection, + _In_ QUIC_PATHID* PathID, _In_ uint8_t Length, _In_reads_(Length) const uint8_t* const Data ) { - QUIC_CID_HASH_ENTRY* Entry = - (QUIC_CID_HASH_ENTRY*) + QUIC_CID_SLIST_ENTRY* Entry = + (QUIC_CID_SLIST_ENTRY*) CXPLAT_ALLOC_NONPAGED( - sizeof(QUIC_CID_HASH_ENTRY) + + sizeof(QUIC_CID_SLIST_ENTRY) + Length, - QUIC_POOL_CIDHASH); + QUIC_POOL_CIDSLIST); if (Entry != NULL) { - Entry->Connection = Connection; + Entry->PathID = PathID; + Entry->HashEntries.Next = NULL; CxPlatZeroMemory(&Entry->CID, sizeof(Entry->CID)); Entry->CID.Length = Length; if (Length != 0) { diff --git a/src/core/configuration.c b/src/core/configuration.c index ebffd3c803..3af6fb9bf6 100644 --- a/src/core/configuration.c +++ b/src/core/configuration.c @@ -450,6 +450,24 @@ QuicConfigurationParamGet( return QUIC_STATUS_SUCCESS; } +#if QUIC_TEST_MANUAL_CONN_ID_GENERATION + if (Param == QUIC_PARAM_CONFIGURATION_CONN_ID_GENERATION_DISABLED) { + + if (*BufferLength < sizeof(BOOLEAN)) { + *BufferLength = sizeof(BOOLEAN); + return QUIC_STATUS_BUFFER_TOO_SMALL; + } + + if (Buffer == NULL) { + return QUIC_STATUS_INVALID_PARAMETER; + } + + *BufferLength = sizeof(BOOLEAN); + *(BOOLEAN*)Buffer = Configuration->Settings.ConnIDGenDisabled; + + return QUIC_STATUS_SUCCESS; + } +#endif return QUIC_STATUS_INVALID_PARAMETER; } @@ -559,6 +577,20 @@ QuicConfigurationParamSet( return QUIC_STATUS_SUCCESS; +#if QUIC_TEST_MANUAL_CONN_ID_GENERATION + case QUIC_PARAM_CONFIGURATION_CONN_ID_GENERATION_DISABLED: + + if (Buffer == NULL || + BufferLength < sizeof(BOOLEAN)) { + return QUIC_STATUS_INVALID_PARAMETER; + } + + Configuration->Settings.IsSet.ConnIDGenDisabled = TRUE; + Configuration->Settings.ConnIDGenDisabled = *(BOOLEAN*)Buffer; + + return QUIC_STATUS_SUCCESS; +#endif + #ifdef WIN32 case QUIC_PARAM_CONFIGURATION_SCHANNEL_CREDENTIAL_ATTRIBUTE_W: diff --git a/src/core/congestion_control.c b/src/core/congestion_control.c index 42d88597b5..6cdf9cf62a 100644 --- a/src/core/congestion_control.c +++ b/src/core/congestion_control.c @@ -30,7 +30,7 @@ QuicCongestionControlInitialize( default: QuicTraceLogConnWarning( InvalidCongestionControlAlgorithm, - QuicCongestionControlGetConnection(Cc), + QuicCongestionControlGetPathID(Cc)->Connection, "Unknown congestion control algorithm: %hu, fallback to Cubic", Settings->CongestionControlAlgorithm); __fallthrough; diff --git a/src/core/connection.c b/src/core/connection.c index b59d19ba45..3fdfb793e8 100644 --- a/src/core/connection.c +++ b/src/core/connection.c @@ -114,7 +114,6 @@ QuicConnAlloc( Connection->State.ShareBinding = IsServer; Connection->State.FixedBit = TRUE; Connection->Stats.Timing.Start = CxPlatTimeUs64(); - Connection->SourceCidLimit = QUIC_ACTIVE_CONNECTION_ID_LIMIT; Connection->AckDelayExponent = QUIC_ACK_DELAY_EXPONENT; Connection->PacketTolerance = QUIC_MIN_ACK_SEND_NUMBER; Connection->PeerPacketTolerance = QUIC_MIN_ACK_SEND_NUMBER; @@ -125,28 +124,17 @@ QuicConnAlloc( QuicSettingsCopy(&Connection->Settings, &MsQuicLib.Settings); Connection->Settings.IsSetFlags = 0; // Just grab the global values, not IsSet flags. CxPlatDispatchLockInitialize(&Connection->ReceiveQueueLock); - CxPlatListInitializeHead(&Connection->DestCids); QuicStreamSetInitialize(&Connection->Streams); QuicSendBufferInitialize(&Connection->SendBuffer); QuicOperationQueueInitialize(&Connection->OperQ); QuicSendInitialize(&Connection->Send, &Connection->Settings); - QuicCongestionControlInitialize(&Connection->CongestionControl, &Connection->Settings); - QuicLossDetectionInitialize(&Connection->LossDetection); + QuicPathIDSetInitialize(&Connection->PathIDs); QuicDatagramInitialize(&Connection->Datagram); QuicRangeInitialize( QUIC_MAX_RANGE_DECODE_ACKS, &Connection->DecodedAckRanges); - for (uint32_t i = 0; i < ARRAYSIZE(Connection->Packets); i++) { - Status = - QuicPacketSpaceInitialize( - Connection, - (QUIC_ENCRYPT_LEVEL)i, - &Connection->Packets[i]); - if (QUIC_FAILED(Status)) { - goto Error; - } - } + QUIC_PATHID *PathID = NULL; QUIC_PATH* Path = &Connection->Paths[0]; QuicPathInitialize(Connection, Path); @@ -200,6 +188,21 @@ QuicConnAlloc( Connection, CASTED_CLOG_BYTEARRAY(sizeof(Path->Route.RemoteAddress), &Path->Route.RemoteAddress)); + BOOLEAN FatalError = FALSE; + PathID = QuicPathIDSetGetPathIDForPeer( + &Connection->PathIDs, + 0, + TRUE, + &FatalError); + if (PathID == NULL) { + Status = QUIC_STATUS_INTERNAL_ERROR; + goto Error; + } + QuicPathIDAddRef(PathID, QUIC_PATHID_REF_PATH); + Path->PathID = PathID; + PathID->Path = Path; + QuicCongestionControlInitialize(&PathID->CongestionControl, &Connection->Settings); + Path->DestCid = QuicCidNewDestination(Packet->SourceCidLen, Packet->SourceCid); if (Path->DestCid == NULL) { @@ -208,29 +211,17 @@ QuicConnAlloc( } QUIC_CID_SET_PATH(Connection, Path->DestCid, Path); Path->DestCid->CID.UsedLocally = TRUE; - CxPlatListInsertTail(&Connection->DestCids, &Path->DestCid->Link); - QuicTraceEvent( - ConnDestCidAdded, - "[conn][%p] (SeqNum=%llu) New Destination CID: %!CID!", - Connection, - Path->DestCid->CID.SequenceNumber, - CASTED_CLOG_BYTEARRAY(Path->DestCid->CID.Length, Path->DestCid->CID.Data)); + QuicPathIDAddDestCID(PathID, Path->DestCid); - QUIC_CID_HASH_ENTRY* SourceCid = - QuicCidNewSource(Connection, Packet->DestCidLen, Packet->DestCid); + QUIC_CID_SLIST_ENTRY* SourceCid = + QuicCidNewSource(PathID, Packet->DestCidLen, Packet->DestCid); if (SourceCid == NULL) { Status = QUIC_STATUS_OUT_OF_MEMORY; goto Error; } SourceCid->CID.IsInitial = TRUE; SourceCid->CID.UsedByPeer = TRUE; - CxPlatListPushEntry(&Connection->SourceCids, &SourceCid->Link); - QuicTraceEvent( - ConnSourceCidAdded, - "[conn][%p] (SeqNum=%llu) New Source CID: %!CID!", - Connection, - SourceCid->CID.SequenceNumber, - CASTED_CLOG_BYTEARRAY(SourceCid->CID.Length, SourceCid->CID.Data)); + QuicPathIDAddSourceCID(PathID, SourceCid, TRUE); // // Server lazily finishes initialization in response to first operation. @@ -242,6 +233,16 @@ QuicConnAlloc( Path->IsPeerValidated = TRUE; Path->Allowance = UINT32_MAX; + Status = QuicPathIDSetNewLocalPathID(&Connection->PathIDs, &PathID); + if (QUIC_FAILED(Status)) { + goto Error; + } + QuicPathIDAddRef(PathID, QUIC_PATHID_REF_LOOKUP); + QuicPathIDAddRef(PathID, QUIC_PATHID_REF_PATH); + Path->PathID = PathID; + PathID->Path = Path; + QuicCongestionControlInitialize(&PathID->CongestionControl, &Connection->Settings); + Path->DestCid = QuicCidNewRandomDestination(); if (Path->DestCid == NULL) { Status = QUIC_STATUS_OUT_OF_MEMORY; @@ -249,14 +250,8 @@ QuicConnAlloc( } QUIC_CID_SET_PATH(Connection, Path->DestCid, Path); Path->DestCid->CID.UsedLocally = TRUE; - Connection->DestCidCount++; - CxPlatListInsertTail(&Connection->DestCids, &Path->DestCid->Link); - QuicTraceEvent( - ConnDestCidAdded, - "[conn][%p] (SeqNum=%llu) New Destination CID: %!CID!", - Connection, - Path->DestCid->CID.SequenceNumber, - CASTED_CLOG_BYTEARRAY(Path->DestCid->CID.Length, Path->DestCid->CID.Data)); + PathID->DestCidCount++; + QuicPathIDAddDestCID(PathID, Path->DestCid); Connection->State.Initialized = TRUE; QuicTraceEvent( @@ -273,6 +268,7 @@ QuicConnAlloc( Status = QUIC_STATUS_INVALID_STATE; goto Error; } + QuicPathIDRelease(PathID, QUIC_PATHID_REF_LOOKUP); *NewConnection = Connection; return QUIC_STATUS_SUCCESS; @@ -280,28 +276,17 @@ QuicConnAlloc( Error: Connection->State.HandleClosed = TRUE; - for (uint32_t i = 0; i < ARRAYSIZE(Connection->Packets); i++) { - if (Connection->Packets[i] != NULL) { - QuicPacketSpaceUninitialize(Connection->Packets[i]); - Connection->Packets[i] = NULL; + if (PathID != NULL) { + if (PathID->SourceCids.Next != NULL) { + CXPLAT_FREE( + CXPLAT_CONTAINING_RECORD( + PathID->SourceCids.Next, + QUIC_CID_SLIST_ENTRY, + Link), + QUIC_POOL_CIDSLIST); + PathID->SourceCids.Next = NULL; } - } - if (Packet != NULL && Connection->SourceCids.Next != NULL) { - CXPLAT_FREE( - CXPLAT_CONTAINING_RECORD( - Connection->SourceCids.Next, - QUIC_CID_HASH_ENTRY, - Link), - QUIC_POOL_CIDHASH); - Connection->SourceCids.Next = NULL; - } - while (!CxPlatListIsEmpty(&Connection->DestCids)) { - QUIC_CID_LIST_ENTRY *CID = - CXPLAT_CONTAINING_RECORD( - CxPlatListRemoveHead(&Connection->DestCids), - QUIC_CID_LIST_ENTRY, - Link); - CXPLAT_FREE(CID, QUIC_POOL_CIDLIST); + QuicPathIDRelease(PathID, QUIC_PATHID_REF_LOOKUP); } QuicConnRelease(Connection, QUIC_CONN_REF_HANDLE_OWNER); @@ -319,18 +304,10 @@ QuicConnFree( if (Connection->State.ExternalOwner) { CXPLAT_TEL_ASSERT(Connection->State.HandleClosed); } - CXPLAT_TEL_ASSERT(Connection->SourceCids.Next == NULL); CXPLAT_TEL_ASSERT(CxPlatListIsEmpty(&Connection->Streams.ClosedStreams)); QuicRangeUninitialize(&Connection->DecodedAckRanges); QuicCryptoUninitialize(&Connection->Crypto); - QuicLossDetectionUninitialize(&Connection->LossDetection); QuicSendUninitialize(&Connection->Send); - for (uint32_t i = 0; i < ARRAYSIZE(Connection->Packets); i++) { - if (Connection->Packets[i] != NULL) { - QuicPacketSpaceUninitialize(Connection->Packets[i]); - Connection->Packets[i] = NULL; - } - } #if DEBUG while (!CxPlatListIsEmpty(&Connection->Streams.AllStreams)) { QUIC_STREAM *Stream = @@ -341,14 +318,7 @@ QuicConnFree( CXPLAT_DBG_ASSERTMSG(Stream != NULL, "Stream was leaked!"); } #endif - while (!CxPlatListIsEmpty(&Connection->DestCids)) { - QUIC_CID_LIST_ENTRY *CID = - CXPLAT_CONTAINING_RECORD( - CxPlatListRemoveHead(&Connection->DestCids), - QUIC_CID_LIST_ENTRY, - Link); - CXPLAT_FREE(CID, QUIC_POOL_CIDLIST); - } + QuicPathIDSetFree(&Connection->PathIDs); QuicConnUnregister(Connection); if (Connection->Worker != NULL) { QuicTimerWheelRemoveConnection(&Connection->Worker->TimerWheel, Connection); @@ -362,14 +332,20 @@ QuicConnFree( CxPlatRecvDataReturn((CXPLAT_RECV_DATA*)Connection->ReceiveQueue); Connection->ReceiveQueue = NULL; } - QUIC_PATH* Path = &Connection->Paths[0]; - if (Path->Binding != NULL) { - QuicLibraryReleaseBinding(Path->Binding); - Path->Binding = NULL; + for (uint8_t i = 0; i < Connection->PathsCount; ++i) { + if (Connection->Paths[i].PathID != NULL) { + QuicPathIDRelease(Connection->Paths[i].PathID, QUIC_PATHID_REF_PATH); + Connection->Paths[i].PathID = NULL; + } + if (Connection->Paths[i].Binding != NULL) { + QuicLibraryReleaseBinding(Connection->Paths[i].Binding); + Connection->Paths[i].Binding = NULL; + } } CxPlatDispatchLockUninitialize(&Connection->ReceiveQueueLock); QuicOperationQueueUninitialize(&Connection->OperQ); QuicStreamSetUninitialize(&Connection->Streams); + QuicPathIDSetUninitialize(&Connection->PathIDs); QuicSendBufferUninitialize(&Connection->SendBuffer); QuicDatagramSendShutdown(&Connection->Datagram); QuicDatagramUninitialize(&Connection->Datagram); @@ -607,38 +583,6 @@ QuicConnTraceRundownOper( CASTED_CLOG_BYTEARRAY(sizeof(Connection->Paths[i].Route.RemoteAddress), &Connection->Paths[i].Route.RemoteAddress)); } } - for (CXPLAT_SLIST_ENTRY* Entry = Connection->SourceCids.Next; - Entry != NULL; - Entry = Entry->Next) { - const QUIC_CID_HASH_ENTRY* SourceCid = - CXPLAT_CONTAINING_RECORD( - Entry, - QUIC_CID_HASH_ENTRY, - Link); - UNREFERENCED_PARAMETER(SourceCid); - QuicTraceEvent( - ConnSourceCidAdded, - "[conn][%p] (SeqNum=%llu) New Source CID: %!CID!", - Connection, - SourceCid->CID.SequenceNumber, - CASTED_CLOG_BYTEARRAY(SourceCid->CID.Length, SourceCid->CID.Data)); - } - for (CXPLAT_LIST_ENTRY* Entry = Connection->DestCids.Flink; - Entry != &Connection->DestCids; - Entry = Entry->Flink) { - const QUIC_CID_LIST_ENTRY* DestCid = - CXPLAT_CONTAINING_RECORD( - Entry, - QUIC_CID_LIST_ENTRY, - Link); - UNREFERENCED_PARAMETER(DestCid); - QuicTraceEvent( - ConnDestCidAdded, - "[conn][%p] (SeqNum=%llu) New Destination CID: %!CID!", - Connection, - DestCid->CID.SequenceNumber, - CASTED_CLOG_BYTEARRAY(DestCid->CID.Length, DestCid->CID.Data)); - } } if (Connection->State.Connected) { QuicTraceEvent( @@ -657,6 +601,7 @@ QuicConnTraceRundownOper( } QuicStreamSetTraceRundown(&Connection->Streams); + QuicPathIDSetTraceRundown(&Connection->PathIDs); } _IRQL_requires_max_(PASSIVE_LEVEL) @@ -708,7 +653,7 @@ QuicConnQueueOper( #if DEBUG if (!Connection->State.Initialized) { CXPLAT_DBG_ASSERT(QuicConnIsServer(Connection)); - CXPLAT_DBG_ASSERT(Connection->SourceCids.Next != NULL || CxPlatIsRandomMemoryFailureEnabled()); + // CXPLAT_DBG_ASSERT(Connection->SourceCids.Next != NULL || CxPlatIsRandomMemoryFailureEnabled()); } #endif if (QuicOperationEnqueue(&Connection->OperQ, Oper)) { @@ -730,7 +675,7 @@ QuicConnQueuePriorityOper( #if DEBUG if (!Connection->State.Initialized) { CXPLAT_DBG_ASSERT(QuicConnIsServer(Connection)); - CXPLAT_DBG_ASSERT(Connection->SourceCids.Next != NULL || CxPlatIsRandomMemoryFailureEnabled()); + // CXPLAT_DBG_ASSERT(Connection->SourceCids.Next != NULL || CxPlatIsRandomMemoryFailureEnabled()); } #endif if (QuicOperationEnqueuePriority(&Connection->OperQ, Oper)) { @@ -826,335 +771,6 @@ QuicConnUpdateRtt( (uint32_t)(Path->OneWayDelay / 1000), (uint32_t)(Path->OneWayDelay % 1000)); } -_IRQL_requires_max_(PASSIVE_LEVEL) -QUIC_CID_HASH_ENTRY* -QuicConnGenerateNewSourceCid( - _In_ QUIC_CONNECTION* Connection, - _In_ BOOLEAN IsInitial - ) -{ - uint8_t TryCount = 0; - QUIC_CID_HASH_ENTRY* SourceCid; - - if (!Connection->State.ShareBinding) { - // - // We aren't sharing the binding, therefore aren't actually using a CID. - // No need to generate a new one. - // - return NULL; - } - - // - // Keep randomly generating new source CIDs until we find one that doesn't - // collide with an existing one. - // - - do { - SourceCid = - QuicCidNewRandomSource( - Connection, - Connection->ServerID, - Connection->PartitionID, - Connection->CibirId[0], - Connection->CibirId+2); - if (SourceCid == NULL) { - QuicTraceEvent( - AllocFailure, - "Allocation of '%s' failed. (%llu bytes)", - "new Src CID", - sizeof(QUIC_CID_HASH_ENTRY) + MsQuicLib.CidTotalLength); - QuicConnFatalError(Connection, QUIC_STATUS_INTERNAL_ERROR, NULL); - return NULL; - } - if (!QuicBindingAddSourceConnectionID(Connection->Paths[0].Binding, SourceCid)) { - CXPLAT_FREE(SourceCid, QUIC_POOL_CIDHASH); - SourceCid = NULL; - if (++TryCount > QUIC_CID_MAX_COLLISION_RETRY) { - QuicTraceEvent( - ConnError, - "[conn][%p] ERROR, %s.", - Connection, - "Too many CID collisions"); - QuicConnFatalError(Connection, QUIC_STATUS_INTERNAL_ERROR, NULL); - return NULL; - } - QuicTraceLogConnVerbose( - NewSrcCidNameCollision, - Connection, - "CID collision, trying again"); - } - } while (SourceCid == NULL); - - QuicTraceEvent( - ConnSourceCidAdded, - "[conn][%p] (SeqNum=%llu) New Source CID: %!CID!", - Connection, - SourceCid->CID.SequenceNumber, - CASTED_CLOG_BYTEARRAY(SourceCid->CID.Length, SourceCid->CID.Data)); - - SourceCid->CID.SequenceNumber = Connection->NextSourceCidSequenceNumber++; - if (SourceCid->CID.SequenceNumber > 0) { - SourceCid->CID.NeedsToSend = TRUE; - QuicSendSetSendFlag(&Connection->Send, QUIC_CONN_SEND_FLAG_NEW_CONNECTION_ID); - } - - if (IsInitial) { - SourceCid->CID.IsInitial = TRUE; - CxPlatListPushEntry(&Connection->SourceCids, &SourceCid->Link); - } else { - CXPLAT_SLIST_ENTRY** Tail = &Connection->SourceCids.Next; - while (*Tail != NULL) { - Tail = &(*Tail)->Next; - } - *Tail = &SourceCid->Link; - SourceCid->Link.Next = NULL; - } - - return SourceCid; -} - -uint8_t -QuicConnSourceCidsCount( - _In_ const QUIC_CONNECTION* Connection - ) -{ - uint8_t Count = 0; - const CXPLAT_SLIST_ENTRY* Entry = Connection->SourceCids.Next; - while (Entry != NULL) { - ++Count; - Entry = Entry->Next; - } - return Count; -} - -// -// This generates new source CIDs for the peer to use to talk to us. If -// indicated, it invalidates all the existing ones, sets a a new retire prior to -// sequence number to send out and generates replacement CIDs. -// -_IRQL_requires_max_(PASSIVE_LEVEL) -void -QuicConnGenerateNewSourceCids( - _In_ QUIC_CONNECTION* Connection, - _In_ BOOLEAN ReplaceExistingCids - ) -{ - if (!Connection->State.ShareBinding) { - // - // Can't generate any new CIDs, so this is a no-op. - // - return; - } - - // - // If we're replacing existing ones, then generate all new CIDs (up to the - // limit). Otherwise, just generate whatever number we need to hit the - // limit. - // - uint8_t NewCidCount; - if (ReplaceExistingCids) { - NewCidCount = Connection->SourceCidLimit; - CXPLAT_SLIST_ENTRY* Entry = Connection->SourceCids.Next; - while (Entry != NULL) { - QUIC_CID_HASH_ENTRY* SourceCid = - CXPLAT_CONTAINING_RECORD(Entry, QUIC_CID_HASH_ENTRY, Link); - SourceCid->CID.Retired = TRUE; - Entry = Entry->Next; - } - } else { - uint8_t CurrentCidCount = QuicConnSourceCidsCount(Connection); - CXPLAT_DBG_ASSERT(CurrentCidCount <= Connection->SourceCidLimit); - if (CurrentCidCount < Connection->SourceCidLimit) { - NewCidCount = Connection->SourceCidLimit - CurrentCidCount; - } else { - NewCidCount = 0; - } - } - - for (uint8_t i = 0; i < NewCidCount; ++i) { - if (QuicConnGenerateNewSourceCid(Connection, FALSE) == NULL) { - break; - } - } -} - -_IRQL_requires_max_(PASSIVE_LEVEL) -QUIC_CID_LIST_ENTRY* -QuicConnGetUnusedDestCid( - _In_ const QUIC_CONNECTION* Connection - ) -{ - for (CXPLAT_LIST_ENTRY* Entry = Connection->DestCids.Flink; - Entry != &Connection->DestCids; - Entry = Entry->Flink) { - QUIC_CID_LIST_ENTRY* DestCid = - CXPLAT_CONTAINING_RECORD( - Entry, - QUIC_CID_LIST_ENTRY, - Link); - if (!DestCid->CID.UsedLocally && !DestCid->CID.Retired) { - return DestCid; - } - } - return NULL; -} - -_IRQL_requires_max_(PASSIVE_LEVEL) -void -QuicConnRetireCid( - _In_ QUIC_CONNECTION* Connection, - _In_ QUIC_CID_LIST_ENTRY* DestCid - ) -{ - QuicTraceEvent( - ConnDestCidRemoved, - "[conn][%p] (SeqNum=%llu) Removed Destination CID: %!CID!", - Connection, - DestCid->CID.SequenceNumber, - CASTED_CLOG_BYTEARRAY(DestCid->CID.Length, DestCid->CID.Data)); - Connection->DestCidCount--; - DestCid->CID.Retired = TRUE; - DestCid->CID.NeedsToSend = TRUE; - QuicSendSetSendFlag(&Connection->Send, QUIC_CONN_SEND_FLAG_RETIRE_CONNECTION_ID); - - Connection->RetiredDestCidCount++; - if (Connection->RetiredDestCidCount > 8 * QUIC_ACTIVE_CONNECTION_ID_LIMIT) { - QuicTraceEvent( - ConnError, - "[conn][%p] ERROR, %s.", - Connection, - "Peer exceeded retire CID limit"); - QuicConnSilentlyAbort(Connection); - } -} - -_IRQL_requires_max_(PASSIVE_LEVEL) -BOOLEAN -QuicConnRetireCurrentDestCid( - _In_ QUIC_CONNECTION* Connection, - _In_ QUIC_PATH* Path - ) -{ - if (Path->DestCid->CID.Length == 0) { - QuicTraceLogConnVerbose( - ZeroLengthCidRetire, - Connection, - "Can't retire current CID because it's zero length"); - return TRUE; // No need to update so treat as success. - } - - QUIC_CID_LIST_ENTRY* NewDestCid = QuicConnGetUnusedDestCid(Connection); - if (NewDestCid == NULL) { - QuicTraceLogConnWarning( - NoReplacementCidForRetire, - Connection, - "Can't retire current CID because we don't have a replacement"); - return FALSE; - } - - CXPLAT_DBG_ASSERT(Path->DestCid != NewDestCid); - QUIC_CID_LIST_ENTRY* OldDestCid = Path->DestCid; - QUIC_CID_CLEAR_PATH(Path->DestCid); - QuicConnRetireCid(Connection, Path->DestCid); - Path->DestCid = NewDestCid; - QUIC_CID_SET_PATH(Connection, Path->DestCid, Path); - QUIC_CID_VALIDATE_NULL(Connection, OldDestCid); - Path->DestCid->CID.UsedLocally = TRUE; - Connection->Stats.Misc.DestCidUpdateCount++; - - return TRUE; -} - -_IRQL_requires_max_(PASSIVE_LEVEL) -BOOLEAN -QuicConnOnRetirePriorToUpdated( - _In_ QUIC_CONNECTION* Connection - ) -{ - BOOLEAN ReplaceRetiredCids = FALSE; - - for (CXPLAT_LIST_ENTRY* Entry = Connection->DestCids.Flink; - Entry != &Connection->DestCids; - Entry = Entry->Flink) { - QUIC_CID_LIST_ENTRY* DestCid = - CXPLAT_CONTAINING_RECORD( - Entry, - QUIC_CID_LIST_ENTRY, - Link); - if (DestCid->CID.SequenceNumber >= Connection->RetirePriorTo || - DestCid->CID.Retired) { - continue; - } - - if (DestCid->CID.UsedLocally) { - ReplaceRetiredCids = TRUE; - } - - QUIC_CID_CLEAR_PATH(DestCid); - QuicConnRetireCid(Connection, DestCid); - } - - return ReplaceRetiredCids; -} - -_IRQL_requires_max_(PASSIVE_LEVEL) -BOOLEAN -QuicConnReplaceRetiredCids( - _In_ QUIC_CONNECTION* Connection - ) -{ - CXPLAT_DBG_ASSERT(Connection->PathsCount <= QUIC_MAX_PATH_COUNT); - for (uint8_t i = 0; i < Connection->PathsCount; ++i) { - QUIC_PATH* Path = &Connection->Paths[i]; - if (Path->DestCid == NULL || !Path->DestCid->CID.Retired) { - continue; - } - - QUIC_CID_VALIDATE_NULL(Connection, Path->DestCid); // Previously cleared on retire. - QUIC_CID_LIST_ENTRY* NewDestCid = QuicConnGetUnusedDestCid(Connection); - if (NewDestCid == NULL) { - if (Path->IsActive) { - QuicTraceEvent( - ConnError, - "[conn][%p] ERROR, %s.", - Connection, - "Active path has no replacement for retired CID"); - QuicConnSilentlyAbort(Connection); // Must silently abort because we can't send anything now. - return FALSE; - } - QuicTraceLogConnWarning( - NonActivePathCidRetired, - Connection, - "Non-active path has no replacement for retired CID."); - CXPLAT_DBG_ASSERT(i != 0); - QuicPathRemove(Connection, i--); - continue; - } - - CXPLAT_DBG_ASSERT(NewDestCid != Path->DestCid); - Path->DestCid = NewDestCid; - QUIC_CID_SET_PATH(Connection, NewDestCid, Path); - Path->DestCid->CID.UsedLocally = TRUE; - Path->InitiatedCidUpdate = TRUE; - QuicPathValidate(Path); - } - -#if DEBUG - for (CXPLAT_LIST_ENTRY* Entry = Connection->DestCids.Flink; - Entry != &Connection->DestCids; - Entry = Entry->Flink) { - QUIC_CID_LIST_ENTRY* DestCid = - CXPLAT_CONTAINING_RECORD( - Entry, - QUIC_CID_LIST_ENTRY, - Link); - CXPLAT_DBG_ASSERT(!DestCid->CID.Retired || DestCid->AssignedPath == NULL); - } -#endif - - return TRUE; -} - _IRQL_requires_max_(DISPATCH_LEVEL) uint64_t QuicGetEarliestExpirationTime( @@ -1362,19 +978,25 @@ QuicConnOnShutdownComplete( if (Path->EncryptionOffloading) { QuicPathUpdateQeo(Connection, Path, CXPLAT_QEO_OPERATION_REMOVE); } - - // - // Remove all entries in the binding's lookup tables so we don't get any - // more packets queued. - // - QuicBindingRemoveConnection(Connection->Paths[0].Binding, Connection); + } + // + // Remove all entries in the binding's lookup tables so we don't get any + // more packets queued. + // + if (Connection->RemoteHashEntry != NULL) { + CXPLAT_DBG_ASSERT(Connection->RemoteHashEntry->Binding != NULL); + QuicBindingRemoveRemoteHash( + Connection->RemoteHashEntry->Binding, + Connection->RemoteHashEntry); } + QuicPathIDSetFreeSourceCids(&Connection->PathIDs); + // // Clean up the rest of the internal state. // QuicTimerWheelRemoveConnection(&Connection->Worker->TimerWheel, Connection); - QuicLossDetectionUninitialize(&Connection->LossDetection); + // QuicLossDetectionUninitialize(&Connection->LossDetection); QuicSendUninitialize(&Connection->Send); QuicDatagramSendShutdown(&Connection->Datagram); @@ -1523,7 +1145,7 @@ QuicConnTryClose( // uint64_t Pto = QuicLossDetectionComputeProbeTimeout( - &Connection->LossDetection, + &Connection->Paths[0].PathID->LossDetection, &Connection->Paths[0], QUIC_CLOSE_PTO_COUNT); QuicConnTimerSet( @@ -1859,31 +1481,25 @@ QuicConnStart( // Clients only need to generate a non-zero length source CID if it // intends to share the UDP binding. // - QUIC_CID_HASH_ENTRY* SourceCid; + QUIC_CID_SLIST_ENTRY* SourceCid; if (Connection->State.ShareBinding) { SourceCid = QuicCidNewRandomSource( - Connection, + Path->PathID, NULL, Connection->PartitionID, Connection->CibirId[0], Connection->CibirId+2); } else { - SourceCid = QuicCidNewNullSource(Connection); + SourceCid = QuicCidNewNullSource(Path->PathID); } if (SourceCid == NULL) { Status = QUIC_STATUS_OUT_OF_MEMORY; goto Exit; } - Connection->NextSourceCidSequenceNumber++; - QuicTraceEvent( - ConnSourceCidAdded, - "[conn][%p] (SeqNum=%llu) New Source CID: %!CID!", - Connection, - SourceCid->CID.SequenceNumber, - CASTED_CLOG_BYTEARRAY(SourceCid->CID.Length, SourceCid->CID.Data)); - CxPlatListPushEntry(&Connection->SourceCids, &SourceCid->Link); + Path->PathID->NextSourceCidSequenceNumber++; + QuicPathIDAddSourceCID(Path->PathID, SourceCid, TRUE); if (!QuicBindingAddSourceConnectionID(Path->Binding, SourceCid)) { QuicLibraryReleaseBinding(Path->Binding); @@ -1968,14 +1584,16 @@ QuicConnRestart( Path->RttVariance = Path->SmoothedRtt / 2; } - for (uint32_t i = 0; i < ARRAYSIZE(Connection->Packets); ++i) { - CXPLAT_DBG_ASSERT(Connection->Packets[i] != NULL); - QuicPacketSpaceReset(Connection->Packets[i]); + QUIC_PATHID* PathID = Connection->Paths[0].PathID; + CXPLAT_DBG_ASSERT(PathID != NULL && PathID->ID == 0); + for (uint32_t i = 0; i < ARRAYSIZE(PathID->Packets); ++i) { + CXPLAT_DBG_ASSERT(PathID->Packets[i] != NULL); + QuicPacketSpaceReset(PathID->Packets[i]); } - QuicCongestionControlReset(&Connection->CongestionControl, TRUE); + QuicCongestionControlReset(&PathID->CongestionControl, TRUE); QuicSendReset(&Connection->Send); - QuicLossDetectionReset(&Connection->LossDetection); + QuicLossDetectionReset(&Connection->Paths[0].PathID->LossDetection); QuicCryptoTlsCleanupTransportParameters(&Connection->PeerTransportParams); if (CompleteReset) { @@ -2236,11 +1854,11 @@ QuicConnGenerateLocalTransportParameters( { CXPLAT_TEL_ASSERT(Connection->Configuration != NULL); - CXPLAT_DBG_ASSERT(Connection->SourceCids.Next != NULL); - const QUIC_CID_HASH_ENTRY* SourceCid = + CXPLAT_DBG_ASSERT(Connection->Paths[0].PathID->SourceCids.Next != NULL); + const QUIC_CID_SLIST_ENTRY* SourceCid = CXPLAT_CONTAINING_RECORD( - Connection->SourceCids.Next, - QUIC_CID_HASH_ENTRY, + Connection->Paths[0].PathID->SourceCids.Next, + QUIC_CID_SLIST_ENTRY, Link); LocalTP->InitialMaxData = Connection->Send.MaxData; @@ -2328,6 +1946,11 @@ QuicConnGenerateLocalTransportParameters( QUIC_TP_FLAG_TIMESTAMP_SEND_ENABLED; } + if (Connection->Settings.MultipathEnabled) { + LocalTP->Flags |= QUIC_TP_FLAG_INITIAL_MAX_PATH_ID; + LocalTP->InitialMaxPathId = QUIC_ACTIVE_PATH_ID_LIMIT - 1; + } + if (QuicConnIsServer(Connection)) { if (Connection->Streams.Types[STREAM_ID_FLAG_IS_CLIENT | STREAM_ID_FLAG_IS_BI_DIR].MaxTotalStreamCount) { @@ -2372,10 +1995,10 @@ QuicConnGenerateLocalTransportParameters( if (Connection->State.HandshakeUsedRetryPacket) { CXPLAT_DBG_ASSERT(SourceCid->Link.Next != NULL); - const QUIC_CID_HASH_ENTRY* PrevSourceCid = + const QUIC_CID_SLIST_ENTRY* PrevSourceCid = CXPLAT_CONTAINING_RECORD( SourceCid->Link.Next, - QUIC_CID_HASH_ENTRY, + QUIC_CID_SLIST_ENTRY, Link); LocalTP->Flags |= QUIC_TP_FLAG_RETRY_SOURCE_CONNECTION_ID; @@ -2452,10 +2075,10 @@ QuicConnSetConfiguration( } } - CXPLAT_DBG_ASSERT(!CxPlatListIsEmpty(&Connection->DestCids)); + CXPLAT_DBG_ASSERT(!CxPlatListIsEmpty(&Connection->Paths[0].PathID->DestCids)); const QUIC_CID_LIST_ENTRY* DestCid = CXPLAT_CONTAINING_RECORD( - Connection->DestCids.Flink, + Connection->Paths[0].PathID->DestCids.Flink, QUIC_CID_LIST_ENTRY, Link); @@ -2554,9 +2177,13 @@ QuicConnValidateTransportParameterCIDs( return FALSE; } + // if (!(Connection->PeerTransportParams.Flags & QUIC_TP_FLAG_INITIAL_MAX_PATH_ID)) { + // return FALSE; + // } + const QUIC_CID_LIST_ENTRY* DestCid = CXPLAT_CONTAINING_RECORD( - Connection->DestCids.Flink, + Connection->Paths[0].PathID->DestCids.Flink, QUIC_CID_LIST_ENTRY, Link); if (DestCid->CID.Length != Connection->PeerTransportParams.InitialSourceConnectionIDLength || @@ -2884,13 +2511,18 @@ QuicConnProcessPeerTransportParameters( "Peer Transport Parameters Set"); Connection->State.PeerTransportParameterValid = TRUE; - if (Connection->PeerTransportParams.Flags & QUIC_TP_FLAG_ACTIVE_CONNECTION_ID_LIMIT) { - CXPLAT_DBG_ASSERT(Connection->PeerTransportParams.ActiveConnectionIdLimit >= QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT_MIN); - if (Connection->SourceCidLimit > Connection->PeerTransportParams.ActiveConnectionIdLimit) { - Connection->SourceCidLimit = (uint8_t) Connection->PeerTransportParams.ActiveConnectionIdLimit; - } + if ((Connection->PeerTransportParams.Flags & QUIC_TP_FLAG_INITIAL_MAX_PATH_ID)) { + QuicPathIDSetInitializeTransportParameters(&Connection->PathIDs, + (Connection->PeerTransportParams.Flags & QUIC_TP_FLAG_ACTIVE_CONNECTION_ID_LIMIT) ? + (uint8_t)Connection->PeerTransportParams.ActiveConnectionIdLimit : + QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT_DEFAULT, + (uint32_t)Connection->PeerTransportParams.InitialMaxPathId); } else { - Connection->SourceCidLimit = QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT_DEFAULT; + QuicPathIDSetInitializeTransportParameters(&Connection->PathIDs, + (Connection->PeerTransportParams.Flags & QUIC_TP_FLAG_ACTIVE_CONNECTION_ID_LIMIT) ? + (uint8_t)Connection->PeerTransportParams.ActiveConnectionIdLimit : + QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT_DEFAULT, + UINT32_MAX); } if (!FromResumptionTicket) { @@ -2918,11 +2550,11 @@ QuicConnProcessPeerTransportParameters( } if (Connection->PeerTransportParams.Flags & QUIC_TP_FLAG_STATELESS_RESET_TOKEN) { - CXPLAT_DBG_ASSERT(!CxPlatListIsEmpty(&Connection->DestCids)); + CXPLAT_DBG_ASSERT(!CxPlatListIsEmpty(&Connection->Paths[0].PathID->DestCids)); CXPLAT_DBG_ASSERT(QuicConnIsClient(Connection)); QUIC_CID_LIST_ENTRY* DestCid = CXPLAT_CONTAINING_RECORD( - Connection->DestCids.Flink, + Connection->Paths[0].PathID->DestCids.Flink, QUIC_CID_LIST_ENTRY, Link); CxPlatCopyMemory( @@ -2999,6 +2631,11 @@ QuicConnProcessPeerTransportParameters( QuicConnIndicateEvent(Connection, &Event); } + if (Connection->Settings.MultipathEnabled) { + Connection->State.MultipathNegotiated = + !!(Connection->PeerTransportParams.Flags & QUIC_TP_FLAG_INITIAL_MAX_PATH_ID); + } + // // Fully validate all exchanged connection IDs. // @@ -3158,11 +2795,13 @@ QuicConnQueueRecvPackets( ) { QUIC_RX_PACKET** PacketsTail = (QUIC_RX_PACKET**)&Packets->Next; + uint32_t PathId = Packets->PathId; Packets->QueuedOnConnection = TRUE; Packets->AssignedToConnection = TRUE; while (*PacketsTail != NULL) { (*PacketsTail)->QueuedOnConnection = TRUE; (*PacketsTail)->AssignedToConnection = TRUE; + (*PacketsTail)->PathId = PathId; PacketsTail = (QUIC_RX_PACKET**)&((*PacketsTail)->Next); } @@ -3290,105 +2929,16 @@ QuicConnQueueRouteCompletion( QuicConnRelease(Connection, QUIC_CONN_REF_ROUTE); } -// -// Updates the current destination CID to the received packet's source CID, if -// not already equal. Only used during the handshake, on the client side. -// _IRQL_requires_max_(PASSIVE_LEVEL) -BOOLEAN -QuicConnUpdateDestCid( +void +QuicConnRecvVerNeg( _In_ QUIC_CONNECTION* Connection, _In_ const QUIC_RX_PACKET* const Packet ) { - CXPLAT_DBG_ASSERT(QuicConnIsClient(Connection)); - CXPLAT_DBG_ASSERT(!Connection->State.Connected); - - if (CxPlatListIsEmpty(&Connection->DestCids)) { - CXPLAT_DBG_ASSERT(CxPlatIsRandomMemoryFailureEnabled()); - QuicConnTransportError(Connection, QUIC_ERROR_INTERNAL_ERROR); - return FALSE; - } - QUIC_CID_LIST_ENTRY* DestCid = - CXPLAT_CONTAINING_RECORD( - Connection->DestCids.Flink, - QUIC_CID_LIST_ENTRY, - Link); - CXPLAT_DBG_ASSERT(Connection->Paths[0].DestCid == DestCid); + uint32_t SupportedVersion = 0; - if (Packet->SourceCidLen != DestCid->CID.Length || - memcmp(Packet->SourceCid, DestCid->CID.Data, DestCid->CID.Length) != 0) { - - // TODO - Only update for the first packet of each type (Initial and Retry). - - QuicTraceEvent( - ConnDestCidRemoved, - "[conn][%p] (SeqNum=%llu) Removed Destination CID: %!CID!", - Connection, - DestCid->CID.SequenceNumber, - CASTED_CLOG_BYTEARRAY(DestCid->CID.Length, DestCid->CID.Data)); - - // - // We have just received the a packet from a new source CID - // from the server. Remove the current DestCid we have for the - // server (which we randomly generated) and replace it with - // the one we have just received. - // - if (Packet->SourceCidLen <= DestCid->CID.Length) { - // - // Since the current structure has enough room for the - // new CID, we will just reuse it. - // - DestCid->CID.IsInitial = FALSE; - DestCid->CID.Length = Packet->SourceCidLen; - CxPlatCopyMemory(DestCid->CID.Data, Packet->SourceCid, DestCid->CID.Length); - } else { - // - // There isn't enough room in the existing structure, - // so we must allocate a new one and free the old one. - // - CxPlatListEntryRemove(&DestCid->Link); - CXPLAT_FREE(DestCid, QUIC_POOL_CIDLIST); - DestCid = - QuicCidNewDestination( - Packet->SourceCidLen, - Packet->SourceCid); - if (DestCid == NULL) { - Connection->DestCidCount--; - Connection->Paths[0].DestCid = NULL; - QuicConnFatalError(Connection, QUIC_STATUS_OUT_OF_MEMORY, "Out of memory"); - return FALSE; - } - - Connection->Paths[0].DestCid = DestCid; - QUIC_CID_SET_PATH(Connection, DestCid, &Connection->Paths[0]); - DestCid->CID.UsedLocally = TRUE; - CxPlatListInsertHead(&Connection->DestCids, &DestCid->Link); - } - - if (DestCid != NULL) { - QuicTraceEvent( - ConnDestCidAdded, - "[conn][%p] (SeqNum=%llu) New Destination CID: %!CID!", - Connection, - DestCid->CID.SequenceNumber, - CASTED_CLOG_BYTEARRAY(DestCid->CID.Length, DestCid->CID.Data)); - } - } - - return TRUE; -} - -_IRQL_requires_max_(PASSIVE_LEVEL) -void -QuicConnRecvVerNeg( - _In_ QUIC_CONNECTION* Connection, - _In_ const QUIC_RX_PACKET* const Packet - ) -{ - uint32_t SupportedVersion = 0; - - // TODO - Validate the packet's SourceCid is equal to our DestCid. + // TODO - Validate the packet's SourceCid is equal to our DestCid. const uint32_t* ServerVersionList = (const uint32_t*)( @@ -3540,10 +3090,10 @@ QuicConnRecvRetry( Packet->AvailBuffer, 0); - CXPLAT_DBG_ASSERT(!CxPlatListIsEmpty(&Connection->DestCids)); + CXPLAT_DBG_ASSERT(!CxPlatListIsEmpty(&Connection->Paths[0].PathID->DestCids)); const QUIC_CID_LIST_ENTRY* DestCid = CXPLAT_CONTAINING_RECORD( - Connection->DestCids.Flink, + Connection->Paths[0].PathID->DestCids.Flink, QUIC_CID_LIST_ENTRY, Link); @@ -3590,7 +3140,7 @@ QuicConnRecvRetry( // // Update the (destination) server's CID. // - if (!QuicConnUpdateDestCid(Connection, Packet)) { + if (!QuicPathIDUpdateDestCid(Connection->Paths[0].PathID, Packet)) { return; } @@ -3605,10 +3155,10 @@ QuicConnRecvRetry( Connection->Crypto.TlsState.ReadKeys[QUIC_PACKET_KEY_INITIAL] = NULL; Connection->Crypto.TlsState.WriteKeys[QUIC_PACKET_KEY_INITIAL] = NULL; - CXPLAT_DBG_ASSERT(!CxPlatListIsEmpty(&Connection->DestCids)); + CXPLAT_DBG_ASSERT(!CxPlatListIsEmpty(&Connection->Paths[0].PathID->DestCids)); DestCid = CXPLAT_CONTAINING_RECORD( - Connection->DestCids.Flink, + Connection->Paths[0].PathID->DestCids.Flink, QUIC_CID_LIST_ENTRY, Link); @@ -3667,7 +3217,16 @@ QuicConnGetKeyOrDeferDatagram( } else { QUIC_ENCRYPT_LEVEL EncryptLevel = QuicKeyTypeToEncryptLevel(Packet->KeyType); - QUIC_PACKET_SPACE* Packets = Connection->Packets[EncryptLevel]; + BOOLEAN FatalError = FALSE; + QUIC_PATHID* PathID = + QuicPathIDSetGetPathIDForPeer( + &Connection->PathIDs, + Packet->PathId, + FALSE, + &FatalError); + CXPLAT_DBG_ASSERT(!FatalError && PathID != NULL); + QUIC_PACKET_SPACE* Packets = PathID->Packets[EncryptLevel]; + CXPLAT_DBG_ASSERT(Packets != NULL); if (Packets->DeferredPacketsCount == QUIC_MAX_PENDING_DATAGRAMS) { // // We already have too many packets queued up. Just drop this @@ -3696,6 +3255,7 @@ QuicConnGetKeyOrDeferDatagram( *Tail = Packet; (*Tail)->Next = NULL; } + QuicPathIDRelease(PathID, QUIC_PATHID_REF_LOOKUP); } return FALSE; @@ -4031,9 +3591,24 @@ QuicConnRecvPrepareDecrypt( // QUIC_ENCRYPT_LEVEL EncryptLevel = QuicKeyTypeToEncryptLevel(Packet->KeyType); + + BOOLEAN FatalError = FALSE; + QUIC_PATHID* PathID = + QuicPathIDSetGetPathIDForPeer( + &Connection->PathIDs, + Packet->PathId, + FALSE, + &FatalError); + CXPLAT_DBG_ASSERT(!FatalError); + if (PathID == NULL) { + QuicPacketLogDrop(Connection, Packet, "No PathID"); + return FALSE; + } + CXPLAT_DBG_ASSERT(PathID->Packets[EncryptLevel] != NULL); + Packet->PacketNumber = QuicPktNumDecompress( - Connection->Packets[EncryptLevel]->NextRecvPacketNumber, + PathID->Packets[EncryptLevel]->NextRecvPacketNumber, CompressedPacketNumber, CompressedPacketNumberLength); Packet->PacketNumberSet = TRUE; @@ -4056,7 +3631,7 @@ QuicConnRecvPrepareDecrypt( return FALSE; } - QUIC_PACKET_SPACE* PacketSpace = Connection->Packets[QUIC_ENCRYPT_LEVEL_1_RTT]; + QUIC_PACKET_SPACE* PacketSpace = PathID->Packets[QUIC_ENCRYPT_LEVEL_1_RTT]; if (Packet->IsShortHeader && EncryptLevel == QUIC_ENCRYPT_LEVEL_1_RTT && Packet->SH->KeyPhase != PacketSpace->CurrentKeyPhase) { if (Packet->PacketNumber < PacketSpace->ReadKeyPhaseStartPacketNumber) { @@ -4087,11 +3662,13 @@ QuicConnRecvPrepareDecrypt( QUIC_STATUS Status = QuicCryptoGenerateNewKeys(Connection); if (QUIC_FAILED(Status)) { QuicPacketLogDrop(Connection, Packet, "Generate new packet keys"); + QuicPathIDRelease(PathID, QUIC_PATHID_REF_LOOKUP); return FALSE; } Packet->KeyType = QUIC_PACKET_KEY_1_RTT_NEW; } } + QuicPathIDRelease(PathID, QUIC_PATHID_REF_LOOKUP); return TRUE; } @@ -4133,10 +3710,18 @@ QuicConnRecvDecryptAndAuthenticate( CXPLAT_DBG_ASSERT(Packet->PacketId != 0); uint8_t Iv[CXPLAT_MAX_IV_LENGTH]; - QuicCryptoCombineIvAndPacketNumber( - Connection->Crypto.TlsState.ReadKeys[Packet->KeyType]->Iv, - (uint8_t*)&Packet->PacketNumber, - Iv); + if (Packet->PathId == 0) { + QuicCryptoCombineIvAndPacketNumber( + Connection->Crypto.TlsState.ReadKeys[Packet->KeyType]->Iv, + (uint8_t*)&Packet->PacketNumber, + Iv); + } else { + QuicCryptoCombineIvAndPathIDAndPacketNumber( + Connection->Crypto.TlsState.ReadKeys[Packet->KeyType]->Iv, + (uint8_t*)&Packet->PathId, + (uint8_t*)&Packet->PacketNumber, + Iv); + } // // Decrypt the payload with the appropriate key. @@ -4159,39 +3744,55 @@ QuicConnRecvDecryptAndAuthenticate( // Check for a stateless reset packet. // if (CanCheckForStatelessReset) { - for (CXPLAT_LIST_ENTRY* Entry = Connection->DestCids.Flink; - Entry != &Connection->DestCids; - Entry = Entry->Flink) { - // - // Loop through all our stored stateless reset tokens to see if - // we have a match. - // - QUIC_CID_LIST_ENTRY* DestCid = - CXPLAT_CONTAINING_RECORD( - Entry, - QUIC_CID_LIST_ENTRY, - Link); - if (DestCid->CID.HasResetToken && - !DestCid->CID.Retired && - memcmp( - DestCid->ResetToken, - PacketResetToken, - QUIC_STATELESS_RESET_TOKEN_LENGTH) == 0) { - QuicTraceLogVerbose( - PacketRxStatelessReset, - "[S][RX][-] SR %s", - QuicCidBufToStr(PacketResetToken, QUIC_STATELESS_RESET_TOKEN_LENGTH).Buffer); - QuicTraceLogConnInfo( - RecvStatelessReset, - Connection, - "Received stateless reset"); - QuicConnCloseLocally( - Connection, - QUIC_CLOSE_INTERNAL_SILENT | QUIC_CLOSE_QUIC_STATUS, - (uint64_t)QUIC_STATUS_ABORTED, - NULL); - return FALSE; + BOOLEAN Reset = FALSE; + + QUIC_PATHID* PathIDs[QUIC_ACTIVE_PATH_ID_LIMIT]; + uint8_t PathIDCount = QUIC_ACTIVE_PATH_ID_LIMIT; + QuicPathIDSetGetPathIDs(&Connection->PathIDs, PathIDs, &PathIDCount); + + for (uint8_t i = 0; i < PathIDCount ; i++) { + if (!Reset) { + for (CXPLAT_LIST_ENTRY* Entry = PathIDs[i]->DestCids.Flink; + Entry != &PathIDs[i]->DestCids; + Entry = Entry->Flink) { + // + // Loop through all our stored stateless reset tokens to see if + // we have a match. + // + QUIC_CID_LIST_ENTRY* DestCid = + CXPLAT_CONTAINING_RECORD( + Entry, + QUIC_CID_LIST_ENTRY, + Link); + if (DestCid->CID.HasResetToken && + !DestCid->CID.Retired && + memcmp( + DestCid->ResetToken, + PacketResetToken, + QUIC_STATELESS_RESET_TOKEN_LENGTH) == 0) { + QuicTraceLogVerbose( + PacketRxStatelessReset, + "[S][RX][-] SR %s", + QuicCidBufToStr(PacketResetToken, QUIC_STATELESS_RESET_TOKEN_LENGTH).Buffer); + Reset = TRUE; + break; + } + } } + QuicPathIDRelease(PathIDs[i], QUIC_PATHID_REF_LOOKUP); + } + + if (Reset) { + QuicTraceLogConnInfo( + RecvStatelessReset, + Connection, + "Received stateless reset"); + QuicConnCloseLocally( + Connection, + QUIC_CLOSE_INTERNAL_SILENT | QUIC_CLOSE_QUIC_STATUS, + (uint64_t)QUIC_STATUS_ABORTED, + NULL); + return FALSE; } } @@ -4254,8 +3855,10 @@ QuicConnRecvDecryptAndAuthenticate( // valid. // QUIC_ENCRYPT_LEVEL EncryptLevel = QuicKeyTypeToEncryptLevel(Packet->KeyType); + CXPLAT_DBG_ASSERT(Path->PathID != NULL); + CXPLAT_DBG_ASSERT(Path->PathID->Packets[EncryptLevel] != NULL); if (QuicAckTrackerAddPacketNumber( - &Connection->Packets[EncryptLevel]->AckTracker, + &Path->PathID->Packets[EncryptLevel]->AckTracker, Packet->PacketNumber)) { if (QuicTraceLogVerboseEnabled()) { @@ -4313,7 +3916,7 @@ QuicConnRecvDecryptAndAuthenticate( (IsVersion2 && Packet->LH->Type == QUIC_INITIAL_V2)) { if (!Connection->State.Connected && QuicConnIsClient(Connection) && - !QuicConnUpdateDestCid(Connection, Packet)) { + !QuicPathIDUpdateDestCid(Path->PathID, Packet)) { // // Client side needs to respond to the server's new source // connection ID that is received in the first Initial packet. @@ -4333,7 +3936,7 @@ QuicConnRecvDecryptAndAuthenticate( // if (Packet->IsShortHeader) { - QUIC_PACKET_SPACE* PacketSpace = Connection->Packets[QUIC_ENCRYPT_LEVEL_1_RTT]; + QUIC_PACKET_SPACE* PacketSpace = Path->PathID->Packets[QUIC_ENCRYPT_LEVEL_1_RTT]; if (Packet->KeyType == QUIC_PACKET_KEY_1_RTT_NEW) { QuicCryptoUpdateKeyPhase(Connection, FALSE); @@ -4505,11 +4108,12 @@ QuicConnRecvFrames( } case QUIC_FRAME_ACK: - case QUIC_FRAME_ACK_1: { + case QUIC_FRAME_ACK_1: + case QUIC_FRAME_PATH_ACK: + case QUIC_FRAME_PATH_ACK_1: { BOOLEAN InvalidAckFrame; - if (!QuicLossDetectionProcessAckFrame( - &Connection->LossDetection, - Path, + if (!QuicPathIDSetProcessAckFrame( + &Connection->PathIDs, Packet, EncryptLevel, FrameType, @@ -4897,9 +4501,10 @@ QuicConnRecvFrames( break; } - case QUIC_FRAME_NEW_CONNECTION_ID: { + case QUIC_FRAME_NEW_CONNECTION_ID: + case QUIC_FRAME_PATH_NEW_CONNECTION_ID: { QUIC_NEW_CONNECTION_ID_EX Frame; - if (!QuicNewConnectionIDFrameDecode(PayloadLength, Payload, &Offset, &Frame)) { + if (!QuicNewConnectionIDFrameDecode(FrameType, PayloadLength, Payload, &Offset, &Frame)) { QuicTraceEvent( ConnError, "[conn][%p] ERROR, %s.", @@ -4913,13 +4518,24 @@ QuicConnRecvFrames( break; // Ignore frame if we are closed. } + BOOLEAN FatalError = FALSE; + QUIC_PATHID *PathID = NULL; + PathID = QuicPathIDSetGetPathIDForPeer( + &Connection->PathIDs, + (uint32_t)Frame.PathID, + TRUE, + &FatalError); + if (PathID == NULL) { + return FALSE; + } + BOOLEAN ReplaceRetiredCids = FALSE; - if (Connection->RetirePriorTo < Frame.RetirePriorTo) { - Connection->RetirePriorTo = Frame.RetirePriorTo; - ReplaceRetiredCids = QuicConnOnRetirePriorToUpdated(Connection); + if (PathID->RetirePriorTo < Frame.RetirePriorTo) { + PathID->RetirePriorTo = Frame.RetirePriorTo; + ReplaceRetiredCids = QuicPathIDOnRetirePriorToUpdated(PathID); } - if (QuicConnGetDestCidFromSeq(Connection, Frame.Sequence, FALSE) == NULL) { + if (QuicPathIDGetDestCidFromSeq(PathID, Frame.Sequence, FALSE) == NULL) { // // Create the new destination connection ID. // @@ -4945,20 +4561,14 @@ QuicConnRecvFrames( DestCid->ResetToken, Frame.Buffer + Frame.Length, QUIC_STATELESS_RESET_TOKEN_LENGTH); - QuicTraceEvent( - ConnDestCidAdded, - "[conn][%p] (SeqNum=%llu) New Destination CID: %!CID!", - Connection, - DestCid->CID.SequenceNumber, - CASTED_CLOG_BYTEARRAY(DestCid->CID.Length, DestCid->CID.Data)); - CxPlatListInsertTail(&Connection->DestCids, &DestCid->Link); - Connection->DestCidCount++; + QuicPathIDAddDestCID(PathID, DestCid); + PathID->DestCidCount++; - if (DestCid->CID.SequenceNumber < Connection->RetirePriorTo) { - QuicConnRetireCid(Connection, DestCid); + if (DestCid->CID.SequenceNumber < PathID->RetirePriorTo) { + QuicPathIDRetireCid(PathID, DestCid); } - if (Connection->DestCidCount > QUIC_ACTIVE_CONNECTION_ID_LIMIT) { + if (PathID->DestCidCount > QUIC_ACTIVE_CONNECTION_ID_LIMIT) { QuicTraceEvent( ConnError, "[conn][%p] ERROR, %s.", @@ -4973,17 +4583,27 @@ QuicConnRecvFrames( } } - if (ReplaceRetiredCids && !QuicConnReplaceRetiredCids(Connection)) { + if (ReplaceRetiredCids && !QuicPathIDReplaceRetiredCids(PathID)) { return FALSE; } + if (Connection->State.MultipathNegotiated) { + QuicConnAssignPathIDs(Connection); + } + + if (QuicPathIDAssignCids(PathID)) { + QuicSendSetSendFlag(&Connection->Send, QUIC_CONN_SEND_FLAG_PATH_CHALLENGE); + } + AckEliciting = TRUE; + QuicPathIDRelease(PathID, QUIC_PATHID_REF_LOOKUP); break; } - case QUIC_FRAME_RETIRE_CONNECTION_ID: { + case QUIC_FRAME_RETIRE_CONNECTION_ID: + case QUIC_FRAME_PATH_RETIRE_CONNECTION_ID: { QUIC_RETIRE_CONNECTION_ID_EX Frame; - if (!QuicRetireConnectionIDFrameDecode(PayloadLength, Payload, &Offset, &Frame)) { + if (!QuicRetireConnectionIDFrameDecode(FrameType, PayloadLength, Payload, &Offset, &Frame)) { QuicTraceEvent( ConnError, "[conn][%p] ERROR, %s.", @@ -4996,17 +4616,26 @@ QuicConnRecvFrames( if (Closed) { break; // Ignore frame if we are closed. } + BOOLEAN FatalError = FALSE; + QUIC_PATHID* PathID = QuicPathIDSetGetPathIDForPeer( + &Connection->PathIDs, + (uint32_t)Frame.PathID, + FALSE, + &FatalError); + if (PathID == NULL) { + return FALSE; + } BOOLEAN IsLastCid; - QUIC_CID_HASH_ENTRY* SourceCid = - QuicConnGetSourceCidFromSeq( - Connection, + QUIC_CID_SLIST_ENTRY* SourceCid = + QuicPathIDGetSourceCidFromSeq( + PathID, Frame.Sequence, TRUE, &IsLastCid); if (SourceCid != NULL) { BOOLEAN CidAlreadyRetired = SourceCid->CID.Retired; - CXPLAT_FREE(SourceCid, QUIC_POOL_CIDHASH); + CXPLAT_FREE(SourceCid, QUIC_POOL_CIDSLIST); if (IsLastCid) { QuicTraceEvent( ConnError, @@ -5023,7 +4652,7 @@ QuicConnRecvFrames( // Replace the CID if we weren't the one to request it to be // retired in the first place. // - if (!QuicConnGenerateNewSourceCid(Connection, FALSE)) { + if (!QuicPathIDGenerateNewSourceCid(PathID, FALSE)) { break; } } @@ -5031,6 +4660,7 @@ QuicConnRecvFrames( AckEliciting = TRUE; Packet->HasNonProbingFrame = TRUE; + QuicPathIDRelease(PathID, QUIC_PATHID_REF_LOOKUP); break; } @@ -5081,6 +4711,20 @@ QuicConnRecvFrames( !memcmp(Frame.Data, TempPath->Challenge, sizeof(Frame.Data))) { QuicPerfCounterIncrement(QUIC_PERF_COUNTER_PATH_VALIDATED); QuicPathSetValid(Connection, TempPath, QUIC_PATH_VALID_PATH_RESPONSE); + if (Connection->State.MultipathNegotiated) { + QuicPathSetActive(Connection, TempPath); + + QUIC_CONNECTION_EVENT Event; + Event.Type = QUIC_CONNECTION_EVENT_PATH_ADDED; + Event.PATH_ADDED.PeerAddress = &TempPath->Route.RemoteAddress; + Event.PATH_ADDED.LocalAddress = &TempPath->Route.LocalAddress; + Event.PATH_ADDED.PathId = TempPath->PathID->ID; + QuicTraceLogConnVerbose( + IndicatePathAdded, + Connection, + "Indicating QUIC_CONNECTION_EVENT_PATH_ADDED"); + (void)QuicConnIndicateEvent(Connection, &Event); + } break; } } @@ -5089,6 +4733,237 @@ QuicConnRecvFrames( break; } + case QUIC_FRAME_PATH_ABANDON: { + if (!Connection->State.MultipathNegotiated) { + QuicTraceEvent( + ConnError, + "[conn][%p] ERROR, %s.", + Connection, + "Received PATH_ABANDON frame when not negotiated"); + QuicConnTransportError(Connection, QUIC_ERROR_PROTOCOL_VIOLATION); + return FALSE; + } + QUIC_PATH_ABANDON_EX Frame; + if (!QuicPathAbandonFrameDecode(PayloadLength, Payload, &Offset, &Frame)) { + QuicTraceEvent( + ConnError, + "[conn][%p] ERROR, %s.", + Connection, + "Decoding PATH_ABANDON frame"); + QuicConnTransportError(Connection, QUIC_ERROR_FRAME_ENCODING_ERROR); + return FALSE; + } + + if (Closed) { + break; // Ignore frame if we are closed. + } + + BOOLEAN FatalError = FALSE; + QUIC_PATHID *PathID = QuicPathIDSetGetPathIDForPeer( + &Connection->PathIDs, + (uint32_t)Frame.PathID, + FALSE, + &FatalError); + if (PathID == NULL) { + break; + } + CXPLAT_DBG_ASSERT(PathID->Path != NULL); + + PathID->Path->RemoteClose = TRUE; + if (!PathID->Path->LocalClose) { + PathID->Path->LocalClose = TRUE; + PathID->Path->SendAbandon = TRUE; + QuicSendSetSendFlag(&Connection->Send, QUIC_CONN_SEND_FLAG_PATH_ABANDON); + } + + if (PathID->Path->LocalCloseAcked) { + PathID->Flags.Abandoned = TRUE; + } + + if (!PathID->Flags.Closed) { + uint64_t ThreePto = + QuicLossDetectionComputeProbeTimeout( + &PathID->LossDetection, + PathID->Path, + 3); + PathID->Flags.WaitClose = TRUE; + uint64_t TimeNow = CxPlatTimeUs64(); + PathID->CloseTime = TimeNow + ThreePto; + QuicConnTimerSetEx( + Connection, + QUIC_CONN_TIMER_PATH_CLOSE, + ThreePto, + TimeNow); + } + + AckEliciting = TRUE; + QuicPathIDRelease(PathID, QUIC_PATHID_REF_LOOKUP); + break; + } + + case QUIC_FRAME_PATH_BACKUP: { + if (!Connection->State.MultipathNegotiated) { + QuicTraceEvent( + ConnError, + "[conn][%p] ERROR, %s.", + Connection, + "Received PATH_BACKUP frame when not negotiated"); + QuicConnTransportError(Connection, QUIC_ERROR_PROTOCOL_VIOLATION); + return FALSE; + } + QUIC_PATH_BACKUP_EX Frame; + if (!QuicPathBackupFrameDecode(PayloadLength, Payload, &Offset, &Frame)) { + QuicTraceEvent( + ConnError, + "[conn][%p] ERROR, %s.", + Connection, + "Decoding PATH_BACKUP frame"); + QuicConnTransportError(Connection, QUIC_ERROR_FRAME_ENCODING_ERROR); + return FALSE; + } + + if (Closed) { + break; // Ignore frame if we are closed. + } + + BOOLEAN FatalError = FALSE; + QUIC_PATHID *PathID = QuicPathIDSetGetPathIDForPeer( + &Connection->PathIDs, + (uint32_t)Frame.PathID, + FALSE, + &FatalError); + if (PathID == NULL) { + break; + } + CXPLAT_DBG_ASSERT(PathID->Path != NULL); + + if (Frame.StatusSequenceNumber < PathID->StatusRecvSeq) { + // ignore the frame + QuicPathIDRelease(PathID, QUIC_PATHID_REF_LOOKUP); + break; + } + PathID->StatusRecvSeq = Frame.StatusSequenceNumber + 1; + + if (PathID->Path->IsActive) { + // Change status of the path to backup + PathID->Path->IsActive = FALSE; + QUIC_CONNECTION_EVENT Event; + Event.Type = QUIC_CONNECTION_EVENT_PATH_STATUS_CHANGED; + Event.PATH_STATUS_CHANGED.PeerAddress = &PathID->Path->Route.RemoteAddress; + Event.PATH_STATUS_CHANGED.LocalAddress = &PathID->Path->Route.LocalAddress; + Event.PATH_STATUS_CHANGED.PathId = PathID->ID; + Event.PATH_STATUS_CHANGED.IsActive = FALSE; + QuicTraceLogConnVerbose( + IndicatePathStatusChanged, + Connection, + "Indicating QUIC_CONNECTION_EVENT_PATH_STATUS_CHANGED"); + (void)QuicConnIndicateEvent(Connection, &Event); + } + + AckEliciting = TRUE; + QuicPathIDRelease(PathID, QUIC_PATHID_REF_LOOKUP); + break; + } + + case QUIC_FRAME_PATH_AVAILABLE: { + if (!Connection->State.MultipathNegotiated) { + QuicTraceEvent( + ConnError, + "[conn][%p] ERROR, %s.", + Connection, + "Received PATH_AVAILABLE frame when not negotiated"); + QuicConnTransportError(Connection, QUIC_ERROR_PROTOCOL_VIOLATION); + return FALSE; + } + QUIC_PATH_AVAILABLE_EX Frame; + if (!QuicPathAvailableFrameDecode(PayloadLength, Payload, &Offset, &Frame)) { + QuicTraceEvent( + ConnError, + "[conn][%p] ERROR, %s.", + Connection, + "Decoding PATH_AVAILABLE frame"); + QuicConnTransportError(Connection, QUIC_ERROR_FRAME_ENCODING_ERROR); + return FALSE; + } + + if (Closed) { + break; // Ignore frame if we are closed. + } + + BOOLEAN FatalError = FALSE; + QUIC_PATHID *PathID = QuicPathIDSetGetPathIDForPeer( + &Connection->PathIDs, + (uint32_t)Frame.PathID, + FALSE, + &FatalError); + if (PathID == NULL) { + break; + } + CXPLAT_DBG_ASSERT(PathID->Path != NULL); + + if (Frame.StatusSequenceNumber < PathID->StatusRecvSeq) { + // ignore the frame + QuicPathIDRelease(PathID, QUIC_PATHID_REF_LOOKUP); + break; + } + PathID->StatusRecvSeq = Frame.StatusSequenceNumber + 1; + + if (!PathID->Path->IsActive) { + // Change status of the path to available (active) + PathID->Path->IsActive = TRUE; + QUIC_CONNECTION_EVENT Event; + Event.Type = QUIC_CONNECTION_EVENT_PATH_STATUS_CHANGED; + Event.PATH_STATUS_CHANGED.PeerAddress = &PathID->Path->Route.RemoteAddress; + Event.PATH_STATUS_CHANGED.LocalAddress = &PathID->Path->Route.LocalAddress; + Event.PATH_STATUS_CHANGED.PathId = PathID->ID; + Event.PATH_STATUS_CHANGED.IsActive = TRUE; + QuicTraceLogConnVerbose( + IndicatePathStatusChanged, + Connection, + "Indicating QUIC_CONNECTION_EVENT_PATH_STATUS_CHANGED"); + (void)QuicConnIndicateEvent(Connection, &Event); + } + + AckEliciting = TRUE; + QuicPathIDRelease(PathID, QUIC_PATHID_REF_LOOKUP); + break; + } + + case QUIC_FRAME_MAX_PATH_ID: { + QUIC_MAX_PATH_ID_EX Frame; + if (!QuicMaxPathIDFrameDecode(PayloadLength, Payload, &Offset, &Frame)) { + QuicTraceEvent( + ConnError, + "[conn][%p] ERROR, %s.", + Connection, + "Decoding MAX_PATH_ID frame"); + QuicConnTransportError(Connection, QUIC_ERROR_FRAME_ENCODING_ERROR); + return FALSE; + } + + if (Closed) { + break; // Ignore frame if we are closed. + } + + if (Frame.MaximumPathID > QUIC_TP_MAX_PATH_ID_MAX) { + QuicConnTransportError(Connection, QUIC_ERROR_PROTOCOL_VIOLATION); + break; + } + + if (Frame.MaximumPathID < Connection->PathIDs.PeerMaxPathID) { + QuicConnTransportError(Connection, QUIC_ERROR_PROTOCOL_VIOLATION); + break; + } + + QuicPathIDSetUpdateMaxPathID( + &Connection->PathIDs, + (uint32_t)Frame.MaximumPathID); + + AckEliciting = TRUE; + Packet->HasNonProbingFrame = TRUE; + break; + } + case QUIC_FRAME_CONNECTION_CLOSE: case QUIC_FRAME_CONNECTION_CLOSE_1: { QUIC_CONNECTION_CLOSE_EX Frame; @@ -5302,7 +5177,7 @@ QuicConnRecvFrames( Done: if (UpdatedFlowControl) { - QuicConnLogOutFlowStats(Connection); + QuicConnLogOutFlowStats(Path->PathID); } if (Connection->State.ShutdownComplete || Connection->State.HandleClosed) { @@ -5312,10 +5187,10 @@ QuicConnRecvFrames( PtkConnPre(Connection), Packet->PacketNumber); - } else if (Connection->Packets[EncryptLevel] != NULL) { + } else if (Path->PathID->Packets[EncryptLevel] != NULL) { - if (Connection->Packets[EncryptLevel]->NextRecvPacketNumber <= Packet->PacketNumber) { - Connection->Packets[EncryptLevel]->NextRecvPacketNumber = Packet->PacketNumber + 1; + if (Path->PathID->Packets[EncryptLevel]->NextRecvPacketNumber <= Packet->PacketNumber) { + Path->PathID->Packets[EncryptLevel]->NextRecvPacketNumber = Packet->PacketNumber + 1; Packet->NewLargestPacketNumber = TRUE; } @@ -5329,7 +5204,7 @@ QuicConnRecvFrames( } QuicAckTrackerAckPacket( - &Connection->Packets[EncryptLevel]->AckTracker, + &Path->PathID->Packets[EncryptLevel]->AckTracker, Packet->PacketNumber, RecvTime, ECN, @@ -5351,9 +5226,9 @@ QuicConnRecvPostProcessing( { BOOLEAN PeerUpdatedCid = FALSE; if (Packet->DestCidLen != 0) { - QUIC_CID_HASH_ENTRY* SourceCid = - QuicConnGetSourceCidFromBuf( - Connection, + QUIC_CID_SLIST_ENTRY* SourceCid = + QuicPathIDGetSourceCidFromBuf( + (*Path)->PathID, Packet->DestCidLen, Packet->DestCid); if (SourceCid != NULL && !SourceCid->CID.UsedByPeer) { @@ -5372,7 +5247,8 @@ QuicConnRecvPostProcessing( if (!(*Path)->GotValidPacket) { (*Path)->GotValidPacket = TRUE; - if (!(*Path)->IsActive) { + if (!(*Path)->IsActive && + QuicConnIsServer(Connection)) { // // This is the first valid packet received on this non-active path. @@ -5386,7 +5262,7 @@ QuicConnRecvPostProcessing( // TODO - What if the peer (client) only sends a single CID and // rebinding happens? Should we support using the same CID over? // - QUIC_CID_LIST_ENTRY* NewDestCid = QuicConnGetUnusedDestCid(Connection); + QUIC_CID_LIST_ENTRY* NewDestCid = QuicPathIDGetUnusedDestCid((*Path)->PathID); if (NewDestCid == NULL) { QuicTraceEvent( ConnError, @@ -5438,13 +5314,15 @@ QuicConnRecvPostProcessing( // respond to this change with a change of our own. // if (!(*Path)->InitiatedCidUpdate) { - QuicConnRetireCurrentDestCid(Connection, *Path); + QuicPathIDRetireCurrentDestCid((*Path)->PathID, *Path); } else { (*Path)->InitiatedCidUpdate = FALSE; } } - if (Packet->HasNonProbingFrame && + if (QuicConnIsServer(Connection) && + !Connection->State.MultipathNegotiated && + Packet->HasNonProbingFrame && Packet->NewLargestPacketNumber && !(*Path)->IsActive) { // @@ -5601,6 +5479,7 @@ QuicConnRecvDatagrams( QUIC_RX_PACKET* Batch[QUIC_MAX_CRYPTO_BATCH_COUNT]; uint8_t Cipher[CXPLAT_HP_SAMPLE_LENGTH * QUIC_MAX_CRYPTO_BATCH_COUNT]; QUIC_PATH* CurrentPath = NULL; + uint8_t CurrentPathID = 0; QUIC_RX_PACKET* Packet; while ((Packet = Packets) != NULL) { @@ -5623,6 +5502,13 @@ QuicConnRecvDatagrams( CxPlatUpdateRoute(&DatagramPath->Route, Packet->Route); + if (CurrentPath != NULL) { + // + // The current path may be moved. + // + uint8_t PathIndex; + CurrentPath = QuicConnGetPathByID(Connection, CurrentPathID, &PathIndex); + } if (DatagramPath != CurrentPath) { if (BatchCount != 0) { // @@ -5640,6 +5526,7 @@ QuicConnRecvDatagrams( BatchCount = 0; } CurrentPath = DatagramPath; + CurrentPathID = CurrentPath->ID; } if (!IsDeferred) { @@ -5815,20 +5702,25 @@ QuicConnRecvDatagrams( QuicConnSilentlyAbort(Connection); } - // - // Any new paths created here were created before packet validation. Now - // remove any non-active paths that didn't get any valid packets. - // NB: Traversing the array backwards is simpler and more efficient here due - // to the array shifting that happens in QuicPathRemove. - // - for (uint8_t i = Connection->PathsCount - 1; i > 0; --i) { - if (!Connection->Paths[i].GotValidPacket) { - QuicTraceLogConnInfo( - PathDiscarded, - Connection, - "Removing invalid path[%hhu]", - Connection->Paths[i].ID); - QuicPathRemove(Connection, i); + if (QuicConnIsServer(Connection)) { + // + // Any new paths created here were created before packet validation. Now + // remove any non-active paths that didn't get any valid packets. + // NB: Traversing the array backwards is simpler and more efficient here due + // to the array shifting that happens in QuicPathRemove. + // + for (uint8_t i = Connection->PathsCount - 1; i > 0; --i) { + if (!Connection->Paths[i].GotValidPacket) { + QuicTraceLogConnInfo( + PathDiscarded, + Connection, + "Removing invalid path[%hhu]", + Connection->Paths[i].ID); + CXPLAT_DBG_ASSERT(Connection->Paths[i].Binding != NULL); + QuicLibraryReleaseBinding(Connection->Paths[i].Binding); + Connection->Paths[i].Binding = NULL; + QuicPathRemove(Connection, i); + } } } @@ -5838,7 +5730,7 @@ QuicConnRecvDatagrams( CXPLAT_DBG_ASSERT(!Connection->Registration->NoPartitioning); CXPLAT_DBG_ASSERT(RecvState.PartitionIndex != QuicPartitionIdGetIndex(Connection->PartitionID)); Connection->PartitionID = QuicPartitionIdCreate(RecvState.PartitionIndex); - QuicConnGenerateNewSourceCids(Connection, TRUE); + QuicPathIDSetGenerateNewSourceCids(&Connection->PathIDs, TRUE); Connection->State.UpdateWorker = TRUE; } } @@ -5893,7 +5785,8 @@ QuicConnDiscardDeferred0Rtt( { QUIC_RX_PACKET* ReleaseChain = NULL; QUIC_RX_PACKET** ReleaseChainTail = &ReleaseChain; - QUIC_PACKET_SPACE* Packets = Connection->Packets[QUIC_ENCRYPT_LEVEL_1_RTT]; + CXPLAT_DBG_ASSERT(Connection->Paths[0].PathID->ID == 0); + QUIC_PACKET_SPACE* Packets = Connection->Paths[0].PathID->Packets[QUIC_ENCRYPT_LEVEL_1_RTT]; CXPLAT_DBG_ASSERT(Packets != NULL); QUIC_RX_PACKET* DeferredPackets = Packets->DeferredPackets; @@ -5934,7 +5827,8 @@ QuicConnFlushDeferred( QUIC_ENCRYPT_LEVEL EncryptLevel = QuicKeyTypeToEncryptLevel((QUIC_PACKET_KEY_TYPE)i); - QUIC_PACKET_SPACE* Packets = Connection->Packets[EncryptLevel]; + CXPLAT_DBG_ASSERT(Connection->Paths[0].PathID->ID == 0); + QUIC_PACKET_SPACE* Packets = Connection->Paths[0].PathID->Packets[EncryptLevel]; if (Packets->DeferredPackets != NULL) { QUIC_RX_PACKET* DeferredPackets = Packets->DeferredPackets; @@ -6020,11 +5914,17 @@ QuicConnProcessRouteCompletion( "Route resolution failed on Path[%hhu]. Switching paths...", PathId); QuicPathSetActive(Connection, &Connection->Paths[1]); + CXPLAT_DBG_ASSERT(Connection->Paths[1].Binding != NULL); + QuicLibraryReleaseBinding(Connection->Paths[1].Binding); + Connection->Paths[1].Binding = NULL; QuicPathRemove(Connection, 1); if (!QuicSendFlush(&Connection->Send)) { QuicSendQueueFlush(&Connection->Send, REASON_ROUTE_COMPLETION); } } else { + CXPLAT_DBG_ASSERT(Connection->Paths[PathIndex].Binding != NULL); + QuicLibraryReleaseBinding(Connection->Paths[PathIndex].Binding); + Connection->Paths[PathIndex].Binding = NULL; QuicPathRemove(Connection, PathIndex); } } @@ -6071,7 +5971,7 @@ QuicConnResetIdleTimeout( // uint64_t MinIdleTimeoutMs = US_TO_MS(QuicLossDetectionComputeProbeTimeout( - &Connection->LossDetection, + &Path->PathID->LossDetection, Path, QUIC_CLOSE_PTO_COUNT)); if (IdleTimeoutMs < MinIdleTimeoutMs) { @@ -6155,6 +6055,320 @@ QuicConnUpdatePeerPacketTolerance( } } +_IRQL_requires_max_(PASSIVE_LEVEL) +BOOLEAN +QuicConnAssignPathIDs( + _In_ QUIC_CONNECTION* Connection + ) +{ + BOOLEAN Assigned = FALSE; + + CXPLAT_DBG_ASSERT(Connection->PathsCount <= QUIC_MAX_PATH_COUNT); + for (uint8_t i = 0; i < Connection->PathsCount; ++i) { + QUIC_PATH* Path = &Connection->Paths[i]; + if (Path->PathID != NULL || !Path->InUse) { + continue; + } + + QUIC_PATHID* PathID = QuicPathIDSetGetUnusedPathID(&Connection->PathIDs); + if (PathID == NULL) { + return Assigned; + } + + QuicPathIDAddRef(PathID, QUIC_PATHID_REF_PATH); + Path->PathID = PathID; + PathID->Path = Path; + QuicCongestionControlInitialize(&PathID->CongestionControl, &Connection->Settings); + Assigned = TRUE; + QuicPathIDRelease(Path->PathID, QUIC_PATHID_REF_LOOKUP); + } + + return Assigned; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +QUIC_STATUS +QuicConnOpenNewPath( + _In_ QUIC_CONNECTION* Connection, + _In_ QUIC_PATH* Path + ) +{ + CXPLAT_DBG_ASSERT(Connection->State.RemoteAddressSet); + CXPLAT_DBG_ASSERT(Connection->Configuration != NULL); + + CXPLAT_UDP_CONFIG UdpConfig = {0}; + UdpConfig.LocalAddress = &Path->Route.LocalAddress; + UdpConfig.RemoteAddress = &Connection->Paths[0].Route.RemoteAddress; + UdpConfig.Flags = Connection->State.ShareBinding ? CXPLAT_SOCKET_FLAG_SHARE : 0; + UdpConfig.InterfaceIndex = 0; +#ifdef QUIC_COMPARTMENT_ID + UdpConfig.CompartmentId = Connection->Configuration->CompartmentId; +#endif +#ifdef QUIC_OWNING_PROCESS + UdpConfig.OwningProcess = Connection->Configuration->OwningProcess; +#endif + + QUIC_BINDING* NewBinding = NULL; + QUIC_STATUS Status = QuicLibraryGetBinding(&UdpConfig, &NewBinding); + if (QUIC_FAILED(Status)) { + return Status; + } + + Path->Binding = NewBinding; + + QuicBindingGetLocalAddress( + Path->Binding, + &Path->Route.LocalAddress); + + if (Path != &Connection->Paths[0]) { + CxPlatCopyMemory(&Path->Route.RemoteAddress, + &Connection->Paths[0].Route.RemoteAddress, + sizeof(QUIC_ADDR)); + if (Connection->State.MultipathNegotiated) { + Path->PathID = QuicPathIDSetGetUnusedPathID(&Connection->PathIDs); + if (Path->PathID != NULL) { + QuicPathIDAddRef(Path->PathID, QUIC_PATHID_REF_PATH); + Path->PathID->Flags.InUse = TRUE; + Path->PathID->Path = Path; + QuicCongestionControlInitialize(&Path->PathID->CongestionControl, &Connection->Settings); + QuicPathIDRelease(Path->PathID, QUIC_PATHID_REF_LOOKUP); + } + } else { + QuicPathIDAddRef(Connection->Paths[0].PathID, QUIC_PATHID_REF_PATH); + Path->PathID = Connection->Paths[0].PathID; + } + } + + if (!Connection->State.ShareBinding) { + QUIC_CID_SLIST_ENTRY* SourceCid = QuicCidNewNullSource(Path->PathID); + if (SourceCid == NULL) { + return QUIC_STATUS_OUT_OF_MEMORY; + } + + Path->PathID->NextSourceCidSequenceNumber++; + QuicPathIDAddSourceCID(Path->PathID, SourceCid, FALSE); + + if (!QuicBindingAddSourceConnectionID(NewBinding, SourceCid)) { + return QUIC_STATUS_OUT_OF_MEMORY; + } + } else { + if (!QuicBindingAddAllSourceConnectionIDs(NewBinding, Connection)) { + QuicPathIDSetGenerateNewSourceCids(&Connection->PathIDs, TRUE); + } + } + + QuicTraceEvent( + ConnLocalAddrAdded, + "[conn][%p] New Local IP: %!ADDR!", + Connection, + CASTED_CLOG_BYTEARRAY(sizeof(Path->Route.LocalAddress), &Path->Route.LocalAddress)); + + + QUIC_CID_LIST_ENTRY* NewDestCid = Path->PathID != NULL ? + QuicPathIDGetUnusedDestCid(Path->PathID) : + NULL; + // + // If we can't get a unused CID, we defer sending a path challange until we receieve a new CID. + // + if (NewDestCid != NULL) { + Path->DestCid = NewDestCid; + QUIC_CID_SET_PATH(Connection, Path->DestCid, Path); + Path->DestCid->CID.UsedLocally = TRUE; + + CXPLAT_DBG_ASSERT(Path->DestCid != NULL); + QuicPathValidate(Path); + Path->SendChallenge = TRUE; + Path->PathValidationStartTime = CxPlatTimeUs64(); + + CxPlatRandom(sizeof(Path->Challenge), Path->Challenge); + } + + return QUIC_STATUS_SUCCESS; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +BOOLEAN +QuicConnOpenNewPaths( + _In_ QUIC_CONNECTION* Connection + ) +{ + BOOLEAN Assigned = FALSE; + + CXPLAT_DBG_ASSERT(Connection->PathsCount > 0); + for (uint8_t i = 1; i < Connection->PathsCount; ++i) { + if (Connection->Paths[i].Binding == NULL) { + QUIC_STATUS Status = QuicConnOpenNewPath(Connection, &Connection->Paths[i]); + if (QUIC_FAILED(Status)) { + CXPLAT_DBG_ASSERT(i != 0); + if (Connection->Paths[i].Binding != NULL) { + QuicLibraryReleaseBinding(Connection->Paths[i].Binding); + Connection->Paths[i].Binding = NULL; + } + QuicPathRemove(Connection, i--); + } else { + if (Connection->Paths[i].DestCid != NULL) { + Assigned = TRUE; + } + } + } + } + return Assigned; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +static +QUIC_STATUS +QuicConnAddLocalAddress( + _In_ QUIC_CONNECTION* Connection, + _In_ QUIC_ADDR* LocalAddress + ) +{ + if (QuicConnIsServer(Connection)) { + return QUIC_STATUS_NOT_SUPPORTED; + } + + if (Connection->State.ClosedLocally) { + return QUIC_STATUS_INVALID_STATE; + } + + if (!QuicAddrIsValid(LocalAddress)) { + return QUIC_STATUS_INVALID_PARAMETER; + } + + BOOLEAN AddrInUse = FALSE; + if (Connection->State.LocalAddressSet) { + for (uint8_t i = 0; i < Connection->PathsCount; ++i) { + if (QuicAddrCompare( + &Connection->Paths[i].Route.LocalAddress, + LocalAddress)) { + AddrInUse = TRUE; + break; + } + } + } + + if (AddrInUse) { + return QUIC_STATUS_ADDRESS_IN_USE; + } + + if (Connection->PathsCount == QUIC_MAX_PATH_COUNT) { + // + // Already tracking the maximum number of paths, and can't free + // any more. + // + return QUIC_STATUS_OUT_OF_MEMORY; + } + + QUIC_PATH* Path = NULL; + if (!Connection->State.LocalAddressSet) { + Path = &Connection->Paths[0]; + Connection->State.LocalAddressSet = TRUE; + } else { + if (Connection->PathsCount > 1) { + // + // Make room for the new path (at index 1). + // + CxPlatMoveMemory( + &Connection->Paths[2], + &Connection->Paths[1], + (Connection->PathsCount - 1) * sizeof(QUIC_PATH)); + } + Path = &Connection->Paths[1]; + QuicPathInitialize(Connection, Path); + Path->Allowance = UINT32_MAX; + Connection->PathsCount++; + } + + CxPlatCopyMemory(&Path->Route.LocalAddress, LocalAddress, sizeof(QUIC_ADDR)); + + if (!(Connection->State.Started && Connection->State.HandshakeConfirmed)) { + return QUIC_STATUS_SUCCESS; + } + + CXPLAT_DBG_ASSERT(Path != &Connection->Paths[0]); + + QUIC_STATUS Status = QuicConnOpenNewPath(Connection, Path); + if (QUIC_FAILED(Status)) { + if (Path->Binding != NULL) { + QuicLibraryReleaseBinding(Path->Binding); + Path->Binding = NULL; + } + QuicPathRemove(Connection, 1); + } else { + if (Path->DestCid != NULL) { + QuicSendSetSendFlag(&Connection->Send, QUIC_CONN_SEND_FLAG_PATH_CHALLENGE); + } + } + + return Status; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +static +QUIC_STATUS +QuicConnRemoveLocalAddress( + _In_ QUIC_CONNECTION* Connection, + _In_ QUIC_ADDR* LocalAddress + ) +{ + if (QuicConnIsServer(Connection)) { + return QUIC_STATUS_INVALID_STATE; + } + + if (!QuicAddrIsValid(LocalAddress)) { + return QUIC_STATUS_INVALID_PARAMETER; + } + + if (!Connection->State.LocalAddressSet) { + return QUIC_STATUS_NOT_FOUND; + } + + uint8_t PathIndex = Connection->PathsCount; + for (uint8_t i = 0; i < Connection->PathsCount; ++i) { + if (QuicAddrCompare( + &Connection->Paths[i].Route.LocalAddress, + LocalAddress)) { + PathIndex = i; + break; + } + } + + if (PathIndex == Connection->PathsCount) { + return QUIC_STATUS_NOT_FOUND; + } + + QUIC_PATH* Path = &Connection->Paths[PathIndex]; + + if (!Connection->State.MultipathNegotiated) { + if (Path->IsActive && Connection->State.Started) { + return QUIC_STATUS_INVALID_STATE; + } + + if (Path->DestCid != NULL) { + QuicPathIDRetireCid(Path->PathID, Path->DestCid); + } + + if (Path->Binding != NULL) { + QuicBindingRemoveAllSourceConnectionIDs(Path->Binding, Connection); + QuicLibraryReleaseBinding(Path->Binding); + Path->Binding = NULL; + } + + if (Connection->PathsCount == 1) { + CXPLAT_DBG_ASSERT(!Connection->State.Started); + Connection->State.LocalAddressSet = FALSE; + } else { + QuicPathRemove(Connection, PathIndex); + } + } else { + Path->LocalClose = TRUE; + Path->SendAbandon = TRUE; + QuicSendSetSendFlag(&Connection->Send, QUIC_CONN_SEND_FLAG_PATH_ABANDON); + } + + return QUIC_STATUS_SUCCESS; +} + #define QUIC_CONN_BAD_START_STATE(CONN) (CONN->State.Started || CONN->State.ClosedLocally) _IRQL_requires_max_(PASSIVE_LEVEL) @@ -6197,18 +6411,21 @@ QuicConnParamSet( break; } - Connection->State.LocalAddressSet = TRUE; - CxPlatCopyMemory(&Connection->Paths[0].Route.LocalAddress, Buffer, sizeof(QUIC_ADDR)); - QuicTraceEvent( - ConnLocalAddrAdded, - "[conn][%p] New Local IP: %!ADDR!", - Connection, - CASTED_CLOG_BYTEARRAY(sizeof(Connection->Paths[0].Route.LocalAddress), &Connection->Paths[0].Route.LocalAddress)); - - if (Connection->State.Started) { + if (!Connection->State.Started) { + Connection->State.LocalAddressSet = TRUE; + CxPlatCopyMemory(&Connection->Paths[0].Route.LocalAddress, Buffer, sizeof(QUIC_ADDR)); + } else { + CXPLAT_DBG_ASSERT(Connection->State.RemoteAddressSet); + QUIC_PATH* Path = QuicConnGetPathByAddress(Connection, LocalAddress, &Connection->Paths[0].Route.RemoteAddress); + if (Path != NULL) { + if (!Path->IsActive) { + QuicPathSetActive(Connection, Path); + } + Status = QUIC_STATUS_SUCCESS; + break; + } CXPLAT_DBG_ASSERT(Connection->Paths[0].Binding); - CXPLAT_DBG_ASSERT(Connection->State.RemoteAddressSet); CXPLAT_DBG_ASSERT(Connection->Configuration != NULL); QUIC_BINDING* OldBinding = Connection->Paths[0].Binding; @@ -6232,14 +6449,32 @@ QuicConnParamSet( Connection->Paths[0].Binding = OldBinding; break; } + + if (!QuicPathIDRetireCurrentDestCid(Connection->Paths[0].PathID, &Connection->Paths[0])) { + QuicLibraryReleaseBinding(Connection->Paths[0].Binding); + Connection->Paths[0].Binding = OldBinding; + Status = QUIC_STATUS_INVALID_STATE; + } + Connection->Paths[0].Route.Queue = NULL; // // TODO - Need to free any queued recv packets from old binding. // - QuicBindingMoveSourceConnectionIDs( - OldBinding, Connection->Paths[0].Binding, Connection); + if (!Connection->State.ShareBinding) { + if (!QuicBindingAddAllSourceConnectionIDs(Connection->Paths[0].Binding, Connection)) { + QuicLibraryReleaseBinding(Connection->Paths[0].Binding); + Connection->Paths[0].Binding = OldBinding; + Status = QUIC_STATUS_OUT_OF_MEMORY; + break; + } + } else { + if (!QuicBindingAddAllSourceConnectionIDs(Connection->Paths[0].Binding, Connection)) { + QuicPathIDSetGenerateNewSourceCids(&Connection->PathIDs, TRUE); + } + } + QuicBindingRemoveAllSourceConnectionIDs(OldBinding, Connection); QuicLibraryReleaseBinding(OldBinding); QuicTraceEvent( @@ -6258,6 +6493,8 @@ QuicConnParamSet( Connection, CASTED_CLOG_BYTEARRAY(sizeof(Connection->Paths[0].Route.LocalAddress), &Connection->Paths[0].Route.LocalAddress)); + QuicCongestionControlReset(&Connection->Paths[0].PathID->CongestionControl, FALSE); + QuicSendSetSendFlag(&Connection->Send, QUIC_CONN_SEND_FLAG_PING); } @@ -6623,6 +6860,71 @@ QuicConnParamSet( return QUIC_STATUS_SUCCESS; } + case QUIC_PARAM_CONN_ADD_LOCAL_ADDRESS: { + + if (BufferLength != sizeof(QUIC_ADDR)) { + Status = QUIC_STATUS_INVALID_PARAMETER; + break; + } + + Status = QuicConnAddLocalAddress(Connection, (QUIC_ADDR*)Buffer); + break; + } + + case QUIC_PARAM_CONN_REMOVE_LOCAL_ADDRESS: { + + if (BufferLength != sizeof(QUIC_ADDR)) { + Status = QUIC_STATUS_INVALID_PARAMETER; + break; + } + + Status = QuicConnRemoveLocalAddress(Connection, (QUIC_ADDR*)Buffer); + break; + } + + case QUIC_PARAM_CONN_PATH_STATUS: + if (BufferLength != sizeof(QUIC_PATH_STATUS)) { + Status = QUIC_STATUS_INVALID_PARAMETER; + break; + } + + if (!Connection->State.MultipathNegotiated) { + Status = QUIC_STATUS_INVALID_STATE; + break; + } + + QUIC_PATH_STATUS* PathStatus = (QUIC_PATH_STATUS*)Buffer; + QUIC_PATH* Path = NULL; + for (uint8_t i = 0; i < Connection->PathsCount; ++i) { + if (QuicAddrCompare( + &PathStatus->LocalAddress, + &Connection->Paths[i].Route.LocalAddress) && + QuicAddrCompare( + &PathStatus->PeerAddress, + &Connection->Paths[i].Route.RemoteAddress) && + PathStatus->PathId == Connection->Paths[i].PathID->ID) { + Path = &Connection->Paths[i]; + break; + } + } + + if (Path == NULL) { + Status = QUIC_STATUS_INVALID_PARAMETER; + break; + } + BOOLEAN PrevIsActive = Path->IsActive; + Path->IsActive = PathStatus->Active; + if (PrevIsActive != Path->IsActive) { + Path->SendStatus = TRUE; + if (Path->IsActive) { + QuicSendSetSendFlag(&Connection->Send, QUIC_CONN_SEND_FLAG_PATH_AVAILABLE); + } else { + QuicSendSetSendFlag(&Connection->Send, QUIC_CONN_SEND_FLAG_PATH_BACKUP); + } + } + Status = QUIC_STATUS_SUCCESS; + break; + // // Private // @@ -6630,8 +6932,8 @@ QuicConnParamSet( case QUIC_PARAM_CONN_FORCE_KEY_UPDATE: if (!Connection->State.Connected || - Connection->Packets[QUIC_ENCRYPT_LEVEL_1_RTT] == NULL || - Connection->Packets[QUIC_ENCRYPT_LEVEL_1_RTT]->AwaitingKeyPhaseConfirmation || + Connection->Paths[0].PathID->Packets[QUIC_ENCRYPT_LEVEL_1_RTT] == NULL || + Connection->Paths[0].PathID->Packets[QUIC_ENCRYPT_LEVEL_1_RTT]->AwaitingKeyPhaseConfirmation || !Connection->State.HandshakeConfirmed) { Status = QUIC_STATUS_INVALID_STATE; break; @@ -6670,7 +6972,7 @@ QuicConnParamSet( Connection, "Forcing destination CID update"); - if (!QuicConnRetireCurrentDestCid(Connection, &Connection->Paths[0])) { + if (!QuicPathIDRetireCurrentDestCid(Connection->Paths[0].PathID, &Connection->Paths[0])) { Status = QUIC_STATUS_INVALID_STATE; break; } @@ -6729,6 +7031,36 @@ QuicConnParamSet( break; #endif +#if QUIC_TEST_MANUAL_CONN_ID_GENERATION + case QUIC_PARAM_CONN_DISABLE_CONN_ID_GENERATION: + + if (BufferLength != sizeof(BOOLEAN) || Buffer == NULL) { + Status = QUIC_STATUS_INVALID_PARAMETER; + break; + } + + Connection->State.DisableConnIDGen = *(BOOLEAN*)Buffer; + Status = QUIC_STATUS_SUCCESS; + break; + + case QUIC_PARAM_CONN_GENERATE_CONN_ID: + + if (!Connection->State.Connected || + !Connection->State.HandshakeConfirmed) { + Status = QUIC_STATUS_INVALID_STATE; + break; + } + + if (BufferLength != sizeof(BOOLEAN) || Buffer == NULL) { + Status = QUIC_STATUS_INVALID_PARAMETER; + break; + } + + QuicPathIDSetGenerateNewSourceCids(&Connection->PathIDs, *(BOOLEAN*)Buffer); + Status = QUIC_STATUS_SUCCESS; + break; +#endif + default: Status = QUIC_STATUS_INVALID_PARAMETER; break; @@ -6823,7 +7155,7 @@ QuicConnGetV2Statistics( // } if (STATISTICS_HAS_FIELD(*StatsLength, SendCongestionWindow)) { - Stats->SendCongestionWindow = QuicCongestionControlGetCongestionWindow(&Connection->CongestionControl); + Stats->SendCongestionWindow = QuicCongestionControlGetCongestionWindow(&Connection->Paths[0].PathID->CongestionControl); } if (STATISTICS_HAS_FIELD(*StatsLength, DestCidUpdateCount)) { Stats->DestCidUpdateCount = Connection->Stats.Misc.DestCidUpdateCount; @@ -7216,10 +7548,12 @@ QuicConnParamGet( *BufferLength = Connection->OrigDestCID->Length; break; } + if (Buffer == NULL) { Status = QUIC_STATUS_INVALID_PARAMETER; break; } + CxPlatCopyMemory( Buffer, Connection->OrigDestCID->Data, @@ -7228,9 +7562,41 @@ QuicConnParamGet( // Tell app how much buffer we copied. // *BufferLength = Connection->OrigDestCID->Length; + Status = QUIC_STATUS_SUCCESS; break; + case QUIC_PARAM_CONN_PATH_STATUS: + if (*BufferLength < sizeof(QUIC_PATH_STATUS)) { + Status = QUIC_STATUS_BUFFER_TOO_SMALL; + *BufferLength = sizeof(QUIC_PATH_STATUS); + break; + } + QUIC_PATH_STATUS* PathStatus = (QUIC_PATH_STATUS*)Buffer; + QUIC_PATH* Path = NULL; + for (uint8_t i = 0; i < Connection->PathsCount; ++i) { + if (QuicAddrCompare( + &PathStatus->LocalAddress, + &Connection->Paths[i].Route.LocalAddress) && + QuicAddrCompare( + &PathStatus->PeerAddress, + &Connection->Paths[i].Route.RemoteAddress) && + PathStatus->PathId == Connection->Paths[i].PathID->ID) { + Path = &Connection->Paths[i]; + break; + } + } + + if (Path == NULL) { + Status = QUIC_STATUS_INVALID_PARAMETER; + break; + } + PathStatus->Active = Path->IsActive; + + *BufferLength = sizeof(QUIC_PATH_STATUS); + + Status = QUIC_STATUS_SUCCESS; + break; default: Status = QUIC_STATUS_INVALID_PARAMETER; break; @@ -7284,7 +7650,7 @@ QuicConnApplyNewSettings( } QuicSendApplyNewSettings(&Connection->Send, &Connection->Settings); - QuicCongestionControlInitialize(&Connection->CongestionControl, &Connection->Settings); + QuicCongestionControlInitialize(&Connection->Paths[0].PathID->CongestionControl, &Connection->Settings); if (QuicConnIsClient(Connection) && Connection->Settings.IsSet.VersionSettings) { Connection->Stats.QuicVersion = Connection->Settings.VersionSettings->FullyDeployedVersions[0]; @@ -7355,6 +7721,11 @@ QuicConnApplyNewSettings( QuicConnIndicateEvent(Connection, &Event); } + if (QuicConnIsServer(Connection) && Connection->Settings.MultipathEnabled) { + Connection->State.MultipathNegotiated = + !!(Connection->PeerTransportParams.Flags & QUIC_TP_FLAG_INITIAL_MAX_PATH_ID); + } + if (Connection->Settings.EcnEnabled) { QUIC_PATH* Path = &Connection->Paths[0]; Path->EcnValidationState = ECN_VALIDATION_TESTING; @@ -7392,6 +7763,12 @@ QuicConnApplyNewSettings( } } +#if QUIC_TEST_MANUAL_CONN_ID_GENERATION + if (NewSettings->IsSet.ConnIDGenDisabled) { + Connection->State.DisableConnIDGen = NewSettings->ConnIDGenDisabled; + } +#endif + if (OverWrite) { QuicSettingsDumpNew(NewSettings); } else { @@ -7556,11 +7933,14 @@ QuicConnProcessExpiredTimer( QuicConnProcessIdleTimerOperation(Connection); break; case QUIC_CONN_TIMER_LOSS_DETECTION: - QuicLossDetectionProcessTimerOperation(&Connection->LossDetection); + QuicPathIDSetProcessLossDetectionTimerOperation(&Connection->PathIDs); break; case QUIC_CONN_TIMER_KEEP_ALIVE: QuicConnProcessKeepAliveOperation(Connection); break; + case QUIC_CONN_TIMER_PATH_CLOSE: + QuicPathIDSetProcessPathCloseTimerOperation(&Connection->PathIDs); + break; case QUIC_CONN_TIMER_SHUTDOWN: QuicConnProcessShutdownTimerOperation(Connection); break; diff --git a/src/core/connection.h b/src/core/connection.h index c754115f52..cee4bf5d87 100644 --- a/src/core/connection.h +++ b/src/core/connection.h @@ -188,6 +188,11 @@ typedef union QUIC_CONNECTION_STATE { // BOOLEAN TimestampRecvNegotiated : 1; + // + // Multipath extension has been negotiated. + // + BOOLEAN MultipathNegotiated : 1; + // // Indicates we received APPLICATION_ERROR transport error and are checking also // later packets in case they contain CONNECTION_CLOSE frame with application-layer error. @@ -208,6 +213,14 @@ typedef union QUIC_CONNECTION_STATE { // BOOLEAN DisableVneTp : 1; #endif + +#if QUIC_TEST_MANUAL_CONN_ID_GENERATION + // + // Whether to disable automatic generation of Connection ID. + // Only used for testing, and thus only enabled for debug builds. + // + BOOLEAN DisableConnIDGen : 1; +#endif }; } QUIC_CONNECTION_STATE; @@ -225,6 +238,7 @@ typedef enum QUIC_CONNECTION_REF { QUIC_CONN_REF_TIMER_WHEEL, // The timer wheel is tracking the connection. QUIC_CONN_REF_ROUTE, // Route resolution is undergoing. QUIC_CONN_REF_STREAM, // A stream depends on the connection. + QUIC_CONN_REF_PATHID, // A path id depends on the connection. QUIC_CONN_REF_COUNT @@ -388,22 +402,6 @@ typedef struct QUIC_CONNECTION { // uint16_t PartitionID; - // - // Number of non-retired desintation CIDs we currently have cached. - // - uint8_t DestCidCount; - - // - // Number of retired desintation CIDs we currently have cached. - // - uint8_t RetiredDestCidCount; - - // - // The maximum number of source CIDs to give the peer. This is a minimum of - // what we're willing to support and what the peer is willing to accept. - // - uint8_t SourceCidLimit; - // // Number of paths the connection is currently tracking. // @@ -472,17 +470,6 @@ typedef struct QUIC_CONNECTION { // uint64_t NextRecvAckFreqSeqNum; - // - // The sequence number to use for the next source CID. - // - QUIC_VAR_INT NextSourceCidSequenceNumber; - - // - // The most recent Retire Prior To field received in a NEW_CONNECTION_ID - // frame. - // - QUIC_VAR_INT RetirePriorTo; - // // Per-path state. The first entry in the list is the active path. All the // rest (if any) are other tracked paths, sorted from most to least recently @@ -490,16 +477,6 @@ typedef struct QUIC_CONNECTION { // QUIC_PATH Paths[QUIC_MAX_PATH_COUNT]; - // - // The list of connection IDs used for receiving. - // - CXPLAT_SLIST_ENTRY SourceCids; - - // - // The list of connection IDs used for sending. Given to us by the peer. - // - CXPLAT_LIST_ENTRY DestCids; - // // The original CID used by the Client in its first Initial packet. // @@ -584,21 +561,6 @@ typedef struct QUIC_CONNECTION { // QUIC_STREAM_SET Streams; - // - // Congestion control state. - // - QUIC_CONGESTION_CONTROL CongestionControl; - - // - // Manages all the information for outstanding sent packets. - // - QUIC_LOSS_DETECTION LossDetection; - - // - // Per-encryption level packet space information. - // - QUIC_PACKET_SPACE* Packets[QUIC_ENCRYPT_LEVEL_COUNT]; - // // Manages the stream of cryptographic TLS data sent and received. // @@ -669,6 +631,8 @@ typedef struct QUIC_CONNECTION { QUIC_FLOW_BLOCKED_TIMING_TRACKER FlowControl; } BlockedTimings; + QUIC_PATHID_SET PathIDs; + } QUIC_CONNECTION; typedef struct QUIC_SERIALIZED_RESUMPTION_STATE { @@ -784,12 +748,12 @@ QuicSendGetConnection( // inline _Ret_notnull_ -QUIC_CONNECTION* -QuicCongestionControlGetConnection( +QUIC_PATHID* +QuicCongestionControlGetPathID( _In_ const QUIC_CONGESTION_CONTROL* Cc ) { - return CXPLAT_CONTAINING_RECORD(Cc, QUIC_CONNECTION, CongestionControl); + return CXPLAT_CONTAINING_RECORD(Cc, QUIC_PATHID, CongestionControl); } // @@ -797,12 +761,12 @@ QuicCongestionControlGetConnection( // inline _Ret_notnull_ -QUIC_CONNECTION* -QuicLossDetectionGetConnection( +QUIC_PATHID* +QuicLossDetectionGetPathID( _In_ QUIC_LOSS_DETECTION* LossDetection ) { - return CXPLAT_CONTAINING_RECORD(LossDetection, QUIC_CONNECTION, LossDetection); + return CXPLAT_CONTAINING_RECORD(LossDetection, QUIC_PATHID, LossDetection); } // @@ -818,28 +782,41 @@ QuicDatagramGetConnection( return CXPLAT_CONTAINING_RECORD(Datagram, QUIC_CONNECTION, Datagram); } +// +// Helper to get the owning QUIC_CONNECTION for the stream set module. +// +inline +_Ret_notnull_ +QUIC_CONNECTION* +QuicPathIDSetGetConnection( + _In_ QUIC_PATHID_SET* PathIDSet + ) +{ + return CXPLAT_CONTAINING_RECORD(PathIDSet, QUIC_CONNECTION, PathIDs); +} + inline void QuicConnLogOutFlowStats( - _In_ const QUIC_CONNECTION* const Connection + _In_ const QUIC_PATHID* const PathID ) { if (!QuicTraceEventEnabled(ConnOutFlowStats)) { return; } - QuicCongestionControlLogOutFlowStatus(&Connection->CongestionControl); + QuicCongestionControlLogOutFlowStatus(&PathID->CongestionControl); uint64_t FcAvailable, SendWindow; QuicStreamSetGetFlowControlSummary( - &Connection->Streams, + &PathID->Connection->Streams, &FcAvailable, &SendWindow); QuicTraceEvent( ConnOutFlowStreamStats, "[conn][%p] OUT: StreamFC=%llu StreamSendWindow=%llu", - Connection, + PathID->Connection, FcAvailable, SendWindow); } @@ -876,8 +853,8 @@ QuicConnLogStatistics( Connection->Stats.Send.PersistentCongestionCount, Connection->Stats.Send.TotalBytes, Connection->Stats.Recv.TotalBytes, - QuicCongestionControlGetCongestionWindow(&Connection->CongestionControl), - Connection->CongestionControl.Name, + QuicCongestionControlGetCongestionWindow(&Path->PathID->CongestionControl), + Path->PathID->CongestionControl.Name, Connection->Stats.Send.EcnCongestionCount); QuicTraceEvent( @@ -1183,136 +1160,6 @@ QuicConnQueueHighestPriorityOper( _In_ QUIC_OPERATION* Oper ); -// -// Generates a new source connection ID. -// -_IRQL_requires_max_(PASSIVE_LEVEL) -QUIC_CID_HASH_ENTRY* -QuicConnGenerateNewSourceCid( - _In_ QUIC_CONNECTION* Connection, - _In_ BOOLEAN IsInitial - ); - -// -// Generates any necessary source CIDs. -// -_IRQL_requires_max_(PASSIVE_LEVEL) -void -QuicConnGenerateNewSourceCids( - _In_ QUIC_CONNECTION* Connection, - _In_ BOOLEAN ReplaceExistingCids - ); - -// -// Retires the currently used destination connection ID. -// -_IRQL_requires_max_(PASSIVE_LEVEL) -BOOLEAN -QuicConnRetireCurrentDestCid( - _In_ QUIC_CONNECTION* Connection, - _In_ QUIC_PATH* Path - ); - -// -// Look up a source CID by sequence number. -// -_IRQL_requires_max_(DISPATCH_LEVEL) -_Success_(return != NULL) -inline -QUIC_CID_HASH_ENTRY* -QuicConnGetSourceCidFromSeq( - _In_ QUIC_CONNECTION* Connection, - _In_ QUIC_VAR_INT SequenceNumber, - _In_ BOOLEAN RemoveFromList, - _Out_ BOOLEAN* IsLastCid - ) -{ - for (CXPLAT_SLIST_ENTRY** Entry = &Connection->SourceCids.Next; - *Entry != NULL; - Entry = &(*Entry)->Next) { - QUIC_CID_HASH_ENTRY* SourceCid = - CXPLAT_CONTAINING_RECORD( - *Entry, - QUIC_CID_HASH_ENTRY, - Link); - if (SourceCid->CID.SequenceNumber == SequenceNumber) { - if (RemoveFromList) { - QuicBindingRemoveSourceConnectionID( - Connection->Paths[0].Binding, - SourceCid, - Entry); - QuicTraceEvent( - ConnSourceCidRemoved, - "[conn][%p] (SeqNum=%llu) Removed Source CID: %!CID!", - Connection, - SourceCid->CID.SequenceNumber, - CASTED_CLOG_BYTEARRAY(SourceCid->CID.Length, SourceCid->CID.Data)); - } - *IsLastCid = Connection->SourceCids.Next == NULL; - return SourceCid; - } - } - return NULL; -} - -// -// Look up a source CID by data buffer. -// -_IRQL_requires_max_(DISPATCH_LEVEL) -inline -QUIC_CID_HASH_ENTRY* -QuicConnGetSourceCidFromBuf( - _In_ QUIC_CONNECTION* Connection, - _In_ uint8_t CidLength, - _In_reads_(CidLength) - const uint8_t* CidBuffer - ) -{ - for (CXPLAT_SLIST_ENTRY* Entry = Connection->SourceCids.Next; - Entry != NULL; - Entry = Entry->Next) { - QUIC_CID_HASH_ENTRY* SourceCid = - CXPLAT_CONTAINING_RECORD( - Entry, - QUIC_CID_HASH_ENTRY, - Link); - if (CidLength == SourceCid->CID.Length && - memcmp(CidBuffer, SourceCid->CID.Data, CidLength) == 0) { - return SourceCid; - } - } - return NULL; -} - -// -// Look up a source CID by sequence number. -// -_IRQL_requires_max_(DISPATCH_LEVEL) -inline -QUIC_CID_LIST_ENTRY* -QuicConnGetDestCidFromSeq( - _In_ QUIC_CONNECTION* Connection, - _In_ QUIC_VAR_INT SequenceNumber, - _In_ BOOLEAN RemoveFromList - ) -{ - for (CXPLAT_LIST_ENTRY* Entry = Connection->DestCids.Flink; - Entry != &Connection->DestCids; - Entry = Entry->Flink) { - QUIC_CID_LIST_ENTRY* DestCid = - CXPLAT_CONTAINING_RECORD( - Entry, - QUIC_CID_LIST_ENTRY, - Link); - if (DestCid->CID.SequenceNumber == SequenceNumber) { - if (RemoveFromList) { - CxPlatListEntryRemove(Entry); - } - return DestCid; - } - } - return NULL; -} // // Adds a sample (in microsec) to the connection's RTT estimator. @@ -1598,6 +1445,31 @@ QuicConnUpdatePeerPacketTolerance( _In_ uint8_t NewPacketTolerance ); +_IRQL_requires_max_(PASSIVE_LEVEL) +BOOLEAN +QuicConnAssignPathIDs( + _In_ QUIC_CONNECTION* Connection + ); + +// +// Open a new path for the connection. +// +_IRQL_requires_max_(PASSIVE_LEVEL) +QUIC_STATUS +QuicConnOpenNewPath( + _In_ QUIC_CONNECTION* Connection, + _In_ QUIC_PATH* Path + ); + +// +// Open new paths for the connection. +// +_IRQL_requires_max_(PASSIVE_LEVEL) +BOOLEAN +QuicConnOpenNewPaths( + _In_ QUIC_CONNECTION* Connection + ); + // // Sets a connection parameter. // diff --git a/src/core/crypto.c b/src/core/crypto.c index 7633f9b32f..c6846f41e3 100644 --- a/src/core/crypto.c +++ b/src/core/crypto.c @@ -160,21 +160,21 @@ QuicCryptoInitialize( RecvBufferInitialized = TRUE; if (QuicConnIsServer(Connection)) { - CXPLAT_DBG_ASSERT(Connection->SourceCids.Next != NULL); - QUIC_CID_HASH_ENTRY* SourceCid = + CXPLAT_DBG_ASSERT(Connection->Paths[0].PathID->SourceCids.Next != NULL); + QUIC_CID_SLIST_ENTRY* SourceCid = CXPLAT_CONTAINING_RECORD( - Connection->SourceCids.Next, - QUIC_CID_HASH_ENTRY, + Connection->Paths[0].PathID->SourceCids.Next, + QUIC_CID_SLIST_ENTRY, Link); HandshakeCid = SourceCid->CID.Data; HandshakeCidLength = SourceCid->CID.Length; } else { - CXPLAT_DBG_ASSERT(!CxPlatListIsEmpty(&Connection->DestCids)); + CXPLAT_DBG_ASSERT(!CxPlatListIsEmpty(&Connection->Paths[0].PathID->DestCids)); QUIC_CID_LIST_ENTRY* DestCid = CXPLAT_CONTAINING_RECORD( - Connection->DestCids.Flink, + Connection->Paths[0].PathID->DestCids.Flink, QUIC_CID_LIST_ENTRY, Link); @@ -415,21 +415,21 @@ QuicCryptoOnVersionChange( } if (QuicConnIsServer(Connection)) { - CXPLAT_DBG_ASSERT(Connection->SourceCids.Next != NULL); - QUIC_CID_HASH_ENTRY* SourceCid = + CXPLAT_DBG_ASSERT(Connection->Paths[0].PathID->SourceCids.Next != NULL); + QUIC_CID_SLIST_ENTRY* SourceCid = CXPLAT_CONTAINING_RECORD( - Connection->SourceCids.Next, - QUIC_CID_HASH_ENTRY, + Connection->Paths[0].PathID->SourceCids.Next, + QUIC_CID_SLIST_ENTRY, Link); HandshakeCid = SourceCid->CID.Data; HandshakeCidLength = SourceCid->CID.Length; } else { - CXPLAT_DBG_ASSERT(!CxPlatListIsEmpty(&Connection->DestCids)); + CXPLAT_DBG_ASSERT(!CxPlatListIsEmpty(&Connection->Paths[0].PathID->DestCids)); QUIC_CID_LIST_ENTRY* DestCid = CXPLAT_CONTAINING_RECORD( - Connection->DestCids.Flink, + Connection->Paths[0].PathID->DestCids.Flink, QUIC_CID_LIST_ENTRY, Link); @@ -498,6 +498,10 @@ QuicCryptoHandshakeConfirmed( QuicBindingOnConnectionHandshakeConfirmed(Path->Binding, Connection); } + if (QuicConnOpenNewPaths(Connection)) { + QuicSendSetSendFlag(&Connection->Send, QUIC_CONN_SEND_FLAG_PATH_CHALLENGE); + } + QuicCryptoDiscardKeys(Crypto, QUIC_PACKET_KEY_HANDSHAKE); } @@ -541,12 +545,13 @@ QuicCryptoDiscardKeys( // Clean up send/recv tracking state for the encryption level. // - CXPLAT_DBG_ASSERT(Connection->Packets[EncryptLevel] != NULL); + CXPLAT_DBG_ASSERT(Connection->Paths[0].PathID->ID == 0); + CXPLAT_DBG_ASSERT(Connection->Paths[0].PathID->Packets[EncryptLevel] != NULL); BOOLEAN HasAckElicitingPacketsToAcknowledge = - Connection->Packets[EncryptLevel]->AckTracker.AckElicitingPacketsToAcknowledge != 0; - QuicLossDetectionDiscardPackets(&Connection->LossDetection, KeyType); - QuicPacketSpaceUninitialize(Connection->Packets[EncryptLevel]); - Connection->Packets[EncryptLevel] = NULL; + Connection->Paths[0].PathID->Packets[EncryptLevel]->AckTracker.AckElicitingPacketsToAcknowledge != 0; + QuicLossDetectionDiscardPackets(&Connection->Paths[0].PathID->LossDetection, KeyType); + QuicPacketSpaceUninitialize(Connection->Paths[0].PathID->Packets[EncryptLevel]); + Connection->Paths[0].PathID->Packets[EncryptLevel] = NULL; // // Clean up any possible left over recovery state. @@ -1405,7 +1410,7 @@ QuicCryptoProcessTlsCompletion( CXPLAT_TEL_ASSERT(Crypto->TlsState.EarlyDataState != CXPLAT_TLS_EARLY_DATA_ACCEPTED); if (QuicConnIsClient(Connection)) { QuicCryptoDiscardKeys(Crypto, QUIC_PACKET_KEY_0_RTT); - QuicLossDetectionOnZeroRttRejected(&Connection->LossDetection); + QuicLossDetectionOnZeroRttRejected(&Connection->Paths[0].PathID->LossDetection); } else { QuicConnDiscardDeferred0Rtt(Connection); } @@ -1593,25 +1598,25 @@ QuicCryptoProcessTlsCompletion( // Take this opportinuty to clean up the client chosen initial CID. // It will be the second one in the list. // - CXPLAT_DBG_ASSERT(Connection->SourceCids.Next != NULL); - CXPLAT_DBG_ASSERT(Connection->SourceCids.Next->Next != NULL); - CXPLAT_DBG_ASSERT(Connection->SourceCids.Next->Next != NULL); - CXPLAT_DBG_ASSERT(Connection->SourceCids.Next->Next->Next == NULL); - QUIC_CID_HASH_ENTRY* InitialSourceCid = + CXPLAT_DBG_ASSERT(Connection->Paths[0].PathID->SourceCids.Next != NULL); + CXPLAT_DBG_ASSERT(Connection->Paths[0].PathID->SourceCids.Next->Next != NULL); + CXPLAT_DBG_ASSERT(Connection->Paths[0].PathID->SourceCids.Next->Next->Next == NULL); + QUIC_CID_SLIST_ENTRY* InitialSourceCid = CXPLAT_CONTAINING_RECORD( - Connection->SourceCids.Next->Next, - QUIC_CID_HASH_ENTRY, + Connection->Paths[0].PathID->SourceCids.Next->Next, + QUIC_CID_SLIST_ENTRY, Link); CXPLAT_DBG_ASSERT(InitialSourceCid->CID.IsInitial); - Connection->SourceCids.Next->Next = Connection->SourceCids.Next->Next->Next; + Connection->Paths[0].PathID->SourceCids.Next->Next = Connection->Paths[0].PathID->SourceCids.Next->Next->Next; CXPLAT_DBG_ASSERT(!InitialSourceCid->CID.IsInLookupTable); QuicTraceEvent( ConnSourceCidRemoved, - "[conn][%p] (SeqNum=%llu) Removed Source CID: %!CID!", + "[conn][%p][pathid][%u] (SeqNum=%llu) Removed Source CID: %!CID!", Connection, + Connection->Paths[0].PathID->ID, InitialSourceCid->CID.SequenceNumber, CASTED_CLOG_BYTEARRAY(InitialSourceCid->CID.Length, InitialSourceCid->CID.Data)); - CXPLAT_FREE(InitialSourceCid, QUIC_POOL_CIDHASH); + CXPLAT_FREE(InitialSourceCid, QUIC_POOL_CIDSLIST); } // @@ -1622,7 +1627,13 @@ QuicCryptoProcessTlsCompletion( Connection->State.Connected = TRUE; QuicPerfCounterIncrement(QUIC_PERF_COUNTER_CONN_CONNECTED); - QuicConnGenerateNewSourceCids(Connection, FALSE); +#if QUIC_TEST_MANUAL_CONN_ID_GENERATION + if (!Connection->State.DisableConnIDGen) { + QuicPathIDSetGenerateNewSourceCids(&Connection->PathIDs, FALSE); + } +#else + QuicPathIDSetGenerateNewSourceCids(&Connection->PathIDs, FALSE); +#endif CXPLAT_DBG_ASSERT(Crypto->TlsState.NegotiatedAlpn != NULL); if (QuicConnIsClient(Connection)) { @@ -1656,7 +1667,7 @@ QuicCryptoProcessTlsCompletion( } Connection->Stats.ResumptionSucceeded = Crypto->TlsState.SessionResumed; - CXPLAT_DBG_ASSERT(Connection->PathsCount == 1); + CXPLAT_DBG_ASSERT(Connection->PathsCount >= 1); QUIC_PATH* Path = &Connection->Paths[0]; CXPLAT_DBG_ASSERT(Path->IsActive); @@ -2123,8 +2134,6 @@ QuicCryptoUpdateKeyPhase( Connection->Stats.Misc.KeyUpdateCount++; } - QUIC_PACKET_SPACE* PacketSpace = Connection->Packets[QUIC_ENCRYPT_LEVEL_1_RTT]; - UNREFERENCED_PARAMETER(LocalUpdate); QuicTraceEvent( ConnKeyPhaseChange, @@ -2132,17 +2141,27 @@ QuicCryptoUpdateKeyPhase( Connection, LocalUpdate); - PacketSpace->WriteKeyPhaseStartPacketNumber = Connection->Send.NextPacketNumber; - PacketSpace->CurrentKeyPhase = !PacketSpace->CurrentKeyPhase; + QUIC_PATHID* PathIDs[QUIC_ACTIVE_PATH_ID_LIMIT]; + uint8_t PathIDCount = QUIC_ACTIVE_PATH_ID_LIMIT; + QuicPathIDSetGetPathIDs(&Connection->PathIDs, PathIDs, &PathIDCount); - // - // Reset the read packet space so any new packet will be properly detected. - // - PacketSpace->ReadKeyPhaseStartPacketNumber = UINT64_MAX; + for (uint8_t i = 0; i < PathIDCount; i++) { + QUIC_PACKET_SPACE* PacketSpace = PathIDs[i]->Packets[QUIC_ENCRYPT_LEVEL_1_RTT]; + + PacketSpace->WriteKeyPhaseStartPacketNumber = PathIDs[i]->NextPacketNumber; + PacketSpace->CurrentKeyPhase = !PacketSpace->CurrentKeyPhase; + + // + // Reset the read packet space so any new packet will be properly detected. + // + PacketSpace->ReadKeyPhaseStartPacketNumber = UINT64_MAX; + + PacketSpace->AwaitingKeyPhaseConfirmation = TRUE; - PacketSpace->AwaitingKeyPhaseConfirmation = TRUE; + PacketSpace->CurrentKeyPhaseBytesSent = 0; - PacketSpace->CurrentKeyPhaseBytesSent = 0; + QuicPathIDRelease(PathIDs[i], QUIC_PATHID_REF_LOOKUP); + } } QUIC_STATUS diff --git a/src/core/crypto_tls.c b/src/core/crypto_tls.c index 713405fef7..077c77a990 100644 --- a/src/core/crypto_tls.c +++ b/src/core/crypto_tls.c @@ -68,6 +68,7 @@ typedef enum eSniNameType { #define QUIC_TP_ID_GREASE_QUIC_BIT 0x2AB2 // N/A #define QUIC_TP_ID_RELIABLE_RESET_ENABLED 0x17f7586d2cb570 // varint #define QUIC_TP_ID_ENABLE_TIMESTAMP 0x7158 // varint +#define QUIC_TP_ID_INITIAL_MAX_PATH_ID 0x0f739bbc1b666d11 // varint BOOLEAN QuicTpIdIsReserved( @@ -904,6 +905,12 @@ QuicCryptoTlsEncodeTransportParameters( QUIC_TP_ID_ENABLE_TIMESTAMP, QuicVarIntSize(value)); } + if (TransportParams->Flags & QUIC_TP_FLAG_INITIAL_MAX_PATH_ID) { + RequiredTPLen += + TlsTransportParamLength( + QUIC_TP_ID_INITIAL_MAX_PATH_ID, + QuicVarIntSize(TransportParams->InitialMaxPathId)); + } if (TestParam != NULL) { RequiredTPLen += TlsTransportParamLength( @@ -1246,6 +1253,17 @@ QuicCryptoTlsEncodeTransportParameters( "TP: Timestamp (%u)", value); } + if (TransportParams->Flags & QUIC_TP_FLAG_INITIAL_MAX_PATH_ID) { + TPBuf = + TlsWriteTransportParamVarInt( + QUIC_TP_ID_INITIAL_MAX_PATH_ID, + TransportParams->InitialMaxPathId, TPBuf); + QuicTraceLogConnVerbose( + EncodeTPInitMaxPathId, + Connection, + "TP: Max Path Id (%llu)", + TransportParams->InitialMaxPathId); + } if (TestParam != NULL) { TPBuf = TlsWriteTransportParam( @@ -1952,6 +1970,23 @@ QuicCryptoTlsDecodeTransportParameters( // NOLINT(readability-function-size, goo TransportParams->Flags |= (uint32_t)value; break; } + case QUIC_TP_ID_INITIAL_MAX_PATH_ID: + if (!TRY_READ_VAR_INT(TransportParams->InitialMaxPathId)) { + QuicTraceEvent( + ConnErrorStatus, + "[conn][%p] ERROR, %u, %s.", + Connection, + Length, + "Invalid length of QUIC_TP_ID_INITIAL_MAX_PATH_ID"); + goto Exit; + } + TransportParams->Flags |= QUIC_TP_FLAG_INITIAL_MAX_PATH_ID; + QuicTraceLogConnVerbose( + DecodeTPInitMaxPathId, + Connection, + "TP: Max Path Id (%llu)", + TransportParams->InitialMaxPathId); + break; default: if (QuicTpIdIsReserved(Id)) { diff --git a/src/core/cubic.c b/src/core/cubic.c index 75e606e61b..4b86e3cb18 100644 --- a/src/core/cubic.c +++ b/src/core/cubic.c @@ -64,15 +64,15 @@ CubeRoot( _IRQL_requires_max_(DISPATCH_LEVEL) void QuicConnLogCubic( - _In_ const QUIC_CONNECTION* const Connection + _In_ const QUIC_PATHID* const PathID ) { - const QUIC_CONGESTION_CONTROL_CUBIC* Cubic = &Connection->CongestionControl.Cubic; + const QUIC_CONGESTION_CONTROL_CUBIC* Cubic = &PathID->CongestionControl.Cubic; QuicTraceEvent( ConnCubic, "[conn][%p] CUBIC: SlowStartThreshold=%u K=%u WindowMax=%u WindowLastMax=%u", - Connection, + PathID->Connection, Cubic->SlowStartThreshold, Cubic->KCubic, Cubic->WindowMax, @@ -85,7 +85,7 @@ CubicCongestionHyStartChangeState( _In_ QUIC_CUBIC_HYSTART_STATE NewHyStartState ) { - QUIC_CONNECTION* Connection = QuicCongestionControlGetConnection(Cc); + QUIC_CONNECTION* Connection = QuicCongestionControlGetPathID(Cc)->Connection; if (!Connection->Settings.HyStartEnabled) { return; } @@ -153,12 +153,13 @@ CubicCongestionControlReset( { QUIC_CONGESTION_CONTROL_CUBIC* Cubic = &Cc->Cubic; - QUIC_CONNECTION* Connection = QuicCongestionControlGetConnection(Cc); + QUIC_PATHID* PathID = QuicCongestionControlGetPathID(Cc); + const uint16_t DatagramPayloadLength = - QuicPathGetDatagramPayloadSize(&Connection->Paths[0]); + QuicPathGetDatagramPayloadSize(PathID->Path); Cubic->SlowStartThreshold = UINT32_MAX; Cubic->MinRttInCurrentRound = UINT32_MAX; - Cubic->HyStartRoundEnd = Connection->Send.NextPacketNumber; + Cubic->HyStartRoundEnd = PathID->NextPacketNumber; CubicCongestionHyStartResetPerRttRound(Cubic); CubicCongestionHyStartChangeState(Cc, HYSTART_NOT_STARTED); Cubic->IsInRecovery = FALSE; @@ -170,8 +171,8 @@ CubicCongestionControlReset( Cubic->BytesInFlight = 0; } - QuicConnLogOutFlowStats(Connection); - QuicConnLogCubic(Connection); + QuicConnLogOutFlowStats(PathID); + QuicConnLogCubic(PathID); } _IRQL_requires_max_(DISPATCH_LEVEL) @@ -185,7 +186,8 @@ CubicCongestionControlGetSendAllowance( QUIC_CONGESTION_CONTROL_CUBIC* Cubic = &Cc->Cubic; uint32_t SendAllowance; - QUIC_CONNECTION* Connection = QuicCongestionControlGetConnection(Cc); + QUIC_PATHID* PathID = QuicCongestionControlGetPathID(Cc); + QUIC_CONNECTION* Connection = PathID->Connection; if (Cubic->BytesInFlight >= Cubic->CongestionWindow) { // // We are CC blocked, so we can't send anything. @@ -195,8 +197,8 @@ CubicCongestionControlGetSendAllowance( } else if ( !TimeSinceLastSendValid || !Connection->Settings.PacingEnabled || - !Connection->Paths[0].GotFirstRttSample || - Connection->Paths[0].SmoothedRtt < QUIC_MIN_PACING_RTT) { + !PathID->Path->GotFirstRttSample || + PathID->Path->SmoothedRtt < QUIC_MIN_PACING_RTT) { // // We're not in the necessary state to pace. // @@ -230,7 +232,7 @@ CubicCongestionControlGetSendAllowance( SendAllowance = Cubic->LastSendAllowance + - (uint32_t)((EstimatedWnd * TimeSinceLastSend) / Connection->Paths[0].SmoothedRtt); + (uint32_t)((EstimatedWnd * TimeSinceLastSend) / PathID->Path->SmoothedRtt); if (SendAllowance < Cubic->LastSendAllowance || // Overflow case SendAllowance > (Cubic->CongestionWindow - Cubic->BytesInFlight)) { SendAllowance = Cubic->CongestionWindow - Cubic->BytesInFlight; @@ -251,8 +253,9 @@ CubicCongestionControlUpdateBlockedState( _In_ BOOLEAN PreviousCanSendState ) { - QUIC_CONNECTION* Connection = QuicCongestionControlGetConnection(Cc); - QuicConnLogOutFlowStats(Connection); + QUIC_PATHID* PathID = QuicCongestionControlGetPathID(Cc); + QUIC_CONNECTION* Connection = PathID->Connection; + QuicConnLogOutFlowStats(PathID); if (PreviousCanSendState != CubicCongestionControlCanSend(Cc)) { if (PreviousCanSendState) { QuicConnAddOutFlowBlockedReason( @@ -277,9 +280,10 @@ CubicCongestionControlOnCongestionEvent( { QUIC_CONGESTION_CONTROL_CUBIC* Cubic = &Cc->Cubic; - QUIC_CONNECTION* Connection = QuicCongestionControlGetConnection(Cc); + QUIC_PATHID* PathID = QuicCongestionControlGetPathID(Cc); + QUIC_CONNECTION* Connection = PathID->Connection; const uint16_t DatagramPayloadLength = - QuicPathGetDatagramPayloadSize(&Connection->Paths[0]); + QuicPathGetDatagramPayloadSize(PathID->Path); QuicTraceEvent( ConnCongestionV2, "[conn][%p] Congestion event: IsEcn=%hu", @@ -313,7 +317,7 @@ CubicCongestionControlOnCongestionEvent( Connection); Connection->Stats.Send.PersistentCongestionCount++; - Connection->Paths[0].Route.State = RouteSuspected; // used only for RAW datapath + PathID->Path->Route.State = RouteSuspected; // used only for RAW datapath Cubic->IsInPersistentCongestion = TRUE; Cubic->WindowPrior = @@ -381,7 +385,7 @@ CubicCongestionControlOnDataSent( Cubic->BytesInFlight += NumRetransmittableBytes; if (Cubic->BytesInFlightMax < Cubic->BytesInFlight) { Cubic->BytesInFlightMax = Cubic->BytesInFlight; - QuicSendBufferConnectionAdjust(QuicCongestionControlGetConnection(Cc)); + QuicSendBufferConnectionAdjust(QuicCongestionControlGetPathID(Cc)->Connection); } if (NumRetransmittableBytes > Cubic->LastSendAllowance) { @@ -424,7 +428,7 @@ CubicCongestionControlOnDataAcknowledged( QUIC_CONGESTION_CONTROL_CUBIC* Cubic = &Cc->Cubic; const uint64_t TimeNowUs = AckEvent->TimeNow; - QUIC_CONNECTION* Connection = QuicCongestionControlGetConnection(Cc); + QUIC_PATHID* PathID = QuicCongestionControlGetPathID(Cc); BOOLEAN PreviousCanSendState = CubicCongestionControlCanSend(Cc); uint32_t BytesAcked = AckEvent->NumRetransmittableBytes; @@ -441,7 +445,7 @@ CubicCongestionControlOnDataAcknowledged( QuicTraceEvent( ConnRecoveryExit, "[conn][%p] Recovery complete", - Connection); + PathID->Connection); Cubic->IsInRecovery = FALSE; Cubic->IsInPersistentCongestion = FALSE; Cubic->TimeOfCongAvoidStart = TimeNowUs; @@ -454,7 +458,7 @@ CubicCongestionControlOnDataAcknowledged( // // Update HyStart++ RTT sample. // - if (Connection->Settings.HyStartEnabled && Cubic->HyStartState != HYSTART_DONE) { + if (PathID->Connection->Settings.HyStartEnabled && Cubic->HyStartState != HYSTART_DONE) { if (AckEvent->MinRttValid) { // // Update Min RTT for the first N ACKs. @@ -503,7 +507,7 @@ CubicCongestionControlOnDataAcknowledged( // Reset HyStart parameters for each RTT round. // if (AckEvent->LargestAck >= Cubic->HyStartRoundEnd) { - Cubic->HyStartRoundEnd = Connection->Send.NextPacketNumber; + Cubic->HyStartRoundEnd = PathID->NextPacketNumber; if (Cubic->HyStartState == HYSTART_ACTIVE) { if (--Cubic->ConservativeSlowStartRounds == 0) { // @@ -550,7 +554,7 @@ CubicCongestionControlOnDataAcknowledged( CXPLAT_DBG_ASSERT(Cubic->CongestionWindow >= Cubic->SlowStartThreshold); const uint16_t DatagramPayloadLength = - QuicPathGetDatagramPayloadSize(&Connection->Paths[0]); + QuicPathGetDatagramPayloadSize(PathID->Path); // // We require steady ACK feedback to justify window growth. If there is @@ -561,7 +565,7 @@ CubicCongestionControlOnDataAcknowledged( if (Cubic->TimeOfLastAckValid) { const uint64_t TimeSinceLastAck = CxPlatTimeDiff64(Cubic->TimeOfLastAck, TimeNowUs); if (TimeSinceLastAck > MS_TO_US((uint64_t)Cubic->SendIdleTimeoutMs) && - TimeSinceLastAck > (Connection->Paths[0].SmoothedRtt + 4 * Connection->Paths[0].RttVariance)) { + TimeSinceLastAck > (PathID->Path->SmoothedRtt + 4 * PathID->Path->RttVariance)) { Cubic->TimeOfCongAvoidStart += TimeSinceLastAck; if (CxPlatTimeAtOrBefore64(TimeNowUs, Cubic->TimeOfCongAvoidStart)) { Cubic->TimeOfCongAvoidStart = TimeNowUs; @@ -670,20 +674,20 @@ CubicCongestionControlOnDataAcknowledged( Cubic->TimeOfLastAck = TimeNowUs; Cubic->TimeOfLastAckValid = TRUE; - if (Connection->Settings.NetStatsEventEnabled) { - const QUIC_PATH* Path = &Connection->Paths[0]; + if (PathID->Connection->Settings.NetStatsEventEnabled) { + const QUIC_PATH* Path = PathID->Path; QUIC_CONNECTION_EVENT Event; Event.Type = QUIC_CONNECTION_EVENT_NETWORK_STATISTICS; Event.NETWORK_STATISTICS.BytesInFlight = Cubic->BytesInFlight; - Event.NETWORK_STATISTICS.PostedBytes = Connection->SendBuffer.PostedBytes; - Event.NETWORK_STATISTICS.IdealBytes = Connection->SendBuffer.IdealBytes; + Event.NETWORK_STATISTICS.PostedBytes = PathID->Connection->SendBuffer.PostedBytes; + Event.NETWORK_STATISTICS.IdealBytes = PathID->Connection->SendBuffer.IdealBytes; Event.NETWORK_STATISTICS.SmoothedRTT = Path->SmoothedRtt; Event.NETWORK_STATISTICS.CongestionWindow = Cubic->CongestionWindow; Event.NETWORK_STATISTICS.Bandwidth = Cubic->CongestionWindow / Path->SmoothedRtt; QuicTraceLogConnVerbose( IndicateDataAcked, - Connection, + PathID->Connection, "Indicating QUIC_CONNECTION_EVENT_NETWORK_STATISTICS [BytesInFlight=%u,PostedBytes=%llu,IdealBytes=%llu,SmoothedRTT=%llu,CongestionWindow=%u,Bandwidth=%llu]", Event.NETWORK_STATISTICS.BytesInFlight, Event.NETWORK_STATISTICS.PostedBytes, @@ -691,7 +695,7 @@ CubicCongestionControlOnDataAcknowledged( Event.NETWORK_STATISTICS.SmoothedRTT, Event.NETWORK_STATISTICS.CongestionWindow, Event.NETWORK_STATISTICS.Bandwidth); - QuicConnIndicateEvent(Connection, &Event); + QuicConnIndicateEvent(PathID->Connection, &Event); } return CubicCongestionControlUpdateBlockedState(Cc, PreviousCanSendState); @@ -729,7 +733,7 @@ CubicCongestionControlOnDataLost( Cubic->BytesInFlight -= LossEvent->NumRetransmittableBytes; CubicCongestionControlUpdateBlockedState(Cc, PreviousCanSendState); - QuicConnLogCubic(QuicCongestionControlGetConnection(Cc)); + QuicConnLogCubic(QuicCongestionControlGetPathID(Cc)); } _IRQL_requires_max_(DISPATCH_LEVEL) @@ -752,7 +756,7 @@ CubicCongestionControlOnEcn( EcnEvent->LargestPacketNumberAcked > Cubic->RecoverySentPacketNumber) { Cubic->RecoverySentPacketNumber = EcnEvent->LargestSentPacketNumber; - QuicCongestionControlGetConnection(Cc)->Stats.Send.EcnCongestionCount++; + QuicCongestionControlGetPathID(Cc)->Connection->Stats.Send.EcnCongestionCount++; CubicCongestionControlOnCongestionEvent( Cc, FALSE, @@ -761,7 +765,7 @@ CubicCongestionControlOnEcn( } CubicCongestionControlUpdateBlockedState(Cc, PreviousCanSendState); - QuicConnLogCubic(QuicCongestionControlGetConnection(Cc)); + QuicConnLogCubic(QuicCongestionControlGetPathID(Cc)); } _IRQL_requires_max_(DISPATCH_LEVEL) @@ -776,7 +780,8 @@ CubicCongestionControlOnSpuriousCongestionEvent( return FALSE; } - QUIC_CONNECTION* Connection = QuicCongestionControlGetConnection(Cc); + QUIC_PATHID* PathID = QuicCongestionControlGetPathID(Cc); + QUIC_CONNECTION* Connection = PathID->Connection; BOOLEAN PreviousCanSendState = QuicCongestionControlCanSend(Cc); QuicTraceEvent( @@ -799,7 +804,7 @@ CubicCongestionControlOnSpuriousCongestionEvent( Cubic->HasHadCongestionEvent = FALSE; BOOLEAN Result = CubicCongestionControlUpdateBlockedState(Cc, PreviousCanSendState); - QuicConnLogCubic(Connection); + QuicConnLogCubic(PathID); return Result; } @@ -808,20 +813,20 @@ CubicCongestionControlLogOutFlowStatus( _In_ const QUIC_CONGESTION_CONTROL* Cc ) { - const QUIC_CONNECTION* Connection = QuicCongestionControlGetConnection(Cc); - const QUIC_PATH* Path = &Connection->Paths[0]; + const QUIC_PATHID* PathID = QuicCongestionControlGetPathID(Cc); + const QUIC_PATH* Path = PathID->Path; const QUIC_CONGESTION_CONTROL_CUBIC* Cubic = &Cc->Cubic; QuicTraceEvent( ConnOutFlowStatsV2, "[conn][%p] OUT: BytesSent=%llu InFlight=%u CWnd=%u ConnFC=%llu ISB=%llu PostedBytes=%llu SRtt=%llu 1Way=%llu", - Connection, - Connection->Stats.Send.TotalBytes, + PathID->Connection, + PathID->Connection->Stats.Send.TotalBytes, Cubic->BytesInFlight, Cubic->CongestionWindow, - Connection->Send.PeerMaxData - Connection->Send.OrderedStreamBytesSent, - Connection->SendBuffer.IdealBytes, - Connection->SendBuffer.PostedBytes, + PathID->Connection->Send.PeerMaxData - PathID->Connection->Send.OrderedStreamBytesSent, + PathID->Connection->SendBuffer.IdealBytes, + PathID->Connection->SendBuffer.PostedBytes, Path->GotFirstRttSample ? Path->SmoothedRtt : 0, Path->OneWayDelay); } @@ -901,20 +906,20 @@ CubicCongestionControlInitialize( QUIC_CONGESTION_CONTROL_CUBIC* Cubic = &Cc->Cubic; - QUIC_CONNECTION* Connection = QuicCongestionControlGetConnection(Cc); + QUIC_PATHID* PathID = QuicCongestionControlGetPathID(Cc); const uint16_t DatagramPayloadLength = - QuicPathGetDatagramPayloadSize(&Connection->Paths[0]); + QuicPathGetDatagramPayloadSize(PathID->Path); Cubic->SlowStartThreshold = UINT32_MAX; Cubic->SendIdleTimeoutMs = Settings->SendIdleTimeoutMs; Cubic->InitialWindowPackets = Settings->InitialWindowPackets; Cubic->CongestionWindow = DatagramPayloadLength * Cubic->InitialWindowPackets; Cubic->BytesInFlightMax = Cubic->CongestionWindow / 2; Cubic->MinRttInCurrentRound = UINT64_MAX; - Cubic->HyStartRoundEnd = Connection->Send.NextPacketNumber; + Cubic->HyStartRoundEnd = PathID->NextPacketNumber; Cubic->HyStartState = HYSTART_NOT_STARTED; Cubic->CWndSlowStartGrowthDivisor = 1; CubicCongestionHyStartResetPerRttRound(Cubic); - QuicConnLogOutFlowStats(Connection); - QuicConnLogCubic(Connection); + QuicConnLogOutFlowStats(PathID); + QuicConnLogCubic(PathID); } diff --git a/src/core/frame.c b/src/core/frame.c index 20b6d91eb5..7a84f05b82 100644 --- a/src/core/frame.c +++ b/src/core/frame.c @@ -49,6 +49,7 @@ QuicUint8tDecode( _Success_(return != FALSE) BOOLEAN QuicAckHeaderEncode( + _In_ BOOLEAN MultipathNegotiated, _In_ const QUIC_ACK_EX * const Frame, _In_opt_ QUIC_ACK_ECN_EX* Ecn, _Inout_ uint16_t* Offset, @@ -57,7 +58,8 @@ QuicAckHeaderEncode( ) { uint16_t RequiredLength = - sizeof(uint8_t) + // Type + (MultipathNegotiated ? QuicVarIntSize(QUIC_FRAME_PATH_ACK) : sizeof(uint8_t)) + // Type + (MultipathNegotiated ? QuicVarIntSize(Frame->PathId) : 0) + QuicVarIntSize(Frame->LargestAcknowledged) + QuicVarIntSize(Frame->AckDelay) + QuicVarIntSize(Frame->AdditionalAckBlockCount) + @@ -68,7 +70,12 @@ QuicAckHeaderEncode( } Buffer = Buffer + *Offset; - Buffer = QuicUint8Encode(Ecn == NULL ? QUIC_FRAME_ACK : QUIC_FRAME_ACK + 1, Buffer); + if (MultipathNegotiated) { + Buffer = QuicVarIntEncode(Ecn == NULL ? QUIC_FRAME_PATH_ACK : QUIC_FRAME_PATH_ACK + 1, Buffer); + Buffer = QuicVarIntEncode(Frame->PathId, Buffer); + } else { + Buffer = QuicUint8Encode(Ecn == NULL ? QUIC_FRAME_ACK : QUIC_FRAME_ACK + 1, Buffer); + } Buffer = QuicVarIntEncode(Frame->LargestAcknowledged, Buffer); Buffer = QuicVarIntEncode(Frame->AckDelay, Buffer); Buffer = QuicVarIntEncode(Frame->AdditionalAckBlockCount, Buffer); @@ -81,6 +88,7 @@ QuicAckHeaderEncode( _Success_(return != FALSE) BOOLEAN QuicAckHeaderDecode( + _In_ QUIC_FRAME_TYPE FrameType, _In_ uint16_t BufferLength, _In_reads_bytes_(BufferLength) const uint8_t * const Buffer, @@ -88,6 +96,14 @@ QuicAckHeaderDecode( _Out_ QUIC_ACK_EX* Frame ) { + if (FrameType == QUIC_FRAME_PATH_ACK || FrameType == QUIC_FRAME_PATH_ACK_1) { + if (!QuicVarIntDecode(BufferLength, Buffer, Offset, &Frame->PathId)) { + return FALSE; + } + } else { + Frame->PathId = 0; + } + if (!QuicVarIntDecode(BufferLength, Buffer, Offset, &Frame->LargestAcknowledged) || !QuicVarIntDecode(BufferLength, Buffer, Offset, &Frame->AckDelay) || !QuicVarIntDecode(BufferLength, Buffer, Offset, &Frame->AdditionalAckBlockCount) || @@ -188,6 +204,8 @@ QuicAckEcnDecode( _Success_(return != FALSE) BOOLEAN QuicAckFrameEncode( + _In_ BOOLEAN MultipathNegotiated, + _In_ uint32_t PathId, _In_ const QUIC_RANGE * const AckBlocks, _In_ uint64_t AckDelay, _In_opt_ QUIC_ACK_ECN_EX* Ecn, @@ -206,13 +224,14 @@ QuicAckFrameEncode( // Write the ACK Frame Header // QUIC_ACK_EX Frame = { + PathId, Largest, // LargestAcknowledged AckDelay, // AckDelay i, // AdditionalAckBlockCount Count - 1 // FirstAckBlock }; - if (!QuicAckHeaderEncode(&Frame, Ecn, Offset, BufferLength, Buffer)) { + if (!QuicAckHeaderEncode(MultipathNegotiated, &Frame, Ecn, Offset, BufferLength, Buffer)) { return FALSE; } @@ -273,6 +292,7 @@ QuicAckFrameDecode( const uint8_t * const Buffer, _Inout_ uint16_t* Offset, _Out_ BOOLEAN* InvalidFrame, + _Out_ uint32_t* PathId, _Inout_ QUIC_RANGE* AckRanges, // Pre-Initialized by caller _When_(FrameType == QUIC_FRAME_ACK_1, _Out_) QUIC_ACK_ECN_EX* Ecn, @@ -286,7 +306,7 @@ QuicAckFrameDecode( // Decode the ACK frame header. // QUIC_ACK_EX Frame; - if (!QuicAckHeaderDecode(BufferLength, Buffer, Offset, &Frame)) { + if (!QuicAckHeaderDecode(FrameType, BufferLength, Buffer, Offset, &Frame)) { *InvalidFrame = TRUE; return FALSE; } @@ -347,9 +367,10 @@ QuicAckFrameDecode( } } + *PathId = (uint32_t)Frame.PathId; *AckDelay = Frame.AckDelay; - if (FrameType == QUIC_FRAME_ACK_1) { + if (FrameType == QUIC_FRAME_ACK_1 || FrameType == QUIC_FRAME_PATH_ACK_1) { // // The ECN section was provided. Decode it as well. // @@ -953,6 +974,7 @@ QuicStreamsBlockedFrameDecode( _Success_(return != FALSE) BOOLEAN QuicNewConnectionIDFrameEncode( + _In_ QUIC_FRAME_TYPE FrameType, _In_ const QUIC_NEW_CONNECTION_ID_EX * const Frame, _Inout_ uint16_t* Offset, _In_ uint16_t BufferLength, @@ -960,7 +982,10 @@ QuicNewConnectionIDFrameEncode( ) { uint16_t RequiredLength = - sizeof(uint8_t) + // Type + (FrameType == QUIC_FRAME_PATH_NEW_CONNECTION_ID ? + QuicVarIntSize(QUIC_FRAME_PATH_NEW_CONNECTION_ID) : sizeof(uint8_t)) + // Type + (FrameType == QUIC_FRAME_PATH_NEW_CONNECTION_ID ? + QuicVarIntSize(Frame->PathID) : 0) + QuicVarIntSize(Frame->Sequence) + QuicVarIntSize(Frame->RetirePriorTo) + sizeof(uint8_t) + // Length @@ -972,7 +997,12 @@ QuicNewConnectionIDFrameEncode( } Buffer = Buffer + *Offset; - Buffer = QuicUint8Encode(QUIC_FRAME_NEW_CONNECTION_ID, Buffer); + if (FrameType == QUIC_FRAME_PATH_NEW_CONNECTION_ID) { + Buffer = QuicVarIntEncode(QUIC_FRAME_PATH_NEW_CONNECTION_ID, Buffer); + Buffer = QuicVarIntEncode(Frame->PathID, Buffer); + } else { + Buffer = QuicUint8Encode(QUIC_FRAME_NEW_CONNECTION_ID, Buffer); + } Buffer = QuicVarIntEncode(Frame->Sequence, Buffer); Buffer = QuicVarIntEncode(Frame->RetirePriorTo, Buffer); Buffer = QuicUint8Encode(Frame->Length, Buffer); @@ -985,6 +1015,7 @@ QuicNewConnectionIDFrameEncode( _Success_(return != FALSE) BOOLEAN QuicNewConnectionIDFrameDecode( + _In_ QUIC_FRAME_TYPE FrameType, _In_ uint16_t BufferLength, _In_reads_bytes_(BufferLength) const uint8_t * const Buffer, @@ -992,6 +1023,14 @@ QuicNewConnectionIDFrameDecode( _Out_ QUIC_NEW_CONNECTION_ID_EX* Frame ) { + if (FrameType == QUIC_FRAME_PATH_NEW_CONNECTION_ID) { + if (!QuicVarIntDecode(BufferLength, Buffer, Offset, &Frame->PathID)) { + return FALSE; + } + } else { + Frame->PathID = 0; + } + if (!QuicVarIntDecode(BufferLength, Buffer, Offset, &Frame->Sequence) || !QuicVarIntDecode(BufferLength, Buffer, Offset, &Frame->RetirePriorTo) || Frame->RetirePriorTo > Frame->Sequence || @@ -1015,6 +1054,7 @@ QuicNewConnectionIDFrameDecode( _Success_(return != FALSE) BOOLEAN QuicRetireConnectionIDFrameEncode( + _In_ QUIC_FRAME_TYPE FrameType, _In_ const QUIC_RETIRE_CONNECTION_ID_EX * const Frame, _Inout_ uint16_t* Offset, _In_ uint16_t BufferLength, @@ -1022,7 +1062,9 @@ QuicRetireConnectionIDFrameEncode( ) { uint16_t RequiredLength = - sizeof(uint8_t) + // Type + (FrameType == QUIC_FRAME_PATH_RETIRE_CONNECTION_ID ? + QuicVarIntSize(QUIC_FRAME_PATH_RETIRE_CONNECTION_ID) : sizeof(uint8_t)) + // Type + QuicVarIntSize(Frame->PathID) + QuicVarIntSize(Frame->Sequence); if (BufferLength < *Offset + RequiredLength) { @@ -1030,7 +1072,12 @@ QuicRetireConnectionIDFrameEncode( } Buffer = Buffer + *Offset; - Buffer = QuicUint8Encode(QUIC_FRAME_RETIRE_CONNECTION_ID, Buffer); + if (FrameType == QUIC_FRAME_PATH_RETIRE_CONNECTION_ID) { + Buffer = QuicVarIntEncode(QUIC_FRAME_PATH_RETIRE_CONNECTION_ID, Buffer); + Buffer = QuicVarIntEncode(Frame->PathID, Buffer); + } else { + Buffer = QuicUint8Encode(QUIC_FRAME_RETIRE_CONNECTION_ID, Buffer); + } QuicVarIntEncode(Frame->Sequence, Buffer); *Offset += RequiredLength; @@ -1040,6 +1087,7 @@ QuicRetireConnectionIDFrameEncode( _Success_(return != FALSE) BOOLEAN QuicRetireConnectionIDFrameDecode( + _In_ QUIC_FRAME_TYPE FrameType, _In_ uint16_t BufferLength, _In_reads_bytes_(BufferLength) const uint8_t * const Buffer, @@ -1047,6 +1095,14 @@ QuicRetireConnectionIDFrameDecode( _Out_ QUIC_RETIRE_CONNECTION_ID_EX* Frame ) { + if (FrameType == QUIC_FRAME_PATH_RETIRE_CONNECTION_ID) { + if (!QuicVarIntDecode(BufferLength, Buffer, Offset, &Frame->PathID)) { + return FALSE; + } + } else { + Frame->PathID = 0; + } + if (!QuicVarIntDecode(BufferLength, Buffer, Offset, &Frame->Sequence)) { return FALSE; } @@ -1098,6 +1154,185 @@ QuicPathChallengeFrameDecode( return TRUE; } +_Success_(return != FALSE) +BOOLEAN +QuicPathAbandonFrameEncode( + _In_ const QUIC_PATH_ABANDON_EX * const Frame, + _Inout_ uint16_t* Offset, + _In_ uint16_t BufferLength, + _Out_writes_to_(BufferLength, *Offset) uint8_t* Buffer + ) +{ + uint16_t RequiredLength = + QuicVarIntSize(QUIC_FRAME_PATH_ABANDON) + // Type + QuicVarIntSize(Frame->PathID) + + QuicVarIntSize(Frame->ErrorCode); + + if (BufferLength < *Offset + RequiredLength) { + return FALSE; + } + + Buffer = Buffer + *Offset; + Buffer = QuicVarIntEncode(QUIC_FRAME_PATH_ABANDON, Buffer); + Buffer = QuicVarIntEncode(Frame->PathID, Buffer); + QuicVarIntEncode(Frame->ErrorCode, Buffer); + *Offset += RequiredLength; + + return TRUE; +} + +_Success_(return != FALSE) +BOOLEAN +QuicPathAbandonFrameDecode( + _In_ uint16_t BufferLength, + _In_reads_bytes_(BufferLength) + const uint8_t * const Buffer, + _Inout_ uint16_t* Offset, + _Out_ QUIC_PATH_ABANDON_EX* Frame + ) +{ + if (!QuicVarIntDecode(BufferLength, Buffer, Offset, &Frame->PathID) || + !QuicVarIntDecode(BufferLength, Buffer, Offset, &Frame->ErrorCode)) { + return FALSE; + } + + return TRUE; +} + +_Success_(return != FALSE) +BOOLEAN +QuicPathBackupFrameEncode( + _In_ const QUIC_PATH_BACKUP_EX * const Frame, + _Inout_ uint16_t* Offset, + _In_ uint16_t BufferLength, + _Out_writes_to_(BufferLength, *Offset) uint8_t* Buffer + ) +{ + uint16_t RequiredLength = + QuicVarIntSize(QUIC_FRAME_PATH_BACKUP) + // Type + QuicVarIntSize(Frame->PathID) + + QuicVarIntSize(Frame->StatusSequenceNumber); + + if (BufferLength < *Offset + RequiredLength) { + return FALSE; + } + + Buffer = Buffer + *Offset; + Buffer = QuicVarIntEncode(QUIC_FRAME_PATH_BACKUP, Buffer); + Buffer = QuicVarIntEncode(Frame->PathID, Buffer); + QuicVarIntEncode(Frame->StatusSequenceNumber, Buffer); + *Offset += RequiredLength; + + return TRUE; +} + +_Success_(return != FALSE) +BOOLEAN +QuicPathBackupFrameDecode( + _In_ uint16_t BufferLength, + _In_reads_bytes_(BufferLength) + const uint8_t * const Buffer, + _Inout_ uint16_t* Offset, + _Out_ QUIC_PATH_BACKUP_EX* Frame + ) +{ + if (!QuicVarIntDecode(BufferLength, Buffer, Offset, &Frame->PathID) || + !QuicVarIntDecode(BufferLength, Buffer, Offset, &Frame->StatusSequenceNumber)) { + return FALSE; + } + + return TRUE; +} + +_Success_(return != FALSE) +BOOLEAN +QuicPathAvailableFrameEncode( + _In_ const QUIC_PATH_AVAILABLE_EX * const Frame, + _Inout_ uint16_t* Offset, + _In_ uint16_t BufferLength, + _Out_writes_to_(BufferLength, *Offset) uint8_t* Buffer + ) +{ + uint16_t RequiredLength = + QuicVarIntSize(QUIC_FRAME_PATH_AVAILABLE) + // Type + QuicVarIntSize(Frame->PathID) + + QuicVarIntSize(Frame->StatusSequenceNumber); + + if (BufferLength < *Offset + RequiredLength) { + return FALSE; + } + + Buffer = Buffer + *Offset; + Buffer = QuicVarIntEncode(QUIC_FRAME_PATH_AVAILABLE, Buffer); + Buffer = QuicVarIntEncode(Frame->PathID, Buffer); + QuicVarIntEncode(Frame->StatusSequenceNumber, Buffer); + *Offset += RequiredLength; + + return TRUE; +} + +_Success_(return != FALSE) +BOOLEAN +QuicPathAvailableFrameDecode( + _In_ uint16_t BufferLength, + _In_reads_bytes_(BufferLength) + const uint8_t * const Buffer, + _Inout_ uint16_t* Offset, + _Out_ QUIC_PATH_AVAILABLE_EX* Frame + ) +{ + if (!QuicVarIntDecode(BufferLength, Buffer, Offset, &Frame->PathID) || + !QuicVarIntDecode(BufferLength, Buffer, Offset, &Frame->StatusSequenceNumber)) { + return FALSE; + } + + return TRUE; +} + +_Success_(return != FALSE) +BOOLEAN +QuicMaxPathIDFrameEncode( + _In_ const QUIC_MAX_PATH_ID_EX * const Frame, + _Inout_ uint16_t* Offset, + _In_ uint16_t BufferLength, + _Out_writes_to_(BufferLength, *Offset) + uint8_t* Buffer + ) +{ + uint16_t RequiredLength = + QuicVarIntSize(QUIC_FRAME_MAX_PATH_ID) + // Type + QuicVarIntSize(Frame->MaximumPathID); + + if (BufferLength < *Offset + RequiredLength) { + return FALSE; + } + + Buffer = Buffer + *Offset; + Buffer = QuicVarIntEncode(QUIC_FRAME_MAX_PATH_ID, Buffer); + QuicVarIntEncode(Frame->MaximumPathID, Buffer); + *Offset += RequiredLength; + + return TRUE; + +} + +_Success_(return != FALSE) +BOOLEAN +QuicMaxPathIDFrameDecode( + _In_ uint16_t BufferLength, + _In_reads_bytes_(BufferLength) + const uint8_t * const Buffer, + _Inout_ uint16_t* Offset, + _Out_ QUIC_MAX_PATH_ID_EX* Frame + ) +{ + if (!QuicVarIntDecode(BufferLength, Buffer, Offset, &Frame->MaximumPathID)) { + return FALSE; + } + + return TRUE; +} + _Success_(return != FALSE) BOOLEAN QuicConnCloseFrameEncode( @@ -1389,26 +1624,50 @@ QuicFrameLog( } case QUIC_FRAME_ACK: - case QUIC_FRAME_ACK_1: { + case QUIC_FRAME_ACK_1: + case QUIC_FRAME_PATH_ACK: + case QUIC_FRAME_PATH_ACK_1: { QUIC_ACK_EX Frame; - if (!QuicAckHeaderDecode(PacketLength, Packet, Offset, &Frame)) { + if (FrameType == QUIC_FRAME_ACK || FrameType == QUIC_FRAME_ACK_1) { + if (!QuicAckHeaderDecode(FrameType, PacketLength, Packet, Offset, &Frame)) { + QuicTraceLogVerbose( + FrameLogAckInvalid, + "[%c][%cX][%llu] ACK [Invalid]", + PtkConnPre(Connection), + PktRxPre(Rx), + PacketNumber); + return FALSE; + } + QuicTraceLogVerbose( - FrameLogAckInvalid, - "[%c][%cX][%llu] ACK [Invalid]", + FrameLogAck, + "[%c][%cX][%llu] ACK Largest:%llu Delay:%llu", PtkConnPre(Connection), PktRxPre(Rx), - PacketNumber); - return FALSE; - } + PacketNumber, + Frame.LargestAcknowledged, + Frame.AckDelay); + } else { + if (!QuicAckHeaderDecode(FrameType, PacketLength, Packet, Offset, &Frame)) { + QuicTraceLogVerbose( + FrameLogPathAckInvalid, + "[%c][%cX][%llu] PATH_ACK [Invalid]", + PtkConnPre(Connection), + PktRxPre(Rx), + PacketNumber); + return FALSE; + } - QuicTraceLogVerbose( - FrameLogAck, - "[%c][%cX][%llu] ACK Largest:%llu Delay:%llu", - PtkConnPre(Connection), - PktRxPre(Rx), - PacketNumber, - Frame.LargestAcknowledged, - Frame.AckDelay); + QuicTraceLogVerbose( + FrameLogPathAck, + "[%c][%cX][%llu] PathId:%llu ACK Largest:%llu Delay:%llu", + PtkConnPre(Connection), + PktRxPre(Rx), + PacketNumber, + Frame.PathId, + Frame.LargestAcknowledged, + Frame.AckDelay); + } if (Frame.FirstAckBlock == 0) { QuicTraceLogVerbose( @@ -1771,7 +2030,7 @@ QuicFrameLog( case QUIC_FRAME_NEW_CONNECTION_ID: { QUIC_NEW_CONNECTION_ID_EX Frame; - if (!QuicNewConnectionIDFrameDecode(PacketLength, Packet, Offset, &Frame)) { + if (!QuicNewConnectionIDFrameDecode(FrameType, PacketLength, Packet, Offset, &Frame)) { QuicTraceLogVerbose( FrameLogNewConnectionIDInvalid, "[%c][%cX][%llu] NEW_CONN_ID [Invalid]", @@ -1794,9 +2053,35 @@ QuicFrameLog( break; } + case QUIC_FRAME_PATH_NEW_CONNECTION_ID: { + QUIC_NEW_CONNECTION_ID_EX Frame; + if (!QuicNewConnectionIDFrameDecode(FrameType, PacketLength, Packet, Offset, &Frame)) { + QuicTraceLogVerbose( + FrameLogPathNewConnectionIDInvalid, + "[%c][%cX][%llu] PATH_NEW_CONN_ID [Invalid]", + PtkConnPre(Connection), + PktRxPre(Rx), + PacketNumber); + return FALSE; + } + + QuicTraceLogVerbose( + FrameLogPathNewConnectionID, + "[%c][%cX][%llu] PATH_NEW_CONN_ID PathID:%llu Seq:%llu RPT:%llu CID:%s Token:%s", + PtkConnPre(Connection), + PktRxPre(Rx), + PacketNumber, + Frame.PathID, + Frame.Sequence, + Frame.RetirePriorTo, + QuicCidBufToStr(Frame.Buffer, Frame.Length).Buffer, + QuicCidBufToStr(Frame.Buffer + Frame.Length, QUIC_STATELESS_RESET_TOKEN_LENGTH).Buffer); + break; + } + case QUIC_FRAME_RETIRE_CONNECTION_ID: { QUIC_RETIRE_CONNECTION_ID_EX Frame; - if (!QuicRetireConnectionIDFrameDecode(PacketLength, Packet, Offset, &Frame)) { + if (!QuicRetireConnectionIDFrameDecode(FrameType, PacketLength, Packet, Offset, &Frame)) { QuicTraceLogVerbose( FrameLogRetireConnectionIDInvalid, "[%c][%cX][%llu] RETIRE_CONN_ID [Invalid]", @@ -1816,6 +2101,29 @@ QuicFrameLog( break; } + case QUIC_FRAME_PATH_RETIRE_CONNECTION_ID: { + QUIC_RETIRE_CONNECTION_ID_EX Frame; + if (!QuicRetireConnectionIDFrameDecode(FrameType, PacketLength, Packet, Offset, &Frame)) { + QuicTraceLogVerbose( + FrameLogPathRetireConnectionIDInvalid, + "[%c][%cX][%llu] PATH_RETIRE_CONN_ID [Invalid]", + PtkConnPre(Connection), + PktRxPre(Rx), + PacketNumber); + return FALSE; + } + + QuicTraceLogVerbose( + FrameLogPathRetireConnectionID, + "[%c][%cX][%llu] PATH_RETIRE_CONN_ID PathID:%llu Seq:%llu", + PtkConnPre(Connection), + PktRxPre(Rx), + PacketNumber, + Frame.PathID, + Frame.Sequence); + break; + } + case QUIC_FRAME_PATH_CHALLENGE: { QUIC_PATH_CHALLENGE_EX Frame; if (!QuicPathChallengeFrameDecode(PacketLength, Packet, Offset, &Frame)) { @@ -1860,6 +2168,97 @@ QuicFrameLog( break; } + case QUIC_FRAME_PATH_ABANDON: { + QUIC_PATH_ABANDON_EX Frame; + if (!QuicPathAbandonFrameDecode(PacketLength, Packet, Offset, &Frame)) { + QuicTraceLogVerbose( + FrameLogPathAbandonInvalid, + "[%c][%cX][%llu] PATH_ABANDON [Invalid]", + PtkConnPre(Connection), + PktRxPre(Rx), + PacketNumber); + return FALSE; + } + + QuicTraceLogVerbose( + FrameLogPathAbandon, + "[%c][%cX][%llu] PATH_ABANDON PathID:%llu ErrorCode:0x%llX", + PtkConnPre(Connection), + PktRxPre(Rx), + PacketNumber, + Frame.PathID, + Frame.ErrorCode); + break; + } + + case QUIC_FRAME_PATH_BACKUP: { + QUIC_PATH_BACKUP_EX Frame; + if (!QuicPathBackupFrameDecode(PacketLength, Packet, Offset, &Frame)) { + QuicTraceLogVerbose( + FrameLogPathBackupInvalid, + "[%c][%cX][%llu] PATH_BACKUP [Invalid]", + PtkConnPre(Connection), + PktRxPre(Rx), + PacketNumber); + return FALSE; + } + + QuicTraceLogVerbose( + FrameLogPathBackup, + "[%c][%cX][%llu] PATH_BACKUP PathID:%llu SSN:0x%llX", + PtkConnPre(Connection), + PktRxPre(Rx), + PacketNumber, + Frame.PathID, + Frame.StatusSequenceNumber); + break; + } + + case QUIC_FRAME_PATH_AVAILABLE: { + QUIC_PATH_AVAILABLE_EX Frame; + if (!QuicPathAvailableFrameDecode(PacketLength, Packet, Offset, &Frame)) { + QuicTraceLogVerbose( + FrameLogPathAvailableInvalid, + "[%c][%cX][%llu] PATH_AVAILABLE [Invalid]", + PtkConnPre(Connection), + PktRxPre(Rx), + PacketNumber); + return FALSE; + } + + QuicTraceLogVerbose( + FrameLogPathAvailable, + "[%c][%cX][%llu] PATH_AVAILABLE PathID:%llu SSN:0x%llX", + PtkConnPre(Connection), + PktRxPre(Rx), + PacketNumber, + Frame.PathID, + Frame.StatusSequenceNumber); + break; + } + + case QUIC_FRAME_MAX_PATH_ID: { + QUIC_MAX_PATH_ID_EX Frame; + if (!QuicMaxPathIDFrameDecode(PacketLength, Packet, Offset, &Frame)) { + QuicTraceLogVerbose( + FrameLogMaxPathIDInvalid, + "[%c][%cX][%llu] MAX_PATH_ID [Invalid]", + PtkConnPre(Connection), + PktRxPre(Rx), + PacketNumber); + return FALSE; + } + + QuicTraceLogVerbose( + FrameLogMaxPathID, + "[%c][%cX][%llu] MAX_PATH_ID Max:%llu", + PtkConnPre(Connection), + PktRxPre(Rx), + PacketNumber, + Frame.MaximumPathID); + break; + } + case QUIC_FRAME_CONNECTION_CLOSE: case QUIC_FRAME_CONNECTION_CLOSE_1: { QUIC_CONNECTION_CLOSE_EX Frame; diff --git a/src/core/frame.h b/src/core/frame.h index f538ecffbc..6e20950150 100644 --- a/src/core/frame.h +++ b/src/core/frame.h @@ -159,6 +159,15 @@ typedef enum QUIC_FRAME_TYPE { QUIC_FRAME_IMMEDIATE_ACK = 0x1fULL, /* 0xaf to 0x2f4 are unused currently */ QUIC_FRAME_TIMESTAMP = 0x2f5ULL, + QUIC_FRAME_PATH_ACK = 0x15228c00ULL, // to 0x15228c01 + QUIC_FRAME_PATH_ACK_1 = 0x15228c01ULL, + QUIC_FRAME_PATH_ABANDON = 0x15228c05ULL, + QUIC_FRAME_PATH_BACKUP = 0x15228c07ULL, + QUIC_FRAME_PATH_AVAILABLE = 0x15228c08ULL, + QUIC_FRAME_PATH_NEW_CONNECTION_ID = 0x15228c09ULL, + QUIC_FRAME_PATH_RETIRE_CONNECTION_ID = 0x15228c0aULL, + QUIC_FRAME_MAX_PATH_ID = 0x15228c0cULL, + QUIC_FRAME_PATHS_BLOCKED = 0x15228c0dULL, QUIC_FRAME_MAX_SUPPORTED @@ -173,15 +182,20 @@ CXPLAT_STATIC_ASSERT( (X >= QUIC_FRAME_DATAGRAM && X <= QUIC_FRAME_DATAGRAM_1) || \ X == QUIC_FRAME_ACK_FREQUENCY || X == QUIC_FRAME_IMMEDIATE_ACK || \ X == QUIC_FRAME_RELIABLE_RESET_STREAM || \ - X == QUIC_FRAME_TIMESTAMP \ + X == QUIC_FRAME_TIMESTAMP || \ + (X >= QUIC_FRAME_PATH_ACK && X <= QUIC_FRAME_PATH_ACK_1) || \ + X == QUIC_FRAME_PATH_ABANDON || \ + (X >= QUIC_FRAME_PATH_BACKUP && X <= QUIC_FRAME_PATH_RETIRE_CONNECTION_ID) || \ + X == QUIC_FRAME_MAX_PATH_ID \ ) // -// QUIC_FRAME_ACK Encoding/Decoding +// QUIC_FRAME_ACK/QUIC_FRAME_PATH_ACK Encoding/Decoding // typedef struct QUIC_ACK_EX { + QUIC_VAR_INT PathId; QUIC_VAR_INT LargestAcknowledged; QUIC_VAR_INT AckDelay; QUIC_VAR_INT AdditionalAckBlockCount; @@ -207,6 +221,8 @@ typedef struct QUIC_ACK_ECN_EX { _Success_(return != FALSE) BOOLEAN QuicAckFrameEncode( + _In_ BOOLEAN MultipathNegotiated, + _In_ uint32_t PathId, _In_ const QUIC_RANGE * const AckBlocks, _In_ uint64_t AckDelay, _In_opt_ QUIC_ACK_ECN_EX* Ecn, @@ -225,6 +241,7 @@ QuicAckFrameDecode( const uint8_t * const Buffer, _Inout_ uint16_t* Offset, _Out_ BOOLEAN* InvalidFrame, + _Out_ uint32_t* PathId, _Inout_ QUIC_RANGE* AckRanges, // Pre-Initialized by caller _When_(FrameType == QUIC_FRAME_ACK_1, _Out_) QUIC_ACK_ECN_EX* Ecn, @@ -650,12 +667,13 @@ QuicStreamsBlockedFrameDecode( ); // -// QUIC_FRAME_NEW_CONNECTION_ID Encoding/Decoding +// QUIC_FRAME_NEW_CONNECTION_ID/QUIC_FRAME_PATH_NEW_CONNECTION_ID Encoding/Decoding // typedef struct QUIC_NEW_CONNECTION_ID_EX { uint8_t Length; + QUIC_VAR_INT PathID; QUIC_VAR_INT Sequence; QUIC_VAR_INT RetirePriorTo; uint8_t Buffer[QUIC_MAX_CONNECTION_ID_LENGTH_V1 + QUIC_STATELESS_RESET_TOKEN_LENGTH]; @@ -667,6 +685,7 @@ typedef struct QUIC_NEW_CONNECTION_ID_EX { _Success_(return != FALSE) BOOLEAN QuicNewConnectionIDFrameEncode( + _In_ QUIC_FRAME_TYPE FrameType, _In_ const QUIC_NEW_CONNECTION_ID_EX * const Frame, _Inout_ uint16_t* Offset, _In_ uint16_t BufferLength, @@ -677,6 +696,7 @@ QuicNewConnectionIDFrameEncode( _Success_(return != FALSE) BOOLEAN QuicNewConnectionIDFrameDecode( + _In_ QUIC_FRAME_TYPE FrameType, _In_ uint16_t BufferLength, _In_reads_bytes_(BufferLength) const uint8_t * const Buffer, @@ -690,6 +710,7 @@ QuicNewConnectionIDFrameDecode( typedef struct QUIC_RETIRE_CONNECTION_ID_EX { + QUIC_VAR_INT PathID; QUIC_VAR_INT Sequence; } QUIC_RETIRE_CONNECTION_ID_EX; @@ -697,6 +718,7 @@ typedef struct QUIC_RETIRE_CONNECTION_ID_EX { _Success_(return != FALSE) BOOLEAN QuicRetireConnectionIDFrameEncode( + _In_ QUIC_FRAME_TYPE FrameType, _In_ const QUIC_RETIRE_CONNECTION_ID_EX * const Frame, _Inout_ uint16_t* Offset, _In_ uint16_t BufferLength, @@ -707,6 +729,7 @@ QuicRetireConnectionIDFrameEncode( _Success_(return != FALSE) BOOLEAN QuicRetireConnectionIDFrameDecode( + _In_ QUIC_FRAME_TYPE FrameType, _In_ uint16_t BufferLength, _In_reads_bytes_(BufferLength) const uint8_t * const Buffer, @@ -752,6 +775,129 @@ QuicPathChallengeFrameDecode( _Out_ QUIC_PATH_CHALLENGE_EX* Frame ); +// +// QUIC_FRAME_PATH_ABANDON Encoding/Decoding +// + +typedef struct QUIC_PATH_ABANDON_EX { + + QUIC_VAR_INT PathID; + QUIC_VAR_INT ErrorCode; + +} QUIC_PATH_ABANDON_EX; + +_Success_(return != FALSE) +BOOLEAN +QuicPathAbandonFrameEncode( + _In_ const QUIC_PATH_ABANDON_EX * const Frame, + _Inout_ uint16_t* Offset, + _In_ uint16_t BufferLength, + _Out_writes_to_(BufferLength, *Offset) + uint8_t* Buffer + ); + +_Success_(return != FALSE) +BOOLEAN +QuicPathAbandonFrameDecode( + _In_ uint16_t BufferLength, + _In_reads_bytes_(BufferLength) + const uint8_t * const Buffer, + _Inout_ uint16_t* Offset, + _Out_ QUIC_PATH_ABANDON_EX* Frame + ); + +// +// QUIC_FRAME_PATH_BACKUP Encoding/Decoding +// + +typedef struct QUIC_PATH_BACKUP_EX { + + QUIC_VAR_INT PathID; + QUIC_VAR_INT StatusSequenceNumber; + +} QUIC_PATH_BACKUP_EX; + +_Success_(return != FALSE) +BOOLEAN +QuicPathBackupFrameEncode( + _In_ const QUIC_PATH_BACKUP_EX * const Frame, + _Inout_ uint16_t* Offset, + _In_ uint16_t BufferLength, + _Out_writes_to_(BufferLength, *Offset) + uint8_t* Buffer + ); + +_Success_(return != FALSE) +BOOLEAN +QuicPathBackupFrameDecode( + _In_ uint16_t BufferLength, + _In_reads_bytes_(BufferLength) + const uint8_t * const Buffer, + _Inout_ uint16_t* Offset, + _Out_ QUIC_PATH_BACKUP_EX* Frame + ); + +// +// QUIC_FRAME_PATH_AVAILABLE Encoding/Decoding +// + +typedef struct QUIC_PATH_AVAILABLE_EX { + + QUIC_VAR_INT PathID; + QUIC_VAR_INT StatusSequenceNumber; + +} QUIC_PATH_AVAILABLE_EX; + +_Success_(return != FALSE) +BOOLEAN +QuicPathAvailableFrameEncode( + _In_ const QUIC_PATH_AVAILABLE_EX * const Frame, + _Inout_ uint16_t* Offset, + _In_ uint16_t BufferLength, + _Out_writes_to_(BufferLength, *Offset) + uint8_t* Buffer + ); + +_Success_(return != FALSE) +BOOLEAN +QuicPathAvailableFrameDecode( + _In_ uint16_t BufferLength, + _In_reads_bytes_(BufferLength) + const uint8_t * const Buffer, + _Inout_ uint16_t* Offset, + _Out_ QUIC_PATH_AVAILABLE_EX* Frame + ); + +// +// QUIC_FRAME_MAX_PATH_ID Encoding/Decoding +// + +typedef struct QUIC_MAX_PATH_ID_EX { + + QUIC_VAR_INT MaximumPathID; + +} QUIC_MAX_PATH_ID_EX; + +_Success_(return != FALSE) +BOOLEAN +QuicMaxPathIDFrameEncode( + _In_ const QUIC_MAX_PATH_ID_EX * const Frame, + _Inout_ uint16_t* Offset, + _In_ uint16_t BufferLength, + _Out_writes_to_(BufferLength, *Offset) + uint8_t* Buffer + ); + +_Success_(return != FALSE) +BOOLEAN +QuicMaxPathIDFrameDecode( + _In_ uint16_t BufferLength, + _In_reads_bytes_(BufferLength) + const uint8_t * const Buffer, + _Inout_ uint16_t* Offset, + _Out_ QUIC_MAX_PATH_ID_EX* Frame + ); + // // QUIC_FRAME_CONNECTION_CLOSE Encoding/Decoding // @@ -899,6 +1045,7 @@ QuicTimestampFrameDecode( _Out_ QUIC_TIMESTAMP_EX* Frame ); + // // Helper functions // diff --git a/src/core/inline.c b/src/core/inline.c index a128550ea7..f26e7d26b1 100644 --- a/src/core/inline.c +++ b/src/core/inline.c @@ -27,22 +27,22 @@ QuicCidNewDestination( const uint8_t* const Data ); -QUIC_CID_HASH_ENTRY* +QUIC_CID_SLIST_ENTRY* QuicCidNewSource( - _In_ QUIC_CONNECTION* Connection, + _In_ QUIC_PATHID* PathID, _In_ uint8_t Length, _In_reads_(Length) const uint8_t* const Data ); -QUIC_CID_HASH_ENTRY* +QUIC_CID_SLIST_ENTRY* QuicCidNewNullSource( - _In_ QUIC_CONNECTION* Connection + _In_ QUIC_PATHID* PathID ); -QUIC_CID_HASH_ENTRY* +QUIC_CID_SLIST_ENTRY* QuicCidNewRandomSource( - _In_opt_ QUIC_CONNECTION* Connection, + _In_opt_ QUIC_PATHID* PathID, _In_reads_opt_(MsQuicLib.CidServerIdLength) const void* ServerID, _In_ uint16_t PartitionID, @@ -260,6 +260,18 @@ QuicCryptoCombineIvAndPacketNumber( uint8_t* IvOut ); +void +QuicCryptoCombineIvAndPathIDAndPacketNumber( + _In_reads_bytes_(CXPLAT_IV_LENGTH) + const uint8_t* const IvIn, + _In_reads_bytes_(sizeof(uint32_t)) + const uint8_t* const PathID, + _In_reads_bytes_(sizeof(uint64_t)) + const uint8_t* const PacketNumber, + _Out_writes_bytes_(CXPLAT_IV_LENGTH) + uint8_t* IvOut + ); + QUIC_SUBRANGE* QuicRangeGetSafe( _In_ const QUIC_RANGE * const Range, @@ -594,7 +606,7 @@ QuicPktNumDecode( void QuicConnLogOutFlowStats( - _In_ const QUIC_CONNECTION* const Connection + _In_ const QUIC_PATHID* const PathID ); void @@ -715,6 +727,11 @@ QuicRetryTokenDecrypt( _Out_ QUIC_TOKEN_CONTENTS* Token ); +QUIC_BINDING* +QuicLookupGetBinding( + _In_ QUIC_LOOKUP* Lookup + ); + void QuicConnLogStatistics( _In_ const QUIC_CONNECTION* const Connection @@ -723,7 +740,7 @@ QuicConnLogStatistics( BOOLEAN QuicPacketBuilderAddFrame( _Inout_ QUIC_PACKET_BUILDER* Builder, - _In_ uint8_t FrameType, + _In_ uint32_t FrameType, _In_ BOOLEAN IsAckEliciting ); @@ -744,25 +761,37 @@ QuicPacketBuilderHasAllowance( _In_ const QUIC_PACKET_BUILDER* Builder ); -QUIC_CID_HASH_ENTRY* -QuicConnGetSourceCidFromSeq( - _In_ QUIC_CONNECTION* Connection, +void +QuicPathIDAddRef( + _In_ QUIC_PATHID* PathID, + _In_ QUIC_PATHID_REF Ref + ); + +BOOLEAN +QuicPathIDRelease( + _In_ __drv_freesMem(Mem) QUIC_PATHID* PathID, + _In_ QUIC_PATHID_REF Ref + ); + +QUIC_CID_SLIST_ENTRY* +QuicPathIDGetSourceCidFromSeq( + _In_ QUIC_PATHID* PathID, _In_ QUIC_VAR_INT SequenceNumber, _In_ BOOLEAN RemoveFromList, _Out_ BOOLEAN* IsLastCid ); -QUIC_CID_HASH_ENTRY* -QuicConnGetSourceCidFromBuf( - _In_ QUIC_CONNECTION* Connection, +QUIC_CID_SLIST_ENTRY* +QuicPathIDGetSourceCidFromBuf( + _In_ QUIC_PATHID* PathID, _In_ uint8_t CidLength, _In_reads_(CidLength) const uint8_t* CidBuffer ); QUIC_CID_LIST_ENTRY* -QuicConnGetDestCidFromSeq( - _In_ QUIC_CONNECTION* Connection, +QuicPathIDGetDestCidFromSeq( + _In_ QUIC_PATHID* PathID, _In_ QUIC_VAR_INT SequenceNumber, _In_ BOOLEAN RemoveFromList ); diff --git a/src/core/library.h b/src/core/library.h index 930ce8111e..a6c18eb7ea 100644 --- a/src/core/library.h +++ b/src/core/library.h @@ -451,9 +451,9 @@ QuicPerfCounterTrySnapShot( // inline _Success_(return != NULL) -QUIC_CID_HASH_ENTRY* +QUIC_CID_SLIST_ENTRY* QuicCidNewRandomSource( - _In_opt_ QUIC_CONNECTION* Connection, + _In_opt_ QUIC_PATHID* PathID, _In_reads_opt_(MsQuicLib.CidServerIdLength) const void* ServerID, _In_ uint16_t PartitionID, @@ -466,15 +466,16 @@ QuicCidNewRandomSource( CXPLAT_DBG_ASSERT(MsQuicLib.CidTotalLength == MsQuicLib.CidServerIdLength + QUIC_CID_PID_LENGTH + QUIC_CID_PAYLOAD_LENGTH); CXPLAT_DBG_ASSERT(QUIC_CID_PAYLOAD_LENGTH > PrefixLength); - QUIC_CID_HASH_ENTRY* Entry = - (QUIC_CID_HASH_ENTRY*) + QUIC_CID_SLIST_ENTRY* Entry = + (QUIC_CID_SLIST_ENTRY*) CXPLAT_ALLOC_NONPAGED( - sizeof(QUIC_CID_HASH_ENTRY) + + sizeof(QUIC_CID_SLIST_ENTRY) + MsQuicLib.CidTotalLength, - QUIC_POOL_CIDHASH); + QUIC_POOL_CIDSLIST); if (Entry != NULL) { - Entry->Connection = Connection; + Entry->PathID = PathID; + Entry->HashEntries.Next = NULL; CxPlatZeroMemory(&Entry->CID, sizeof(Entry->CID)); Entry->CID.Length = MsQuicLib.CidTotalLength; diff --git a/src/core/listener.c b/src/core/listener.c index 8466f8302f..7659d7fd6a 100644 --- a/src/core/listener.c +++ b/src/core/listener.c @@ -717,7 +717,7 @@ QuicListenerAcceptConnection( Connection->CibirId[1]); } - if (!QuicConnGenerateNewSourceCid(Connection, TRUE)) { + if (!QuicPathIDGenerateNewSourceCid(Connection->Paths[0].PathID, TRUE)) { return; } diff --git a/src/core/lookup.c b/src/core/lookup.c index 4449a05afc..b78680a5d1 100644 --- a/src/core/lookup.c +++ b/src/core/lookup.c @@ -175,21 +175,38 @@ QuicLookupRebalance( // if (PreviousLookup != NULL) { - CXPLAT_SLIST_ENTRY* Entry = - ((QUIC_CONNECTION*)PreviousLookup)->SourceCids.Next; - - while (Entry != NULL) { - QUIC_CID_HASH_ENTRY *CID = - CXPLAT_CONTAINING_RECORD( - Entry, - QUIC_CID_HASH_ENTRY, - Link); - (void)QuicLookupInsertLocalCid( - Lookup, - CxPlatHashSimple(CID->CID.Length, CID->CID.Data), - CID, - FALSE); - Entry = Entry->Next; + QUIC_PATHID* PathIDs[QUIC_ACTIVE_PATH_ID_LIMIT]; + uint8_t PathIDCount = QUIC_ACTIVE_PATH_ID_LIMIT; + QuicPathIDSetGetPathIDs(&((QUIC_CONNECTION*)PreviousLookup)->PathIDs, PathIDs, &PathIDCount); + + for (uint8_t i = 0; i < PathIDCount; i++) { + CXPLAT_SLIST_ENTRY* Entry = PathIDs[i]->SourceCids.Next; + + while (Entry != NULL) { + QUIC_CID_SLIST_ENTRY *CID = + CXPLAT_CONTAINING_RECORD( + Entry, + QUIC_CID_SLIST_ENTRY, + Link); + CXPLAT_SLIST_ENTRY* Entry1 = CID->HashEntries.Next; + while (Entry1 != NULL) { + QUIC_CID_HASH_ENTRY *CID1 = + CXPLAT_CONTAINING_RECORD( + Entry1, + QUIC_CID_HASH_ENTRY, + Link); + if (CID1->Binding == QuicLookupGetBinding(Lookup)) { + (void)QuicLookupInsertLocalCid( + Lookup, + CxPlatHashSimple(CID->CID.Length, CID->CID.Data), + CID1, + FALSE); + } + Entry1 = Entry1->Next; + } + Entry = Entry->Next; + } + QuicPathIDRelease(PathIDs[i], QUIC_PATHID_REF_LOOKUP); } } @@ -216,14 +233,14 @@ QuicLookupRebalance( } CxPlatHashtableRemove(&PreviousTable[i].Table, Entry, NULL); - QUIC_CID_HASH_ENTRY *CID = + QUIC_CID_HASH_ENTRY* CID = CXPLAT_CONTAINING_RECORD( Entry, QUIC_CID_HASH_ENTRY, Entry); (void)QuicLookupInsertLocalCid( Lookup, - CxPlatHashSimple(CID->CID.Length, CID->CID.Data), + CxPlatHashSimple(CID->CID->CID.Length, CID->CID->CID.Data), CID, FALSE); } @@ -276,26 +293,56 @@ QuicLookupMaximizePartitioning( _IRQL_requires_max_(DISPATCH_LEVEL) BOOLEAN QuicCidMatchConnection( - _In_ const QUIC_CONNECTION* const Connection, + _In_ QUIC_LOOKUP* Lookup, + _In_ QUIC_CONNECTION* Connection, _In_reads_(Length) const uint8_t* const DestCid, - _In_ uint8_t Length + _In_ uint8_t Length, + _Out_ uint32_t* PathId ) { - for (CXPLAT_SLIST_ENTRY* Link = Connection->SourceCids.Next; - Link != NULL; - Link = Link->Next) { - - const QUIC_CID_HASH_ENTRY* const Entry = - CXPLAT_CONTAINING_RECORD(Link, const QUIC_CID_HASH_ENTRY, Link); + BOOLEAN Match = FALSE; + *PathId = 0; + QUIC_PATHID* PathIDs[QUIC_ACTIVE_PATH_ID_LIMIT]; + uint8_t PathIDCount = QUIC_ACTIVE_PATH_ID_LIMIT; + QuicPathIDSetGetPathIDs(&Connection->PathIDs, PathIDs, &PathIDCount); + + for (uint8_t i = 0; i < PathIDCount; i++) { + if (!Match) { + for (CXPLAT_SLIST_ENTRY* Link = PathIDs[i]->SourceCids.Next; + Link != NULL; + Link = Link->Next) { + + const QUIC_CID_SLIST_ENTRY* const Entry = + CXPLAT_CONTAINING_RECORD(Link, const QUIC_CID_SLIST_ENTRY, Link); + + for (CXPLAT_SLIST_ENTRY* Link1 = Entry->HashEntries.Next; + Link1 != NULL; + Link1 = Link1->Next) { + + const QUIC_CID_HASH_ENTRY* const Entry1 = + CXPLAT_CONTAINING_RECORD(Link1, const QUIC_CID_HASH_ENTRY, Link); + + if (Entry1->Binding != QuicLookupGetBinding(Lookup)) { + continue; + } - if (Length == Entry->CID.Length && - (Length == 0 || memcmp(DestCid, Entry->CID.Data, Length) == 0)) { - return TRUE; + if (Length == Entry1->CID->CID.Length && + (Length == 0 || memcmp(DestCid, Entry1->CID->CID.Data, Length) == 0)) { + Match = TRUE; + goto Match; + } + } + } +Match: + if (Match) { + *PathId = PathIDs[i]->ID; + } } + QuicPathIDRelease(PathIDs[i], QUIC_PATHID_REF_LOOKUP); } - return FALSE; + return Match; } // @@ -309,9 +356,11 @@ QuicHashLookupConnection( _In_reads_(Length) const uint8_t* const DestCid, _In_ uint8_t Length, - _In_ uint32_t Hash + _In_ uint32_t Hash, + _Out_ uint32_t* PathId ) { + *PathId = 0; CXPLAT_HASHTABLE_LOOKUP_CONTEXT Context; CXPLAT_HASHTABLE_ENTRY* TableEntry = CxPlatHashtableLookup(Table, Hash, &Context); @@ -320,9 +369,10 @@ QuicHashLookupConnection( QUIC_CID_HASH_ENTRY* CIDEntry = CXPLAT_CONTAINING_RECORD(TableEntry, QUIC_CID_HASH_ENTRY, Entry); - if (CIDEntry->CID.Length == Length && - memcmp(DestCid, CIDEntry->CID.Data, Length) == 0) { - return CIDEntry->Connection; + if (CIDEntry->CID->CID.Length == Length && + memcmp(DestCid, CIDEntry->CID->CID.Data, Length) == 0) { + *PathId = CIDEntry->PathID->ID; + return CIDEntry->PathID->Connection; } TableEntry = CxPlatHashtableLookupNext(Table, &Context); @@ -338,9 +388,11 @@ QuicLookupFindConnectionByLocalCidInternal( _In_reads_(CIDLen) const uint8_t* const CID, _In_ uint8_t CIDLen, - _In_ uint32_t Hash + _In_ uint32_t Hash, + _Out_ uint32_t* PathId ) { + *PathId = 0; QUIC_CONNECTION* Connection = NULL; if (Lookup->PartitionCount == 0) { @@ -349,7 +401,7 @@ QuicLookupFindConnectionByLocalCidInternal( // destination connection ID matches that connection. // if (Lookup->SINGLE.Connection != NULL && - QuicCidMatchConnection(Lookup->SINGLE.Connection, CID, CIDLen)) { + QuicCidMatchConnection(Lookup, Lookup->SINGLE.Connection, CID, CIDLen, PathId)) { Connection = Lookup->SINGLE.Connection; } @@ -375,7 +427,8 @@ QuicLookupFindConnectionByLocalCidInternal( &Table->Table, CID, CIDLen, - Hash); + Hash, + PathId); CxPlatDispatchRwLockReleaseShared(&Table->RwLock, PrevIrql); } @@ -462,7 +515,7 @@ QuicLookupInsertLocalCid( _In_ BOOLEAN UpdateRefCount ) { - if (!QuicLookupRebalance(Lookup, SourceCid->Connection)) { + if (!QuicLookupRebalance(Lookup, SourceCid->PathID->Connection)) { return FALSE; } @@ -471,18 +524,18 @@ QuicLookupInsertLocalCid( // Make sure the connection pointer is set. // if (Lookup->SINGLE.Connection == NULL) { - Lookup->SINGLE.Connection = SourceCid->Connection; + Lookup->SINGLE.Connection = SourceCid->PathID->Connection; } } else { - CXPLAT_DBG_ASSERT(SourceCid->CID.Length >= MsQuicLib.CidServerIdLength + QUIC_CID_PID_LENGTH); + CXPLAT_DBG_ASSERT(SourceCid->CID->CID.Length >= MsQuicLib.CidServerIdLength + QUIC_CID_PID_LENGTH); // // Insert the source connection ID into the hash table. // CXPLAT_STATIC_ASSERT(QUIC_CID_PID_LENGTH == 2, "The code below assumes 2 bytes"); uint16_t PartitionIndex; - CxPlatCopyMemory(&PartitionIndex, SourceCid->CID.Data + MsQuicLib.CidServerIdLength, 2); + CxPlatCopyMemory(&PartitionIndex, SourceCid->CID->CID.Data + MsQuicLib.CidServerIdLength, 2); PartitionIndex &= MsQuicLib.PartitionMask; PartitionIndex %= Lookup->PartitionCount; QUIC_PARTITIONED_HASHTABLE* Table = &Lookup->HASH.Tables[PartitionIndex]; @@ -498,7 +551,7 @@ QuicLookupInsertLocalCid( if (UpdateRefCount) { Lookup->CidCount++; - QuicConnAddRef(SourceCid->Connection, QUIC_CONN_REF_LOOKUP_TABLE); + QuicConnAddRef(SourceCid->PathID->Connection, QUIC_CONN_REF_LOOKUP_TABLE); } #if QUIC_DEBUG_HASHTABLE_LOOKUP @@ -510,8 +563,6 @@ QuicLookupInsertLocalCid( Hash); #endif - SourceCid->CID.IsInLookupTable = TRUE; - return TRUE; } @@ -584,7 +635,7 @@ QuicLookupRemoveLocalCidInt( _In_ QUIC_CID_HASH_ENTRY* SourceCid ) { - CXPLAT_DBG_ASSERT(SourceCid->CID.IsInLookupTable); + CXPLAT_DBG_ASSERT(SourceCid->CID != NULL); CXPLAT_DBG_ASSERT(Lookup->CidCount != 0); Lookup->CidCount--; @@ -597,7 +648,7 @@ QuicLookupRemoveLocalCidInt( #endif if (Lookup->PartitionCount == 0) { - CXPLAT_DBG_ASSERT(Lookup->SINGLE.Connection == SourceCid->Connection); + CXPLAT_DBG_ASSERT(Lookup->SINGLE.Connection == SourceCid->PathID->Connection); if (Lookup->CidCount == 0) { // // This was the last CID reference, so we can clear the connection @@ -606,14 +657,14 @@ QuicLookupRemoveLocalCidInt( Lookup->SINGLE.Connection = NULL; } } else { - CXPLAT_DBG_ASSERT(SourceCid->CID.Length >= MsQuicLib.CidServerIdLength + QUIC_CID_PID_LENGTH); + CXPLAT_DBG_ASSERT(SourceCid->CID->CID.Length >= MsQuicLib.CidServerIdLength + QUIC_CID_PID_LENGTH); // // Remove the source connection ID from the multi-hash table. // CXPLAT_STATIC_ASSERT(QUIC_CID_PID_LENGTH == 2, "The code below assumes 2 bytes"); uint16_t PartitionIndex; - CxPlatCopyMemory(&PartitionIndex, SourceCid->CID.Data + MsQuicLib.CidServerIdLength, 2); + CxPlatCopyMemory(&PartitionIndex, SourceCid->CID->CID.Data + MsQuicLib.CidServerIdLength, 2); PartitionIndex &= MsQuicLib.PartitionMask; PartitionIndex %= Lookup->PartitionCount; QUIC_PARTITIONED_HASHTABLE* Table = &Lookup->HASH.Tables[PartitionIndex]; @@ -629,7 +680,8 @@ QuicLookupFindConnectionByLocalCid( _In_ QUIC_LOOKUP* Lookup, _In_reads_(CIDLen) const uint8_t* const CID, - _In_ uint8_t CIDLen + _In_ uint8_t CIDLen, + _Out_ uint32_t* PathId ) { uint32_t Hash = CxPlatHashSimple(CIDLen, CID); @@ -641,7 +693,8 @@ QuicLookupFindConnectionByLocalCid( Lookup, CID, CIDLen, - Hash); + Hash, + PathId); if (ExistingConnection != NULL) { QuicConnAddRef(ExistingConnection, QUIC_CONN_REF_LOOKUP_RESULT); @@ -659,9 +712,11 @@ QuicLookupFindConnectionByRemoteHash( _In_ const QUIC_ADDR* const RemoteAddress, _In_ uint8_t RemoteCidLength, _In_reads_(RemoteCidLength) - const uint8_t* const RemoteCid + const uint8_t* const RemoteCid, + _Out_ uint32_t* PathId ) { + *PathId = 0; uint32_t Hash = QuicPacketHash(RemoteAddress, RemoteCidLength, RemoteCid); CxPlatDispatchRwLockAcquireShared(&Lookup->RwLock, PrevIrql); @@ -677,6 +732,7 @@ QuicLookupFindConnectionByRemoteHash( Hash); if (ExistingConnection != NULL) { + *PathId = 0; QuicConnAddRef(ExistingConnection, QUIC_CONN_REF_LOOKUP_RESULT); } @@ -726,7 +782,7 @@ _IRQL_requires_max_(DISPATCH_LEVEL) BOOLEAN QuicLookupAddLocalCid( _In_ QUIC_LOOKUP* Lookup, - _In_ QUIC_CID_HASH_ENTRY* SourceCid, + _In_ QUIC_CID_SLIST_ENTRY* SourceCid, _Out_opt_ QUIC_CONNECTION** Collision ) { @@ -738,16 +794,34 @@ QuicLookupAddLocalCid( CXPLAT_DBG_ASSERT(!SourceCid->CID.IsInLookupTable); + uint32_t PathId = 0; ExistingConnection = QuicLookupFindConnectionByLocalCidInternal( Lookup, SourceCid->CID.Data, SourceCid->CID.Length, - Hash); + Hash, + &PathId); if (ExistingConnection == NULL) { - Result = - QuicLookupInsertLocalCid(Lookup, Hash, SourceCid, TRUE); + QUIC_CID_HASH_ENTRY* CID = + (QUIC_CID_HASH_ENTRY*)CXPLAT_ALLOC_NONPAGED( + sizeof(QUIC_CID_HASH_ENTRY), + QUIC_POOL_CIDHASH); + if (CID != NULL) { + CID->CID = SourceCid; + CID->Binding = QuicLookupGetBinding(Lookup); + CID->PathID = SourceCid->PathID; + Result = + QuicLookupInsertLocalCid(Lookup, Hash, CID, TRUE); + if (Result) { + CxPlatListPushEntry(&SourceCid->HashEntries, &CID->Link); + } else { + CXPLAT_FREE(CID, QUIC_POOL_CIDHASH); + } + } else { + Result = FALSE; + } if (Collision != NULL) { *Collision = NULL; } @@ -822,16 +896,13 @@ _IRQL_requires_max_(DISPATCH_LEVEL) void QuicLookupRemoveLocalCid( _In_ QUIC_LOOKUP* Lookup, - _In_ QUIC_CID_HASH_ENTRY* SourceCid, - _In_ CXPLAT_SLIST_ENTRY** Entry + _In_ QUIC_CID_HASH_ENTRY* SourceCid ) { CxPlatDispatchRwLockAcquireExclusive(&Lookup->RwLock, PrevIrql); QuicLookupRemoveLocalCidInt(Lookup, SourceCid); - SourceCid->CID.IsInLookupTable = FALSE; - *Entry = (*Entry)->Next; CxPlatDispatchRwLockReleaseExclusive(&Lookup->RwLock, PrevIrql); - QuicConnRelease(SourceCid->Connection, QUIC_CONN_REF_LOOKUP_TABLE); + QuicConnRelease(SourceCid->PathID->Connection, QUIC_CONN_REF_LOOKUP_TABLE); } _IRQL_requires_max_(DISPATCH_LEVEL) @@ -859,82 +930,3 @@ QuicLookupRemoveRemoteHash( QuicConnRelease(Connection, QUIC_CONN_REF_LOOKUP_TABLE); } -_IRQL_requires_max_(DISPATCH_LEVEL) -void -QuicLookupRemoveLocalCids( - _In_ QUIC_LOOKUP* Lookup, - _In_ QUIC_CONNECTION* Connection - ) -{ - uint8_t ReleaseRefCount = 0; - - CxPlatDispatchRwLockAcquireExclusive(&Lookup->RwLock, PrevIrql); - while (Connection->SourceCids.Next != NULL) { - QUIC_CID_HASH_ENTRY *CID = - CXPLAT_CONTAINING_RECORD( - CxPlatListPopEntry(&Connection->SourceCids), - QUIC_CID_HASH_ENTRY, - Link); - if (CID->CID.IsInLookupTable) { - QuicLookupRemoveLocalCidInt(Lookup, CID); - CID->CID.IsInLookupTable = FALSE; - ReleaseRefCount++; - } - CXPLAT_FREE(CID, QUIC_POOL_CIDHASH); - } - CxPlatDispatchRwLockReleaseExclusive(&Lookup->RwLock, PrevIrql); - - for (uint8_t i = 0; i < ReleaseRefCount; i++) { -#pragma prefast(suppress:6001, "SAL doesn't understand ref counts") - QuicConnRelease(Connection, QUIC_CONN_REF_LOOKUP_TABLE); - } -} - -_IRQL_requires_max_(DISPATCH_LEVEL) -void -QuicLookupMoveLocalConnectionIDs( - _In_ QUIC_LOOKUP* LookupSrc, - _In_ QUIC_LOOKUP* LookupDest, - _In_ QUIC_CONNECTION* Connection - ) -{ - CXPLAT_SLIST_ENTRY* Entry = Connection->SourceCids.Next; - - CxPlatDispatchRwLockAcquireExclusive(&LookupSrc->RwLock, PrevIrql1); - while (Entry != NULL) { - QUIC_CID_HASH_ENTRY *CID = - CXPLAT_CONTAINING_RECORD( - Entry, - QUIC_CID_HASH_ENTRY, - Link); - if (CID->CID.IsInLookupTable) { - QuicLookupRemoveLocalCidInt(LookupSrc, CID); - QuicConnRelease(Connection, QUIC_CONN_REF_LOOKUP_TABLE); - } - Entry = Entry->Next; - } - CxPlatDispatchRwLockReleaseExclusive(&LookupSrc->RwLock, PrevIrql1); - - CxPlatDispatchRwLockAcquireExclusive(&LookupDest->RwLock, PrevIrql2); -#pragma prefast(suppress:6001, "SAL doesn't understand ref counts") - Entry = Connection->SourceCids.Next; - while (Entry != NULL) { - QUIC_CID_HASH_ENTRY *CID = - CXPLAT_CONTAINING_RECORD( - Entry, - QUIC_CID_HASH_ENTRY, - Link); - if (CID->CID.IsInLookupTable) { - BOOLEAN Result = - QuicLookupInsertLocalCid( - LookupDest, - CxPlatHashSimple(CID->CID.Length, CID->CID.Data), - CID, - TRUE); - CXPLAT_DBG_ASSERT(Result); - UNREFERENCED_PARAMETER(Result); - } - Entry = Entry->Next; - } - CxPlatDispatchRwLockReleaseExclusive(&LookupDest->RwLock, PrevIrql2); -} diff --git a/src/core/lookup.h b/src/core/lookup.h index 6675c29ef8..636d602b0f 100644 --- a/src/core/lookup.h +++ b/src/core/lookup.h @@ -11,6 +11,7 @@ typedef struct QUIC_REMOTE_HASH_ENTRY { CXPLAT_HASHTABLE_ENTRY Entry; QUIC_CONNECTION* Connection; + QUIC_BINDING* Binding; QUIC_ADDR RemoteAddress; uint8_t RemoteCidLength; uint8_t RemoteCid[0]; @@ -107,7 +108,8 @@ QuicLookupFindConnectionByLocalCid( _In_ QUIC_LOOKUP* Lookup, _In_reads_(CIDLen) const uint8_t* const CID, - _In_ uint8_t CIDLen + _In_ uint8_t CIDLen, + _Out_ uint32_t* PathId ); // @@ -120,7 +122,8 @@ QuicLookupFindConnectionByRemoteHash( _In_ const QUIC_ADDR* const RemoteAddress, _In_ uint8_t RemoteCidLength, _In_reads_(RemoteCidLength) - const uint8_t* const RemoteCid + const uint8_t* const RemoteCid, + _Out_ uint32_t* PathId ); // @@ -140,7 +143,7 @@ _IRQL_requires_max_(DISPATCH_LEVEL) BOOLEAN QuicLookupAddLocalCid( _In_ QUIC_LOOKUP* Lookup, - _In_ QUIC_CID_HASH_ENTRY* SourceCid, + _In_ QUIC_CID_SLIST_ENTRY* SourceCid, _Out_opt_ QUIC_CONNECTION** Collision ); @@ -166,8 +169,7 @@ _IRQL_requires_max_(DISPATCH_LEVEL) void QuicLookupRemoveLocalCid( _In_ QUIC_LOOKUP* Lookup, - _In_ QUIC_CID_HASH_ENTRY* SourceCid, - _In_ CXPLAT_SLIST_ENTRY** Entry + _In_ QUIC_CID_HASH_ENTRY* SourceCid ); // @@ -181,22 +183,14 @@ QuicLookupRemoveRemoteHash( ); // -// Removes all the connection's local CIDs from the lookup. +// Inserts a source connection ID into the lookup table. Requires the +// Lookup->RwLock to be exlusively held. // _IRQL_requires_max_(DISPATCH_LEVEL) -void -QuicLookupRemoveLocalCids( +BOOLEAN +QuicLookupInsertLocalCid( _In_ QUIC_LOOKUP* Lookup, - _In_ QUIC_CONNECTION* Connection - ); - -// -// Moves all the connection's local CIDs from the one lookup to another. -// -_IRQL_requires_max_(DISPATCH_LEVEL) -void -QuicLookupMoveLocalConnectionIDs( - _In_ QUIC_LOOKUP* LookupSrc, - _In_ QUIC_LOOKUP* LookupDest, - _In_ QUIC_CONNECTION* Connection + _In_ uint32_t Hash, + _In_ QUIC_CID_HASH_ENTRY* SourceCid, + _In_ BOOLEAN UpdateRefCount ); diff --git a/src/core/loss_detection.c b/src/core/loss_detection.c index 9598c56676..3b48a6f838 100644 --- a/src/core/loss_detection.c +++ b/src/core/loss_detection.c @@ -136,7 +136,7 @@ QuicLossDetectionUninitialize( _In_ QUIC_LOSS_DETECTION* LossDetection ) { - QUIC_CONNECTION* Connection = QuicLossDetectionGetConnection(LossDetection); + QUIC_CONNECTION* Connection = QuicLossDetectionGetPathID(LossDetection)->Connection; while (LossDetection->SentPackets != NULL) { QUIC_SENT_PACKET_METADATA* Packet = LossDetection->SentPackets; @@ -173,7 +173,7 @@ QuicLossDetectionReset( _In_ QUIC_LOSS_DETECTION* LossDetection ) { - QUIC_CONNECTION* Connection = QuicLossDetectionGetConnection(LossDetection); + QUIC_CONNECTION* Connection = QuicLossDetectionGetPathID(LossDetection)->Connection; QuicConnTimerCancel(Connection, QUIC_CONN_TIMER_LOSS_DETECTION); @@ -229,7 +229,7 @@ QuicLossDetectionComputeProbeTimeout( _In_ uint32_t Count ) { - QUIC_CONNECTION* Connection = QuicLossDetectionGetConnection(LossDetection); + QUIC_CONNECTION* Connection = QuicLossDetectionGetPathID(LossDetection)->Connection; CXPLAT_DBG_ASSERT(Path->SmoothedRtt != 0); @@ -257,7 +257,7 @@ QuicLossDetectionUpdateTimer( _In_ BOOLEAN ExecuteImmediatelyIfNecessary ) { - QUIC_CONNECTION* Connection = QuicLossDetectionGetConnection(LossDetection); + QUIC_CONNECTION* Connection = QuicLossDetectionGetPathID(LossDetection)->Connection; if (Connection->State.ClosedLocally || Connection->State.ClosedRemotely) { // @@ -388,7 +388,7 @@ QuicLossDetectionOnPacketSent( _In_ QUIC_SENT_PACKET_METADATA* TempSentPacket ) { - QUIC_CONNECTION* Connection = QuicLossDetectionGetConnection(LossDetection); + QUIC_CONNECTION* Connection = QuicLossDetectionGetPathID(LossDetection)->Connection; CXPLAT_DBG_ASSERT(TempSentPacket->FrameCount != 0); // @@ -449,7 +449,7 @@ QuicLossDetectionOnPacketSent( } QuicCongestionControlOnDataSent( - &Connection->CongestionControl, SentPacket->PacketLength); + &Path->PathID->CongestionControl, SentPacket->PacketLength); } uint64_t SendPostedBytes = Connection->SendBuffer.PostedBytes; @@ -461,13 +461,13 @@ QuicLossDetectionOnPacketSent( NULL; if (SendPostedBytes < Path->Mtu && - QuicCongestionControlCanSend(&Connection->CongestionControl) && + QuicCongestionControlCanSend(&Path->PathID->CongestionControl) && !QuicCryptoHasPendingCryptoFrame(&Connection->Crypto) && (Stream && QuicStreamAllowedByPeer(Stream)) && !QuicStreamCanSendNow(Stream, FALSE)) { - QuicCongestionControlSetAppLimited(&Connection->CongestionControl); + QuicCongestionControlSetAppLimited(&Path->PathID->CongestionControl); } - SentPacket->Flags.IsAppLimited = QuicCongestionControlIsAppLimited(&Connection->CongestionControl); + SentPacket->Flags.IsAppLimited = QuicCongestionControlIsAppLimited(&Path->PathID->CongestionControl); LossDetection->TotalBytesSent += TempSentPacket->PacketLength; @@ -498,9 +498,10 @@ QuicLossDetectionOnPacketAcknowledged( _In_ uint64_t AckDelay ) { - QUIC_CONNECTION* Connection = QuicLossDetectionGetConnection(LossDetection); + QUIC_CONNECTION* Connection = QuicLossDetectionGetPathID(LossDetection)->Connection; uint8_t PathIndex; QUIC_PATH* Path = QuicConnGetPathByID(Connection, Packet->PathId, &PathIndex); + CXPLAT_DBG_ASSERT(Path != NULL); UNREFERENCED_PARAMETER(PathIndex); _Analysis_assume_( @@ -517,7 +518,7 @@ QuicLossDetectionOnPacketAcknowledged( QuicCryptoHandshakeConfirmed(&Connection->Crypto, TRUE); } - QUIC_PACKET_SPACE* PacketSpace = Connection->Packets[QUIC_ENCRYPT_LEVEL_1_RTT]; + QUIC_PACKET_SPACE* PacketSpace = Path->PathID->Packets[QUIC_ENCRYPT_LEVEL_1_RTT]; if (EncryptLevel == QUIC_ENCRYPT_LEVEL_1_RTT && PacketSpace->AwaitingKeyPhaseConfirmation && Packet->Flags.KeyPhase == PacketSpace->CurrentKeyPhase && @@ -535,7 +536,7 @@ QuicLossDetectionOnPacketAcknowledged( case QUIC_FRAME_ACK: case QUIC_FRAME_ACK_1: QuicAckTrackerOnAckFrameAcked( - &Connection->Packets[EncryptLevel]->AckTracker, + &Path->PathID->Packets[EncryptLevel]->AckTracker, Packet->Frames[i].ACK.LargestAckedPacketNumber); break; @@ -583,34 +584,72 @@ QuicLossDetectionOnPacketAcknowledged( } break; - case QUIC_FRAME_NEW_CONNECTION_ID: { - BOOLEAN IsLastCid; - QUIC_CID_HASH_ENTRY* SourceCid = - QuicConnGetSourceCidFromSeq( - Connection, - Packet->Frames[i].NEW_CONNECTION_ID.Sequence, - FALSE, - &IsLastCid); - if (SourceCid != NULL) { - SourceCid->CID.Acknowledged = TRUE; + case QUIC_FRAME_NEW_CONNECTION_ID: + case QUIC_FRAME_PATH_NEW_CONNECTION_ID: { + BOOLEAN FatalError = FALSE; + QUIC_PATHID *PathID = QuicPathIDSetGetPathIDForLocal( + &Connection->PathIDs, + Packet->Frames[i].NEW_CONNECTION_ID.PathID, + &FatalError); + CXPLAT_DBG_ASSERT(!FatalError); + if (PathID != NULL) { + BOOLEAN IsLastCid; + QUIC_CID_SLIST_ENTRY* SourceCid = + QuicPathIDGetSourceCidFromSeq( + PathID, + Packet->Frames[i].NEW_CONNECTION_ID.Sequence, + FALSE, + &IsLastCid); + if (SourceCid != NULL) { + SourceCid->CID.Acknowledged = TRUE; + } + QuicPathIDRelease(PathID, QUIC_PATHID_REF_LOOKUP); } break; } - case QUIC_FRAME_RETIRE_CONNECTION_ID: { - QUIC_CID_LIST_ENTRY* DestCid = - QuicConnGetDestCidFromSeq( - Connection, - Packet->Frames[i].RETIRE_CONNECTION_ID.Sequence, - TRUE); - if (DestCid != NULL) { -#pragma prefast(suppress:6001, "TODO - Why does compiler think: Using uninitialized memory '*DestCid'") - CXPLAT_DBG_ASSERT(DestCid->CID.Retired); - CXPLAT_DBG_ASSERT(Path == NULL || Path->DestCid != DestCid); - QUIC_CID_VALIDATE_NULL(Connection, DestCid); - CXPLAT_DBG_ASSERT(Connection->RetiredDestCidCount > 0); - Connection->RetiredDestCidCount--; - CXPLAT_FREE(DestCid, QUIC_POOL_CIDLIST); + case QUIC_FRAME_RETIRE_CONNECTION_ID: + case QUIC_FRAME_PATH_RETIRE_CONNECTION_ID: { + BOOLEAN FatalError = FALSE; + QUIC_PATHID *PathID = QuicPathIDSetGetPathIDForLocal( + &Connection->PathIDs, + Packet->Frames[i].RETIRE_CONNECTION_ID.PathID, + &FatalError); + CXPLAT_DBG_ASSERT(!FatalError); + if (PathID != NULL) { + QUIC_CID_LIST_ENTRY* DestCid = + QuicPathIDGetDestCidFromSeq( + PathID, + Packet->Frames[i].RETIRE_CONNECTION_ID.Sequence, + TRUE); + if (DestCid != NULL) { + #pragma prefast(suppress:6001, "TODO - Why does compiler think: Using uninitialized memory '*DestCid'") + CXPLAT_DBG_ASSERT(DestCid->CID.Retired); + CXPLAT_DBG_ASSERT(Path == NULL || Path->DestCid != DestCid); + QUIC_CID_VALIDATE_NULL(Connection, DestCid); + CXPLAT_DBG_ASSERT(PathID->RetiredDestCidCount > 0); + PathID->RetiredDestCidCount--; + CXPLAT_FREE(DestCid, QUIC_POOL_CIDLIST); + } + QuicPathIDRelease(PathID, QUIC_PATHID_REF_LOOKUP); + } + break; + } + + case QUIC_FRAME_PATH_ABANDON: { + BOOLEAN FatalError = FALSE; + QUIC_PATHID *PathID = QuicPathIDSetGetPathIDForLocal( + &Connection->PathIDs, + Packet->Frames[i].PATH_ABANDON.PathID, + &FatalError); + CXPLAT_DBG_ASSERT(!FatalError); + if (PathID != NULL) { + PathID->Path->LocalCloseAcked = TRUE; + if (PathID->Path->RemoteClose) { + PathID->Flags.Abandoned = TRUE; + QuicPathIDSetTryFreePathID(&Connection->PathIDs, PathID); + } + QuicPathIDRelease(PathID, QUIC_PATHID_REF_LOOKUP); } break; } @@ -684,7 +723,7 @@ QuicLossDetectionRetransmitFrames( _In_ BOOLEAN ReleasePacket ) { - QUIC_CONNECTION* Connection = QuicLossDetectionGetConnection(LossDetection); + QUIC_CONNECTION* Connection = QuicLossDetectionGetPathID(LossDetection)->Connection; BOOLEAN NewDataQueued = FALSE; for (uint8_t i = 0; i < Packet->FrameCount; i++) { @@ -788,39 +827,59 @@ QuicLossDetectionRetransmitFrames( FALSE); break; - case QUIC_FRAME_NEW_CONNECTION_ID: { - BOOLEAN IsLastCid; - QUIC_CID_HASH_ENTRY* SourceCid = - QuicConnGetSourceCidFromSeq( - Connection, - Packet->Frames[i].NEW_CONNECTION_ID.Sequence, - FALSE, - &IsLastCid); - if (SourceCid != NULL && - !SourceCid->CID.Acknowledged) { - SourceCid->CID.NeedsToSend = TRUE; - NewDataQueued |= - QuicSendSetSendFlag( - &Connection->Send, - QUIC_CONN_SEND_FLAG_NEW_CONNECTION_ID); + case QUIC_FRAME_NEW_CONNECTION_ID: + case QUIC_FRAME_PATH_NEW_CONNECTION_ID: { + BOOLEAN FatalError = FALSE; + QUIC_PATHID *PathID = QuicPathIDSetGetPathIDForLocal( + &Connection->PathIDs, + Packet->Frames[i].NEW_CONNECTION_ID.PathID, + &FatalError); + CXPLAT_DBG_ASSERT(!FatalError); + if (PathID != NULL) { + BOOLEAN IsLastCid; + QUIC_CID_SLIST_ENTRY* SourceCid = + QuicPathIDGetSourceCidFromSeq( + PathID, + Packet->Frames[i].NEW_CONNECTION_ID.Sequence, + FALSE, + &IsLastCid); + if (SourceCid != NULL && + !SourceCid->CID.Acknowledged) { + SourceCid->CID.NeedsToSend = TRUE; + NewDataQueued |= + QuicSendSetSendFlag( + &Connection->Send, + QUIC_CONN_SEND_FLAG_NEW_CONNECTION_ID); + } + QuicPathIDRelease(PathID, QUIC_PATHID_REF_LOOKUP); } break; } - case QUIC_FRAME_RETIRE_CONNECTION_ID: { - QUIC_CID_LIST_ENTRY* DestCid = - QuicConnGetDestCidFromSeq( - Connection, - Packet->Frames[i].RETIRE_CONNECTION_ID.Sequence, - FALSE); - if (DestCid != NULL) { - CXPLAT_DBG_ASSERT(DestCid->CID.Retired); - QUIC_CID_VALIDATE_NULL(Connection, DestCid); - DestCid->CID.NeedsToSend = TRUE; - NewDataQueued |= - QuicSendSetSendFlag( - &Connection->Send, - QUIC_CONN_SEND_FLAG_RETIRE_CONNECTION_ID); + case QUIC_FRAME_RETIRE_CONNECTION_ID: + case QUIC_FRAME_PATH_RETIRE_CONNECTION_ID:{ + BOOLEAN FatalError = FALSE; + QUIC_PATHID *PathID = QuicPathIDSetGetPathIDForLocal( + &Connection->PathIDs, + Packet->Frames[i].RETIRE_CONNECTION_ID.PathID, + &FatalError); + CXPLAT_DBG_ASSERT(!FatalError); + if (PathID != NULL) { + QUIC_CID_LIST_ENTRY* DestCid = + QuicPathIDGetDestCidFromSeq( + PathID, + Packet->Frames[i].RETIRE_CONNECTION_ID.Sequence, + FALSE); + if (DestCid != NULL) { + CXPLAT_DBG_ASSERT(DestCid->CID.Retired); + QUIC_CID_VALIDATE_NULL(Connection, DestCid); + DestCid->CID.NeedsToSend = TRUE; + NewDataQueued |= + QuicSendSetSendFlag( + &Connection->Send, + QUIC_CONN_SEND_FLAG_RETIRE_CONNECTION_ID); + } + QuicPathIDRelease(PathID, QUIC_PATHID_REF_LOOKUP); } break; } @@ -841,6 +900,9 @@ QuicLossDetectionRetransmitFrames( "Path[%hhu] validation timed out", Path->ID); QuicPerfCounterIncrement(QUIC_PERF_COUNTER_PATH_FAILURE); + CXPLAT_DBG_ASSERT(Connection->Paths[PathIndex].Binding != NULL); + QuicLibraryReleaseBinding(Connection->Paths[PathIndex].Binding); + Connection->Paths[PathIndex].Binding = NULL; QuicPathRemove(Connection, PathIndex); } else { Path->SendChallenge = TRUE; @@ -852,6 +914,70 @@ QuicLossDetectionRetransmitFrames( break; } + case QUIC_FRAME_PATH_ABANDON: { + BOOLEAN FatalError = FALSE; + QUIC_PATHID *PathID = QuicPathIDSetGetPathIDForLocal( + &Connection->PathIDs, + Packet->Frames[i].PATH_ABANDON.PathID, + &FatalError); + CXPLAT_DBG_ASSERT(!FatalError); + if (PathID != NULL) { + if (!PathID->Path->LocalCloseAcked) { + PathID->Path->SendAbandon = TRUE; + QuicSendSetSendFlag( + &Connection->Send, + QUIC_CONN_SEND_FLAG_PATH_ABANDON); + } + QuicPathIDRelease(PathID, QUIC_PATHID_REF_LOOKUP); + } + break; + } + + case QUIC_FRAME_PATH_BACKUP: { + BOOLEAN FatalError = FALSE; + QUIC_PATHID *PathID = QuicPathIDSetGetPathIDForLocal( + &Connection->PathIDs, + Packet->Frames[i].PATH_BACKUP.PathID, + &FatalError); + CXPLAT_DBG_ASSERT(!FatalError); + if (PathID != NULL) { + if (!PathID->Path->IsActive && + Packet->Frames[i].PATH_BACKUP.Sequence + 1 == PathID->StatusSendSeq) { + QuicSendSetSendFlag( + &Connection->Send, + QUIC_CONN_SEND_FLAG_PATH_BACKUP); + } + QuicPathIDRelease(PathID, QUIC_PATHID_REF_LOOKUP); + } + break; + } + + case QUIC_FRAME_PATH_AVAILABLE: { + BOOLEAN FatalError = FALSE; + QUIC_PATHID *PathID = QuicPathIDSetGetPathIDForLocal( + &Connection->PathIDs, + Packet->Frames[i].PATH_AVAILABLE.PathID, + &FatalError); + CXPLAT_DBG_ASSERT(!FatalError); + if (PathID != NULL) { + if (PathID->Path->IsActive && + Packet->Frames[i].PATH_AVAILABLE.Sequence + 1 == PathID->StatusSendSeq) { + QuicSendSetSendFlag( + &Connection->Send, + QUIC_CONN_SEND_FLAG_PATH_AVAILABLE); + } + QuicPathIDRelease(PathID, QUIC_PATHID_REF_LOOKUP); + } + break; + } + + case QUIC_FRAME_MAX_PATH_ID: + NewDataQueued |= + QuicSendSetSendFlag( + &Connection->Send, + QUIC_CONN_SEND_FLAG_MAX_PATH_ID); + break; + case QUIC_FRAME_HANDSHAKE_DONE: NewDataQueued |= QuicSendSetSendFlag( @@ -897,7 +1023,7 @@ QuicLossDetectionOnPacketDiscarded( _In_ BOOLEAN DiscardedForLoss ) { - QUIC_CONNECTION* Connection = QuicLossDetectionGetConnection(LossDetection); + QUIC_CONNECTION* Connection = QuicLossDetectionGetPathID(LossDetection)->Connection; if (Packet->Flags.IsMtuProbe && DiscardedForLoss) { uint8_t PathIndex; @@ -925,7 +1051,9 @@ QuicLossDetectionDetectAndHandleLostPackets( _In_ uint64_t TimeNow ) { - QUIC_CONNECTION* Connection = QuicLossDetectionGetConnection(LossDetection); + QUIC_PATHID* PathID = QuicLossDetectionGetPathID(LossDetection); + QUIC_CONNECTION* Connection = PathID->Connection; + CXPLAT_DBG_ASSERT(Connection != NULL); uint32_t LostRetransmittableBytes = 0; QUIC_SENT_PACKET_METADATA* Packet; @@ -966,7 +1094,7 @@ QuicLossDetectionDetectAndHandleLostPackets( // This implementation excludes kGranularity from the calculation, // because it is not needed to keep timers from firing early. // - const QUIC_PATH* Path = &Connection->Paths[0]; // TODO - Correct? + const QUIC_PATH* Path = PathID->Path; // TODO - Correct? uint64_t Rtt = CXPLAT_MAX(Path->SmoothedRtt, Path->LatestRttSample); uint64_t TimeReorderThreshold = QUIC_TIME_REORDER_THRESHOLD(Rtt); uint64_t LargestLostPacketNumber = 0; @@ -1069,7 +1197,7 @@ QuicLossDetectionDetectAndHandleLostPackets( LossDetection->ProbeCount > QUIC_PERSISTENT_CONGESTION_THRESHOLD }; - QuicCongestionControlOnDataLost(&Connection->CongestionControl, &LossEvent); + QuicCongestionControlOnDataLost(&PathID->CongestionControl, &LossEvent); // // Send packets from any previously blocked streams. // @@ -1089,7 +1217,9 @@ QuicLossDetectionDiscardPackets( _In_ QUIC_PACKET_KEY_TYPE KeyType ) { - QUIC_CONNECTION* Connection = QuicLossDetectionGetConnection(LossDetection); + QUIC_PATHID* PathID = QuicLossDetectionGetPathID(LossDetection); + QUIC_CONNECTION* Connection = PathID->Connection; + CXPLAT_DBG_ASSERT(Connection != NULL); QUIC_ENCRYPT_LEVEL EncryptLevel = QuicKeyTypeToEncryptLevel(KeyType); QUIC_SENT_PACKET_METADATA* PrevPacket; QUIC_SENT_PACKET_METADATA* Packet; @@ -1215,7 +1345,7 @@ QuicLossDetectionDiscardPackets( .MinRttValid = FALSE }; - if (QuicCongestionControlOnDataAcknowledged(&Connection->CongestionControl, &AckEvent)) { + if (QuicCongestionControlOnDataAcknowledged(&PathID->CongestionControl, &AckEvent)) { // // We were previously blocked and are now unblocked. // @@ -1230,7 +1360,9 @@ QuicLossDetectionOnZeroRttRejected( _In_ QUIC_LOSS_DETECTION* LossDetection ) { - QUIC_CONNECTION* Connection = QuicLossDetectionGetConnection(LossDetection); + QUIC_PATHID* PathID = QuicLossDetectionGetPathID(LossDetection); + QUIC_CONNECTION* Connection = PathID->Connection; + CXPLAT_DBG_ASSERT(Connection != NULL); QUIC_SENT_PACKET_METADATA* PrevPacket; QUIC_SENT_PACKET_METADATA* Packet; uint32_t CountRetransmittableBytes = 0; @@ -1282,7 +1414,7 @@ QuicLossDetectionOnZeroRttRejected( if (CountRetransmittableBytes > 0) { if (QuicCongestionControlOnDataInvalidated( - &Connection->CongestionControl, + &PathID->CongestionControl, CountRetransmittableBytes)) { // // We were previously blocked and are now unblocked. @@ -1309,7 +1441,8 @@ QuicLossDetectionProcessAckBlocks( QUIC_SENT_PACKET_METADATA** AckedPacketsTail = &AckedPackets; uint32_t AckedRetransmittableBytes = 0; - QUIC_CONNECTION* Connection = QuicLossDetectionGetConnection(LossDetection); + QUIC_PATHID* PathID = QuicLossDetectionGetPathID(LossDetection); + QUIC_CONNECTION* Connection = PathID->Connection; uint64_t TimeNow = CxPlatTimeUs64(); uint64_t MinRtt = UINT64_MAX; BOOLEAN NewLargestAck = FALSE; @@ -1371,7 +1504,7 @@ QuicLossDetectionProcessAckBlocks( // spuriously lost. Inform congestion control. // if (QuicCongestionControlOnSpuriousCongestionEvent( - &Connection->CongestionControl)) { + &PathID->CongestionControl)) { // // We were previously blocked and are now unblocked. // @@ -1514,7 +1647,7 @@ QuicLossDetectionProcessAckBlocks( // Per RFC 9000, we validate ECN counts from received ACK frames // when the largest acked packet number increases. // - QUIC_PACKET_SPACE* Packets = Connection->Packets[EncryptLevel]; + QUIC_PACKET_SPACE* Packets = Path->PathID->Packets[EncryptLevel]; BOOLEAN EcnValidated = TRUE; int64_t EctCeDeltaSum = 0; if (Ecn != NULL) { @@ -1549,7 +1682,7 @@ QuicLossDetectionProcessAckBlocks( .LargestPacketNumberAcked = LargestAckedPacketNum, .LargestSentPacketNumber = LossDetection->LargestSentPacketNumber, }; - QuicCongestionControlOnEcn(&Connection->CongestionControl, &EcnEvent); + QuicCongestionControlOnEcn(&PathID->CongestionControl, &EcnEvent); } } } else { @@ -1603,7 +1736,7 @@ QuicLossDetectionProcessAckBlocks( .MinRttValid = TRUE, }; - if (QuicCongestionControlOnDataAcknowledged(&Connection->CongestionControl, &AckEvent)) { + if (QuicCongestionControlOnDataAcknowledged(&PathID->CongestionControl, &AckEvent)) { // // We were previously blocked and are now unblocked. // @@ -1627,76 +1760,6 @@ QuicLossDetectionProcessAckBlocks( QuicLossDetectionUpdateTimer(LossDetection, FALSE); } -_IRQL_requires_max_(PASSIVE_LEVEL) -BOOLEAN -QuicLossDetectionProcessAckFrame( - _In_ QUIC_LOSS_DETECTION* LossDetection, - _In_ QUIC_PATH* Path, - _In_ QUIC_RX_PACKET* Packet, - _In_ QUIC_ENCRYPT_LEVEL EncryptLevel, - _In_ QUIC_FRAME_TYPE FrameType, - _In_ uint16_t BufferLength, - _In_reads_bytes_(BufferLength) - const uint8_t* const Buffer, - _Inout_ uint16_t* Offset, - _Out_ BOOLEAN* InvalidFrame - ) -{ - QUIC_CONNECTION* Connection = QuicLossDetectionGetConnection(LossDetection); - - // - // Called for each received ACK frame. An ACK frame consists of one or more - // ACK blocks, each of which acknowledges a contiguous range of packets. - // - - uint64_t AckDelay; // microsec - QUIC_ACK_ECN_EX Ecn; - - BOOLEAN Result = - QuicAckFrameDecode( - FrameType, - BufferLength, - Buffer, - Offset, - InvalidFrame, - &Connection->DecodedAckRanges, - &Ecn, - &AckDelay); - - if (Result) { - - uint64_t Largest; - if (!QuicRangeGetMaxSafe(&Connection->DecodedAckRanges, &Largest) || - LossDetection->LargestSentPacketNumber < Largest) { - - // - // The ACK frame should never acknowledge a packet number we haven't - // sent. - // - *InvalidFrame = TRUE; - Result = FALSE; - - } else { - - AckDelay <<= Connection->PeerTransportParams.AckDelayExponent; - - QuicLossDetectionProcessAckBlocks( - LossDetection, - Path, - Packet, - EncryptLevel, - AckDelay, - &Connection->DecodedAckRanges, - InvalidFrame, - FrameType == QUIC_FRAME_ACK_1 ? &Ecn : NULL); - } - } - - QuicRangeReset(&Connection->DecodedAckRanges); - - return Result; -} - // // Schedules a fixed number of (ACK-eliciting) probe packets to be sent. // @@ -1706,7 +1769,8 @@ QuicLossDetectionScheduleProbe( _In_ QUIC_LOSS_DETECTION* LossDetection ) { - QUIC_CONNECTION* Connection = QuicLossDetectionGetConnection(LossDetection); + QUIC_PATHID* PathID = QuicLossDetectionGetPathID(LossDetection); + QUIC_CONNECTION* Connection = PathID->Connection; LossDetection->ProbeCount++; QuicTraceLogConnInfo( @@ -1730,7 +1794,7 @@ QuicLossDetectionScheduleProbe( // GQUIC's previous experience, we go with 2. // uint8_t NumPackets = 2; - QuicCongestionControlSetExemption(&Connection->CongestionControl, NumPackets); + QuicCongestionControlSetExemption(&PathID->CongestionControl, NumPackets); QuicSendQueueFlush(&Connection->Send, REASON_PROBE); Connection->Send.TailLossProbeNeeded = TRUE; @@ -1793,7 +1857,7 @@ QuicLossDetectionProcessTimerOperation( _In_ QUIC_LOSS_DETECTION* LossDetection ) { - QUIC_CONNECTION* Connection = QuicLossDetectionGetConnection(LossDetection); + QUIC_CONNECTION* Connection = QuicLossDetectionGetPathID(LossDetection)->Connection; const QUIC_SENT_PACKET_METADATA* OldestPacket = // Oldest retransmittable packet. QuicLossDetectionOldestOutstandingPacket(LossDetection); diff --git a/src/core/loss_detection.h b/src/core/loss_detection.h index b59a584097..c8ed50a360 100644 --- a/src/core/loss_detection.h +++ b/src/core/loss_detection.h @@ -159,26 +159,6 @@ QuicLossDetectionOnPacketSent( _In_ QUIC_SENT_PACKET_METADATA* SentPacket ); -// -// Processes a received ACK frame. Returns true if the frame could be -// successfully processed. On failure, 'InvalidFrame' indicates if the frame -// was corrupt or not. -// -_IRQL_requires_max_(PASSIVE_LEVEL) -BOOLEAN -QuicLossDetectionProcessAckFrame( - _In_ QUIC_LOSS_DETECTION* LossDetection, - _In_ QUIC_PATH* Path, - _In_ QUIC_RX_PACKET* Packet, - _In_ QUIC_ENCRYPT_LEVEL EncryptLevel, - _In_ QUIC_FRAME_TYPE FrameType, - _In_ uint16_t BufferLength, - _In_reads_bytes_(BufferLength) - const uint8_t* const Buffer, - _Inout_ uint16_t* Offset, - _Out_ BOOLEAN* InvalidFrame - ); - // // Called when the loss detection timer fires. // @@ -187,3 +167,16 @@ void QuicLossDetectionProcessTimerOperation( _In_ QUIC_LOSS_DETECTION* LossDetection ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +void +QuicLossDetectionProcessAckBlocks( + _In_ QUIC_LOSS_DETECTION* LossDetection, + _In_ QUIC_PATH* Path, + _In_ QUIC_RX_PACKET* Packet, + _In_ QUIC_ENCRYPT_LEVEL EncryptLevel, + _In_ uint64_t AckDelay, + _In_ QUIC_RANGE* AckBlocks, + _Out_ BOOLEAN* InvalidAckBlock, + _In_opt_ QUIC_ACK_ECN_EX* Ecn + ); diff --git a/src/core/operation.h b/src/core/operation.h index 3146588a07..037896b502 100644 --- a/src/core/operation.h +++ b/src/core/operation.h @@ -178,6 +178,7 @@ typedef enum QUIC_CONN_TIMER_TYPE { QUIC_CONN_TIMER_LOSS_DETECTION, QUIC_CONN_TIMER_KEEP_ALIVE, QUIC_CONN_TIMER_IDLE, + QUIC_CONN_TIMER_PATH_CLOSE, QUIC_CONN_TIMER_SHUTDOWN, QUIC_CONN_TIMER_COUNT diff --git a/src/core/packet_builder.c b/src/core/packet_builder.c index 9d380fa09a..9642e7a870 100644 --- a/src/core/packet_builder.c +++ b/src/core/packet_builder.c @@ -106,7 +106,7 @@ QuicPacketBuilderInitialize( Builder->EncryptionOverhead = CXPLAT_ENCRYPTION_OVERHEAD; Builder->TotalDatagramsLength = 0; - if (Connection->SourceCids.Next == NULL) { + if (Path->PathID->SourceCids.Next == NULL) { QuicTraceLogConnWarning( NoSrcCidAvailable, Connection, @@ -116,8 +116,8 @@ QuicPacketBuilderInitialize( Builder->SourceCid = CXPLAT_CONTAINING_RECORD( - Connection->SourceCids.Next, - QUIC_CID_HASH_ENTRY, + Path->PathID->SourceCids.Next, + QUIC_CID_SLIST_ENTRY, Link); uint64_t TimeNow = CxPlatTimeUs64(); @@ -130,7 +130,7 @@ QuicPacketBuilderInitialize( } Builder->SendAllowance = QuicCongestionControlGetSendAllowance( - &Connection->CongestionControl, + &Path->PathID->CongestionControl, TimeSinceLastSend, Connection->Send.LastFlushTimeValid); if (Builder->SendAllowance > Path->Allowance) { @@ -151,7 +151,7 @@ QuicPacketBuilderCleanup( CXPLAT_DBG_ASSERT(Builder->SendData == NULL); if (Builder->PacketBatchSent && Builder->PacketBatchRetransmittable) { - QuicLossDetectionUpdateTimer(&Builder->Connection->LossDetection, FALSE); + QuicLossDetectionUpdateTimer(&Builder->Path->PathID->LossDetection, FALSE); } QuicSentPacketMetadataReleaseFrames(Builder->Metadata, Builder->Connection); @@ -379,7 +379,7 @@ QuicPacketBuilderPrepare( Builder->BatchId); Builder->Metadata->FrameCount = 0; - Builder->Metadata->PacketNumber = Connection->Send.NextPacketNumber++; + Builder->Metadata->PacketNumber = Builder->Path->PathID->NextPacketNumber++; Builder->Metadata->Flags.KeyType = NewPacketKeyType; Builder->Metadata->Flags.IsAckEliciting = FALSE; Builder->Metadata->Flags.IsMtuProbe = IsPathMtuDiscovery; @@ -397,7 +397,7 @@ QuicPacketBuilderPrepare( (uint16_t)Builder->Datagram->Length - Builder->DatagramLength; if (NewPacketType == SEND_PACKET_SHORT_HEADER_TYPE) { - QUIC_PACKET_SPACE* PacketSpace = Connection->Packets[Builder->EncryptLevel]; + QUIC_PACKET_SPACE* PacketSpace = Builder->Path->PathID->Packets[Builder->EncryptLevel]; Builder->PacketNumberLength = 4; // TODO - Determine correct length based on BDP. @@ -538,7 +538,7 @@ QuicPacketBuilderGetPacketTypeAndKeyForControlFrames( return TRUE; } - QUIC_PACKET_SPACE* Packets = Connection->Packets[EncryptLevel]; + QUIC_PACKET_SPACE* Packets = Builder->Path->PathID->Packets[EncryptLevel]; CXPLAT_DBG_ASSERT(Packets != NULL); if (SendFlags & QUIC_CONN_SEND_FLAG_ACK && @@ -715,7 +715,7 @@ QuicPacketBuilderFinalize( // packet. // if (Builder->Datagram != NULL) { - --Connection->Send.NextPacketNumber; + --Builder->Path->PathID->NextPacketNumber; Builder->DatagramLength -= Builder->HeaderLength; Builder->HeaderLength = 0; CanKeepSending = FALSE; @@ -838,7 +838,14 @@ QuicPacketBuilderFinalize( uint8_t* Payload = Header + Builder->HeaderLength; uint8_t Iv[CXPLAT_MAX_IV_LENGTH]; - QuicCryptoCombineIvAndPacketNumber(Builder->Key->Iv, (uint8_t*) &Builder->Metadata->PacketNumber, Iv); + if (Builder->Path->PathID->ID == 0) { + QuicCryptoCombineIvAndPacketNumber(Builder->Key->Iv, + (uint8_t*) &Builder->Metadata->PacketNumber, Iv); + } else { + QuicCryptoCombineIvAndPathIDAndPacketNumber(Builder->Key->Iv, + (uint8_t*) &Builder->Path->PathID->ID, + (uint8_t*) &Builder->Metadata->PacketNumber, Iv); + } QUIC_STATUS Status; if (QUIC_FAILED( @@ -910,7 +917,7 @@ QuicPacketBuilderFinalize( // // Increment the key phase sent bytes count. // - QUIC_PACKET_SPACE* PacketSpace = Connection->Packets[Builder->EncryptLevel]; + QUIC_PACKET_SPACE* PacketSpace = Builder->Path->PathID->Packets[Builder->EncryptLevel]; PacketSpace->CurrentKeyPhaseBytesSent += (PayloadLength - Builder->EncryptionOverhead); // @@ -963,6 +970,7 @@ QuicPacketBuilderFinalize( Builder->Metadata->PacketLength = Builder->HeaderLength + PayloadLength; Builder->Metadata->Flags.EcnEctSet = Builder->EcnEctSet; + Builder->Metadata->PathId = Builder->Path->ID; QuicTraceEvent( ConnPacketSent, "[conn][%p][TX][%llu] %hhu (%hu bytes)", @@ -971,7 +979,7 @@ QuicPacketBuilderFinalize( QuicPacketTraceType(Builder->Metadata), Builder->Metadata->PacketLength); QuicLossDetectionOnPacketSent( - &Connection->LossDetection, + &Builder->Path->PathID->LossDetection, Builder->Path, Builder->Metadata); diff --git a/src/core/packet_builder.h b/src/core/packet_builder.h index 912ce89769..0ecc4cd844 100644 --- a/src/core/packet_builder.h +++ b/src/core/packet_builder.h @@ -23,7 +23,7 @@ typedef struct QUIC_PACKET_BUILDER { // // The source connection ID. // - QUIC_CID_HASH_ENTRY* SourceCid; + QUIC_CID_SLIST_ENTRY* SourceCid; // // Represents a set of UDP datagrams. @@ -236,7 +236,7 @@ QuicPacketBuilderHasAllowance( { return Builder->SendAllowance > 0 || - QuicCongestionControlGetExemptions(&Builder->Connection->CongestionControl) > 0; + QuicCongestionControlGetExemptions(&Builder->Path->PathID->CongestionControl) > 0; } // @@ -247,7 +247,7 @@ inline BOOLEAN QuicPacketBuilderAddFrame( _Inout_ QUIC_PACKET_BUILDER* Builder, - _In_ uint8_t FrameType, + _In_ uint32_t FrameType, _In_ BOOLEAN IsAckEliciting ) { diff --git a/src/core/packet_space.c b/src/core/packet_space.c index 91f47e57bc..54ac97a5b2 100644 --- a/src/core/packet_space.c +++ b/src/core/packet_space.c @@ -18,7 +18,7 @@ _IRQL_requires_max_(DISPATCH_LEVEL) QUIC_STATUS QuicPacketSpaceInitialize( - _In_ QUIC_CONNECTION* Connection, + _In_ QUIC_PATHID* PathID, _In_ QUIC_ENCRYPT_LEVEL EncryptLevel, _Out_ QUIC_PACKET_SPACE** NewPackets ) @@ -34,7 +34,8 @@ QuicPacketSpaceInitialize( } CxPlatZeroMemory(Packets, sizeof(QUIC_PACKET_SPACE)); - Packets->Connection = Connection; + Packets->Connection = PathID->Connection; + Packets->PathID = PathID; Packets->EncryptLevel = EncryptLevel; QuicAckTrackerInitialize(&Packets->AckTracker); diff --git a/src/core/packet_space.h b/src/core/packet_space.h index b51e525bec..8b2cb94110 100644 --- a/src/core/packet_space.h +++ b/src/core/packet_space.h @@ -73,6 +73,8 @@ typedef struct QUIC_PACKET_SPACE { // QUIC_CONNECTION* Connection; + QUIC_PATHID* PathID; + // // List of received packets that we don't have the key for yet. // @@ -129,7 +131,7 @@ QuicAckTrackerGetPacketSpace( _IRQL_requires_max_(DISPATCH_LEVEL) QUIC_STATUS QuicPacketSpaceInitialize( - _In_ QUIC_CONNECTION* Connection, + _In_ QUIC_PATHID* PathID, _In_ QUIC_ENCRYPT_LEVEL EncryptLevel, _Out_ QUIC_PACKET_SPACE** NewPackets ); diff --git a/src/core/path.c b/src/core/path.c index 91a545c54e..68995e9542 100644 --- a/src/core/path.c +++ b/src/core/path.c @@ -69,6 +69,7 @@ QuicPathRemove( "Path[%hhu] Removed", Path->ID); + QuicPathIDRelease(Path->PathID, QUIC_PATHID_REF_PATH); #if DEBUG if (Path->DestCid) { QUIC_CID_CLEAR_PATH(Path->DestCid); @@ -116,7 +117,7 @@ QuicPathSetAllowance( // even cause the loss timer to fire immediately because packets // were already lost, but we didn't know it. // - QuicLossDetectionUpdateTimer(&Connection->LossDetection, TRUE); + QuicLossDetectionUpdateTimer(&Path->PathID->LossDetection, TRUE); } } else { @@ -183,6 +184,28 @@ QuicConnGetPathByID( return NULL; } +_IRQL_requires_max_(PASSIVE_LEVEL) +_Ret_maybenull_ +QUIC_PATH* +QuicConnGetPathByAddress( + _In_ QUIC_CONNECTION* Connection, + _In_ const QUIC_ADDR* LocalAddress, + _In_ const QUIC_ADDR* RemoteAddress + ) +{ + for (uint8_t i = 0; i < Connection->PathsCount; ++i) { + if (QuicAddrCompare( + LocalAddress, + &Connection->Paths[i].Route.LocalAddress) && + QuicAddrCompare( + RemoteAddress, + &Connection->Paths[i].Route.RemoteAddress)) { + return &Connection->Paths[i]; + } + } + return NULL; +} + _IRQL_requires_max_(PASSIVE_LEVEL) _Ret_maybenull_ QUIC_PATH* @@ -191,8 +214,15 @@ QuicConnGetPathForPacket( _In_ const QUIC_RX_PACKET* Packet ) { + BOOLEAN FatalError = FALSE; + QUIC_PATHID* PathID = QuicPathIDSetGetPathIDForLocal(&Connection->PathIDs, Packet->PathId, &FatalError); + CXPLAT_DBG_ASSERT(!FatalError); + if (PathID == NULL) { + return NULL; + } for (uint8_t i = 0; i < Connection->PathsCount; ++i) { - if (!QuicAddrCompare( + if (PathID != Connection->Paths[i].PathID || + !QuicAddrCompare( &Packet->Route->LocalAddress, &Connection->Paths[i].Route.LocalAddress) || !QuicAddrCompare( @@ -202,10 +232,12 @@ QuicConnGetPathForPacket( // // Ignore packets on any other paths until connected/confirmed. // + QuicPathIDRelease(PathID, QUIC_PATHID_REF_LOOKUP); return NULL; } continue; } + QuicPathIDRelease(PathID, QUIC_PATHID_REF_LOOKUP); return &Connection->Paths[i]; } @@ -221,6 +253,7 @@ QuicConnGetPathForPacket( && QuicAddrGetFamily(&Packet->Route->RemoteAddress) == QuicAddrGetFamily(&Connection->Paths[i].Route.RemoteAddress) && QuicAddrCompareIp(&Packet->Route->RemoteAddress, &Connection->Paths[i].Route.RemoteAddress) && QuicAddrCompare(&Packet->Route->LocalAddress, &Connection->Paths[i].Route.LocalAddress)) { + QuicLibraryReleaseBinding(Connection->Paths[i].Binding); QuicPathRemove(Connection, i); } } @@ -234,6 +267,11 @@ QuicConnGetPathForPacket( } } + if (!QuicLibraryTryAddRefBinding(Connection->Paths[0].Binding)) { + QuicPathIDRelease(PathID, QUIC_PATHID_REF_LOOKUP); + return NULL; + } + if (Connection->PathsCount > 1) { // // Make room for the new path (at index 1). @@ -253,8 +291,48 @@ QuicConnGetPathForPacket( Path->DestCid = Connection->Paths[0].DestCid; // TODO - Copy instead? } Path->Binding = Connection->Paths[0].Binding; + QuicPathIDAddRef(PathID, QUIC_PATHID_REF_PATH); + Path->PathID = PathID; + PathID->Path = Path; + QuicCongestionControlInitialize(&PathID->CongestionControl, &Connection->Settings); + PathID->Flags.InUse = TRUE; QuicCopyRouteInfo(&Path->Route, Packet->Route); QuicPathValidate(Path); + QuicPathIDRelease(PathID, QUIC_PATHID_REF_LOOKUP); + return Path; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +_Ret_notnull_ +QUIC_PATH* +QuicConnChoosePath( + _In_ QUIC_CONNECTION* Connection + ) +{ + QUIC_PATH* Path = &Connection->Paths[0]; + + if (Connection->State.MultipathNegotiated && Connection->State.HandshakeConfirmed) { + QUIC_PATH* ActivePaths[QUIC_MAX_PATH_COUNT]; + uint8_t ActivePathCount = 0; + for (uint8_t i = 0; i < Connection->PathsCount; ++i) { + if (Connection->Paths[i].IsActive && + !Connection->Paths[i].LocalClose && + !Connection->Paths[i].RemoteClose) { + ActivePaths[ActivePathCount++] = &Connection->Paths[i]; + } + } + if (ActivePathCount > 1) { + uint8_t Random; + CxPlatRandom(sizeof(Random), &Random); + Path = ActivePaths[Random % ActivePathCount]; + } + } + + QuicTraceLogConnInfo( + PathChosen, + Connection, + "Path[%hhu] Chosen", + Path->ID); return Path; } @@ -267,7 +345,10 @@ QuicPathSetActive( ) { BOOLEAN UdpPortChangeOnly = FALSE; - if (Path == &Connection->Paths[0]) { + + if (Connection->State.MultipathNegotiated) { + Path->IsActive = TRUE; + } else if (Path == &Connection->Paths[0]) { CXPLAT_DBG_ASSERT(!Path->IsActive); Path->IsActive = TRUE; } else { @@ -299,7 +380,7 @@ QuicPathSetActive( UdpPortChangeOnly); if (!UdpPortChangeOnly) { - QuicCongestionControlReset(&Connection->CongestionControl, FALSE); + QuicCongestionControlReset(&Path->PathID->CongestionControl, FALSE); } CXPLAT_DBG_ASSERT(Path->DestCid != NULL); CXPLAT_DBG_ASSERT(!Path->DestCid->CID.Retired); @@ -313,8 +394,8 @@ QuicPathUpdateQeo( _In_ CXPLAT_QEO_OPERATION Operation ) { - const QUIC_CID_HASH_ENTRY* SourceCid = - CXPLAT_CONTAINING_RECORD(Connection->SourceCids.Next, QUIC_CID_HASH_ENTRY, Link); + const QUIC_CID_SLIST_ENTRY* SourceCid = + CXPLAT_CONTAINING_RECORD(Path->PathID->SourceCids.Next, QUIC_CID_SLIST_ENTRY, Link); CXPLAT_QEO_CONNECTION Offloads[2] = { { Operation, @@ -323,7 +404,7 @@ QuicPathUpdateQeo( 0, // KeyPhase 0, // Reserved CXPLAT_QEO_CIPHER_TYPE_AEAD_AES_256_GCM, - Connection->Send.NextPacketNumber, + Path->PathID->NextPacketNumber, Path->Route.RemoteAddress, Path->DestCid->CID.Length, }, @@ -342,10 +423,10 @@ QuicPathUpdateQeo( CxPlatCopyMemory(Offloads[1].ConnectionId, SourceCid->CID.Data, SourceCid->CID.Length); if (Operation == CXPLAT_QEO_OPERATION_ADD) { - CXPLAT_DBG_ASSERT(Connection->Packets[QUIC_ENCRYPT_LEVEL_1_RTT]); - Offloads[0].KeyPhase = Connection->Packets[QUIC_ENCRYPT_LEVEL_1_RTT]->CurrentKeyPhase; - Offloads[1].KeyPhase = Connection->Packets[QUIC_ENCRYPT_LEVEL_1_RTT]->CurrentKeyPhase; - Offloads[1].NextPacketNumber = Connection->Packets[QUIC_ENCRYPT_LEVEL_1_RTT]->AckTracker.LargestPacketNumberAcknowledged; + CXPLAT_DBG_ASSERT(Path->PathID->Packets[QUIC_ENCRYPT_LEVEL_1_RTT]); + Offloads[0].KeyPhase = Path->PathID->Packets[QUIC_ENCRYPT_LEVEL_1_RTT]->CurrentKeyPhase; + Offloads[1].KeyPhase = Path->PathID->Packets[QUIC_ENCRYPT_LEVEL_1_RTT]->CurrentKeyPhase; + Offloads[1].NextPacketNumber = Path->PathID->Packets[QUIC_ENCRYPT_LEVEL_1_RTT]->AckTracker.LargestPacketNumberAcknowledged; if (QuicTlsPopulateOffloadKeys(Connection->Crypto.TLS, Connection->Crypto.TlsState.WriteKeys[QUIC_PACKET_KEY_1_RTT], "Tx offload", &Offloads[0]) && QuicTlsPopulateOffloadKeys(Connection->Crypto.TLS, Connection->Crypto.TlsState.ReadKeys[QUIC_PACKET_KEY_1_RTT], "Rx offload", &Offloads[1]) && QUIC_SUCCEEDED(CxPlatSocketUpdateQeo(Path->Binding->Socket, Offloads, 2))) { diff --git a/src/core/path.h b/src/core/path.h index 4fdc2d78d8..f5fd4107a0 100644 --- a/src/core/path.h +++ b/src/core/path.h @@ -101,6 +101,15 @@ typedef struct QUIC_PATH { // BOOLEAN SendResponse : 1; + BOOLEAN SendStatus : 1; + + BOOLEAN LocalClose : 1; + BOOLEAN LocalCloseAcked : 1; + + BOOLEAN SendAbandon : 1; + + BOOLEAN RemoteClose : 1; + // // Indicates the partition has updated for this path. // @@ -136,6 +145,8 @@ typedef struct QUIC_PATH { // QUIC_MTU_DISCOVERY MtuDiscovery; + QUIC_PATHID *PathID; + // // The binding used for sending/receiving UDP packets. // @@ -296,6 +307,15 @@ QuicConnGetPathByID( _Out_ uint8_t* Index ); +_IRQL_requires_max_(PASSIVE_LEVEL) +_Ret_maybenull_ +QUIC_PATH* +QuicConnGetPathByAddress( + _In_ QUIC_CONNECTION* Connection, + _In_ const QUIC_ADDR* LocalAddress, + _In_ const QUIC_ADDR* RemoteAddress + ); + _IRQL_requires_max_(PASSIVE_LEVEL) _Ret_maybenull_ QUIC_PATH* @@ -304,6 +324,13 @@ QuicConnGetPathForPacket( _In_ const QUIC_RX_PACKET* Packet ); +_IRQL_requires_max_(PASSIVE_LEVEL) +_Ret_notnull_ +QUIC_PATH* +QuicConnChoosePath( + _In_ QUIC_CONNECTION* Connection + ); + _IRQL_requires_max_(PASSIVE_LEVEL) void QuicCopyRouteInfo( diff --git a/src/core/pathid.c b/src/core/pathid.c new file mode 100644 index 0000000000..169b9e9fde --- /dev/null +++ b/src/core/pathid.c @@ -0,0 +1,885 @@ +/*++ + Copyright (c) Microsoft Corporation. + Licensed under the MIT License. +Abstract: + A path id manages the resources for multipath. This file + contains the initialization and cleanup functionality for the path id. +--*/ +#include "precomp.h" +#ifdef QUIC_CLOG +#include "pathid.c.clog.h" +#endif + +_IRQL_requires_max_(DISPATCH_LEVEL) +QUIC_STATUS +QuicPathIDInitialize( + _In_ QUIC_CONNECTION* Connection, + _Outptr_ _At_(*NewPathID, __drv_allocatesMem(Mem)) + QUIC_PATHID** NewPathID + ) +{ + QUIC_STATUS Status; + QUIC_PATHID* PathID = CXPLAT_ALLOC_NONPAGED(sizeof(QUIC_PATHID), QUIC_POOL_PATHID); + if (PathID == NULL) { + Status = QUIC_STATUS_OUT_OF_MEMORY; + goto Exit; + } + CxPlatZeroMemory(PathID, sizeof(QUIC_PATHID)); + PathID->ID = UINT32_MAX; + PathID->Connection = Connection; + PathID->SourceCidLimit = QUIC_ACTIVE_CONNECTION_ID_LIMIT; + CxPlatListInitializeHead(&PathID->DestCids); + QuicLossDetectionInitialize(&PathID->LossDetection); + PathID->RefCount = 1; +#if DEBUG + PathID->RefTypeCount[QUIC_PATHID_REF_PATHID_SET] = 1; +#endif + *NewPathID = PathID; + + Status = QUIC_STATUS_SUCCESS; +Exit: + return Status; +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +void +QuicPathIDFree( + _In_ __drv_freesMem(Mem) QUIC_PATHID* PathID + ) +{ + CXPLAT_TEL_ASSERT(PathID->SourceCids.Next == NULL); + + while (!CxPlatListIsEmpty(&PathID->DestCids)) { + QUIC_CID_LIST_ENTRY *CID = + CXPLAT_CONTAINING_RECORD( + CxPlatListRemoveHead(&PathID->DestCids), + QUIC_CID_LIST_ENTRY, + Link); + CXPLAT_FREE(CID, QUIC_POOL_CIDLIST); + } + + QuicLossDetectionUninitialize(&PathID->LossDetection); + + for (uint32_t i = 0; i < ARRAYSIZE(PathID->Packets); i++) { + if (PathID->Packets[i] != NULL) { + QuicPacketSpaceUninitialize(PathID->Packets[i]); + PathID->Packets[i] = NULL; + } + } + + PathID->Flags.Freed = TRUE; + CXPLAT_FREE(PathID, QUIC_POOL_PATHID); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +void +QuicPathIDProcessPathCloseTimerOperation( + _Inout_ QUIC_PATHID* PathID + ) +{ + if (PathID->Flags.WaitClose) { + uint64_t TimeNow = CxPlatTimeUs64(); + if (PathID->CloseTime <= TimeNow) { + PathID->Flags.WaitClose = FALSE; + PathID->Flags.Closed = TRUE; + QuicTraceEvent( + ConnPathIDCloseTimerExpired, + "[conn][%p][pathid][%u] Close Timer expired", + PathID->Connection, + PathID->ID); + QuicPathIDSetTryFreePathID(&PathID->Connection->PathIDs, PathID); + } + } +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +void +QuicPathIDAddDestCID( + _Inout_ QUIC_PATHID* PathID, + _In_ QUIC_CID_LIST_ENTRY *DestCid + ) +{ + CxPlatListInsertTail(&PathID->DestCids, &DestCid->Link); + QuicTraceEvent( + ConnDestCidAdded, + "[conn][%p][pathid][%u] (SeqNum=%llu) New Destination CID: %!CID!", + PathID->Connection, + PathID->ID, + DestCid->CID.SequenceNumber, + CASTED_CLOG_BYTEARRAY(DestCid->CID.Length, DestCid->CID.Data)); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +void +QuicPathIDAddSourceCID( + _Inout_ QUIC_PATHID* PathID, + _In_ QUIC_CID_SLIST_ENTRY *SourceCid, + _In_ BOOLEAN IsInitial + ) +{ + if (IsInitial) { + SourceCid->CID.IsInitial = TRUE; + CxPlatListPushEntry(&PathID->SourceCids, &SourceCid->Link); + } else { + CXPLAT_SLIST_ENTRY** Tail = &PathID->SourceCids.Next; + while (*Tail != NULL) { + Tail = &(*Tail)->Next; + } + *Tail = &SourceCid->Link; + SourceCid->Link.Next = NULL; + } + + QuicTraceEvent( + ConnSourceCidAdded, + "[conn][%p][pathid][%u] (SeqNum=%llu) New Source CID: %!CID!", + PathID->Connection, + PathID->ID, + SourceCid->CID.SequenceNumber, + CASTED_CLOG_BYTEARRAY(SourceCid->CID.Length, SourceCid->CID.Data)); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +void +QuicPathIDFreeSourceCids( + _Inout_ QUIC_PATHID* PathID + ) +{ + while (PathID->SourceCids.Next != NULL) { + QUIC_CID_SLIST_ENTRY* CID = + CXPLAT_CONTAINING_RECORD( + CxPlatListPopEntry(&PathID->SourceCids), + QUIC_CID_SLIST_ENTRY, + Link); + while (CID->HashEntries.Next != NULL) { + QUIC_CID_HASH_ENTRY* CID1 = + CXPLAT_CONTAINING_RECORD( + CxPlatListPopEntry(&CID->HashEntries), + QUIC_CID_HASH_ENTRY, + Link); + QuicBindingRemoveSourceConnectionID( + CID1->Binding, + CID1); + CXPLAT_FREE(CID1, QUIC_POOL_CIDHASH); + } + CXPLAT_FREE(CID, QUIC_POOL_CIDSLIST); + } +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +void +QuicPathIDTraceRundown( + _In_ QUIC_PATHID* PathID + ) +{ + for (CXPLAT_SLIST_ENTRY* Entry = PathID->SourceCids.Next; + Entry != NULL; + Entry = Entry->Next) { + const QUIC_CID_SLIST_ENTRY* SourceCid = + CXPLAT_CONTAINING_RECORD( + Entry, + QUIC_CID_SLIST_ENTRY, + Link); + UNREFERENCED_PARAMETER(SourceCid); + QuicTraceEvent( + ConnSourceCidAdded, + "[conn][%p][pathid][%u] (SeqNum=%llu) New Source CID: %!CID!", + PathID->Connection, + PathID->ID, + SourceCid->CID.SequenceNumber, + CASTED_CLOG_BYTEARRAY(SourceCid->CID.Length, SourceCid->CID.Data)); + } + for (CXPLAT_LIST_ENTRY* Entry = PathID->DestCids.Flink; + Entry != &PathID->DestCids; + Entry = Entry->Flink) { + const QUIC_CID_LIST_ENTRY* DestCid = + CXPLAT_CONTAINING_RECORD( + Entry, + QUIC_CID_LIST_ENTRY, + Link); + UNREFERENCED_PARAMETER(DestCid); + QuicTraceEvent( + ConnDestCidAdded, + "[conn][%p][pathid][%u] (SeqNum=%llu) New Destination CID: %!CID!", + PathID->Connection, + PathID->ID, + DestCid->CID.SequenceNumber, + CASTED_CLOG_BYTEARRAY(DestCid->CID.Length, DestCid->CID.Data)); + } +} + +uint8_t +QuicPathIDSourceCidsCount( + _In_ const QUIC_PATHID* PathID + ) +{ + uint8_t Count = 0; + const CXPLAT_SLIST_ENTRY* Entry = PathID->SourceCids.Next; + while (Entry != NULL) { + QUIC_CID_SLIST_ENTRY* SourceCid = + CXPLAT_CONTAINING_RECORD(Entry, QUIC_CID_SLIST_ENTRY, Link); + if (!SourceCid->CID.Retired) { + ++Count; + } + Entry = Entry->Next; + } + return Count; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +QUIC_CID_SLIST_ENTRY* +QuicPathIDGenerateNewSourceCid( + _In_ QUIC_PATHID* PathID, + _In_ BOOLEAN IsInitial + ) +{ + uint8_t TryCount = 0; + QUIC_CID_SLIST_ENTRY* SourceCid; + + if (!PathID->Connection->State.ShareBinding) { + // + // We aren't sharing the binding, therefore aren't actually using a CID. + // No need to generate a new one. + // + return NULL; + } + + uint8_t CurrentCidCount = QuicPathIDSourceCidsCount(PathID); + CXPLAT_DBG_ASSERT(CurrentCidCount < PathID->SourceCidLimit); + + // + // Find all the bindings that are currently in use by this connection. + // + QUIC_BINDING* Bindings[QUIC_MAX_PATH_COUNT] = {NULL}; + uint8_t BindingsCount = 0; + + for (uint8_t i = 0; i < PathID->Connection->PathsCount; ++i) { + if (PathID->Connection->Paths[i].Binding != NULL) { + BOOLEAN NewBinding = TRUE; + for (uint8_t j = 0; j < BindingsCount; ++j) { + if (PathID->Connection->Paths[i].Binding == Bindings[j]) { + NewBinding = FALSE; + break; + } + } + if (NewBinding) { + Bindings[BindingsCount++] = PathID->Connection->Paths[i].Binding; + } + } + } + + // + // Keep randomly generating new source CIDs until we find one that doesn't + // collide with an existing one. + // + + do { + SourceCid = + QuicCidNewRandomSource( + PathID, + PathID->Connection->ServerID, + PathID->Connection->PartitionID, + PathID->Connection->CibirId[0], + PathID->Connection->CibirId+2); + if (SourceCid == NULL) { + QuicTraceEvent( + AllocFailure, + "Allocation of '%s' failed. (%llu bytes)", + "new Src CID", + sizeof(QUIC_CID_SLIST_ENTRY) + MsQuicLib.CidTotalLength); + QuicConnFatalError(PathID->Connection, QUIC_STATUS_INTERNAL_ERROR, NULL); + return NULL; + } + + BOOLEAN Collision = FALSE; + int8_t Revert = -1; + for (uint8_t i = 0; i < BindingsCount; ++i) { + if (!QuicBindingAddSourceConnectionID(Bindings[i], SourceCid)) { + Collision = TRUE; + if (i > 0) { + Revert = i - 1; + } + break; + } + } + + if (Collision) { + if (Revert >= 0) { + for (int8_t i = Revert; i >= 0; --i) { + if (Bindings[i] != NULL) { + while (SourceCid->HashEntries.Next != NULL) { + QUIC_CID_HASH_ENTRY* CID = + CXPLAT_CONTAINING_RECORD( + CxPlatListPopEntry(&SourceCid->HashEntries), + QUIC_CID_HASH_ENTRY, + Link); + if (CID->Binding == Bindings[i]) { + QuicBindingRemoveSourceConnectionID( + Bindings[i], + CID); + CXPLAT_FREE(CID, QUIC_POOL_CIDHASH); + break; + } + } + } + } + } + CXPLAT_FREE(SourceCid, QUIC_POOL_CIDSLIST); + SourceCid = NULL; + if (++TryCount > QUIC_CID_MAX_COLLISION_RETRY) { + QuicTraceEvent( + ConnError, + "[conn][%p] ERROR, %s.", + PathID->Connection, + "Too many CID collisions"); + QuicConnFatalError(PathID->Connection, QUIC_STATUS_INTERNAL_ERROR, NULL); + return NULL; + } + QuicTraceLogConnVerbose( + NewSrcCidNameCollision, + PathID->Connection, + "CID collision, trying again"); + } + } while (SourceCid == NULL); + + SourceCid->CID.SequenceNumber = PathID->NextSourceCidSequenceNumber++; + + if (PathID->ID != 0 || SourceCid->CID.SequenceNumber > 0) { + SourceCid->CID.NeedsToSend = TRUE; + QuicSendSetSendFlag(&PathID->Connection->Send, QUIC_CONN_SEND_FLAG_NEW_CONNECTION_ID); + } + + QuicPathIDAddSourceCID(PathID, SourceCid, IsInitial); + + return SourceCid; +} + +// +// This generates new source CIDs for the peer to use to talk to us. If +// indicated, it invalidates all the existing ones, sets a a new retire prior to +// sequence number to send out and generates replacement CIDs. +// +_IRQL_requires_max_(PASSIVE_LEVEL) +void +QuicPathIDGenerateNewSourceCids( + _In_ QUIC_PATHID* PathID, + _In_ BOOLEAN ReplaceExistingCids + ) +{ + if (!PathID->Connection->State.ShareBinding) { + // + // Can't generate any new CIDs, so this is a no-op. + // + return; + } + + // + // If we're replacing existing ones, then generate all new CIDs (up to the + // limit). Otherwise, just generate whatever number we need to hit the + // limit. + // + uint8_t NewCidCount; + if (ReplaceExistingCids) { + NewCidCount = 0; + CXPLAT_SLIST_ENTRY* Entry = PathID->SourceCids.Next; + while (Entry != NULL) { + QUIC_CID_SLIST_ENTRY* SourceCid = + CXPLAT_CONTAINING_RECORD(Entry, QUIC_CID_SLIST_ENTRY, Link); + if (!SourceCid->CID.Retired) { + SourceCid->CID.Retired = TRUE; + NewCidCount++; + } + Entry = Entry->Next; + } + } else { + uint8_t CurrentCidCount = QuicPathIDSourceCidsCount(PathID); + CXPLAT_DBG_ASSERT(CurrentCidCount <= PathID->SourceCidLimit); + if (CurrentCidCount < PathID->SourceCidLimit) { + NewCidCount = PathID->SourceCidLimit - CurrentCidCount; + } else { + NewCidCount = 0; + } + } + + for (uint8_t i = 0; i < NewCidCount; ++i) { + if (QuicPathIDGenerateNewSourceCid(PathID, FALSE) == NULL) { + break; + } + } +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +QUIC_CID_LIST_ENTRY* +QuicPathIDGetUnusedDestCid( + _In_ const QUIC_PATHID* PathID + ) +{ + for (CXPLAT_LIST_ENTRY* Entry = PathID->DestCids.Flink; + Entry != &PathID->DestCids; + Entry = Entry->Flink) { + QUIC_CID_LIST_ENTRY* DestCid = + CXPLAT_CONTAINING_RECORD( + Entry, + QUIC_CID_LIST_ENTRY, + Link); + if (!DestCid->CID.UsedLocally && !DestCid->CID.Retired) { + return DestCid; + } + } + return NULL; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +void +QuicPathIDRetireCid( + _In_ QUIC_PATHID* PathID, + _In_ QUIC_CID_LIST_ENTRY* DestCid + ) +{ + QuicTraceEvent( + ConnDestCidRemoved, + "[conn][%p][pathid][%u] (SeqNum=%llu) Removed Destination CID: %!CID!", + PathID->Connection, + PathID->ID, + DestCid->CID.SequenceNumber, + CASTED_CLOG_BYTEARRAY(DestCid->CID.Length, DestCid->CID.Data)); + PathID->DestCidCount--; + DestCid->CID.Retired = TRUE; + DestCid->CID.NeedsToSend = TRUE; + QuicSendSetSendFlag(&PathID->Connection->Send, QUIC_CONN_SEND_FLAG_RETIRE_CONNECTION_ID); + + PathID->RetiredDestCidCount++; + if (PathID->RetiredDestCidCount > 8 * QUIC_ACTIVE_CONNECTION_ID_LIMIT) { + QuicTraceEvent( + ConnError, + "[conn][%p] ERROR, %s.", + PathID->Connection, + "Peer exceeded retire CID limit"); + QuicConnSilentlyAbort(PathID->Connection); + } +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +BOOLEAN +QuicPathIDRetireCurrentDestCid( + _In_ QUIC_PATHID* PathID, + _In_ QUIC_PATH* Path + ) +{ + if (Path->DestCid->CID.Length == 0) { + QuicTraceLogConnVerbose( + ZeroLengthCidRetire, + PathID->Connection, + "Can't retire current CID because it's zero length"); + return TRUE; // No need to update so treat as success. + } + + QUIC_CID_LIST_ENTRY* NewDestCid = QuicPathIDGetUnusedDestCid(PathID); + if (NewDestCid == NULL) { + QuicTraceLogConnWarning( + NoReplacementCidForRetire, + PathID->Connection, + "Can't retire current CID because we don't have a replacement"); + return FALSE; + } + + CXPLAT_DBG_ASSERT(Path->DestCid != NewDestCid); + QUIC_CID_LIST_ENTRY* OldDestCid = Path->DestCid; + QUIC_CID_CLEAR_PATH(Path->DestCid); + QuicPathIDRetireCid(PathID, Path->DestCid); + Path->DestCid = NewDestCid; + QUIC_CID_SET_PATH(PathID->Connection, Path->DestCid, Path); + QUIC_CID_VALIDATE_NULL(PathID->Connection, OldDestCid); + Path->DestCid->CID.UsedLocally = TRUE; + QuicTraceEvent( + ConnDestCidUpdated, + "[conn][%p][pathid][%u] (SeqNum=%llu) Updated Destination CID: %!CID!", + PathID->Connection, + PathID->ID, + Path->DestCid->CID.SequenceNumber, + CASTED_CLOG_BYTEARRAY(Path->DestCid->CID.Length, Path->DestCid->CID.Data)); + + PathID->Connection->Stats.Misc.DestCidUpdateCount++; + + return TRUE; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +BOOLEAN +QuicPathIDOnRetirePriorToUpdated( + _In_ QUIC_PATHID* PathID + ) +{ + BOOLEAN ReplaceRetiredCids = FALSE; + + for (CXPLAT_LIST_ENTRY* Entry = PathID->DestCids.Flink; + Entry != &PathID->DestCids; + Entry = Entry->Flink) { + QUIC_CID_LIST_ENTRY* DestCid = + CXPLAT_CONTAINING_RECORD( + Entry, + QUIC_CID_LIST_ENTRY, + Link); + if (DestCid->CID.SequenceNumber >= PathID->RetirePriorTo || + DestCid->CID.Retired) { + continue; + } + + if (DestCid->CID.UsedLocally) { + ReplaceRetiredCids = TRUE; + } + + QUIC_CID_CLEAR_PATH(DestCid); + QuicPathIDRetireCid(PathID, DestCid); + } + + return ReplaceRetiredCids; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +BOOLEAN +QuicPathIDReplaceRetiredCids( + _In_ QUIC_PATHID* PathID + ) +{ + CXPLAT_DBG_ASSERT(PathID->Connection->PathsCount <= QUIC_MAX_PATH_COUNT); + for (uint8_t i = 0; i < PathID->Connection->PathsCount; ++i) { + QUIC_PATH* Path = &PathID->Connection->Paths[i]; + if (Path->PathID != PathID || Path->DestCid == NULL || !Path->DestCid->CID.Retired) { + continue; + } + + QUIC_CID_LIST_ENTRY* NewDestCid = QuicPathIDGetUnusedDestCid(PathID); + if (NewDestCid == NULL) { + if (Path->IsActive) { + QuicTraceEvent( + ConnError, + "[conn][%p] ERROR, %s.", + PathID->Connection, + "Active path has no replacement for retired CID"); + QuicConnSilentlyAbort(PathID->Connection); // Must silently abort because we can't send anything now. + return FALSE; + } + QuicTraceLogConnWarning( + NonActivePathCidRetired, + PathID->Connection, + "Non-active path has no replacement for retired CID."); + CXPLAT_DBG_ASSERT(i != 0); + CXPLAT_DBG_ASSERT(PathID->Connection->Paths[i].Binding != NULL); + QuicLibraryReleaseBinding(PathID->Connection->Paths[i].Binding); + PathID->Connection->Paths[i].Binding = NULL; + QuicPathRemove(PathID->Connection, i--); + continue; + } + + CXPLAT_DBG_ASSERT(NewDestCid != Path->DestCid); + QUIC_CID_LIST_ENTRY* OldDestCid = Path->DestCid; + Path->DestCid = NewDestCid; + QUIC_CID_SET_PATH(PathID->Connection, NewDestCid, Path); + QUIC_CID_VALIDATE_NULL(PathID->Connection, OldDestCid); + Path->DestCid->CID.UsedLocally = TRUE; + Path->InitiatedCidUpdate = TRUE; + QuicPathValidate(Path); + QuicTraceEvent( + ConnDestCidUpdated, + "[conn][%p][pathid][%u] (SeqNum=%llu) Updated Destination CID: %!CID!", + PathID->Connection, + PathID->ID, + Path->DestCid->CID.SequenceNumber, + CASTED_CLOG_BYTEARRAY(Path->DestCid->CID.Length, Path->DestCid->CID.Data)); + + } + +#if DEBUG + for (CXPLAT_LIST_ENTRY* Entry = PathID->DestCids.Flink; + Entry != &PathID->DestCids; + Entry = Entry->Flink) { + QUIC_CID_LIST_ENTRY* DestCid = + CXPLAT_CONTAINING_RECORD( + Entry, + QUIC_CID_LIST_ENTRY, + Link); + CXPLAT_DBG_ASSERT(!DestCid->CID.Retired || DestCid->AssignedPath == NULL); + } +#endif + + return TRUE; +} + +// +// Updates the current destination CID to the received packet's source CID, if +// not already equal. Only used during the handshake, on the client side. +// +_IRQL_requires_max_(PASSIVE_LEVEL) +BOOLEAN +QuicPathIDUpdateDestCid( + _In_ QUIC_PATHID* PathID, + _In_ const QUIC_RX_PACKET* const Packet + ) +{ + CXPLAT_DBG_ASSERT(QuicConnIsClient(PathID->Connection)); + CXPLAT_DBG_ASSERT(!PathID->Connection->State.Connected); + + if (CxPlatListIsEmpty(&PathID->DestCids)) { + CXPLAT_DBG_ASSERT(CxPlatIsRandomMemoryFailureEnabled()); + QuicConnTransportError(PathID->Connection, QUIC_ERROR_INTERNAL_ERROR); + return FALSE; + } + QUIC_CID_LIST_ENTRY* DestCid = + CXPLAT_CONTAINING_RECORD( + PathID->DestCids.Flink, + QUIC_CID_LIST_ENTRY, + Link); + CXPLAT_DBG_ASSERT(PathID->Connection->Paths[0].DestCid == DestCid); + + if (Packet->SourceCidLen != DestCid->CID.Length || + memcmp(Packet->SourceCid, DestCid->CID.Data, DestCid->CID.Length) != 0) { + + // TODO - Only update for the first packet of each type (Initial and Retry). + + QuicTraceEvent( + ConnDestCidRemoved, + "[conn][%p][pathid][%u] (SeqNum=%llu) Removed Destination CID: %!CID!", + PathID->Connection, + PathID->ID, + DestCid->CID.SequenceNumber, + CASTED_CLOG_BYTEARRAY(DestCid->CID.Length, DestCid->CID.Data)); + + // + // We have just received the a packet from a new source CID + // from the server. Remove the current DestCid we have for the + // server (which we randomly generated) and replace it with + // the one we have just received. + // + if (Packet->SourceCidLen <= DestCid->CID.Length) { + // + // Since the current structure has enough room for the + // new CID, we will just reuse it. + // + DestCid->CID.IsInitial = FALSE; + DestCid->CID.Length = Packet->SourceCidLen; + CxPlatCopyMemory(DestCid->CID.Data, Packet->SourceCid, DestCid->CID.Length); + } else { + // + // There isn't enough room in the existing structure, + // so we must allocate a new one and free the old one. + // + CxPlatListEntryRemove(&DestCid->Link); + CXPLAT_FREE(DestCid, QUIC_POOL_CIDLIST); + DestCid = + QuicCidNewDestination( + Packet->SourceCidLen, + Packet->SourceCid); + if (DestCid == NULL) { + PathID->DestCidCount--; + PathID->Connection->Paths[0].DestCid = NULL; + QuicConnFatalError(PathID->Connection, QUIC_STATUS_OUT_OF_MEMORY, "Out of memory"); + return FALSE; + } + + PathID->Connection->Paths[0].DestCid = DestCid; + QUIC_CID_SET_PATH(PathID->Connection, DestCid, &PathID->Connection->Paths[0]); + DestCid->CID.UsedLocally = TRUE; + CxPlatListInsertHead(&PathID->DestCids, &DestCid->Link); + } + + if (DestCid != NULL) { + QuicTraceEvent( + ConnDestCidAdded, + "[conn][%p][pathid][%u] (SeqNum=%llu) New Destination CID: %!CID!", + PathID->Connection, + PathID->ID, + DestCid->CID.SequenceNumber, + CASTED_CLOG_BYTEARRAY(DestCid->CID.Length, DestCid->CID.Data)); + } + } + + return TRUE; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +BOOLEAN +QuicPathIDAssignCids( + _In_ QUIC_PATHID* PathID + ) +{ + BOOLEAN Assigned = FALSE; + + CXPLAT_DBG_ASSERT(PathID->Connection->PathsCount <= QUIC_MAX_PATH_COUNT); + for (uint8_t i = 0; i < PathID->Connection->PathsCount; ++i) { + QUIC_PATH* Path = &PathID->Connection->Paths[i]; + if (Path->PathID != PathID || Path->DestCid != NULL || !Path->InUse) { + continue; + } + + QUIC_CID_LIST_ENTRY* NewDestCid = QuicPathIDGetUnusedDestCid(PathID); + if (NewDestCid == NULL) { + return Assigned; + } + + Path->DestCid = NewDestCid; + QUIC_CID_SET_PATH(PathID->Connection, NewDestCid, Path); + Path->DestCid->CID.UsedLocally = TRUE; + QuicPathValidate(Path); + + Path->SendChallenge = TRUE; + Path->PathValidationStartTime = CxPlatTimeUs64(); + + CxPlatRandom(sizeof(Path->Challenge), Path->Challenge); + + Assigned = TRUE; + } + + return Assigned; +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +BOOLEAN +QuicPathIDWriteAckFrame( + _In_ QUIC_PATHID* PathID, + _Inout_ QUIC_PACKET_BUILDER* Builder + ) +{ + QUIC_PACKET_SPACE* Packets = PathID->Packets[Builder->EncryptLevel]; + if (Packets != NULL && QuicAckTrackerHasPacketsToAck(&Packets->AckTracker)) { + if (!QuicAckTrackerAckFrameEncode(&Packets->AckTracker, Builder)) { + return FALSE; + } + } + return TRUE; +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +BOOLEAN +QuicPathIDWriteNewConnectionIDFrame( + _In_ QUIC_PATHID* PathID, + _Inout_ QUIC_PACKET_BUILDER* Builder, + _In_ uint16_t AvailableBufferLength, + _Inout_ BOOLEAN* HasMoreCidsToSend, + _Inout_ BOOLEAN* MaxFrameLimitHit + ) +{ + QUIC_FRAME_TYPE FrameType = + PathID->Connection->State.MultipathNegotiated ? + QUIC_FRAME_PATH_NEW_CONNECTION_ID : QUIC_FRAME_NEW_CONNECTION_ID; + for (CXPLAT_SLIST_ENTRY* Entry = PathID->SourceCids.Next; + Entry != NULL; + Entry = Entry->Next) { + QUIC_CID_SLIST_ENTRY* SourceCid = + CXPLAT_CONTAINING_RECORD( + Entry, + QUIC_CID_SLIST_ENTRY, + Link); + if (!SourceCid->CID.NeedsToSend) { + continue; + } + if (*MaxFrameLimitHit) { + *HasMoreCidsToSend = TRUE; + return TRUE; + } + + QUIC_NEW_CONNECTION_ID_EX Frame = { + SourceCid->CID.Length, + PathID->ID, + SourceCid->CID.SequenceNumber, + 0, + { 0 } }; + CXPLAT_DBG_ASSERT(PathID->SourceCidLimit >= QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT_MIN); + if (Frame.Sequence >= PathID->SourceCidLimit) { + Frame.RetirePriorTo = Frame.Sequence + 1 - PathID->SourceCidLimit; + } + CxPlatCopyMemory( + Frame.Buffer, + SourceCid->CID.Data, + SourceCid->CID.Length); + CXPLAT_DBG_ASSERT(SourceCid->CID.Length == MsQuicLib.CidTotalLength); + QuicLibraryGenerateStatelessResetToken( + SourceCid->CID.Data, + Frame.Buffer + SourceCid->CID.Length); + + if (QuicNewConnectionIDFrameEncode( + FrameType, + &Frame, + &Builder->DatagramLength, + AvailableBufferLength, + Builder->Datagram->Buffer)) { + + SourceCid->CID.NeedsToSend = FALSE; + Builder->Metadata->Frames[ + Builder->Metadata->FrameCount].NEW_CONNECTION_ID.PathID = + PathID->ID; + Builder->Metadata->Frames[ + Builder->Metadata->FrameCount].NEW_CONNECTION_ID.Sequence = + SourceCid->CID.SequenceNumber; + *MaxFrameLimitHit = + QuicPacketBuilderAddFrame( + Builder, + FrameType, + TRUE); + } else { + *HasMoreCidsToSend = TRUE; + return FALSE; + } + } + return TRUE; +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +BOOLEAN +QuicPathIDWriteRetireConnectionIDFrame( + _In_ QUIC_PATHID* PathID, + _Inout_ QUIC_PACKET_BUILDER* Builder, + _In_ uint16_t AvailableBufferLength, + _Inout_ BOOLEAN* HasMoreCidsToSend, + _Inout_ BOOLEAN* MaxFrameLimitHit + ) +{ + QUIC_FRAME_TYPE FrameType = + PathID->Connection->State.MultipathNegotiated ? + QUIC_FRAME_PATH_RETIRE_CONNECTION_ID : QUIC_FRAME_RETIRE_CONNECTION_ID; + for (CXPLAT_LIST_ENTRY* Entry = PathID->DestCids.Flink; + Entry != &PathID->DestCids; + Entry = Entry->Flink) { + QUIC_CID_LIST_ENTRY* DestCid = + CXPLAT_CONTAINING_RECORD( + Entry, + QUIC_CID_LIST_ENTRY, + Link); + if (!DestCid->CID.NeedsToSend) { + continue; + } + CXPLAT_DBG_ASSERT(DestCid->CID.Retired); + + if (*MaxFrameLimitHit) { + *HasMoreCidsToSend = TRUE; + return TRUE; + } + + QUIC_RETIRE_CONNECTION_ID_EX Frame = { + PathID->ID, + DestCid->CID.SequenceNumber + }; + + if (QuicRetireConnectionIDFrameEncode( + FrameType, + &Frame, + &Builder->DatagramLength, + AvailableBufferLength, + Builder->Datagram->Buffer)) { + + DestCid->CID.NeedsToSend = FALSE; + Builder->Metadata->Frames[ + Builder->Metadata->FrameCount].RETIRE_CONNECTION_ID.PathID = + PathID->ID; + Builder->Metadata->Frames[ + Builder->Metadata->FrameCount].RETIRE_CONNECTION_ID.Sequence = + DestCid->CID.SequenceNumber; + + *MaxFrameLimitHit = + QuicPacketBuilderAddFrame(Builder, FrameType, TRUE); + } else { + *HasMoreCidsToSend = TRUE; + return FALSE; + } + } + return TRUE; +} diff --git a/src/core/pathid.h b/src/core/pathid.h new file mode 100644 index 0000000000..6d7df55f02 --- /dev/null +++ b/src/core/pathid.h @@ -0,0 +1,464 @@ +/*++ + Copyright (c) Microsoft Corporation. + Licensed under the MIT License. +--*/ +#ifdef QUIC_CLOG +#include "pathid.h.clog.h" +#endif + +// +// Different flags of a pathid. +// Note - Keep quictypes.h's copy up to date. +// +typedef union QUIC_PATHID_FLAGS { + uint64_t AllFlags; + struct { + BOOLEAN InPathIDTable : 1; // The path id is currently in the connection's table. + BOOLEAN InUse : 1; // The path id is currently in use. + BOOLEAN Abandoned : 1; + BOOLEAN WaitClose : 1; + BOOLEAN Closed : 1; + BOOLEAN Started : 1; // The path id has started. + BOOLEAN Freed : 1; // The path id has been freed. + BOOLEAN LocalBlocked : 1; // The path id is blocked by local restriction. + BOOLEAN PeerBlocked : 1; // The path id is blocked by peer restriction. + }; +} QUIC_PATHID_FLAGS; + +// +// Different references on a PathID. +// +typedef enum QUIC_PATHID_REF { + + QUIC_PATHID_REF_PATHID_SET, + QUIC_PATHID_REF_PATH, + QUIC_PATHID_REF_SEND, + QUIC_PATHID_REF_SEND_PACKET, + QUIC_PATHID_REF_LOOKUP, + QUIC_PATHID_REF_OPERATION, + + QUIC_PATHID_REF_COUNT + +} QUIC_PATHID_REF; + +// +// This structure represents all the per path id specific data. +// +typedef struct QUIC_PATHID { + + QUIC_CONNECTION* Connection; + + QUIC_PATH* Path; + + // + // Unique identifier; + // + uint32_t ID; + + // + // The current flags for this path id. + // + QUIC_PATHID_FLAGS Flags; + + // + // The entry in the connection's hashtable of path ids. + // + CXPLAT_HASHTABLE_ENTRY TableEntry; + + // + // The list of connection IDs used for receiving. + // + CXPLAT_SLIST_ENTRY SourceCids; + + // + // The list of connection IDs used for sending. Given to us by the peer. + // + CXPLAT_LIST_ENTRY DestCids; + + // + // Number of non-retired desintation CIDs we currently have cached. + // + uint8_t DestCidCount; + + // + // Number of retired desintation CIDs we currently have cached. + // + uint8_t RetiredDestCidCount; + + // + // The maximum number of source CIDs to give the peer. This is a minimum of + // what we're willing to support and what the peer is willing to accept. + // + uint8_t SourceCidLimit; + + // + // The sequence number to use for the next source CID. + // + QUIC_VAR_INT NextSourceCidSequenceNumber; + + // + // The most recent Retire Prior To field received in a NEW_CONNECTION_ID + // frame. + // + QUIC_VAR_INT RetirePriorTo; + + uint64_t CloseTime; + + // + // Per-encryption level packet space information. + // + QUIC_PACKET_SPACE* Packets[QUIC_ENCRYPT_LEVEL_COUNT]; + + // + // Manages all the information for outstanding sent packets. + // + QUIC_LOSS_DETECTION LossDetection; + + // + // Congestion control state. + // + QUIC_CONGESTION_CONTROL CongestionControl; + + // + // The next packet number to use. + // + uint64_t NextPacketNumber; + + // + // Number of references to the handle. + // + CXPLAT_REF_COUNT RefCount; + +#if DEBUG + short RefTypeCount[QUIC_PATHID_REF_COUNT]; +#endif + + uint64_t StatusSendSeq; + + uint64_t StatusRecvSeq; + +} QUIC_PATHID; + +// +// Allocates and partially initializes a new path id object. +// +_IRQL_requires_max_(DISPATCH_LEVEL) +QUIC_STATUS +QuicPathIDInitialize( + _In_ QUIC_CONNECTION* Connection, + _Outptr_ _At_(*NewPathID, __drv_allocatesMem(Mem)) + QUIC_PATHID** NewPathID + ); + +// +// Free the path id object. +// +_IRQL_requires_max_(DISPATCH_LEVEL) +void +QuicPathIDFree( + _In_ __drv_freesMem(Mem) QUIC_PATHID* PathID + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +void +QuicPathIDAddDestCID( + _Inout_ QUIC_PATHID* PathID, + _In_ QUIC_CID_LIST_ENTRY *DestCid + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +void +QuicPathIDAddSourceCID( + _Inout_ QUIC_PATHID* PathID, + _In_ QUIC_CID_SLIST_ENTRY *SourceCid, + _In_ BOOLEAN IsInitial + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +void +QuicPathIDFreeSourceCids( + _Inout_ QUIC_PATHID* PathID + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +void +QuicPathIDProcessPathCloseTimerOperation( + _Inout_ QUIC_PATHID* PathID + ); + +// +// Tracing rundown for the pathid. +// +_IRQL_requires_max_(PASSIVE_LEVEL) +void +QuicPathIDTraceRundown( + _In_ QUIC_PATHID* PathID + ); + +// +// Generates a new source connection ID. +// +_IRQL_requires_max_(PASSIVE_LEVEL) +QUIC_CID_SLIST_ENTRY* +QuicPathIDGenerateNewSourceCid( + _In_ QUIC_PATHID* PathID, + _In_ BOOLEAN IsInitial + ); + +// +// Generates any necessary source CIDs. +// +_IRQL_requires_max_(PASSIVE_LEVEL) +void +QuicPathIDGenerateNewSourceCids( + _In_ QUIC_PATHID* PathID, + _In_ BOOLEAN ReplaceExistingCids + ); + +// +// Look up a source CID by sequence number. +// +_IRQL_requires_max_(DISPATCH_LEVEL) +_Success_(return != NULL) +inline +QUIC_CID_SLIST_ENTRY* +QuicPathIDGetSourceCidFromSeq( + _In_ QUIC_PATHID* PathID, + _In_ QUIC_VAR_INT SequenceNumber, + _In_ BOOLEAN RemoveFromList, + _Out_ BOOLEAN* IsLastCid + ) +{ + for (CXPLAT_SLIST_ENTRY** Entry = &PathID->SourceCids.Next; + *Entry != NULL; + Entry = &(*Entry)->Next) { + QUIC_CID_SLIST_ENTRY* SourceCid = + CXPLAT_CONTAINING_RECORD( + *Entry, + QUIC_CID_SLIST_ENTRY, + Link); + if (SourceCid->CID.SequenceNumber == SequenceNumber) { + if (RemoveFromList) { + while (SourceCid->HashEntries.Next != NULL) { + QUIC_CID_HASH_ENTRY* CID = + CXPLAT_CONTAINING_RECORD( + CxPlatListPopEntry(&SourceCid->HashEntries), + QUIC_CID_HASH_ENTRY, + Link); + QuicBindingRemoveSourceConnectionID( + CID->Binding, + CID); + } + QuicTraceEvent( + ConnSourceCidRemoved, + "[conn][%p][pathid][%u] (SeqNum=%llu) Removed Source CID: %!CID!", + PathID->Connection, + PathID->ID, + SourceCid->CID.SequenceNumber, + CASTED_CLOG_BYTEARRAY(SourceCid->CID.Length, SourceCid->CID.Data)); + *Entry = (*Entry)->Next; + } + *IsLastCid = PathID->SourceCids.Next == NULL; + return SourceCid; + } + } + return NULL; +} + +// +// Look up a source CID by data buffer. +// +_IRQL_requires_max_(DISPATCH_LEVEL) +inline +QUIC_CID_SLIST_ENTRY* +QuicPathIDGetSourceCidFromBuf( + _In_ QUIC_PATHID* PathID, + _In_ uint8_t CidLength, + _In_reads_(CidLength) + const uint8_t* CidBuffer + ) +{ + for (CXPLAT_SLIST_ENTRY* Entry = PathID->SourceCids.Next; + Entry != NULL; + Entry = Entry->Next) { + QUIC_CID_SLIST_ENTRY* SourceCid = + CXPLAT_CONTAINING_RECORD( + Entry, + QUIC_CID_SLIST_ENTRY, + Link); + if (CidLength == SourceCid->CID.Length && + memcmp(CidBuffer, SourceCid->CID.Data, CidLength) == 0) { + return SourceCid; + } + } + return NULL; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +QUIC_CID_LIST_ENTRY* +QuicPathIDGetUnusedDestCid( + _In_ const QUIC_PATHID* PathID + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +void +QuicPathIDRetireCid( + _In_ QUIC_PATHID* PathID, + _In_ QUIC_CID_LIST_ENTRY* DestCid + ); + +// +// Retires the currently used destination connection ID. +// +_IRQL_requires_max_(PASSIVE_LEVEL) +BOOLEAN +QuicPathIDRetireCurrentDestCid( + _In_ QUIC_PATHID* PathID, + _In_ QUIC_PATH* Path + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +BOOLEAN +QuicPathIDOnRetirePriorToUpdated( + _In_ QUIC_PATHID* PathID + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +BOOLEAN +QuicPathIDReplaceRetiredCids( + _In_ QUIC_PATHID* PathID + ); + +// +// Updates the current destination CID to the received packet's source CID, if +// not already equal. Only used during the handshake, on the client side. +// +_IRQL_requires_max_(PASSIVE_LEVEL) +BOOLEAN +QuicPathIDUpdateDestCid( + _In_ QUIC_PATHID* PathID, + _In_ const QUIC_RX_PACKET* const Packet + ); + +// +// Look up a source CID by sequence number. +// +_IRQL_requires_max_(DISPATCH_LEVEL) +inline +QUIC_CID_LIST_ENTRY* +QuicPathIDGetDestCidFromSeq( + _In_ QUIC_PATHID* PathID, + _In_ QUIC_VAR_INT SequenceNumber, + _In_ BOOLEAN RemoveFromList + ) +{ + for (CXPLAT_LIST_ENTRY* Entry = PathID->DestCids.Flink; + Entry != &PathID->DestCids; + Entry = Entry->Flink) { + QUIC_CID_LIST_ENTRY* DestCid = + CXPLAT_CONTAINING_RECORD( + Entry, + QUIC_CID_LIST_ENTRY, + Link); + if (DestCid->CID.SequenceNumber == SequenceNumber) { + if (RemoveFromList) { + CxPlatListEntryRemove(Entry); + } + return DestCid; + } + } + return NULL; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +BOOLEAN +QuicPathIDAssignCids( + _In_ QUIC_PATHID* PathID + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +BOOLEAN +QuicPathIDWriteAckFrame( + _In_ QUIC_PATHID* PathID, + _Inout_ QUIC_PACKET_BUILDER* Builder + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +BOOLEAN +QuicPathIDWriteNewConnectionIDFrame( + _In_ QUIC_PATHID* PathID, + _Inout_ QUIC_PACKET_BUILDER* Builder, + _In_ uint16_t AvailableBufferLength, + _Inout_ BOOLEAN* HasMoreCidsToSend, + _Inout_ BOOLEAN* MaxFrameLimitHit + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +BOOLEAN +QuicPathIDWriteRetireConnectionIDFrame( + _In_ QUIC_PATHID* PathID, + _Inout_ QUIC_PACKET_BUILDER* Builder, + _In_ uint16_t AvailableBufferLength, + _Inout_ BOOLEAN* HasMoreCidsToSend, + _Inout_ BOOLEAN* MaxFrameLimitHit + ); + +// +// Adds a ref to a PathID. +// +_IRQL_requires_max_(DISPATCH_LEVEL) +inline +void +QuicPathIDAddRef( + _In_ QUIC_PATHID* PathID, + _In_ QUIC_PATHID_REF Ref + ) +{ + CXPLAT_DBG_ASSERT(PathID->Connection); + CXPLAT_DBG_ASSERT(PathID->RefCount > 0); + +#if DEBUG + InterlockedIncrement16((volatile short*)&PathID->RefTypeCount[Ref]); +#else + UNREFERENCED_PARAMETER(Ref); +#endif + + CxPlatRefIncrement(&PathID->RefCount); +} + +// +// Releases a ref on a PathID. +// +#pragma warning(push) +#pragma warning(disable:6014) // SAL doesn't understand ref counts +_IRQL_requires_max_(DISPATCH_LEVEL) +inline +BOOLEAN +QuicPathIDRelease( + _In_ __drv_freesMem(Mem) QUIC_PATHID* PathID, + _In_ QUIC_PATHID_REF Ref + ) +{ + CXPLAT_DBG_ASSERT(PathID->Connection); + CXPLAT_TEL_ASSERT(PathID->RefCount > 0); + +#if DEBUG + CXPLAT_TEL_ASSERT(PathID->RefTypeCount[Ref] > 0); + uint16_t result = (uint16_t)InterlockedDecrement16((volatile short*)&PathID->RefTypeCount[Ref]); + CXPLAT_TEL_ASSERT(result != 0xFFFF); +#else + UNREFERENCED_PARAMETER(Ref); +#endif + + if (CxPlatRefDecrement(&PathID->RefCount)) { +#if DEBUG + for (uint32_t i = 0; i < QUIC_PATHID_REF_COUNT; i++) { + CXPLAT_TEL_ASSERT(PathID->RefTypeCount[i] == 0); + } +#endif + QuicPathIDFree(PathID); + return TRUE; + } + return FALSE; +} +#pragma warning(pop) diff --git a/src/core/pathid_set.c b/src/core/pathid_set.c new file mode 100644 index 0000000000..6908af4bce --- /dev/null +++ b/src/core/pathid_set.c @@ -0,0 +1,878 @@ +/*++ + Copyright (c) Microsoft Corporation. + Licensed under the MIT License. +Abstract: + A path id set manages all PathID-related state for a single connection. It + keeps track of locally and remotely initiated path ids, and synchronizes max + path ids with the peer. +--*/ +#include "precomp.h" +#ifdef QUIC_CLOG +#include "pathid_set.c.clog.h" +#endif + +_IRQL_requires_max_(PASSIVE_LEVEL) +void +QuicPathIDSetInitialize( + _Inout_ QUIC_PATHID_SET* PathIDSet + ) +{ + PathIDSet->MaxPathID = 0; + PathIDSet->MaxCurrentPathIDCount = 1; + PathIDSet->CurrentPathIDCount = 0; + CxPlatDispatchRwLockInitialize(&PathIDSet->RwLock); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +void +QuicPathIDSetUninitialize( + _Inout_ QUIC_PATHID_SET* PathIDSet + ) +{ + if (PathIDSet->Flags.HashTableInitialized) { + CXPLAT_DBG_ASSERT(PathIDSet->HASH.Table->NumEntries == 0); + CxPlatHashtableUninitialize(PathIDSet->HASH.Table); + } +} + +BOOLEAN +QuicPathIDSetGetPathIDs( + _In_ QUIC_PATHID_SET* PathIDSet, + _Out_writes_(*PathIDCount) QUIC_PATHID** PathIDs, + _Inout_ uint8_t* PathIDCount + ) +{ + BOOLEAN Within = TRUE; + uint8_t Count = 0; + CxPlatDispatchRwLockAcquireExclusive(&PathIDSet->RwLock, PrevIrql); + if (!PathIDSet->Flags.HashTableInitialized) { + if (Count < *PathIDCount) { + QuicPathIDAddRef(PathIDSet->SINGLE.PathID, QUIC_PATHID_REF_LOOKUP); + PathIDs[Count++] = PathIDSet->SINGLE.PathID; + } else { + Within = FALSE; + } + *PathIDCount = Count; + } else { + CXPLAT_HASHTABLE_ENUMERATOR Enumerator; + CXPLAT_HASHTABLE_ENTRY* Entry; + CxPlatHashtableEnumerateBegin(PathIDSet->HASH.Table, &Enumerator); + while ((Entry = CxPlatHashtableEnumerateNext(PathIDSet->HASH.Table, &Enumerator)) != NULL) { + if (Count < *PathIDCount) { + QUIC_PATHID* PathID = + CXPLAT_CONTAINING_RECORD(Entry, QUIC_PATHID, TableEntry); + QuicPathIDAddRef(PathID, QUIC_PATHID_REF_LOOKUP); + PathIDs[Count++] = PathID; + } else { + break; + } + } + *PathIDCount = Count; + if (Entry != NULL) { + Within = FALSE; + } + CxPlatHashtableEnumerateEnd(PathIDSet->HASH.Table, &Enumerator); + } + CxPlatDispatchRwLockReleaseExclusive(&PathIDSet->RwLock, PrevIrql); + return Within; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +void +QuicPathIDSetTraceRundown( + _In_ QUIC_PATHID_SET* PathIDSet + ) +{ + QUIC_PATHID* PathIDs[QUIC_ACTIVE_PATH_ID_LIMIT]; + uint8_t PathIDCount = QUIC_ACTIVE_PATH_ID_LIMIT; + QuicPathIDSetGetPathIDs(PathIDSet, PathIDs, &PathIDCount); + + for (uint8_t i = 0; i < PathIDCount; i++) { + QuicPathIDTraceRundown(PathIDs[i]); + QuicPathIDRelease(PathIDs[i], QUIC_PATHID_REF_LOOKUP); + } +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +_Success_(return != FALSE) +BOOLEAN +QuicPathIDSetInsertPathID( + _Inout_ QUIC_PATHID_SET* PathIDSet, + _In_ QUIC_PATHID* PathID + ) +{ + BOOLEAN Success = FALSE; + + if (PathIDSet->CurrentPathIDCount == 0) { + PathID->Flags.InPathIDTable = TRUE; + PathIDSet->SINGLE.PathID = PathID; + Success = TRUE; + goto Exit; + } else if (!PathIDSet->Flags.HashTableInitialized) { + QUIC_PATHID* ExisitingPathID = PathIDSet->SINGLE.PathID; + PathIDSet->HASH.Table = NULL; + // + // Lazily initialize the hash table. + // + if (!CxPlatHashtableInitialize(&PathIDSet->HASH.Table, CXPLAT_HASH_MIN_SIZE)) { + QuicTraceEvent( + AllocFailure, + "Allocation of '%s' failed. (%llu bytes)", + "pathid hash table", + 0); + goto Exit; + } + CxPlatHashtableInsert( + PathIDSet->HASH.Table, + &ExisitingPathID->TableEntry, + ExisitingPathID->ID, + NULL); + PathIDSet->Flags.HashTableInitialized = TRUE; + } + PathID->Flags.InPathIDTable = TRUE; + CxPlatHashtableInsert( + PathIDSet->HASH.Table, + &PathID->TableEntry, + PathID->ID, + NULL); + Success = TRUE; + +Exit: + return Success; +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +_Ret_maybenull_ +QUIC_PATHID* +QuicPathIDSetLookupPathID( + _Inout_ QUIC_PATHID_SET* PathIDSet, + _In_ uint32_t Id + ) +{ + QUIC_PATHID *PathID = NULL; + CxPlatDispatchRwLockAcquireShared(&PathIDSet->RwLock, PrevIrql); + + if (PathIDSet->CurrentPathIDCount == 0) { + goto Exit; // No pathids have been created yet. + } else if (!PathIDSet->Flags.HashTableInitialized) { + if (PathIDSet->SINGLE.PathID->ID == Id) { + PathID = PathIDSet->SINGLE.PathID; + } + } else { + + CXPLAT_HASHTABLE_LOOKUP_CONTEXT Context; + CXPLAT_HASHTABLE_ENTRY* Entry = + CxPlatHashtableLookup(PathIDSet->HASH.Table, Id, &Context); + while (Entry != NULL) { + QUIC_PATHID* TempPathID = + CXPLAT_CONTAINING_RECORD(Entry, QUIC_PATHID, TableEntry); + if (TempPathID->ID == Id) { + PathID = TempPathID; + break; + } + Entry = CxPlatHashtableLookupNext(PathIDSet->HASH.Table, &Context); + } + } + +Exit: + if (PathID != NULL) { + QuicPathIDAddRef(PathID, QUIC_PATHID_REF_LOOKUP); + } + CxPlatDispatchRwLockReleaseShared(&PathIDSet->RwLock, PrevIrql); + return PathID; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +void +QuicPathIDSetFree( + _Inout_ QUIC_PATHID_SET* PathIDSet + ) +{ + CxPlatDispatchRwLockAcquireExclusive(&PathIDSet->RwLock, PrevIrql); + + if (PathIDSet->CurrentPathIDCount == 0) { + goto Exit; + } else if (!PathIDSet->Flags.HashTableInitialized) { + QuicPathIDFree(PathIDSet->SINGLE.PathID); + PathIDSet->SINGLE.PathID = NULL; + } else { + CXPLAT_HASHTABLE_ENUMERATOR Enumerator; + CXPLAT_HASHTABLE_ENTRY* Entry; + CxPlatHashtableEnumerateBegin(PathIDSet->HASH.Table, &Enumerator); + while ((Entry = CxPlatHashtableEnumerateNext(PathIDSet->HASH.Table, &Enumerator)) != NULL) { + CxPlatHashtableRemove(PathIDSet->HASH.Table, Entry, NULL); + QUIC_PATHID* PathID = CXPLAT_CONTAINING_RECORD(Entry, QUIC_PATHID, TableEntry); + QuicPathIDRelease(PathID, QUIC_PATHID_REF_PATHID_SET); + } + CxPlatHashtableEnumerateEnd(PathIDSet->HASH.Table, &Enumerator); + } + +Exit: + CxPlatDispatchRwLockReleaseExclusive(&PathIDSet->RwLock, PrevIrql); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +void +QuicPathIDSetFreeSourceCids( + _Inout_ QUIC_PATHID_SET* PathIDSet + ) +{ + QUIC_PATHID* PathIDs[QUIC_ACTIVE_PATH_ID_LIMIT]; + uint8_t PathIDCount = QUIC_ACTIVE_PATH_ID_LIMIT; + QuicPathIDSetGetPathIDs(PathIDSet, PathIDs, &PathIDCount); + + for (uint8_t i = 0; i < PathIDCount; i++) { + QuicPathIDFreeSourceCids(PathIDs[i]); + QuicPathIDRelease(PathIDs[i], QUIC_PATHID_REF_LOOKUP); + } +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +void +QuicPathIDSetProcessLossDetectionTimerOperation( + _Inout_ QUIC_PATHID_SET* PathIDSet + ) +{ + QUIC_PATHID* PathIDs[QUIC_ACTIVE_PATH_ID_LIMIT]; + uint8_t PathIDCount = QUIC_ACTIVE_PATH_ID_LIMIT; + QuicPathIDSetGetPathIDs(PathIDSet, PathIDs, &PathIDCount); + + for (uint8_t i = 0; i < PathIDCount; i++) { + QuicLossDetectionProcessTimerOperation(&PathIDs[i]->LossDetection); + QuicPathIDRelease(PathIDs[i], QUIC_PATHID_REF_LOOKUP); + } +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +void +QuicPathIDSetProcessPathCloseTimerOperation( + _Inout_ QUIC_PATHID_SET* PathIDSet + ) +{ + QUIC_PATHID* PathIDs[QUIC_ACTIVE_PATH_ID_LIMIT]; + uint8_t PathIDCount = QUIC_ACTIVE_PATH_ID_LIMIT; + QuicPathIDSetGetPathIDs(PathIDSet, PathIDs, &PathIDCount); + + for (uint8_t i = 0; i < PathIDCount; i++) { + QuicPathIDProcessPathCloseTimerOperation(PathIDs[i]); + QuicPathIDRelease(PathIDs[i], QUIC_PATHID_REF_LOOKUP); + } +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +void +QuicPathIDSetTryFreePathID( + _Inout_ QUIC_PATHID_SET* PathIDSet, + _In_ __drv_freesMem(Mem) QUIC_PATHID* PathID + ) +{ + if (!PathID->Flags.Abandoned || !PathID->Flags.Closed) { + return; + } + + QUIC_CONNECTION* Connection = QuicPathIDSetGetConnection(PathIDSet); + + QuicTraceEvent( + ConnPathIDRemove, + "[conn][%p] Removed PathID %u", + Connection, + PathID->ID); + + CXPLAT_DBG_ASSERT(PathID->Path != NULL); + uint8_t PathIndex; + QUIC_PATH* Path = QuicConnGetPathByID(Connection, PathID->Path->ID, &PathIndex); + CXPLAT_DBG_ASSERT(PathID->Path == Path); + + if (!QuicConnIsServer(Connection)) { + QuicBindingRemoveAllSourceConnectionIDs(Path->Binding, Connection); + } + QuicLibraryReleaseBinding(Path->Binding); + Path->Binding = NULL; + + QuicPathRemove(Connection, PathIndex); + + PathID->Flags.InPathIDTable = FALSE; + + CxPlatDispatchRwLockAcquireExclusive(&PathIDSet->RwLock, PrevIrql); + if (!PathIDSet->Flags.HashTableInitialized) { + CXPLAT_DBG_ASSERT(PathID == PathIDSet->SINGLE.PathID); + PathIDSet->SINGLE.PathID = NULL; + } else { + CxPlatHashtableRemove(PathIDSet->HASH.Table, &PathID->TableEntry, NULL); + } + CxPlatDispatchRwLockReleaseExclusive(&PathIDSet->RwLock, PrevIrql); + PathIDSet->CurrentPathIDCount--; + + QuicLossDetectionReset(&PathID->LossDetection); + QuicPathIDFreeSourceCids(PathID); + QuicPathIDRelease(PathID, QUIC_PATHID_REF_PATHID_SET); + + if (PathIDSet->CurrentPathIDCount < PathIDSet->MaxCurrentPathIDCount) { + PathIDSet->MaxPathID++; + QuicSendSetSendFlag(&Connection->Send, QUIC_CONN_SEND_FLAG_MAX_PATH_ID); + } +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +void +QuicPathIDSetGenerateNewSourceCids( + _In_ QUIC_PATHID_SET* PathIDSet, + _In_ BOOLEAN ReplaceExistingCids + ) +{ + if (QuicPathIDSetGetConnection(PathIDSet)->State.MultipathNegotiated) { + uint16_t NewPathIDCount = 0; + if (PathIDSet->CurrentPathIDCount < PathIDSet->MaxCurrentPathIDCount) { + NewPathIDCount = PathIDSet->MaxCurrentPathIDCount - PathIDSet->CurrentPathIDCount; + } + for (uint16_t i = 0; i < NewPathIDCount; ++i) { + QUIC_PATHID *PathID = NULL; + QUIC_STATUS Status = QuicPathIDSetNewLocalPathID(PathIDSet, &PathID); + if (Status == QUIC_STATUS_PATHID_LIMIT_REACHED) { + break; + } else if (QUIC_FAILED(Status)) { + QuicTraceEvent( + ConnError, + "[conn][%p] ERROR, %s.", + QuicPathIDSetGetConnection(PathIDSet), + "Failed to generate new path ID"); + QuicConnTransportError(QuicPathIDSetGetConnection(PathIDSet), QUIC_ERROR_INTERNAL_ERROR); + return; + } + } + } + + QUIC_PATHID* PathIDs[QUIC_ACTIVE_PATH_ID_LIMIT]; + uint8_t PathIDCount = QUIC_ACTIVE_PATH_ID_LIMIT; + QuicPathIDSetGetPathIDs(PathIDSet, PathIDs, &PathIDCount); + + for (uint8_t i = 0; i < PathIDCount; i++) { + QuicPathIDGenerateNewSourceCids(PathIDs[i], ReplaceExistingCids); + QuicPathIDRelease(PathIDs[i], QUIC_PATHID_REF_LOOKUP); + } +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +BOOLEAN +QuicPathIDSetWriteAckFrame( + _In_ QUIC_PATHID_SET* PathIDSet, + _Inout_ QUIC_PACKET_BUILDER* Builder, + _Out_ BOOLEAN* RanOutOfRoom + ) +{ + BOOLEAN Success = FALSE; + *RanOutOfRoom = FALSE; + + QUIC_PATHID* PathIDs[QUIC_ACTIVE_PATH_ID_LIMIT]; + uint8_t PathIDCount = QUIC_ACTIVE_PATH_ID_LIMIT; + QuicPathIDSetGetPathIDs(PathIDSet, PathIDs, &PathIDCount); + + for (uint8_t i = 0; i < PathIDCount; i++) { + if (QuicPathIDWriteAckFrame(PathIDs[i], Builder)) { + QuicPathIDRelease(PathIDs[i], QUIC_PATHID_REF_LOOKUP); + Success = TRUE; + } else { + QuicPathIDRelease(PathIDs[i], QUIC_PATHID_REF_LOOKUP); + *RanOutOfRoom = TRUE; + break; + } + } + + return Success; +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +BOOLEAN +QuicPathIDSetWriteNewConnectionIDFrame( + _In_ QUIC_PATHID_SET* PathIDSet, + _Inout_ QUIC_PACKET_BUILDER* Builder, + _In_ uint16_t AvailableBufferLength, + _Out_ BOOLEAN* HasMoreCidsToSend, + _Out_ BOOLEAN* MaxFrameLimitHit + ) +{ + BOOLEAN HaveRoom = TRUE; + QUIC_PATHID* PathIDs[QUIC_ACTIVE_PATH_ID_LIMIT]; + uint8_t PathIDCount = QUIC_ACTIVE_PATH_ID_LIMIT; + QuicPathIDSetGetPathIDs(PathIDSet, PathIDs, &PathIDCount); + + BOOLEAN HasMoreCidsToSend1 = FALSE; + BOOLEAN MaxFrameLimitHit1 = FALSE; + for (uint8_t i = 0; i < PathIDCount; i++) { + if (!MaxFrameLimitHit1) { + HaveRoom = QuicPathIDWriteNewConnectionIDFrame( + PathIDs[i], + Builder, + AvailableBufferLength, + &HasMoreCidsToSend1, + &MaxFrameLimitHit1); + } + QuicPathIDRelease(PathIDs[i], QUIC_PATHID_REF_LOOKUP); + } + *HasMoreCidsToSend = HasMoreCidsToSend1; + *MaxFrameLimitHit = MaxFrameLimitHit1; + + return HaveRoom; +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +BOOLEAN +QuicPathIDSetWriteRetireConnectionIDFrame( + _In_ QUIC_PATHID_SET* PathIDSet, + _Inout_ QUIC_PACKET_BUILDER* Builder, + _In_ uint16_t AvailableBufferLength, + _Out_ BOOLEAN* HasMoreCidsToSend, + _Out_ BOOLEAN* MaxFrameLimitHit + ) +{ + BOOLEAN HaveRoom = TRUE; + QUIC_PATHID* PathIDs[QUIC_ACTIVE_PATH_ID_LIMIT]; + uint8_t PathIDCount = QUIC_ACTIVE_PATH_ID_LIMIT; + QuicPathIDSetGetPathIDs(PathIDSet, PathIDs, &PathIDCount); + + BOOLEAN HasMoreCidsToSend1 = FALSE; + BOOLEAN MaxFrameLimitHit1 = FALSE; + for (uint8_t i = 0; i < PathIDCount; i++) { + if (!MaxFrameLimitHit1) { + HaveRoom = QuicPathIDWriteRetireConnectionIDFrame( + PathIDs[i], + Builder, + AvailableBufferLength, + &HasMoreCidsToSend1, + &MaxFrameLimitHit1); + } + QuicPathIDRelease(PathIDs[i], QUIC_PATHID_REF_LOOKUP); + } + *HasMoreCidsToSend = HasMoreCidsToSend1; + *MaxFrameLimitHit = MaxFrameLimitHit1; + + return HaveRoom; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +BOOLEAN +QuicPathIDSetProcessAckFrame( + _In_ QUIC_PATHID_SET* PathIDSet, + _In_ QUIC_RX_PACKET* Packet, + _In_ QUIC_ENCRYPT_LEVEL EncryptLevel, + _In_ QUIC_FRAME_TYPE FrameType, + _In_ uint16_t BufferLength, + _In_reads_bytes_(BufferLength) + const uint8_t* const Buffer, + _Inout_ uint16_t* Offset, + _Out_ BOOLEAN* InvalidFrame + ) +{ + QUIC_CONNECTION* Connection = QuicPathIDSetGetConnection(PathIDSet); + + // + // Called for each received ACK frame. An ACK frame consists of one or more + // ACK blocks, each of which acknowledges a contiguous range of packets. + // + + uint32_t PathId; + uint64_t AckDelay; // microsec + QUIC_ACK_ECN_EX Ecn; + + BOOLEAN Result = + QuicAckFrameDecode( + FrameType, + BufferLength, + Buffer, + Offset, + InvalidFrame, + &PathId, + &Connection->DecodedAckRanges, + &Ecn, + &AckDelay); + + if (Result) { + + BOOLEAN FatalError = FALSE; + QUIC_PATHID *PathID = NULL; + PathID = QuicPathIDSetGetPathIDForPeer( + PathIDSet, + PathId, + TRUE, + &FatalError); + + if (PathID != NULL) { + uint64_t Largest; + if (!QuicRangeGetMaxSafe(&Connection->DecodedAckRanges, &Largest) || + PathID->LossDetection.LargestSentPacketNumber < Largest) { + + // + // The ACK frame should never acknowledge a packet number we haven't + // sent. + // + *InvalidFrame = TRUE; + Result = FALSE; + + } else { + + AckDelay <<= Connection->PeerTransportParams.AckDelayExponent; + + QuicLossDetectionProcessAckBlocks( + &PathID->LossDetection, + PathID->Path, + Packet, + EncryptLevel, + AckDelay, + &Connection->DecodedAckRanges, + InvalidFrame, + FrameType == QUIC_FRAME_ACK_1 ? &Ecn : NULL); + } + QuicPathIDRelease(PathID, QUIC_PATHID_REF_LOOKUP); + } else { + *InvalidFrame = TRUE; + Result = FALSE; + } + } + + QuicRangeReset(&Connection->DecodedAckRanges); + + return Result; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +void +QuicPathIDSetInitializeTransportParameters( + _Inout_ QUIC_PATHID_SET* PathIDSet, + _In_ uint8_t SourceCidLimit, + _In_ uint32_t MaxPathID + ) +{ + CXPLAT_DBG_ASSERT(PathIDSet->CurrentPathIDCount == 1); + CXPLAT_DBG_ASSERT(SourceCidLimit >= QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT_MIN); + if (PathIDSet->SINGLE.PathID->SourceCidLimit > SourceCidLimit) { + PathIDSet->SINGLE.PathID->SourceCidLimit = SourceCidLimit; + } + + PathIDSet->SINGLE.PathID->SourceCidLimit = SourceCidLimit; + + if (MaxPathID != UINT32_MAX) { + PathIDSet->Flags.InitialMaxPathRecvd = TRUE; + PathIDSet->MaxPathID = QUIC_ACTIVE_PATH_ID_LIMIT - 1; + PathIDSet->PeerMaxPathID = MaxPathID; + PathIDSet->MaxCurrentPathIDCount = QUIC_ACTIVE_PATH_ID_LIMIT; + } else { + PathIDSet->Flags.InitialMaxPathRecvd = FALSE; + PathIDSet->MaxPathID = 0; + PathIDSet->PeerMaxPathID = 0; + PathIDSet->MaxCurrentPathIDCount = 1; + } +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +void +QuicPathIDSetUpdateMaxPathID( + _Inout_ QUIC_PATHID_SET* PathIDSet, + _In_ uint32_t MaxPathID + ) +{ + if (PathIDSet->PeerMaxPathID < MaxPathID) { + QuicTraceLogConnVerbose( + PeerMaxPathIDUpdated, + QuicPathIDSetGetConnection(PathIDSet), + "Peer updated max path id (%u).", + MaxPathID); + PathIDSet->PeerMaxPathID = MaxPathID; + QuicPathIDSetGenerateNewSourceCids(PathIDSet, FALSE); + } +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +QUIC_STATUS +QuicPathIDSetNewLocalPathID( + _Inout_ QUIC_PATHID_SET* PathIDSet, + _Outptr_ _At_(*NewPathID, __drv_allocatesMem(Mem)) + QUIC_PATHID** NewPathID + ) +{ + QUIC_STATUS Status = QUIC_STATUS_SUCCESS; + QUIC_CONNECTION* Connection = QuicPathIDSetGetConnection(PathIDSet); + QUIC_PATHID* PathID = NULL; + BOOLEAN NewPathIDBlocked = PathIDSet->TotalPathIDCount >= (PathIDSet->PeerMaxPathID + 1); + + if (NewPathIDBlocked) { + if (Connection->State.PeerTransportParameterValid) { + // QuicSendSetSendFlag(&Connection->Send, QUIC_CONN_SEND_FLAG_PATHS_BLOCKED); + } + Status = QUIC_STATUS_PATHID_LIMIT_REACHED; + goto Exit; + } + + Status = QuicPathIDInitialize(QuicPathIDSetGetConnection(PathIDSet), &PathID); + if (QUIC_FAILED(Status)) { + goto Exit; + } + + PathID->ID = PathIDSet->TotalPathIDCount; + if (PathID->ID == 0) { + for (uint32_t i = 0; i < ARRAYSIZE(PathID->Packets); i++) { + Status = + QuicPacketSpaceInitialize( + PathID, + (QUIC_ENCRYPT_LEVEL)i, + &PathID->Packets[i]); + if (QUIC_FAILED(Status)) { + break; + } + } + } else { + Status = + QuicPacketSpaceInitialize( + PathID, + QUIC_ENCRYPT_LEVEL_1_RTT, + &PathID->Packets[QUIC_ENCRYPT_LEVEL_1_RTT]); + } + if (QUIC_FAILED(Status)) { + QuicPathIDRelease(PathID, QUIC_PATHID_REF_PATHID_SET); + goto Exit; + } + + CxPlatDispatchRwLockAcquireExclusive(&PathIDSet->RwLock, PrevIrql); + if (!QuicPathIDSetInsertPathID(PathIDSet, PathID)) { + CxPlatDispatchRwLockReleaseExclusive(&PathIDSet->RwLock, PrevIrql); + QuicPathIDRelease(PathID, QUIC_PATHID_REF_PATHID_SET); + Status = QUIC_STATUS_OUT_OF_MEMORY; + goto Exit; + } + CxPlatDispatchRwLockReleaseExclusive(&PathIDSet->RwLock, PrevIrql); + PathIDSet->CurrentPathIDCount++; + PathIDSet->TotalPathIDCount++; + + QuicTraceEvent( + ConnPathIDAdd, + "[conn][%p] Added New PathID %u", + QuicPathIDSetGetConnection(PathIDSet), + PathID->ID); + + if (PathIDSet->MaxCurrentPathIDCount < PathIDSet->CurrentPathIDCount) { + PathIDSet->MaxCurrentPathIDCount = PathIDSet->CurrentPathIDCount; + } + *NewPathID = PathID; +Exit: + return Status; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +_Success_(return != NULL) +QUIC_PATHID* +QuicPathIDSetGetPathIDForLocal( + _Inout_ QUIC_PATHID_SET* PathIDSet, + _In_ uint32_t PathId, + _Out_ BOOLEAN* FatalError + ) +{ + QUIC_CONNECTION* Connection = QuicPathIDSetGetConnection(PathIDSet); + + *FatalError = FALSE; + + // + // Connection is closed. No more pathids are open. + // + if (QuicConnIsClosed(Connection)) { + return NULL; + } + + // + // Validate the stream ID isn't above the allowed max. + // + if (PathId > PathIDSet->PeerMaxPathID) { + QuicTraceEvent( + ConnError, + "[conn][%p] ERROR, %s.", + Connection, + "local tried to use more pathids than allowed"); + QuicConnTransportError(Connection, QUIC_ERROR_INTERNAL_ERROR); + *FatalError = TRUE; + return NULL; + } + + QUIC_PATHID* PathID = NULL; + // + // If the stream ID is in the acceptable range of already opened streams, + // look for it; but note it could be missing because it has been closed. + // + if (PathId + 1 <= PathIDSet->TotalPathIDCount) { + + // + // Find the stream for the ID. + // + PathID = QuicPathIDSetLookupPathID(PathIDSet, PathId); + + } else { + // + // Local tried to open stream that it wasn't allowed to. + // + QuicTraceEvent( + ConnError, + "[conn][%p] ERROR, %s.", + Connection, + "Local tried to open pathid it wasn't allowed to open."); + QuicConnTransportError(Connection, QUIC_ERROR_INTERNAL_ERROR); + *FatalError = TRUE; + } + + return PathID; +} + +#pragma warning(push) +#pragma warning(disable:6014) // SAL doesn't double ref count semantics +_IRQL_requires_max_(PASSIVE_LEVEL) +__drv_allocatesMem(Mem) +_Must_inspect_result_ +_Success_(return != NULL) +QUIC_PATHID* +QuicPathIDSetGetPathIDForPeer( + _Inout_ QUIC_PATHID_SET* PathIDSet, + _In_ uint32_t PathId, + _In_ BOOLEAN CreateIfMissing, + _Out_ BOOLEAN* FatalError + ) +{ + QUIC_CONNECTION* Connection = QuicPathIDSetGetConnection(PathIDSet); + + *FatalError = FALSE; + + // + // Connection is closed. No more pathids are open. + // + // if (QuicConnIsClosed(Connection)) { + // return NULL; + // } + + // + // Validate the stream ID isn't above the allowed max. + // + if (PathId > PathIDSet->MaxPathID) { + QuicTraceEvent( + ConnError, + "[conn][%p] ERROR, %s.", + Connection, + "Peer used more pathids than allowed"); + QuicConnTransportError(Connection, QUIC_ERROR_PROTOCOL_VIOLATION); + *FatalError = TRUE; + return NULL; + } + + QUIC_PATHID* PathID = NULL; + // + // If the stream ID is in the acceptable range of already opened streams, + // look for it; but note it could be missing because it has been closed. + // + if (PathId + 1 <= PathIDSet->TotalPathIDCount) { + + // + // Find the stream for the ID. + // + PathID = QuicPathIDSetLookupPathID(PathIDSet, PathId); + + } else if (CreateIfMissing) { + + do { + if (PathID != NULL) { + QuicPathIDRelease(PathID, QUIC_PATHID_REF_LOOKUP); + PathID = NULL; + } + // + // Calculate the next Path ID. + // + uint32_t NewPathId = PathIDSet->TotalPathIDCount; + + QUIC_STATUS Status = QuicPathIDInitialize(QuicPathIDSetGetConnection(PathIDSet), &PathID); + if (QUIC_FAILED(Status)) { + *FatalError = TRUE; + QuicConnTransportError(Connection, QUIC_ERROR_INTERNAL_ERROR); + goto Exit; + } + + PathID->ID = NewPathId; + if (PathID->ID == 0) { + for (uint32_t i = 0; i < ARRAYSIZE(PathID->Packets); i++) { + Status = + QuicPacketSpaceInitialize( + PathID, + (QUIC_ENCRYPT_LEVEL)i, + &PathID->Packets[i]); + if (QUIC_FAILED(Status)) { + break; + } + } + } else { + Status = + QuicPacketSpaceInitialize( + PathID, + QUIC_ENCRYPT_LEVEL_1_RTT, + &PathID->Packets[QUIC_ENCRYPT_LEVEL_1_RTT]); + } + if (QUIC_FAILED(Status)) { + *FatalError = TRUE; + QuicConnTransportError(Connection, QUIC_ERROR_INTERNAL_ERROR); + QuicPathIDRelease(PathID, QUIC_PATHID_REF_PATHID_SET); + PathID = NULL; + goto Exit; + } + + CxPlatDispatchRwLockAcquireExclusive(&PathIDSet->RwLock, PrevIrql); + if (!QuicPathIDSetInsertPathID(PathIDSet, PathID)) { + CxPlatDispatchRwLockReleaseExclusive(&PathIDSet->RwLock, PrevIrql); + *FatalError = TRUE; + QuicConnTransportError(Connection, QUIC_ERROR_INTERNAL_ERROR); + QuicPathIDRelease(PathID, QUIC_PATHID_REF_PATHID_SET); + PathID = NULL; + goto Exit; + } + QuicPathIDAddRef(PathID, QUIC_PATHID_REF_LOOKUP); + CxPlatDispatchRwLockReleaseExclusive(&PathIDSet->RwLock, PrevIrql); + + PathIDSet->CurrentPathIDCount++; + PathIDSet->TotalPathIDCount++; + + QuicTraceEvent( + ConnPathIDAdd, + "[conn][%p] Added New PathID %u", + Connection, + PathID->ID); + + } while (PathIDSet->TotalPathIDCount != PathId + 1); + } else { + + // + // Remote tried to open stream that it wasn't allowed to. + // + QuicTraceEvent( + ConnError, + "[conn][%p] ERROR, %s.", + Connection, + "Remote tried to open pathid it wasn't allowed to open."); + QuicConnTransportError(Connection, QUIC_ERROR_PROTOCOL_VIOLATION); + *FatalError = TRUE; + } +Exit: + return PathID; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +QUIC_PATHID* +QuicPathIDSetGetUnusedPathID( + _In_ QUIC_PATHID_SET* PathIDSet + ) +{ + QUIC_PATHID *PathID = NULL; + + QUIC_PATHID* PathIDs[QUIC_ACTIVE_PATH_ID_LIMIT]; + uint8_t PathIDCount = QUIC_ACTIVE_PATH_ID_LIMIT; + QuicPathIDSetGetPathIDs(PathIDSet, PathIDs, &PathIDCount); + + for (uint8_t i = 0; i < PathIDCount; i++) { + if (PathID == NULL && !PathIDs[i]->Flags.InUse) { + PathID = PathIDs[i]; + } else { + QuicPathIDRelease(PathIDs[i], QUIC_PATHID_REF_LOOKUP); + } + } + + return PathID; +} diff --git a/src/core/pathid_set.h b/src/core/pathid_set.h new file mode 100644 index 0000000000..819eb9b298 --- /dev/null +++ b/src/core/pathid_set.h @@ -0,0 +1,284 @@ +/*++ + Copyright (c) Microsoft Corporation. + Licensed under the MIT License. +--*/ + +// +// Different flags of a stream. +// Note - Keep quictypes.h's copy up to date. +// +typedef union QUIC_PATHID_SET_FLAGS { + uint64_t AllFlags; + struct { + BOOLEAN HashTableInitialized : 1; + BOOLEAN InitialMaxPathRecvd : 1; + }; +} QUIC_PATHID_SET_FLAGS; + +typedef struct QUIC_PATHID_SET { + // + // The largest MAX_PATH_ID value indicated to the peer. This MUST not ever + // decrease once the connection has started. + // + uint32_t MaxPathID; + + // + // The largest MAX_PATH_ID value indicated by the peer. This MUST not ever + // decrease once the connection has started. + // + uint32_t PeerMaxPathID; + + // + // The total number of path ids that have been opened. Includes any path ids + // that have been closed as well. + // + uint32_t TotalPathIDCount; + + // + // The maximum number of simultaneous open path ids allowed. + // + uint16_t MaxCurrentPathIDCount; + + // + // The number of PathIDs. Value of less than 2 + // indicates only a single PathID (may be NULL) is bound. + uint16_t CurrentPathIDCount; + + // + // The current flags for path id set. + // + QUIC_PATHID_SET_FLAGS Flags; + + // + // Lock for accessing the lookup data. + // + CXPLAT_DISPATCH_RW_LOCK RwLock; + + // + // PathID lookup. + // + union { + void* LookupTable; + struct { + // + // Single PathID is bound. + // + QUIC_PATHID* PathID; + } SINGLE; + struct { + // + // Hash table. + // + CXPLAT_HASHTABLE* Table; + } HASH; + }; +} QUIC_PATHID_SET; +// +// Initializes the path id set. +// +_IRQL_requires_max_(PASSIVE_LEVEL) +void +QuicPathIDSetInitialize( + _Inout_ QUIC_PATHID_SET* PathIDSet + ); + +// +// Uninitializes the path id set. +// +_IRQL_requires_max_(PASSIVE_LEVEL) +void +QuicPathIDSetUninitialize( + _Inout_ QUIC_PATHID_SET* PathIDSet + ); + +BOOLEAN +QuicPathIDSetGetPathIDs( + _In_ QUIC_PATHID_SET* PathIDSet, + _Out_writes_(*PathIDCount) QUIC_PATHID** PathIDs, + _Inout_ uint8_t* PathIDCount + ); + +// +// Tracing rundown for the path id set. +// +_IRQL_requires_max_(PASSIVE_LEVEL) +void +QuicPathIDSetTraceRundown( + _In_ QUIC_PATHID_SET* PathIDSet + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +void +QuicPathIDSetFree( + _Inout_ QUIC_PATHID_SET* PathIDSet + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +void +QuicPathIDSetFreeSourceCids( + _Inout_ QUIC_PATHID_SET* PathIDSet + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +void +QuicPathIDSetProcessLossDetectionTimerOperation( + _Inout_ QUIC_PATHID_SET* PathIDSet + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +void +QuicPathIDSetProcessPathCloseTimerOperation( + _Inout_ QUIC_PATHID_SET* PathIDSet + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +void +QuicPathIDSetTryFreePathID( + _Inout_ QUIC_PATHID_SET* PathIDSet, + _In_ __drv_freesMem(Mem) QUIC_PATHID* PathID + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +void +QuicPathIDSetGenerateNewSourceCids( + _In_ QUIC_PATHID_SET* PathIDSet, + _In_ BOOLEAN ReplaceExistingCids + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +BOOLEAN +QuicPathIDSetWriteAckFrame( + _In_ QUIC_PATHID_SET* PathIDSet, + _Inout_ QUIC_PACKET_BUILDER* Builder, + _Out_ BOOLEAN* RanOutOfRoom + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +BOOLEAN +QuicPathIDSetWriteNewConnectionIDFrame( + _In_ QUIC_PATHID_SET* PathIDSet, + _Inout_ QUIC_PACKET_BUILDER* Builder, + _In_ uint16_t AvailableBufferLength, + _Out_ BOOLEAN* HasMoreCidsToSend, + _Out_ BOOLEAN* MaxFrameLimitHit + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +BOOLEAN +QuicPathIDSetWriteRetireConnectionIDFrame( + _In_ QUIC_PATHID_SET* PathIDSet, + _Inout_ QUIC_PACKET_BUILDER* Builder, + _In_ uint16_t AvailableBufferLength, + _Out_ BOOLEAN* HasMoreCidsToSend, + _Out_ BOOLEAN* MaxFrameLimitHit + ); + +// +// Processes a received ACK frame. Returns true if the frame could be +// successfully processed. On failure, 'InvalidFrame' indicates if the frame +// was corrupt or not. +// +_IRQL_requires_max_(PASSIVE_LEVEL) +BOOLEAN +QuicPathIDSetProcessAckFrame( + _In_ QUIC_PATHID_SET* PathIDSet, + _In_ QUIC_RX_PACKET* Packet, + _In_ QUIC_ENCRYPT_LEVEL EncryptLevel, + _In_ QUIC_FRAME_TYPE FrameType, + _In_ uint16_t BufferLength, + _In_reads_bytes_(BufferLength) + const uint8_t* const Buffer, + _Inout_ uint16_t* Offset, + _Out_ BOOLEAN* InvalidFrame + ); + +// +// Invoked when the the transport parameters have been received from the peer. +// +_IRQL_requires_max_(PASSIVE_LEVEL) +void +QuicPathIDSetInitializeTransportParameters( + _Inout_ QUIC_PATHID_SET* PathIDSet, + _In_ uint8_t SourceCidLimit, + _In_ uint32_t MaxPathID + ); + +// +// Invoked when the peer sends a MAX_PATH_ID frame. +// +_IRQL_requires_max_(PASSIVE_LEVEL) +void +QuicPathIDSetUpdateMaxPathID( + _Inout_ QUIC_PATHID_SET* PathIDSet, + _In_ uint32_t MaxPathID + ); + +// +// Updates the maximum count of pathids allowed for a pathid set. +// +_IRQL_requires_max_(PASSIVE_LEVEL) +void +QuicPathIDmSetUpdateMaxCount( + _Inout_ QUIC_PATHID_SET* PathIDSet, + _In_ uint8_t Type, + _In_ uint16_t Count + ); + +// +// Returns the number of available path ids still allowed. +// +_IRQL_requires_max_(PASSIVE_LEVEL) +uint16_t +QuicPathIDSetGetCountAvailable( + _In_ const QUIC_PATHID_SET* PathIDSet, + _In_ uint8_t Type + ); + +// +// Queries the current max Path IDs. +// +_IRQL_requires_max_(PASSIVE_LEVEL) +void +QuicPathIDSetGetMaxPathIDs( + _In_ const QUIC_PATHID_SET* PathIDSet, + _Out_writes_all_(NUMBER_OF_PATHID_TYPES) + uint64_t* MaxPathIds + ); + +// +// Creates a new local path id. +// +_IRQL_requires_max_(PASSIVE_LEVEL) +QUIC_STATUS +QuicPathIDSetNewLocalPathID( + _Inout_ QUIC_PATHID_SET* PathIDSet, + _Outptr_ _At_(*NewPathID, __drv_allocatesMem(Mem)) + QUIC_PATHID** NewPathID + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +_Success_(return != NULL) +QUIC_PATHID* +QuicPathIDSetGetPathIDForLocal( + _Inout_ QUIC_PATHID_SET* PathIDSet, + _In_ uint32_t PathId, + _Out_ BOOLEAN* FatalError + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +__drv_allocatesMem(Mem) +_Must_inspect_result_ +_Success_(return != NULL) +QUIC_PATHID* +QuicPathIDSetGetPathIDForPeer( + _Inout_ QUIC_PATHID_SET* PathIDSet, + _In_ uint32_t PathId, + _In_ BOOLEAN CreateIfMissing, + _Out_ BOOLEAN* FatalError + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +QUIC_PATHID* +QuicPathIDSetGetUnusedPathID( + _In_ QUIC_PATHID_SET* PathIDSet + ); diff --git a/src/core/precomp.h b/src/core/precomp.h index 253cc48be9..723008a4b3 100644 --- a/src/core/precomp.h +++ b/src/core/precomp.h @@ -72,6 +72,8 @@ #include "stream_set.h" #include "datagram.h" #include "version_neg.h" +#include "pathid_set.h" +#include "pathid.h" #include "connection.h" #include "packet_builder.h" #include "listener.h" diff --git a/src/core/quicdef.h b/src/core/quicdef.h index 10bec83f95..311b5fa9ad 100644 --- a/src/core/quicdef.h +++ b/src/core/quicdef.h @@ -16,6 +16,7 @@ typedef struct QUIC_CONGESTION_CONTROL QUIC_CONGESTION_CONTROL; typedef struct QUIC_CONNECTION QUIC_CONNECTION; typedef struct QUIC_STREAM QUIC_STREAM; typedef struct QUIC_PACKET_BUILDER QUIC_PACKET_BUILDER; +typedef struct QUIC_PATHID QUIC_PATHID; typedef struct QUIC_PATH QUIC_PATH; typedef struct QUIC_RX_PACKET QUIC_RX_PACKET; @@ -380,6 +381,11 @@ CXPLAT_STATIC_ASSERT( QUIC_MAX_PATH_COUNT <= QUIC_ACTIVE_CONNECTION_ID_LIMIT, "Should always have enough CIDs for all paths"); +// +// Maximum number of PATH IDs accepted from the peer. +// +#define QUIC_ACTIVE_PATH_ID_LIMIT 4 + // // The default value for pacing being enabled or not. // @@ -538,6 +544,16 @@ CXPLAT_STATIC_ASSERT( // #define QUIC_DEFAULT_STREAM_MULTI_RECEIVE_ENABLED FALSE +// +// The default settings for disabling Connection ID generation. +// +#define QUIC_DEFAULT_CONN_ID_GENERATION_DISABLED FALSE + +// +// The default settings for allowing multipath. +// +#define QUIC_DEFAULT_MULTIPATH_ENABLED FALSE + // // The number of rounds in Cubic Slow Start to sample RTT. // @@ -595,6 +611,7 @@ CXPLAT_STATIC_ASSERT( #define QUIC_TP_FLAG_TIMESTAMP_RECV_ENABLED 0x01000000 #define QUIC_TP_FLAG_TIMESTAMP_SEND_ENABLED 0x02000000 #define QUIC_TP_FLAG_TIMESTAMP_SHIFT 24 +#define QUIC_TP_FLAG_INITIAL_MAX_PATH_ID 0x04000000 #define QUIC_TP_MAX_PACKET_SIZE_DEFAULT 65527 #define QUIC_TP_MAX_UDP_PAYLOAD_SIZE_MIN 1200 @@ -617,6 +634,12 @@ CXPLAT_STATIC_ASSERT( // #define QUIC_TP_MAX_STREAMS_MAX ((1ULL << 60) - 1) +// +// Max allowed value of a MAX_PATHS frame or transport parameter. +// Any larger value would allow a max path ID that cannot be used in the nonce. +// +#define QUIC_TP_MAX_PATH_ID_MAX ((1ULL << 32) - 1) + /************************************************************* PERSISTENT SETTINGS *************************************************************/ @@ -645,6 +668,7 @@ CXPLAT_STATIC_ASSERT( #define QUIC_SETTING_ONE_WAY_DELAY_ENABLED "OneWayDelayEnabled" #define QUIC_SETTING_NET_STATS_EVENT_ENABLED "NetStatsEventEnabled" #define QUIC_SETTING_STREAM_MULTI_RECEIVE_ENABLED "StreamMultiReceiveEnabled" +#define QUIC_SETTING_MULTIPATH_ENABLED "MultipathEnabled" #define QUIC_SETTING_INITIAL_WINDOW_PACKETS "InitialWindowPackets" #define QUIC_SETTING_SEND_IDLE_TIMEOUT_MS "SendIdleTimeoutMs" @@ -682,3 +706,5 @@ CXPLAT_STATIC_ASSERT( #define QUIC_SETTING_MTU_MISSING_PROBE_COUNT "MtuDiscoveryMissingProbeCount" #define QUIC_SETTING_CONGESTION_CONTROL_ALGORITHM "CongestionControlAlgorithm" + +#define QUIC_SETTING_CONN_ID_GENERATION_DISABLED "ConnIDGenerationDisabled" diff --git a/src/core/send.c b/src/core/send.c index 306801d4bf..e5a5cb5271 100644 --- a/src/core/send.c +++ b/src/core/send.c @@ -224,13 +224,21 @@ QuicSendValidate( QUIC_CONNECTION* Connection = QuicSendGetConnection(Send); BOOLEAN HasAckElicitingPacketsToAcknowledge = FALSE; - for (uint32_t i = 0; i < QUIC_ENCRYPT_LEVEL_COUNT; ++i) { - if (Connection->Packets[i] != NULL) { - if (Connection->Packets[i]->AckTracker.AckElicitingPacketsToAcknowledge) { - HasAckElicitingPacketsToAcknowledge = TRUE; - break; + QUIC_PATHID* PathIDs[QUIC_ACTIVE_PATH_ID_LIMIT]; + uint8_t PathIDCount = QUIC_ACTIVE_PATH_ID_LIMIT; + QuicPathIDSetGetPathIDs(&Connection->PathIDs, PathIDs, &PathIDCount); + + for (uint8_t i = 0; i < PathIDCount; i++) { + if (!HasAckElicitingPacketsToAcknowledge) { + for (uint32_t j = 0; j < QUIC_ENCRYPT_LEVEL_COUNT; ++j) { + if (PathIDs[i]->Packets[j] != NULL && + PathIDs[i]->Packets[j]->AckTracker.AckElicitingPacketsToAcknowledge) { + HasAckElicitingPacketsToAcknowledge = TRUE; + break; + } } } + QuicPathIDRelease(PathIDs[i], QUIC_PATHID_REF_LOOKUP); } if (Send->SendFlags & QUIC_CONN_SEND_FLAG_ACK) { @@ -343,12 +351,21 @@ QuicSendUpdateAckState( QUIC_CONNECTION* Connection = QuicSendGetConnection(Send); BOOLEAN HasAckElicitingPacketsToAcknowledge = FALSE; - for (uint32_t i = 0; i < QUIC_ENCRYPT_LEVEL_COUNT; ++i) { - if (Connection->Packets[i] != NULL && - Connection->Packets[i]->AckTracker.AckElicitingPacketsToAcknowledge) { - HasAckElicitingPacketsToAcknowledge = TRUE; - break; + QUIC_PATHID* PathIDs[QUIC_ACTIVE_PATH_ID_LIMIT]; + uint8_t PathIDCount = QUIC_ACTIVE_PATH_ID_LIMIT; + QuicPathIDSetGetPathIDs(&Connection->PathIDs, PathIDs, &PathIDCount); + + for (uint8_t i = 0; i < PathIDCount; i++) { + if (!HasAckElicitingPacketsToAcknowledge) { + for (uint32_t j = 0; j < QUIC_ENCRYPT_LEVEL_COUNT; ++j) { + if (PathIDs[i]->Packets[j] != NULL && + PathIDs[i]->Packets[j]->AckTracker.AckElicitingPacketsToAcknowledge) { + HasAckElicitingPacketsToAcknowledge = TRUE; + break; + } + } } + QuicPathIDRelease(PathIDs[i], QUIC_PATHID_REF_LOOKUP); } if (!HasAckElicitingPacketsToAcknowledge) { @@ -477,9 +494,6 @@ QuicSendWriteFrames( uint8_t PrevFrameCount = Builder->Metadata->FrameCount; BOOLEAN RanOutOfRoom = FALSE; - QUIC_PACKET_SPACE* Packets = Connection->Packets[Builder->EncryptLevel]; - CXPLAT_DBG_ASSERT(Packets != NULL); - BOOLEAN IsCongestionControlBlocked = !QuicPacketBuilderHasAllowance(Builder); BOOLEAN Is1RttEncryptionLevel = @@ -497,10 +511,9 @@ QuicSendWriteFrames( uint8_t ZeroRttPacketType = Connection->Stats.QuicVersion == QUIC_VERSION_2 ? QUIC_0_RTT_PROTECTED_V2 : QUIC_0_RTT_PROTECTED_V1; - if (Builder->PacketType != ZeroRttPacketType && - QuicAckTrackerHasPacketsToAck(&Packets->AckTracker)) { - if (!QuicAckTrackerAckFrameEncode(&Packets->AckTracker, Builder)) { - RanOutOfRoom = TRUE; + if (Builder->PacketType != ZeroRttPacketType) { + QuicPathIDSetWriteAckFrame(&Connection->PathIDs, Builder, &RanOutOfRoom); + if (RanOutOfRoom) { goto Exit; } } @@ -628,6 +641,130 @@ QuicSendWriteFrames( } } + if (Send->SendFlags & QUIC_CONN_SEND_FLAG_PATH_ABANDON) { + + uint8_t i; + for (i = 0; i < Connection->PathsCount; ++i) { + QUIC_PATH* TempPath = &Connection->Paths[i]; + if (!TempPath->SendAbandon) { + continue; + } + + QUIC_PATH_ABANDON_EX Frame = { TempPath->PathID->ID, 0x00 }; + + if (QuicPathAbandonFrameEncode( + &Frame, + &Builder->DatagramLength, + AvailableBufferLength, + Builder->Datagram->Buffer)) { + + TempPath->SendAbandon = FALSE; + Builder->Metadata->Frames[Builder->Metadata->FrameCount].PATH_ABANDON.PathID = + (uint32_t)Frame.PathID; + if (QuicPacketBuilderAddFrame(Builder, QUIC_FRAME_PATH_ABANDON, TRUE)) { + break; + } + } else { + RanOutOfRoom = TRUE; + break; + } + } + + if (i == Connection->PathsCount) { + Send->SendFlags &= ~QUIC_CONN_SEND_FLAG_PATH_ABANDON; + } + + if (Builder->Metadata->FrameCount == QUIC_MAX_FRAMES_PER_PACKET) { + return TRUE; + } + } + + if (Send->SendFlags & QUIC_CONN_SEND_FLAG_PATH_BACKUP) { + + uint8_t i; + for (i = 0; i < Connection->PathsCount; ++i) { + QUIC_PATH* TempPath = &Connection->Paths[i]; + if (!TempPath->SendStatus) { + continue; + } + if (TempPath->IsActive) { + continue; + } + + QUIC_PATH_BACKUP_EX Frame = { TempPath->PathID->ID, TempPath->PathID->StatusSendSeq++ }; + + if (QuicPathBackupFrameEncode( + &Frame, + &Builder->DatagramLength, + AvailableBufferLength, + Builder->Datagram->Buffer)) { + + TempPath->SendStatus = FALSE; + Builder->Metadata->Frames[Builder->Metadata->FrameCount].PATH_BACKUP.PathID = + (uint32_t)Frame.PathID; + Builder->Metadata->Frames[Builder->Metadata->FrameCount].PATH_BACKUP.Sequence = + (uint32_t)Frame.StatusSequenceNumber; + if (QuicPacketBuilderAddFrame(Builder, QUIC_FRAME_PATH_BACKUP, TRUE)) { + break; + } + } else { + RanOutOfRoom = TRUE; + break; + } + } + + if (i == Connection->PathsCount) { + Send->SendFlags &= ~QUIC_CONN_SEND_FLAG_PATH_BACKUP; + } + + if (Builder->Metadata->FrameCount == QUIC_MAX_FRAMES_PER_PACKET) { + return TRUE; + } + } + + if (Send->SendFlags & QUIC_CONN_SEND_FLAG_PATH_AVAILABLE) { + + uint8_t i; + for (i = 0; i < Connection->PathsCount; ++i) { + QUIC_PATH* TempPath = &Connection->Paths[i]; + if (!TempPath->SendStatus) { + continue; + } + if (!TempPath->IsActive) { + continue; + } + + QUIC_PATH_AVAILABLE_EX Frame = { TempPath->PathID->ID, TempPath->PathID->StatusSendSeq++ }; + + if (QuicPathAvailableFrameEncode( + &Frame, + &Builder->DatagramLength, + AvailableBufferLength, + Builder->Datagram->Buffer)) { + + TempPath->SendStatus = FALSE; + Builder->Metadata->Frames[Builder->Metadata->FrameCount].PATH_AVAILABLE.PathID = + (uint32_t)Frame.PathID; + Builder->Metadata->Frames[Builder->Metadata->FrameCount].PATH_AVAILABLE.Sequence = + (uint32_t)Frame.StatusSequenceNumber; + if (QuicPacketBuilderAddFrame(Builder, QUIC_FRAME_PATH_AVAILABLE, TRUE)) { + break; + } + } else { + RanOutOfRoom = TRUE; + break; + } + } + + if (i == Connection->PathsCount) { + Send->SendFlags &= ~QUIC_CONN_SEND_FLAG_PATH_AVAILABLE; + } + + if (Builder->Metadata->FrameCount == QUIC_MAX_FRAMES_PER_PACKET) { + return TRUE; + } + } + if (Is1RttEncryptionLevel) { if (Builder->Metadata->Flags.KeyType == QUIC_PACKET_KEY_1_RTT && Send->SendFlags & QUIC_CONN_SEND_FLAG_HANDSHAKE_DONE) { @@ -775,61 +912,15 @@ QuicSendWriteFrames( } if ((Send->SendFlags & QUIC_CONN_SEND_FLAG_NEW_CONNECTION_ID)) { - BOOLEAN HasMoreCidsToSend = FALSE; BOOLEAN MaxFrameLimitHit = FALSE; - for (CXPLAT_SLIST_ENTRY* Entry = Connection->SourceCids.Next; - Entry != NULL; - Entry = Entry->Next) { - QUIC_CID_HASH_ENTRY* SourceCid = - CXPLAT_CONTAINING_RECORD( - Entry, - QUIC_CID_HASH_ENTRY, - Link); - if (!SourceCid->CID.NeedsToSend) { - continue; - } - if (MaxFrameLimitHit) { - HasMoreCidsToSend = TRUE; - break; - } - - QUIC_NEW_CONNECTION_ID_EX Frame = { - SourceCid->CID.Length, - SourceCid->CID.SequenceNumber, - 0, - { 0 } }; - CXPLAT_DBG_ASSERT(Connection->SourceCidLimit >= QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT_MIN); - if (Frame.Sequence >= Connection->SourceCidLimit) { - Frame.RetirePriorTo = Frame.Sequence + 1 - Connection->SourceCidLimit; - } - CxPlatCopyMemory( - Frame.Buffer, - SourceCid->CID.Data, - SourceCid->CID.Length); - CXPLAT_DBG_ASSERT(SourceCid->CID.Length == MsQuicLib.CidTotalLength); - QuicLibraryGenerateStatelessResetToken( - SourceCid->CID.Data, - Frame.Buffer + SourceCid->CID.Length); - - if (QuicNewConnectionIDFrameEncode( - &Frame, - &Builder->DatagramLength, - AvailableBufferLength, - Builder->Datagram->Buffer)) { - - SourceCid->CID.NeedsToSend = FALSE; - Builder->Metadata->Frames[ - Builder->Metadata->FrameCount].NEW_CONNECTION_ID.Sequence = - SourceCid->CID.SequenceNumber; - MaxFrameLimitHit = - QuicPacketBuilderAddFrame( - Builder, QUIC_FRAME_NEW_CONNECTION_ID, TRUE); - } else { - RanOutOfRoom = TRUE; - HasMoreCidsToSend = TRUE; - break; - } + if (!QuicPathIDSetWriteNewConnectionIDFrame( + &Connection->PathIDs, + Builder, + AvailableBufferLength, + &HasMoreCidsToSend, + &MaxFrameLimitHit)) { + RanOutOfRoom = TRUE; } if (!HasMoreCidsToSend) { Send->SendFlags &= ~QUIC_CONN_SEND_FLAG_NEW_CONNECTION_ID; @@ -840,47 +931,15 @@ QuicSendWriteFrames( } if ((Send->SendFlags & QUIC_CONN_SEND_FLAG_RETIRE_CONNECTION_ID)) { - BOOLEAN HasMoreCidsToSend = FALSE; BOOLEAN MaxFrameLimitHit = FALSE; - for (CXPLAT_LIST_ENTRY* Entry = Connection->DestCids.Flink; - Entry != &Connection->DestCids; - Entry = Entry->Flink) { - QUIC_CID_LIST_ENTRY* DestCid = - CXPLAT_CONTAINING_RECORD( - Entry, - QUIC_CID_LIST_ENTRY, - Link); - if (!DestCid->CID.NeedsToSend) { - continue; - } - CXPLAT_DBG_ASSERT(DestCid->CID.Retired); - if (MaxFrameLimitHit) { - HasMoreCidsToSend = TRUE; - break; - } - - QUIC_RETIRE_CONNECTION_ID_EX Frame = { - DestCid->CID.SequenceNumber - }; - if (QuicRetireConnectionIDFrameEncode( - &Frame, - &Builder->DatagramLength, - AvailableBufferLength, - Builder->Datagram->Buffer)) { - - DestCid->CID.NeedsToSend = FALSE; - Builder->Metadata->Frames[ - Builder->Metadata->FrameCount].RETIRE_CONNECTION_ID.Sequence = - DestCid->CID.SequenceNumber; - MaxFrameLimitHit = - QuicPacketBuilderAddFrame( - Builder, QUIC_FRAME_RETIRE_CONNECTION_ID, TRUE); - } else { - RanOutOfRoom = TRUE; - HasMoreCidsToSend = TRUE; - break; - } + if (!QuicPathIDSetWriteRetireConnectionIDFrame( + &Connection->PathIDs, + Builder, + AvailableBufferLength, + &HasMoreCidsToSend, + &MaxFrameLimitHit)) { + RanOutOfRoom = TRUE; } if (!HasMoreCidsToSend) { Send->SendFlags &= ~QUIC_CONN_SEND_FLAG_RETIRE_CONNECTION_ID; @@ -890,6 +949,25 @@ QuicSendWriteFrames( } } + if ((Send->SendFlags & QUIC_CONN_SEND_FLAG_MAX_PATH_ID)) { + + QUIC_MAX_PATH_ID_EX Frame = { Connection->PathIDs.MaxPathID }; + + if (QuicMaxPathIDFrameEncode( + &Frame, + &Builder->DatagramLength, + AvailableBufferLength, + Builder->Datagram->Buffer)) { + + Send->SendFlags &= ~QUIC_CONN_SEND_FLAG_MAX_PATH_ID; + if (QuicPacketBuilderAddFrame(Builder, QUIC_FRAME_MAX_PATH_ID, TRUE)) { + return TRUE; + } + } else { + RanOutOfRoom = TRUE; + } + } + if (Send->SendFlags & QUIC_CONN_SEND_FLAG_ACK_FREQUENCY) { QUIC_ACK_FREQUENCY_EX Frame; @@ -1165,6 +1243,20 @@ QuicSendPathChallenges( Path->SendChallenge = FALSE; } + if ((Send->SendFlags & QUIC_CONN_SEND_FLAG_NEW_CONNECTION_ID)) { + BOOLEAN HasMoreCidsToSend = FALSE; + BOOLEAN MaxFrameLimitHit = FALSE; + QuicPathIDSetWriteNewConnectionIDFrame( + &Connection->PathIDs, + &Builder, + AvailableBufferLength, + &HasMoreCidsToSend, + &MaxFrameLimitHit); + if (!HasMoreCidsToSend) { + Send->SendFlags &= ~QUIC_CONN_SEND_FLAG_NEW_CONNECTION_ID; + } + } + QuicPacketBuilderFinalize(&Builder, TRUE); QuicPacketBuilderCleanup(&Builder); } @@ -1188,7 +1280,7 @@ QuicSendFlush( ) { QUIC_CONNECTION* Connection = QuicSendGetConnection(Send); - QUIC_PATH* Path = &Connection->Paths[0]; + QUIC_PATH* Path = QuicConnChoosePath(Connection); CXPLAT_DBG_ASSERT(!Connection->State.HandleClosed); @@ -1224,7 +1316,7 @@ QuicSendFlush( if (Connection->Settings.DestCidUpdateIdleTimeoutMs != 0 && Send->LastFlushTimeValid && CxPlatTimeDiff64(Send->LastFlushTime, TimeNow) >= MS_TO_US(Connection->Settings.DestCidUpdateIdleTimeoutMs)) { - (void)QuicConnRetireCurrentDestCid(Connection, Path); + (void)QuicPathIDRetireCurrentDestCid(Path->PathID, Path); } QUIC_SEND_RESULT Result = QUIC_SEND_INCOMPLETE; @@ -1261,7 +1353,7 @@ QuicSendFlush( } else { uint64_t ThreePtosInUs = QuicLossDetectionComputeProbeTimeout( - &Connection->LossDetection, + &Connection->Paths[0].PathID->LossDetection, &Connection->Paths[0], QUIC_CLOSE_PTO_COUNT); Builder.Path->EcnTestingEndingTime = TimeNow + ThreePtosInUs; @@ -1311,7 +1403,7 @@ QuicSendFlush( // SendFlags &= QUIC_CONN_SEND_FLAGS_BYPASS_CC; if (!SendFlags) { - if (QuicCongestionControlCanSend(&Connection->CongestionControl)) { + if (QuicCongestionControlCanSend(&Path->PathID->CongestionControl)) { // // The current pacing chunk is finished. We need to schedule a // new pacing send. @@ -1381,14 +1473,13 @@ QuicSendFlush( // // Write any ACK frames if we have them. // - QUIC_PACKET_SPACE* Packets = Connection->Packets[Builder.EncryptLevel]; uint8_t ZeroRttPacketType = Connection->Stats.QuicVersion == QUIC_VERSION_2 ? QUIC_0_RTT_PROTECTED_V2 : QUIC_0_RTT_PROTECTED_V1; + BOOLEAN RanOutOfRoom = FALSE; WrotePacketFrames = Builder.PacketType != ZeroRttPacketType && - QuicAckTrackerHasPacketsToAck(&Packets->AckTracker) && - QuicAckTrackerAckFrameEncode(&Packets->AckTracker, &Builder); + QuicPathIDSetWriteAckFrame(&Connection->PathIDs, &Builder, &RanOutOfRoom); // // Write the stream frames. @@ -1541,12 +1632,21 @@ QuicSendProcessDelayedAckTimer( QUIC_CONNECTION* Connection = QuicSendGetConnection(Send); BOOLEAN AckElicitingPacketsToAcknowledge = FALSE; - for (uint32_t i = 0; i < QUIC_ENCRYPT_LEVEL_COUNT; ++i) { - if (Connection->Packets[i] != NULL && - Connection->Packets[i]->AckTracker.AckElicitingPacketsToAcknowledge) { - AckElicitingPacketsToAcknowledge = TRUE; - break; + QUIC_PATHID* PathIDs[QUIC_ACTIVE_PATH_ID_LIMIT]; + uint8_t PathIDCount = QUIC_ACTIVE_PATH_ID_LIMIT; + QuicPathIDSetGetPathIDs(&Connection->PathIDs, PathIDs, &PathIDCount); + + for (uint8_t i = 0; i < PathIDCount; i++) { + if (!AckElicitingPacketsToAcknowledge) { + for (uint32_t j = 0; j < QUIC_ENCRYPT_LEVEL_COUNT; ++j) { + if (PathIDs[i]->Packets[j] != NULL && + PathIDs[i]->Packets[j]->AckTracker.AckElicitingPacketsToAcknowledge) { + AckElicitingPacketsToAcknowledge = TRUE; + break; + } + } } + QuicPathIDRelease(PathIDs[i], QUIC_PATHID_REF_LOOKUP); } CXPLAT_DBG_ASSERT(AckElicitingPacketsToAcknowledge); diff --git a/src/core/send.h b/src/core/send.h index 92ac65502c..900b575ccc 100644 --- a/src/core/send.h +++ b/src/core/send.h @@ -145,6 +145,11 @@ QuicPacketTypeToEncryptLevelV2( #define QUIC_CONN_SEND_FLAG_ACK_FREQUENCY 0x00008000U #define QUIC_CONN_SEND_FLAG_BIDI_STREAMS_BLOCKED 0x00010000U #define QUIC_CONN_SEND_FLAG_UNI_STREAMS_BLOCKED 0x00020000U +#define QUIC_CONN_SEND_FLAG_PATH_ABANDON 0x00040000U +#define QUIC_CONN_SEND_FLAG_PATH_BACKUP 0x00080000U +#define QUIC_CONN_SEND_FLAG_PATH_AVAILABLE 0x00100000U +#define QUIC_CONN_SEND_FLAG_MAX_PATH_ID 0x00200000U +#define QUIC_CONN_SEND_FLAG_PATHS_BLOCKED 0x00400000U #define QUIC_CONN_SEND_FLAG_DPLPMTUD 0x80000000U // @@ -262,11 +267,6 @@ typedef struct QUIC_SEND { // BOOLEAN Uninitialized : 1; - // - // The next packet number to use. - // - uint64_t NextPacketNumber; - // // Last time send flush occurred. Used for pacing calculations. // diff --git a/src/core/send_buffer.c b/src/core/send_buffer.c index e8a79f767a..faec0616a4 100644 --- a/src/core/send_buffer.c +++ b/src/core/send_buffer.c @@ -259,7 +259,7 @@ QuicSendBufferConnectionAdjust( const uint64_t NewIdealBytes = QuicGetNextIdealBytes( - QuicCongestionControlGetBytesInFlightMax(&Connection->CongestionControl)); + QuicCongestionControlGetBytesInFlightMax(&Connection->Paths[0].PathID->CongestionControl)); // // TODO: Currently, IdealBytes only grows and never shrinks. Add appropriate diff --git a/src/core/sent_packet_metadata.h b/src/core/sent_packet_metadata.h index d18359fc62..23fad5aa27 100644 --- a/src/core/sent_packet_metadata.h +++ b/src/core/sent_packet_metadata.h @@ -8,7 +8,7 @@ // // The maximum number of frames we will write to a single packet. // -#define QUIC_MAX_FRAMES_PER_PACKET 12 +#define QUIC_MAX_FRAMES_PER_PACKET 10 typedef struct QUIC_STREAM QUIC_STREAM; @@ -47,9 +47,11 @@ typedef struct QUIC_SENT_FRAME_METADATA { QUIC_STREAM* Stream; } STREAM_DATA_BLOCKED; struct { + uint32_t PathID; QUIC_VAR_INT Sequence; } NEW_CONNECTION_ID; struct { + uint32_t PathID; QUIC_VAR_INT Sequence; } RETIRE_CONNECTION_ID; struct { @@ -58,6 +60,17 @@ typedef struct QUIC_SENT_FRAME_METADATA { struct { uint8_t Data[8]; } PATH_RESPONSE; + struct { + uint32_t PathID; + } PATH_ABANDON; + struct { + uint32_t PathID; + QUIC_VAR_INT Sequence; + } PATH_BACKUP; + struct { + uint32_t PathID; + QUIC_VAR_INT Sequence; + } PATH_AVAILABLE; struct { void* ClientContext; } DATAGRAM; @@ -75,14 +88,14 @@ typedef struct QUIC_SENT_FRAME_METADATA { // uint64_t StreamOffset; uint16_t StreamLength; - uint16_t Type; // QUIC_FRAME_* + uint32_t Type; // QUIC_FRAME_* uint8_t Flags; // QUIC_SENT_FRAME_FLAG_* } QUIC_SENT_FRAME_METADATA; CXPLAT_STATIC_ASSERT( - QUIC_FRAME_MAX_SUPPORTED <= (uint64_t)UINT16_MAX, - "Metadata 'Type' field above assumes frames types fit in 16-bits"); + QUIC_FRAME_MAX_SUPPORTED <= (uint64_t)UINT32_MAX, + "Metadata 'Type' field above assumes frames types fit in 32-bits"); typedef struct QUIC_SEND_PACKET_FLAGS { diff --git a/src/core/settings.c b/src/core/settings.c index 40dd41245f..75b5713e2e 100644 --- a/src/core/settings.c +++ b/src/core/settings.c @@ -168,6 +168,14 @@ QuicSettingsSetDefault( if (!Settings->IsSet.StreamMultiReceiveEnabled) { Settings->StreamMultiReceiveEnabled = QUIC_DEFAULT_STREAM_MULTI_RECEIVE_ENABLED; } +#if QUIC_TEST_MANUAL_CONN_ID_GENERATION + if (!Settings->IsSet.ConnIDGenDisabled) { + Settings->ConnIDGenDisabled = QUIC_DEFAULT_CONN_ID_GENERATION_DISABLED; + } +#endif + if (!Settings->IsSet.MultipathEnabled) { + Settings->MultipathEnabled = QUIC_DEFAULT_MULTIPATH_ENABLED; + } } _IRQL_requires_max_(PASSIVE_LEVEL) @@ -336,6 +344,14 @@ QuicSettingsCopy( if (!Destination->IsSet.StreamMultiReceiveEnabled) { Destination->StreamMultiReceiveEnabled = Source->StreamMultiReceiveEnabled; } +#if QUIC_TEST_MANUAL_CONN_ID_GENERATION + if (!Destination->IsSet.ConnIDGenDisabled) { + Destination->ConnIDGenDisabled = Source->ConnIDGenDisabled; + } +#endif + if (!Destination->IsSet.MultipathEnabled) { + Destination->MultipathEnabled = Source->MultipathEnabled; + } } _IRQL_requires_max_(PASSIVE_LEVEL) @@ -714,6 +730,18 @@ QuicSettingApply( Destination->StreamMultiReceiveEnabled = Source->StreamMultiReceiveEnabled; Destination->IsSet.StreamMultiReceiveEnabled = TRUE; } + +#if QUIC_TEST_MANUAL_CONN_ID_GENERATION + if (Source->IsSet.ConnIDGenDisabled && (!Destination->IsSet.ConnIDGenDisabled || OverWrite)) { + Destination->ConnIDGenDisabled = Source->ConnIDGenDisabled; + Destination->IsSet.ConnIDGenDisabled = TRUE; + } +#endif + + if (Source->IsSet.MultipathEnabled && (!Destination->IsSet.MultipathEnabled || OverWrite)) { + Destination->MultipathEnabled = Source->MultipathEnabled; + Destination->IsSet.MultipathEnabled = TRUE; + } return TRUE; } @@ -1382,6 +1410,28 @@ QuicSettingsLoad( &ValueLen); Settings->StreamMultiReceiveEnabled = !!Value; } +#if QUIC_TEST_MANUAL_CONN_ID_GENERATION + if (!Settings->IsSet.ConnIDGenDisabled) { + Value = QUIC_DEFAULT_CONN_ID_GENERATION_DISABLED; + ValueLen = sizeof(Value); + CxPlatStorageReadValue( + Storage, + QUIC_SETTING_CONN_ID_GENERATION_DISABLED, + (uint8_t*)&Value, + &ValueLen); + Settings->ConnIDGenDisabled = !!Value; + } +#endif + if (!Settings->IsSet.MultipathEnabled) { + Value = QUIC_DEFAULT_MULTIPATH_ENABLED; + ValueLen = sizeof(Value); + CxPlatStorageReadValue( + Storage, + QUIC_SETTING_MULTIPATH_ENABLED, + (uint8_t*)&Value, + &ValueLen); + Settings->MultipathEnabled = !!Value; + } } _IRQL_requires_max_(PASSIVE_LEVEL) @@ -1451,6 +1501,7 @@ QuicSettingsDump( QuicTraceLogVerbose(SettingOneWayDelayEnabled, "[sett] OneWayDelayEnabled = %hhu", Settings->OneWayDelayEnabled); QuicTraceLogVerbose(SettingNetStatsEventEnabled, "[sett] NetStatsEventEnabled = %hhu", Settings->NetStatsEventEnabled); QuicTraceLogVerbose(SettingsStreamMultiReceiveEnabled, "[sett] StreamMultiReceiveEnabled= %hhu", Settings->StreamMultiReceiveEnabled); + QuicTraceLogVerbose(SettingMultipathEnabled, "[sett] MultipathEnabled = %hhu", Settings->MultipathEnabled); } _IRQL_requires_max_(PASSIVE_LEVEL) @@ -1615,6 +1666,14 @@ QuicSettingsDumpNew( if (Settings->IsSet.StreamMultiReceiveEnabled) { QuicTraceLogVerbose(SettingStreamMultiReceiveEnabled, "[sett] StreamMultiReceiveEnabled = %hhu", Settings->StreamMultiReceiveEnabled); } +#if QUIC_TEST_MANUAL_CONN_ID_GENERATION + if (Settings->IsSet.ConnIDGenDisabled) { + QuicTraceLogVerbose(SettingConnIDGenDisabled, "[sett] ConnIDGenDisabled = %hhu", Settings->ConnIDGenDisabled); + } +#endif + if (Settings->IsSet.MultipathEnabled) { + QuicTraceLogVerbose(SettingMultipathEnabled, "[sett] MultipathEnabled = %hhu", Settings->MultipathEnabled); + } } #define SETTINGS_SIZE_THRU_FIELD(SettingsType, Field) \ @@ -1879,6 +1938,14 @@ QuicSettingsSettingsToInternal( SettingsSize, InternalSettings); + SETTING_COPY_FLAG_TO_INTERNAL_SIZED( + Flags, + MultipathEnabled, + QUIC_SETTINGS, + Settings, + SettingsSize, + InternalSettings); + return QUIC_STATUS_SUCCESS; } diff --git a/src/core/settings.h b/src/core/settings.h index 9650e119bb..ba2c9a43a0 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -62,7 +62,9 @@ typedef struct QUIC_SETTINGS_INTERNAL { uint64_t OneWayDelayEnabled : 1; uint64_t NetStatsEventEnabled : 1; uint64_t StreamMultiReceiveEnabled : 1; - uint64_t RESERVED : 16; + uint64_t ConnIDGenDisabled : 1; + uint64_t MultipathEnabled : 1; + uint64_t RESERVED : 14; } IsSet; }; @@ -113,6 +115,8 @@ typedef struct QUIC_SETTINGS_INTERNAL { uint8_t OneWayDelayEnabled : 1; uint8_t NetStatsEventEnabled : 1; uint8_t StreamMultiReceiveEnabled : 1; + uint8_t ConnIDGenDisabled : 1; + uint8_t MultipathEnabled : 1; uint8_t MtuDiscoveryMissingProbeCount; } QUIC_SETTINGS_INTERNAL; diff --git a/src/core/transport_params.h b/src/core/transport_params.h index e510554f85..d77292bcea 100644 --- a/src/core/transport_params.h +++ b/src/core/transport_params.h @@ -152,6 +152,12 @@ typedef struct QUIC_TRANSPORT_PARAMETERS { uint32_t VersionInfoLength; const uint8_t* VersionInfo; + // + // The initial maximum number of paths allowed. + // + _Field_range_(0, QUIC_TP_MAX_PATH_ID_MAX) + QUIC_VAR_INT InitialMaxPathId; + } QUIC_TRANSPORT_PARAMETERS; // diff --git a/src/core/unittest/FrameTest.cpp b/src/core/unittest/FrameTest.cpp index f3cde7e738..aaf564b5cc 100644 --- a/src/core/unittest/FrameTest.cpp +++ b/src/core/unittest/FrameTest.cpp @@ -23,6 +23,7 @@ TEST_P(AckFrameTest, AckFrameEncodeDecode) const uint64_t ContigPktCount = 4; const uint64_t MinPktNum = 5; const uint64_t AckDelay = 0; + uint32_t PathId; QUIC_ACK_ECN_EX Ecn = {4, 4, 4}; QUIC_ACK_ECN_EX DecodedEcn = {0, 0, 0}; QUIC_RANGE AckRange; @@ -44,10 +45,10 @@ TEST_P(AckFrameTest, AckFrameEncodeDecode) ASSERT_TRUE(QuicRangeAddRange(&AckRange, MinPktNum, ContigPktCount, &Unused) != nullptr); ASSERT_TRUE(QuicRangeAddValue(&AckRange, MaxPktNum)); - ASSERT_TRUE(QuicAckFrameEncode(&AckRange, AckDelay, (GetParam() == QUIC_FRAME_ACK ? nullptr : &Ecn), &Offset, BufferLength, Buffer)); + ASSERT_TRUE(QuicAckFrameEncode(FALSE, 0, &AckRange, AckDelay, (GetParam() == QUIC_FRAME_ACK ? nullptr : &Ecn), &Offset, BufferLength, Buffer)); Offset = 1; ASSERT_EQ(Buffer[0], GetParam()); - ASSERT_TRUE(QuicAckFrameDecode(GetParam(), BufferLength, Buffer, &Offset, &InvalidFrame, &DecodedAckRange, &DecodedEcn, &DecodedAckDelay)); + ASSERT_TRUE(QuicAckFrameDecode(GetParam(), BufferLength, Buffer, &Offset, &InvalidFrame, &PathId, &DecodedAckRange, &DecodedEcn, &DecodedAckDelay)); ASSERT_FALSE(InvalidFrame); ASSERT_EQ(AckDelay, DecodedAckDelay); @@ -72,6 +73,7 @@ TEST_P(AckFrameTest, AckFrameEncodeDecode) } TEST_P(AckFrameTest, DecodeAckFrameFail) { + uint32_t PathId; QUIC_ACK_ECN_EX DecodedEcn; uint8_t Buffer[18]; uint16_t BufferLength; @@ -100,7 +102,7 @@ TEST_P(AckFrameTest, DecodeAckFrameFail) { Buffer[9] = 3; } - BOOLEAN Result = QuicAckFrameDecode(GetParam(), BufferLength, Buffer, &Offset, &InvalidFrame, &DecodedAckBlocks, &DecodedEcn, &AckDelay); + BOOLEAN Result = QuicAckFrameDecode(GetParam(), BufferLength, Buffer, &Offset, &InvalidFrame, &PathId, &DecodedAckBlocks, &DecodedEcn, &AckDelay); ASSERT_TRUE(InvalidFrame); ASSERT_FALSE(Result); @@ -134,7 +136,7 @@ TEST_P(AckFrameTest, DecodeAckFrameFail) { Buffer[17] = 6; } - Result = QuicAckFrameDecode(GetParam(), BufferLength, Buffer, &Offset, &InvalidFrame, &DecodedAckBlocks, &DecodedEcn, &AckDelay); + Result = QuicAckFrameDecode(GetParam(), BufferLength, Buffer, &Offset, &InvalidFrame, &PathId, &DecodedAckBlocks, &DecodedEcn, &AckDelay); ASSERT_TRUE(InvalidFrame); ASSERT_FALSE(Result); @@ -158,7 +160,7 @@ TEST_P(AckFrameTest, DecodeAckFrameFail) { Buffer[7] = 9; } - Result = QuicAckFrameDecode(GetParam(), BufferLength, Buffer, &Offset, &InvalidFrame, &DecodedAckBlocks, &DecodedEcn, &AckDelay); + Result = QuicAckFrameDecode(GetParam(), BufferLength, Buffer, &Offset, &InvalidFrame, &PathId, &DecodedAckBlocks, &DecodedEcn, &AckDelay); ASSERT_TRUE(InvalidFrame); ASSERT_FALSE(Result); @@ -190,7 +192,7 @@ TEST_P(AckFrameTest, DecodeAckFrameFail) { // Buffer[7] = (i & 4) ? (uint8_t)TestValue : 0; - ASSERT_FALSE(QuicAckFrameDecode(GetParam(), BufferLength, Buffer, &Offset, &InvalidFrame, &DecodedAckBlocks, &DecodedEcn, &AckDelay)); + ASSERT_FALSE(QuicAckFrameDecode(GetParam(), BufferLength, Buffer, &Offset, &InvalidFrame, &PathId, &DecodedAckBlocks, &DecodedEcn, &AckDelay)); QuicRangeReset(&DecodedAckBlocks); } @@ -982,7 +984,7 @@ INSTANTIATE_TEST_SUITE_P( TEST(FrameTest, NewConnectionIdFrameEncodeDecode) { - QUIC_NEW_CONNECTION_ID_EX Frame = {5, 63, 0, + QUIC_NEW_CONNECTION_ID_EX Frame = {5, 0, 63, 0, {5, 5, 5, 5, 5, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}}; QUIC_NEW_CONNECTION_ID_EX DecodedFrame; @@ -993,9 +995,9 @@ TEST(FrameTest, NewConnectionIdFrameEncodeDecode) CxPlatZeroMemory(Buffer, BufferLength); CxPlatZeroMemory(&DecodedFrame, sizeof(DecodedFrame)); - ASSERT_TRUE(QuicNewConnectionIDFrameEncode(&Frame, &Offset, BufferLength, Buffer)); + ASSERT_TRUE(QuicNewConnectionIDFrameEncode(QUIC_FRAME_NEW_CONNECTION_ID, &Frame, &Offset, BufferLength, Buffer)); Offset = 1; - ASSERT_TRUE(QuicNewConnectionIDFrameDecode(BufferLength, Buffer, &Offset, &DecodedFrame)); + ASSERT_TRUE(QuicNewConnectionIDFrameDecode(QUIC_FRAME_NEW_CONNECTION_ID, BufferLength, Buffer, &Offset, &DecodedFrame)); ASSERT_EQ(Frame.Length, DecodedFrame.Length); ASSERT_EQ(Frame.Sequence, DecodedFrame.Sequence); @@ -1129,7 +1131,7 @@ struct NewConnectionIdFrameTest : ::testing::TestWithParamPriorityConnectionsTail = &Worker->Connections.Flink; CxPlatListInitializeHead(&Worker->Operations); CxPlatPoolInitialize(FALSE, sizeof(QUIC_STREAM), QUIC_POOL_STREAM, &Worker->StreamPool); + CxPlatPoolInitialize(FALSE, sizeof(QUIC_PATHID), QUIC_POOL_PATHID, &Worker->PathIDPool); CxPlatPoolInitialize(FALSE, sizeof(QUIC_RECV_CHUNK)+QUIC_DEFAULT_STREAM_RECV_BUFFER_SIZE, QUIC_POOL_SBUF, &Worker->DefaultReceiveBufferPool); CxPlatPoolInitialize(FALSE, sizeof(QUIC_SEND_REQUEST), QUIC_POOL_SEND_REQUEST, &Worker->SendRequestPool); QuicSentPacketPoolInitialize(&Worker->SentPacketPool); @@ -194,6 +195,7 @@ QuicWorkerUninitialize( CXPLAT_TEL_ASSERT(CxPlatListIsEmpty(&Worker->Operations)); CxPlatPoolUninitialize(&Worker->StreamPool); + CxPlatPoolUninitialize(&Worker->PathIDPool); CxPlatPoolUninitialize(&Worker->DefaultReceiveBufferPool); CxPlatPoolUninitialize(&Worker->SendRequestPool); QuicSentPacketPoolUninitialize(&Worker->SentPacketPool); diff --git a/src/core/worker.h b/src/core/worker.h index 5cb4796bb6..8425a9144c 100644 --- a/src/core/worker.h +++ b/src/core/worker.h @@ -80,6 +80,7 @@ typedef struct QUIC_CACHEALIGN QUIC_WORKER { uint64_t DroppedOperationCount; CXPLAT_POOL StreamPool; // QUIC_STREAM + CXPLAT_POOL PathIDPool; // QUIC_PATHID CXPLAT_POOL DefaultReceiveBufferPool; // QUIC_DEFAULT_STREAM_RECV_BUFFER_SIZE CXPLAT_POOL SendRequestPool; // QUIC_SEND_REQUEST QUIC_SENT_PACKET_POOL SentPacketPool; // QUIC_SENT_PACKET_METADATA diff --git a/src/generated/linux/bbr.c.clog.h b/src/generated/linux/bbr.c.clog.h index e99ba72d08..d739e6bb02 100644 --- a/src/generated/linux/bbr.c.clog.h +++ b/src/generated/linux/bbr.c.clog.h @@ -61,7 +61,7 @@ tracepoint(CLOG_BBR_C, IndicateDataAcked , arg1, arg3, arg4, arg5, arg6, arg7, a // QuicTraceEvent( ConnBbr, "[conn][%p] BBR: State=%u RState=%u CongestionWindow=%u BytesInFlight=%u BytesInFlightMax=%u MinRttEst=%lu EstBw=%lu AppLimited=%u", - Connection, + PathID->Connection, Bbr->BbrState, Bbr->RecoveryState, BbrCongestionControlGetCongestionWindow(Cc), @@ -70,7 +70,7 @@ tracepoint(CLOG_BBR_C, IndicateDataAcked , arg1, arg3, arg4, arg5, arg6, arg7, a Bbr->MinRtt, BbrCongestionControlGetBandwidth(Cc) / BW_UNIT, BbrCongestionControlIsAppLimited(Cc)); -// arg2 = arg2 = Connection = arg2 +// arg2 = arg2 = PathID->Connection = arg2 // arg3 = arg3 = Bbr->BbrState = arg3 // arg4 = arg4 = Bbr->RecoveryState = arg4 // arg5 = arg5 = BbrCongestionControlGetCongestionWindow(Cc) = arg5 diff --git a/src/generated/linux/bbr.c.clog.h.lttng.h b/src/generated/linux/bbr.c.clog.h.lttng.h index 89a30cc133..7438497c07 100644 --- a/src/generated/linux/bbr.c.clog.h.lttng.h +++ b/src/generated/linux/bbr.c.clog.h.lttng.h @@ -50,7 +50,7 @@ TRACEPOINT_EVENT(CLOG_BBR_C, IndicateDataAcked, // QuicTraceEvent( ConnBbr, "[conn][%p] BBR: State=%u RState=%u CongestionWindow=%u BytesInFlight=%u BytesInFlightMax=%u MinRttEst=%lu EstBw=%lu AppLimited=%u", - Connection, + PathID->Connection, Bbr->BbrState, Bbr->RecoveryState, BbrCongestionControlGetCongestionWindow(Cc), @@ -59,7 +59,7 @@ TRACEPOINT_EVENT(CLOG_BBR_C, IndicateDataAcked, Bbr->MinRtt, BbrCongestionControlGetBandwidth(Cc) / BW_UNIT, BbrCongestionControlIsAppLimited(Cc)); -// arg2 = arg2 = Connection = arg2 +// arg2 = arg2 = PathID->Connection = arg2 // arg3 = arg3 = Bbr->BbrState = arg3 // arg4 = arg4 = Bbr->RecoveryState = arg4 // arg5 = arg5 = BbrCongestionControlGetCongestionWindow(Cc) = arg5 diff --git a/src/generated/linux/congestion_control.c.clog.h b/src/generated/linux/congestion_control.c.clog.h index c6cf3e6714..4fb57cf978 100644 --- a/src/generated/linux/congestion_control.c.clog.h +++ b/src/generated/linux/congestion_control.c.clog.h @@ -26,10 +26,10 @@ extern "C" { // [conn][%p] Unknown congestion control algorithm: %hu, fallback to Cubic // QuicTraceLogConnWarning( InvalidCongestionControlAlgorithm, - QuicCongestionControlGetConnection(Cc), + QuicCongestionControlGetPathID(Cc)->Connection, "Unknown congestion control algorithm: %hu, fallback to Cubic", Settings->CongestionControlAlgorithm); -// arg1 = arg1 = QuicCongestionControlGetConnection(Cc) = arg1 +// arg1 = arg1 = QuicCongestionControlGetPathID(Cc)->Connection = arg1 // arg3 = arg3 = Settings->CongestionControlAlgorithm = arg3 ----------------------------------------------------------*/ #ifndef _clog_4_ARGS_TRACE_InvalidCongestionControlAlgorithm diff --git a/src/generated/linux/congestion_control.c.clog.h.lttng.h b/src/generated/linux/congestion_control.c.clog.h.lttng.h index df64b9f1c8..869edf6aa2 100644 --- a/src/generated/linux/congestion_control.c.clog.h.lttng.h +++ b/src/generated/linux/congestion_control.c.clog.h.lttng.h @@ -6,10 +6,10 @@ // [conn][%p] Unknown congestion control algorithm: %hu, fallback to Cubic // QuicTraceLogConnWarning( InvalidCongestionControlAlgorithm, - QuicCongestionControlGetConnection(Cc), + QuicCongestionControlGetPathID(Cc)->Connection, "Unknown congestion control algorithm: %hu, fallback to Cubic", Settings->CongestionControlAlgorithm); -// arg1 = arg1 = QuicCongestionControlGetConnection(Cc) = arg1 +// arg1 = arg1 = QuicCongestionControlGetPathID(Cc)->Connection = arg1 // arg3 = arg3 = Settings->CongestionControlAlgorithm = arg3 ----------------------------------------------------------*/ TRACEPOINT_EVENT(CLOG_CONGESTION_CONTROL_C, InvalidCongestionControlAlgorithm, diff --git a/src/generated/linux/connection.c.clog.h b/src/generated/linux/connection.c.clog.h index 181deaaa58..2f80f91e95 100644 --- a/src/generated/linux/connection.c.clog.h +++ b/src/generated/linux/connection.c.clog.h @@ -45,9 +45,9 @@ extern "C" { // Decoder Ring for PacketRxStatelessReset // [S][RX][-] SR %s // QuicTraceLogVerbose( - PacketRxStatelessReset, - "[S][RX][-] SR %s", - QuicCidBufToStr(PacketResetToken, QUIC_STATELESS_RESET_TOKEN_LENGTH).Buffer); + PacketRxStatelessReset, + "[S][RX][-] SR %s", + QuicCidBufToStr(PacketResetToken, QUIC_STATELESS_RESET_TOKEN_LENGTH).Buffer); // arg2 = arg2 = QuicCidBufToStr(PacketResetToken, QUIC_STATELESS_RESET_TOKEN_LENGTH).Buffer = arg2 ----------------------------------------------------------*/ #ifndef _clog_3_ARGS_TRACE_PacketRxStatelessReset @@ -321,42 +321,6 @@ tracepoint(CLOG_CONNECTION_C, ApiEventNoHandler , arg1);\ -/*---------------------------------------------------------- -// Decoder Ring for NoReplacementCidForRetire -// [conn][%p] Can't retire current CID because we don't have a replacement -// QuicTraceLogConnWarning( - NoReplacementCidForRetire, - Connection, - "Can't retire current CID because we don't have a replacement"); -// arg1 = arg1 = Connection = arg1 -----------------------------------------------------------*/ -#ifndef _clog_3_ARGS_TRACE_NoReplacementCidForRetire -#define _clog_3_ARGS_TRACE_NoReplacementCidForRetire(uniqueId, arg1, encoded_arg_string)\ -tracepoint(CLOG_CONNECTION_C, NoReplacementCidForRetire , arg1);\ - -#endif - - - - -/*---------------------------------------------------------- -// Decoder Ring for NonActivePathCidRetired -// [conn][%p] Non-active path has no replacement for retired CID. -// QuicTraceLogConnWarning( - NonActivePathCidRetired, - Connection, - "Non-active path has no replacement for retired CID."); -// arg1 = arg1 = Connection = arg1 -----------------------------------------------------------*/ -#ifndef _clog_3_ARGS_TRACE_NonActivePathCidRetired -#define _clog_3_ARGS_TRACE_NonActivePathCidRetired(uniqueId, arg1, encoded_arg_string)\ -tracepoint(CLOG_CONNECTION_C, NonActivePathCidRetired , arg1);\ - -#endif - - - - /*---------------------------------------------------------- // Decoder Ring for IgnoreUnreachable // [conn][%p] Ignoring received unreachable event (inline) @@ -606,9 +570,9 @@ tracepoint(CLOG_CONNECTION_C, CustomCertValidationPending , arg1);\ // Decoder Ring for RecvStatelessReset // [conn][%p] Received stateless reset // QuicTraceLogConnInfo( - RecvStatelessReset, - Connection, - "Received stateless reset"); + RecvStatelessReset, + Connection, + "Received stateless reset"); // arg1 = arg1 = Connection = arg1 ----------------------------------------------------------*/ #ifndef _clog_3_ARGS_TRACE_RecvStatelessReset @@ -682,10 +646,10 @@ tracepoint(CLOG_CONNECTION_C, FirstCidUsage , arg1, arg3);\ // Decoder Ring for PathDiscarded // [conn][%p] Removing invalid path[%hhu] // QuicTraceLogConnInfo( - PathDiscarded, - Connection, - "Removing invalid path[%hhu]", - Connection->Paths[i].ID); + PathDiscarded, + Connection, + "Removing invalid path[%hhu]", + Connection->Paths[i].ID); // arg1 = arg1 = Connection = arg1 // arg3 = arg3 = Connection->Paths[i].ID = arg3 ----------------------------------------------------------*/ @@ -903,42 +867,6 @@ tracepoint(CLOG_CONNECTION_C, RttUpdatedV2 , arg1, arg3, arg4, arg5, arg6, arg7, -/*---------------------------------------------------------- -// Decoder Ring for NewSrcCidNameCollision -// [conn][%p] CID collision, trying again -// QuicTraceLogConnVerbose( - NewSrcCidNameCollision, - Connection, - "CID collision, trying again"); -// arg1 = arg1 = Connection = arg1 -----------------------------------------------------------*/ -#ifndef _clog_3_ARGS_TRACE_NewSrcCidNameCollision -#define _clog_3_ARGS_TRACE_NewSrcCidNameCollision(uniqueId, arg1, encoded_arg_string)\ -tracepoint(CLOG_CONNECTION_C, NewSrcCidNameCollision , arg1);\ - -#endif - - - - -/*---------------------------------------------------------- -// Decoder Ring for ZeroLengthCidRetire -// [conn][%p] Can't retire current CID because it's zero length -// QuicTraceLogConnVerbose( - ZeroLengthCidRetire, - Connection, - "Can't retire current CID because it's zero length"); -// arg1 = arg1 = Connection = arg1 -----------------------------------------------------------*/ -#ifndef _clog_3_ARGS_TRACE_ZeroLengthCidRetire -#define _clog_3_ARGS_TRACE_ZeroLengthCidRetire(uniqueId, arg1, encoded_arg_string)\ -tracepoint(CLOG_CONNECTION_C, ZeroLengthCidRetire , arg1);\ - -#endif - - - - /*---------------------------------------------------------- // Decoder Ring for IndicateShutdownByPeer // [conn][%p] Indicating QUIC_CONNECTION_EVENT_SHUTDOWN_INITIATED_BY_PEER [0x%llx] @@ -1360,6 +1288,42 @@ tracepoint(CLOG_CONNECTION_C, IndicatePeerNeedStreamsV2 , arg1, arg3);\ +/*---------------------------------------------------------- +// Decoder Ring for IndicatePathAdded +// [conn][%p] Indicating QUIC_CONNECTION_EVENT_PATH_ADDED +// QuicTraceLogConnVerbose( + IndicatePathAdded, + Connection, + "Indicating QUIC_CONNECTION_EVENT_PATH_ADDED"); +// arg1 = arg1 = Connection = arg1 +----------------------------------------------------------*/ +#ifndef _clog_3_ARGS_TRACE_IndicatePathAdded +#define _clog_3_ARGS_TRACE_IndicatePathAdded(uniqueId, arg1, encoded_arg_string)\ +tracepoint(CLOG_CONNECTION_C, IndicatePathAdded , arg1);\ + +#endif + + + + +/*---------------------------------------------------------- +// Decoder Ring for IndicatePathStatusChanged +// [conn][%p] Indicating QUIC_CONNECTION_EVENT_PATH_STATUS_CHANGED +// QuicTraceLogConnVerbose( + IndicatePathStatusChanged, + Connection, + "Indicating QUIC_CONNECTION_EVENT_PATH_STATUS_CHANGED"); +// arg1 = arg1 = Connection = arg1 +----------------------------------------------------------*/ +#ifndef _clog_3_ARGS_TRACE_IndicatePathStatusChanged +#define _clog_3_ARGS_TRACE_IndicatePathStatusChanged(uniqueId, arg1, encoded_arg_string)\ +tracepoint(CLOG_CONNECTION_C, IndicatePathStatusChanged , arg1);\ + +#endif + + + + /*---------------------------------------------------------- // Decoder Ring for IndicatePeerAddrChanged // [conn][%p] Indicating QUIC_CONNECTION_EVENT_PEER_ADDRESS_CHANGED @@ -1598,50 +1562,6 @@ tracepoint(CLOG_CONNECTION_C, ConnRemoteAddrAdded , arg2, arg3_len, arg3);\ -/*---------------------------------------------------------- -// Decoder Ring for ConnDestCidAdded -// [conn][%p] (SeqNum=%llu) New Destination CID: %!CID! -// QuicTraceEvent( - ConnDestCidAdded, - "[conn][%p] (SeqNum=%llu) New Destination CID: %!CID!", - Connection, - Path->DestCid->CID.SequenceNumber, - CASTED_CLOG_BYTEARRAY(Path->DestCid->CID.Length, Path->DestCid->CID.Data)); -// arg2 = arg2 = Connection = arg2 -// arg3 = arg3 = Path->DestCid->CID.SequenceNumber = arg3 -// arg4 = arg4 = CASTED_CLOG_BYTEARRAY(Path->DestCid->CID.Length, Path->DestCid->CID.Data) = arg4 -----------------------------------------------------------*/ -#ifndef _clog_6_ARGS_TRACE_ConnDestCidAdded -#define _clog_6_ARGS_TRACE_ConnDestCidAdded(uniqueId, encoded_arg_string, arg2, arg3, arg4, arg4_len)\ -tracepoint(CLOG_CONNECTION_C, ConnDestCidAdded , arg2, arg3, arg4_len, arg4);\ - -#endif - - - - -/*---------------------------------------------------------- -// Decoder Ring for ConnSourceCidAdded -// [conn][%p] (SeqNum=%llu) New Source CID: %!CID! -// QuicTraceEvent( - ConnSourceCidAdded, - "[conn][%p] (SeqNum=%llu) New Source CID: %!CID!", - Connection, - SourceCid->CID.SequenceNumber, - CASTED_CLOG_BYTEARRAY(SourceCid->CID.Length, SourceCid->CID.Data)); -// arg2 = arg2 = Connection = arg2 -// arg3 = arg3 = SourceCid->CID.SequenceNumber = arg3 -// arg4 = arg4 = CASTED_CLOG_BYTEARRAY(SourceCid->CID.Length, SourceCid->CID.Data) = arg4 -----------------------------------------------------------*/ -#ifndef _clog_6_ARGS_TRACE_ConnSourceCidAdded -#define _clog_6_ARGS_TRACE_ConnSourceCidAdded(uniqueId, encoded_arg_string, arg2, arg3, arg4, arg4_len)\ -tracepoint(CLOG_CONNECTION_C, ConnSourceCidAdded , arg2, arg3, arg4_len, arg4);\ - -#endif - - - - /*---------------------------------------------------------- // Decoder Ring for ConnInitializeComplete // [conn][%p] Initialize complete @@ -1836,48 +1756,6 @@ tracepoint(CLOG_CONNECTION_C, ConnHandshakeComplete , arg2);\ -/*---------------------------------------------------------- -// Decoder Ring for ConnError -// [conn][%p] ERROR, %s. -// QuicTraceEvent( - ConnError, - "[conn][%p] ERROR, %s.", - Connection, - "Too many CID collisions"); -// arg2 = arg2 = Connection = arg2 -// arg3 = arg3 = "Too many CID collisions" = arg3 -----------------------------------------------------------*/ -#ifndef _clog_4_ARGS_TRACE_ConnError -#define _clog_4_ARGS_TRACE_ConnError(uniqueId, encoded_arg_string, arg2, arg3)\ -tracepoint(CLOG_CONNECTION_C, ConnError , arg2, arg3);\ - -#endif - - - - -/*---------------------------------------------------------- -// Decoder Ring for ConnDestCidRemoved -// [conn][%p] (SeqNum=%llu) Removed Destination CID: %!CID! -// QuicTraceEvent( - ConnDestCidRemoved, - "[conn][%p] (SeqNum=%llu) Removed Destination CID: %!CID!", - Connection, - DestCid->CID.SequenceNumber, - CASTED_CLOG_BYTEARRAY(DestCid->CID.Length, DestCid->CID.Data)); -// arg2 = arg2 = Connection = arg2 -// arg3 = arg3 = DestCid->CID.SequenceNumber = arg3 -// arg4 = arg4 = CASTED_CLOG_BYTEARRAY(DestCid->CID.Length, DestCid->CID.Data) = arg4 -----------------------------------------------------------*/ -#ifndef _clog_6_ARGS_TRACE_ConnDestCidRemoved -#define _clog_6_ARGS_TRACE_ConnDestCidRemoved(uniqueId, encoded_arg_string, arg2, arg3, arg4, arg4_len)\ -tracepoint(CLOG_CONNECTION_C, ConnDestCidRemoved , arg2, arg3, arg4_len, arg4);\ - -#endif - - - - /*---------------------------------------------------------- // Decoder Ring for ConnSetTimer // [conn][%p] Setting %hhu, delay=%llu us @@ -2027,6 +1905,26 @@ tracepoint(CLOG_CONNECTION_C, ConnErrorStatus , arg2, arg3, arg4);\ +/*---------------------------------------------------------- +// Decoder Ring for ConnError +// [conn][%p] ERROR, %s. +// QuicTraceEvent( + ConnError, + "[conn][%p] ERROR, %s.", + Connection, + "Invalid wildcard remote address in connection start"); +// arg2 = arg2 = Connection = arg2 +// arg3 = arg3 = "Invalid wildcard remote address in connection start" = arg3 +----------------------------------------------------------*/ +#ifndef _clog_4_ARGS_TRACE_ConnError +#define _clog_4_ARGS_TRACE_ConnError(uniqueId, encoded_arg_string, arg2, arg3)\ +tracepoint(CLOG_CONNECTION_C, ConnError , arg2, arg3);\ + +#endif + + + + /*---------------------------------------------------------- // Decoder Ring for ConnServerResumeTicket // [conn][%p] Server app accepted resumption ticket diff --git a/src/generated/linux/connection.c.clog.h.lttng.h b/src/generated/linux/connection.c.clog.h.lttng.h index 8cef04d1cc..b671703563 100644 --- a/src/generated/linux/connection.c.clog.h.lttng.h +++ b/src/generated/linux/connection.c.clog.h.lttng.h @@ -5,9 +5,9 @@ // Decoder Ring for PacketRxStatelessReset // [S][RX][-] SR %s // QuicTraceLogVerbose( - PacketRxStatelessReset, - "[S][RX][-] SR %s", - QuicCidBufToStr(PacketResetToken, QUIC_STATELESS_RESET_TOKEN_LENGTH).Buffer); + PacketRxStatelessReset, + "[S][RX][-] SR %s", + QuicCidBufToStr(PacketResetToken, QUIC_STATELESS_RESET_TOKEN_LENGTH).Buffer); // arg2 = arg2 = QuicCidBufToStr(PacketResetToken, QUIC_STATELESS_RESET_TOKEN_LENGTH).Buffer = arg2 ----------------------------------------------------------*/ TRACEPOINT_EVENT(CLOG_CONNECTION_C, PacketRxStatelessReset, @@ -323,44 +323,6 @@ TRACEPOINT_EVENT(CLOG_CONNECTION_C, ApiEventNoHandler, -/*---------------------------------------------------------- -// Decoder Ring for NoReplacementCidForRetire -// [conn][%p] Can't retire current CID because we don't have a replacement -// QuicTraceLogConnWarning( - NoReplacementCidForRetire, - Connection, - "Can't retire current CID because we don't have a replacement"); -// arg1 = arg1 = Connection = arg1 -----------------------------------------------------------*/ -TRACEPOINT_EVENT(CLOG_CONNECTION_C, NoReplacementCidForRetire, - TP_ARGS( - const void *, arg1), - TP_FIELDS( - ctf_integer_hex(uint64_t, arg1, (uint64_t)arg1) - ) -) - - - -/*---------------------------------------------------------- -// Decoder Ring for NonActivePathCidRetired -// [conn][%p] Non-active path has no replacement for retired CID. -// QuicTraceLogConnWarning( - NonActivePathCidRetired, - Connection, - "Non-active path has no replacement for retired CID."); -// arg1 = arg1 = Connection = arg1 -----------------------------------------------------------*/ -TRACEPOINT_EVENT(CLOG_CONNECTION_C, NonActivePathCidRetired, - TP_ARGS( - const void *, arg1), - TP_FIELDS( - ctf_integer_hex(uint64_t, arg1, (uint64_t)arg1) - ) -) - - - /*---------------------------------------------------------- // Decoder Ring for IgnoreUnreachable // [conn][%p] Ignoring received unreachable event (inline) @@ -635,9 +597,9 @@ TRACEPOINT_EVENT(CLOG_CONNECTION_C, CustomCertValidationPending, // Decoder Ring for RecvStatelessReset // [conn][%p] Received stateless reset // QuicTraceLogConnInfo( - RecvStatelessReset, - Connection, - "Received stateless reset"); + RecvStatelessReset, + Connection, + "Received stateless reset"); // arg1 = arg1 = Connection = arg1 ----------------------------------------------------------*/ TRACEPOINT_EVENT(CLOG_CONNECTION_C, RecvStatelessReset, @@ -719,10 +681,10 @@ TRACEPOINT_EVENT(CLOG_CONNECTION_C, FirstCidUsage, // Decoder Ring for PathDiscarded // [conn][%p] Removing invalid path[%hhu] // QuicTraceLogConnInfo( - PathDiscarded, - Connection, - "Removing invalid path[%hhu]", - Connection->Paths[i].ID); + PathDiscarded, + Connection, + "Removing invalid path[%hhu]", + Connection->Paths[i].ID); // arg1 = arg1 = Connection = arg1 // arg3 = arg3 = Connection->Paths[i].ID = arg3 ----------------------------------------------------------*/ @@ -981,44 +943,6 @@ TRACEPOINT_EVENT(CLOG_CONNECTION_C, RttUpdatedV2, -/*---------------------------------------------------------- -// Decoder Ring for NewSrcCidNameCollision -// [conn][%p] CID collision, trying again -// QuicTraceLogConnVerbose( - NewSrcCidNameCollision, - Connection, - "CID collision, trying again"); -// arg1 = arg1 = Connection = arg1 -----------------------------------------------------------*/ -TRACEPOINT_EVENT(CLOG_CONNECTION_C, NewSrcCidNameCollision, - TP_ARGS( - const void *, arg1), - TP_FIELDS( - ctf_integer_hex(uint64_t, arg1, (uint64_t)arg1) - ) -) - - - -/*---------------------------------------------------------- -// Decoder Ring for ZeroLengthCidRetire -// [conn][%p] Can't retire current CID because it's zero length -// QuicTraceLogConnVerbose( - ZeroLengthCidRetire, - Connection, - "Can't retire current CID because it's zero length"); -// arg1 = arg1 = Connection = arg1 -----------------------------------------------------------*/ -TRACEPOINT_EVENT(CLOG_CONNECTION_C, ZeroLengthCidRetire, - TP_ARGS( - const void *, arg1), - TP_FIELDS( - ctf_integer_hex(uint64_t, arg1, (uint64_t)arg1) - ) -) - - - /*---------------------------------------------------------- // Decoder Ring for IndicateShutdownByPeer // [conn][%p] Indicating QUIC_CONNECTION_EVENT_SHUTDOWN_INITIATED_BY_PEER [0x%llx] @@ -1503,6 +1427,44 @@ TRACEPOINT_EVENT(CLOG_CONNECTION_C, IndicatePeerNeedStreamsV2, +/*---------------------------------------------------------- +// Decoder Ring for IndicatePathAdded +// [conn][%p] Indicating QUIC_CONNECTION_EVENT_PATH_ADDED +// QuicTraceLogConnVerbose( + IndicatePathAdded, + Connection, + "Indicating QUIC_CONNECTION_EVENT_PATH_ADDED"); +// arg1 = arg1 = Connection = arg1 +----------------------------------------------------------*/ +TRACEPOINT_EVENT(CLOG_CONNECTION_C, IndicatePathAdded, + TP_ARGS( + const void *, arg1), + TP_FIELDS( + ctf_integer_hex(uint64_t, arg1, (uint64_t)arg1) + ) +) + + + +/*---------------------------------------------------------- +// Decoder Ring for IndicatePathStatusChanged +// [conn][%p] Indicating QUIC_CONNECTION_EVENT_PATH_STATUS_CHANGED +// QuicTraceLogConnVerbose( + IndicatePathStatusChanged, + Connection, + "Indicating QUIC_CONNECTION_EVENT_PATH_STATUS_CHANGED"); +// arg1 = arg1 = Connection = arg1 +----------------------------------------------------------*/ +TRACEPOINT_EVENT(CLOG_CONNECTION_C, IndicatePathStatusChanged, + TP_ARGS( + const void *, arg1), + TP_FIELDS( + ctf_integer_hex(uint64_t, arg1, (uint64_t)arg1) + ) +) + + + /*---------------------------------------------------------- // Decoder Ring for IndicatePeerAddrChanged // [conn][%p] Indicating QUIC_CONNECTION_EVENT_PEER_ADDRESS_CHANGED @@ -1779,64 +1741,6 @@ TRACEPOINT_EVENT(CLOG_CONNECTION_C, ConnRemoteAddrAdded, -/*---------------------------------------------------------- -// Decoder Ring for ConnDestCidAdded -// [conn][%p] (SeqNum=%llu) New Destination CID: %!CID! -// QuicTraceEvent( - ConnDestCidAdded, - "[conn][%p] (SeqNum=%llu) New Destination CID: %!CID!", - Connection, - Path->DestCid->CID.SequenceNumber, - CASTED_CLOG_BYTEARRAY(Path->DestCid->CID.Length, Path->DestCid->CID.Data)); -// arg2 = arg2 = Connection = arg2 -// arg3 = arg3 = Path->DestCid->CID.SequenceNumber = arg3 -// arg4 = arg4 = CASTED_CLOG_BYTEARRAY(Path->DestCid->CID.Length, Path->DestCid->CID.Data) = arg4 -----------------------------------------------------------*/ -TRACEPOINT_EVENT(CLOG_CONNECTION_C, ConnDestCidAdded, - TP_ARGS( - const void *, arg2, - unsigned long long, arg3, - unsigned int, arg4_len, - const void *, arg4), - TP_FIELDS( - ctf_integer_hex(uint64_t, arg2, (uint64_t)arg2) - ctf_integer(uint64_t, arg3, arg3) - ctf_integer(unsigned int, arg4_len, arg4_len) - ctf_sequence(char, arg4, arg4, unsigned int, arg4_len) - ) -) - - - -/*---------------------------------------------------------- -// Decoder Ring for ConnSourceCidAdded -// [conn][%p] (SeqNum=%llu) New Source CID: %!CID! -// QuicTraceEvent( - ConnSourceCidAdded, - "[conn][%p] (SeqNum=%llu) New Source CID: %!CID!", - Connection, - SourceCid->CID.SequenceNumber, - CASTED_CLOG_BYTEARRAY(SourceCid->CID.Length, SourceCid->CID.Data)); -// arg2 = arg2 = Connection = arg2 -// arg3 = arg3 = SourceCid->CID.SequenceNumber = arg3 -// arg4 = arg4 = CASTED_CLOG_BYTEARRAY(SourceCid->CID.Length, SourceCid->CID.Data) = arg4 -----------------------------------------------------------*/ -TRACEPOINT_EVENT(CLOG_CONNECTION_C, ConnSourceCidAdded, - TP_ARGS( - const void *, arg2, - unsigned long long, arg3, - unsigned int, arg4_len, - const void *, arg4), - TP_FIELDS( - ctf_integer_hex(uint64_t, arg2, (uint64_t)arg2) - ctf_integer(uint64_t, arg3, arg3) - ctf_integer(unsigned int, arg4_len, arg4_len) - ctf_sequence(char, arg4, arg4, unsigned int, arg4_len) - ) -) - - - /*---------------------------------------------------------- // Decoder Ring for ConnInitializeComplete // [conn][%p] Initialize complete @@ -2055,58 +1959,6 @@ TRACEPOINT_EVENT(CLOG_CONNECTION_C, ConnHandshakeComplete, -/*---------------------------------------------------------- -// Decoder Ring for ConnError -// [conn][%p] ERROR, %s. -// QuicTraceEvent( - ConnError, - "[conn][%p] ERROR, %s.", - Connection, - "Too many CID collisions"); -// arg2 = arg2 = Connection = arg2 -// arg3 = arg3 = "Too many CID collisions" = arg3 -----------------------------------------------------------*/ -TRACEPOINT_EVENT(CLOG_CONNECTION_C, ConnError, - TP_ARGS( - const void *, arg2, - const char *, arg3), - TP_FIELDS( - ctf_integer_hex(uint64_t, arg2, (uint64_t)arg2) - ctf_string(arg3, arg3) - ) -) - - - -/*---------------------------------------------------------- -// Decoder Ring for ConnDestCidRemoved -// [conn][%p] (SeqNum=%llu) Removed Destination CID: %!CID! -// QuicTraceEvent( - ConnDestCidRemoved, - "[conn][%p] (SeqNum=%llu) Removed Destination CID: %!CID!", - Connection, - DestCid->CID.SequenceNumber, - CASTED_CLOG_BYTEARRAY(DestCid->CID.Length, DestCid->CID.Data)); -// arg2 = arg2 = Connection = arg2 -// arg3 = arg3 = DestCid->CID.SequenceNumber = arg3 -// arg4 = arg4 = CASTED_CLOG_BYTEARRAY(DestCid->CID.Length, DestCid->CID.Data) = arg4 -----------------------------------------------------------*/ -TRACEPOINT_EVENT(CLOG_CONNECTION_C, ConnDestCidRemoved, - TP_ARGS( - const void *, arg2, - unsigned long long, arg3, - unsigned int, arg4_len, - const void *, arg4), - TP_FIELDS( - ctf_integer_hex(uint64_t, arg2, (uint64_t)arg2) - ctf_integer(uint64_t, arg3, arg3) - ctf_integer(unsigned int, arg4_len, arg4_len) - ctf_sequence(char, arg4, arg4, unsigned int, arg4_len) - ) -) - - - /*---------------------------------------------------------- // Decoder Ring for ConnSetTimer // [conn][%p] Setting %hhu, delay=%llu us @@ -2287,6 +2139,29 @@ TRACEPOINT_EVENT(CLOG_CONNECTION_C, ConnErrorStatus, +/*---------------------------------------------------------- +// Decoder Ring for ConnError +// [conn][%p] ERROR, %s. +// QuicTraceEvent( + ConnError, + "[conn][%p] ERROR, %s.", + Connection, + "Invalid wildcard remote address in connection start"); +// arg2 = arg2 = Connection = arg2 +// arg3 = arg3 = "Invalid wildcard remote address in connection start" = arg3 +----------------------------------------------------------*/ +TRACEPOINT_EVENT(CLOG_CONNECTION_C, ConnError, + TP_ARGS( + const void *, arg2, + const char *, arg3), + TP_FIELDS( + ctf_integer_hex(uint64_t, arg2, (uint64_t)arg2) + ctf_string(arg3, arg3) + ) +) + + + /*---------------------------------------------------------- // Decoder Ring for ConnServerResumeTicket // [conn][%p] Server app accepted resumption ticket diff --git a/src/generated/linux/connection.h.clog.h b/src/generated/linux/connection.h.clog.h index 3f2bdc5c6c..d82e88736b 100644 --- a/src/generated/linux/connection.h.clog.h +++ b/src/generated/linux/connection.h.clog.h @@ -27,10 +27,10 @@ extern "C" { // QuicTraceEvent( ConnOutFlowStreamStats, "[conn][%p] OUT: StreamFC=%llu StreamSendWindow=%llu", - Connection, + PathID->Connection, FcAvailable, SendWindow); -// arg2 = arg2 = Connection = arg2 +// arg2 = arg2 = PathID->Connection = arg2 // arg3 = arg3 = FcAvailable = arg3 // arg4 = arg4 = SendWindow = arg4 ----------------------------------------------------------*/ @@ -75,8 +75,8 @@ tracepoint(CLOG_CONNECTION_H, ConnInFlowStats , arg2, arg3);\ Connection->Stats.Send.PersistentCongestionCount, Connection->Stats.Send.TotalBytes, Connection->Stats.Recv.TotalBytes, - QuicCongestionControlGetCongestionWindow(&Connection->CongestionControl), - Connection->CongestionControl.Name, + QuicCongestionControlGetCongestionWindow(&Path->PathID->CongestionControl), + Path->PathID->CongestionControl.Name, Connection->Stats.Send.EcnCongestionCount); // arg2 = arg2 = Connection = arg2 // arg3 = arg3 = Path->SmoothedRtt = arg3 @@ -84,8 +84,8 @@ tracepoint(CLOG_CONNECTION_H, ConnInFlowStats , arg2, arg3);\ // arg5 = arg5 = Connection->Stats.Send.PersistentCongestionCount = arg5 // arg6 = arg6 = Connection->Stats.Send.TotalBytes = arg6 // arg7 = arg7 = Connection->Stats.Recv.TotalBytes = arg7 -// arg8 = arg8 = QuicCongestionControlGetCongestionWindow(&Connection->CongestionControl) = arg8 -// arg9 = arg9 = Connection->CongestionControl.Name = arg9 +// arg8 = arg8 = QuicCongestionControlGetCongestionWindow(&Path->PathID->CongestionControl) = arg8 +// arg9 = arg9 = Path->PathID->CongestionControl.Name = arg9 // arg10 = arg10 = Connection->Stats.Send.EcnCongestionCount = arg10 ----------------------------------------------------------*/ #ifndef _clog_11_ARGS_TRACE_ConnStatsV3 @@ -151,28 +151,6 @@ tracepoint(CLOG_CONNECTION_H, ConnOutFlowBlocked , arg2, arg3);\ -/*---------------------------------------------------------- -// Decoder Ring for ConnSourceCidRemoved -// [conn][%p] (SeqNum=%llu) Removed Source CID: %!CID! -// QuicTraceEvent( - ConnSourceCidRemoved, - "[conn][%p] (SeqNum=%llu) Removed Source CID: %!CID!", - Connection, - SourceCid->CID.SequenceNumber, - CASTED_CLOG_BYTEARRAY(SourceCid->CID.Length, SourceCid->CID.Data)); -// arg2 = arg2 = Connection = arg2 -// arg3 = arg3 = SourceCid->CID.SequenceNumber = arg3 -// arg4 = arg4 = CASTED_CLOG_BYTEARRAY(SourceCid->CID.Length, SourceCid->CID.Data) = arg4 -----------------------------------------------------------*/ -#ifndef _clog_6_ARGS_TRACE_ConnSourceCidRemoved -#define _clog_6_ARGS_TRACE_ConnSourceCidRemoved(uniqueId, encoded_arg_string, arg2, arg3, arg4, arg4_len)\ -tracepoint(CLOG_CONNECTION_H, ConnSourceCidRemoved , arg2, arg3, arg4_len, arg4);\ - -#endif - - - - #ifdef __cplusplus } #endif diff --git a/src/generated/linux/connection.h.clog.h.lttng.h b/src/generated/linux/connection.h.clog.h.lttng.h index 0b51042d75..ff5f578c25 100644 --- a/src/generated/linux/connection.h.clog.h.lttng.h +++ b/src/generated/linux/connection.h.clog.h.lttng.h @@ -7,10 +7,10 @@ // QuicTraceEvent( ConnOutFlowStreamStats, "[conn][%p] OUT: StreamFC=%llu StreamSendWindow=%llu", - Connection, + PathID->Connection, FcAvailable, SendWindow); -// arg2 = arg2 = Connection = arg2 +// arg2 = arg2 = PathID->Connection = arg2 // arg3 = arg3 = FcAvailable = arg3 // arg4 = arg4 = SendWindow = arg4 ----------------------------------------------------------*/ @@ -63,8 +63,8 @@ TRACEPOINT_EVENT(CLOG_CONNECTION_H, ConnInFlowStats, Connection->Stats.Send.PersistentCongestionCount, Connection->Stats.Send.TotalBytes, Connection->Stats.Recv.TotalBytes, - QuicCongestionControlGetCongestionWindow(&Connection->CongestionControl), - Connection->CongestionControl.Name, + QuicCongestionControlGetCongestionWindow(&Path->PathID->CongestionControl), + Path->PathID->CongestionControl.Name, Connection->Stats.Send.EcnCongestionCount); // arg2 = arg2 = Connection = arg2 // arg3 = arg3 = Path->SmoothedRtt = arg3 @@ -72,8 +72,8 @@ TRACEPOINT_EVENT(CLOG_CONNECTION_H, ConnInFlowStats, // arg5 = arg5 = Connection->Stats.Send.PersistentCongestionCount = arg5 // arg6 = arg6 = Connection->Stats.Send.TotalBytes = arg6 // arg7 = arg7 = Connection->Stats.Recv.TotalBytes = arg7 -// arg8 = arg8 = QuicCongestionControlGetCongestionWindow(&Connection->CongestionControl) = arg8 -// arg9 = arg9 = Connection->CongestionControl.Name = arg9 +// arg8 = arg8 = QuicCongestionControlGetCongestionWindow(&Path->PathID->CongestionControl) = arg8 +// arg9 = arg9 = Path->PathID->CongestionControl.Name = arg9 // arg10 = arg10 = Connection->Stats.Send.EcnCongestionCount = arg10 ----------------------------------------------------------*/ TRACEPOINT_EVENT(CLOG_CONNECTION_H, ConnStatsV3, @@ -173,32 +173,3 @@ TRACEPOINT_EVENT(CLOG_CONNECTION_H, ConnOutFlowBlocked, ctf_integer(unsigned char, arg3, arg3) ) ) - - - -/*---------------------------------------------------------- -// Decoder Ring for ConnSourceCidRemoved -// [conn][%p] (SeqNum=%llu) Removed Source CID: %!CID! -// QuicTraceEvent( - ConnSourceCidRemoved, - "[conn][%p] (SeqNum=%llu) Removed Source CID: %!CID!", - Connection, - SourceCid->CID.SequenceNumber, - CASTED_CLOG_BYTEARRAY(SourceCid->CID.Length, SourceCid->CID.Data)); -// arg2 = arg2 = Connection = arg2 -// arg3 = arg3 = SourceCid->CID.SequenceNumber = arg3 -// arg4 = arg4 = CASTED_CLOG_BYTEARRAY(SourceCid->CID.Length, SourceCid->CID.Data) = arg4 -----------------------------------------------------------*/ -TRACEPOINT_EVENT(CLOG_CONNECTION_H, ConnSourceCidRemoved, - TP_ARGS( - const void *, arg2, - unsigned long long, arg3, - unsigned int, arg4_len, - const void *, arg4), - TP_FIELDS( - ctf_integer_hex(uint64_t, arg2, (uint64_t)arg2) - ctf_integer(uint64_t, arg3, arg3) - ctf_integer(unsigned int, arg4_len, arg4_len) - ctf_sequence(char, arg4, arg4, unsigned int, arg4_len) - ) -) diff --git a/src/generated/linux/crypto.c.clog.h b/src/generated/linux/crypto.c.clog.h index 4cf58e75a6..b98a9d6231 100644 --- a/src/generated/linux/crypto.c.clog.h +++ b/src/generated/linux/crypto.c.clog.h @@ -505,20 +505,22 @@ tracepoint(CLOG_CRYPTO_C, ConnHandshakeComplete , arg2);\ /*---------------------------------------------------------- // Decoder Ring for ConnSourceCidRemoved -// [conn][%p] (SeqNum=%llu) Removed Source CID: %!CID! +// [conn][%p][pathid][%u] (SeqNum=%llu) Removed Source CID: %!CID! // QuicTraceEvent( ConnSourceCidRemoved, - "[conn][%p] (SeqNum=%llu) Removed Source CID: %!CID!", + "[conn][%p][pathid][%u] (SeqNum=%llu) Removed Source CID: %!CID!", Connection, + Connection->Paths[0].PathID->ID, InitialSourceCid->CID.SequenceNumber, CASTED_CLOG_BYTEARRAY(InitialSourceCid->CID.Length, InitialSourceCid->CID.Data)); // arg2 = arg2 = Connection = arg2 -// arg3 = arg3 = InitialSourceCid->CID.SequenceNumber = arg3 -// arg4 = arg4 = CASTED_CLOG_BYTEARRAY(InitialSourceCid->CID.Length, InitialSourceCid->CID.Data) = arg4 +// arg3 = arg3 = Connection->Paths[0].PathID->ID = arg3 +// arg4 = arg4 = InitialSourceCid->CID.SequenceNumber = arg4 +// arg5 = arg5 = CASTED_CLOG_BYTEARRAY(InitialSourceCid->CID.Length, InitialSourceCid->CID.Data) = arg5 ----------------------------------------------------------*/ -#ifndef _clog_6_ARGS_TRACE_ConnSourceCidRemoved -#define _clog_6_ARGS_TRACE_ConnSourceCidRemoved(uniqueId, encoded_arg_string, arg2, arg3, arg4, arg4_len)\ -tracepoint(CLOG_CRYPTO_C, ConnSourceCidRemoved , arg2, arg3, arg4_len, arg4);\ +#ifndef _clog_7_ARGS_TRACE_ConnSourceCidRemoved +#define _clog_7_ARGS_TRACE_ConnSourceCidRemoved(uniqueId, encoded_arg_string, arg2, arg3, arg4, arg5, arg5_len)\ +tracepoint(CLOG_CRYPTO_C, ConnSourceCidRemoved , arg2, arg3, arg4, arg5_len, arg5);\ #endif diff --git a/src/generated/linux/crypto.c.clog.h.lttng.h b/src/generated/linux/crypto.c.clog.h.lttng.h index ba3b860ff8..1ba79b3c2b 100644 --- a/src/generated/linux/crypto.c.clog.h.lttng.h +++ b/src/generated/linux/crypto.c.clog.h.lttng.h @@ -552,28 +552,32 @@ TRACEPOINT_EVENT(CLOG_CRYPTO_C, ConnHandshakeComplete, /*---------------------------------------------------------- // Decoder Ring for ConnSourceCidRemoved -// [conn][%p] (SeqNum=%llu) Removed Source CID: %!CID! +// [conn][%p][pathid][%u] (SeqNum=%llu) Removed Source CID: %!CID! // QuicTraceEvent( ConnSourceCidRemoved, - "[conn][%p] (SeqNum=%llu) Removed Source CID: %!CID!", + "[conn][%p][pathid][%u] (SeqNum=%llu) Removed Source CID: %!CID!", Connection, + Connection->Paths[0].PathID->ID, InitialSourceCid->CID.SequenceNumber, CASTED_CLOG_BYTEARRAY(InitialSourceCid->CID.Length, InitialSourceCid->CID.Data)); // arg2 = arg2 = Connection = arg2 -// arg3 = arg3 = InitialSourceCid->CID.SequenceNumber = arg3 -// arg4 = arg4 = CASTED_CLOG_BYTEARRAY(InitialSourceCid->CID.Length, InitialSourceCid->CID.Data) = arg4 +// arg3 = arg3 = Connection->Paths[0].PathID->ID = arg3 +// arg4 = arg4 = InitialSourceCid->CID.SequenceNumber = arg4 +// arg5 = arg5 = CASTED_CLOG_BYTEARRAY(InitialSourceCid->CID.Length, InitialSourceCid->CID.Data) = arg5 ----------------------------------------------------------*/ TRACEPOINT_EVENT(CLOG_CRYPTO_C, ConnSourceCidRemoved, TP_ARGS( const void *, arg2, - unsigned long long, arg3, - unsigned int, arg4_len, - const void *, arg4), + unsigned int, arg3, + unsigned long long, arg4, + unsigned int, arg5_len, + const void *, arg5), TP_FIELDS( ctf_integer_hex(uint64_t, arg2, (uint64_t)arg2) - ctf_integer(uint64_t, arg3, arg3) - ctf_integer(unsigned int, arg4_len, arg4_len) - ctf_sequence(char, arg4, arg4, unsigned int, arg4_len) + ctf_integer(unsigned int, arg3, arg3) + ctf_integer(uint64_t, arg4, arg4) + ctf_integer(unsigned int, arg5_len, arg5_len) + ctf_sequence(char, arg5, arg5, unsigned int, arg5_len) ) ) diff --git a/src/generated/linux/crypto_tls.c.clog.h b/src/generated/linux/crypto_tls.c.clog.h index 21242b0576..cfcb0ea347 100644 --- a/src/generated/linux/crypto_tls.c.clog.h +++ b/src/generated/linux/crypto_tls.c.clog.h @@ -619,6 +619,26 @@ tracepoint(CLOG_CRYPTO_TLS_C, EncodeTPTimestamp , arg1, arg3);\ +/*---------------------------------------------------------- +// Decoder Ring for EncodeTPInitMaxPathId +// [conn][%p] TP: Max Path Id (%llu) +// QuicTraceLogConnVerbose( + EncodeTPInitMaxPathId, + Connection, + "TP: Max Path Id (%llu)", + TransportParams->InitialMaxPathId); +// arg1 = arg1 = Connection = arg1 +// arg3 = arg3 = TransportParams->InitialMaxPathId = arg3 +----------------------------------------------------------*/ +#ifndef _clog_4_ARGS_TRACE_EncodeTPInitMaxPathId +#define _clog_4_ARGS_TRACE_EncodeTPInitMaxPathId(uniqueId, arg1, encoded_arg_string, arg3)\ +tracepoint(CLOG_CRYPTO_TLS_C, EncodeTPInitMaxPathId , arg1, arg3);\ + +#endif + + + + /*---------------------------------------------------------- // Decoder Ring for EncodeTPTest // [conn][%p] TP: TEST TP (Type %hu, Length %hu) @@ -1171,6 +1191,26 @@ tracepoint(CLOG_CRYPTO_TLS_C, DecodeTPReliableReset , arg1);\ +/*---------------------------------------------------------- +// Decoder Ring for DecodeTPInitMaxPathId +// [conn][%p] TP: Max Path Id (%llu) +// QuicTraceLogConnVerbose( + DecodeTPInitMaxPathId, + Connection, + "TP: Max Path Id (%llu)", + TransportParams->InitialMaxPathId); +// arg1 = arg1 = Connection = arg1 +// arg3 = arg3 = TransportParams->InitialMaxPathId = arg3 +----------------------------------------------------------*/ +#ifndef _clog_4_ARGS_TRACE_DecodeTPInitMaxPathId +#define _clog_4_ARGS_TRACE_DecodeTPInitMaxPathId(uniqueId, arg1, encoded_arg_string, arg3)\ +tracepoint(CLOG_CRYPTO_TLS_C, DecodeTPInitMaxPathId , arg1, arg3);\ + +#endif + + + + /*---------------------------------------------------------- // Decoder Ring for ConnError // [conn][%p] ERROR, %s. diff --git a/src/generated/linux/crypto_tls.c.clog.h.lttng.h b/src/generated/linux/crypto_tls.c.clog.h.lttng.h index 06eb22974f..76faa1a790 100644 --- a/src/generated/linux/crypto_tls.c.clog.h.lttng.h +++ b/src/generated/linux/crypto_tls.c.clog.h.lttng.h @@ -672,6 +672,29 @@ TRACEPOINT_EVENT(CLOG_CRYPTO_TLS_C, EncodeTPTimestamp, +/*---------------------------------------------------------- +// Decoder Ring for EncodeTPInitMaxPathId +// [conn][%p] TP: Max Path Id (%llu) +// QuicTraceLogConnVerbose( + EncodeTPInitMaxPathId, + Connection, + "TP: Max Path Id (%llu)", + TransportParams->InitialMaxPathId); +// arg1 = arg1 = Connection = arg1 +// arg3 = arg3 = TransportParams->InitialMaxPathId = arg3 +----------------------------------------------------------*/ +TRACEPOINT_EVENT(CLOG_CRYPTO_TLS_C, EncodeTPInitMaxPathId, + TP_ARGS( + const void *, arg1, + unsigned long long, arg3), + TP_FIELDS( + ctf_integer_hex(uint64_t, arg1, (uint64_t)arg1) + ctf_integer(uint64_t, arg3, arg3) + ) +) + + + /*---------------------------------------------------------- // Decoder Ring for EncodeTPTest // [conn][%p] TP: TEST TP (Type %hu, Length %hu) @@ -1301,6 +1324,29 @@ TRACEPOINT_EVENT(CLOG_CRYPTO_TLS_C, DecodeTPReliableReset, +/*---------------------------------------------------------- +// Decoder Ring for DecodeTPInitMaxPathId +// [conn][%p] TP: Max Path Id (%llu) +// QuicTraceLogConnVerbose( + DecodeTPInitMaxPathId, + Connection, + "TP: Max Path Id (%llu)", + TransportParams->InitialMaxPathId); +// arg1 = arg1 = Connection = arg1 +// arg3 = arg3 = TransportParams->InitialMaxPathId = arg3 +----------------------------------------------------------*/ +TRACEPOINT_EVENT(CLOG_CRYPTO_TLS_C, DecodeTPInitMaxPathId, + TP_ARGS( + const void *, arg1, + unsigned long long, arg3), + TP_FIELDS( + ctf_integer_hex(uint64_t, arg1, (uint64_t)arg1) + ctf_integer(uint64_t, arg3, arg3) + ) +) + + + /*---------------------------------------------------------- // Decoder Ring for ConnError // [conn][%p] ERROR, %s. diff --git a/src/generated/linux/cubic.c.clog.h b/src/generated/linux/cubic.c.clog.h index 94ce95bbbe..4d643d7ff2 100644 --- a/src/generated/linux/cubic.c.clog.h +++ b/src/generated/linux/cubic.c.clog.h @@ -30,7 +30,7 @@ extern "C" { // [conn][%p] Indicating QUIC_CONNECTION_EVENT_NETWORK_STATISTICS [BytesInFlight=%u,PostedBytes=%llu,IdealBytes=%llu,SmoothedRTT=%llu,CongestionWindow=%u,Bandwidth=%llu] // QuicTraceLogConnVerbose( IndicateDataAcked, - Connection, + PathID->Connection, "Indicating QUIC_CONNECTION_EVENT_NETWORK_STATISTICS [BytesInFlight=%u,PostedBytes=%llu,IdealBytes=%llu,SmoothedRTT=%llu,CongestionWindow=%u,Bandwidth=%llu]", Event.NETWORK_STATISTICS.BytesInFlight, Event.NETWORK_STATISTICS.PostedBytes, @@ -38,7 +38,7 @@ extern "C" { Event.NETWORK_STATISTICS.SmoothedRTT, Event.NETWORK_STATISTICS.CongestionWindow, Event.NETWORK_STATISTICS.Bandwidth); -// arg1 = arg1 = Connection = arg1 +// arg1 = arg1 = PathID->Connection = arg1 // arg3 = arg3 = Event.NETWORK_STATISTICS.BytesInFlight = arg3 // arg4 = arg4 = Event.NETWORK_STATISTICS.PostedBytes = arg4 // arg5 = arg5 = Event.NETWORK_STATISTICS.IdealBytes = arg5 @@ -61,12 +61,12 @@ tracepoint(CLOG_CUBIC_C, IndicateDataAcked , arg1, arg3, arg4, arg5, arg6, arg7, // QuicTraceEvent( ConnCubic, "[conn][%p] CUBIC: SlowStartThreshold=%u K=%u WindowMax=%u WindowLastMax=%u", - Connection, + PathID->Connection, Cubic->SlowStartThreshold, Cubic->KCubic, Cubic->WindowMax, Cubic->WindowLastMax); -// arg2 = arg2 = Connection = arg2 +// arg2 = arg2 = PathID->Connection = arg2 // arg3 = arg3 = Cubic->SlowStartThreshold = arg3 // arg4 = arg4 = Cubic->KCubic = arg4 // arg5 = arg5 = Cubic->WindowMax = arg5 @@ -149,8 +149,8 @@ tracepoint(CLOG_CUBIC_C, ConnPersistentCongestion , arg2);\ // QuicTraceEvent( ConnRecoveryExit, "[conn][%p] Recovery complete", - Connection); -// arg2 = arg2 = Connection = arg2 + PathID->Connection); +// arg2 = arg2 = PathID->Connection = arg2 ----------------------------------------------------------*/ #ifndef _clog_3_ARGS_TRACE_ConnRecoveryExit #define _clog_3_ARGS_TRACE_ConnRecoveryExit(uniqueId, encoded_arg_string, arg2)\ @@ -185,22 +185,22 @@ tracepoint(CLOG_CUBIC_C, ConnSpuriousCongestion , arg2);\ // QuicTraceEvent( ConnOutFlowStatsV2, "[conn][%p] OUT: BytesSent=%llu InFlight=%u CWnd=%u ConnFC=%llu ISB=%llu PostedBytes=%llu SRtt=%llu 1Way=%llu", - Connection, - Connection->Stats.Send.TotalBytes, + PathID->Connection, + PathID->Connection->Stats.Send.TotalBytes, Cubic->BytesInFlight, Cubic->CongestionWindow, - Connection->Send.PeerMaxData - Connection->Send.OrderedStreamBytesSent, - Connection->SendBuffer.IdealBytes, - Connection->SendBuffer.PostedBytes, + PathID->Connection->Send.PeerMaxData - PathID->Connection->Send.OrderedStreamBytesSent, + PathID->Connection->SendBuffer.IdealBytes, + PathID->Connection->SendBuffer.PostedBytes, Path->GotFirstRttSample ? Path->SmoothedRtt : 0, Path->OneWayDelay); -// arg2 = arg2 = Connection = arg2 -// arg3 = arg3 = Connection->Stats.Send.TotalBytes = arg3 +// arg2 = arg2 = PathID->Connection = arg2 +// arg3 = arg3 = PathID->Connection->Stats.Send.TotalBytes = arg3 // arg4 = arg4 = Cubic->BytesInFlight = arg4 // arg5 = arg5 = Cubic->CongestionWindow = arg5 -// arg6 = arg6 = Connection->Send.PeerMaxData - Connection->Send.OrderedStreamBytesSent = arg6 -// arg7 = arg7 = Connection->SendBuffer.IdealBytes = arg7 -// arg8 = arg8 = Connection->SendBuffer.PostedBytes = arg8 +// arg6 = arg6 = PathID->Connection->Send.PeerMaxData - PathID->Connection->Send.OrderedStreamBytesSent = arg6 +// arg7 = arg7 = PathID->Connection->SendBuffer.IdealBytes = arg7 +// arg8 = arg8 = PathID->Connection->SendBuffer.PostedBytes = arg8 // arg9 = arg9 = Path->GotFirstRttSample ? Path->SmoothedRtt : 0 = arg9 // arg10 = arg10 = Path->OneWayDelay = arg10 ----------------------------------------------------------*/ diff --git a/src/generated/linux/cubic.c.clog.h.lttng.h b/src/generated/linux/cubic.c.clog.h.lttng.h index 783c30da0e..cd36329a1e 100644 --- a/src/generated/linux/cubic.c.clog.h.lttng.h +++ b/src/generated/linux/cubic.c.clog.h.lttng.h @@ -6,7 +6,7 @@ // [conn][%p] Indicating QUIC_CONNECTION_EVENT_NETWORK_STATISTICS [BytesInFlight=%u,PostedBytes=%llu,IdealBytes=%llu,SmoothedRTT=%llu,CongestionWindow=%u,Bandwidth=%llu] // QuicTraceLogConnVerbose( IndicateDataAcked, - Connection, + PathID->Connection, "Indicating QUIC_CONNECTION_EVENT_NETWORK_STATISTICS [BytesInFlight=%u,PostedBytes=%llu,IdealBytes=%llu,SmoothedRTT=%llu,CongestionWindow=%u,Bandwidth=%llu]", Event.NETWORK_STATISTICS.BytesInFlight, Event.NETWORK_STATISTICS.PostedBytes, @@ -14,7 +14,7 @@ Event.NETWORK_STATISTICS.SmoothedRTT, Event.NETWORK_STATISTICS.CongestionWindow, Event.NETWORK_STATISTICS.Bandwidth); -// arg1 = arg1 = Connection = arg1 +// arg1 = arg1 = PathID->Connection = arg1 // arg3 = arg3 = Event.NETWORK_STATISTICS.BytesInFlight = arg3 // arg4 = arg4 = Event.NETWORK_STATISTICS.PostedBytes = arg4 // arg5 = arg5 = Event.NETWORK_STATISTICS.IdealBytes = arg5 @@ -50,12 +50,12 @@ TRACEPOINT_EVENT(CLOG_CUBIC_C, IndicateDataAcked, // QuicTraceEvent( ConnCubic, "[conn][%p] CUBIC: SlowStartThreshold=%u K=%u WindowMax=%u WindowLastMax=%u", - Connection, + PathID->Connection, Cubic->SlowStartThreshold, Cubic->KCubic, Cubic->WindowMax, Cubic->WindowLastMax); -// arg2 = arg2 = Connection = arg2 +// arg2 = arg2 = PathID->Connection = arg2 // arg3 = arg3 = Cubic->SlowStartThreshold = arg3 // arg4 = arg4 = Cubic->KCubic = arg4 // arg5 = arg5 = Cubic->WindowMax = arg5 @@ -158,8 +158,8 @@ TRACEPOINT_EVENT(CLOG_CUBIC_C, ConnPersistentCongestion, // QuicTraceEvent( ConnRecoveryExit, "[conn][%p] Recovery complete", - Connection); -// arg2 = arg2 = Connection = arg2 + PathID->Connection); +// arg2 = arg2 = PathID->Connection = arg2 ----------------------------------------------------------*/ TRACEPOINT_EVENT(CLOG_CUBIC_C, ConnRecoveryExit, TP_ARGS( @@ -196,22 +196,22 @@ TRACEPOINT_EVENT(CLOG_CUBIC_C, ConnSpuriousCongestion, // QuicTraceEvent( ConnOutFlowStatsV2, "[conn][%p] OUT: BytesSent=%llu InFlight=%u CWnd=%u ConnFC=%llu ISB=%llu PostedBytes=%llu SRtt=%llu 1Way=%llu", - Connection, - Connection->Stats.Send.TotalBytes, + PathID->Connection, + PathID->Connection->Stats.Send.TotalBytes, Cubic->BytesInFlight, Cubic->CongestionWindow, - Connection->Send.PeerMaxData - Connection->Send.OrderedStreamBytesSent, - Connection->SendBuffer.IdealBytes, - Connection->SendBuffer.PostedBytes, + PathID->Connection->Send.PeerMaxData - PathID->Connection->Send.OrderedStreamBytesSent, + PathID->Connection->SendBuffer.IdealBytes, + PathID->Connection->SendBuffer.PostedBytes, Path->GotFirstRttSample ? Path->SmoothedRtt : 0, Path->OneWayDelay); -// arg2 = arg2 = Connection = arg2 -// arg3 = arg3 = Connection->Stats.Send.TotalBytes = arg3 +// arg2 = arg2 = PathID->Connection = arg2 +// arg3 = arg3 = PathID->Connection->Stats.Send.TotalBytes = arg3 // arg4 = arg4 = Cubic->BytesInFlight = arg4 // arg5 = arg5 = Cubic->CongestionWindow = arg5 -// arg6 = arg6 = Connection->Send.PeerMaxData - Connection->Send.OrderedStreamBytesSent = arg6 -// arg7 = arg7 = Connection->SendBuffer.IdealBytes = arg7 -// arg8 = arg8 = Connection->SendBuffer.PostedBytes = arg8 +// arg6 = arg6 = PathID->Connection->Send.PeerMaxData - PathID->Connection->Send.OrderedStreamBytesSent = arg6 +// arg7 = arg7 = PathID->Connection->SendBuffer.IdealBytes = arg7 +// arg8 = arg8 = PathID->Connection->SendBuffer.PostedBytes = arg8 // arg9 = arg9 = Path->GotFirstRttSample ? Path->SmoothedRtt : 0 = arg9 // arg10 = arg10 = Path->OneWayDelay = arg10 ----------------------------------------------------------*/ diff --git a/src/generated/linux/frame.c.clog.h b/src/generated/linux/frame.c.clog.h index e8c8b30384..d825474ca0 100644 --- a/src/generated/linux/frame.c.clog.h +++ b/src/generated/linux/frame.c.clog.h @@ -99,11 +99,11 @@ tracepoint(CLOG_FRAME_C, FrameLogPing , arg2, arg3, arg4);\ // Decoder Ring for FrameLogAckInvalid // [%c][%cX][%llu] ACK [Invalid] // QuicTraceLogVerbose( - FrameLogAckInvalid, - "[%c][%cX][%llu] ACK [Invalid]", - PtkConnPre(Connection), - PktRxPre(Rx), - PacketNumber); + FrameLogAckInvalid, + "[%c][%cX][%llu] ACK [Invalid]", + PtkConnPre(Connection), + PktRxPre(Rx), + PacketNumber); // arg2 = arg2 = PtkConnPre(Connection) = arg2 // arg3 = arg3 = PktRxPre(Rx) = arg3 // arg4 = arg4 = PacketNumber = arg4 @@ -121,13 +121,13 @@ tracepoint(CLOG_FRAME_C, FrameLogAckInvalid , arg2, arg3, arg4);\ // Decoder Ring for FrameLogAck // [%c][%cX][%llu] ACK Largest:%llu Delay:%llu // QuicTraceLogVerbose( - FrameLogAck, - "[%c][%cX][%llu] ACK Largest:%llu Delay:%llu", - PtkConnPre(Connection), - PktRxPre(Rx), - PacketNumber, - Frame.LargestAcknowledged, - Frame.AckDelay); + FrameLogAck, + "[%c][%cX][%llu] ACK Largest:%llu Delay:%llu", + PtkConnPre(Connection), + PktRxPre(Rx), + PacketNumber, + Frame.LargestAcknowledged, + Frame.AckDelay); // arg2 = arg2 = PtkConnPre(Connection) = arg2 // arg3 = arg3 = PktRxPre(Rx) = arg3 // arg4 = arg4 = PacketNumber = arg4 @@ -143,6 +143,56 @@ tracepoint(CLOG_FRAME_C, FrameLogAck , arg2, arg3, arg4, arg5, arg6);\ +/*---------------------------------------------------------- +// Decoder Ring for FrameLogPathAckInvalid +// [%c][%cX][%llu] PATH_ACK [Invalid] +// QuicTraceLogVerbose( + FrameLogPathAckInvalid, + "[%c][%cX][%llu] PATH_ACK [Invalid]", + PtkConnPre(Connection), + PktRxPre(Rx), + PacketNumber); +// arg2 = arg2 = PtkConnPre(Connection) = arg2 +// arg3 = arg3 = PktRxPre(Rx) = arg3 +// arg4 = arg4 = PacketNumber = arg4 +----------------------------------------------------------*/ +#ifndef _clog_5_ARGS_TRACE_FrameLogPathAckInvalid +#define _clog_5_ARGS_TRACE_FrameLogPathAckInvalid(uniqueId, encoded_arg_string, arg2, arg3, arg4)\ +tracepoint(CLOG_FRAME_C, FrameLogPathAckInvalid , arg2, arg3, arg4);\ + +#endif + + + + +/*---------------------------------------------------------- +// Decoder Ring for FrameLogPathAck +// [%c][%cX][%llu] PathId:%llu ACK Largest:%llu Delay:%llu +// QuicTraceLogVerbose( + FrameLogPathAck, + "[%c][%cX][%llu] PathId:%llu ACK Largest:%llu Delay:%llu", + PtkConnPre(Connection), + PktRxPre(Rx), + PacketNumber, + Frame.PathId, + Frame.LargestAcknowledged, + Frame.AckDelay); +// arg2 = arg2 = PtkConnPre(Connection) = arg2 +// arg3 = arg3 = PktRxPre(Rx) = arg3 +// arg4 = arg4 = PacketNumber = arg4 +// arg5 = arg5 = Frame.PathId = arg5 +// arg6 = arg6 = Frame.LargestAcknowledged = arg6 +// arg7 = arg7 = Frame.AckDelay = arg7 +----------------------------------------------------------*/ +#ifndef _clog_8_ARGS_TRACE_FrameLogPathAck +#define _clog_8_ARGS_TRACE_FrameLogPathAck(uniqueId, encoded_arg_string, arg2, arg3, arg4, arg5, arg6, arg7)\ +tracepoint(CLOG_FRAME_C, FrameLogPathAck , arg2, arg3, arg4, arg5, arg6, arg7);\ + +#endif + + + + /*---------------------------------------------------------- // Decoder Ring for FrameLogAckSingleBlock // [%c][%cX][%llu] %llu @@ -871,6 +921,60 @@ tracepoint(CLOG_FRAME_C, FrameLogNewConnectionID , arg2, arg3, arg4, arg5, arg6, +/*---------------------------------------------------------- +// Decoder Ring for FrameLogPathNewConnectionIDInvalid +// [%c][%cX][%llu] PATH_NEW_CONN_ID [Invalid] +// QuicTraceLogVerbose( + FrameLogPathNewConnectionIDInvalid, + "[%c][%cX][%llu] PATH_NEW_CONN_ID [Invalid]", + PtkConnPre(Connection), + PktRxPre(Rx), + PacketNumber); +// arg2 = arg2 = PtkConnPre(Connection) = arg2 +// arg3 = arg3 = PktRxPre(Rx) = arg3 +// arg4 = arg4 = PacketNumber = arg4 +----------------------------------------------------------*/ +#ifndef _clog_5_ARGS_TRACE_FrameLogPathNewConnectionIDInvalid +#define _clog_5_ARGS_TRACE_FrameLogPathNewConnectionIDInvalid(uniqueId, encoded_arg_string, arg2, arg3, arg4)\ +tracepoint(CLOG_FRAME_C, FrameLogPathNewConnectionIDInvalid , arg2, arg3, arg4);\ + +#endif + + + + +/*---------------------------------------------------------- +// Decoder Ring for FrameLogPathNewConnectionID +// [%c][%cX][%llu] PATH_NEW_CONN_ID PathID:%llu Seq:%llu RPT:%llu CID:%s Token:%s +// QuicTraceLogVerbose( + FrameLogPathNewConnectionID, + "[%c][%cX][%llu] PATH_NEW_CONN_ID PathID:%llu Seq:%llu RPT:%llu CID:%s Token:%s", + PtkConnPre(Connection), + PktRxPre(Rx), + PacketNumber, + Frame.PathID, + Frame.Sequence, + Frame.RetirePriorTo, + QuicCidBufToStr(Frame.Buffer, Frame.Length).Buffer, + QuicCidBufToStr(Frame.Buffer + Frame.Length, QUIC_STATELESS_RESET_TOKEN_LENGTH).Buffer); +// arg2 = arg2 = PtkConnPre(Connection) = arg2 +// arg3 = arg3 = PktRxPre(Rx) = arg3 +// arg4 = arg4 = PacketNumber = arg4 +// arg5 = arg5 = Frame.PathID = arg5 +// arg6 = arg6 = Frame.Sequence = arg6 +// arg7 = arg7 = Frame.RetirePriorTo = arg7 +// arg8 = arg8 = QuicCidBufToStr(Frame.Buffer, Frame.Length).Buffer = arg8 +// arg9 = arg9 = QuicCidBufToStr(Frame.Buffer + Frame.Length, QUIC_STATELESS_RESET_TOKEN_LENGTH).Buffer = arg9 +----------------------------------------------------------*/ +#ifndef _clog_10_ARGS_TRACE_FrameLogPathNewConnectionID +#define _clog_10_ARGS_TRACE_FrameLogPathNewConnectionID(uniqueId, encoded_arg_string, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)\ +tracepoint(CLOG_FRAME_C, FrameLogPathNewConnectionID , arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);\ + +#endif + + + + /*---------------------------------------------------------- // Decoder Ring for FrameLogRetireConnectionIDInvalid // [%c][%cX][%llu] RETIRE_CONN_ID [Invalid] @@ -917,6 +1021,54 @@ tracepoint(CLOG_FRAME_C, FrameLogRetireConnectionID , arg2, arg3, arg4, arg5);\ +/*---------------------------------------------------------- +// Decoder Ring for FrameLogPathRetireConnectionIDInvalid +// [%c][%cX][%llu] PATH_RETIRE_CONN_ID [Invalid] +// QuicTraceLogVerbose( + FrameLogPathRetireConnectionIDInvalid, + "[%c][%cX][%llu] PATH_RETIRE_CONN_ID [Invalid]", + PtkConnPre(Connection), + PktRxPre(Rx), + PacketNumber); +// arg2 = arg2 = PtkConnPre(Connection) = arg2 +// arg3 = arg3 = PktRxPre(Rx) = arg3 +// arg4 = arg4 = PacketNumber = arg4 +----------------------------------------------------------*/ +#ifndef _clog_5_ARGS_TRACE_FrameLogPathRetireConnectionIDInvalid +#define _clog_5_ARGS_TRACE_FrameLogPathRetireConnectionIDInvalid(uniqueId, encoded_arg_string, arg2, arg3, arg4)\ +tracepoint(CLOG_FRAME_C, FrameLogPathRetireConnectionIDInvalid , arg2, arg3, arg4);\ + +#endif + + + + +/*---------------------------------------------------------- +// Decoder Ring for FrameLogPathRetireConnectionID +// [%c][%cX][%llu] PATH_RETIRE_CONN_ID PathID:%llu Seq:%llu +// QuicTraceLogVerbose( + FrameLogPathRetireConnectionID, + "[%c][%cX][%llu] PATH_RETIRE_CONN_ID PathID:%llu Seq:%llu", + PtkConnPre(Connection), + PktRxPre(Rx), + PacketNumber, + Frame.PathID, + Frame.Sequence); +// arg2 = arg2 = PtkConnPre(Connection) = arg2 +// arg3 = arg3 = PktRxPre(Rx) = arg3 +// arg4 = arg4 = PacketNumber = arg4 +// arg5 = arg5 = Frame.PathID = arg5 +// arg6 = arg6 = Frame.Sequence = arg6 +----------------------------------------------------------*/ +#ifndef _clog_7_ARGS_TRACE_FrameLogPathRetireConnectionID +#define _clog_7_ARGS_TRACE_FrameLogPathRetireConnectionID(uniqueId, encoded_arg_string, arg2, arg3, arg4, arg5, arg6)\ +tracepoint(CLOG_FRAME_C, FrameLogPathRetireConnectionID , arg2, arg3, arg4, arg5, arg6);\ + +#endif + + + + /*---------------------------------------------------------- // Decoder Ring for FrameLogPathChallengeInvalid // [%c][%cX][%llu] PATH_CHALLENGE [Invalid] @@ -1009,6 +1161,196 @@ tracepoint(CLOG_FRAME_C, FrameLogPathResponse , arg2, arg3, arg4, arg5);\ +/*---------------------------------------------------------- +// Decoder Ring for FrameLogPathAbandonInvalid +// [%c][%cX][%llu] PATH_ABANDON [Invalid] +// QuicTraceLogVerbose( + FrameLogPathAbandonInvalid, + "[%c][%cX][%llu] PATH_ABANDON [Invalid]", + PtkConnPre(Connection), + PktRxPre(Rx), + PacketNumber); +// arg2 = arg2 = PtkConnPre(Connection) = arg2 +// arg3 = arg3 = PktRxPre(Rx) = arg3 +// arg4 = arg4 = PacketNumber = arg4 +----------------------------------------------------------*/ +#ifndef _clog_5_ARGS_TRACE_FrameLogPathAbandonInvalid +#define _clog_5_ARGS_TRACE_FrameLogPathAbandonInvalid(uniqueId, encoded_arg_string, arg2, arg3, arg4)\ +tracepoint(CLOG_FRAME_C, FrameLogPathAbandonInvalid , arg2, arg3, arg4);\ + +#endif + + + + +/*---------------------------------------------------------- +// Decoder Ring for FrameLogPathAbandon +// [%c][%cX][%llu] PATH_ABANDON PathID:%llu ErrorCode:0x%llX +// QuicTraceLogVerbose( + FrameLogPathAbandon, + "[%c][%cX][%llu] PATH_ABANDON PathID:%llu ErrorCode:0x%llX", + PtkConnPre(Connection), + PktRxPre(Rx), + PacketNumber, + Frame.PathID, + Frame.ErrorCode); +// arg2 = arg2 = PtkConnPre(Connection) = arg2 +// arg3 = arg3 = PktRxPre(Rx) = arg3 +// arg4 = arg4 = PacketNumber = arg4 +// arg5 = arg5 = Frame.PathID = arg5 +// arg6 = arg6 = Frame.ErrorCode = arg6 +----------------------------------------------------------*/ +#ifndef _clog_7_ARGS_TRACE_FrameLogPathAbandon +#define _clog_7_ARGS_TRACE_FrameLogPathAbandon(uniqueId, encoded_arg_string, arg2, arg3, arg4, arg5, arg6)\ +tracepoint(CLOG_FRAME_C, FrameLogPathAbandon , arg2, arg3, arg4, arg5, arg6);\ + +#endif + + + + +/*---------------------------------------------------------- +// Decoder Ring for FrameLogPathBackupInvalid +// [%c][%cX][%llu] PATH_BACKUP [Invalid] +// QuicTraceLogVerbose( + FrameLogPathBackupInvalid, + "[%c][%cX][%llu] PATH_BACKUP [Invalid]", + PtkConnPre(Connection), + PktRxPre(Rx), + PacketNumber); +// arg2 = arg2 = PtkConnPre(Connection) = arg2 +// arg3 = arg3 = PktRxPre(Rx) = arg3 +// arg4 = arg4 = PacketNumber = arg4 +----------------------------------------------------------*/ +#ifndef _clog_5_ARGS_TRACE_FrameLogPathBackupInvalid +#define _clog_5_ARGS_TRACE_FrameLogPathBackupInvalid(uniqueId, encoded_arg_string, arg2, arg3, arg4)\ +tracepoint(CLOG_FRAME_C, FrameLogPathBackupInvalid , arg2, arg3, arg4);\ + +#endif + + + + +/*---------------------------------------------------------- +// Decoder Ring for FrameLogPathBackup +// [%c][%cX][%llu] PATH_BACKUP PathID:%llu SSN:0x%llX +// QuicTraceLogVerbose( + FrameLogPathBackup, + "[%c][%cX][%llu] PATH_BACKUP PathID:%llu SSN:0x%llX", + PtkConnPre(Connection), + PktRxPre(Rx), + PacketNumber, + Frame.PathID, + Frame.StatusSequenceNumber); +// arg2 = arg2 = PtkConnPre(Connection) = arg2 +// arg3 = arg3 = PktRxPre(Rx) = arg3 +// arg4 = arg4 = PacketNumber = arg4 +// arg5 = arg5 = Frame.PathID = arg5 +// arg6 = arg6 = Frame.StatusSequenceNumber = arg6 +----------------------------------------------------------*/ +#ifndef _clog_7_ARGS_TRACE_FrameLogPathBackup +#define _clog_7_ARGS_TRACE_FrameLogPathBackup(uniqueId, encoded_arg_string, arg2, arg3, arg4, arg5, arg6)\ +tracepoint(CLOG_FRAME_C, FrameLogPathBackup , arg2, arg3, arg4, arg5, arg6);\ + +#endif + + + + +/*---------------------------------------------------------- +// Decoder Ring for FrameLogPathAvailableInvalid +// [%c][%cX][%llu] PATH_AVAILABLE [Invalid] +// QuicTraceLogVerbose( + FrameLogPathAvailableInvalid, + "[%c][%cX][%llu] PATH_AVAILABLE [Invalid]", + PtkConnPre(Connection), + PktRxPre(Rx), + PacketNumber); +// arg2 = arg2 = PtkConnPre(Connection) = arg2 +// arg3 = arg3 = PktRxPre(Rx) = arg3 +// arg4 = arg4 = PacketNumber = arg4 +----------------------------------------------------------*/ +#ifndef _clog_5_ARGS_TRACE_FrameLogPathAvailableInvalid +#define _clog_5_ARGS_TRACE_FrameLogPathAvailableInvalid(uniqueId, encoded_arg_string, arg2, arg3, arg4)\ +tracepoint(CLOG_FRAME_C, FrameLogPathAvailableInvalid , arg2, arg3, arg4);\ + +#endif + + + + +/*---------------------------------------------------------- +// Decoder Ring for FrameLogPathAvailable +// [%c][%cX][%llu] PATH_AVAILABLE PathID:%llu SSN:0x%llX +// QuicTraceLogVerbose( + FrameLogPathAvailable, + "[%c][%cX][%llu] PATH_AVAILABLE PathID:%llu SSN:0x%llX", + PtkConnPre(Connection), + PktRxPre(Rx), + PacketNumber, + Frame.PathID, + Frame.StatusSequenceNumber); +// arg2 = arg2 = PtkConnPre(Connection) = arg2 +// arg3 = arg3 = PktRxPre(Rx) = arg3 +// arg4 = arg4 = PacketNumber = arg4 +// arg5 = arg5 = Frame.PathID = arg5 +// arg6 = arg6 = Frame.StatusSequenceNumber = arg6 +----------------------------------------------------------*/ +#ifndef _clog_7_ARGS_TRACE_FrameLogPathAvailable +#define _clog_7_ARGS_TRACE_FrameLogPathAvailable(uniqueId, encoded_arg_string, arg2, arg3, arg4, arg5, arg6)\ +tracepoint(CLOG_FRAME_C, FrameLogPathAvailable , arg2, arg3, arg4, arg5, arg6);\ + +#endif + + + + +/*---------------------------------------------------------- +// Decoder Ring for FrameLogMaxPathIDInvalid +// [%c][%cX][%llu] MAX_PATH_ID [Invalid] +// QuicTraceLogVerbose( + FrameLogMaxPathIDInvalid, + "[%c][%cX][%llu] MAX_PATH_ID [Invalid]", + PtkConnPre(Connection), + PktRxPre(Rx), + PacketNumber); +// arg2 = arg2 = PtkConnPre(Connection) = arg2 +// arg3 = arg3 = PktRxPre(Rx) = arg3 +// arg4 = arg4 = PacketNumber = arg4 +----------------------------------------------------------*/ +#ifndef _clog_5_ARGS_TRACE_FrameLogMaxPathIDInvalid +#define _clog_5_ARGS_TRACE_FrameLogMaxPathIDInvalid(uniqueId, encoded_arg_string, arg2, arg3, arg4)\ +tracepoint(CLOG_FRAME_C, FrameLogMaxPathIDInvalid , arg2, arg3, arg4);\ + +#endif + + + + +/*---------------------------------------------------------- +// Decoder Ring for FrameLogMaxPathID +// [%c][%cX][%llu] MAX_PATH_ID Max:%llu +// QuicTraceLogVerbose( + FrameLogMaxPathID, + "[%c][%cX][%llu] MAX_PATH_ID Max:%llu", + PtkConnPre(Connection), + PktRxPre(Rx), + PacketNumber, + Frame.MaximumPathID); +// arg2 = arg2 = PtkConnPre(Connection) = arg2 +// arg3 = arg3 = PktRxPre(Rx) = arg3 +// arg4 = arg4 = PacketNumber = arg4 +// arg5 = arg5 = Frame.MaximumPathID = arg5 +----------------------------------------------------------*/ +#ifndef _clog_6_ARGS_TRACE_FrameLogMaxPathID +#define _clog_6_ARGS_TRACE_FrameLogMaxPathID(uniqueId, encoded_arg_string, arg2, arg3, arg4, arg5)\ +tracepoint(CLOG_FRAME_C, FrameLogMaxPathID , arg2, arg3, arg4, arg5);\ + +#endif + + + + /*---------------------------------------------------------- // Decoder Ring for FrameLogConnectionCloseInvalid // [%c][%cX][%llu] CONN_CLOSE [Invalid] diff --git a/src/generated/linux/frame.c.clog.h.lttng.h b/src/generated/linux/frame.c.clog.h.lttng.h index df916db905..4c36841a4a 100644 --- a/src/generated/linux/frame.c.clog.h.lttng.h +++ b/src/generated/linux/frame.c.clog.h.lttng.h @@ -94,11 +94,11 @@ TRACEPOINT_EVENT(CLOG_FRAME_C, FrameLogPing, // Decoder Ring for FrameLogAckInvalid // [%c][%cX][%llu] ACK [Invalid] // QuicTraceLogVerbose( - FrameLogAckInvalid, - "[%c][%cX][%llu] ACK [Invalid]", - PtkConnPre(Connection), - PktRxPre(Rx), - PacketNumber); + FrameLogAckInvalid, + "[%c][%cX][%llu] ACK [Invalid]", + PtkConnPre(Connection), + PktRxPre(Rx), + PacketNumber); // arg2 = arg2 = PtkConnPre(Connection) = arg2 // arg3 = arg3 = PktRxPre(Rx) = arg3 // arg4 = arg4 = PacketNumber = arg4 @@ -121,13 +121,13 @@ TRACEPOINT_EVENT(CLOG_FRAME_C, FrameLogAckInvalid, // Decoder Ring for FrameLogAck // [%c][%cX][%llu] ACK Largest:%llu Delay:%llu // QuicTraceLogVerbose( - FrameLogAck, - "[%c][%cX][%llu] ACK Largest:%llu Delay:%llu", - PtkConnPre(Connection), - PktRxPre(Rx), - PacketNumber, - Frame.LargestAcknowledged, - Frame.AckDelay); + FrameLogAck, + "[%c][%cX][%llu] ACK Largest:%llu Delay:%llu", + PtkConnPre(Connection), + PktRxPre(Rx), + PacketNumber, + Frame.LargestAcknowledged, + Frame.AckDelay); // arg2 = arg2 = PtkConnPre(Connection) = arg2 // arg3 = arg3 = PktRxPre(Rx) = arg3 // arg4 = arg4 = PacketNumber = arg4 @@ -152,6 +152,72 @@ TRACEPOINT_EVENT(CLOG_FRAME_C, FrameLogAck, +/*---------------------------------------------------------- +// Decoder Ring for FrameLogPathAckInvalid +// [%c][%cX][%llu] PATH_ACK [Invalid] +// QuicTraceLogVerbose( + FrameLogPathAckInvalid, + "[%c][%cX][%llu] PATH_ACK [Invalid]", + PtkConnPre(Connection), + PktRxPre(Rx), + PacketNumber); +// arg2 = arg2 = PtkConnPre(Connection) = arg2 +// arg3 = arg3 = PktRxPre(Rx) = arg3 +// arg4 = arg4 = PacketNumber = arg4 +----------------------------------------------------------*/ +TRACEPOINT_EVENT(CLOG_FRAME_C, FrameLogPathAckInvalid, + TP_ARGS( + unsigned char, arg2, + unsigned char, arg3, + unsigned long long, arg4), + TP_FIELDS( + ctf_integer(unsigned char, arg2, arg2) + ctf_integer(unsigned char, arg3, arg3) + ctf_integer(uint64_t, arg4, arg4) + ) +) + + + +/*---------------------------------------------------------- +// Decoder Ring for FrameLogPathAck +// [%c][%cX][%llu] PathId:%llu ACK Largest:%llu Delay:%llu +// QuicTraceLogVerbose( + FrameLogPathAck, + "[%c][%cX][%llu] PathId:%llu ACK Largest:%llu Delay:%llu", + PtkConnPre(Connection), + PktRxPre(Rx), + PacketNumber, + Frame.PathId, + Frame.LargestAcknowledged, + Frame.AckDelay); +// arg2 = arg2 = PtkConnPre(Connection) = arg2 +// arg3 = arg3 = PktRxPre(Rx) = arg3 +// arg4 = arg4 = PacketNumber = arg4 +// arg5 = arg5 = Frame.PathId = arg5 +// arg6 = arg6 = Frame.LargestAcknowledged = arg6 +// arg7 = arg7 = Frame.AckDelay = arg7 +----------------------------------------------------------*/ +TRACEPOINT_EVENT(CLOG_FRAME_C, FrameLogPathAck, + TP_ARGS( + unsigned char, arg2, + unsigned char, arg3, + unsigned long long, arg4, + unsigned long long, arg5, + unsigned long long, arg6, + unsigned long long, arg7), + TP_FIELDS( + ctf_integer(unsigned char, arg2, arg2) + ctf_integer(unsigned char, arg3, arg3) + ctf_integer(uint64_t, arg4, arg4) + ctf_integer(uint64_t, arg5, arg5) + ctf_integer(uint64_t, arg6, arg6) + ctf_integer(uint64_t, arg7, arg7) + ) +) + + + /*---------------------------------------------------------- // Decoder Ring for FrameLogAckSingleBlock // [%c][%cX][%llu] %llu @@ -1098,6 +1164,80 @@ TRACEPOINT_EVENT(CLOG_FRAME_C, FrameLogNewConnectionID, +/*---------------------------------------------------------- +// Decoder Ring for FrameLogPathNewConnectionIDInvalid +// [%c][%cX][%llu] PATH_NEW_CONN_ID [Invalid] +// QuicTraceLogVerbose( + FrameLogPathNewConnectionIDInvalid, + "[%c][%cX][%llu] PATH_NEW_CONN_ID [Invalid]", + PtkConnPre(Connection), + PktRxPre(Rx), + PacketNumber); +// arg2 = arg2 = PtkConnPre(Connection) = arg2 +// arg3 = arg3 = PktRxPre(Rx) = arg3 +// arg4 = arg4 = PacketNumber = arg4 +----------------------------------------------------------*/ +TRACEPOINT_EVENT(CLOG_FRAME_C, FrameLogPathNewConnectionIDInvalid, + TP_ARGS( + unsigned char, arg2, + unsigned char, arg3, + unsigned long long, arg4), + TP_FIELDS( + ctf_integer(unsigned char, arg2, arg2) + ctf_integer(unsigned char, arg3, arg3) + ctf_integer(uint64_t, arg4, arg4) + ) +) + + + +/*---------------------------------------------------------- +// Decoder Ring for FrameLogPathNewConnectionID +// [%c][%cX][%llu] PATH_NEW_CONN_ID PathID:%llu Seq:%llu RPT:%llu CID:%s Token:%s +// QuicTraceLogVerbose( + FrameLogPathNewConnectionID, + "[%c][%cX][%llu] PATH_NEW_CONN_ID PathID:%llu Seq:%llu RPT:%llu CID:%s Token:%s", + PtkConnPre(Connection), + PktRxPre(Rx), + PacketNumber, + Frame.PathID, + Frame.Sequence, + Frame.RetirePriorTo, + QuicCidBufToStr(Frame.Buffer, Frame.Length).Buffer, + QuicCidBufToStr(Frame.Buffer + Frame.Length, QUIC_STATELESS_RESET_TOKEN_LENGTH).Buffer); +// arg2 = arg2 = PtkConnPre(Connection) = arg2 +// arg3 = arg3 = PktRxPre(Rx) = arg3 +// arg4 = arg4 = PacketNumber = arg4 +// arg5 = arg5 = Frame.PathID = arg5 +// arg6 = arg6 = Frame.Sequence = arg6 +// arg7 = arg7 = Frame.RetirePriorTo = arg7 +// arg8 = arg8 = QuicCidBufToStr(Frame.Buffer, Frame.Length).Buffer = arg8 +// arg9 = arg9 = QuicCidBufToStr(Frame.Buffer + Frame.Length, QUIC_STATELESS_RESET_TOKEN_LENGTH).Buffer = arg9 +----------------------------------------------------------*/ +TRACEPOINT_EVENT(CLOG_FRAME_C, FrameLogPathNewConnectionID, + TP_ARGS( + unsigned char, arg2, + unsigned char, arg3, + unsigned long long, arg4, + unsigned long long, arg5, + unsigned long long, arg6, + unsigned long long, arg7, + const char *, arg8, + const char *, arg9), + TP_FIELDS( + ctf_integer(unsigned char, arg2, arg2) + ctf_integer(unsigned char, arg3, arg3) + ctf_integer(uint64_t, arg4, arg4) + ctf_integer(uint64_t, arg5, arg5) + ctf_integer(uint64_t, arg6, arg6) + ctf_integer(uint64_t, arg7, arg7) + ctf_string(arg8, arg8) + ctf_string(arg9, arg9) + ) +) + + + /*---------------------------------------------------------- // Decoder Ring for FrameLogRetireConnectionIDInvalid // [%c][%cX][%llu] RETIRE_CONN_ID [Invalid] @@ -1156,6 +1296,68 @@ TRACEPOINT_EVENT(CLOG_FRAME_C, FrameLogRetireConnectionID, +/*---------------------------------------------------------- +// Decoder Ring for FrameLogPathRetireConnectionIDInvalid +// [%c][%cX][%llu] PATH_RETIRE_CONN_ID [Invalid] +// QuicTraceLogVerbose( + FrameLogPathRetireConnectionIDInvalid, + "[%c][%cX][%llu] PATH_RETIRE_CONN_ID [Invalid]", + PtkConnPre(Connection), + PktRxPre(Rx), + PacketNumber); +// arg2 = arg2 = PtkConnPre(Connection) = arg2 +// arg3 = arg3 = PktRxPre(Rx) = arg3 +// arg4 = arg4 = PacketNumber = arg4 +----------------------------------------------------------*/ +TRACEPOINT_EVENT(CLOG_FRAME_C, FrameLogPathRetireConnectionIDInvalid, + TP_ARGS( + unsigned char, arg2, + unsigned char, arg3, + unsigned long long, arg4), + TP_FIELDS( + ctf_integer(unsigned char, arg2, arg2) + ctf_integer(unsigned char, arg3, arg3) + ctf_integer(uint64_t, arg4, arg4) + ) +) + + + +/*---------------------------------------------------------- +// Decoder Ring for FrameLogPathRetireConnectionID +// [%c][%cX][%llu] PATH_RETIRE_CONN_ID PathID:%llu Seq:%llu +// QuicTraceLogVerbose( + FrameLogPathRetireConnectionID, + "[%c][%cX][%llu] PATH_RETIRE_CONN_ID PathID:%llu Seq:%llu", + PtkConnPre(Connection), + PktRxPre(Rx), + PacketNumber, + Frame.PathID, + Frame.Sequence); +// arg2 = arg2 = PtkConnPre(Connection) = arg2 +// arg3 = arg3 = PktRxPre(Rx) = arg3 +// arg4 = arg4 = PacketNumber = arg4 +// arg5 = arg5 = Frame.PathID = arg5 +// arg6 = arg6 = Frame.Sequence = arg6 +----------------------------------------------------------*/ +TRACEPOINT_EVENT(CLOG_FRAME_C, FrameLogPathRetireConnectionID, + TP_ARGS( + unsigned char, arg2, + unsigned char, arg3, + unsigned long long, arg4, + unsigned long long, arg5, + unsigned long long, arg6), + TP_FIELDS( + ctf_integer(unsigned char, arg2, arg2) + ctf_integer(unsigned char, arg3, arg3) + ctf_integer(uint64_t, arg4, arg4) + ctf_integer(uint64_t, arg5, arg5) + ctf_integer(uint64_t, arg6, arg6) + ) +) + + + /*---------------------------------------------------------- // Decoder Ring for FrameLogPathChallengeInvalid // [%c][%cX][%llu] PATH_CHALLENGE [Invalid] @@ -1272,6 +1474,250 @@ TRACEPOINT_EVENT(CLOG_FRAME_C, FrameLogPathResponse, +/*---------------------------------------------------------- +// Decoder Ring for FrameLogPathAbandonInvalid +// [%c][%cX][%llu] PATH_ABANDON [Invalid] +// QuicTraceLogVerbose( + FrameLogPathAbandonInvalid, + "[%c][%cX][%llu] PATH_ABANDON [Invalid]", + PtkConnPre(Connection), + PktRxPre(Rx), + PacketNumber); +// arg2 = arg2 = PtkConnPre(Connection) = arg2 +// arg3 = arg3 = PktRxPre(Rx) = arg3 +// arg4 = arg4 = PacketNumber = arg4 +----------------------------------------------------------*/ +TRACEPOINT_EVENT(CLOG_FRAME_C, FrameLogPathAbandonInvalid, + TP_ARGS( + unsigned char, arg2, + unsigned char, arg3, + unsigned long long, arg4), + TP_FIELDS( + ctf_integer(unsigned char, arg2, arg2) + ctf_integer(unsigned char, arg3, arg3) + ctf_integer(uint64_t, arg4, arg4) + ) +) + + + +/*---------------------------------------------------------- +// Decoder Ring for FrameLogPathAbandon +// [%c][%cX][%llu] PATH_ABANDON PathID:%llu ErrorCode:0x%llX +// QuicTraceLogVerbose( + FrameLogPathAbandon, + "[%c][%cX][%llu] PATH_ABANDON PathID:%llu ErrorCode:0x%llX", + PtkConnPre(Connection), + PktRxPre(Rx), + PacketNumber, + Frame.PathID, + Frame.ErrorCode); +// arg2 = arg2 = PtkConnPre(Connection) = arg2 +// arg3 = arg3 = PktRxPre(Rx) = arg3 +// arg4 = arg4 = PacketNumber = arg4 +// arg5 = arg5 = Frame.PathID = arg5 +// arg6 = arg6 = Frame.ErrorCode = arg6 +----------------------------------------------------------*/ +TRACEPOINT_EVENT(CLOG_FRAME_C, FrameLogPathAbandon, + TP_ARGS( + unsigned char, arg2, + unsigned char, arg3, + unsigned long long, arg4, + unsigned long long, arg5, + unsigned long long, arg6), + TP_FIELDS( + ctf_integer(unsigned char, arg2, arg2) + ctf_integer(unsigned char, arg3, arg3) + ctf_integer(uint64_t, arg4, arg4) + ctf_integer(uint64_t, arg5, arg5) + ctf_integer(uint64_t, arg6, arg6) + ) +) + + + +/*---------------------------------------------------------- +// Decoder Ring for FrameLogPathBackupInvalid +// [%c][%cX][%llu] PATH_BACKUP [Invalid] +// QuicTraceLogVerbose( + FrameLogPathBackupInvalid, + "[%c][%cX][%llu] PATH_BACKUP [Invalid]", + PtkConnPre(Connection), + PktRxPre(Rx), + PacketNumber); +// arg2 = arg2 = PtkConnPre(Connection) = arg2 +// arg3 = arg3 = PktRxPre(Rx) = arg3 +// arg4 = arg4 = PacketNumber = arg4 +----------------------------------------------------------*/ +TRACEPOINT_EVENT(CLOG_FRAME_C, FrameLogPathBackupInvalid, + TP_ARGS( + unsigned char, arg2, + unsigned char, arg3, + unsigned long long, arg4), + TP_FIELDS( + ctf_integer(unsigned char, arg2, arg2) + ctf_integer(unsigned char, arg3, arg3) + ctf_integer(uint64_t, arg4, arg4) + ) +) + + + +/*---------------------------------------------------------- +// Decoder Ring for FrameLogPathBackup +// [%c][%cX][%llu] PATH_BACKUP PathID:%llu SSN:0x%llX +// QuicTraceLogVerbose( + FrameLogPathBackup, + "[%c][%cX][%llu] PATH_BACKUP PathID:%llu SSN:0x%llX", + PtkConnPre(Connection), + PktRxPre(Rx), + PacketNumber, + Frame.PathID, + Frame.StatusSequenceNumber); +// arg2 = arg2 = PtkConnPre(Connection) = arg2 +// arg3 = arg3 = PktRxPre(Rx) = arg3 +// arg4 = arg4 = PacketNumber = arg4 +// arg5 = arg5 = Frame.PathID = arg5 +// arg6 = arg6 = Frame.StatusSequenceNumber = arg6 +----------------------------------------------------------*/ +TRACEPOINT_EVENT(CLOG_FRAME_C, FrameLogPathBackup, + TP_ARGS( + unsigned char, arg2, + unsigned char, arg3, + unsigned long long, arg4, + unsigned long long, arg5, + unsigned long long, arg6), + TP_FIELDS( + ctf_integer(unsigned char, arg2, arg2) + ctf_integer(unsigned char, arg3, arg3) + ctf_integer(uint64_t, arg4, arg4) + ctf_integer(uint64_t, arg5, arg5) + ctf_integer(uint64_t, arg6, arg6) + ) +) + + + +/*---------------------------------------------------------- +// Decoder Ring for FrameLogPathAvailableInvalid +// [%c][%cX][%llu] PATH_AVAILABLE [Invalid] +// QuicTraceLogVerbose( + FrameLogPathAvailableInvalid, + "[%c][%cX][%llu] PATH_AVAILABLE [Invalid]", + PtkConnPre(Connection), + PktRxPre(Rx), + PacketNumber); +// arg2 = arg2 = PtkConnPre(Connection) = arg2 +// arg3 = arg3 = PktRxPre(Rx) = arg3 +// arg4 = arg4 = PacketNumber = arg4 +----------------------------------------------------------*/ +TRACEPOINT_EVENT(CLOG_FRAME_C, FrameLogPathAvailableInvalid, + TP_ARGS( + unsigned char, arg2, + unsigned char, arg3, + unsigned long long, arg4), + TP_FIELDS( + ctf_integer(unsigned char, arg2, arg2) + ctf_integer(unsigned char, arg3, arg3) + ctf_integer(uint64_t, arg4, arg4) + ) +) + + + +/*---------------------------------------------------------- +// Decoder Ring for FrameLogPathAvailable +// [%c][%cX][%llu] PATH_AVAILABLE PathID:%llu SSN:0x%llX +// QuicTraceLogVerbose( + FrameLogPathAvailable, + "[%c][%cX][%llu] PATH_AVAILABLE PathID:%llu SSN:0x%llX", + PtkConnPre(Connection), + PktRxPre(Rx), + PacketNumber, + Frame.PathID, + Frame.StatusSequenceNumber); +// arg2 = arg2 = PtkConnPre(Connection) = arg2 +// arg3 = arg3 = PktRxPre(Rx) = arg3 +// arg4 = arg4 = PacketNumber = arg4 +// arg5 = arg5 = Frame.PathID = arg5 +// arg6 = arg6 = Frame.StatusSequenceNumber = arg6 +----------------------------------------------------------*/ +TRACEPOINT_EVENT(CLOG_FRAME_C, FrameLogPathAvailable, + TP_ARGS( + unsigned char, arg2, + unsigned char, arg3, + unsigned long long, arg4, + unsigned long long, arg5, + unsigned long long, arg6), + TP_FIELDS( + ctf_integer(unsigned char, arg2, arg2) + ctf_integer(unsigned char, arg3, arg3) + ctf_integer(uint64_t, arg4, arg4) + ctf_integer(uint64_t, arg5, arg5) + ctf_integer(uint64_t, arg6, arg6) + ) +) + + + +/*---------------------------------------------------------- +// Decoder Ring for FrameLogMaxPathIDInvalid +// [%c][%cX][%llu] MAX_PATH_ID [Invalid] +// QuicTraceLogVerbose( + FrameLogMaxPathIDInvalid, + "[%c][%cX][%llu] MAX_PATH_ID [Invalid]", + PtkConnPre(Connection), + PktRxPre(Rx), + PacketNumber); +// arg2 = arg2 = PtkConnPre(Connection) = arg2 +// arg3 = arg3 = PktRxPre(Rx) = arg3 +// arg4 = arg4 = PacketNumber = arg4 +----------------------------------------------------------*/ +TRACEPOINT_EVENT(CLOG_FRAME_C, FrameLogMaxPathIDInvalid, + TP_ARGS( + unsigned char, arg2, + unsigned char, arg3, + unsigned long long, arg4), + TP_FIELDS( + ctf_integer(unsigned char, arg2, arg2) + ctf_integer(unsigned char, arg3, arg3) + ctf_integer(uint64_t, arg4, arg4) + ) +) + + + +/*---------------------------------------------------------- +// Decoder Ring for FrameLogMaxPathID +// [%c][%cX][%llu] MAX_PATH_ID Max:%llu +// QuicTraceLogVerbose( + FrameLogMaxPathID, + "[%c][%cX][%llu] MAX_PATH_ID Max:%llu", + PtkConnPre(Connection), + PktRxPre(Rx), + PacketNumber, + Frame.MaximumPathID); +// arg2 = arg2 = PtkConnPre(Connection) = arg2 +// arg3 = arg3 = PktRxPre(Rx) = arg3 +// arg4 = arg4 = PacketNumber = arg4 +// arg5 = arg5 = Frame.MaximumPathID = arg5 +----------------------------------------------------------*/ +TRACEPOINT_EVENT(CLOG_FRAME_C, FrameLogMaxPathID, + TP_ARGS( + unsigned char, arg2, + unsigned char, arg3, + unsigned long long, arg4, + unsigned long long, arg5), + TP_FIELDS( + ctf_integer(unsigned char, arg2, arg2) + ctf_integer(unsigned char, arg3, arg3) + ctf_integer(uint64_t, arg4, arg4) + ctf_integer(uint64_t, arg5, arg5) + ) +) + + + /*---------------------------------------------------------- // Decoder Ring for FrameLogConnectionCloseInvalid // [%c][%cX][%llu] CONN_CLOSE [Invalid] diff --git a/src/generated/linux/path.c.clog.h b/src/generated/linux/path.c.clog.h index 23f70922ad..8ff92d71f5 100644 --- a/src/generated/linux/path.c.clog.h +++ b/src/generated/linux/path.c.clog.h @@ -83,6 +83,26 @@ tracepoint(CLOG_PATH_C, PathValidated , arg1, arg3, arg4);\ +/*---------------------------------------------------------- +// Decoder Ring for PathChosen +// [conn][%p] Path[%hhu] Chosen +// QuicTraceLogConnInfo( + PathChosen, + Connection, + "Path[%hhu] Chosen", + Path->ID); +// arg1 = arg1 = Connection = arg1 +// arg3 = arg3 = Path->ID = arg3 +----------------------------------------------------------*/ +#ifndef _clog_4_ARGS_TRACE_PathChosen +#define _clog_4_ARGS_TRACE_PathChosen(uniqueId, arg1, encoded_arg_string, arg3)\ +tracepoint(CLOG_PATH_C, PathChosen , arg1, arg3);\ + +#endif + + + + /*---------------------------------------------------------- // Decoder Ring for PathActive // [conn][%p] Path[%hhu] Set active (rebind=%hhu) diff --git a/src/generated/linux/path.c.clog.h.lttng.h b/src/generated/linux/path.c.clog.h.lttng.h index eb57556270..45b08caae2 100644 --- a/src/generated/linux/path.c.clog.h.lttng.h +++ b/src/generated/linux/path.c.clog.h.lttng.h @@ -74,6 +74,29 @@ TRACEPOINT_EVENT(CLOG_PATH_C, PathValidated, +/*---------------------------------------------------------- +// Decoder Ring for PathChosen +// [conn][%p] Path[%hhu] Chosen +// QuicTraceLogConnInfo( + PathChosen, + Connection, + "Path[%hhu] Chosen", + Path->ID); +// arg1 = arg1 = Connection = arg1 +// arg3 = arg3 = Path->ID = arg3 +----------------------------------------------------------*/ +TRACEPOINT_EVENT(CLOG_PATH_C, PathChosen, + 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 PathActive // [conn][%p] Path[%hhu] Set active (rebind=%hhu) diff --git a/src/generated/linux/pathid.c.clog.h b/src/generated/linux/pathid.c.clog.h new file mode 100644 index 0000000000..ec5b1628fc --- /dev/null +++ b/src/generated/linux/pathid.c.clog.h @@ -0,0 +1,265 @@ +#ifndef CLOG_DO_NOT_INCLUDE_HEADER +#include +#endif +#undef TRACEPOINT_PROVIDER +#define TRACEPOINT_PROVIDER CLOG_PATHID_C +#undef TRACEPOINT_PROBE_DYNAMIC_LINKAGE +#define TRACEPOINT_PROBE_DYNAMIC_LINKAGE +#undef TRACEPOINT_INCLUDE +#define TRACEPOINT_INCLUDE "pathid.c.clog.h.lttng.h" +#if !defined(DEF_CLOG_PATHID_C) || defined(TRACEPOINT_HEADER_MULTI_READ) +#define DEF_CLOG_PATHID_C +#include +#define __int64 __int64_t +#include "pathid.c.clog.h.lttng.h" +#endif +#include +#ifndef _clog_MACRO_QuicTraceLogConnWarning +#define _clog_MACRO_QuicTraceLogConnWarning 1 +#define QuicTraceLogConnWarning(a, ...) _clog_CAT(_clog_ARGN_SELECTOR(__VA_ARGS__), _clog_CAT(_,a(#a, __VA_ARGS__))) +#endif +#ifndef _clog_MACRO_QuicTraceLogConnVerbose +#define _clog_MACRO_QuicTraceLogConnVerbose 1 +#define QuicTraceLogConnVerbose(a, ...) _clog_CAT(_clog_ARGN_SELECTOR(__VA_ARGS__), _clog_CAT(_,a(#a, __VA_ARGS__))) +#endif +#ifndef _clog_MACRO_QuicTraceEvent +#define _clog_MACRO_QuicTraceEvent 1 +#define QuicTraceEvent(a, ...) _clog_CAT(_clog_ARGN_SELECTOR(__VA_ARGS__), _clog_CAT(_,a(#a, __VA_ARGS__))) +#endif +#ifdef __cplusplus +extern "C" { +#endif +/*---------------------------------------------------------- +// Decoder Ring for NoReplacementCidForRetire +// [conn][%p] Can't retire current CID because we don't have a replacement +// QuicTraceLogConnWarning( + NoReplacementCidForRetire, + PathID->Connection, + "Can't retire current CID because we don't have a replacement"); +// arg1 = arg1 = PathID->Connection = arg1 +----------------------------------------------------------*/ +#ifndef _clog_3_ARGS_TRACE_NoReplacementCidForRetire +#define _clog_3_ARGS_TRACE_NoReplacementCidForRetire(uniqueId, arg1, encoded_arg_string)\ +tracepoint(CLOG_PATHID_C, NoReplacementCidForRetire , arg1);\ + +#endif + + + + +/*---------------------------------------------------------- +// Decoder Ring for NonActivePathCidRetired +// [conn][%p] Non-active path has no replacement for retired CID. +// QuicTraceLogConnWarning( + NonActivePathCidRetired, + PathID->Connection, + "Non-active path has no replacement for retired CID."); +// arg1 = arg1 = PathID->Connection = arg1 +----------------------------------------------------------*/ +#ifndef _clog_3_ARGS_TRACE_NonActivePathCidRetired +#define _clog_3_ARGS_TRACE_NonActivePathCidRetired(uniqueId, arg1, encoded_arg_string)\ +tracepoint(CLOG_PATHID_C, NonActivePathCidRetired , arg1);\ + +#endif + + + + +/*---------------------------------------------------------- +// Decoder Ring for NewSrcCidNameCollision +// [conn][%p] CID collision, trying again +// QuicTraceLogConnVerbose( + NewSrcCidNameCollision, + PathID->Connection, + "CID collision, trying again"); +// arg1 = arg1 = PathID->Connection = arg1 +----------------------------------------------------------*/ +#ifndef _clog_3_ARGS_TRACE_NewSrcCidNameCollision +#define _clog_3_ARGS_TRACE_NewSrcCidNameCollision(uniqueId, arg1, encoded_arg_string)\ +tracepoint(CLOG_PATHID_C, NewSrcCidNameCollision , arg1);\ + +#endif + + + + +/*---------------------------------------------------------- +// Decoder Ring for ZeroLengthCidRetire +// [conn][%p] Can't retire current CID because it's zero length +// QuicTraceLogConnVerbose( + ZeroLengthCidRetire, + PathID->Connection, + "Can't retire current CID because it's zero length"); +// arg1 = arg1 = PathID->Connection = arg1 +----------------------------------------------------------*/ +#ifndef _clog_3_ARGS_TRACE_ZeroLengthCidRetire +#define _clog_3_ARGS_TRACE_ZeroLengthCidRetire(uniqueId, arg1, encoded_arg_string)\ +tracepoint(CLOG_PATHID_C, ZeroLengthCidRetire , arg1);\ + +#endif + + + + +/*---------------------------------------------------------- +// Decoder Ring for ConnPathIDCloseTimerExpired +// [conn][%p][pathid][%u] Close Timer expired +// QuicTraceEvent( + ConnPathIDCloseTimerExpired, + "[conn][%p][pathid][%u] Close Timer expired", + PathID->Connection, + PathID->ID); +// arg2 = arg2 = PathID->Connection = arg2 +// arg3 = arg3 = PathID->ID = arg3 +----------------------------------------------------------*/ +#ifndef _clog_4_ARGS_TRACE_ConnPathIDCloseTimerExpired +#define _clog_4_ARGS_TRACE_ConnPathIDCloseTimerExpired(uniqueId, encoded_arg_string, arg2, arg3)\ +tracepoint(CLOG_PATHID_C, ConnPathIDCloseTimerExpired , arg2, arg3);\ + +#endif + + + + +/*---------------------------------------------------------- +// Decoder Ring for ConnDestCidAdded +// [conn][%p][pathid][%u] (SeqNum=%llu) New Destination CID: %!CID! +// QuicTraceEvent( + ConnDestCidAdded, + "[conn][%p][pathid][%u] (SeqNum=%llu) New Destination CID: %!CID!", + PathID->Connection, + PathID->ID, + DestCid->CID.SequenceNumber, + CASTED_CLOG_BYTEARRAY(DestCid->CID.Length, DestCid->CID.Data)); +// arg2 = arg2 = PathID->Connection = arg2 +// arg3 = arg3 = PathID->ID = arg3 +// arg4 = arg4 = DestCid->CID.SequenceNumber = arg4 +// arg5 = arg5 = CASTED_CLOG_BYTEARRAY(DestCid->CID.Length, DestCid->CID.Data) = arg5 +----------------------------------------------------------*/ +#ifndef _clog_7_ARGS_TRACE_ConnDestCidAdded +#define _clog_7_ARGS_TRACE_ConnDestCidAdded(uniqueId, encoded_arg_string, arg2, arg3, arg4, arg5, arg5_len)\ +tracepoint(CLOG_PATHID_C, ConnDestCidAdded , arg2, arg3, arg4, arg5_len, arg5);\ + +#endif + + + + +/*---------------------------------------------------------- +// Decoder Ring for ConnSourceCidAdded +// [conn][%p][pathid][%u] (SeqNum=%llu) New Source CID: %!CID! +// QuicTraceEvent( + ConnSourceCidAdded, + "[conn][%p][pathid][%u] (SeqNum=%llu) New Source CID: %!CID!", + PathID->Connection, + PathID->ID, + SourceCid->CID.SequenceNumber, + CASTED_CLOG_BYTEARRAY(SourceCid->CID.Length, SourceCid->CID.Data)); +// arg2 = arg2 = PathID->Connection = arg2 +// arg3 = arg3 = PathID->ID = arg3 +// arg4 = arg4 = SourceCid->CID.SequenceNumber = arg4 +// arg5 = arg5 = CASTED_CLOG_BYTEARRAY(SourceCid->CID.Length, SourceCid->CID.Data) = arg5 +----------------------------------------------------------*/ +#ifndef _clog_7_ARGS_TRACE_ConnSourceCidAdded +#define _clog_7_ARGS_TRACE_ConnSourceCidAdded(uniqueId, encoded_arg_string, arg2, arg3, arg4, arg5, arg5_len)\ +tracepoint(CLOG_PATHID_C, ConnSourceCidAdded , arg2, arg3, arg4, arg5_len, arg5);\ + +#endif + + + + +/*---------------------------------------------------------- +// Decoder Ring for AllocFailure +// Allocation of '%s' failed. (%llu bytes) +// QuicTraceEvent( + AllocFailure, + "Allocation of '%s' failed. (%llu bytes)", + "new Src CID", + sizeof(QUIC_CID_SLIST_ENTRY) + MsQuicLib.CidTotalLength); +// arg2 = arg2 = "new Src CID" = arg2 +// arg3 = arg3 = sizeof(QUIC_CID_SLIST_ENTRY) + MsQuicLib.CidTotalLength = arg3 +----------------------------------------------------------*/ +#ifndef _clog_4_ARGS_TRACE_AllocFailure +#define _clog_4_ARGS_TRACE_AllocFailure(uniqueId, encoded_arg_string, arg2, arg3)\ +tracepoint(CLOG_PATHID_C, AllocFailure , arg2, arg3);\ + +#endif + + + + +/*---------------------------------------------------------- +// Decoder Ring for ConnError +// [conn][%p] ERROR, %s. +// QuicTraceEvent( + ConnError, + "[conn][%p] ERROR, %s.", + PathID->Connection, + "Too many CID collisions"); +// arg2 = arg2 = PathID->Connection = arg2 +// arg3 = arg3 = "Too many CID collisions" = arg3 +----------------------------------------------------------*/ +#ifndef _clog_4_ARGS_TRACE_ConnError +#define _clog_4_ARGS_TRACE_ConnError(uniqueId, encoded_arg_string, arg2, arg3)\ +tracepoint(CLOG_PATHID_C, ConnError , arg2, arg3);\ + +#endif + + + + +/*---------------------------------------------------------- +// Decoder Ring for ConnDestCidRemoved +// [conn][%p][pathid][%u] (SeqNum=%llu) Removed Destination CID: %!CID! +// QuicTraceEvent( + ConnDestCidRemoved, + "[conn][%p][pathid][%u] (SeqNum=%llu) Removed Destination CID: %!CID!", + PathID->Connection, + PathID->ID, + DestCid->CID.SequenceNumber, + CASTED_CLOG_BYTEARRAY(DestCid->CID.Length, DestCid->CID.Data)); +// arg2 = arg2 = PathID->Connection = arg2 +// arg3 = arg3 = PathID->ID = arg3 +// arg4 = arg4 = DestCid->CID.SequenceNumber = arg4 +// arg5 = arg5 = CASTED_CLOG_BYTEARRAY(DestCid->CID.Length, DestCid->CID.Data) = arg5 +----------------------------------------------------------*/ +#ifndef _clog_7_ARGS_TRACE_ConnDestCidRemoved +#define _clog_7_ARGS_TRACE_ConnDestCidRemoved(uniqueId, encoded_arg_string, arg2, arg3, arg4, arg5, arg5_len)\ +tracepoint(CLOG_PATHID_C, ConnDestCidRemoved , arg2, arg3, arg4, arg5_len, arg5);\ + +#endif + + + + +/*---------------------------------------------------------- +// Decoder Ring for ConnDestCidUpdated +// [conn][%p][pathid][%u] (SeqNum=%llu) Updated Destination CID: %!CID! +// QuicTraceEvent( + ConnDestCidUpdated, + "[conn][%p][pathid][%u] (SeqNum=%llu) Updated Destination CID: %!CID!", + PathID->Connection, + PathID->ID, + Path->DestCid->CID.SequenceNumber, + CASTED_CLOG_BYTEARRAY(Path->DestCid->CID.Length, Path->DestCid->CID.Data)); +// arg2 = arg2 = PathID->Connection = arg2 +// arg3 = arg3 = PathID->ID = arg3 +// arg4 = arg4 = Path->DestCid->CID.SequenceNumber = arg4 +// arg5 = arg5 = CASTED_CLOG_BYTEARRAY(Path->DestCid->CID.Length, Path->DestCid->CID.Data) = arg5 +----------------------------------------------------------*/ +#ifndef _clog_7_ARGS_TRACE_ConnDestCidUpdated +#define _clog_7_ARGS_TRACE_ConnDestCidUpdated(uniqueId, encoded_arg_string, arg2, arg3, arg4, arg5, arg5_len)\ +tracepoint(CLOG_PATHID_C, ConnDestCidUpdated , arg2, arg3, arg4, arg5_len, arg5);\ + +#endif + + + + +#ifdef __cplusplus +} +#endif +#ifdef CLOG_INLINE_IMPLEMENTATION +#include "quic.clog_pathid.c.clog.h.c" +#endif diff --git a/src/generated/linux/pathid.c.clog.h.lttng.h b/src/generated/linux/pathid.c.clog.h.lttng.h new file mode 100644 index 0000000000..0820c27512 --- /dev/null +++ b/src/generated/linux/pathid.c.clog.h.lttng.h @@ -0,0 +1,277 @@ + + + +/*---------------------------------------------------------- +// Decoder Ring for NoReplacementCidForRetire +// [conn][%p] Can't retire current CID because we don't have a replacement +// QuicTraceLogConnWarning( + NoReplacementCidForRetire, + PathID->Connection, + "Can't retire current CID because we don't have a replacement"); +// arg1 = arg1 = PathID->Connection = arg1 +----------------------------------------------------------*/ +TRACEPOINT_EVENT(CLOG_PATHID_C, NoReplacementCidForRetire, + TP_ARGS( + const void *, arg1), + TP_FIELDS( + ctf_integer_hex(uint64_t, arg1, (uint64_t)arg1) + ) +) + + + +/*---------------------------------------------------------- +// Decoder Ring for NonActivePathCidRetired +// [conn][%p] Non-active path has no replacement for retired CID. +// QuicTraceLogConnWarning( + NonActivePathCidRetired, + PathID->Connection, + "Non-active path has no replacement for retired CID."); +// arg1 = arg1 = PathID->Connection = arg1 +----------------------------------------------------------*/ +TRACEPOINT_EVENT(CLOG_PATHID_C, NonActivePathCidRetired, + TP_ARGS( + const void *, arg1), + TP_FIELDS( + ctf_integer_hex(uint64_t, arg1, (uint64_t)arg1) + ) +) + + + +/*---------------------------------------------------------- +// Decoder Ring for NewSrcCidNameCollision +// [conn][%p] CID collision, trying again +// QuicTraceLogConnVerbose( + NewSrcCidNameCollision, + PathID->Connection, + "CID collision, trying again"); +// arg1 = arg1 = PathID->Connection = arg1 +----------------------------------------------------------*/ +TRACEPOINT_EVENT(CLOG_PATHID_C, NewSrcCidNameCollision, + TP_ARGS( + const void *, arg1), + TP_FIELDS( + ctf_integer_hex(uint64_t, arg1, (uint64_t)arg1) + ) +) + + + +/*---------------------------------------------------------- +// Decoder Ring for ZeroLengthCidRetire +// [conn][%p] Can't retire current CID because it's zero length +// QuicTraceLogConnVerbose( + ZeroLengthCidRetire, + PathID->Connection, + "Can't retire current CID because it's zero length"); +// arg1 = arg1 = PathID->Connection = arg1 +----------------------------------------------------------*/ +TRACEPOINT_EVENT(CLOG_PATHID_C, ZeroLengthCidRetire, + TP_ARGS( + const void *, arg1), + TP_FIELDS( + ctf_integer_hex(uint64_t, arg1, (uint64_t)arg1) + ) +) + + + +/*---------------------------------------------------------- +// Decoder Ring for ConnPathIDCloseTimerExpired +// [conn][%p][pathid][%u] Close Timer expired +// QuicTraceEvent( + ConnPathIDCloseTimerExpired, + "[conn][%p][pathid][%u] Close Timer expired", + PathID->Connection, + PathID->ID); +// arg2 = arg2 = PathID->Connection = arg2 +// arg3 = arg3 = PathID->ID = arg3 +----------------------------------------------------------*/ +TRACEPOINT_EVENT(CLOG_PATHID_C, ConnPathIDCloseTimerExpired, + TP_ARGS( + const void *, arg2, + unsigned int, arg3), + TP_FIELDS( + ctf_integer_hex(uint64_t, arg2, (uint64_t)arg2) + ctf_integer(unsigned int, arg3, arg3) + ) +) + + + +/*---------------------------------------------------------- +// Decoder Ring for ConnDestCidAdded +// [conn][%p][pathid][%u] (SeqNum=%llu) New Destination CID: %!CID! +// QuicTraceEvent( + ConnDestCidAdded, + "[conn][%p][pathid][%u] (SeqNum=%llu) New Destination CID: %!CID!", + PathID->Connection, + PathID->ID, + DestCid->CID.SequenceNumber, + CASTED_CLOG_BYTEARRAY(DestCid->CID.Length, DestCid->CID.Data)); +// arg2 = arg2 = PathID->Connection = arg2 +// arg3 = arg3 = PathID->ID = arg3 +// arg4 = arg4 = DestCid->CID.SequenceNumber = arg4 +// arg5 = arg5 = CASTED_CLOG_BYTEARRAY(DestCid->CID.Length, DestCid->CID.Data) = arg5 +----------------------------------------------------------*/ +TRACEPOINT_EVENT(CLOG_PATHID_C, ConnDestCidAdded, + TP_ARGS( + const void *, arg2, + unsigned int, arg3, + unsigned long long, arg4, + unsigned int, arg5_len, + const void *, arg5), + TP_FIELDS( + ctf_integer_hex(uint64_t, arg2, (uint64_t)arg2) + ctf_integer(unsigned int, arg3, arg3) + ctf_integer(uint64_t, arg4, arg4) + ctf_integer(unsigned int, arg5_len, arg5_len) + ctf_sequence(char, arg5, arg5, unsigned int, arg5_len) + ) +) + + + +/*---------------------------------------------------------- +// Decoder Ring for ConnSourceCidAdded +// [conn][%p][pathid][%u] (SeqNum=%llu) New Source CID: %!CID! +// QuicTraceEvent( + ConnSourceCidAdded, + "[conn][%p][pathid][%u] (SeqNum=%llu) New Source CID: %!CID!", + PathID->Connection, + PathID->ID, + SourceCid->CID.SequenceNumber, + CASTED_CLOG_BYTEARRAY(SourceCid->CID.Length, SourceCid->CID.Data)); +// arg2 = arg2 = PathID->Connection = arg2 +// arg3 = arg3 = PathID->ID = arg3 +// arg4 = arg4 = SourceCid->CID.SequenceNumber = arg4 +// arg5 = arg5 = CASTED_CLOG_BYTEARRAY(SourceCid->CID.Length, SourceCid->CID.Data) = arg5 +----------------------------------------------------------*/ +TRACEPOINT_EVENT(CLOG_PATHID_C, ConnSourceCidAdded, + TP_ARGS( + const void *, arg2, + unsigned int, arg3, + unsigned long long, arg4, + unsigned int, arg5_len, + const void *, arg5), + TP_FIELDS( + ctf_integer_hex(uint64_t, arg2, (uint64_t)arg2) + ctf_integer(unsigned int, arg3, arg3) + ctf_integer(uint64_t, arg4, arg4) + ctf_integer(unsigned int, arg5_len, arg5_len) + ctf_sequence(char, arg5, arg5, unsigned int, arg5_len) + ) +) + + + +/*---------------------------------------------------------- +// Decoder Ring for AllocFailure +// Allocation of '%s' failed. (%llu bytes) +// QuicTraceEvent( + AllocFailure, + "Allocation of '%s' failed. (%llu bytes)", + "new Src CID", + sizeof(QUIC_CID_SLIST_ENTRY) + MsQuicLib.CidTotalLength); +// arg2 = arg2 = "new Src CID" = arg2 +// arg3 = arg3 = sizeof(QUIC_CID_SLIST_ENTRY) + MsQuicLib.CidTotalLength = arg3 +----------------------------------------------------------*/ +TRACEPOINT_EVENT(CLOG_PATHID_C, AllocFailure, + TP_ARGS( + const char *, arg2, + unsigned long long, arg3), + TP_FIELDS( + ctf_string(arg2, arg2) + ctf_integer(uint64_t, arg3, arg3) + ) +) + + + +/*---------------------------------------------------------- +// Decoder Ring for ConnError +// [conn][%p] ERROR, %s. +// QuicTraceEvent( + ConnError, + "[conn][%p] ERROR, %s.", + PathID->Connection, + "Too many CID collisions"); +// arg2 = arg2 = PathID->Connection = arg2 +// arg3 = arg3 = "Too many CID collisions" = arg3 +----------------------------------------------------------*/ +TRACEPOINT_EVENT(CLOG_PATHID_C, ConnError, + TP_ARGS( + const void *, arg2, + const char *, arg3), + TP_FIELDS( + ctf_integer_hex(uint64_t, arg2, (uint64_t)arg2) + ctf_string(arg3, arg3) + ) +) + + + +/*---------------------------------------------------------- +// Decoder Ring for ConnDestCidRemoved +// [conn][%p][pathid][%u] (SeqNum=%llu) Removed Destination CID: %!CID! +// QuicTraceEvent( + ConnDestCidRemoved, + "[conn][%p][pathid][%u] (SeqNum=%llu) Removed Destination CID: %!CID!", + PathID->Connection, + PathID->ID, + DestCid->CID.SequenceNumber, + CASTED_CLOG_BYTEARRAY(DestCid->CID.Length, DestCid->CID.Data)); +// arg2 = arg2 = PathID->Connection = arg2 +// arg3 = arg3 = PathID->ID = arg3 +// arg4 = arg4 = DestCid->CID.SequenceNumber = arg4 +// arg5 = arg5 = CASTED_CLOG_BYTEARRAY(DestCid->CID.Length, DestCid->CID.Data) = arg5 +----------------------------------------------------------*/ +TRACEPOINT_EVENT(CLOG_PATHID_C, ConnDestCidRemoved, + TP_ARGS( + const void *, arg2, + unsigned int, arg3, + unsigned long long, arg4, + unsigned int, arg5_len, + const void *, arg5), + TP_FIELDS( + ctf_integer_hex(uint64_t, arg2, (uint64_t)arg2) + ctf_integer(unsigned int, arg3, arg3) + ctf_integer(uint64_t, arg4, arg4) + ctf_integer(unsigned int, arg5_len, arg5_len) + ctf_sequence(char, arg5, arg5, unsigned int, arg5_len) + ) +) + + + +/*---------------------------------------------------------- +// Decoder Ring for ConnDestCidUpdated +// [conn][%p][pathid][%u] (SeqNum=%llu) Updated Destination CID: %!CID! +// QuicTraceEvent( + ConnDestCidUpdated, + "[conn][%p][pathid][%u] (SeqNum=%llu) Updated Destination CID: %!CID!", + PathID->Connection, + PathID->ID, + Path->DestCid->CID.SequenceNumber, + CASTED_CLOG_BYTEARRAY(Path->DestCid->CID.Length, Path->DestCid->CID.Data)); +// arg2 = arg2 = PathID->Connection = arg2 +// arg3 = arg3 = PathID->ID = arg3 +// arg4 = arg4 = Path->DestCid->CID.SequenceNumber = arg4 +// arg5 = arg5 = CASTED_CLOG_BYTEARRAY(Path->DestCid->CID.Length, Path->DestCid->CID.Data) = arg5 +----------------------------------------------------------*/ +TRACEPOINT_EVENT(CLOG_PATHID_C, ConnDestCidUpdated, + TP_ARGS( + const void *, arg2, + unsigned int, arg3, + unsigned long long, arg4, + unsigned int, arg5_len, + const void *, arg5), + TP_FIELDS( + ctf_integer_hex(uint64_t, arg2, (uint64_t)arg2) + ctf_integer(unsigned int, arg3, arg3) + ctf_integer(uint64_t, arg4, arg4) + ctf_integer(unsigned int, arg5_len, arg5_len) + ctf_sequence(char, arg5, arg5, unsigned int, arg5_len) + ) +) diff --git a/src/generated/linux/pathid.h.clog.h b/src/generated/linux/pathid.h.clog.h new file mode 100644 index 0000000000..1ac67cc872 --- /dev/null +++ b/src/generated/linux/pathid.h.clog.h @@ -0,0 +1,53 @@ +#ifndef CLOG_DO_NOT_INCLUDE_HEADER +#include +#endif +#undef TRACEPOINT_PROVIDER +#define TRACEPOINT_PROVIDER CLOG_PATHID_H +#undef TRACEPOINT_PROBE_DYNAMIC_LINKAGE +#define TRACEPOINT_PROBE_DYNAMIC_LINKAGE +#undef TRACEPOINT_INCLUDE +#define TRACEPOINT_INCLUDE "pathid.h.clog.h.lttng.h" +#if !defined(DEF_CLOG_PATHID_H) || defined(TRACEPOINT_HEADER_MULTI_READ) +#define DEF_CLOG_PATHID_H +#include +#define __int64 __int64_t +#include "pathid.h.clog.h.lttng.h" +#endif +#include +#ifndef _clog_MACRO_QuicTraceEvent +#define _clog_MACRO_QuicTraceEvent 1 +#define QuicTraceEvent(a, ...) _clog_CAT(_clog_ARGN_SELECTOR(__VA_ARGS__), _clog_CAT(_,a(#a, __VA_ARGS__))) +#endif +#ifdef __cplusplus +extern "C" { +#endif +/*---------------------------------------------------------- +// Decoder Ring for ConnSourceCidRemoved +// [conn][%p][pathid][%u] (SeqNum=%llu) Removed Source CID: %!CID! +// QuicTraceEvent( + ConnSourceCidRemoved, + "[conn][%p][pathid][%u] (SeqNum=%llu) Removed Source CID: %!CID!", + PathID->Connection, + PathID->ID, + SourceCid->CID.SequenceNumber, + CASTED_CLOG_BYTEARRAY(SourceCid->CID.Length, SourceCid->CID.Data)); +// arg2 = arg2 = PathID->Connection = arg2 +// arg3 = arg3 = PathID->ID = arg3 +// arg4 = arg4 = SourceCid->CID.SequenceNumber = arg4 +// arg5 = arg5 = CASTED_CLOG_BYTEARRAY(SourceCid->CID.Length, SourceCid->CID.Data) = arg5 +----------------------------------------------------------*/ +#ifndef _clog_7_ARGS_TRACE_ConnSourceCidRemoved +#define _clog_7_ARGS_TRACE_ConnSourceCidRemoved(uniqueId, encoded_arg_string, arg2, arg3, arg4, arg5, arg5_len)\ +tracepoint(CLOG_PATHID_H, ConnSourceCidRemoved , arg2, arg3, arg4, arg5_len, arg5);\ + +#endif + + + + +#ifdef __cplusplus +} +#endif +#ifdef CLOG_INLINE_IMPLEMENTATION +#include "quic.clog_pathid.h.clog.h.c" +#endif diff --git a/src/generated/linux/pathid.h.clog.h.lttng.h b/src/generated/linux/pathid.h.clog.h.lttng.h new file mode 100644 index 0000000000..77cc01558b --- /dev/null +++ b/src/generated/linux/pathid.h.clog.h.lttng.h @@ -0,0 +1,33 @@ + + + +/*---------------------------------------------------------- +// Decoder Ring for ConnSourceCidRemoved +// [conn][%p][pathid][%u] (SeqNum=%llu) Removed Source CID: %!CID! +// QuicTraceEvent( + ConnSourceCidRemoved, + "[conn][%p][pathid][%u] (SeqNum=%llu) Removed Source CID: %!CID!", + PathID->Connection, + PathID->ID, + SourceCid->CID.SequenceNumber, + CASTED_CLOG_BYTEARRAY(SourceCid->CID.Length, SourceCid->CID.Data)); +// arg2 = arg2 = PathID->Connection = arg2 +// arg3 = arg3 = PathID->ID = arg3 +// arg4 = arg4 = SourceCid->CID.SequenceNumber = arg4 +// arg5 = arg5 = CASTED_CLOG_BYTEARRAY(SourceCid->CID.Length, SourceCid->CID.Data) = arg5 +----------------------------------------------------------*/ +TRACEPOINT_EVENT(CLOG_PATHID_H, ConnSourceCidRemoved, + TP_ARGS( + const void *, arg2, + unsigned int, arg3, + unsigned long long, arg4, + unsigned int, arg5_len, + const void *, arg5), + TP_FIELDS( + ctf_integer_hex(uint64_t, arg2, (uint64_t)arg2) + ctf_integer(unsigned int, arg3, arg3) + ctf_integer(uint64_t, arg4, arg4) + ctf_integer(unsigned int, arg5_len, arg5_len) + ctf_sequence(char, arg5, arg5, unsigned int, arg5_len) + ) +) diff --git a/src/generated/linux/pathid_set.c.clog.h b/src/generated/linux/pathid_set.c.clog.h new file mode 100644 index 0000000000..8ebe3f4a79 --- /dev/null +++ b/src/generated/linux/pathid_set.c.clog.h @@ -0,0 +1,133 @@ +#ifndef CLOG_DO_NOT_INCLUDE_HEADER +#include +#endif +#undef TRACEPOINT_PROVIDER +#define TRACEPOINT_PROVIDER CLOG_PATHID_SET_C +#undef TRACEPOINT_PROBE_DYNAMIC_LINKAGE +#define TRACEPOINT_PROBE_DYNAMIC_LINKAGE +#undef TRACEPOINT_INCLUDE +#define TRACEPOINT_INCLUDE "pathid_set.c.clog.h.lttng.h" +#if !defined(DEF_CLOG_PATHID_SET_C) || defined(TRACEPOINT_HEADER_MULTI_READ) +#define DEF_CLOG_PATHID_SET_C +#include +#define __int64 __int64_t +#include "pathid_set.c.clog.h.lttng.h" +#endif +#include +#ifndef _clog_MACRO_QuicTraceLogConnVerbose +#define _clog_MACRO_QuicTraceLogConnVerbose 1 +#define QuicTraceLogConnVerbose(a, ...) _clog_CAT(_clog_ARGN_SELECTOR(__VA_ARGS__), _clog_CAT(_,a(#a, __VA_ARGS__))) +#endif +#ifndef _clog_MACRO_QuicTraceEvent +#define _clog_MACRO_QuicTraceEvent 1 +#define QuicTraceEvent(a, ...) _clog_CAT(_clog_ARGN_SELECTOR(__VA_ARGS__), _clog_CAT(_,a(#a, __VA_ARGS__))) +#endif +#ifdef __cplusplus +extern "C" { +#endif +/*---------------------------------------------------------- +// Decoder Ring for PeerMaxPathIDUpdated +// [conn][%p] Peer updated max path id (%u). +// QuicTraceLogConnVerbose( + PeerMaxPathIDUpdated, + QuicPathIDSetGetConnection(PathIDSet), + "Peer updated max path id (%u).", + MaxPathID); +// arg1 = arg1 = QuicPathIDSetGetConnection(PathIDSet) = arg1 +// arg3 = arg3 = MaxPathID = arg3 +----------------------------------------------------------*/ +#ifndef _clog_4_ARGS_TRACE_PeerMaxPathIDUpdated +#define _clog_4_ARGS_TRACE_PeerMaxPathIDUpdated(uniqueId, arg1, encoded_arg_string, arg3)\ +tracepoint(CLOG_PATHID_SET_C, PeerMaxPathIDUpdated , arg1, arg3);\ + +#endif + + + + +/*---------------------------------------------------------- +// Decoder Ring for AllocFailure +// Allocation of '%s' failed. (%llu bytes) +// QuicTraceEvent( + AllocFailure, + "Allocation of '%s' failed. (%llu bytes)", + "pathid hash table", + 0); +// arg2 = arg2 = "pathid hash table" = arg2 +// arg3 = arg3 = 0 = arg3 +----------------------------------------------------------*/ +#ifndef _clog_4_ARGS_TRACE_AllocFailure +#define _clog_4_ARGS_TRACE_AllocFailure(uniqueId, encoded_arg_string, arg2, arg3)\ +tracepoint(CLOG_PATHID_SET_C, AllocFailure , arg2, arg3);\ + +#endif + + + + +/*---------------------------------------------------------- +// Decoder Ring for ConnPathIDRemove +// [conn][%p] Removed PathID %u +// QuicTraceEvent( + ConnPathIDRemove, + "[conn][%p] Removed PathID %u", + Connection, + PathID->ID); +// arg2 = arg2 = Connection = arg2 +// arg3 = arg3 = PathID->ID = arg3 +----------------------------------------------------------*/ +#ifndef _clog_4_ARGS_TRACE_ConnPathIDRemove +#define _clog_4_ARGS_TRACE_ConnPathIDRemove(uniqueId, encoded_arg_string, arg2, arg3)\ +tracepoint(CLOG_PATHID_SET_C, ConnPathIDRemove , arg2, arg3);\ + +#endif + + + + +/*---------------------------------------------------------- +// Decoder Ring for ConnError +// [conn][%p] ERROR, %s. +// QuicTraceEvent( + ConnError, + "[conn][%p] ERROR, %s.", + QuicPathIDSetGetConnection(PathIDSet), + "Failed to generate new path ID"); +// arg2 = arg2 = QuicPathIDSetGetConnection(PathIDSet) = arg2 +// arg3 = arg3 = "Failed to generate new path ID" = arg3 +----------------------------------------------------------*/ +#ifndef _clog_4_ARGS_TRACE_ConnError +#define _clog_4_ARGS_TRACE_ConnError(uniqueId, encoded_arg_string, arg2, arg3)\ +tracepoint(CLOG_PATHID_SET_C, ConnError , arg2, arg3);\ + +#endif + + + + +/*---------------------------------------------------------- +// Decoder Ring for ConnPathIDAdd +// [conn][%p] Added New PathID %u +// QuicTraceEvent( + ConnPathIDAdd, + "[conn][%p] Added New PathID %u", + QuicPathIDSetGetConnection(PathIDSet), + PathID->ID); +// arg2 = arg2 = QuicPathIDSetGetConnection(PathIDSet) = arg2 +// arg3 = arg3 = PathID->ID = arg3 +----------------------------------------------------------*/ +#ifndef _clog_4_ARGS_TRACE_ConnPathIDAdd +#define _clog_4_ARGS_TRACE_ConnPathIDAdd(uniqueId, encoded_arg_string, arg2, arg3)\ +tracepoint(CLOG_PATHID_SET_C, ConnPathIDAdd , arg2, arg3);\ + +#endif + + + + +#ifdef __cplusplus +} +#endif +#ifdef CLOG_INLINE_IMPLEMENTATION +#include "quic.clog_pathid_set.c.clog.h.c" +#endif diff --git a/src/generated/linux/pathid_set.c.clog.h.lttng.h b/src/generated/linux/pathid_set.c.clog.h.lttng.h new file mode 100644 index 0000000000..c365c0ca21 --- /dev/null +++ b/src/generated/linux/pathid_set.c.clog.h.lttng.h @@ -0,0 +1,115 @@ + + + +/*---------------------------------------------------------- +// Decoder Ring for PeerMaxPathIDUpdated +// [conn][%p] Peer updated max path id (%u). +// QuicTraceLogConnVerbose( + PeerMaxPathIDUpdated, + QuicPathIDSetGetConnection(PathIDSet), + "Peer updated max path id (%u).", + MaxPathID); +// arg1 = arg1 = QuicPathIDSetGetConnection(PathIDSet) = arg1 +// arg3 = arg3 = MaxPathID = arg3 +----------------------------------------------------------*/ +TRACEPOINT_EVENT(CLOG_PATHID_SET_C, PeerMaxPathIDUpdated, + TP_ARGS( + const void *, arg1, + unsigned int, arg3), + TP_FIELDS( + ctf_integer_hex(uint64_t, arg1, (uint64_t)arg1) + ctf_integer(unsigned int, arg3, arg3) + ) +) + + + +/*---------------------------------------------------------- +// Decoder Ring for AllocFailure +// Allocation of '%s' failed. (%llu bytes) +// QuicTraceEvent( + AllocFailure, + "Allocation of '%s' failed. (%llu bytes)", + "pathid hash table", + 0); +// arg2 = arg2 = "pathid hash table" = arg2 +// arg3 = arg3 = 0 = arg3 +----------------------------------------------------------*/ +TRACEPOINT_EVENT(CLOG_PATHID_SET_C, AllocFailure, + TP_ARGS( + const char *, arg2, + unsigned long long, arg3), + TP_FIELDS( + ctf_string(arg2, arg2) + ctf_integer(uint64_t, arg3, arg3) + ) +) + + + +/*---------------------------------------------------------- +// Decoder Ring for ConnPathIDRemove +// [conn][%p] Removed PathID %u +// QuicTraceEvent( + ConnPathIDRemove, + "[conn][%p] Removed PathID %u", + Connection, + PathID->ID); +// arg2 = arg2 = Connection = arg2 +// arg3 = arg3 = PathID->ID = arg3 +----------------------------------------------------------*/ +TRACEPOINT_EVENT(CLOG_PATHID_SET_C, ConnPathIDRemove, + TP_ARGS( + const void *, arg2, + unsigned int, arg3), + TP_FIELDS( + ctf_integer_hex(uint64_t, arg2, (uint64_t)arg2) + ctf_integer(unsigned int, arg3, arg3) + ) +) + + + +/*---------------------------------------------------------- +// Decoder Ring for ConnError +// [conn][%p] ERROR, %s. +// QuicTraceEvent( + ConnError, + "[conn][%p] ERROR, %s.", + QuicPathIDSetGetConnection(PathIDSet), + "Failed to generate new path ID"); +// arg2 = arg2 = QuicPathIDSetGetConnection(PathIDSet) = arg2 +// arg3 = arg3 = "Failed to generate new path ID" = arg3 +----------------------------------------------------------*/ +TRACEPOINT_EVENT(CLOG_PATHID_SET_C, ConnError, + TP_ARGS( + const void *, arg2, + const char *, arg3), + TP_FIELDS( + ctf_integer_hex(uint64_t, arg2, (uint64_t)arg2) + ctf_string(arg3, arg3) + ) +) + + + +/*---------------------------------------------------------- +// Decoder Ring for ConnPathIDAdd +// [conn][%p] Added New PathID %u +// QuicTraceEvent( + ConnPathIDAdd, + "[conn][%p] Added New PathID %u", + QuicPathIDSetGetConnection(PathIDSet), + PathID->ID); +// arg2 = arg2 = QuicPathIDSetGetConnection(PathIDSet) = arg2 +// arg3 = arg3 = PathID->ID = arg3 +----------------------------------------------------------*/ +TRACEPOINT_EVENT(CLOG_PATHID_SET_C, ConnPathIDAdd, + TP_ARGS( + const void *, arg2, + unsigned int, arg3), + TP_FIELDS( + ctf_integer_hex(uint64_t, arg2, (uint64_t)arg2) + ctf_integer(unsigned int, arg3, arg3) + ) +) diff --git a/src/generated/linux/quic.clog_pathid.c.clog.h.c b/src/generated/linux/quic.clog_pathid.c.clog.h.c new file mode 100644 index 0000000000..c9108634a2 --- /dev/null +++ b/src/generated/linux/quic.clog_pathid.c.clog.h.c @@ -0,0 +1,7 @@ +#include +#ifdef BUILDING_TRACEPOINT_PROVIDER +#define TRACEPOINT_CREATE_PROBES +#else +#define TRACEPOINT_DEFINE +#endif +#include "pathid.c.clog.h" diff --git a/src/generated/linux/quic.clog_pathid.h.clog.h.c b/src/generated/linux/quic.clog_pathid.h.clog.h.c new file mode 100644 index 0000000000..c89f2869ce --- /dev/null +++ b/src/generated/linux/quic.clog_pathid.h.clog.h.c @@ -0,0 +1,7 @@ +#include +#ifdef BUILDING_TRACEPOINT_PROVIDER +#define TRACEPOINT_CREATE_PROBES +#else +#define TRACEPOINT_DEFINE +#endif +#include "pathid.h.clog.h" diff --git a/src/generated/linux/quic.clog_pathid_set.c.clog.h.c b/src/generated/linux/quic.clog_pathid_set.c.clog.h.c new file mode 100644 index 0000000000..a2739f87ff --- /dev/null +++ b/src/generated/linux/quic.clog_pathid_set.c.clog.h.c @@ -0,0 +1,7 @@ +#include +#ifdef BUILDING_TRACEPOINT_PROVIDER +#define TRACEPOINT_CREATE_PROBES +#else +#define TRACEPOINT_DEFINE +#endif +#include "pathid_set.c.clog.h" diff --git a/src/generated/linux/settings.c.clog.h b/src/generated/linux/settings.c.clog.h index ddf319a195..81a156143f 100644 --- a/src/generated/linux/settings.c.clog.h +++ b/src/generated/linux/settings.c.clog.h @@ -797,6 +797,21 @@ tracepoint(CLOG_SETTINGS_C, SettingsStreamMultiReceiveEnabled , arg2);\ +/*---------------------------------------------------------- +// Decoder Ring for SettingMultipathEnabled +// [sett] MultipathEnabled = %hhu +// QuicTraceLogVerbose(SettingMultipathEnabled, "[sett] MultipathEnabled = %hhu", Settings->MultipathEnabled); +// arg2 = arg2 = Settings->MultipathEnabled = arg2 +----------------------------------------------------------*/ +#ifndef _clog_3_ARGS_TRACE_SettingMultipathEnabled +#define _clog_3_ARGS_TRACE_SettingMultipathEnabled(uniqueId, encoded_arg_string, arg2)\ +tracepoint(CLOG_SETTINGS_C, SettingMultipathEnabled , arg2);\ + +#endif + + + + /*---------------------------------------------------------- // Decoder Ring for SettingDumpLFixedServerID // [sett] FixedServerID = %u @@ -842,6 +857,21 @@ tracepoint(CLOG_SETTINGS_C, SettingStreamMultiReceiveEnabled , arg2);\ +/*---------------------------------------------------------- +// Decoder Ring for SettingConnIDGenDisabled +// [sett] ConnIDGenDisabled = %hhu +// QuicTraceLogVerbose(SettingConnIDGenDisabled, "[sett] ConnIDGenDisabled = %hhu", Settings->ConnIDGenDisabled); +// arg2 = arg2 = Settings->ConnIDGenDisabled = arg2 +----------------------------------------------------------*/ +#ifndef _clog_3_ARGS_TRACE_SettingConnIDGenDisabled +#define _clog_3_ARGS_TRACE_SettingConnIDGenDisabled(uniqueId, encoded_arg_string, arg2)\ +tracepoint(CLOG_SETTINGS_C, SettingConnIDGenDisabled , arg2);\ + +#endif + + + + /*---------------------------------------------------------- // Decoder Ring for SettingsLoadInvalidAcceptableVersion // Invalid AcceptableVersion loaded from storage! 0x%x at position %d diff --git a/src/generated/linux/settings.c.clog.h.lttng.h b/src/generated/linux/settings.c.clog.h.lttng.h index c168d96477..0a320b3721 100644 --- a/src/generated/linux/settings.c.clog.h.lttng.h +++ b/src/generated/linux/settings.c.clog.h.lttng.h @@ -826,6 +826,22 @@ TRACEPOINT_EVENT(CLOG_SETTINGS_C, SettingsStreamMultiReceiveEnabled, +/*---------------------------------------------------------- +// Decoder Ring for SettingMultipathEnabled +// [sett] MultipathEnabled = %hhu +// QuicTraceLogVerbose(SettingMultipathEnabled, "[sett] MultipathEnabled = %hhu", Settings->MultipathEnabled); +// arg2 = arg2 = Settings->MultipathEnabled = arg2 +----------------------------------------------------------*/ +TRACEPOINT_EVENT(CLOG_SETTINGS_C, SettingMultipathEnabled, + TP_ARGS( + unsigned char, arg2), + TP_FIELDS( + ctf_integer(unsigned char, arg2, arg2) + ) +) + + + /*---------------------------------------------------------- // Decoder Ring for SettingDumpLFixedServerID // [sett] FixedServerID = %u @@ -874,6 +890,22 @@ TRACEPOINT_EVENT(CLOG_SETTINGS_C, SettingStreamMultiReceiveEnabled, +/*---------------------------------------------------------- +// Decoder Ring for SettingConnIDGenDisabled +// [sett] ConnIDGenDisabled = %hhu +// QuicTraceLogVerbose(SettingConnIDGenDisabled, "[sett] ConnIDGenDisabled = %hhu", Settings->ConnIDGenDisabled); +// arg2 = arg2 = Settings->ConnIDGenDisabled = arg2 +----------------------------------------------------------*/ +TRACEPOINT_EVENT(CLOG_SETTINGS_C, SettingConnIDGenDisabled, + TP_ARGS( + unsigned char, arg2), + TP_FIELDS( + ctf_integer(unsigned char, arg2, arg2) + ) +) + + + /*---------------------------------------------------------- // Decoder Ring for SettingsLoadInvalidAcceptableVersion // Invalid AcceptableVersion loaded from storage! 0x%x at position %d diff --git a/src/inc/msquic.h b/src/inc/msquic.h index 825bfb8a6a..761680ad38 100644 --- a/src/inc/msquic.h +++ b/src/inc/msquic.h @@ -626,6 +626,13 @@ typedef struct QUIC_VERSION_SETTINGS { uint32_t FullyDeployedVersionsLength; } QUIC_VERSION_SETTINGS; + +typedef struct QUIC_PATH_STATUS { + QUIC_ADDR PeerAddress; + QUIC_ADDR LocalAddress; + uint32_t PathId; + BOOLEAN Active; +} QUIC_PATH_STATUS; #endif typedef struct QUIC_GLOBAL_SETTINGS { @@ -692,7 +699,8 @@ typedef struct QUIC_SETTINGS { uint64_t OneWayDelayEnabled : 1; uint64_t NetStatsEventEnabled : 1; uint64_t StreamMultiReceiveEnabled : 1; - uint64_t RESERVED : 21; + uint64_t MultipathEnabled : 1; + uint64_t RESERVED : 20; #else uint64_t RESERVED : 26; #endif @@ -743,7 +751,8 @@ typedef struct QUIC_SETTINGS { uint64_t OneWayDelayEnabled : 1; uint64_t NetStatsEventEnabled : 1; uint64_t StreamMultiReceiveEnabled : 1; - uint64_t ReservedFlags : 58; + uint64_t MultipathEnabled : 1; + uint64_t ReservedFlags : 57; #else uint64_t ReservedFlags : 63; #endif @@ -922,6 +931,11 @@ 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[] +#ifdef QUIC_API_ENABLE_PREVIEW_FEATURES +#define QUIC_PARAM_CONN_ADD_LOCAL_ADDRESS 0x05000019 // QUIC_ADDR +#define QUIC_PARAM_CONN_REMOVE_LOCAL_ADDRESS 0x0500001A // QUIC_ADDR +#define QUIC_PARAM_CONN_PATH_STATUS 0x0500001B // QUIC_PATH_STATUS +#endif // // Parameters for TLS. @@ -1179,6 +1193,9 @@ typedef enum QUIC_CONNECTION_EVENT_TYPE { QUIC_CONNECTION_EVENT_RELIABLE_RESET_NEGOTIATED = 16, // Only indicated if QUIC_SETTINGS.ReliableResetEnabled is TRUE. QUIC_CONNECTION_EVENT_ONE_WAY_DELAY_NEGOTIATED = 17, // Only indicated if QUIC_SETTINGS.OneWayDelayEnabled is TRUE. QUIC_CONNECTION_EVENT_NETWORK_STATISTICS = 18, // Only indicated if QUIC_SETTINGS.EnableNetStatsEvent is TRUE. + QUIC_CONNECTION_EVENT_PATH_ADDED = 19, // Only indicated if QUIC_SETTINGS.EnableMultipath is TRUE. + QUIC_CONNECTION_EVENT_PATH_REMOVED = 20, // Only indicated if QUIC_SETTINGS.EnableMultipath is TRUE. + QUIC_CONNECTION_EVENT_PATH_STATUS_CHANGED = 21, // Only indicated if QUIC_SETTINGS.EnableMultipath is TRUE. #endif } QUIC_CONNECTION_EVENT_TYPE; @@ -1269,6 +1286,22 @@ typedef struct QUIC_CONNECTION_EVENT { uint32_t CongestionWindow; // Congestion Window uint64_t Bandwidth; // Estimated bandwidth } NETWORK_STATISTICS; + struct { + const QUIC_ADDR* PeerAddress; + const QUIC_ADDR* LocalAddress; + uint32_t PathId; + } PATH_ADDED; + struct { + const QUIC_ADDR* PeerAddress; + const QUIC_ADDR* LocalAddress; + uint32_t PathId; + } PATH_REMOVED; + struct { + const QUIC_ADDR* PeerAddress; + const QUIC_ADDR* LocalAddress; + uint32_t PathId; + BOOLEAN IsActive; + } PATH_STATUS_CHANGED; #endif }; } QUIC_CONNECTION_EVENT; diff --git a/src/inc/msquic.hpp b/src/inc/msquic.hpp index f051e84139..fe80a4c50b 100644 --- a/src/inc/msquic.hpp +++ b/src/inc/msquic.hpp @@ -596,6 +596,7 @@ class MsQuicSettings : public QUIC_SETTINGS { MsQuicSettings& SetOneWayDelayEnabled(bool value) { OneWayDelayEnabled = value; IsSet.OneWayDelayEnabled = TRUE; return *this; } MsQuicSettings& SetNetStatsEventEnabled(bool value) { NetStatsEventEnabled = value; IsSet.NetStatsEventEnabled = TRUE; return *this; } MsQuicSettings& SetStreamMultiReceiveEnabled(bool value) { StreamMultiReceiveEnabled = value; IsSet.StreamMultiReceiveEnabled = TRUE; return *this; } + MsQuicSettings& SetMultipathEnabled(bool value) { MultipathEnabled = value; IsSet.MultipathEnabled = TRUE; return *this; } #endif QUIC_STATUS @@ -741,6 +742,24 @@ struct MsQuicConfiguration { MsQuicConfiguration(const MsQuicConfiguration& Other) = delete; MsQuicConfiguration& operator=(const MsQuicConfiguration& Other) = delete; QUIC_STATUS + SetParam( + _In_ uint32_t Param, + _In_ uint32_t BufferLength, + _In_reads_bytes_(BufferLength) + const void* Buffer + ) noexcept { + return MsQuic->SetParam(Handle, Param, BufferLength, Buffer); + } + QUIC_STATUS + GetParam( + _In_ uint32_t Param, + _Inout_ _Pre_defensive_ uint32_t* BufferLength, + _Out_writes_bytes_opt_(*BufferLength) + void* Buffer + ) noexcept { + return MsQuic->GetParam(Handle, Param, BufferLength, Buffer); + } + QUIC_STATUS LoadCredential(_In_ const QUIC_CREDENTIAL_CONFIG* CredConfig) noexcept { return MsQuic->ConfigurationLoadCredential(Handle, CredConfig); } diff --git a/src/inc/msquic_posix.h b/src/inc/msquic_posix.h index 27393e1233..d69e187d0b 100644 --- a/src/inc/msquic_posix.h +++ b/src/inc/msquic_posix.h @@ -127,6 +127,7 @@ inline ENUMTYPE &operator ^= (ENUMTYPE &a, ENUMTYPE b) throw() { return (ENUMTYP #define QUIC_STATUS_USER_CANCELED ((QUIC_STATUS)EOWNERDEAD) // 130 (105 on macOS) #define QUIC_STATUS_ALPN_NEG_FAILURE ((QUIC_STATUS)ENOPROTOOPT) // 92 (42 on macOS) #define QUIC_STATUS_STREAM_LIMIT_REACHED ((QUIC_STATUS)ESTRPIPE) // 86 +#define QUIC_STATUS_PATHID_LIMIT_REACHED ((QUIC_STATUS)ESTRPIPE) // 86 #define QUIC_STATUS_ALPN_IN_USE ((QUIC_STATUS)EPROTOTYPE) // 91 (41 on macOS) #define QUIC_STATUS_ADDRESS_NOT_AVAILABLE ((QUIC_STATUS)EADDRNOTAVAIL) // 99 (47 on macOS) diff --git a/src/inc/msquic_winuser.h b/src/inc/msquic_winuser.h index adc2f2292e..92af41116d 100644 --- a/src/inc/msquic_winuser.h +++ b/src/inc/msquic_winuser.h @@ -81,6 +81,10 @@ #define ERROR_QUIC_ALPN_IN_USE _HRESULT_TYPEDEF_(0x80410009L) #endif +#ifndef ERROR_QUIC_PATHID_LIMIT_REACHED +#define ERROR_QUIC_PATHID_LIMIT_REACHED _HRESULT_TYPEDEF_(0x8041000AL) +#endif + #ifndef QUIC_TLS_ALERT_HRESULT_PREFIX #define QUIC_TLS_ALERT_HRESULT_PREFIX _HRESULT_TYPEDEF_(0x80410100L) #endif @@ -116,6 +120,7 @@ #define QUIC_STATUS_ALPN_NEG_FAILURE ERROR_QUIC_ALPN_NEG_FAILURE // 0x80410007 #define QUIC_STATUS_STREAM_LIMIT_REACHED ERROR_QUIC_STREAM_LIMIT_REACHED // 0x80410008 #define QUIC_STATUS_ALPN_IN_USE ERROR_QUIC_ALPN_IN_USE // 0x80410009 +#define QUIC_STATUS_PATHID_LIMIT_REACHED ERROR_QUIC_PATHID_LIMIT_REACHED // 0x8041000A #define QUIC_STATUS_TLS_ALERT(Alert) (QUIC_TLS_ALERT_HRESULT_PREFIX | (0xff & Alert)) diff --git a/src/inc/msquicp.h b/src/inc/msquicp.h index 138a880c74..70e73b1a6a 100644 --- a/src/inc/msquicp.h +++ b/src/inc/msquicp.h @@ -93,6 +93,11 @@ typedef struct QUIC_TEST_DATAPATH_HOOKS { // negotiation transport parameter. // #define QUIC_TEST_DISABLE_VNE_TP_GENERATION 1 + +// +// Enable support to disable automatic generation of connection ID. +// +#define QUIC_TEST_MANUAL_CONN_ID_GENERATION 1 #endif typedef struct QUIC_PRIVATE_TRANSPORT_PARAMETER { @@ -125,6 +130,7 @@ typedef struct QUIC_PRIVATE_TRANSPORT_PARAMETER { #ifdef QUIC_API_ENABLE_PREVIEW_FEATURES #define QUIC_PARAM_CONFIGURATION_VERSION_NEG_ENABLED 0x83000001 // BOOLEAN #endif +#define QUIC_PARAM_CONFIGURATION_CONN_ID_GENERATION_DISABLED 0x83000002 // BOOLEAN // // The different private parameters for Connection. @@ -135,6 +141,8 @@ typedef struct QUIC_PRIVATE_TRANSPORT_PARAMETER { #define QUIC_PARAM_CONN_TEST_TRANSPORT_PARAMETER 0x85000002 // QUIC_PRIVATE_TRANSPORT_PARAMETER #define QUIC_PARAM_CONN_KEEP_ALIVE_PADDING 0x85000003 // uint16_t #define QUIC_PARAM_CONN_DISABLE_VNE_TP_GENERATION 0x85000004 // BOOLEAN +#define QUIC_PARAM_CONN_DISABLE_CONN_ID_GENERATION 0x85000005 // BOOLEAN +#define QUIC_PARAM_CONN_GENERATE_CONN_ID 0x85000006 // No payload #ifdef QUIC_API_ENABLE_PREVIEW_FEATURES #define QUIC_PARAM_STREAM_RELIABLE_OFFSET_RECV 0x88000000 // uint64_t diff --git a/src/inc/quic_crypt.h b/src/inc/quic_crypt.h index bc1633ce32..380dc21bdf 100644 --- a/src/inc/quic_crypt.h +++ b/src/inc/quic_crypt.h @@ -282,6 +282,39 @@ QuicCryptoCombineIvAndPacketNumber( IvOut[11] = IvIn[11] ^ PacketNumber[0]; } +inline +void +QuicCryptoCombineIvAndPathIDAndPacketNumber( + _In_reads_bytes_(CXPLAT_IV_LENGTH) + const uint8_t* const IvIn, + _In_reads_bytes_(sizeof(uint32_t)) + const uint8_t* const PathID, + _In_reads_bytes_(sizeof(uint64_t)) + const uint8_t* const PacketNumber, + _Out_writes_bytes_(CXPLAT_IV_LENGTH) + uint8_t* IvOut + ) +{ + // + // XOR the packet number with the IV. + // Because PacketNumber is in host-order (little-endian), and the protocol + // expects it to be XORed in network-order, count down from the "end" of + // PacketNumber while counting up to the end of IV when doing the XOR. + // + IvOut[0] = IvIn[0] ^ PathID[3]; + IvOut[1] = IvIn[1] ^ PathID[2]; + IvOut[2] = IvIn[2] ^ PathID[1]; + IvOut[3] = IvIn[3] ^ PathID[0]; + IvOut[4] = IvIn[4] ^ PacketNumber[7]; + IvOut[5] = IvIn[5] ^ PacketNumber[6]; + IvOut[6] = IvIn[6] ^ PacketNumber[5]; + IvOut[7] = IvIn[7] ^ PacketNumber[4]; + IvOut[8] = IvIn[8] ^ PacketNumber[3]; + IvOut[9] = IvIn[9] ^ PacketNumber[2]; + IvOut[10] = IvIn[10] ^ PacketNumber[1]; + IvOut[11] = IvIn[11] ^ PacketNumber[0]; +} + // // Encrypts buffer with the given key. 'BufferLength' includes the extra space // that should be preallocated for the overhead, as indicated by diff --git a/src/inc/quic_platform.h b/src/inc/quic_platform.h index ceaa6cdcd8..dede8ea1c6 100644 --- a/src/inc/quic_platform.h +++ b/src/inc/quic_platform.h @@ -148,6 +148,8 @@ typedef struct CXPLAT_SLIST_ENTRY { #define QUIC_POOL_ROUTE_RESOLUTION_WORKER 'A4cQ' // Qc4A - QUIC route resolution worker #define QUIC_POOL_ROUTE_RESOLUTION_OPER 'B4cQ' // Qc4B - QUIC route resolution operation #define QUIC_POOL_EXECUTION_CONFIG 'C4cQ' // Qc4C - QUIC execution config +#define QUIC_POOL_CIDSLIST 'D4cQ' // Qc4D - QUIC CID SLIST Entry +#define QUIC_POOL_PATHID 'E4cQ' // Qc4E - QUIC PathID typedef enum CXPLAT_THREAD_FLAGS { CXPLAT_THREAD_FLAG_NONE = 0x0000, diff --git a/src/lib.rs b/src/lib.rs index 9a5e00b1d3..9fd0f0d9d3 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -116,6 +116,17 @@ impl From for Addr { } } +impl std::fmt::Debug for Addr { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + if let Some(addr) = self.as_socket() { + writeln!(f, "{:?}", addr)?; + } else { + writeln!(f, "*:{}", self.port())?; + } + Ok(()) + } +} + #[cfg(target_os = "windows")] mod status { pub const QUIC_STATUS_SUCCESS: u32 = 0x0; @@ -779,6 +790,28 @@ pub const PERF_COUNTER_WORK_OPER_QUEUED: PerformanceCounter = 25; pub const PERF_COUNTER_WORK_OPER_COMPLETED: PerformanceCounter = 26; pub const PERF_COUNTER_MAX: PerformanceCounter = 27; +#[cfg(feature = "preview-api")] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct VersionSettings { + acceptable_versions: *const u32, + offered_versions: *const u32, + fully_deployed_versions: *const u32, + acceptable_versions_length: u32, + offered_versions_length: u32, + fully_deployed_versions_length: u32, +} + +#[cfg(feature = "preview-api")] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct PathStatus { + peer_address: Addr, + local_address: Addr, + path_id: u32, + active: BOOLEAN, +} + pub const QUIC_TLS_SECRETS_MAX_SECRET_LEN: usize = 64; #[repr(C)] @@ -882,6 +915,13 @@ pub const PARAM_CONN_VERSION_SETTINGS: u32 = 0x05000014; pub const PARAM_CONN_INITIAL_DCID_PREFIX: u32 = 0x05000015; pub const PARAM_CONN_STATISTICS_V2: u32 = 0x05000016; pub const PARAM_CONN_STATISTICS_V2_PLAT: u32 = 0x05000017; +pub const PARAM_CONN_ORIG_DEST_CID: u32 = 0x05000018; +#[cfg(feature = "preview-api")] +pub const PARAM_CONN_ADD_LOCAL_ADDRESS: u32 = 0x05000019; +#[cfg(feature = "preview-api")] +pub const PARAM_CONN_REMOVE_LOCAL_ADDRESS: u32 = 0x0500001A; +#[cfg(feature = "preview-api")] +pub const PARAM_CONN_PATH_STATUS: u32 = 0x0500001B; pub const PARAM_TLS_HANDSHAKE_INFO: u32 = 0x06000000; pub const PARAM_TLS_NEGOTIATED_ALPN: u32 = 0x06000001; @@ -969,6 +1009,18 @@ pub const CONNECTION_EVENT_DATAGRAM_SEND_STATE_CHANGED: ConnectionEventType = 12 pub const CONNECTION_EVENT_RESUMED: ConnectionEventType = 13; pub const CONNECTION_EVENT_RESUMPTION_TICKET_RECEIVED: ConnectionEventType = 14; pub const CONNECTION_EVENT_PEER_CERTIFICATE_RECEIVED: ConnectionEventType = 15; +#[cfg(feature = "preview-api")] +pub const CONNECTION_EVENT_RELIABLE_RESET_NEGOTIATED: ConnectionEventType = 16; +#[cfg(feature = "preview-api")] +pub const CONNECTION_EVENT_ONE_WAY_DELAY_NEGOTIATED: ConnectionEventType = 17; +#[cfg(feature = "preview-api")] +pub const CONNECTION_EVENT_NETWORK_STATISTICS: ConnectionEventType = 18; +#[cfg(feature = "preview-api")] +pub const CONNECTION_EVENT_PATH_ADDED: ConnectionEventType = 19; +#[cfg(feature = "preview-api")] +pub const CONNECTION_EVENT_PATH_REMOVED: ConnectionEventType = 20; +#[cfg(feature = "preview-api")] +pub const CONNECTION_EVENT_PATH_STATUS_CHANGED: ConnectionEventType = 21; #[repr(C)] #[derive(Debug, Copy, Clone)] @@ -1091,6 +1143,61 @@ pub struct ConnectionEventPeerCertificateReceived { pub chain: *const CertificateChain, } +#[cfg(feature = "preview-api")] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ConnectionEventReliableResetNegotiated { + pub is_negotiated: BOOLEAN, +} + +#[cfg(feature = "preview-api")] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ConnectionEventOneWayDelayNegotiated { + pub send_negotiated: BOOLEAN, + pub receive_negotiated: BOOLEAN, +} + +#[cfg(feature = "preview-api")] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ConnectionEventNetworkStatistics { + pub bytes_in_flight: u32, + pub posted_bytes: u64, + pub ideal_bytes: u64, + pub smoothed_rtt: u64, + pub congestion_window: u64, + pub bandwidth: u64, +} + +#[cfg(feature = "preview-api")] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ConnectionEventPathAdded { + pub peer_address: Addr, + pub local_address: Addr, + pub path_id: u32, +} + +#[cfg(feature = "preview-api")] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ConnectionEventPathRemoved { + pub peer_address: Addr, + pub local_address: Addr, + pub path_id: u32, +} + +#[cfg(feature = "preview-api")] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ConnectionEventPathStatusChanged { + pub peer_address: Addr, + pub local_address: Addr, + pub path_id: u32, + pub is_active: BOOLEAN, +} + #[repr(C)] #[derive(Copy, Clone)] pub union ConnectionEventPayload { @@ -1110,6 +1217,18 @@ pub union ConnectionEventPayload { pub resumed: ConnectionEventResumed, pub resumption_ticket_received: ConnectionEventResumptionTicketReceived, pub peer_certificated_received: ConnectionEventPeerCertificateReceived, + #[cfg(feature = "preview-api")] + pub reliable_reset_negotiated: ConnectionEventReliableResetNegotiated, + #[cfg(feature = "preview-api")] + pub one_way_delay_negotiated: ConnectionEventOneWayDelayNegotiated, + #[cfg(feature = "preview-api")] + pub network_statistics: ConnectionEventNetworkStatistics, + #[cfg(feature = "preview-api")] + pub path_added: ConnectionEventPathAdded, + #[cfg(feature = "preview-api")] + pub path_removed: ConnectionEventPathRemoved, + #[cfg(feature = "preview-api")] + pub path_status_changed: ConnectionEventPathStatusChanged, } #[repr(C)] @@ -1471,6 +1590,12 @@ impl Settings { self.other2_flags |= (value as u64) << 5; self } + #[cfg(feature = "preview-api")] + pub fn set_multipath_enabled(&mut self, value: bool) -> &mut Settings { + self.is_set_flags |= 1 << 43; + self.other2_flags |= (value as u64) << 6; + self + } } impl CredentialConfig { diff --git a/src/manifest/MsQuicEtw.man b/src/manifest/MsQuicEtw.man index 8c8dc8e2d0..fcedbbbc70 100644 --- a/src/manifest/MsQuicEtw.man +++ b/src/manifest/MsQuicEtw.man @@ -265,9 +265,13 @@ value="4" /> + + + + + + + + + + + + diff --git a/src/manifest/clog.sidecar b/src/manifest/clog.sidecar index 907d055946..f445159569 100644 --- a/src/manifest/clog.sidecar +++ b/src/manifest/clog.sidecar @@ -1149,7 +1149,7 @@ }, "ConnDestCidAdded": { "ModuleProperites": {}, - "TraceString": "[conn][%p] (SeqNum=%llu) New Destination CID: %!CID!", + "TraceString": "[conn][%p][pathid][%u] (SeqNum=%llu) New Destination CID: %!CID!", "UniqueId": "ConnDestCidAdded", "splitArgs": [ { @@ -1157,19 +1157,23 @@ "MacroVariableName": "arg2" }, { - "DefinationEncoding": "llu", + "DefinationEncoding": "u", "MacroVariableName": "arg3" }, { - "DefinationEncoding": "!CID!", + "DefinationEncoding": "llu", "MacroVariableName": "arg4" + }, + { + "DefinationEncoding": "!CID!", + "MacroVariableName": "arg5" } ], "macroName": "QuicTraceEvent" }, "ConnDestCidRemoved": { "ModuleProperites": {}, - "TraceString": "[conn][%p] (SeqNum=%llu) Removed Destination CID: %!CID!", + "TraceString": "[conn][%p][pathid][%u] (SeqNum=%llu) Removed Destination CID: %!CID!", "UniqueId": "ConnDestCidRemoved", "splitArgs": [ { @@ -1177,12 +1181,40 @@ "MacroVariableName": "arg2" }, { - "DefinationEncoding": "llu", + "DefinationEncoding": "u", "MacroVariableName": "arg3" }, + { + "DefinationEncoding": "llu", + "MacroVariableName": "arg4" + }, { "DefinationEncoding": "!CID!", + "MacroVariableName": "arg5" + } + ], + "macroName": "QuicTraceEvent" + }, + "ConnDestCidUpdated": { + "ModuleProperites": {}, + "TraceString": "[conn][%p][pathid][%u] (SeqNum=%llu) Updated Destination CID: %!CID!", + "UniqueId": "ConnDestCidUpdated", + "splitArgs": [ + { + "DefinationEncoding": "p", + "MacroVariableName": "arg2" + }, + { + "DefinationEncoding": "u", + "MacroVariableName": "arg3" + }, + { + "DefinationEncoding": "llu", "MacroVariableName": "arg4" + }, + { + "DefinationEncoding": "!CID!", + "MacroVariableName": "arg5" } ], "macroName": "QuicTraceEvent" @@ -1839,6 +1871,70 @@ ], "macroName": "QuicTraceEvent" }, + "ConnPathIDAdd": { + "ModuleProperites": {}, + "TraceString": "[conn][%p] Added New PathID %u", + "UniqueId": "ConnPathIDAdd", + "splitArgs": [ + { + "DefinationEncoding": "p", + "MacroVariableName": "arg2" + }, + { + "DefinationEncoding": "u", + "MacroVariableName": "arg3" + } + ], + "macroName": "QuicTraceEvent" + }, + "ConnPathIDCloseTimerExpired": { + "ModuleProperites": {}, + "TraceString": "[conn][%p][pathid][%u] Close Timer expired", + "UniqueId": "ConnPathIDCloseTimerExpired", + "splitArgs": [ + { + "DefinationEncoding": "p", + "MacroVariableName": "arg2" + }, + { + "DefinationEncoding": "u", + "MacroVariableName": "arg3" + } + ], + "macroName": "QuicTraceEvent" + }, + "ConnPathIDCreated": { + "ModuleProperites": {}, + "TraceString": "[conn][%p] New PathID %u", + "UniqueId": "ConnPathIDCreated", + "splitArgs": [ + { + "DefinationEncoding": "p", + "MacroVariableName": "arg2" + }, + { + "DefinationEncoding": "u", + "MacroVariableName": "arg3" + } + ], + "macroName": "QuicTraceEvent" + }, + "ConnPathIDRemove": { + "ModuleProperites": {}, + "TraceString": "[conn][%p] Removed PathID %u", + "UniqueId": "ConnPathIDRemove", + "splitArgs": [ + { + "DefinationEncoding": "p", + "MacroVariableName": "arg2" + }, + { + "DefinationEncoding": "u", + "MacroVariableName": "arg3" + } + ], + "macroName": "QuicTraceEvent" + }, "ConnPersistentCongestion": { "ModuleProperites": {}, "TraceString": "[conn][%p] Persistent congestion event", @@ -2033,7 +2129,7 @@ }, "ConnSourceCidAdded": { "ModuleProperites": {}, - "TraceString": "[conn][%p] (SeqNum=%llu) New Source CID: %!CID!", + "TraceString": "[conn][%p][pathid][%u] (SeqNum=%llu) New Source CID: %!CID!", "UniqueId": "ConnSourceCidAdded", "splitArgs": [ { @@ -2041,19 +2137,23 @@ "MacroVariableName": "arg2" }, { - "DefinationEncoding": "llu", + "DefinationEncoding": "u", "MacroVariableName": "arg3" }, { - "DefinationEncoding": "!CID!", + "DefinationEncoding": "llu", "MacroVariableName": "arg4" + }, + { + "DefinationEncoding": "!CID!", + "MacroVariableName": "arg5" } ], "macroName": "QuicTraceEvent" }, "ConnSourceCidRemoved": { "ModuleProperites": {}, - "TraceString": "[conn][%p] (SeqNum=%llu) Removed Source CID: %!CID!", + "TraceString": "[conn][%p][pathid][%u] (SeqNum=%llu) Removed Source CID: %!CID!", "UniqueId": "ConnSourceCidRemoved", "splitArgs": [ { @@ -2061,12 +2161,16 @@ "MacroVariableName": "arg2" }, { - "DefinationEncoding": "llu", + "DefinationEncoding": "u", "MacroVariableName": "arg3" }, { - "DefinationEncoding": "!CID!", + "DefinationEncoding": "llu", "MacroVariableName": "arg4" + }, + { + "DefinationEncoding": "!CID!", + "MacroVariableName": "arg5" } ], "macroName": "QuicTraceEvent" @@ -3239,6 +3343,22 @@ ], "macroName": "QuicTraceLogConnVerbose" }, + "DecodeTPInitMaxPathId": { + "ModuleProperites": {}, + "TraceString": "[conn][%p] TP: Max Path Id (%llu)", + "UniqueId": "DecodeTPInitMaxPathId", + "splitArgs": [ + { + "DefinationEncoding": "p", + "MacroVariableName": "arg1" + }, + { + "DefinationEncoding": "llu", + "MacroVariableName": "arg3" + } + ], + "macroName": "QuicTraceLogConnVerbose" + }, "DecodeTPInitMaxStreamDataBidiLocal": { "ModuleProperites": {}, "TraceString": "[conn][%p] TP: Max Local Bidirectional Stream Data (%llu bytes)", @@ -3787,6 +3907,22 @@ ], "macroName": "QuicTraceLogConnVerbose" }, + "EncodeTPInitMaxPathId": { + "ModuleProperites": {}, + "TraceString": "[conn][%p] TP: Max Path Id (%llu)", + "UniqueId": "EncodeTPInitMaxPathId", + "splitArgs": [ + { + "DefinationEncoding": "p", + "MacroVariableName": "arg1" + }, + { + "DefinationEncoding": "llu", + "MacroVariableName": "arg3" + } + ], + "macroName": "QuicTraceLogConnVerbose" + }, "EncodeTPInitMaxStreamDataBidiLocal": { "ModuleProperites": {}, "TraceString": "[conn][%p] TP: Max Local Bidirectional Stream Data (%llu bytes)", @@ -4744,6 +4880,50 @@ ], "macroName": "QuicTraceLogVerbose" }, + "FrameLogMaxPathID": { + "ModuleProperites": {}, + "TraceString": "[%c][%cX][%llu] MAX_PATH_ID Max:%llu", + "UniqueId": "FrameLogMaxPathID", + "splitArgs": [ + { + "DefinationEncoding": "c", + "MacroVariableName": "arg2" + }, + { + "DefinationEncoding": "c", + "MacroVariableName": "arg3" + }, + { + "DefinationEncoding": "llu", + "MacroVariableName": "arg4" + }, + { + "DefinationEncoding": "llu", + "MacroVariableName": "arg5" + } + ], + "macroName": "QuicTraceLogVerbose" + }, + "FrameLogMaxPathIDInvalid": { + "ModuleProperites": {}, + "TraceString": "[%c][%cX][%llu] MAX_PATH_ID [Invalid]", + "UniqueId": "FrameLogMaxPathIDInvalid", + "splitArgs": [ + { + "DefinationEncoding": "c", + "MacroVariableName": "arg2" + }, + { + "DefinationEncoding": "c", + "MacroVariableName": "arg3" + }, + { + "DefinationEncoding": "llu", + "MacroVariableName": "arg4" + } + ], + "macroName": "QuicTraceLogVerbose" + }, "FrameLogMaxStreamData": { "ModuleProperites": {}, "TraceString": "[%c][%cX][%llu] MAX_STREAM_DATA ID:%llu Max:%llu", @@ -4926,24 +5106,328 @@ "UniqueId": "FrameLogNewTokenInvalid", "splitArgs": [ { - "DefinationEncoding": "c", - "MacroVariableName": "arg2" + "DefinationEncoding": "c", + "MacroVariableName": "arg2" + }, + { + "DefinationEncoding": "c", + "MacroVariableName": "arg3" + }, + { + "DefinationEncoding": "llu", + "MacroVariableName": "arg4" + } + ], + "macroName": "QuicTraceLogVerbose" + }, + "FrameLogPadding": { + "ModuleProperites": {}, + "TraceString": "[%c][%cX][%llu] PADDING Len:%hu", + "UniqueId": "FrameLogPadding", + "splitArgs": [ + { + "DefinationEncoding": "c", + "MacroVariableName": "arg2" + }, + { + "DefinationEncoding": "c", + "MacroVariableName": "arg3" + }, + { + "DefinationEncoding": "llu", + "MacroVariableName": "arg4" + }, + { + "DefinationEncoding": "hu", + "MacroVariableName": "arg5" + } + ], + "macroName": "QuicTraceLogVerbose" + }, + "FrameLogPathAbandon": { + "ModuleProperites": {}, + "TraceString": "[%c][%cX][%llu] PATH_ABANDON PathID:%llu ErrorCode:0x%llX", + "UniqueId": "FrameLogPathAbandon", + "splitArgs": [ + { + "DefinationEncoding": "c", + "MacroVariableName": "arg2" + }, + { + "DefinationEncoding": "c", + "MacroVariableName": "arg3" + }, + { + "DefinationEncoding": "llu", + "MacroVariableName": "arg4" + }, + { + "DefinationEncoding": "llu", + "MacroVariableName": "arg5" + }, + { + "DefinationEncoding": "llX", + "MacroVariableName": "arg6" + } + ], + "macroName": "QuicTraceLogVerbose" + }, + "FrameLogPathAbandonInvalid": { + "ModuleProperites": {}, + "TraceString": "[%c][%cX][%llu] PATH_ABANDON [Invalid]", + "UniqueId": "FrameLogPathAbandonInvalid", + "splitArgs": [ + { + "DefinationEncoding": "c", + "MacroVariableName": "arg2" + }, + { + "DefinationEncoding": "c", + "MacroVariableName": "arg3" + }, + { + "DefinationEncoding": "llu", + "MacroVariableName": "arg4" + } + ], + "macroName": "QuicTraceLogVerbose" + }, + "FrameLogPathAck": { + "ModuleProperites": {}, + "TraceString": "[%c][%cX][%llu] PathId:%llu ACK Largest:%llu Delay:%llu", + "UniqueId": "FrameLogPathAck", + "splitArgs": [ + { + "DefinationEncoding": "c", + "MacroVariableName": "arg2" + }, + { + "DefinationEncoding": "c", + "MacroVariableName": "arg3" + }, + { + "DefinationEncoding": "llu", + "MacroVariableName": "arg4" + }, + { + "DefinationEncoding": "llu", + "MacroVariableName": "arg5" + }, + { + "DefinationEncoding": "llu", + "MacroVariableName": "arg6" + }, + { + "DefinationEncoding": "llu", + "MacroVariableName": "arg7" + } + ], + "macroName": "QuicTraceLogVerbose" + }, + "FrameLogPathAckInvalid": { + "ModuleProperites": {}, + "TraceString": "[%c][%cX][%llu] PATH_ACK [Invalid]", + "UniqueId": "FrameLogPathAckInvalid", + "splitArgs": [ + { + "DefinationEncoding": "c", + "MacroVariableName": "arg2" + }, + { + "DefinationEncoding": "c", + "MacroVariableName": "arg3" + }, + { + "DefinationEncoding": "llu", + "MacroVariableName": "arg4" + } + ], + "macroName": "QuicTraceLogVerbose" + }, + "FrameLogPathAvailable": { + "ModuleProperites": {}, + "TraceString": "[%c][%cX][%llu] PATH_AVAILABLE PathID:%llu SSN:0x%llX", + "UniqueId": "FrameLogPathAvailable", + "splitArgs": [ + { + "DefinationEncoding": "c", + "MacroVariableName": "arg2" + }, + { + "DefinationEncoding": "c", + "MacroVariableName": "arg3" + }, + { + "DefinationEncoding": "llu", + "MacroVariableName": "arg4" + }, + { + "DefinationEncoding": "llu", + "MacroVariableName": "arg5" + }, + { + "DefinationEncoding": "llX", + "MacroVariableName": "arg6" + } + ], + "macroName": "QuicTraceLogVerbose" + }, + "FrameLogPathAvailableInvalid": { + "ModuleProperites": {}, + "TraceString": "[%c][%cX][%llu] PATH_AVAILABLE [Invalid]", + "UniqueId": "FrameLogPathAvailableInvalid", + "splitArgs": [ + { + "DefinationEncoding": "c", + "MacroVariableName": "arg2" + }, + { + "DefinationEncoding": "c", + "MacroVariableName": "arg3" + }, + { + "DefinationEncoding": "llu", + "MacroVariableName": "arg4" + } + ], + "macroName": "QuicTraceLogVerbose" + }, + "FrameLogPathBackup": { + "ModuleProperites": {}, + "TraceString": "[%c][%cX][%llu] PATH_BACKUP PathID:%llu SSN:0x%llX", + "UniqueId": "FrameLogPathBackup", + "splitArgs": [ + { + "DefinationEncoding": "c", + "MacroVariableName": "arg2" + }, + { + "DefinationEncoding": "c", + "MacroVariableName": "arg3" + }, + { + "DefinationEncoding": "llu", + "MacroVariableName": "arg4" + }, + { + "DefinationEncoding": "llu", + "MacroVariableName": "arg5" + }, + { + "DefinationEncoding": "llX", + "MacroVariableName": "arg6" + } + ], + "macroName": "QuicTraceLogVerbose" + }, + "FrameLogPathBackupInvalid": { + "ModuleProperites": {}, + "TraceString": "[%c][%cX][%llu] PATH_BACKUP [Invalid]", + "UniqueId": "FrameLogPathBackupInvalid", + "splitArgs": [ + { + "DefinationEncoding": "c", + "MacroVariableName": "arg2" + }, + { + "DefinationEncoding": "c", + "MacroVariableName": "arg3" + }, + { + "DefinationEncoding": "llu", + "MacroVariableName": "arg4" + } + ], + "macroName": "QuicTraceLogVerbose" + }, + "FrameLogPathChallenge": { + "ModuleProperites": {}, + "TraceString": "[%c][%cX][%llu] PATH_CHALLENGE [%llu]", + "UniqueId": "FrameLogPathChallenge", + "splitArgs": [ + { + "DefinationEncoding": "c", + "MacroVariableName": "arg2" + }, + { + "DefinationEncoding": "c", + "MacroVariableName": "arg3" + }, + { + "DefinationEncoding": "llu", + "MacroVariableName": "arg4" + }, + { + "DefinationEncoding": "llu", + "MacroVariableName": "arg5" + } + ], + "macroName": "QuicTraceLogVerbose" + }, + "FrameLogPathChallengeInvalid": { + "ModuleProperites": {}, + "TraceString": "[%c][%cX][%llu] PATH_CHALLENGE [Invalid]", + "UniqueId": "FrameLogPathChallengeInvalid", + "splitArgs": [ + { + "DefinationEncoding": "c", + "MacroVariableName": "arg2" + }, + { + "DefinationEncoding": "c", + "MacroVariableName": "arg3" + }, + { + "DefinationEncoding": "llu", + "MacroVariableName": "arg4" + } + ], + "macroName": "QuicTraceLogVerbose" + }, + "FrameLogPathNewConnectionID": { + "ModuleProperites": {}, + "TraceString": "[%c][%cX][%llu] PATH_NEW_CONN_ID PathID:%llu Seq:%llu RPT:%llu CID:%s Token:%s", + "UniqueId": "FrameLogPathNewConnectionID", + "splitArgs": [ + { + "DefinationEncoding": "c", + "MacroVariableName": "arg2" + }, + { + "DefinationEncoding": "c", + "MacroVariableName": "arg3" + }, + { + "DefinationEncoding": "llu", + "MacroVariableName": "arg4" + }, + { + "DefinationEncoding": "llu", + "MacroVariableName": "arg5" }, { - "DefinationEncoding": "c", - "MacroVariableName": "arg3" + "DefinationEncoding": "llu", + "MacroVariableName": "arg6" }, { "DefinationEncoding": "llu", - "MacroVariableName": "arg4" + "MacroVariableName": "arg7" + }, + { + "DefinationEncoding": "s", + "MacroVariableName": "arg8" + }, + { + "DefinationEncoding": "s", + "MacroVariableName": "arg9" } ], "macroName": "QuicTraceLogVerbose" }, - "FrameLogPadding": { + "FrameLogPathNewConnectionIDInvalid": { "ModuleProperites": {}, - "TraceString": "[%c][%cX][%llu] PADDING Len:%hu", - "UniqueId": "FrameLogPadding", + "TraceString": "[%c][%cX][%llu] PATH_NEW_CONN_ID [Invalid]", + "UniqueId": "FrameLogPathNewConnectionIDInvalid", "splitArgs": [ { "DefinationEncoding": "c", @@ -4956,18 +5440,14 @@ { "DefinationEncoding": "llu", "MacroVariableName": "arg4" - }, - { - "DefinationEncoding": "hu", - "MacroVariableName": "arg5" } ], "macroName": "QuicTraceLogVerbose" }, - "FrameLogPathChallenge": { + "FrameLogPathResponse": { "ModuleProperites": {}, - "TraceString": "[%c][%cX][%llu] PATH_CHALLENGE [%llu]", - "UniqueId": "FrameLogPathChallenge", + "TraceString": "[%c][%cX][%llu] PATH_RESPONSE [%llu]", + "UniqueId": "FrameLogPathResponse", "splitArgs": [ { "DefinationEncoding": "c", @@ -4988,10 +5468,10 @@ ], "macroName": "QuicTraceLogVerbose" }, - "FrameLogPathChallengeInvalid": { + "FrameLogPathResponseInvalid": { "ModuleProperites": {}, - "TraceString": "[%c][%cX][%llu] PATH_CHALLENGE [Invalid]", - "UniqueId": "FrameLogPathChallengeInvalid", + "TraceString": "[%c][%cX][%llu] PATH_RESPONSE [Invalid]", + "UniqueId": "FrameLogPathResponseInvalid", "splitArgs": [ { "DefinationEncoding": "c", @@ -5008,10 +5488,10 @@ ], "macroName": "QuicTraceLogVerbose" }, - "FrameLogPathResponse": { + "FrameLogPathRetireConnectionID": { "ModuleProperites": {}, - "TraceString": "[%c][%cX][%llu] PATH_RESPONSE [%llu]", - "UniqueId": "FrameLogPathResponse", + "TraceString": "[%c][%cX][%llu] PATH_RETIRE_CONN_ID PathID:%llu Seq:%llu", + "UniqueId": "FrameLogPathRetireConnectionID", "splitArgs": [ { "DefinationEncoding": "c", @@ -5028,14 +5508,18 @@ { "DefinationEncoding": "llu", "MacroVariableName": "arg5" + }, + { + "DefinationEncoding": "llu", + "MacroVariableName": "arg6" } ], "macroName": "QuicTraceLogVerbose" }, - "FrameLogPathResponseInvalid": { + "FrameLogPathRetireConnectionIDInvalid": { "ModuleProperites": {}, - "TraceString": "[%c][%cX][%llu] PATH_RESPONSE [Invalid]", - "UniqueId": "FrameLogPathResponseInvalid", + "TraceString": "[%c][%cX][%llu] PATH_RETIRE_CONN_ID [Invalid]", + "UniqueId": "FrameLogPathRetireConnectionIDInvalid", "splitArgs": [ { "DefinationEncoding": "c", @@ -5852,6 +6336,30 @@ ], "macroName": "QuicTraceLogConnVerbose" }, + "IndicatePathAdded": { + "ModuleProperites": {}, + "TraceString": "[conn][%p] Indicating QUIC_CONNECTION_EVENT_PATH_ADDED", + "UniqueId": "IndicatePathAdded", + "splitArgs": [ + { + "DefinationEncoding": "p", + "MacroVariableName": "arg1" + } + ], + "macroName": "QuicTraceLogConnVerbose" + }, + "IndicatePathStatusChanged": { + "ModuleProperites": {}, + "TraceString": "[conn][%p] Indicating QUIC_CONNECTION_EVENT_PATH_STATUS_CHANGED", + "UniqueId": "IndicatePathStatusChanged", + "splitArgs": [ + { + "DefinationEncoding": "p", + "MacroVariableName": "arg1" + } + ], + "macroName": "QuicTraceLogConnVerbose" + }, "IndicatePeerAccepted": { "ModuleProperites": {}, "TraceString": "[strm][%p] Indicating QUIC_STREAM_EVENT_PEER_ACCEPTED", @@ -8099,6 +8607,22 @@ ], "macroName": "QuicTraceLogConnInfo" }, + "PathChosen": { + "ModuleProperites": {}, + "TraceString": "[conn][%p] Path[%hhu] Chosen", + "UniqueId": "PathChosen", + "splitArgs": [ + { + "DefinationEncoding": "p", + "MacroVariableName": "arg1" + }, + { + "DefinationEncoding": "hhu", + "MacroVariableName": "arg3" + } + ], + "macroName": "QuicTraceLogConnInfo" + }, "PathDiscarded": { "ModuleProperites": {}, "TraceString": "[conn][%p] Removing invalid path[%hhu]", @@ -8115,6 +8639,102 @@ ], "macroName": "QuicTraceLogConnInfo" }, + "PathIDDestCidAdded": { + "ModuleProperites": {}, + "TraceString": "[conn][%p] [pathid][%u] (SeqNum=%llu) New Destination CID: %!CID!", + "UniqueId": "PathIDDestCidAdded", + "splitArgs": [ + { + "DefinationEncoding": "p", + "MacroVariableName": "arg1" + }, + { + "DefinationEncoding": "u", + "MacroVariableName": "arg3" + }, + { + "DefinationEncoding": "llu", + "MacroVariableName": "arg4" + }, + { + "DefinationEncoding": "!CID!", + "MacroVariableName": "arg5" + } + ], + "macroName": "QuicTraceLogConnInfo" + }, + "PathIDDestCidRemoved": { + "ModuleProperites": {}, + "TraceString": "[conn][%p] [pathid][%u] (SeqNum=%llu) Removed Destination CID: %!CID!", + "UniqueId": "PathIDDestCidRemoved", + "splitArgs": [ + { + "DefinationEncoding": "p", + "MacroVariableName": "arg1" + }, + { + "DefinationEncoding": "u", + "MacroVariableName": "arg3" + }, + { + "DefinationEncoding": "llu", + "MacroVariableName": "arg4" + }, + { + "DefinationEncoding": "!CID!", + "MacroVariableName": "arg5" + } + ], + "macroName": "QuicTraceLogConnInfo" + }, + "PathIDSourceCidAdded": { + "ModuleProperites": {}, + "TraceString": "[conn][%p] [pathid][%u] (SeqNum=%llu) New Source CID: %!CID!", + "UniqueId": "PathIDSourceCidAdded", + "splitArgs": [ + { + "DefinationEncoding": "p", + "MacroVariableName": "arg1" + }, + { + "DefinationEncoding": "u", + "MacroVariableName": "arg3" + }, + { + "DefinationEncoding": "llu", + "MacroVariableName": "arg4" + }, + { + "DefinationEncoding": "!CID!", + "MacroVariableName": "arg5" + } + ], + "macroName": "QuicTraceLogConnInfo" + }, + "PathIDSourceCidRemoved": { + "ModuleProperites": {}, + "TraceString": "[conn][%p] [pathid][%u] (SeqNum=%llu) Removed Source CID: %!CID!", + "UniqueId": "PathIDSourceCidRemoved", + "splitArgs": [ + { + "DefinationEncoding": "p", + "MacroVariableName": "arg1" + }, + { + "DefinationEncoding": "u", + "MacroVariableName": "arg3" + }, + { + "DefinationEncoding": "llu", + "MacroVariableName": "arg4" + }, + { + "DefinationEncoding": "!CID!", + "MacroVariableName": "arg5" + } + ], + "macroName": "QuicTraceLogConnInfo" + }, "PathInitialized": { "ModuleProperites": {}, "TraceString": "[conn][%p] Path[%hhu] Initialized", @@ -8267,6 +8887,22 @@ ], "macroName": "QuicTraceLogConnVerbose" }, + "PeerMaxPathIDUpdated": { + "ModuleProperites": {}, + "TraceString": "[conn][%p] Peer updated max path id (%u).", + "UniqueId": "PeerMaxPathIDUpdated", + "splitArgs": [ + { + "DefinationEncoding": "p", + "MacroVariableName": "arg1" + }, + { + "DefinationEncoding": "u", + "MacroVariableName": "arg3" + } + ], + "macroName": "QuicTraceLogConnVerbose" + }, "PeerPreferredAddress": { "ModuleProperites": {}, "TraceString": "[conn][%p] Peer configured preferred address %!ADDR!", @@ -10326,6 +10962,18 @@ ], "macroName": "QuicTraceLogVerbose" }, + "SettingConnIDGenDisabled": { + "ModuleProperites": {}, + "TraceString": "[sett] ConnIDGenDisabled = %hhu", + "UniqueId": "SettingConnIDGenDisabled", + "splitArgs": [ + { + "DefinationEncoding": "hhu", + "MacroVariableName": "arg2" + } + ], + "macroName": "QuicTraceLogVerbose" + }, "SettingDestCidUpdateIdleTimeoutMs": { "ModuleProperites": {}, "TraceString": "[sett] DestCidUpdateIdleTimeoutMs = %u", @@ -10914,6 +11562,18 @@ ], "macroName": "QuicTraceLogVerbose" }, + "SettingMultipathEnabled": { + "ModuleProperites": {}, + "TraceString": "[sett] MultipathEnabled = %hhu", + "UniqueId": "SettingMultipathEnabled", + "splitArgs": [ + { + "DefinationEncoding": "hhu", + "MacroVariableName": "arg2" + } + ], + "macroName": "QuicTraceLogVerbose" + }, "SettingNetStatsEventEnabled": { "ModuleProperites": {}, "TraceString": "[sett] NetStatsEventEnabled = %hhu", @@ -13760,14 +14420,19 @@ "EncodingString": "[conn][%p] Received APPLICATION_ERROR error, delaying close in expectation of a 1-RTT CONNECTION_CLOSE frame." }, { - "UniquenessHash": "e2133726-1e36-d515-e6b1-ab7ac6fdf53e", + "UniquenessHash": "d83cee8b-9ec7-90fc-9c4b-8eaced00af97", "TraceID": "ConnDestCidAdded", - "EncodingString": "[conn][%p] (SeqNum=%llu) New Destination CID: %!CID!" + "EncodingString": "[conn][%p][pathid][%u] (SeqNum=%llu) New Destination CID: %!CID!" }, { - "UniquenessHash": "8f204a2e-9160-ae42-2cdd-4f8e8eab10c5", + "UniquenessHash": "4e8bf48f-c558-e231-7340-72d7673dc9cb", "TraceID": "ConnDestCidRemoved", - "EncodingString": "[conn][%p] (SeqNum=%llu) Removed Destination CID: %!CID!" + "EncodingString": "[conn][%p][pathid][%u] (SeqNum=%llu) Removed Destination CID: %!CID!" + }, + { + "UniquenessHash": "27c1726a-786a-1e16-3567-f7d27ded1211", + "TraceID": "ConnDestCidUpdated", + "EncodingString": "[conn][%p][pathid][%u] (SeqNum=%llu) Updated Destination CID: %!CID!" }, { "UniquenessHash": "3903cc44-b387-b5f6-17fc-62d5aee48015", @@ -13934,6 +14599,26 @@ "TraceID": "ConnPacketStats", "EncodingString": "[conn][%p] STATS: SendTotalPackets=%llu SendSuspectedLostPackets=%llu SendSpuriousLostPackets=%llu RecvTotalPackets=%llu RecvReorderedPackets=%llu RecvDroppedPackets=%llu RecvDuplicatePackets=%llu RecvDecryptionFailures=%llu" }, + { + "UniquenessHash": "4ca3aeb8-2919-6c50-9c9b-db8d0d8d910a", + "TraceID": "ConnPathIDAdd", + "EncodingString": "[conn][%p] Added New PathID %u" + }, + { + "UniquenessHash": "b79e53fd-ca11-f041-12c6-bc12d51453cb", + "TraceID": "ConnPathIDCloseTimerExpired", + "EncodingString": "[conn][%p][pathid][%u] Close Timer expired" + }, + { + "UniquenessHash": "03ab7814-30a8-e2f0-69bc-24a671996e5b", + "TraceID": "ConnPathIDCreated", + "EncodingString": "[conn][%p] New PathID %u" + }, + { + "UniquenessHash": "9f64af53-b5e1-7f8e-0808-31005e9bf4ce", + "TraceID": "ConnPathIDRemove", + "EncodingString": "[conn][%p] Removed PathID %u" + }, { "UniquenessHash": "c339eadc-2eef-8e45-4a51-1fc84a3c198e", "TraceID": "ConnPersistentCongestion", @@ -13995,14 +14680,14 @@ "EncodingString": "[conn][%p] Shutdown complete, PeerFailedToAcknowledged=%hhu." }, { - "UniquenessHash": "b1ef59fd-834d-2786-8b05-c14f32023aea", + "UniquenessHash": "8f27db2a-e029-442b-fa7a-a1464d32ddac", "TraceID": "ConnSourceCidAdded", - "EncodingString": "[conn][%p] (SeqNum=%llu) New Source CID: %!CID!" + "EncodingString": "[conn][%p][pathid][%u] (SeqNum=%llu) New Source CID: %!CID!" }, { - "UniquenessHash": "65f1ff8d-810a-4f24-b2f6-817daf9275ef", + "UniquenessHash": "d84737e0-d705-7cfd-8e09-ae17924dcdaa", "TraceID": "ConnSourceCidRemoved", - "EncodingString": "[conn][%p] (SeqNum=%llu) Removed Source CID: %!CID!" + "EncodingString": "[conn][%p][pathid][%u] (SeqNum=%llu) Removed Source CID: %!CID!" }, { "UniquenessHash": "262484c2-7385-f5dd-c3de-0bb48fe2ffea", @@ -14364,6 +15049,11 @@ "TraceID": "DecodeTPInitMaxData", "EncodingString": "[conn][%p] TP: Max Data (%llu bytes)" }, + { + "UniquenessHash": "f7cfe233-52f3-1303-9d6c-667658d07f9b", + "TraceID": "DecodeTPInitMaxPathId", + "EncodingString": "[conn][%p] TP: Max Path Id (%llu)" + }, { "UniquenessHash": "e4d0eb5f-0f76-f0ac-1c84-f306c642b9a6", "TraceID": "DecodeTPInitMaxStreamDataBidiLocal", @@ -14539,6 +15229,11 @@ "TraceID": "EncodeTPInitMaxData", "EncodingString": "[conn][%p] TP: Max Data (%llu bytes)" }, + { + "UniquenessHash": "e23da5d6-ae36-a312-7cab-a54cbc96943b", + "TraceID": "EncodeTPInitMaxPathId", + "EncodingString": "[conn][%p] TP: Max Path Id (%llu)" + }, { "UniquenessHash": "1cf3e10e-79dd-5aed-6c1c-f0675514be81", "TraceID": "EncodeTPInitMaxStreamDataBidiLocal", @@ -14799,6 +15494,16 @@ "TraceID": "FrameLogMaxDataInvalid", "EncodingString": "[%c][%cX][%llu] MAX_DATA [Invalid]" }, + { + "UniquenessHash": "9377bb20-38fe-0def-a836-2f1fe0a240ab", + "TraceID": "FrameLogMaxPathID", + "EncodingString": "[%c][%cX][%llu] MAX_PATH_ID Max:%llu" + }, + { + "UniquenessHash": "85a2b018-7072-a1a2-33d3-3589b3072de0", + "TraceID": "FrameLogMaxPathIDInvalid", + "EncodingString": "[%c][%cX][%llu] MAX_PATH_ID [Invalid]" + }, { "UniquenessHash": "3fa56e85-dbd2-f442-7f76-c4c011e23ecc", "TraceID": "FrameLogMaxStreamData", @@ -14844,6 +15549,46 @@ "TraceID": "FrameLogPadding", "EncodingString": "[%c][%cX][%llu] PADDING Len:%hu" }, + { + "UniquenessHash": "03fbb7ee-7d96-5bd3-2423-230ab4612cea", + "TraceID": "FrameLogPathAbandon", + "EncodingString": "[%c][%cX][%llu] PATH_ABANDON PathID:%llu ErrorCode:0x%llX" + }, + { + "UniquenessHash": "907c4419-057f-14b4-5a97-ec0b9ad0934d", + "TraceID": "FrameLogPathAbandonInvalid", + "EncodingString": "[%c][%cX][%llu] PATH_ABANDON [Invalid]" + }, + { + "UniquenessHash": "eb6523d9-6482-91c0-13aa-e3bef283e45e", + "TraceID": "FrameLogPathAck", + "EncodingString": "[%c][%cX][%llu] PathId:%llu ACK Largest:%llu Delay:%llu" + }, + { + "UniquenessHash": "e062ff15-a298-baea-6e29-aa5580272d8c", + "TraceID": "FrameLogPathAckInvalid", + "EncodingString": "[%c][%cX][%llu] PATH_ACK [Invalid]" + }, + { + "UniquenessHash": "36f89342-6a41-e997-cb5d-8949b244bf83", + "TraceID": "FrameLogPathAvailable", + "EncodingString": "[%c][%cX][%llu] PATH_AVAILABLE PathID:%llu SSN:0x%llX" + }, + { + "UniquenessHash": "86763eb1-03df-f8c5-6fba-21b418914721", + "TraceID": "FrameLogPathAvailableInvalid", + "EncodingString": "[%c][%cX][%llu] PATH_AVAILABLE [Invalid]" + }, + { + "UniquenessHash": "be44b7ac-6457-8be3-7e64-2a58bf581a88", + "TraceID": "FrameLogPathBackup", + "EncodingString": "[%c][%cX][%llu] PATH_BACKUP PathID:%llu SSN:0x%llX" + }, + { + "UniquenessHash": "89498c5c-9a3b-214e-25bf-400c47d52895", + "TraceID": "FrameLogPathBackupInvalid", + "EncodingString": "[%c][%cX][%llu] PATH_BACKUP [Invalid]" + }, { "UniquenessHash": "230959d3-aa58-0944-8287-6120bebac2f0", "TraceID": "FrameLogPathChallenge", @@ -14854,6 +15599,16 @@ "TraceID": "FrameLogPathChallengeInvalid", "EncodingString": "[%c][%cX][%llu] PATH_CHALLENGE [Invalid]" }, + { + "UniquenessHash": "551b1ae9-51b6-70f3-76c1-e428c25d5885", + "TraceID": "FrameLogPathNewConnectionID", + "EncodingString": "[%c][%cX][%llu] PATH_NEW_CONN_ID PathID:%llu Seq:%llu RPT:%llu CID:%s Token:%s" + }, + { + "UniquenessHash": "24e192ff-90cd-4918-4bec-529eb9a41789", + "TraceID": "FrameLogPathNewConnectionIDInvalid", + "EncodingString": "[%c][%cX][%llu] PATH_NEW_CONN_ID [Invalid]" + }, { "UniquenessHash": "48bdfe8e-61dc-d2b1-c15b-cd1157a7f291", "TraceID": "FrameLogPathResponse", @@ -14864,6 +15619,16 @@ "TraceID": "FrameLogPathResponseInvalid", "EncodingString": "[%c][%cX][%llu] PATH_RESPONSE [Invalid]" }, + { + "UniquenessHash": "34b9e0da-8485-2487-b4c9-425af72055b3", + "TraceID": "FrameLogPathRetireConnectionID", + "EncodingString": "[%c][%cX][%llu] PATH_RETIRE_CONN_ID PathID:%llu Seq:%llu" + }, + { + "UniquenessHash": "7ac366c2-d381-41e3-714c-fc85389b1e14", + "TraceID": "FrameLogPathRetireConnectionIDInvalid", + "EncodingString": "[%c][%cX][%llu] PATH_RETIRE_CONN_ID [Invalid]" + }, { "UniquenessHash": "4e057b3b-1d37-81dc-0b9d-e449ba9a5bbf", "TraceID": "FrameLogPing", @@ -15059,6 +15824,16 @@ "TraceID": "IndicateOneWayDelayNegotiated", "EncodingString": "[conn][%p] Indicating QUIC_CONNECTION_EVENT_ONE_WAY_DELAY_NEGOTIATED [Send=%hhu,Recv=%hhu]" }, + { + "UniquenessHash": "e59e9b10-d76e-af58-77ce-02c0a4aed7b8", + "TraceID": "IndicatePathAdded", + "EncodingString": "[conn][%p] Indicating QUIC_CONNECTION_EVENT_PATH_ADDED" + }, + { + "UniquenessHash": "ce9f8559-14a7-f7ea-79d0-d66df91fb31b", + "TraceID": "IndicatePathStatusChanged", + "EncodingString": "[conn][%p] Indicating QUIC_CONNECTION_EVENT_PATH_STATUS_CHANGED" + }, { "UniquenessHash": "446a0073-26fb-eed7-4ed4-fa9838fbd654", "TraceID": "IndicatePeerAccepted", @@ -15774,11 +16549,36 @@ "TraceID": "PathActive", "EncodingString": "[conn][%p] Path[%hhu] Set active (rebind=%hhu)" }, + { + "UniquenessHash": "5a90f0fc-2798-02bc-480f-c3072af80b0f", + "TraceID": "PathChosen", + "EncodingString": "[conn][%p] Path[%hhu] Chosen" + }, { "UniquenessHash": "8843a66a-349f-e5a2-a63c-5120fb187f69", "TraceID": "PathDiscarded", "EncodingString": "[conn][%p] Removing invalid path[%hhu]" }, + { + "UniquenessHash": "266baddf-b44e-90a5-2343-1fba327c0c28", + "TraceID": "PathIDDestCidAdded", + "EncodingString": "[conn][%p] [pathid][%u] (SeqNum=%llu) New Destination CID: %!CID!" + }, + { + "UniquenessHash": "37bfc3f5-ad53-bdc8-1e09-2b5c74d59de7", + "TraceID": "PathIDDestCidRemoved", + "EncodingString": "[conn][%p] [pathid][%u] (SeqNum=%llu) Removed Destination CID: %!CID!" + }, + { + "UniquenessHash": "283ebf8f-59cb-eeb8-9eb6-c1f2373815ed", + "TraceID": "PathIDSourceCidAdded", + "EncodingString": "[conn][%p] [pathid][%u] (SeqNum=%llu) New Source CID: %!CID!" + }, + { + "UniquenessHash": "fe26463b-ece6-ec42-38cc-3b59e48930fb", + "TraceID": "PathIDSourceCidRemoved", + "EncodingString": "[conn][%p] [pathid][%u] (SeqNum=%llu) Removed Source CID: %!CID!" + }, { "UniquenessHash": "607e449d-59a9-9d66-fcd1-b0a2e12f1dc1", "TraceID": "PathInitialized", @@ -15824,6 +16624,11 @@ "TraceID": "PeerConnFCBlocked", "EncodingString": "[conn][%p] Peer Connection FC blocked (%llu)" }, + { + "UniquenessHash": "2e07df3e-5e1f-693b-6f1f-b22b7ca42ee8", + "TraceID": "PeerMaxPathIDUpdated", + "EncodingString": "[conn][%p] Peer updated max path id (%u)." + }, { "UniquenessHash": "74d787df-3260-879d-5e65-e28486df5e26", "TraceID": "PeerPreferredAddress", @@ -16489,6 +17294,11 @@ "TraceID": "SettingCongestionControlAlgorithm", "EncodingString": "[sett] CongestionControlAlgorithm = %hu" }, + { + "UniquenessHash": "b6c1fd3f-0e54-a7a9-78a2-d86eecf13d2a", + "TraceID": "SettingConnIDGenDisabled", + "EncodingString": "[sett] ConnIDGenDisabled = %hhu" + }, { "UniquenessHash": "7aef2287-3f2c-be15-9d32-4f26f16b46f1", "TraceID": "SettingDestCidUpdateIdleTimeoutMs", @@ -16729,6 +17539,11 @@ "TraceID": "SettingHyStartEnabled", "EncodingString": "[sett] HyStartEnabled = %hhu" }, + { + "UniquenessHash": "025f13c0-6d85-2f19-a68e-e80104f42f1f", + "TraceID": "SettingMultipathEnabled", + "EncodingString": "[sett] MultipathEnabled = %hhu" + }, { "UniquenessHash": "b2b7c2a6-35c7-4b14-47f2-dca7aad8817a", "TraceID": "SettingNetStatsEventEnabled", diff --git a/src/platform/datapath_winkernel.c b/src/platform/datapath_winkernel.c index a2f7391153..e76634a415 100644 --- a/src/platform/datapath_winkernel.c +++ b/src/platform/datapath_winkernel.c @@ -2381,7 +2381,6 @@ RecvDataReturn( DATAPATH_RX_IO_BLOCK* IoBlock = CXPLAT_CONTAINING_RECORD(Datagram, DATAPATH_RX_PACKET, Data)->IoBlock; - CXPLAT_DBG_ASSERT(Binding == NULL || Binding == IoBlock->Binding); Binding = IoBlock->Binding; Datagram->Allocated = FALSE; diff --git a/src/test/MsQuicTests.h b/src/test/MsQuicTests.h index aaae75274e..09f86d1f3b 100644 --- a/src/test/MsQuicTests.h +++ b/src/test/MsQuicTests.h @@ -364,6 +364,34 @@ QuicTestVNTPOtherVersionZero( // Post Handshake Tests // +void +QuicTestProbePath( + _In_ int Family, + _In_ BOOLEAN ShareBinding, + _In_ BOOLEAN DeferConnIDGen, + _In_ uint32_t DropPacketCount + ); + +void +QuicTestMigration( + _In_ int Family, + _In_ BOOLEAN ShareBinding, + _In_ BOOLEAN PathProbe + ); + +void +QuicTestMultipleLocalAddresses( + _In_ int Family, + _In_ BOOLEAN ShareBinding, + _In_ BOOLEAN DeferConnIDGen, + _In_ uint32_t DropPacketCount + ); + +void +QuicTestMultipath( + _In_ int Family + ); + void QuicTestNatPortRebind( _In_ int Family, @@ -1331,4 +1359,32 @@ typedef struct { QUIC_CTL_CODE(125, METHOD_BUFFERED, FILE_WRITE_DATA) // BOOLEAN - EnableResumption -#define QUIC_MAX_IOCTL_FUNC_CODE 125 +typedef struct { + int Family; + BOOLEAN ShareBinding; + BOOLEAN DeferConnIDGen; + uint32_t DropPacketCount; +} QUIC_RUN_PROBE_PATH_PARAMS; + +#define IOCTL_QUIC_RUN_PROBE_PATH \ + QUIC_CTL_CODE(126, METHOD_BUFFERED, FILE_WRITE_DATA) + // QUIC_RUN_PROBE_PATH_PARAMS + +typedef struct { + int Family; + BOOLEAN ShareBinding; + BOOLEAN Smooth; +} QUIC_RUN_MIGRATION_PARAMS; + +#define IOCTL_QUIC_RUN_MIGRATION \ + QUIC_CTL_CODE(127, METHOD_BUFFERED, FILE_WRITE_DATA) + // QUIC_RUN_MIGRATION + +typedef struct { + int Family; +} QUIC_RUN_MULTIPATH_PARAMS; + +#define IOCTL_QUIC_RUN_MULTIPATH \ + QUIC_CTL_CODE(128, METHOD_BUFFERED, FILE_WRITE_DATA) + // QUIC_RUN_MULTIPATH +#define QUIC_MAX_IOCTL_FUNC_CODE 128 diff --git a/src/test/bin/quic_gtest.cpp b/src/test/bin/quic_gtest.cpp index 2010fb93bd..c387c33fc8 100644 --- a/src/test/bin/quic_gtest.cpp +++ b/src/test/bin/quic_gtest.cpp @@ -1665,7 +1665,72 @@ TEST_P(WithFamilyArgs, PathValidationTimeout) { QuicTestPathValidationTimeout(GetParam().Family); } } -#endif + +#if defined(QUIC_API_ENABLE_PREVIEW_FEATURES) +TEST_P(WithProbePathArgs, ProbePath) { + TestLoggerT Logger("QuicTestProbePath", GetParam()); + if (TestingKernelMode) { + QUIC_RUN_PROBE_PATH_PARAMS Params = { + GetParam().Family, + GetParam().ShareBinding, + GetParam().DeferConnIDGen, + GetParam().DropPacketCount + }; + ASSERT_TRUE(DriverClient.Run(IOCTL_QUIC_RUN_PROBE_PATH, Params)); + } else { + QuicTestProbePath( + GetParam().Family, + GetParam().ShareBinding, + GetParam().DeferConnIDGen, + GetParam().DropPacketCount); + } +} + +TEST_P(WithMigrationArgs, Migration) { + TestLoggerT Logger("QuicTestMigration", GetParam()); + if (TestingKernelMode) { + QUIC_RUN_MIGRATION_PARAMS Params = { + GetParam().Family, + GetParam().ShareBinding, + GetParam().Smooth + }; + ASSERT_TRUE(DriverClient.Run(IOCTL_QUIC_RUN_MIGRATION, Params)); + } else { + QuicTestMigration(GetParam().Family, GetParam().ShareBinding, GetParam().Smooth); + } +} + +TEST_P(WithProbePathArgs, MultipleLocalAddresses) { + TestLoggerT Logger("QuicTestMultipleLocalAddresses", GetParam()); + if (TestingKernelMode) { + QUIC_RUN_PROBE_PATH_PARAMS Params = { + GetParam().Family, + GetParam().ShareBinding, + GetParam().DeferConnIDGen, + GetParam().DropPacketCount + }; + ASSERT_TRUE(DriverClient.Run(IOCTL_QUIC_RUN_PROBE_PATH, Params)); + } else { + QuicTestMultipleLocalAddresses(GetParam().Family, + GetParam().ShareBinding, + GetParam().DeferConnIDGen, + GetParam().DropPacketCount); + } +} + +TEST_P(WithMultipathArgs, Multipath) { + TestLoggerT Logger("QuicTestMultipath", GetParam()); + if (TestingKernelMode) { + QUIC_RUN_MULTIPATH_PARAMS Params = { + GetParam().Family, + }; + ASSERT_TRUE(DriverClient.Run(IOCTL_QUIC_RUN_MULTIPATH, Params)); + } else { + QuicTestMultipath(GetParam().Family); + } +} +#endif // QUIC_API_ENABLE_PREVIEW_FEATURES +#endif // QUIC_TEST_DATAPATH_HOOKS_ENABLED TEST_P(WithFamilyArgs, ChangeMaxStreamIDs) { TestLoggerT Logger("QuicTestChangeMaxStreamID", GetParam()); @@ -2430,6 +2495,20 @@ INSTANTIATE_TEST_SUITE_P( WithRebindPaddingArgs, ::testing::ValuesIn(RebindPaddingArgs::Generate())); +INSTANTIATE_TEST_SUITE_P( + Basic, + WithProbePathArgs, + ::testing::ValuesIn(ProbePathArgs::Generate())); + +INSTANTIATE_TEST_SUITE_P( + Basic, + WithMigrationArgs, + ::testing::ValuesIn(MigrationArgs::Generate())); + +INSTANTIATE_TEST_SUITE_P( + Basic, + WithMultipathArgs, + ::testing::ValuesIn(MultipathArgs::Generate())); #endif // QUIC_TEST_DATAPATH_HOOKS_ENABLED #ifdef QUIC_API_ENABLE_PREVIEW_FEATURES diff --git a/src/test/bin/quic_gtest.h b/src/test/bin/quic_gtest.h index c280313c23..344bb036f1 100644 --- a/src/test/bin/quic_gtest.h +++ b/src/test/bin/quic_gtest.h @@ -929,3 +929,74 @@ std::ostream& operator << (std::ostream& o, const TlsConfigArgs& args) { class WithValidateTlsConfigArgs : public testing::Test, public testing::WithParamInterface { }; + +#if defined(QUIC_API_ENABLE_PREVIEW_FEATURES) +struct ProbePathArgs { + int Family; + BOOLEAN ShareBinding; + BOOLEAN DeferConnIDGen; + uint32_t DropPacketCount; + static ::std::vector Generate() { + ::std::vector list; + for (int Family : { 4, 6 }) + for (BOOLEAN ShareBinding : { TRUE, FALSE }) + for (BOOLEAN DeferConnIDGen : { TRUE, FALSE }) + for (uint32_t DropPacketCount : { 0, 1 }) + list.push_back({ Family, ShareBinding, DeferConnIDGen, DropPacketCount }); + return list; + } +}; + +std::ostream& operator << (std::ostream& o, const ProbePathArgs& args) { + return o << (args.Family == 4 ? "v4" : "v6") << "/" + << (args.ShareBinding ? "ShareBinding" : "not ShareBinding") << "/" + << (args.DeferConnIDGen ? "DeferConnIDGen" : "not DeferConnIDGen") << "/" + << "DropPacketCount: " << args.DropPacketCount; +} + +class WithProbePathArgs : public testing::Test, + public testing::WithParamInterface { +}; + +struct MigrationArgs { + int Family; + BOOLEAN ShareBinding; + BOOLEAN Smooth; + static ::std::vector Generate() { + ::std::vector list; + for (int Family : { 4, 6 }) + for (BOOLEAN ShareBinding : { TRUE, FALSE }) + for (BOOLEAN Smooth : { TRUE, FALSE }) + list.push_back({ Family, ShareBinding, Smooth }); + return list; + } +}; + +std::ostream& operator << (std::ostream& o, const MigrationArgs& args) { + return o << (args.Family == 4 ? "v4" : "v6") << "/" + << (args.ShareBinding ? "ShareBinding" : "not ShareBinding") << "/" + << (args.Smooth ? "Smooth" : "not Smooth"); +} + +class WithMigrationArgs : public testing::Test, + public testing::WithParamInterface { +}; + +struct MultipathArgs { + int Family; + static ::std::vector Generate() { + ::std::vector list; + for (int Family : { 4, 6 }) + list.push_back({ Family }); + return list; + } +}; + +std::ostream& operator << (std::ostream& o, const MultipathArgs& args) { + return o << (args.Family == 4 ? "v4" : "v6"); +} + +class WithMultipathArgs : public testing::Test, + public testing::WithParamInterface { +}; +#endif diff --git a/src/test/bin/winkernel/control.cpp b/src/test/bin/winkernel/control.cpp index bdeab35fd3..613b5b6465 100644 --- a/src/test/bin/winkernel/control.cpp +++ b/src/test/bin/winkernel/control.cpp @@ -524,6 +524,8 @@ size_t QUIC_IOCTL_BUFFER_SIZES[] = 0, 0, sizeof(BOOLEAN), + sizeof(QUIC_RUN_PROBE_PATH_PARAMS), + sizeof(QUIC_RUN_MIGRATION_PARAMS), }; CXPLAT_STATIC_ASSERT( @@ -555,6 +557,8 @@ typedef union { QUIC_RUN_KEY_UPDATE_RANDOM_LOSS_PARAMS KeyUpdateRandomLossParams; QUIC_RUN_MTU_DISCOVERY_PARAMS MtuDiscoveryParams; uint32_t Test; + QUIC_RUN_PROBE_PATH_PARAMS ProbePathParams; + QUIC_RUN_MIGRATION_PARAMS MigrationParams; QUIC_RUN_REBIND_PARAMS RebindParams; UINT8 RejectByClosing; QUIC_RUN_CIBIR_EXTENSION CibirParams; @@ -955,6 +959,25 @@ QuicTestCtlEvtIoDeviceControl( Params->Family)); break; + case IOCTL_QUIC_RUN_PROBE_PATH: + CXPLAT_FRE_ASSERT(Params != nullptr); + QuicTestCtlRun( + QuicTestProbePath( + Params->ProbePathParams.Family, + Params->ProbePathParams.ShareBinding, + Params->ProbePathParams.DeferConnIDGen, + Params->ProbePathParams.DropPacketCount)); + break; + + case IOCTL_QUIC_RUN_MIGRATION: + CXPLAT_FRE_ASSERT(Params != nullptr); + QuicTestCtlRun( + QuicTestMigration( + Params->MigrationParams.Family, + Params->MigrationParams.ShareBinding, + Params->MigrationParams.Smooth)); + break; + case IOCTL_QUIC_RUN_NAT_PORT_REBIND: CXPLAT_FRE_ASSERT(Params != nullptr); QuicTestCtlRun( diff --git a/src/test/lib/ApiTest.cpp b/src/test/lib/ApiTest.cpp index 71bda9c8ef..19a0543f4f 100644 --- a/src/test/lib/ApiTest.cpp +++ b/src/test/lib/ApiTest.cpp @@ -4521,6 +4521,190 @@ void QuicTest_QUIC_PARAM_CONN_ORIG_DEST_CID(MsQuicRegistration& Registration, Ms } } +#if defined(QUIC_API_ENABLE_PREVIEW_FEATURES) +void QuicTest_QUIC_PARAM_CONN_ADD_LOCAL_ADDRESS(MsQuicRegistration& Registration, MsQuicConfiguration& ClientConfiguration) +{ + TestScopeLogger LogScope0("QUIC_PARAM_CONN_ADD_LOCAL_ADDRESS"); + // + // SetParam + // + { + TestScopeLogger LogScope1("SetParam"); + // + // Connection ClosedLocally + // + { + TestScopeLogger LogScope2("Connection is closed locally"); + TEST_TRUE(ClientConfiguration.IsValid()); + MsQuicConnection Connection(Registration); + TEST_QUIC_SUCCEEDED(Connection.GetInitStatus()); + SimulateConnBadStartState(Connection, ClientConfiguration); + + QUIC_ADDR Dummy = {}; + TEST_QUIC_STATUS( + QUIC_STATUS_INVALID_STATE, + Connection.SetParam( + QUIC_PARAM_CONN_ADD_LOCAL_ADDRESS, + sizeof(Dummy), + &Dummy)); + } + + // + // Good before ConnectionStart + // + { + TestScopeLogger LogScope2("Good before ConnectionStart"); + MsQuicConnection Connection(Registration); + TEST_QUIC_SUCCEEDED(Connection.GetInitStatus()); + QUIC_ADDR Dummy = {}; + TEST_QUIC_SUCCEEDED( + Connection.SetParam( + QUIC_PARAM_CONN_ADD_LOCAL_ADDRESS, + sizeof(Dummy), + &Dummy)); + } + + // + // Good after ConnectionStart + // + { + TestScopeLogger LogScope2("Good after ConnectionStart"); + MsQuicConnection Connection(Registration); + TEST_QUIC_SUCCEEDED(Connection.GetInitStatus()); + TEST_QUIC_SUCCEEDED( + MsQuic->ConnectionStart( + Connection.Handle, + ClientConfiguration, + QUIC_ADDRESS_FAMILY_INET, + "localhost", + 4433)); + + QUIC_ADDR Dummy = {}; + TEST_QUIC_SUCCEEDED( + Connection.SetParam( + QUIC_PARAM_CONN_ADD_LOCAL_ADDRESS, + sizeof(Dummy), + &Dummy)); + } + + // + // Duplicate address + // + { + TestScopeLogger LogScope2("Duplicate address"); + MsQuicConnection Connection(Registration); + TEST_QUIC_SUCCEEDED(Connection.GetInitStatus()); + QUIC_ADDR Dummy = {}; + TEST_QUIC_SUCCEEDED( + Connection.SetParam( + QUIC_PARAM_CONN_ADD_LOCAL_ADDRESS, + sizeof(Dummy), + &Dummy)); + TEST_QUIC_STATUS( + QUIC_STATUS_ADDRESS_IN_USE, + Connection.SetParam( + QUIC_PARAM_CONN_ADD_LOCAL_ADDRESS, + sizeof(Dummy), + &Dummy)); + } + + // + // Multiple local addresses + // + { + TestScopeLogger LogScope2("Multiple local addresses"); + MsQuicConnection Connection(Registration); + TEST_QUIC_SUCCEEDED(Connection.GetInitStatus()); + uint16_t Port = 4433; + + for (uint8_t i = 0; i < 4; i++) { + QUIC_ADDR ClientAddr; + QuicAddrFromString("127.0.0.1", Port++, &ClientAddr); + TEST_QUIC_SUCCEEDED( + Connection.SetParam( + QUIC_PARAM_CONN_ADD_LOCAL_ADDRESS, + sizeof(ClientAddr), + &ClientAddr)); + } + } + } +} + +void QuicTest_QUIC_PARAM_CONN_REMOVE_LOCAL_ADDRESS(MsQuicRegistration& Registration, MsQuicConfiguration& ClientConfiguration) +{ + TestScopeLogger LogScope0("QUIC_PARAM_CONN_REMOVE_LOCAL_ADDRESS"); + // + // SetParam + // + { + TestScopeLogger LogScope1("SetParam"); + // + // No local address to remove + // + { + TestScopeLogger LogScope2("No local address to remove"); + TEST_TRUE(ClientConfiguration.IsValid()); + MsQuicConnection Connection(Registration); + TEST_QUIC_SUCCEEDED(Connection.GetInitStatus()); + + QUIC_ADDR Dummy = {}; + TEST_QUIC_STATUS( + QUIC_STATUS_NOT_FOUND, + Connection.SetParam( + QUIC_PARAM_CONN_REMOVE_LOCAL_ADDRESS, + sizeof(Dummy), + &Dummy)); + } + + // + // Add and remove a local address + // + { + TestScopeLogger LogScope2("Add and remove a local address"); + MsQuicConnection Connection(Registration); + TEST_QUIC_SUCCEEDED(Connection.GetInitStatus()); + QUIC_ADDR Dummy = {}; + TEST_QUIC_SUCCEEDED( + Connection.SetParam( + QUIC_PARAM_CONN_ADD_LOCAL_ADDRESS, + sizeof(Dummy), + &Dummy)); + + TEST_QUIC_SUCCEEDED( + Connection.SetParam( + QUIC_PARAM_CONN_REMOVE_LOCAL_ADDRESS, + sizeof(Dummy), + &Dummy)); + } + + // + // Remove a local address that belongs to another the active path + // + { + TestScopeLogger LogScope2("Remove a local address that belongs to another the active path"); + MsQuicConnection Connection(Registration); + TEST_QUIC_SUCCEEDED(Connection.GetInitStatus()); + TEST_QUIC_SUCCEEDED( + MsQuic->ConnectionStart( + Connection.Handle, + ClientConfiguration, + QUIC_ADDRESS_FAMILY_INET, + "localhost", + 4433)); + + QuicAddr ClientLocalAddr; + TEST_QUIC_SUCCEEDED(Connection.GetLocalAddr(ClientLocalAddr)); + TEST_QUIC_STATUS( + QUIC_STATUS_INVALID_STATE, + Connection.SetParam( + QUIC_PARAM_CONN_REMOVE_LOCAL_ADDRESS, + sizeof(ClientLocalAddr.SockAddr), + &ClientLocalAddr.SockAddr)); + } + } +} +#endif + void QuicTestConnectionParam() { MsQuicAlpn Alpn("MsQuicTest"); @@ -4554,6 +4738,10 @@ 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); +#if defined(QUIC_API_ENABLE_PREVIEW_FEATURES) + QuicTest_QUIC_PARAM_CONN_ADD_LOCAL_ADDRESS(Registration, ClientConfiguration); + QuicTest_QUIC_PARAM_CONN_REMOVE_LOCAL_ADDRESS(Registration, ClientConfiguration); +#endif } // diff --git a/src/test/lib/PathTest.cpp b/src/test/lib/PathTest.cpp index fc5b0c7979..8c92909466 100644 --- a/src/test/lib/PathTest.cpp +++ b/src/test/lib/PathTest.cpp @@ -119,3 +119,389 @@ QuicTestLocalPathChanges( PeerStreamsChanged.Reset(); } } + +#if defined(QUIC_API_ENABLE_PREVIEW_FEATURES) +void +QuicTestProbePath( + _In_ int Family, + _In_ BOOLEAN ShareBinding, + _In_ BOOLEAN DeferConnIDGen, + _In_ uint32_t DropPacketCount + ) +{ + PathTestContext Context; + CxPlatEvent PeerStreamsChanged; + MsQuicRegistration Registration(true); + TEST_TRUE(Registration.IsValid()); + + MsQuicConfiguration ServerConfiguration(Registration, "MsQuicTest", ServerSelfSignedCredConfig); + TEST_TRUE(ServerConfiguration.IsValid()); + + if (DeferConnIDGen) { + BOOLEAN DisableConnIdGeneration = TRUE; + TEST_QUIC_SUCCEEDED( + ServerConfiguration.SetParam( + QUIC_PARAM_CONFIGURATION_CONN_ID_GENERATION_DISABLED, + sizeof(DisableConnIdGeneration), + &DisableConnIdGeneration)); + } + + MsQuicCredentialConfig ClientCredConfig; + MsQuicConfiguration ClientConfiguration(Registration, "MsQuicTest", ClientCredConfig); + TEST_TRUE(ClientConfiguration.IsValid()); + + MsQuicAutoAcceptListener Listener(Registration, ServerConfiguration, PathTestContext::ConnCallback, &Context); + TEST_QUIC_SUCCEEDED(Listener.GetInitStatus()); + QUIC_ADDRESS_FAMILY QuicAddrFamily = (Family == 4) ? QUIC_ADDRESS_FAMILY_INET : QUIC_ADDRESS_FAMILY_INET6; + QuicAddr ServerLocalAddr(QuicAddrFamily); + TEST_QUIC_SUCCEEDED(Listener.Start("MsQuicTest", &ServerLocalAddr.SockAddr)); + TEST_QUIC_SUCCEEDED(Listener.GetLocalAddr(ServerLocalAddr)); + + MsQuicConnection Connection(Registration, CleanUpManual, ClientCallback, &PeerStreamsChanged); + TEST_QUIC_SUCCEEDED(Connection.GetInitStatus()); + + if (ShareBinding) { + Connection.SetShareUdpBinding(); + } + + TEST_QUIC_SUCCEEDED(Connection.Start(ClientConfiguration, ServerLocalAddr.GetFamily(), QUIC_TEST_LOOPBACK_FOR_AF(ServerLocalAddr.GetFamily()), ServerLocalAddr.GetPort())); + TEST_TRUE(Connection.HandshakeCompleteEvent.WaitTimeout(TestWaitTimeout)); + TEST_TRUE(Context.HandshakeCompleteEvent.WaitTimeout(TestWaitTimeout)); + TEST_NOT_EQUAL(nullptr, Context.Connection); + + QuicAddr SecondLocalAddr; + TEST_QUIC_SUCCEEDED(Connection.GetLocalAddr(SecondLocalAddr)); + SecondLocalAddr.IncrementPort(); + + PathProbeHelper *ProbeHelper = new PathProbeHelper(SecondLocalAddr.GetPort(), DropPacketCount, DropPacketCount); + + QUIC_STATUS Status = QUIC_STATUS_SUCCESS; + uint32_t Try = 0; + do { + Status = Connection.SetParam( + QUIC_PARAM_CONN_ADD_LOCAL_ADDRESS, + sizeof(SecondLocalAddr.SockAddr), + &SecondLocalAddr.SockAddr); + + if (Status != QUIC_STATUS_SUCCESS) { + delete ProbeHelper; + SecondLocalAddr.IncrementPort(); + ProbeHelper = new PathProbeHelper(SecondLocalAddr.GetPort(), DropPacketCount, DropPacketCount); + } + } while (Status == QUIC_STATUS_ADDRESS_IN_USE && ++Try <= 3); + TEST_EQUAL(Status, QUIC_STATUS_SUCCESS); + + if (DeferConnIDGen) { + BOOLEAN ReplaceExistingCids = FALSE; + TEST_QUIC_SUCCEEDED( + Context.Connection->SetParam( + QUIC_PARAM_CONN_GENERATE_CONN_ID, + sizeof(ReplaceExistingCids), + &ReplaceExistingCids)); + } + + TEST_TRUE(ProbeHelper->ServerReceiveProbeEvent.WaitTimeout(TestWaitTimeout * 10)); + TEST_TRUE(ProbeHelper->ClientReceiveProbeEvent.WaitTimeout(TestWaitTimeout * 10)); + QUIC_STATISTICS_V2 Stats; + uint32_t Size = sizeof(Stats); + TEST_QUIC_SUCCEEDED( + Connection.GetParam( + QUIC_PARAM_CONN_STATISTICS_V2_PLAT, + &Size, + &Stats)); + TEST_EQUAL(Stats.RecvDroppedPackets, 0); + delete ProbeHelper; +} + +void +QuicTestMigration( + _In_ int Family, + _In_ BOOLEAN ShareBinding, + _In_ BOOLEAN Smooth + ) +{ + PathTestContext Context; + CxPlatEvent PeerStreamsChanged; + MsQuicRegistration Registration(true); + TEST_TRUE(Registration.IsValid()); + + MsQuicConfiguration ServerConfiguration(Registration, "MsQuicTest", ServerSelfSignedCredConfig); + TEST_TRUE(ServerConfiguration.IsValid()); + + MsQuicCredentialConfig ClientCredConfig; + MsQuicConfiguration ClientConfiguration(Registration, "MsQuicTest", ClientCredConfig); + TEST_TRUE(ClientConfiguration.IsValid()); + + MsQuicAutoAcceptListener Listener(Registration, ServerConfiguration, PathTestContext::ConnCallback, &Context); + TEST_QUIC_SUCCEEDED(Listener.GetInitStatus()); + QUIC_ADDRESS_FAMILY QuicAddrFamily = (Family == 4) ? QUIC_ADDRESS_FAMILY_INET : QUIC_ADDRESS_FAMILY_INET6; + QuicAddr ServerLocalAddr(QuicAddrFamily); + TEST_QUIC_SUCCEEDED(Listener.Start("MsQuicTest", &ServerLocalAddr.SockAddr)); + TEST_QUIC_SUCCEEDED(Listener.GetLocalAddr(ServerLocalAddr)); + + MsQuicConnection Connection(Registration, MsQuicCleanUpMode::CleanUpManual, ClientCallback, &PeerStreamsChanged); + TEST_QUIC_SUCCEEDED(Connection.GetInitStatus()); + + if (ShareBinding) { + Connection.SetShareUdpBinding(); + } + + Connection.SetSettings(MsQuicSettings{}.SetKeepAlive(25)); + + TEST_QUIC_SUCCEEDED(Connection.Start(ClientConfiguration, ServerLocalAddr.GetFamily(), QUIC_TEST_LOOPBACK_FOR_AF(ServerLocalAddr.GetFamily()), ServerLocalAddr.GetPort())); + TEST_TRUE(Connection.HandshakeCompleteEvent.WaitTimeout(TestWaitTimeout)); + TEST_TRUE(Context.HandshakeCompleteEvent.WaitTimeout(TestWaitTimeout)); + TEST_NOT_EQUAL(nullptr, Context.Connection); + + QuicAddr SecondLocalAddr; + TEST_QUIC_SUCCEEDED(Connection.GetLocalAddr(SecondLocalAddr)); + SecondLocalAddr.IncrementPort(); + + PathProbeHelper* ProbeHelper = new PathProbeHelper(SecondLocalAddr.GetPort()); + + if (Smooth) { + QUIC_STATUS Status = QUIC_STATUS_SUCCESS; + int Try = 0; + do { + Status = Connection.SetParam( + QUIC_PARAM_CONN_ADD_LOCAL_ADDRESS, + sizeof(SecondLocalAddr.SockAddr), + &SecondLocalAddr.SockAddr); + + if (Status != QUIC_STATUS_SUCCESS) { + delete ProbeHelper; + SecondLocalAddr.IncrementPort(); + ProbeHelper = new PathProbeHelper(SecondLocalAddr.GetPort()); + } + } while (Status == QUIC_STATUS_ADDRESS_IN_USE && ++Try <= 3); + TEST_QUIC_SUCCEEDED(Status); + + TEST_TRUE(ProbeHelper->ServerReceiveProbeEvent.WaitTimeout(TestWaitTimeout)); + TEST_TRUE(ProbeHelper->ClientReceiveProbeEvent.WaitTimeout(TestWaitTimeout)); + delete ProbeHelper; + + QUIC_STATISTICS_V2 Stats; + uint32_t Size = sizeof(Stats); + TEST_QUIC_SUCCEEDED( + Connection.GetParam( + QUIC_PARAM_CONN_STATISTICS_V2_PLAT, + &Size, + &Stats)); + TEST_EQUAL(Stats.RecvDroppedPackets, 0); + + TEST_QUIC_SUCCEEDED( + Connection.SetParam( + QUIC_PARAM_CONN_LOCAL_ADDRESS, + sizeof(SecondLocalAddr.SockAddr), + &SecondLocalAddr.SockAddr)); + } else { + // + // Wait for handshake confirmation. + // + CxPlatSleep(100); + + QUIC_STATUS Status = QUIC_STATUS_SUCCESS; + int Try = 0; + do { + Status = Connection.SetParam( + QUIC_PARAM_CONN_LOCAL_ADDRESS, + sizeof(SecondLocalAddr.SockAddr), + &SecondLocalAddr.SockAddr); + if (Status != QUIC_STATUS_SUCCESS) { + SecondLocalAddr.IncrementPort(); + } + } while (Status == QUIC_STATUS_ADDRESS_IN_USE && ++Try <= 3); + TEST_QUIC_SUCCEEDED(Status); + } + + + TEST_TRUE(Context.PeerAddrChangedEvent.WaitTimeout(1500)); + QuicAddr ServerRemoteAddr; + TEST_QUIC_SUCCEEDED(Context.Connection->GetRemoteAddr(ServerRemoteAddr)); + TEST_TRUE(QuicAddrCompare(&SecondLocalAddr.SockAddr, &ServerRemoteAddr.SockAddr)); + Connection.SetSettings(MsQuicSettings{}.SetKeepAlive(0)); + TEST_TRUE(PeerStreamsChanged.WaitTimeout(1500)); +} + +void +QuicTestMultipleLocalAddresses( + _In_ int Family, + _In_ BOOLEAN ShareBinding, + _In_ BOOLEAN DeferConnIDGen, + _In_ uint32_t DropPacketCount + ) +{ + PathTestContext Context; + CxPlatEvent PeerStreamsChanged; + MsQuicRegistration Registration(true); + TEST_TRUE(Registration.IsValid()); + + MsQuicConfiguration ServerConfiguration(Registration, "MsQuicTest", ServerSelfSignedCredConfig); + TEST_TRUE(ServerConfiguration.IsValid()); + + if (DeferConnIDGen) { + BOOLEAN DisableConnIdGeneration = TRUE; + TEST_QUIC_SUCCEEDED( + ServerConfiguration.SetParam( + QUIC_PARAM_CONFIGURATION_CONN_ID_GENERATION_DISABLED, + sizeof(DisableConnIdGeneration), + &DisableConnIdGeneration)); + } + + MsQuicCredentialConfig ClientCredConfig; + MsQuicConfiguration ClientConfiguration(Registration, "MsQuicTest", ClientCredConfig); + TEST_TRUE(ClientConfiguration.IsValid()); + + MsQuicAutoAcceptListener Listener(Registration, ServerConfiguration, PathTestContext::ConnCallback, &Context); + TEST_QUIC_SUCCEEDED(Listener.GetInitStatus()); + QUIC_ADDRESS_FAMILY QuicAddrFamily = (Family == 4) ? QUIC_ADDRESS_FAMILY_INET : QUIC_ADDRESS_FAMILY_INET6; + QuicAddr ServerLocalAddr(QuicAddrFamily); + TEST_QUIC_SUCCEEDED(Listener.Start("MsQuicTest", &ServerLocalAddr.SockAddr)); + TEST_QUIC_SUCCEEDED(Listener.GetLocalAddr(ServerLocalAddr)); + + MsQuicConnection Connection(Registration, CleanUpManual, ClientCallback, &PeerStreamsChanged); + TEST_QUIC_SUCCEEDED(Connection.GetInitStatus()); + + if (ShareBinding) { + Connection.SetShareUdpBinding(); + } + + QuicAddr ClientLocalAddrs[4] = {QuicAddrFamily, QuicAddrFamily, QuicAddrFamily, QuicAddrFamily}; + for (uint8_t i = 0; i < 4; i++) { + ClientLocalAddrs[i].SetPort(rand() % 65536); + QUIC_STATUS Status; + uint32_t Try = 0; + do { + Status = Connection.SetParam( + QUIC_PARAM_CONN_ADD_LOCAL_ADDRESS, + sizeof(ClientLocalAddrs[i].SockAddr), + &ClientLocalAddrs[i].SockAddr); + if (Status != QUIC_STATUS_ADDRESS_IN_USE) { + TEST_QUIC_SUCCEEDED(Status); + break; + } + } while (++Try < 3); + TEST_QUIC_SUCCEEDED(Status); + } + + PathProbeHelper ProbeHelpers[3] = { + {ClientLocalAddrs[1].GetPort(), DropPacketCount, DropPacketCount}, + {ClientLocalAddrs[2].GetPort(), DropPacketCount, DropPacketCount}, + {ClientLocalAddrs[3].GetPort(), DropPacketCount, DropPacketCount}}; + + TEST_QUIC_SUCCEEDED(Connection.Start(ClientConfiguration, ServerLocalAddr.GetFamily(), QUIC_TEST_LOOPBACK_FOR_AF(ServerLocalAddr.GetFamily()), ServerLocalAddr.GetPort())); + TEST_TRUE(Connection.HandshakeCompleteEvent.WaitTimeout(TestWaitTimeout)); + TEST_TRUE(Context.HandshakeCompleteEvent.WaitTimeout(TestWaitTimeout)); + TEST_NOT_EQUAL(nullptr, Context.Connection); + + if (DeferConnIDGen) { + BOOLEAN ReplaceExistingCids = FALSE; + TEST_QUIC_SUCCEEDED( + Context.Connection->SetParam( + QUIC_PARAM_CONN_GENERATE_CONN_ID, + sizeof(ReplaceExistingCids), + &ReplaceExistingCids)); + } + + TEST_TRUE(ProbeHelpers[0].ServerReceiveProbeEvent.WaitTimeout(TestWaitTimeout * 10)); + TEST_TRUE(ProbeHelpers[0].ClientReceiveProbeEvent.WaitTimeout(TestWaitTimeout * 10)); + TEST_TRUE(ProbeHelpers[1].ServerReceiveProbeEvent.WaitTimeout(TestWaitTimeout * 10)); + TEST_TRUE(ProbeHelpers[1].ClientReceiveProbeEvent.WaitTimeout(TestWaitTimeout * 10)); + TEST_TRUE(ProbeHelpers[2].ServerReceiveProbeEvent.WaitTimeout(TestWaitTimeout * 10)); + TEST_TRUE(ProbeHelpers[2].ClientReceiveProbeEvent.WaitTimeout(TestWaitTimeout * 10)); +} + +void +QuicTestMultipath( + _In_ int Family + ) +{ + PathTestContext Context; + CxPlatEvent PeerStreamsChanged; + MsQuicRegistration Registration(true); + TEST_TRUE(Registration.IsValid()); + + MsQuicConfiguration ServerConfiguration(Registration, + "MsQuicTest", + MsQuicSettings{}.SetMultipathEnabled(TRUE), + ServerSelfSignedCredConfig); + + TEST_TRUE(ServerConfiguration.IsValid()); + + MsQuicCredentialConfig ClientCredConfig; + MsQuicConfiguration ClientConfiguration(Registration, + "MsQuicTest", + MsQuicSettings{}.SetMultipathEnabled(TRUE), + ClientCredConfig); + TEST_TRUE(ClientConfiguration.IsValid()); + + MsQuicAutoAcceptListener Listener(Registration, ServerConfiguration, PathTestContext::ConnCallback, &Context); + TEST_QUIC_SUCCEEDED(Listener.GetInitStatus()); + QUIC_ADDRESS_FAMILY QuicAddrFamily = (Family == 4) ? QUIC_ADDRESS_FAMILY_INET : QUIC_ADDRESS_FAMILY_INET6; + QuicAddr ServerLocalAddr(QuicAddrFamily); + TEST_QUIC_SUCCEEDED(Listener.Start("MsQuicTest", &ServerLocalAddr.SockAddr)); + TEST_QUIC_SUCCEEDED(Listener.GetLocalAddr(ServerLocalAddr)); + + MsQuicConnection Connection(Registration, MsQuicCleanUpMode::CleanUpManual, ClientCallback, &PeerStreamsChanged); + TEST_QUIC_SUCCEEDED(Connection.GetInitStatus()); + + Connection.SetShareUdpBinding(); + + Connection.SetSettings(MsQuicSettings{}.SetKeepAlive(25)); + + TEST_QUIC_SUCCEEDED(Connection.Start(ClientConfiguration, ServerLocalAddr.GetFamily(), QUIC_TEST_LOOPBACK_FOR_AF(ServerLocalAddr.GetFamily()), ServerLocalAddr.GetPort())); + TEST_TRUE(Connection.HandshakeCompleteEvent.WaitTimeout(TestWaitTimeout)); + TEST_TRUE(Context.HandshakeCompleteEvent.WaitTimeout(TestWaitTimeout)); + TEST_NOT_EQUAL(nullptr, Context.Connection); + + QuicAddr SecondLocalAddr; + TEST_QUIC_SUCCEEDED(Connection.GetLocalAddr(SecondLocalAddr)); + SecondLocalAddr.IncrementPort(); + + PathProbeHelper* ProbeHelper = new PathProbeHelper(SecondLocalAddr.GetPort()); + + QUIC_STATUS Status = QUIC_STATUS_SUCCESS; + int Try = 0; + do { + Status = Connection.SetParam( + QUIC_PARAM_CONN_ADD_LOCAL_ADDRESS, + sizeof(SecondLocalAddr.SockAddr), + &SecondLocalAddr.SockAddr); + + if (Status != QUIC_STATUS_SUCCESS) { + delete ProbeHelper; + SecondLocalAddr.IncrementPort(); + ProbeHelper = new PathProbeHelper(SecondLocalAddr.GetPort()); + } + } while (Status == QUIC_STATUS_ADDRESS_IN_USE && ++Try <= 3); + TEST_QUIC_SUCCEEDED(Status); + + TEST_TRUE(ProbeHelper->ServerReceiveProbeEvent.WaitTimeout(TestWaitTimeout)); + TEST_TRUE(ProbeHelper->ClientReceiveProbeEvent.WaitTimeout(TestWaitTimeout)); + delete ProbeHelper; + + QUIC_STATISTICS_V2 Stats; + uint32_t Size = sizeof(Stats); + TEST_QUIC_SUCCEEDED( + Connection.GetParam( + QUIC_PARAM_CONN_STATISTICS_V2_PLAT, + &Size, + &Stats)); + TEST_EQUAL(Stats.RecvDroppedPackets, 0); + + // TEST_QUIC_SUCCEEDED( + // Connection.SetParam( + // QUIC_PARAM_CONN_REMOVE_LOCAL_ADDRESS, + // sizeof(SecondLocalAddr.SockAddr), + // &SecondLocalAddr.SockAddr)); + + // BOOLEAN ReplaceExistingCids = TRUE; + // TEST_QUIC_SUCCEEDED( + // Context.Connection->SetParam( + // QUIC_PARAM_CONN_GENERATE_CONN_ID, + // sizeof(ReplaceExistingCids), + // &ReplaceExistingCids)); + + CxPlatSleep(5000); +} +#endif diff --git a/src/test/lib/TestHelpers.h b/src/test/lib/TestHelpers.h index d4a04f9d58..cbfd6ce504 100644 --- a/src/test/lib/TestHelpers.h +++ b/src/test/lib/TestHelpers.h @@ -782,6 +782,49 @@ struct MtuDropHelper : public DatapathHook } }; +struct PathProbeHelper : public DatapathHook +{ + uint16_t ClientProbePort; + CxPlatEvent ServerReceiveProbeEvent; + CxPlatEvent ClientReceiveProbeEvent; + uint32_t ClientDropPacketCount; + uint32_t ServerDropPacketCount; + PathProbeHelper(uint16_t ClientPort, uint32_t ClientCount = 0, uint32_t ServerCount = 0) : + ClientProbePort(ClientPort), + ClientDropPacketCount(ClientCount), + ServerDropPacketCount(ServerCount) { + DatapathHooks::Instance->AddHook(this); + } + ~PathProbeHelper() { + DatapathHooks::Instance->RemoveHook(this); + } + void ClientDropPackets(uint32_t Count) { ClientDropPacketCount = Count; } + void ServerDropPackets(uint32_t Count) { ServerDropPacketCount = Count; } + _IRQL_requires_max_(DISPATCH_LEVEL) + BOOLEAN + Receive( + _Inout_ struct CXPLAT_RECV_DATA* Datagram + ) { + if (QuicAddrGetPort(&Datagram->Route->RemoteAddress) == ClientProbePort) { + if (ClientDropPacketCount == 0) { + ServerReceiveProbeEvent.Set(); + } else { + ClientDropPacketCount--; + return TRUE; + } + } + if (QuicAddrGetPort(&Datagram->Route->LocalAddress) == ClientProbePort) { + if (ServerDropPacketCount == 0) { + ClientReceiveProbeEvent.Set(); + } else { + ServerDropPacketCount--; + return TRUE; + } + } + return FALSE; + } +}; + struct ReplaceAddressHelper : public DatapathHook { QUIC_ADDR Original; diff --git a/src/tools/recvfuzz/recvfuzz.cpp b/src/tools/recvfuzz/recvfuzz.cpp index 178fb00e97..080d205663 100644 --- a/src/tools/recvfuzz/recvfuzz.cpp +++ b/src/tools/recvfuzz/recvfuzz.cpp @@ -426,6 +426,8 @@ bool WriteAckFrame( QuicRangeAddRange(&AckRange, LargestAcknowledge, 1, &RangeUpdated); uint64_t AckDelay = 40; if (!QuicAckFrameEncode( + FALSE, + 0, &AckRange, AckDelay, nullptr,