From 3ca34bb1e23000f137380e686ee2c430cb371cff Mon Sep 17 00:00:00 2001 From: "masa.koz" Date: Thu, 28 Mar 2024 08:10:09 +0000 Subject: [PATCH 01/29] Add active migration support. --- src/core/binding.c | 91 ++++-- src/core/binding.h | 44 ++- src/core/cid.h | 34 ++- src/core/connection.c | 426 +++++++++++++++++++++++++---- src/core/connection.h | 29 +- src/core/crypto.c | 14 +- src/core/inline.c | 15 +- src/core/library.h | 11 +- src/core/lookup.c | 177 +++++------- src/core/lookup.h | 27 +- src/core/loss_detection.c | 4 +- src/core/packet_builder.c | 3 +- src/core/packet_builder.h | 2 +- src/core/path.c | 32 ++- src/core/path.h | 10 + src/core/send.c | 4 +- src/inc/msquic.h | 3 + src/inc/quic_platform.h | 4 +- src/platform/datapath_winkernel.c | 1 - src/test/MsQuicTests.h | 36 ++- src/test/bin/quic_gtest.cpp | 37 +++ src/test/bin/quic_gtest.h | 48 ++++ src/test/bin/winkernel/control.cpp | 22 ++ src/test/lib/PathTest.cpp | 178 ++++++++++++ src/test/lib/TestHelpers.h | 43 +++ 25 files changed, 1030 insertions(+), 265 deletions(-) diff --git a/src/core/binding.c b/src/core/binding.c index d8f77fdd5f..5895ebec60 100644 --- a/src/core/binding.c +++ b/src/core/binding.c @@ -560,46 +560,101 @@ _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 + ) +{ + for (CXPLAT_SLIST_ENTRY* Link = Connection->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)) { + QuicBindingRemoveAllSourceConnectionIDs(Binding, Connection); + return FALSE; + } + } + + return TRUE; +} + _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); + CXPLAT_SLIST_ENTRY EntriesToFree = {0}; + + for (CXPLAT_SLIST_ENTRY* Link = Connection->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); } - 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) @@ -1280,10 +1335,10 @@ QuicBindingCreateConnection( BOOLEAN BindingRefAdded = FALSE; CXPLAT_DBG_ASSERT(NewConnection->SourceCids.Next != NULL); - QUIC_CID_HASH_ENTRY* SourceCid = + QUIC_CID_SLIST_ENTRY* SourceCid = CXPLAT_CONTAINING_RECORD( NewConnection->SourceCids.Next, - QUIC_CID_HASH_ENTRY, + QUIC_CID_SLIST_ENTRY, Link); QuicConnAddRef(NewConnection, QUIC_CONN_REF_LOOKUP_RESULT); @@ -1318,6 +1373,8 @@ QuicBindingCreateConnection( } goto Exit; } + CXPLAT_DBG_ASSERT(NewConnection->RemoteHashEntry != NULL); + NewConnection->RemoteHashEntry->Binding = Binding; QuicWorkerQueueConnection(NewConnection->Worker, NewConnection); @@ -1351,7 +1408,7 @@ QuicBindingCreateConnection( } else { NewConnection->SourceCids.Next = NULL; - CXPLAT_FREE(SourceCid, QUIC_POOL_CIDHASH); + 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); diff --git a/src/core/binding.h b/src/core/binding.h index 1c5b94e42b..9258d25a23 100644 --- a/src/core/binding.h +++ b/src/core/binding.h @@ -373,7 +373,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 +394,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 +521,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); +} \ No newline at end of file diff --git a/src/core/cid.h b/src/core/cid.h index 845c7a960b..b5fcc47ee9 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_CONNECTION* Connection; + 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_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 ) { - 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->HashEntries.Next = NULL; CxPlatZeroMemory(&Entry->CID, sizeof(Entry->CID)); } @@ -201,7 +212,7 @@ QuicCidNewNullSource( // inline _Success_(return != NULL) -QUIC_CID_HASH_ENTRY* +QUIC_CID_SLIST_ENTRY* QuicCidNewSource( _In_ QUIC_CONNECTION* Connection, _In_ uint8_t Length, @@ -209,15 +220,16 @@ QuicCidNewSource( 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->HashEntries.Next = NULL; CxPlatZeroMemory(&Entry->CID, sizeof(Entry->CID)); Entry->CID.Length = Length; if (Length != 0) { diff --git a/src/core/connection.c b/src/core/connection.c index 70fe9425ae..cef8e55695 100644 --- a/src/core/connection.c +++ b/src/core/connection.c @@ -214,7 +214,7 @@ QuicConnAlloc( Path->DestCid->CID.SequenceNumber, CASTED_CLOG_BYTEARRAY(Path->DestCid->CID.Length, Path->DestCid->CID.Data)); - QUIC_CID_HASH_ENTRY* SourceCid = + QUIC_CID_SLIST_ENTRY* SourceCid = QuicCidNewSource(Connection, Packet->DestCidLen, Packet->DestCid); if (SourceCid == NULL) { Status = QUIC_STATUS_OUT_OF_MEMORY; @@ -288,9 +288,9 @@ QuicConnAlloc( CXPLAT_FREE( CXPLAT_CONTAINING_RECORD( Connection->SourceCids.Next, - QUIC_CID_HASH_ENTRY, + QUIC_CID_SLIST_ENTRY, Link), - QUIC_POOL_CIDHASH); + QUIC_POOL_CIDSLIST); Connection->SourceCids.Next = NULL; } while (!CxPlatListIsEmpty(&Connection->DestCids)) { @@ -360,10 +360,11 @@ 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].Binding != NULL) { + QuicLibraryReleaseBinding(Connection->Paths[i].Binding); + Connection->Paths[i].Binding = NULL; + } } CxPlatDispatchLockUninitialize(&Connection->ReceiveQueueLock); QuicOperationQueueUninitialize(&Connection->OperQ); @@ -607,10 +608,10 @@ QuicConnTraceRundownOper( for (CXPLAT_SLIST_ENTRY* Entry = Connection->SourceCids.Next; Entry != NULL; Entry = Entry->Next) { - const QUIC_CID_HASH_ENTRY* SourceCid = + const QUIC_CID_SLIST_ENTRY* SourceCid = CXPLAT_CONTAINING_RECORD( Entry, - QUIC_CID_HASH_ENTRY, + QUIC_CID_SLIST_ENTRY, Link); UNREFERENCED_PARAMETER(SourceCid); QuicTraceEvent( @@ -801,14 +802,14 @@ QuicConnUpdateRtt( } _IRQL_requires_max_(PASSIVE_LEVEL) -QUIC_CID_HASH_ENTRY* +QUIC_CID_SLIST_ENTRY* QuicConnGenerateNewSourceCid( _In_ QUIC_CONNECTION* Connection, _In_ BOOLEAN IsInitial ) { uint8_t TryCount = 0; - QUIC_CID_HASH_ENTRY* SourceCid; + QUIC_CID_SLIST_ENTRY* SourceCid; if (!Connection->State.ShareBinding) { // @@ -836,12 +837,37 @@ QuicConnGenerateNewSourceCid( AllocFailure, "Allocation of '%s' failed. (%llu bytes)", "new Src CID", - sizeof(QUIC_CID_HASH_ENTRY) + MsQuicLib.CidTotalLength); + sizeof(QUIC_CID_SLIST_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); + + BOOLEAN Collision = FALSE; + + CxPlatDispatchLockAcquire(&MsQuicLib.DatapathLock); + + // Check whether a sourceCid collides or not around all the connections. + for (CXPLAT_LIST_ENTRY* Link = MsQuicLib.Bindings.Flink; + Link != &MsQuicLib.Bindings; + Link = Link->Flink) { + + QUIC_BINDING* Binding = + CXPLAT_CONTAINING_RECORD(Link, QUIC_BINDING, Link); + QUIC_CONNECTION* Connection1 = + QuicLookupFindConnectionByLocalCid( + &Binding->Lookup, + SourceCid->CID.Data, + SourceCid->CID.Length); + if (Connection1 != NULL) { + Collision = TRUE; + break; + } + } + + CxPlatDispatchLockRelease(&MsQuicLib.DatapathLock); + + if (Collision) { + CXPLAT_FREE(SourceCid, QUIC_POOL_CIDSLIST); SourceCid = NULL; if (++TryCount > QUIC_CID_MAX_COLLISION_RETRY) { QuicTraceEvent( @@ -859,6 +885,14 @@ QuicConnGenerateNewSourceCid( } } while (SourceCid == NULL); + for (uint8_t i = 0; i < Connection->PathsCount; ++i) { + if (Connection->Paths[i].Binding != NULL) { + QuicBindingAddSourceConnectionID(Connection->Paths[i].Binding, SourceCid); + } + } + + SourceCid->CID.SequenceNumber = Connection->NextSourceCidSequenceNumber++; + QuicTraceEvent( ConnSourceCidAdded, "[conn][%p] (SeqNum=%llu) New Source CID: %!CID!", @@ -866,7 +900,6 @@ QuicConnGenerateNewSourceCid( 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); @@ -930,8 +963,8 @@ QuicConnGenerateNewSourceCids( 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); + QUIC_CID_SLIST_ENTRY* SourceCid = + CXPLAT_CONTAINING_RECORD(Entry, QUIC_CID_SLIST_ENTRY, Link); SourceCid->CID.Retired = TRUE; Entry = Entry->Next; } @@ -952,6 +985,28 @@ QuicConnGenerateNewSourceCids( } } +_IRQL_requires_max_(PASSIVE_LEVEL) +uint16_t +QuicConnUnusedDestCidsCount( + _In_ const QUIC_CONNECTION* Connection + ) +{ + uint16_t Count = 0; + 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) { + ++Count; + } + } + return Count; +} + _IRQL_requires_max_(PASSIVE_LEVEL) QUIC_CID_LIST_ENTRY* QuicConnGetUnusedDestCid( @@ -1084,7 +1139,6 @@ QuicConnReplaceRetiredCids( 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) { @@ -1106,8 +1160,10 @@ QuicConnReplaceRetiredCids( } CXPLAT_DBG_ASSERT(NewDestCid != Path->DestCid); + QUIC_CID_LIST_ENTRY* OldDestCid = Path->DestCid; Path->DestCid = NewDestCid; QUIC_CID_SET_PATH(Connection, NewDestCid, Path); + QUIC_CID_VALIDATE_NULL(Connection, OldDestCid); Path->DestCid->CID.UsedLocally = TRUE; Path->InitiatedCidUpdate = TRUE; QuicPathValidate(Path); @@ -1356,12 +1412,36 @@ 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. + // + if (Connection->RemoteHashEntry != NULL) { + CXPLAT_DBG_ASSERT(Connection->RemoteHashEntry->Binding != NULL); + QuicBindingRemoveRemoteHash( + Connection->RemoteHashEntry->Binding, + Connection->RemoteHashEntry); + } - // - // Remove all entries in the binding's lookup tables so we don't get any - // more packets queued. - // - QuicBindingRemoveConnection(Connection->Paths[0].Binding, Connection); + while (Connection->SourceCids.Next != NULL) { + QUIC_CID_SLIST_ENTRY* CID = + CXPLAT_CONTAINING_RECORD( + CxPlatListPopEntry(&Connection->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); } // @@ -1852,7 +1932,7 @@ 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( @@ -2230,10 +2310,10 @@ QuicConnGenerateLocalTransportParameters( CXPLAT_TEL_ASSERT(Connection->Configuration != NULL); CXPLAT_DBG_ASSERT(Connection->SourceCids.Next != NULL); - const QUIC_CID_HASH_ENTRY* SourceCid = + const QUIC_CID_SLIST_ENTRY* SourceCid = CXPLAT_CONTAINING_RECORD( Connection->SourceCids.Next, - QUIC_CID_HASH_ENTRY, + QUIC_CID_SLIST_ENTRY, Link); LocalTP->InitialMaxData = Connection->Send.MaxData; @@ -2365,10 +2445,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; @@ -4982,7 +5062,7 @@ QuicConnRecvFrames( } BOOLEAN IsLastCid; - QUIC_CID_HASH_ENTRY* SourceCid = + QUIC_CID_SLIST_ENTRY* SourceCid = QuicConnGetSourceCidFromSeq( Connection, Frame.Sequence, @@ -4990,7 +5070,7 @@ QuicConnRecvFrames( &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, @@ -5065,7 +5145,7 @@ QuicConnRecvFrames( !memcmp(Frame.Data, TempPath->Challenge, sizeof(Frame.Data))) { QuicPerfCounterIncrement(QUIC_PERF_COUNTER_PATH_VALIDATED); QuicPathSetValid(Connection, TempPath, QUIC_PATH_VALID_PATH_RESPONSE); - break; + break; } } @@ -5310,7 +5390,7 @@ QuicConnRecvPostProcessing( { BOOLEAN PeerUpdatedCid = FALSE; if (Packet->DestCidLen != 0) { - QUIC_CID_HASH_ENTRY* SourceCid = + QUIC_CID_SLIST_ENTRY* SourceCid = QuicConnGetSourceCidFromBuf( Connection, Packet->DestCidLen, @@ -5331,7 +5411,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. @@ -5403,7 +5484,8 @@ QuicConnRecvPostProcessing( } } - if (Packet->HasNonProbingFrame && + if (QuicConnIsServer(Connection) && + Packet->HasNonProbingFrame && Packet->NewLargestPacketNumber && !(*Path)->IsActive) { // @@ -5759,20 +5841,22 @@ 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); + QuicPathRemove(Connection, i); + } } } @@ -6141,6 +6225,15 @@ QuicConnParamSet( break; } + 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; + } + Connection->State.LocalAddressSet = TRUE; CxPlatCopyMemory(&Connection->Paths[0].Route.LocalAddress, Buffer, sizeof(QUIC_ADDR)); QuicTraceEvent( @@ -6182,8 +6275,8 @@ QuicConnParamSet( // TODO - Need to free any queued recv packets from old binding. // - QuicBindingMoveSourceConnectionIDs( - OldBinding, Connection->Paths[0].Binding, Connection); + QuicBindingAddAllSourceConnectionIDs(Connection->Paths[0].Binding, Connection); + QuicBindingRemoveAllSourceConnectionIDs(OldBinding, Connection); QuicLibraryReleaseBinding(OldBinding); QuicTraceEvent( @@ -6567,6 +6660,217 @@ QuicConnParamSet( return QUIC_STATUS_SUCCESS; } + case QUIC_PARAM_CONN_ADD_LOCAL_ADDRESS: { + + if (BufferLength != sizeof(QUIC_ADDR)) { + Status = QUIC_STATUS_INVALID_PARAMETER; + break; + } + + if (QuicConnIsServer(Connection)) { + Status = QUIC_STATUS_INVALID_STATE; + break; + } + + if (!Connection->State.Started) { + Status = QUIC_STATUS_INVALID_STATE; + break; + } + + QUIC_CID_LIST_ENTRY* NewDestCid = QuicConnGetUnusedDestCid(Connection); + if (NewDestCid == NULL) { + Status = QUIC_STATUS_INVALID_STATE; + break; + } + + const QUIC_ADDR* LocalAddress = (const QUIC_ADDR*)Buffer; + + if (!QuicAddrIsValid(LocalAddress)) { + Status = QUIC_STATUS_INVALID_PARAMETER; + break; + } + + BOOLEAN AddrInUse = FALSE; + for (uint8_t i = 0; i < Connection->PathsCount; ++i) { + if (QuicAddrCompare( + &Connection->Paths[i].Route.LocalAddress, + LocalAddress)) { + AddrInUse = TRUE; + break; + } + } + + if (AddrInUse) { + Status = QUIC_STATUS_ADDRESS_IN_USE; + break; + } + + if (Connection->PathsCount == QUIC_MAX_PATH_COUNT) { + // + // Already tracking the maximum number of paths, and can't free + // any more. + // + Status = QUIC_STATUS_OUT_OF_MEMORY; + break; + } + + CXPLAT_DBG_ASSERT(Connection->State.RemoteAddressSet); + CXPLAT_DBG_ASSERT(Connection->Configuration != NULL); + + CXPLAT_UDP_CONFIG UdpConfig = {0}; + UdpConfig.LocalAddress = 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; + Status = + QuicLibraryGetBinding( + &UdpConfig, + &NewBinding); + if (QUIC_FAILED(Status)) { + break; + } + + if (!Connection->State.ShareBinding) { + QUIC_CID_SLIST_ENTRY* SourceCid = QuicCidNewNullSource(Connection); + if (SourceCid == NULL) { + QuicLibraryReleaseBinding(NewBinding); + Status = QUIC_STATUS_OUT_OF_MEMORY; + break; + } + + 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); + + if (!QuicBindingAddSourceConnectionID(NewBinding, SourceCid)) { + QuicLibraryReleaseBinding(NewBinding); + Status = QUIC_STATUS_OUT_OF_MEMORY; + break; + } + } else { + if (!QuicBindingAddAllSourceConnectionIDs(NewBinding, Connection)) { + QuicLibraryReleaseBinding(NewBinding); + Status = QUIC_STATUS_OUT_OF_MEMORY; + break; + } + } + + 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)); + } + + QUIC_PATH* Path = &Connection->Paths[1]; + QuicPathInitialize(Connection, Path); + Connection->PathsCount++; + + Path->Binding = NewBinding; + + QuicBindingGetLocalAddress( + Path->Binding, + &Path->Route.LocalAddress); + CxPlatCopyMemory(&Path->Route.RemoteAddress, &Connection->Paths[0].Route.RemoteAddress, sizeof(QUIC_ADDR)); + + Path->Allowance = UINT32_MAX; + + 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); + + QuicTraceEvent( + ConnLocalAddrAdded, + "[conn][%p] New Local IP: %!ADDR!", + Connection, + CASTED_CLOG_BYTEARRAY(sizeof(Path->Route.LocalAddress), &Path->Route.LocalAddress)); + + QuicSendSetSendFlag(&Connection->Send, QUIC_CONN_SEND_FLAG_PATH_CHALLENGE); + + Status = QUIC_STATUS_SUCCESS; + break; + } + + case QUIC_PARAM_CONN_REMOVE_LOCAL_ADDRESS: { + + if (BufferLength != sizeof(QUIC_ADDR)) { + Status = QUIC_STATUS_INVALID_PARAMETER; + break; + } + + if (QuicConnIsServer(Connection)) { + Status = QUIC_STATUS_INVALID_STATE; + break; + } + + if (!Connection->State.Started) { + Status = QUIC_STATUS_INVALID_STATE; + break; + } + + const QUIC_ADDR* LocalAddress = (const QUIC_ADDR*)Buffer; + + if (!QuicAddrIsValid(LocalAddress)) { + Status = QUIC_STATUS_INVALID_PARAMETER; + break; + } + + 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) { + Status = QUIC_STATUS_NOT_FOUND; + break; + } + + QUIC_PATH* Path = &Connection->Paths[PathIndex]; + + if (Path->IsActive) { + Status = QUIC_STATUS_INVALID_STATE; + break; + } + + QuicConnRetireCid(Connection, Path->DestCid); + + QuicBindingRemoveAllSourceConnectionIDs(Path->Binding, Connection); + QuicLibraryReleaseBinding(Path->Binding); + + QuicPathRemove(Connection, PathIndex); + + Status = QUIC_STATUS_SUCCESS; + break; + } + // // Private // @@ -7156,10 +7460,12 @@ QuicConnParamGet( *BufferLength = Connection->OrigDestCID->Length; break; } + if (Buffer == NULL) { Status = QUIC_STATUS_INVALID_PARAMETER; break; } + CxPlatCopyMemory( Buffer, Connection->OrigDestCID->Data, @@ -7168,6 +7474,26 @@ QuicConnParamGet( // Tell app how much buffer we copied. // *BufferLength = Connection->OrigDestCID->Length; + + Status = QUIC_STATUS_SUCCESS; + break; + + case QUIC_PARAM_CONN_LOCAL_UNUSED_DEST_CID_COUNT: + if (*BufferLength < sizeof(uint16_t)) { + *BufferLength = sizeof(uint16_t); + Status = QUIC_STATUS_BUFFER_TOO_SMALL; + break; + } + + if (Buffer == NULL) { + Status = QUIC_STATUS_INVALID_PARAMETER; + break; + } + + *BufferLength = sizeof(uint16_t); + *(uint16_t*)Buffer = + QuicConnUnusedDestCidsCount(Connection); + Status = QUIC_STATUS_SUCCESS; break; diff --git a/src/core/connection.h b/src/core/connection.h index 7a327f497e..35b9f925f7 100644 --- a/src/core/connection.h +++ b/src/core/connection.h @@ -1162,7 +1162,7 @@ QuicConnQueueHighestPriorityOper( // Generates a new source connection ID. // _IRQL_requires_max_(PASSIVE_LEVEL) -QUIC_CID_HASH_ENTRY* +QUIC_CID_SLIST_ENTRY* QuicConnGenerateNewSourceCid( _In_ QUIC_CONNECTION* Connection, _In_ BOOLEAN IsInitial @@ -1194,7 +1194,7 @@ QuicConnRetireCurrentDestCid( _IRQL_requires_max_(DISPATCH_LEVEL) _Success_(return != NULL) inline -QUIC_CID_HASH_ENTRY* +QUIC_CID_SLIST_ENTRY* QuicConnGetSourceCidFromSeq( _In_ QUIC_CONNECTION* Connection, _In_ QUIC_VAR_INT SequenceNumber, @@ -1205,23 +1205,30 @@ QuicConnGetSourceCidFromSeq( for (CXPLAT_SLIST_ENTRY** Entry = &Connection->SourceCids.Next; *Entry != NULL; Entry = &(*Entry)->Next) { - QUIC_CID_HASH_ENTRY* SourceCid = + QUIC_CID_SLIST_ENTRY* SourceCid = CXPLAT_CONTAINING_RECORD( *Entry, - QUIC_CID_HASH_ENTRY, + QUIC_CID_SLIST_ENTRY, Link); if (SourceCid->CID.SequenceNumber == SequenceNumber) { if (RemoveFromList) { - QuicBindingRemoveSourceConnectionID( - Connection->Paths[0].Binding, - SourceCid, - Entry); + 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] (SeqNum=%llu) Removed Source CID: %!CID!", Connection, SourceCid->CID.SequenceNumber, CASTED_CLOG_BYTEARRAY(SourceCid->CID.Length, SourceCid->CID.Data)); + *Entry = (*Entry)->Next; } *IsLastCid = Connection->SourceCids.Next == NULL; return SourceCid; @@ -1235,7 +1242,7 @@ QuicConnGetSourceCidFromSeq( // _IRQL_requires_max_(DISPATCH_LEVEL) inline -QUIC_CID_HASH_ENTRY* +QUIC_CID_SLIST_ENTRY* QuicConnGetSourceCidFromBuf( _In_ QUIC_CONNECTION* Connection, _In_ uint8_t CidLength, @@ -1246,10 +1253,10 @@ QuicConnGetSourceCidFromBuf( for (CXPLAT_SLIST_ENTRY* Entry = Connection->SourceCids.Next; Entry != NULL; Entry = Entry->Next) { - QUIC_CID_HASH_ENTRY* SourceCid = + QUIC_CID_SLIST_ENTRY* SourceCid = CXPLAT_CONTAINING_RECORD( Entry, - QUIC_CID_HASH_ENTRY, + QUIC_CID_SLIST_ENTRY, Link); if (CidLength == SourceCid->CID.Length && memcmp(CidBuffer, SourceCid->CID.Data, CidLength) == 0) { diff --git a/src/core/crypto.c b/src/core/crypto.c index 9cd3255d00..597936bfdb 100644 --- a/src/core/crypto.c +++ b/src/core/crypto.c @@ -161,10 +161,10 @@ QuicCryptoInitialize( if (QuicConnIsServer(Connection)) { CXPLAT_DBG_ASSERT(Connection->SourceCids.Next != NULL); - QUIC_CID_HASH_ENTRY* SourceCid = + QUIC_CID_SLIST_ENTRY* SourceCid = CXPLAT_CONTAINING_RECORD( Connection->SourceCids.Next, - QUIC_CID_HASH_ENTRY, + QUIC_CID_SLIST_ENTRY, Link); HandshakeCid = SourceCid->CID.Data; @@ -416,10 +416,10 @@ QuicCryptoOnVersionChange( if (QuicConnIsServer(Connection)) { CXPLAT_DBG_ASSERT(Connection->SourceCids.Next != NULL); - QUIC_CID_HASH_ENTRY* SourceCid = + QUIC_CID_SLIST_ENTRY* SourceCid = CXPLAT_CONTAINING_RECORD( Connection->SourceCids.Next, - QUIC_CID_HASH_ENTRY, + QUIC_CID_SLIST_ENTRY, Link); HandshakeCid = SourceCid->CID.Data; @@ -1588,10 +1588,10 @@ QuicCryptoProcessTlsCompletion( 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 = + QUIC_CID_SLIST_ENTRY* InitialSourceCid = CXPLAT_CONTAINING_RECORD( Connection->SourceCids.Next->Next, - QUIC_CID_HASH_ENTRY, + QUIC_CID_SLIST_ENTRY, Link); CXPLAT_DBG_ASSERT(InitialSourceCid->CID.IsInitial); Connection->SourceCids.Next->Next = Connection->SourceCids.Next->Next->Next; @@ -1602,7 +1602,7 @@ QuicCryptoProcessTlsCompletion( Connection, InitialSourceCid->CID.SequenceNumber, CASTED_CLOG_BYTEARRAY(InitialSourceCid->CID.Length, InitialSourceCid->CID.Data)); - CXPLAT_FREE(InitialSourceCid, QUIC_POOL_CIDHASH); + CXPLAT_FREE(InitialSourceCid, QUIC_POOL_CIDSLIST); } // diff --git a/src/core/inline.c b/src/core/inline.c index f73a92ca53..0134ab8684 100644 --- a/src/core/inline.c +++ b/src/core/inline.c @@ -27,7 +27,7 @@ QuicCidNewDestination( const uint8_t* const Data ); -QUIC_CID_HASH_ENTRY* +QUIC_CID_SLIST_ENTRY* QuicCidNewSource( _In_ QUIC_CONNECTION* Connection, _In_ uint8_t Length, @@ -35,12 +35,12 @@ QuicCidNewSource( const uint8_t* const Data ); -QUIC_CID_HASH_ENTRY* +QUIC_CID_SLIST_ENTRY* QuicCidNewNullSource( _In_ QUIC_CONNECTION* Connection ); -QUIC_CID_HASH_ENTRY* +QUIC_CID_SLIST_ENTRY* QuicCidNewRandomSource( _In_opt_ QUIC_CONNECTION* Connection, _In_reads_opt_(MsQuicLib.CidServerIdLength) @@ -715,6 +715,11 @@ QuicRetryTokenDecrypt( _Out_ QUIC_TOKEN_CONTENTS* Token ); +QUIC_BINDING* +QuicLookupGetBinding( + _In_ QUIC_LOOKUP* Lookup + ); + void QuicConnLogStatistics( _In_ const QUIC_CONNECTION* const Connection @@ -744,7 +749,7 @@ QuicPacketBuilderHasAllowance( _In_ const QUIC_PACKET_BUILDER* Builder ); -QUIC_CID_HASH_ENTRY* +QUIC_CID_SLIST_ENTRY* QuicConnGetSourceCidFromSeq( _In_ QUIC_CONNECTION* Connection, _In_ QUIC_VAR_INT SequenceNumber, @@ -752,7 +757,7 @@ QuicConnGetSourceCidFromSeq( _Out_ BOOLEAN* IsLastCid ); -QUIC_CID_HASH_ENTRY* +QUIC_CID_SLIST_ENTRY* QuicConnGetSourceCidFromBuf( _In_ QUIC_CONNECTION* Connection, _In_ uint8_t CidLength, diff --git a/src/core/library.h b/src/core/library.h index 1dc0335b6e..b313f96906 100644 --- a/src/core/library.h +++ b/src/core/library.h @@ -446,7 +446,7 @@ QuicPerfCounterTrySnapShot( // inline _Success_(return != NULL) -QUIC_CID_HASH_ENTRY* +QUIC_CID_SLIST_ENTRY* QuicCidNewRandomSource( _In_opt_ QUIC_CONNECTION* Connection, _In_reads_opt_(MsQuicLib.CidServerIdLength) @@ -461,15 +461,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->HashEntries.Next = NULL; CxPlatZeroMemory(&Entry->CID, sizeof(Entry->CID)); Entry->CID.Length = MsQuicLib.CidTotalLength; diff --git a/src/core/lookup.c b/src/core/lookup.c index 3f96e08192..e232ab9450 100644 --- a/src/core/lookup.c +++ b/src/core/lookup.c @@ -179,16 +179,27 @@ QuicLookupRebalance( ((QUIC_CONNECTION*)PreviousLookup)->SourceCids.Next; while (Entry != NULL) { - QUIC_CID_HASH_ENTRY *CID = + QUIC_CID_SLIST_ENTRY *CID = CXPLAT_CONTAINING_RECORD( Entry, - QUIC_CID_HASH_ENTRY, + QUIC_CID_SLIST_ENTRY, Link); - (void)QuicLookupInsertLocalCid( - Lookup, - CxPlatHashSimple(CID->CID.Length, CID->CID.Data), - CID, - FALSE); + 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; } } @@ -216,14 +227,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,6 +287,7 @@ QuicLookupMaximizePartitioning( _IRQL_requires_max_(DISPATCH_LEVEL) BOOLEAN QuicCidMatchConnection( + _In_ QUIC_LOOKUP* Lookup, _In_ const QUIC_CONNECTION* const Connection, _In_reads_(Length) const uint8_t* const DestCid, @@ -286,12 +298,24 @@ QuicCidMatchConnection( Link != NULL; Link = Link->Next) { - const QUIC_CID_HASH_ENTRY* const Entry = - CXPLAT_CONTAINING_RECORD(Link, const QUIC_CID_HASH_ENTRY, Link); + 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 (Length == Entry->CID.Length && - (Length == 0 || memcmp(DestCid, Entry->CID.Data, Length) == 0)) { - return TRUE; + if (Entry1->Binding != QuicLookupGetBinding(Lookup)) { + continue; + } + + if (Length == Entry1->CID->CID.Length && + (Length == 0 || memcmp(DestCid, Entry1->CID->CID.Data, Length) == 0)) { + return TRUE; + } } } @@ -320,8 +344,8 @@ 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) { + if (CIDEntry->CID->CID.Length == Length && + memcmp(DestCid, CIDEntry->CID->CID.Data, Length) == 0) { return CIDEntry->Connection; } @@ -349,7 +373,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)) { Connection = Lookup->SINGLE.Connection; } @@ -475,14 +499,14 @@ QuicLookupInsertLocalCid( } } 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]; @@ -510,8 +534,6 @@ QuicLookupInsertLocalCid( Hash); #endif - SourceCid->CID.IsInLookupTable = TRUE; - return TRUE; } @@ -584,7 +606,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--; @@ -606,14 +628,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]; @@ -726,7 +748,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 ) { @@ -746,8 +768,24 @@ QuicLookupAddLocalCid( Hash); 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->Connection = SourceCid->Connection; + 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,14 +860,11 @@ _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); QuicLookupRemoveLocalCidInt(Lookup, SourceCid); - SourceCid->CID.IsInLookupTable = FALSE; - *Entry = (*Entry)->Next; CxPlatDispatchRwLockReleaseExclusive(&Lookup->RwLock); QuicConnRelease(SourceCid->Connection, QUIC_CONN_REF_LOOKUP_TABLE); } @@ -858,83 +893,3 @@ QuicLookupRemoveRemoteHash( CXPLAT_FREE(RemoteHashEntry, QUIC_POOL_REMOTE_HASH); 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); - 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); - - 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); - 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); - - CxPlatDispatchRwLockAcquireExclusive(&LookupDest->RwLock); -#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); -} diff --git a/src/core/lookup.h b/src/core/lookup.h index 6675c29ef8..6440992fb4 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]; @@ -140,7 +141,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 +167,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 ); // @@ -179,24 +179,3 @@ QuicLookupRemoveRemoteHash( _In_ QUIC_LOOKUP* Lookup, _In_ QUIC_REMOTE_HASH_ENTRY* RemoteHashEntry ); - -// -// Removes all the connection's local CIDs from the lookup. -// -_IRQL_requires_max_(DISPATCH_LEVEL) -void -QuicLookupRemoveLocalCids( - _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 - ); diff --git a/src/core/loss_detection.c b/src/core/loss_detection.c index d8bce352ce..498291c63d 100644 --- a/src/core/loss_detection.c +++ b/src/core/loss_detection.c @@ -585,7 +585,7 @@ QuicLossDetectionOnPacketAcknowledged( case QUIC_FRAME_NEW_CONNECTION_ID: { BOOLEAN IsLastCid; - QUIC_CID_HASH_ENTRY* SourceCid = + QUIC_CID_SLIST_ENTRY* SourceCid = QuicConnGetSourceCidFromSeq( Connection, Packet->Frames[i].NEW_CONNECTION_ID.Sequence, @@ -785,7 +785,7 @@ QuicLossDetectionRetransmitFrames( case QUIC_FRAME_NEW_CONNECTION_ID: { BOOLEAN IsLastCid; - QUIC_CID_HASH_ENTRY* SourceCid = + QUIC_CID_SLIST_ENTRY* SourceCid = QuicConnGetSourceCidFromSeq( Connection, Packet->Frames[i].NEW_CONNECTION_ID.Sequence, diff --git a/src/core/packet_builder.c b/src/core/packet_builder.c index 52704b8369..fffa70ea43 100644 --- a/src/core/packet_builder.c +++ b/src/core/packet_builder.c @@ -116,7 +116,7 @@ QuicPacketBuilderInitialize( Builder->SourceCid = CXPLAT_CONTAINING_RECORD( Connection->SourceCids.Next, - QUIC_CID_HASH_ENTRY, + QUIC_CID_SLIST_ENTRY, Link); uint64_t TimeNow = CxPlatTimeUs64(); @@ -946,6 +946,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)", diff --git a/src/core/packet_builder.h b/src/core/packet_builder.h index b95c54baa2..ac1efaf8af 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. diff --git a/src/core/path.c b/src/core/path.c index 91a545c54e..14164efb30 100644 --- a/src/core/path.c +++ b/src/core/path.c @@ -183,6 +183,29 @@ QuicConnGetPathByID( return NULL; } +_IRQL_requires_max_(PASSIVE_LEVEL) +_Ret_maybenull_ +_Success_(return != NULL) +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* @@ -221,6 +244,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 +258,10 @@ QuicConnGetPathForPacket( } } + if (!QuicLibraryTryAddRefBinding(Connection->Paths[0].Binding)) { + return NULL; + } + if (Connection->PathsCount > 1) { // // Make room for the new path (at index 1). @@ -313,8 +341,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(Connection->SourceCids.Next, QUIC_CID_SLIST_ENTRY, Link); CXPLAT_QEO_CONNECTION Offloads[2] = { { Operation, diff --git a/src/core/path.h b/src/core/path.h index 4fdc2d78d8..ca44799362 100644 --- a/src/core/path.h +++ b/src/core/path.h @@ -296,6 +296,16 @@ QuicConnGetPathByID( _Out_ uint8_t* Index ); +_IRQL_requires_max_(PASSIVE_LEVEL) +_Ret_maybenull_ +_Success_(return != NULL) +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* diff --git a/src/core/send.c b/src/core/send.c index 1166c8933f..221abbff46 100644 --- a/src/core/send.c +++ b/src/core/send.c @@ -756,10 +756,10 @@ QuicSendWriteFrames( for (CXPLAT_SLIST_ENTRY* Entry = Connection->SourceCids.Next; Entry != NULL; Entry = Entry->Next) { - QUIC_CID_HASH_ENTRY* SourceCid = + QUIC_CID_SLIST_ENTRY* SourceCid = CXPLAT_CONTAINING_RECORD( Entry, - QUIC_CID_HASH_ENTRY, + QUIC_CID_SLIST_ENTRY, Link); if (!SourceCid->CID.NeedsToSend) { continue; diff --git a/src/inc/msquic.h b/src/inc/msquic.h index bc63bf20ae..993e9d1cdd 100644 --- a/src/inc/msquic.h +++ b/src/inc/msquic.h @@ -909,6 +909,9 @@ typedef struct QUIC_SCHANNEL_CREDENTIAL_ATTRIBUTE_W { #define QUIC_PARAM_CONN_STATISTICS_V2 0x05000016 // QUIC_STATISTICS_V2 #define QUIC_PARAM_CONN_STATISTICS_V2_PLAT 0x05000017 // QUIC_STATISTICS_V2 #define QUIC_PARAM_CONN_ORIG_DEST_CID 0x05000018 // uint8_t[] +#define QUIC_PARAM_CONN_ADD_LOCAL_ADDRESS 0x05000019 // QUIC_ADDR +#define QUIC_PARAM_CONN_REMOVE_LOCAL_ADDRESS 0x0500001A // QUIC_ADDR +#define QUIC_PARAM_CONN_LOCAL_UNUSED_DEST_CID_COUNT 0x0500001B // uint16_t // // Parameters for TLS. diff --git a/src/inc/quic_platform.h b/src/inc/quic_platform.h index 5de7c3693d..cae6cc6a15 100644 --- a/src/inc/quic_platform.h +++ b/src/inc/quic_platform.h @@ -80,7 +80,7 @@ typedef struct CXPLAT_SLIST_ENTRY { #define QUIC_POOL_WORKER 'A0cQ' // Qc0A - QUIC Worker #define QUIC_POOL_LISTENER 'B0cQ' // Qc0B - QUIC Listener #define QUIC_POOL_CID 'C0cQ' // Qc0C - QUIC CID -#define QUIC_POOL_CIDHASH 'D0cQ' // Qc0D - QUIC CID Hash +#define QUIC_POOL_CIDSLIST 'D0cQ' // Qc0D - QUIC CID Hash #define QUIC_POOL_CIDLIST 'E0cQ' // Qc0E - QUIC CID List Entry #define QUIC_POOL__UNUSED_1_ 'F0cQ' // Qc0F - UNUSED #define QUIC_POOL_ALPN '01cQ' // Qc10 - QUIC ALPN @@ -144,6 +144,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_CIDHASH 'D4cQ' // Qc4D - QUIC CID Hash + typedef enum CXPLAT_THREAD_FLAGS { CXPLAT_THREAD_FLAG_NONE = 0x0000, diff --git a/src/platform/datapath_winkernel.c b/src/platform/datapath_winkernel.c index aea89cf1b5..00eb65bfeb 100644 --- a/src/platform/datapath_winkernel.c +++ b/src/platform/datapath_winkernel.c @@ -2523,7 +2523,6 @@ CxPlatRecvDataReturn( 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 4146c5f379..2164eb871f 100644 --- a/src/test/MsQuicTests.h +++ b/src/test/MsQuicTests.h @@ -353,6 +353,20 @@ QuicTestVNTPOtherVersionZero( // Post Handshake Tests // +void +QuicTestProbePath( + _In_ int Family, + _In_ BOOLEAN ShareBinding, + _In_ uint32_t DropPacketCount + ); + +void +QuicTestMigration( + _In_ int Family, + _In_ BOOLEAN ShareBinding, + _In_ BOOLEAN PathProbe + ); + void QuicTestNatPortRebind( _In_ int Family, @@ -1278,4 +1292,24 @@ typedef struct { QUIC_CTL_CODE(119, METHOD_BUFFERED, FILE_WRITE_DATA) // uint32_t - Test -#define QUIC_MAX_IOCTL_FUNC_CODE 119 +typedef struct { + int Family; + BOOLEAN ShareBinding; + uint32_t DropPacketCount; +} QUIC_RUN_PROBE_PATH_PARAMS; + +#define IOCTL_QUIC_RUN_PROBE_PATH \ + QUIC_CTL_CODE(120, 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(121, METHOD_BUFFERED, FILE_WRITE_DATA) + // QUIC_RUN_MIGRATION + +#define QUIC_MAX_IOCTL_FUNC_CODE 121 diff --git a/src/test/bin/quic_gtest.cpp b/src/test/bin/quic_gtest.cpp index c6483ec8c8..ef41ae79ec 100644 --- a/src/test/bin/quic_gtest.cpp +++ b/src/test/bin/quic_gtest.cpp @@ -1628,6 +1628,34 @@ TEST_P(WithFamilyArgs, PathValidationTimeout) { QuicTestPathValidationTimeout(GetParam().Family); } } + +TEST_P(WithProbePathArgs, ProbePath) { + TestLoggerT Logger("QuicTestProbePath", GetParam()); + if (TestingKernelMode) { + QUIC_RUN_PROBE_PATH_PARAMS Params = { + GetParam().Family, + GetParam().ShareBinding, + GetParam().DropPacketCount + }; + ASSERT_TRUE(DriverClient.Run(IOCTL_QUIC_RUN_PROBE_PATH, Params)); + } else { + QuicTestProbePath(GetParam().Family, GetParam().ShareBinding, 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); + } +} #endif TEST_P(WithFamilyArgs, ChangeMaxStreamIDs) { @@ -2343,6 +2371,15 @@ 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())); #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 a452a8dd12..6c695b512d 100644 --- a/src/test/bin/quic_gtest.h +++ b/src/test/bin/quic_gtest.h @@ -911,3 +911,51 @@ std::ostream& operator << (std::ostream& o, const TlsConfigArgs& args) { class WithValidateTlsConfigArgs : public testing::Test, public testing::WithParamInterface { }; + +struct ProbePathArgs { + int Family; + BOOLEAN ShareBinding; + uint32_t DropPacketCount; + static ::std::vector Generate() { + ::std::vector list; + for (int Family : { 4, 6 }) + for (BOOLEAN ShareBinding : { TRUE, FALSE }) + for (uint32_t DropPacketCount : { 0, 1 }) + list.push_back({ Family, ShareBinding, DropPacketCount }); + return list; + } +}; + +std::ostream& operator << (std::ostream& o, const ProbePathArgs& args) { + return o << (args.Family == 4 ? "v4" : "v6") << "/" + << (args.ShareBinding ? "ShareBinding" : "not ShareBinding") << "/" + << "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 { +}; \ No newline at end of file diff --git a/src/test/bin/winkernel/control.cpp b/src/test/bin/winkernel/control.cpp index 35ce65d5f8..71baf4b123 100644 --- a/src/test/bin/winkernel/control.cpp +++ b/src/test/bin/winkernel/control.cpp @@ -518,6 +518,8 @@ size_t QUIC_IOCTL_BUFFER_SIZES[] = 0, sizeof(QUIC_RUN_CANCEL_ON_LOSS_PARAMS), sizeof(uint32_t), + sizeof(QUIC_RUN_PROBE_PATH_PARAMS), + sizeof(QUIC_RUN_MIGRATION_PARAMS), }; CXPLAT_STATIC_ASSERT( @@ -549,6 +551,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; @@ -925,6 +929,24 @@ 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.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/PathTest.cpp b/src/test/lib/PathTest.cpp index fc5b0c7979..359b94ff81 100644 --- a/src/test/lib/PathTest.cpp +++ b/src/test/lib/PathTest.cpp @@ -119,3 +119,181 @@ QuicTestLocalPathChanges( PeerStreamsChanged.Reset(); } } + +void +QuicTestProbePath( + _In_ int Family, + _In_ BOOLEAN ShareBinding, + _In_ uint32_t DropPacketCount + ) +{ + 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(); + } + + 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); + + uint16_t Count = 0; + uint32_t Try = 0; + + do { + if (Try != 0) { + CxPlatSleep(100); + } + uint32_t Size = sizeof(Count); + QUIC_STATUS Status = + Connection.GetParam( + QUIC_PARAM_CONN_LOCAL_UNUSED_DEST_CID_COUNT, + &Size, + &Count); + if (QUIC_FAILED(Status)) { + break; + } + } while (Count == 0 && ++Try <= 3); + TEST_NOT_EQUAL(Count, 0); + + QuicAddr SecondLocalAddr; + TEST_QUIC_SUCCEEDED(Connection.GetLocalAddr(SecondLocalAddr)); + SecondLocalAddr.IncrementPort(); + + PathProbeHelper ProbeHelper(SecondLocalAddr.GetPort(), DropPacketCount, DropPacketCount); + + TEST_QUIC_SUCCEEDED( + Connection.SetParam( + QUIC_PARAM_CONN_ADD_LOCAL_ADDRESS, + sizeof(SecondLocalAddr.SockAddr), + &SecondLocalAddr.SockAddr)); + + 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); +} + +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(); + } + + 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); + + uint16_t Count = 0; + uint32_t Try = 0; + + do { + if (Try != 0) { + CxPlatSleep(100); + } + uint32_t Size = sizeof(Count); + QUIC_STATUS Status = + Connection.GetParam( + QUIC_PARAM_CONN_LOCAL_UNUSED_DEST_CID_COUNT, + &Size, + &Count); + if (QUIC_FAILED(Status)) { + break; + } + } while (Count == 0 && ++Try <= 3); + TEST_NOT_EQUAL(Count, 0); + + QuicAddr SecondLocalAddr; + TEST_QUIC_SUCCEEDED(Connection.GetLocalAddr(SecondLocalAddr)); + SecondLocalAddr.IncrementPort(); + + PathProbeHelper ProbeHelper(SecondLocalAddr.GetPort()); + + if (Smooth) { + TEST_QUIC_SUCCEEDED( + Connection.SetParam( + QUIC_PARAM_CONN_ADD_LOCAL_ADDRESS, + sizeof(SecondLocalAddr.SockAddr), + &SecondLocalAddr.SockAddr)); + TEST_TRUE(ProbeHelper.ServerReceiveProbeEvent.WaitTimeout(TestWaitTimeout)); + TEST_TRUE(ProbeHelper.ClientReceiveProbeEvent.WaitTimeout(TestWaitTimeout)); + 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)); + + Connection.SetSettings(MsQuicSettings{}.SetKeepAlive(25)); + + 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)); +} diff --git a/src/test/lib/TestHelpers.h b/src/test/lib/TestHelpers.h index 30b2701e40..2ee9f7ed17 100644 --- a/src/test/lib/TestHelpers.h +++ b/src/test/lib/TestHelpers.h @@ -753,6 +753,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; From cb3545e7b49560aaf6425f6a14f7632059e908bf Mon Sep 17 00:00:00 2001 From: Masahiro Kozuka Date: Sat, 30 Mar 2024 15:16:45 +0900 Subject: [PATCH 02/29] fix nits --- src/core/binding.h | 2 +- src/core/connection.c | 17 ++++++++++------- src/core/path.c | 1 - src/core/path.h | 1 - src/inc/quic_platform.h | 5 ++--- src/test/lib/PathTest.cpp | 6 +++--- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/core/binding.h b/src/core/binding.h index 9258d25a23..7b4ad2df0d 100644 --- a/src/core/binding.h +++ b/src/core/binding.h @@ -533,4 +533,4 @@ QuicLookupGetBinding( ) { return CXPLAT_CONTAINING_RECORD(Lookup, QUIC_BINDING, Lookup); -} \ No newline at end of file +} diff --git a/src/core/connection.c b/src/core/connection.c index cef8e55695..f3cf1d5a1c 100644 --- a/src/core/connection.c +++ b/src/core/connection.c @@ -846,7 +846,10 @@ QuicConnGenerateNewSourceCid( CxPlatDispatchLockAcquire(&MsQuicLib.DatapathLock); - // Check whether a sourceCid collides or not around all the connections. + // + // Check whether a new sourceCid collides with any sourceCid which belong to all + // the bindings including the ones which this connection doesn't bound. + // for (CXPLAT_LIST_ENTRY* Link = MsQuicLib.Bindings.Flink; Link != &MsQuicLib.Bindings; Link = Link->Flink) { @@ -5145,7 +5148,7 @@ QuicConnRecvFrames( !memcmp(Frame.Data, TempPath->Challenge, sizeof(Frame.Data))) { QuicPerfCounterIncrement(QUIC_PERF_COUNTER_PATH_VALIDATED); QuicPathSetValid(Connection, TempPath, QUIC_PATH_VALID_PATH_RESPONSE); - break; + break; } } @@ -6668,7 +6671,7 @@ QuicConnParamSet( } if (QuicConnIsServer(Connection)) { - Status = QUIC_STATUS_INVALID_STATE; + Status = QUIC_STATUS_NOT_SUPPORTED; break; } @@ -6693,8 +6696,8 @@ QuicConnParamSet( BOOLEAN AddrInUse = FALSE; for (uint8_t i = 0; i < Connection->PathsCount; ++i) { if (QuicAddrCompare( - &Connection->Paths[i].Route.LocalAddress, - LocalAddress)) { + &Connection->Paths[i].Route.LocalAddress, + LocalAddress)) { AddrInUse = TRUE; break; } @@ -6841,8 +6844,8 @@ QuicConnParamSet( uint8_t PathIndex = Connection->PathsCount; for (uint8_t i = 0; i < Connection->PathsCount; ++i) { if (QuicAddrCompare( - &Connection->Paths[i].Route.LocalAddress, - LocalAddress)) { + &Connection->Paths[i].Route.LocalAddress, + LocalAddress)) { PathIndex = i; break; } diff --git a/src/core/path.c b/src/core/path.c index 14164efb30..842030a2a9 100644 --- a/src/core/path.c +++ b/src/core/path.c @@ -185,7 +185,6 @@ QuicConnGetPathByID( _IRQL_requires_max_(PASSIVE_LEVEL) _Ret_maybenull_ -_Success_(return != NULL) QUIC_PATH* QuicConnGetPathByAddress( _In_ QUIC_CONNECTION* Connection, diff --git a/src/core/path.h b/src/core/path.h index ca44799362..283f6ce079 100644 --- a/src/core/path.h +++ b/src/core/path.h @@ -298,7 +298,6 @@ QuicConnGetPathByID( _IRQL_requires_max_(PASSIVE_LEVEL) _Ret_maybenull_ -_Success_(return != NULL) QUIC_PATH* QuicConnGetPathByAddress( _In_ QUIC_CONNECTION* Connection, diff --git a/src/inc/quic_platform.h b/src/inc/quic_platform.h index cae6cc6a15..4ffa8f41fb 100644 --- a/src/inc/quic_platform.h +++ b/src/inc/quic_platform.h @@ -80,7 +80,7 @@ typedef struct CXPLAT_SLIST_ENTRY { #define QUIC_POOL_WORKER 'A0cQ' // Qc0A - QUIC Worker #define QUIC_POOL_LISTENER 'B0cQ' // Qc0B - QUIC Listener #define QUIC_POOL_CID 'C0cQ' // Qc0C - QUIC CID -#define QUIC_POOL_CIDSLIST 'D0cQ' // Qc0D - QUIC CID Hash +#define QUIC_POOL_CIDHASH 'D0cQ' // Qc0D - QUIC CID Hash #define QUIC_POOL_CIDLIST 'E0cQ' // Qc0E - QUIC CID List Entry #define QUIC_POOL__UNUSED_1_ 'F0cQ' // Qc0F - UNUSED #define QUIC_POOL_ALPN '01cQ' // Qc10 - QUIC ALPN @@ -144,8 +144,7 @@ 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_CIDHASH 'D4cQ' // Qc4D - QUIC CID Hash - +#define QUIC_POOL_CIDSLIST 'D4cQ' // Qc0D - QUIC CID SLIST Entry typedef enum CXPLAT_THREAD_FLAGS { CXPLAT_THREAD_FLAG_NONE = 0x0000, diff --git a/src/test/lib/PathTest.cpp b/src/test/lib/PathTest.cpp index 359b94ff81..449a1fd366 100644 --- a/src/test/lib/PathTest.cpp +++ b/src/test/lib/PathTest.cpp @@ -146,7 +146,7 @@ QuicTestProbePath( TEST_QUIC_SUCCEEDED(Listener.Start("MsQuicTest", &ServerLocalAddr.SockAddr)); TEST_QUIC_SUCCEEDED(Listener.GetLocalAddr(ServerLocalAddr)); - MsQuicConnection Connection(Registration, MsQuicCleanUpMode::CleanUpManual, ClientCallback, &PeerStreamsChanged); + MsQuicConnection Connection(Registration, CleanUpManual, ClientCallback, &PeerStreamsChanged); TEST_QUIC_SUCCEEDED(Connection.GetInitStatus()); if (ShareBinding) { @@ -234,6 +234,8 @@ QuicTestMigration( 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)); @@ -288,8 +290,6 @@ QuicTestMigration( sizeof(SecondLocalAddr.SockAddr), &SecondLocalAddr.SockAddr)); - Connection.SetSettings(MsQuicSettings{}.SetKeepAlive(25)); - TEST_TRUE(Context.PeerAddrChangedEvent.WaitTimeout(1500)); QuicAddr ServerRemoteAddr; TEST_QUIC_SUCCEEDED(Context.Connection->GetRemoteAddr(ServerRemoteAddr)); From ac71d739cb117ba1dd25fac1c6d23cdc0ddbbc22 Mon Sep 17 00:00:00 2001 From: Masahiro Kozuka Date: Sat, 30 Mar 2024 15:55:10 +0900 Subject: [PATCH 03/29] move the codes into the separate functions. --- src/core/connection.c | 388 +++++++++++++++++++++--------------------- 1 file changed, 197 insertions(+), 191 deletions(-) diff --git a/src/core/connection.c b/src/core/connection.c index f3cf1d5a1c..cd128550c9 100644 --- a/src/core/connection.c +++ b/src/core/connection.c @@ -6186,6 +6186,201 @@ QuicConnUpdatePeerPacketTolerance( } } +_IRQL_requires_max_(PASSIVE_LEVEL) +static +QUIC_STATUS +QuicConnAddLocalAddress( + _In_ QUIC_CONNECTION* Connection, + _In_ QUIC_ADDR* LocalAddress + ) +{ + QUIC_STATUS Status; + + if (QuicConnIsServer(Connection)) { + return QUIC_STATUS_NOT_SUPPORTED; + } + + if (!Connection->State.Started) { + return QUIC_STATUS_INVALID_STATE; + } + + QUIC_CID_LIST_ENTRY* NewDestCid = QuicConnGetUnusedDestCid(Connection); + if (NewDestCid == NULL) { + return QUIC_STATUS_INVALID_STATE; + } + + if (!QuicAddrIsValid(LocalAddress)) { + return QUIC_STATUS_INVALID_PARAMETER; + } + + BOOLEAN AddrInUse = FALSE; + 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; + } + + CXPLAT_DBG_ASSERT(Connection->State.RemoteAddressSet); + CXPLAT_DBG_ASSERT(Connection->Configuration != NULL); + + CXPLAT_UDP_CONFIG UdpConfig = {0}; + UdpConfig.LocalAddress = 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; + Status = + QuicLibraryGetBinding( + &UdpConfig, + &NewBinding); + if (QUIC_FAILED(Status)) { + return Status; + } + + if (!Connection->State.ShareBinding) { + QUIC_CID_SLIST_ENTRY* SourceCid = QuicCidNewNullSource(Connection); + if (SourceCid == NULL) { + QuicLibraryReleaseBinding(NewBinding); + return QUIC_STATUS_OUT_OF_MEMORY; + } + + 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); + + if (!QuicBindingAddSourceConnectionID(NewBinding, SourceCid)) { + QuicLibraryReleaseBinding(NewBinding); + return QUIC_STATUS_OUT_OF_MEMORY; + } + } else { + if (!QuicBindingAddAllSourceConnectionIDs(NewBinding, Connection)) { + QuicLibraryReleaseBinding(NewBinding); + return QUIC_STATUS_OUT_OF_MEMORY; + } + } + + 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)); + } + + QUIC_PATH* Path = &Connection->Paths[1]; + QuicPathInitialize(Connection, Path); + Connection->PathsCount++; + + Path->Binding = NewBinding; + + QuicBindingGetLocalAddress( + Path->Binding, + &Path->Route.LocalAddress); + CxPlatCopyMemory(&Path->Route.RemoteAddress, &Connection->Paths[0].Route.RemoteAddress, sizeof(QUIC_ADDR)); + + Path->Allowance = UINT32_MAX; + + 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); + + QuicTraceEvent( + ConnLocalAddrAdded, + "[conn][%p] New Local IP: %!ADDR!", + Connection, + CASTED_CLOG_BYTEARRAY(sizeof(Path->Route.LocalAddress), &Path->Route.LocalAddress)); + + QuicSendSetSendFlag(&Connection->Send, QUIC_CONN_SEND_FLAG_PATH_CHALLENGE); + + return QUIC_STATUS_SUCCESS; +} + +_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 (!Connection->State.Started) { + return QUIC_STATUS_INVALID_STATE; + } + + if (!QuicAddrIsValid(LocalAddress)) { + return QUIC_STATUS_INVALID_PARAMETER; + } + + 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 (Path->IsActive) { + return QUIC_STATUS_INVALID_STATE; + } + + QuicConnRetireCid(Connection, Path->DestCid); + + QuicBindingRemoveAllSourceConnectionIDs(Path->Binding, Connection); + QuicLibraryReleaseBinding(Path->Binding); + + QuicPathRemove(Connection, PathIndex); + + return QUIC_STATUS_SUCCESS; +} + #define QUIC_CONN_BAD_START_STATE(CONN) (CONN->State.Started || CONN->State.ClosedLocally) _IRQL_requires_max_(PASSIVE_LEVEL) @@ -6670,150 +6865,7 @@ QuicConnParamSet( break; } - if (QuicConnIsServer(Connection)) { - Status = QUIC_STATUS_NOT_SUPPORTED; - break; - } - - if (!Connection->State.Started) { - Status = QUIC_STATUS_INVALID_STATE; - break; - } - - QUIC_CID_LIST_ENTRY* NewDestCid = QuicConnGetUnusedDestCid(Connection); - if (NewDestCid == NULL) { - Status = QUIC_STATUS_INVALID_STATE; - break; - } - - const QUIC_ADDR* LocalAddress = (const QUIC_ADDR*)Buffer; - - if (!QuicAddrIsValid(LocalAddress)) { - Status = QUIC_STATUS_INVALID_PARAMETER; - break; - } - - BOOLEAN AddrInUse = FALSE; - for (uint8_t i = 0; i < Connection->PathsCount; ++i) { - if (QuicAddrCompare( - &Connection->Paths[i].Route.LocalAddress, - LocalAddress)) { - AddrInUse = TRUE; - break; - } - } - - if (AddrInUse) { - Status = QUIC_STATUS_ADDRESS_IN_USE; - break; - } - - if (Connection->PathsCount == QUIC_MAX_PATH_COUNT) { - // - // Already tracking the maximum number of paths, and can't free - // any more. - // - Status = QUIC_STATUS_OUT_OF_MEMORY; - break; - } - - CXPLAT_DBG_ASSERT(Connection->State.RemoteAddressSet); - CXPLAT_DBG_ASSERT(Connection->Configuration != NULL); - - CXPLAT_UDP_CONFIG UdpConfig = {0}; - UdpConfig.LocalAddress = 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; - Status = - QuicLibraryGetBinding( - &UdpConfig, - &NewBinding); - if (QUIC_FAILED(Status)) { - break; - } - - if (!Connection->State.ShareBinding) { - QUIC_CID_SLIST_ENTRY* SourceCid = QuicCidNewNullSource(Connection); - if (SourceCid == NULL) { - QuicLibraryReleaseBinding(NewBinding); - Status = QUIC_STATUS_OUT_OF_MEMORY; - break; - } - - 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); - - if (!QuicBindingAddSourceConnectionID(NewBinding, SourceCid)) { - QuicLibraryReleaseBinding(NewBinding); - Status = QUIC_STATUS_OUT_OF_MEMORY; - break; - } - } else { - if (!QuicBindingAddAllSourceConnectionIDs(NewBinding, Connection)) { - QuicLibraryReleaseBinding(NewBinding); - Status = QUIC_STATUS_OUT_OF_MEMORY; - break; - } - } - - 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)); - } - - QUIC_PATH* Path = &Connection->Paths[1]; - QuicPathInitialize(Connection, Path); - Connection->PathsCount++; - - Path->Binding = NewBinding; - - QuicBindingGetLocalAddress( - Path->Binding, - &Path->Route.LocalAddress); - CxPlatCopyMemory(&Path->Route.RemoteAddress, &Connection->Paths[0].Route.RemoteAddress, sizeof(QUIC_ADDR)); - - Path->Allowance = UINT32_MAX; - - 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); - - QuicTraceEvent( - ConnLocalAddrAdded, - "[conn][%p] New Local IP: %!ADDR!", - Connection, - CASTED_CLOG_BYTEARRAY(sizeof(Path->Route.LocalAddress), &Path->Route.LocalAddress)); - - QuicSendSetSendFlag(&Connection->Send, QUIC_CONN_SEND_FLAG_PATH_CHALLENGE); - - Status = QUIC_STATUS_SUCCESS; + Status = QuicConnAddLocalAddress(Connection, (QUIC_ADDR*)Buffer); break; } @@ -6824,53 +6876,7 @@ QuicConnParamSet( break; } - if (QuicConnIsServer(Connection)) { - Status = QUIC_STATUS_INVALID_STATE; - break; - } - - if (!Connection->State.Started) { - Status = QUIC_STATUS_INVALID_STATE; - break; - } - - const QUIC_ADDR* LocalAddress = (const QUIC_ADDR*)Buffer; - - if (!QuicAddrIsValid(LocalAddress)) { - Status = QUIC_STATUS_INVALID_PARAMETER; - break; - } - - 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) { - Status = QUIC_STATUS_NOT_FOUND; - break; - } - - QUIC_PATH* Path = &Connection->Paths[PathIndex]; - - if (Path->IsActive) { - Status = QUIC_STATUS_INVALID_STATE; - break; - } - - QuicConnRetireCid(Connection, Path->DestCid); - - QuicBindingRemoveAllSourceConnectionIDs(Path->Binding, Connection); - QuicLibraryReleaseBinding(Path->Binding); - - QuicPathRemove(Connection, PathIndex); - - Status = QUIC_STATUS_SUCCESS; + Status = QuicConnRemoveLocalAddress(Connection, (QUIC_ADDR*)Buffer); break; } From a33991305abfbd36259d25a7a1fed5906f9b0578 Mon Sep 17 00:00:00 2001 From: "masa.koz" Date: Sat, 6 Apr 2024 13:55:32 +0000 Subject: [PATCH 04/29] Change the ConnID and reset Congestion Control. --- src/core/connection.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/core/connection.c b/src/core/connection.c index cd128550c9..31e2252cd5 100644 --- a/src/core/connection.c +++ b/src/core/connection.c @@ -6467,6 +6467,13 @@ QuicConnParamSet( Connection->Paths[0].Binding = OldBinding; break; } + + if (!QuicConnRetireCurrentDestCid(Connection, &Connection->Paths[0])) { + QuicLibraryReleaseBinding(Connection->Paths[0].Binding); + Connection->Paths[0].Binding = OldBinding; + Status = QUIC_STATUS_INVALID_STATE; + } + Connection->Paths[0].Route.Queue = NULL; // @@ -6493,6 +6500,8 @@ QuicConnParamSet( Connection, CASTED_CLOG_BYTEARRAY(sizeof(Connection->Paths[0].Route.LocalAddress), &Connection->Paths[0].Route.LocalAddress)); + QuicCongestionControlReset(&Connection->CongestionControl, FALSE); + QuicSendSetSendFlag(&Connection->Send, QUIC_CONN_SEND_FLAG_PING); } From c6f7e3d7ecbb21b742095104834889d5937effc9 Mon Sep 17 00:00:00 2001 From: Masahiro Kozuka Date: Wed, 18 Dec 2024 16:21:28 +0900 Subject: [PATCH 05/29] Defer sending a path challange if there is no unused ConnID --- src/core/configuration.c | 32 ++++++ src/core/connection.c | 150 +++++++++++++++++------------ src/core/connection.h | 8 ++ src/core/crypto.c | 6 ++ src/core/quicdef.h | 7 ++ src/core/settings.c | 34 +++++++ src/core/settings.h | 4 +- src/inc/msquic.h | 1 - src/inc/msquic.hpp | 18 ++++ src/inc/msquicp.h | 8 ++ src/test/MsQuicTests.h | 2 + src/test/bin/quic_gtest.cpp | 7 +- src/test/bin/quic_gtest.h | 5 +- src/test/bin/winkernel/control.cpp | 1 + src/test/lib/PathTest.cpp | 61 +++++------- 15 files changed, 243 insertions(+), 101 deletions(-) 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/connection.c b/src/core/connection.c index 70464aa2b2..02cebd6382 100644 --- a/src/core/connection.c +++ b/src/core/connection.c @@ -987,13 +987,14 @@ QuicConnGenerateNewSourceCids( // uint8_t NewCidCount; if (ReplaceExistingCids) { - NewCidCount = Connection->SourceCidLimit; + NewCidCount = 0; CXPLAT_SLIST_ENTRY* Entry = Connection->SourceCids.Next; while (Entry != NULL) { QUIC_CID_SLIST_ENTRY* SourceCid = CXPLAT_CONTAINING_RECORD(Entry, QUIC_CID_SLIST_ENTRY, Link); SourceCid->CID.Retired = TRUE; Entry = Entry->Next; + NewCidCount++; } } else { uint8_t CurrentCidCount = QuicConnSourceCidsCount(Connection); @@ -1012,28 +1013,6 @@ QuicConnGenerateNewSourceCids( } } -_IRQL_requires_max_(PASSIVE_LEVEL) -uint16_t -QuicConnUnusedDestCidsCount( - _In_ const QUIC_CONNECTION* Connection - ) -{ - uint16_t Count = 0; - 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) { - ++Count; - } - } - return Count; -} - _IRQL_requires_max_(PASSIVE_LEVEL) QUIC_CID_LIST_ENTRY* QuicConnGetUnusedDestCid( @@ -1212,6 +1191,42 @@ QuicConnReplaceRetiredCids( return TRUE; } +_IRQL_requires_max_(PASSIVE_LEVEL) +BOOLEAN +QuicConnAssignCids( + _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->DestCid != NULL || !Path->InUse) { + continue; + } + + QUIC_CID_LIST_ENTRY* NewDestCid = QuicConnGetUnusedDestCid(Connection); + if (NewDestCid == NULL) { + return Assigned; + } + + Path->DestCid = NewDestCid; + QUIC_CID_SET_PATH(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) uint64_t QuicGetEarliestExpirationTime( @@ -5058,6 +5073,10 @@ QuicConnRecvFrames( return FALSE; } + if (QuicConnAssignCids(Connection)) { + QuicSendSetSendFlag(&Connection->Send, QUIC_CONN_SEND_FLAG_PATH_CHALLENGE); + } + AckEliciting = TRUE; break; } @@ -6254,11 +6273,6 @@ QuicConnAddLocalAddress( return QUIC_STATUS_INVALID_STATE; } - QUIC_CID_LIST_ENTRY* NewDestCid = QuicConnGetUnusedDestCid(Connection); - if (NewDestCid == NULL) { - return QUIC_STATUS_INVALID_STATE; - } - if (!QuicAddrIsValid(LocalAddress)) { return QUIC_STATUS_INVALID_PARAMETER; } @@ -6359,24 +6373,30 @@ QuicConnAddLocalAddress( Path->Allowance = UINT32_MAX; - 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); - QuicTraceEvent( ConnLocalAddrAdded, "[conn][%p] New Local IP: %!ADDR!", Connection, CASTED_CLOG_BYTEARRAY(sizeof(Path->Route.LocalAddress), &Path->Route.LocalAddress)); - QuicSendSetSendFlag(&Connection->Send, QUIC_CONN_SEND_FLAG_PATH_CHALLENGE); + QUIC_CID_LIST_ENTRY* NewDestCid = QuicConnGetUnusedDestCid(Connection); + // + // 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); + + QuicSendSetSendFlag(&Connection->Send, QUIC_CONN_SEND_FLAG_PATH_CHALLENGE); + } return QUIC_STATUS_SUCCESS; } @@ -7045,6 +7065,31 @@ 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; + } + + QuicConnGenerateNewSourceCids(Connection, FALSE); + Status = QUIC_STATUS_SUCCESS; + break; +#endif + default: Status = QUIC_STATUS_INVALID_PARAMETER; break; @@ -7550,25 +7595,6 @@ QuicConnParamGet( Status = QUIC_STATUS_SUCCESS; break; - case QUIC_PARAM_CONN_LOCAL_UNUSED_DEST_CID_COUNT: - if (*BufferLength < sizeof(uint16_t)) { - *BufferLength = sizeof(uint16_t); - Status = QUIC_STATUS_BUFFER_TOO_SMALL; - break; - } - - if (Buffer == NULL) { - Status = QUIC_STATUS_INVALID_PARAMETER; - break; - } - - *BufferLength = sizeof(uint16_t); - *(uint16_t*)Buffer = - QuicConnUnusedDestCidsCount(Connection); - - Status = QUIC_STATUS_SUCCESS; - break; - default: Status = QUIC_STATUS_INVALID_PARAMETER; break; @@ -7730,6 +7756,12 @@ QuicConnApplyNewSettings( } } +#if QUIC_TEST_MANUAL_CONN_ID_GENERATION + if (NewSettings->IsSet.ConnIDGenDisabled) { + Connection->State.DisableConnIDGen = NewSettings->ConnIDGenDisabled; + } +#endif + if (OverWrite) { QuicSettingsDumpNew(NewSettings); } else { diff --git a/src/core/connection.h b/src/core/connection.h index d7e1b88a8e..0430942e73 100644 --- a/src/core/connection.h +++ b/src/core/connection.h @@ -214,6 +214,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; diff --git a/src/core/crypto.c b/src/core/crypto.c index ff07c13f06..e098b4a6c4 100644 --- a/src/core/crypto.c +++ b/src/core/crypto.c @@ -1622,7 +1622,13 @@ QuicCryptoProcessTlsCompletion( Connection->State.Connected = TRUE; QuicPerfCounterIncrement(QUIC_PERF_COUNTER_CONN_CONNECTED); +#if QUIC_TEST_MANUAL_CONN_ID_GENERATION + if (!Connection->State.DisableConnIDGen) { + QuicConnGenerateNewSourceCids(Connection, FALSE); + } +#else QuicConnGenerateNewSourceCids(Connection, FALSE); +#endif CXPLAT_DBG_ASSERT(Crypto->TlsState.NegotiatedAlpn != NULL); if (QuicConnIsClient(Connection)) { diff --git a/src/core/quicdef.h b/src/core/quicdef.h index 07956b50fb..6942944743 100644 --- a/src/core/quicdef.h +++ b/src/core/quicdef.h @@ -532,6 +532,11 @@ 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 number of rounds in Cubic Slow Start to sample RTT. // @@ -676,3 +681,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/settings.c b/src/core/settings.c index 40dd41245f..cb906e3199 100644 --- a/src/core/settings.c +++ b/src/core/settings.c @@ -168,6 +168,11 @@ 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 } _IRQL_requires_max_(PASSIVE_LEVEL) @@ -336,6 +341,11 @@ 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 } _IRQL_requires_max_(PASSIVE_LEVEL) @@ -714,6 +724,13 @@ 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 return TRUE; } @@ -1382,6 +1399,18 @@ 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 } _IRQL_requires_max_(PASSIVE_LEVEL) @@ -1615,6 +1644,11 @@ 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 } #define SETTINGS_SIZE_THRU_FIELD(SettingsType, Field) \ diff --git a/src/core/settings.h b/src/core/settings.h index 9650e119bb..3f016b482d 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -62,7 +62,8 @@ 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 RESERVED : 15; } IsSet; }; @@ -113,6 +114,7 @@ typedef struct QUIC_SETTINGS_INTERNAL { uint8_t OneWayDelayEnabled : 1; uint8_t NetStatsEventEnabled : 1; uint8_t StreamMultiReceiveEnabled : 1; + uint8_t ConnIDGenDisabled : 1; uint8_t MtuDiscoveryMissingProbeCount; } QUIC_SETTINGS_INTERNAL; diff --git a/src/inc/msquic.h b/src/inc/msquic.h index f18bdaee26..9cf84575d6 100644 --- a/src/inc/msquic.h +++ b/src/inc/msquic.h @@ -924,7 +924,6 @@ typedef struct QUIC_SCHANNEL_CREDENTIAL_ATTRIBUTE_W { #define QUIC_PARAM_CONN_ORIG_DEST_CID 0x05000018 // uint8_t[] #define QUIC_PARAM_CONN_ADD_LOCAL_ADDRESS 0x05000019 // QUIC_ADDR #define QUIC_PARAM_CONN_REMOVE_LOCAL_ADDRESS 0x0500001A // QUIC_ADDR -#define QUIC_PARAM_CONN_LOCAL_UNUSED_DEST_CID_COUNT 0x0500001B // uint16_t // // Parameters for TLS. diff --git a/src/inc/msquic.hpp b/src/inc/msquic.hpp index f051e84139..41fadab557 100644 --- a/src/inc/msquic.hpp +++ b/src/inc/msquic.hpp @@ -741,6 +741,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/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/test/MsQuicTests.h b/src/test/MsQuicTests.h index 41bf73da88..9171a49f7a 100644 --- a/src/test/MsQuicTests.h +++ b/src/test/MsQuicTests.h @@ -368,6 +368,7 @@ void QuicTestProbePath( _In_ int Family, _In_ BOOLEAN ShareBinding, + _In_ BOOLEAN DeferConnIDGen, _In_ uint32_t DropPacketCount ); @@ -1348,6 +1349,7 @@ typedef struct { typedef struct { int Family; BOOLEAN ShareBinding; + BOOLEAN DeferConnIDGen; uint32_t DropPacketCount; } QUIC_RUN_PROBE_PATH_PARAMS; diff --git a/src/test/bin/quic_gtest.cpp b/src/test/bin/quic_gtest.cpp index 681212cc10..6e37b5fe9b 100644 --- a/src/test/bin/quic_gtest.cpp +++ b/src/test/bin/quic_gtest.cpp @@ -1672,11 +1672,16 @@ TEST_P(WithProbePathArgs, ProbePath) { 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().DropPacketCount); + QuicTestProbePath( + GetParam().Family, + GetParam().ShareBinding, + GetParam().DeferConnIDGen, + GetParam().DropPacketCount); } } diff --git a/src/test/bin/quic_gtest.h b/src/test/bin/quic_gtest.h index 9963e7b13a..e85312a32b 100644 --- a/src/test/bin/quic_gtest.h +++ b/src/test/bin/quic_gtest.h @@ -933,13 +933,15 @@ class WithValidateTlsConfigArgs : public testing::Test, 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, DropPacketCount }); + list.push_back({ Family, ShareBinding, DeferConnIDGen, DropPacketCount }); return list; } }; @@ -947,6 +949,7 @@ struct ProbePathArgs { 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; } diff --git a/src/test/bin/winkernel/control.cpp b/src/test/bin/winkernel/control.cpp index 1de71cd636..613b5b6465 100644 --- a/src/test/bin/winkernel/control.cpp +++ b/src/test/bin/winkernel/control.cpp @@ -965,6 +965,7 @@ QuicTestCtlEvtIoDeviceControl( QuicTestProbePath( Params->ProbePathParams.Family, Params->ProbePathParams.ShareBinding, + Params->ProbePathParams.DeferConnIDGen, Params->ProbePathParams.DropPacketCount)); break; diff --git a/src/test/lib/PathTest.cpp b/src/test/lib/PathTest.cpp index 449a1fd366..4572de718b 100644 --- a/src/test/lib/PathTest.cpp +++ b/src/test/lib/PathTest.cpp @@ -124,6 +124,7 @@ void QuicTestProbePath( _In_ int Family, _In_ BOOLEAN ShareBinding, + _In_ BOOLEAN DeferConnIDGen, _In_ uint32_t DropPacketCount ) { @@ -135,6 +136,15 @@ QuicTestProbePath( 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()); @@ -158,25 +168,6 @@ QuicTestProbePath( TEST_TRUE(Context.HandshakeCompleteEvent.WaitTimeout(TestWaitTimeout)); TEST_NOT_EQUAL(nullptr, Context.Connection); - uint16_t Count = 0; - uint32_t Try = 0; - - do { - if (Try != 0) { - CxPlatSleep(100); - } - uint32_t Size = sizeof(Count); - QUIC_STATUS Status = - Connection.GetParam( - QUIC_PARAM_CONN_LOCAL_UNUSED_DEST_CID_COUNT, - &Size, - &Count); - if (QUIC_FAILED(Status)) { - break; - } - } while (Count == 0 && ++Try <= 3); - TEST_NOT_EQUAL(Count, 0); - QuicAddr SecondLocalAddr; TEST_QUIC_SUCCEEDED(Connection.GetLocalAddr(SecondLocalAddr)); SecondLocalAddr.IncrementPort(); @@ -189,6 +180,14 @@ QuicTestProbePath( sizeof(SecondLocalAddr.SockAddr), &SecondLocalAddr.SockAddr)); + if (DeferConnIDGen) { + TEST_QUIC_SUCCEEDED( + Context.Connection->SetParam( + QUIC_PARAM_CONN_GENERATE_CONN_ID, + 0, + NULL)); + } + TEST_TRUE(ProbeHelper.ServerReceiveProbeEvent.WaitTimeout(TestWaitTimeout * 10)); TEST_TRUE(ProbeHelper.ClientReceiveProbeEvent.WaitTimeout(TestWaitTimeout * 10)); QUIC_STATISTICS_V2 Stats; @@ -241,25 +240,6 @@ QuicTestMigration( TEST_TRUE(Context.HandshakeCompleteEvent.WaitTimeout(TestWaitTimeout)); TEST_NOT_EQUAL(nullptr, Context.Connection); - uint16_t Count = 0; - uint32_t Try = 0; - - do { - if (Try != 0) { - CxPlatSleep(100); - } - uint32_t Size = sizeof(Count); - QUIC_STATUS Status = - Connection.GetParam( - QUIC_PARAM_CONN_LOCAL_UNUSED_DEST_CID_COUNT, - &Size, - &Count); - if (QUIC_FAILED(Status)) { - break; - } - } while (Count == 0 && ++Try <= 3); - TEST_NOT_EQUAL(Count, 0); - QuicAddr SecondLocalAddr; TEST_QUIC_SUCCEEDED(Connection.GetLocalAddr(SecondLocalAddr)); SecondLocalAddr.IncrementPort(); @@ -282,6 +262,11 @@ QuicTestMigration( &Size, &Stats)); TEST_EQUAL(Stats.RecvDroppedPackets, 0); + } else { + // + // Wait for handshake confirmation. + // + CxPlatSleep(100); } TEST_QUIC_SUCCEEDED( From ac1f61642b74501ae61694857762dc2117e5425d Mon Sep 17 00:00:00 2001 From: Masahiro Kozuka Date: Wed, 18 Dec 2024 16:46:21 +0900 Subject: [PATCH 06/29] Release bindings and assert non-null for retired paths in connection management --- src/core/connection.c | 14 ++++++++++++++ src/core/loss_detection.c | 3 +++ 2 files changed, 17 insertions(+) diff --git a/src/core/connection.c b/src/core/connection.c index 02cebd6382..5877ba4dea 100644 --- a/src/core/connection.c +++ b/src/core/connection.c @@ -1161,6 +1161,9 @@ QuicConnReplaceRetiredCids( Connection, "Non-active path has no replacement for retired CID."); CXPLAT_DBG_ASSERT(i != 0); + CXPLAT_DBG_ASSERT(Connection->Paths[i].Binding != NULL); + QuicLibraryReleaseBinding(Connection->Paths[i].Binding); + Connection->Paths[i].Binding = NULL; QuicPathRemove(Connection, i--); continue; } @@ -5927,6 +5930,9 @@ QuicConnRecvDatagrams( 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); } } @@ -6120,11 +6126,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); } } @@ -6443,8 +6455,10 @@ QuicConnRemoveLocalAddress( QuicConnRetireCid(Connection, Path->DestCid); + CXPLAT_DBG_ASSERT(Path->Binding != NULL); QuicBindingRemoveAllSourceConnectionIDs(Path->Binding, Connection); QuicLibraryReleaseBinding(Path->Binding); + Path->Binding = NULL; QuicPathRemove(Connection, PathIndex); diff --git a/src/core/loss_detection.c b/src/core/loss_detection.c index ff39eb93f5..f0e8982a5e 100644 --- a/src/core/loss_detection.c +++ b/src/core/loss_detection.c @@ -841,6 +841,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; From 2b3c6fd450f8a93746e3bfd8a03d00d7c34aeafc Mon Sep 17 00:00:00 2001 From: Masahiro Kozuka Date: Wed, 18 Dec 2024 21:45:03 +0900 Subject: [PATCH 07/29] Accept adding local address before connection start --- src/core/connection.c | 262 ++++++++++++++++++++++++--------------- src/core/connection.h | 19 +++ src/core/crypto.c | 6 +- src/test/lib/ApiTest.cpp | 184 +++++++++++++++++++++++++++ 4 files changed, 371 insertions(+), 100 deletions(-) diff --git a/src/core/connection.c b/src/core/connection.c index 5877ba4dea..e94b633468 100644 --- a/src/core/connection.c +++ b/src/core/connection.c @@ -6268,54 +6268,17 @@ QuicConnUpdatePeerPacketTolerance( } _IRQL_requires_max_(PASSIVE_LEVEL) -static QUIC_STATUS -QuicConnAddLocalAddress( +QuicConnOpenNewPath( _In_ QUIC_CONNECTION* Connection, - _In_ QUIC_ADDR* LocalAddress + _In_ QUIC_PATH* Path ) { - QUIC_STATUS Status; - - if (QuicConnIsServer(Connection)) { - return QUIC_STATUS_NOT_SUPPORTED; - } - - if (!Connection->State.Started) { - return QUIC_STATUS_INVALID_STATE; - } - - if (!QuicAddrIsValid(LocalAddress)) { - return QUIC_STATUS_INVALID_PARAMETER; - } - - BOOLEAN AddrInUse = FALSE; - 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; - } - CXPLAT_DBG_ASSERT(Connection->State.RemoteAddressSet); CXPLAT_DBG_ASSERT(Connection->Configuration != NULL); CXPLAT_UDP_CONFIG UdpConfig = {0}; - UdpConfig.LocalAddress = LocalAddress; + 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; @@ -6327,18 +6290,26 @@ QuicConnAddLocalAddress( #endif QUIC_BINDING* NewBinding = NULL; - Status = - QuicLibraryGetBinding( - &UdpConfig, - &NewBinding); + 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.ShareBinding) { QUIC_CID_SLIST_ENTRY* SourceCid = QuicCidNewNullSource(Connection); if (SourceCid == NULL) { - QuicLibraryReleaseBinding(NewBinding); return QUIC_STATUS_OUT_OF_MEMORY; } @@ -6352,45 +6323,21 @@ QuicConnAddLocalAddress( CxPlatListPushEntry(&Connection->SourceCids, &SourceCid->Link); if (!QuicBindingAddSourceConnectionID(NewBinding, SourceCid)) { - QuicLibraryReleaseBinding(NewBinding); return QUIC_STATUS_OUT_OF_MEMORY; } } else { if (!QuicBindingAddAllSourceConnectionIDs(NewBinding, Connection)) { - QuicLibraryReleaseBinding(NewBinding); return QUIC_STATUS_OUT_OF_MEMORY; } } - 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)); - } - - QUIC_PATH* Path = &Connection->Paths[1]; - QuicPathInitialize(Connection, Path); - Connection->PathsCount++; - - Path->Binding = NewBinding; - - QuicBindingGetLocalAddress( - Path->Binding, - &Path->Route.LocalAddress); - CxPlatCopyMemory(&Path->Route.RemoteAddress, &Connection->Paths[0].Route.RemoteAddress, sizeof(QUIC_ADDR)); - - Path->Allowance = UINT32_MAX; - QuicTraceEvent( ConnLocalAddrAdded, "[conn][%p] New Local IP: %!ADDR!", Connection, CASTED_CLOG_BYTEARRAY(sizeof(Path->Route.LocalAddress), &Path->Route.LocalAddress)); + QUIC_CID_LIST_ENTRY* NewDestCid = QuicConnGetUnusedDestCid(Connection); // // If we can't get a unused CID, we defer sending a path challange until we receieve a new CID. @@ -6406,26 +6353,137 @@ QuicConnAddLocalAddress( Path->PathValidationStartTime = CxPlatTimeUs64(); CxPlatRandom(sizeof(Path->Challenge), Path->Challenge); - - QuicSendSetSendFlag(&Connection->Send, QUIC_CONN_SEND_FLAG_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 -QuicConnRemoveLocalAddress( +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 (!Connection->State.Started) { + 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; } @@ -6433,6 +6491,10 @@ QuicConnRemoveLocalAddress( 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( @@ -6449,18 +6511,26 @@ QuicConnRemoveLocalAddress( QUIC_PATH* Path = &Connection->Paths[PathIndex]; - if (Path->IsActive) { + if (Path->IsActive && Connection->State.Started) { return QUIC_STATUS_INVALID_STATE; } - QuicConnRetireCid(Connection, Path->DestCid); + if (Path->DestCid != NULL) { + QuicConnRetireCid(Connection, Path->DestCid); + } - CXPLAT_DBG_ASSERT(Path->Binding != NULL); - QuicBindingRemoveAllSourceConnectionIDs(Path->Binding, Connection); - QuicLibraryReleaseBinding(Path->Binding); - Path->Binding = NULL; + if (Path->Binding != NULL) { + QuicBindingRemoveAllSourceConnectionIDs(Path->Binding, Connection); + QuicLibraryReleaseBinding(Path->Binding); + Path->Binding = NULL; + } - QuicPathRemove(Connection, PathIndex); + if (Connection->PathsCount == 1) { + CXPLAT_DBG_ASSERT(!Connection->State.Started); + Connection->State.LocalAddressSet = FALSE; + } else { + QuicPathRemove(Connection, PathIndex); + } return QUIC_STATUS_SUCCESS; } @@ -6507,27 +6577,21 @@ QuicConnParamSet( break; } - QUIC_PATH* Path = QuicConnGetPathByAddress(Connection, LocalAddress, &Connection->Paths[0].Route.RemoteAddress); - if (Path != NULL) { - if (!Path->IsActive) { - QuicPathSetActive(Connection, Path); + 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; } - Status = QUIC_STATUS_SUCCESS; - 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) { 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; diff --git a/src/core/connection.h b/src/core/connection.h index 0430942e73..c5fd763e3e 100644 --- a/src/core/connection.h +++ b/src/core/connection.h @@ -1604,6 +1604,25 @@ QuicConnUpdatePeerPacketTolerance( _In_ uint8_t NewPacketTolerance ); +// +// 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 e098b4a6c4..9e0922cc10 100644 --- a/src/core/crypto.c +++ b/src/core/crypto.c @@ -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); } @@ -1662,7 +1666,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); diff --git a/src/test/lib/ApiTest.cpp b/src/test/lib/ApiTest.cpp index 71bda9c8ef..93e24ef101 100644 --- a/src/test/lib/ApiTest.cpp +++ b/src/test/lib/ApiTest.cpp @@ -4521,6 +4521,188 @@ void QuicTest_QUIC_PARAM_CONN_ORIG_DEST_CID(MsQuicRegistration& Registration, Ms } } +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)); + } + } +} + void QuicTestConnectionParam() { MsQuicAlpn Alpn("MsQuicTest"); @@ -4554,6 +4736,8 @@ void QuicTestConnectionParam() QuicTest_QUIC_PARAM_CONN_STATISTICS_V2(Registration); QuicTest_QUIC_PARAM_CONN_STATISTICS_V2_PLAT(Registration); QuicTest_QUIC_PARAM_CONN_ORIG_DEST_CID(Registration, ClientConfiguration); + QuicTest_QUIC_PARAM_CONN_ADD_LOCAL_ADDRESS(Registration, ClientConfiguration); + QuicTest_QUIC_PARAM_CONN_REMOVE_LOCAL_ADDRESS(Registration, ClientConfiguration); } // From 9e287a72a5103266e80466071be68d77b83a3926 Mon Sep 17 00:00:00 2001 From: Masahiro Kozuka Date: Wed, 18 Dec 2024 22:10:19 +0900 Subject: [PATCH 08/29] Add support for multiple local addresses in connection tests --- src/core/connection.c | 9 +++++ src/test/MsQuicTests.h | 8 ++++ src/test/bin/quic_gtest.cpp | 18 +++++++++ src/test/lib/PathTest.cpp | 75 +++++++++++++++++++++++++++++++++++++ 4 files changed, 110 insertions(+) diff --git a/src/core/connection.c b/src/core/connection.c index e94b633468..387ff0e521 100644 --- a/src/core/connection.c +++ b/src/core/connection.c @@ -5702,6 +5702,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) { @@ -5724,6 +5725,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) { // @@ -5741,6 +5749,7 @@ QuicConnRecvDatagrams( BatchCount = 0; } CurrentPath = DatagramPath; + CurrentPathID = CurrentPath->ID; } if (!IsDeferred) { diff --git a/src/test/MsQuicTests.h b/src/test/MsQuicTests.h index 9171a49f7a..2db058f241 100644 --- a/src/test/MsQuicTests.h +++ b/src/test/MsQuicTests.h @@ -379,6 +379,14 @@ QuicTestMigration( _In_ BOOLEAN PathProbe ); +void +QuicTestMultipleLocalAddresses( + _In_ int Family, + _In_ BOOLEAN ShareBinding, + _In_ BOOLEAN DeferConnIDGen, + _In_ uint32_t DropPacketCount + ); + void QuicTestNatPortRebind( _In_ int Family, diff --git a/src/test/bin/quic_gtest.cpp b/src/test/bin/quic_gtest.cpp index 6e37b5fe9b..26a197bc19 100644 --- a/src/test/bin/quic_gtest.cpp +++ b/src/test/bin/quic_gtest.cpp @@ -1698,6 +1698,24 @@ TEST_P(WithMigrationArgs, Migration) { 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); + } +} #endif TEST_P(WithFamilyArgs, ChangeMaxStreamIDs) { diff --git a/src/test/lib/PathTest.cpp b/src/test/lib/PathTest.cpp index 4572de718b..2fdc31bd33 100644 --- a/src/test/lib/PathTest.cpp +++ b/src/test/lib/PathTest.cpp @@ -282,3 +282,78 @@ QuicTestMigration( 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(44433 + i); + TEST_QUIC_SUCCEEDED( + Connection.SetParam( + QUIC_PARAM_CONN_ADD_LOCAL_ADDRESS, + sizeof(ClientLocalAddrs[i].SockAddr), + &ClientLocalAddrs[i].SockAddr)); + } + + 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) { + TEST_QUIC_SUCCEEDED(Context.Connection->SetParam(QUIC_PARAM_CONN_GENERATE_CONN_ID, 0, NULL)); + } + + 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)); +} From 5da50d7f3b71670b503a8f62ce4dda3e6bc25a63 Mon Sep 17 00:00:00 2001 From: Masahiro Kozuka Date: Wed, 18 Dec 2024 23:03:08 +0900 Subject: [PATCH 09/29] Replace all the existing source connection IDs if we find the collision in adding a source connection ID to a newly opened bindings --- src/core/binding.c | 1 - src/core/connection.c | 91 +++++++++++++++++++++++++++++-------------- 2 files changed, 61 insertions(+), 31 deletions(-) diff --git a/src/core/binding.c b/src/core/binding.c index 12f2f286ed..24a5c641b3 100644 --- a/src/core/binding.c +++ b/src/core/binding.c @@ -583,7 +583,6 @@ QuicBindingAddAllSourceConnectionIDs( QUIC_CID_SLIST_ENTRY, Link); if (!QuicBindingAddSourceConnectionID(Binding, Entry)) { - QuicBindingRemoveAllSourceConnectionIDs(Binding, Connection); return FALSE; } } diff --git a/src/core/connection.c b/src/core/connection.c index 387ff0e521..69274396e6 100644 --- a/src/core/connection.c +++ b/src/core/connection.c @@ -843,6 +843,27 @@ QuicConnGenerateNewSourceCid( return NULL; } + // + // 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 < Connection->PathsCount; ++i) { + if (Connection->Paths[i].Binding != NULL) { + BOOLEAN NewBinding = TRUE; + for (uint8_t j = 0; j < BindingsCount; ++j) { + if (Connection->Paths[i].Binding == Bindings[j]) { + NewBinding = FALSE; + break; + } + } + if (NewBinding) { + Bindings[BindingsCount++] = Connection->Paths[i].Binding; + } + } + } + // // Keep randomly generating new source CIDs until we find one that doesn't // collide with an existing one. @@ -867,33 +888,38 @@ QuicConnGenerateNewSourceCid( } BOOLEAN Collision = FALSE; - - CxPlatDispatchLockAcquire(&MsQuicLib.DatapathLock); - - // - // Check whether a new sourceCid collides with any sourceCid which belong to all - // the bindings including the ones which this connection doesn't bound. - // - for (CXPLAT_LIST_ENTRY* Link = MsQuicLib.Bindings.Flink; - Link != &MsQuicLib.Bindings; - Link = Link->Flink) { - - QUIC_BINDING* Binding = - CXPLAT_CONTAINING_RECORD(Link, QUIC_BINDING, Link); - QUIC_CONNECTION* Connection1 = - QuicLookupFindConnectionByLocalCid( - &Binding->Lookup, - SourceCid->CID.Data, - SourceCid->CID.Length); - if (Connection1 != NULL) { + 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; - } + } } - CxPlatDispatchLockRelease(&MsQuicLib.DatapathLock); - 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) { @@ -912,12 +938,6 @@ QuicConnGenerateNewSourceCid( } } while (SourceCid == NULL); - for (uint8_t i = 0; i < Connection->PathsCount; ++i) { - if (Connection->Paths[i].Binding != NULL) { - QuicBindingAddSourceConnectionID(Connection->Paths[i].Binding, SourceCid); - } - } - SourceCid->CID.SequenceNumber = Connection->NextSourceCidSequenceNumber++; QuicTraceEvent( @@ -6336,7 +6356,7 @@ QuicConnOpenNewPath( } } else { if (!QuicBindingAddAllSourceConnectionIDs(NewBinding, Connection)) { - return QUIC_STATUS_OUT_OF_MEMORY; + QuicConnGenerateNewSourceCids(Connection, TRUE); } } @@ -6637,7 +6657,18 @@ QuicConnParamSet( // TODO - Need to free any queued recv packets from old binding. // - QuicBindingAddAllSourceConnectionIDs(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)) { + QuicConnGenerateNewSourceCids(Connection, TRUE); + } + } QuicBindingRemoveAllSourceConnectionIDs(OldBinding, Connection); QuicLibraryReleaseBinding(OldBinding); From d1d69a37eb13bf00a7472fb1b3be9cb0aee3e085 Mon Sep 17 00:00:00 2001 From: Masahiro Kozuka Date: Sat, 21 Dec 2024 09:01:22 +0900 Subject: [PATCH 10/29] run ./scripts/update-sidecar.ps1 --- src/generated/linux/connection.c.clog.h | 8 ++++---- src/generated/linux/connection.c.clog.h.lttng.h | 8 ++++---- src/generated/linux/settings.c.clog.h | 15 +++++++++++++++ src/generated/linux/settings.c.clog.h.lttng.h | 16 ++++++++++++++++ src/manifest/clog.sidecar | 17 +++++++++++++++++ 5 files changed, 56 insertions(+), 8 deletions(-) diff --git a/src/generated/linux/connection.c.clog.h b/src/generated/linux/connection.c.clog.h index 181deaaa58..a6cf39afc4 100644 --- a/src/generated/linux/connection.c.clog.h +++ b/src/generated/linux/connection.c.clog.h @@ -682,10 +682,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 ----------------------------------------------------------*/ diff --git a/src/generated/linux/connection.c.clog.h.lttng.h b/src/generated/linux/connection.c.clog.h.lttng.h index 8cef04d1cc..37095d84b3 100644 --- a/src/generated/linux/connection.c.clog.h.lttng.h +++ b/src/generated/linux/connection.c.clog.h.lttng.h @@ -719,10 +719,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 ----------------------------------------------------------*/ diff --git a/src/generated/linux/settings.c.clog.h b/src/generated/linux/settings.c.clog.h index ddf319a195..3501062ef2 100644 --- a/src/generated/linux/settings.c.clog.h +++ b/src/generated/linux/settings.c.clog.h @@ -842,6 +842,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..40aaf98930 100644 --- a/src/generated/linux/settings.c.clog.h.lttng.h +++ b/src/generated/linux/settings.c.clog.h.lttng.h @@ -874,6 +874,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/manifest/clog.sidecar b/src/manifest/clog.sidecar index eacefe88b5..c30ab5166d 100644 --- a/src/manifest/clog.sidecar +++ b/src/manifest/clog.sidecar @@ -10330,6 +10330,18 @@ ], "macroName": "QuicTraceLogVerbose" }, + "SettingConnIDGenDisabled": { + "ModuleProperites": {}, + "TraceString": "[sett] ConnIDGenDisabled = %hhu", + "UniqueId": "SettingConnIDGenDisabled", + "splitArgs": [ + { + "DefinationEncoding": "hhu", + "MacroVariableName": "arg2" + } + ], + "macroName": "QuicTraceLogVerbose" + }, "SettingDestCidUpdateIdleTimeoutMs": { "ModuleProperites": {}, "TraceString": "[sett] DestCidUpdateIdleTimeoutMs = %u", @@ -16493,6 +16505,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", From 12c157903a277af28aa9a4019dce59437bb1ee2c Mon Sep 17 00:00:00 2001 From: Masahiro Kozuka Date: Sat, 21 Dec 2024 09:32:07 +0900 Subject: [PATCH 11/29] Fix missing newline at end of file in quic_gtest.h --- src/test/bin/quic_gtest.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/bin/quic_gtest.h b/src/test/bin/quic_gtest.h index e85312a32b..1f68173c07 100644 --- a/src/test/bin/quic_gtest.h +++ b/src/test/bin/quic_gtest.h @@ -979,4 +979,4 @@ std::ostream& operator << (std::ostream& o, const MigrationArgs& args) { class WithMigrationArgs : public testing::Test, public testing::WithParamInterface { -}; \ No newline at end of file +}; From f2c962919be19bcf89a3ae775a7a0dc824183242 Mon Sep 17 00:00:00 2001 From: Masahiro Kozuka Date: Sat, 21 Dec 2024 10:03:31 +0900 Subject: [PATCH 12/29] Define local address management parameters only when preview features enabled --- src/inc/msquic.h | 2 ++ src/test/bin/quic_gtest.cpp | 4 +++- src/test/bin/quic_gtest.h | 2 ++ src/test/lib/ApiTest.cpp | 4 ++++ src/test/lib/PathTest.cpp | 2 ++ 5 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/inc/msquic.h b/src/inc/msquic.h index 9cf84575d6..e5f8e34bc4 100644 --- a/src/inc/msquic.h +++ b/src/inc/msquic.h @@ -922,8 +922,10 @@ 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 +#endif // // Parameters for TLS. diff --git a/src/test/bin/quic_gtest.cpp b/src/test/bin/quic_gtest.cpp index 26a197bc19..4afd543d4c 100644 --- a/src/test/bin/quic_gtest.cpp +++ b/src/test/bin/quic_gtest.cpp @@ -1666,6 +1666,7 @@ TEST_P(WithFamilyArgs, PathValidationTimeout) { } } +#if defined(QUIC_API_ENABLE_PREVIEW_FEATURES) TEST_P(WithProbePathArgs, ProbePath) { TestLoggerT Logger("QuicTestProbePath", GetParam()); if (TestingKernelMode) { @@ -1716,7 +1717,8 @@ TEST_P(WithProbePathArgs, MultipleLocalAddresses) { GetParam().DropPacketCount); } } -#endif +#endif // QUIC_API_ENABLE_PREVIEW_FEATURES +#endif // QUIC_TEST_DATAPATH_HOOKS_ENABLED TEST_P(WithFamilyArgs, ChangeMaxStreamIDs) { TestLoggerT Logger("QuicTestChangeMaxStreamID", GetParam()); diff --git a/src/test/bin/quic_gtest.h b/src/test/bin/quic_gtest.h index 1f68173c07..469670f821 100644 --- a/src/test/bin/quic_gtest.h +++ b/src/test/bin/quic_gtest.h @@ -930,6 +930,7 @@ class WithValidateTlsConfigArgs : public testing::Test, public testing::WithParamInterface { }; +#if defined(QUIC_API_ENABLE_PREVIEW_FEATURES) struct ProbePathArgs { int Family; BOOLEAN ShareBinding; @@ -980,3 +981,4 @@ std::ostream& operator << (std::ostream& o, const MigrationArgs& args) { class WithMigrationArgs : public testing::Test, public testing::WithParamInterface { }; +#endif diff --git a/src/test/lib/ApiTest.cpp b/src/test/lib/ApiTest.cpp index 93e24ef101..19a0543f4f 100644 --- a/src/test/lib/ApiTest.cpp +++ b/src/test/lib/ApiTest.cpp @@ -4521,6 +4521,7 @@ 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"); @@ -4702,6 +4703,7 @@ void QuicTest_QUIC_PARAM_CONN_REMOVE_LOCAL_ADDRESS(MsQuicRegistration& Registrat } } } +#endif void QuicTestConnectionParam() { @@ -4736,8 +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 2fdc31bd33..d9645b210c 100644 --- a/src/test/lib/PathTest.cpp +++ b/src/test/lib/PathTest.cpp @@ -120,6 +120,7 @@ QuicTestLocalPathChanges( } } +#if defined(QUIC_API_ENABLE_PREVIEW_FEATURES) void QuicTestProbePath( _In_ int Family, @@ -357,3 +358,4 @@ QuicTestMultipleLocalAddresses( TEST_TRUE(ProbeHelpers[2].ServerReceiveProbeEvent.WaitTimeout(TestWaitTimeout * 10)); TEST_TRUE(ProbeHelpers[2].ClientReceiveProbeEvent.WaitTimeout(TestWaitTimeout * 10)); } +#endif From b85b832f4004f9c88bdd086790eacf7b33fbb591 Mon Sep 17 00:00:00 2001 From: Masahiro Kozuka Date: Sat, 21 Dec 2024 11:31:52 +0900 Subject: [PATCH 13/29] Improve local address handling in path tests with retry logic for address collisions --- src/test/lib/PathTest.cpp | 90 +++++++++++++++++++++++++++++---------- 1 file changed, 68 insertions(+), 22 deletions(-) diff --git a/src/test/lib/PathTest.cpp b/src/test/lib/PathTest.cpp index d9645b210c..ca0089efc8 100644 --- a/src/test/lib/PathTest.cpp +++ b/src/test/lib/PathTest.cpp @@ -173,13 +173,23 @@ QuicTestProbePath( TEST_QUIC_SUCCEEDED(Connection.GetLocalAddr(SecondLocalAddr)); SecondLocalAddr.IncrementPort(); - PathProbeHelper ProbeHelper(SecondLocalAddr.GetPort(), DropPacketCount, DropPacketCount); + PathProbeHelper *ProbeHelper = new PathProbeHelper(SecondLocalAddr.GetPort(), DropPacketCount, DropPacketCount); - TEST_QUIC_SUCCEEDED( - Connection.SetParam( + 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)); + &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) { TEST_QUIC_SUCCEEDED( @@ -189,8 +199,8 @@ QuicTestProbePath( NULL)); } - TEST_TRUE(ProbeHelper.ServerReceiveProbeEvent.WaitTimeout(TestWaitTimeout * 10)); - TEST_TRUE(ProbeHelper.ClientReceiveProbeEvent.WaitTimeout(TestWaitTimeout * 10)); + 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( @@ -199,6 +209,7 @@ QuicTestProbePath( &Size, &Stats)); TEST_EQUAL(Stats.RecvDroppedPackets, 0); + delete ProbeHelper; } void @@ -245,16 +256,29 @@ QuicTestMigration( TEST_QUIC_SUCCEEDED(Connection.GetLocalAddr(SecondLocalAddr)); SecondLocalAddr.IncrementPort(); - PathProbeHelper ProbeHelper(SecondLocalAddr.GetPort()); + PathProbeHelper* ProbeHelper = new PathProbeHelper(SecondLocalAddr.GetPort()); if (Smooth) { - TEST_QUIC_SUCCEEDED( - Connection.SetParam( + QUIC_STATUS Status = QUIC_STATUS_SUCCESS; + int Try = 0; + do { + Status = Connection.SetParam( QUIC_PARAM_CONN_ADD_LOCAL_ADDRESS, sizeof(SecondLocalAddr.SockAddr), - &SecondLocalAddr.SockAddr)); - TEST_TRUE(ProbeHelper.ServerReceiveProbeEvent.WaitTimeout(TestWaitTimeout)); - TEST_TRUE(ProbeHelper.ClientReceiveProbeEvent.WaitTimeout(TestWaitTimeout)); + &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( @@ -263,18 +287,32 @@ QuicTestMigration( &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); + 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_QUIC_SUCCEEDED( - Connection.SetParam( - QUIC_PARAM_CONN_LOCAL_ADDRESS, - sizeof(SecondLocalAddr.SockAddr), - &SecondLocalAddr.SockAddr)); TEST_TRUE(Context.PeerAddrChangedEvent.WaitTimeout(1500)); QuicAddr ServerRemoteAddr; @@ -329,12 +367,20 @@ QuicTestMultipleLocalAddresses( QuicAddr ClientLocalAddrs[4] = {QuicAddrFamily, QuicAddrFamily, QuicAddrFamily, QuicAddrFamily}; for (uint8_t i = 0; i < 4; i++) { - ClientLocalAddrs[i].SetPort(44433 + i); - TEST_QUIC_SUCCEEDED( - Connection.SetParam( + 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)); + &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] = { From f04be9cbee1c656656bc96bc1d9cfda000146880 Mon Sep 17 00:00:00 2001 From: Masahiro Kozuka Date: Sat, 21 Dec 2024 15:54:06 +0900 Subject: [PATCH 14/29] Add support for multipath by introducing path ID management structures and settings --- scripts/clog.inputs | 3 + src/core/CMakeLists.txt | 2 + src/core/ack_tracker.c | 4 + src/core/bbr.c | 69 +- src/core/binding.c | 113 +- src/core/binding.h | 1 + src/core/cid.h | 12 +- src/core/congestion_control.c | 2 +- src/core/connection.c | 1253 ++++++----------- src/core/connection.h | 247 +--- src/core/crypto.c | 75 +- src/core/crypto_tls.c | 35 + src/core/cubic.c | 103 +- src/core/frame.c | 315 ++++- src/core/frame.h | 92 +- src/core/inline.c | 34 +- src/core/library.h | 4 +- src/core/listener.c | 2 +- src/core/lookup.c | 152 +- src/core/lookup.h | 19 +- src/core/loss_detection.c | 327 +++-- src/core/loss_detection.h | 33 +- src/core/operation.h | 1 + src/core/packet_builder.c | 29 +- src/core/packet_builder.h | 4 +- src/core/packet_space.c | 5 +- src/core/packet_space.h | 4 +- src/core/path.c | 74 +- src/core/path.h | 16 + src/core/pathid.c | 885 ++++++++++++ src/core/pathid.h | 459 ++++++ src/core/pathid_set.c | 878 ++++++++++++ src/core/pathid_set.h | 284 ++++ src/core/precomp.h | 2 + src/core/quicdef.h | 19 + src/core/send.c | 256 ++-- src/core/send.h | 11 +- src/core/send_buffer.c | 2 +- src/core/sent_packet_metadata.h | 13 +- src/core/settings.c | 33 + src/core/settings.h | 4 +- src/core/transport_params.h | 6 + src/core/unittest/FrameTest.cpp | 28 +- src/core/unittest/SettingsTest.cpp | 2 + src/core/unittest/SpinFrame.cpp | 11 +- src/core/worker.c | 2 + src/core/worker.h | 1 + src/generated/linux/connection.c.clog.h | 202 +-- .../linux/connection.c.clog.h.lttng.h | 234 +-- src/generated/linux/connection.h.clog.h | 22 - .../linux/connection.h.clog.h.lttng.h | 29 - src/generated/linux/crypto.c.clog.h | 16 +- src/generated/linux/crypto.c.clog.h.lttng.h | 24 +- src/generated/linux/crypto_tls.c.clog.h | 40 + .../linux/crypto_tls.c.clog.h.lttng.h | 46 + src/generated/linux/frame.c.clog.h | 54 + src/generated/linux/frame.c.clog.h.lttng.h | 74 + src/generated/linux/pathid.c.clog.h | 243 ++++ src/generated/linux/pathid.c.clog.h.lttng.h | 240 ++++ src/generated/linux/pathid.h.clog.h | 53 + src/generated/linux/pathid.h.clog.h.lttng.h | 33 + src/generated/linux/pathid_set.c.clog.h | 89 ++ .../linux/pathid_set.c.clog.h.lttng.h | 69 + .../linux/quic.clog_pathid.c.clog.h.c | 7 + .../linux/quic.clog_pathid.h.clog.h.c | 7 + .../linux/quic.clog_pathid_set.c.clog.h.c | 7 + src/generated/linux/settings.c.clog.h | 15 + src/generated/linux/settings.c.clog.h.lttng.h | 16 + src/inc/msquic.h | 6 +- src/inc/msquic.hpp | 1 + src/inc/msquic_posix.h | 1 + src/inc/msquic_winuser.h | 5 + src/inc/quic_crypt.h | 33 + src/inc/quic_platform.h | 3 +- src/manifest/MsQuicEtw.man | 75 +- src/manifest/clog.sidecar | 322 ++++- src/test/MsQuicTests.h | 14 +- src/test/bin/quic_gtest.cpp | 17 + src/test/bin/quic_gtest.h | 18 + src/test/lib/PathTest.cpp | 106 +- src/tools/recvfuzz/recvfuzz.cpp | 2 + 81 files changed, 5954 insertions(+), 2095 deletions(-) create mode 100644 src/core/pathid.c create mode 100644 src/core/pathid.h create mode 100644 src/core/pathid_set.c create mode 100644 src/core/pathid_set.h create mode 100644 src/generated/linux/pathid.c.clog.h create mode 100644 src/generated/linux/pathid.c.clog.h.lttng.h create mode 100644 src/generated/linux/pathid.h.clog.h create mode 100644 src/generated/linux/pathid.h.clog.h.lttng.h create mode 100644 src/generated/linux/pathid_set.c.clog.h create mode 100644 src/generated/linux/pathid_set.c.clog.h.lttng.h create mode 100644 src/generated/linux/quic.clog_pathid.c.clog.h.c create mode 100644 src/generated/linux/quic.clog_pathid.h.clog.h.c create mode 100644 src/generated/linux/quic.clog_pathid_set.c.clog.h.c 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 fe70fa57df..0310cd2095 100644 --- a/src/core/ack_tracker.c +++ b/src/core/ack_tracker.c @@ -227,6 +227,7 @@ QuicAckTrackerAckFrameEncode( _Inout_ QUIC_PACKET_BUILDER* Builder ) { + QUIC_PACKET_SPACE* PacketSpace = QuicAckTrackerGetPacketSpace(Tracker); CXPLAT_DBG_ASSERT(QuicAckTrackerHasPacketsToAck(Tracker)); const uint64_t Timestamp = CxPlatTimeUs64(); @@ -247,6 +248,9 @@ QuicAckTrackerAckFrameEncode( } if (!QuicAckFrameEncode( + QuicConnIsMultipathEnabled(PacketSpace->Connection) && + 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..2de907acf0 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,11 @@ BbrCongestionControlUpdateRecoveryWindow( ) { 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]); + QuicPathGetDatagramPayloadSize(PathID->Path); CXPLAT_DBG_ASSERT(Bbr->RecoveryState != RECOVERY_STATE_NOT_RECOVERY); @@ -500,13 +504,14 @@ BbrCongestionControlHandleAckInProbeRtt( ) { QUIC_CONGESTION_CONTROL_BBR* Bbr = &Cc->Bbr; - QUIC_CONNECTION* Connection = QuicCongestionControlGetConnection(Cc); + QUIC_PATHID* PathID = QuicCongestionControlGetPathID(Cc); + QUIC_CONNECTION* Connection = PathID->Connection; 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 +613,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 +699,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 +727,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 +759,7 @@ BbrCongestionControlUpdateCongestionWindow( Bbr->CongestionWindow = CXPLAT_MAX(CongestionWindow, MinCongestionWindow); - QuicConnLogBbr(QuicCongestionControlGetConnection(Cc)); + QuicConnLogBbr(PathID); } _IRQL_requires_max_(DISPATCH_LEVEL) @@ -764,7 +772,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 +906,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 +958,7 @@ BbrCongestionControlOnDataLost( } BbrCongestionControlUpdateBlockedState(Cc, PreviousCanSendState); - QuicConnLogBbr(QuicCongestionControlGetConnection(Cc)); + QuicConnLogBbr(PathID); } _IRQL_requires_max_(DISPATCH_LEVEL) @@ -969,8 +979,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 +1000,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 +1058,7 @@ BbrCongestionControlReset( Bbr->BandwidthFilter.AppLimitedExitTarget = 0; BbrCongestionControlLogOutFlowStatus(Cc); - QuicConnLogBbr(Connection); + QuicConnLogBbr(PathID); } @@ -1081,7 +1093,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 +1154,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 24a5c641b3..01063560d9 100644 --- a/src/core/binding.c +++ b/src/core/binding.c @@ -573,23 +573,36 @@ QuicBindingAddAllSourceConnectionIDs( _In_ QUIC_CONNECTION* Connection ) { - for (CXPLAT_SLIST_ENTRY* Link = Connection->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)) { - return FALSE; + 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 TRUE; + return Success; } + _IRQL_requires_max_(DISPATCH_LEVEL) void QuicBindingRemoveSourceConnectionID( @@ -607,42 +620,50 @@ QuicBindingRemoveAllSourceConnectionIDs( _In_ QUIC_CONNECTION* Connection ) { - CXPLAT_SLIST_ENTRY EntriesToFree = {0}; + QUIC_PATHID* PathIDs[QUIC_ACTIVE_PATH_ID_LIMIT]; + uint8_t PathIDCount = QUIC_ACTIVE_PATH_ID_LIMIT; + QuicPathIDSetGetPathIDs(&Connection->PathIDs, PathIDs, &PathIDCount); - for (CXPLAT_SLIST_ENTRY* Link = Connection->SourceCids.Next; - Link != NULL; - Link = Link->Next) { + for (uint8_t i = 0; i < PathIDCount; i++) { + CXPLAT_SLIST_ENTRY EntriesToFree = {0}; - QUIC_CID_SLIST_ENTRY* Entry = - CXPLAT_CONTAINING_RECORD( - Link, - QUIC_CID_SLIST_ENTRY, - Link); + for (CXPLAT_SLIST_ENTRY* Link = PathIDs[i]->SourceCids.Next; + Link != NULL; + Link = Link->Next) { - CXPLAT_SLIST_ENTRY** Link1 = &Entry->HashEntries.Next; - while (*Link1 != NULL) { - QUIC_CID_HASH_ENTRY* Entry1 = + QUIC_CID_SLIST_ENTRY* Entry = CXPLAT_CONTAINING_RECORD( - *Link1, - QUIC_CID_HASH_ENTRY, + Link, + QUIC_CID_SLIST_ENTRY, Link); - if (Entry1->Binding == Binding) { - QuicBindingRemoveSourceConnectionID(Binding, Entry1); - *Link1 = (*Link1)->Next; - CxPlatListPushEntry(&EntriesToFree, &Entry1->Link); - } else { - Link1 = &(*Link1)->Next; + + 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); + 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); } } @@ -1335,10 +1356,10 @@ QuicBindingCreateConnection( } BOOLEAN BindingRefAdded = FALSE; - CXPLAT_DBG_ASSERT(NewConnection->SourceCids.Next != NULL); + CXPLAT_DBG_ASSERT(NewConnection->Paths[0].PathID->SourceCids.Next != NULL); QUIC_CID_SLIST_ENTRY* SourceCid = CXPLAT_CONTAINING_RECORD( - NewConnection->SourceCids.Next, + NewConnection->Paths[0].PathID->SourceCids.Next, QUIC_CID_SLIST_ENTRY, Link); @@ -1408,7 +1429,7 @@ QuicBindingCreateConnection( #pragma warning(pop) } else { - NewConnection->SourceCids.Next = NULL; + 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") @@ -1510,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 795ab815e1..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. diff --git a/src/core/cid.h b/src/core/cid.h index b5fcc47ee9..557d52625e 100644 --- a/src/core/cid.h +++ b/src/core/cid.h @@ -166,7 +166,7 @@ typedef struct QUIC_CID_LIST_ENTRY { typedef struct QUIC_CID_SLIST_ENTRY { CXPLAT_SLIST_ENTRY Link; - QUIC_CONNECTION* Connection; + QUIC_PATHID* PathID; CXPLAT_SLIST_ENTRY HashEntries; QUIC_CID CID; @@ -176,7 +176,7 @@ typedef struct QUIC_CID_HASH_ENTRY { CXPLAT_HASHTABLE_ENTRY Entry; CXPLAT_SLIST_ENTRY Link; - QUIC_CONNECTION* Connection; + QUIC_PATHID* PathID; QUIC_BINDING* Binding; QUIC_CID_SLIST_ENTRY* CID; @@ -190,7 +190,7 @@ inline _Success_(return != NULL) QUIC_CID_SLIST_ENTRY* QuicCidNewNullSource( - _In_ QUIC_CONNECTION* Connection + _In_ QUIC_PATHID* PathID ) { QUIC_CID_SLIST_ENTRY* Entry = @@ -199,7 +199,7 @@ QuicCidNewNullSource( QUIC_POOL_CIDSLIST); if (Entry != NULL) { - Entry->Connection = Connection; + Entry->PathID = PathID; Entry->HashEntries.Next = NULL; CxPlatZeroMemory(&Entry->CID, sizeof(Entry->CID)); } @@ -214,7 +214,7 @@ inline _Success_(return != NULL) 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 @@ -228,7 +228,7 @@ QuicCidNewSource( 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; 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 69274396e6..1ae5844256 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; @@ -123,28 +122,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); @@ -198,6 +186,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) { @@ -206,29 +209,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_SLIST_ENTRY* SourceCid = - QuicCidNewSource(Connection, Packet->DestCidLen, Packet->DestCid); + 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. @@ -240,6 +231,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; @@ -247,14 +248,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( @@ -271,6 +266,7 @@ QuicConnAlloc( Status = QUIC_STATUS_INVALID_STATE; goto Error; } + QuicPathIDRelease(PathID, QUIC_PATHID_REF_LOOKUP); *NewConnection = Connection; return QUIC_STATUS_SUCCESS; @@ -278,28 +274,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_SLIST_ENTRY, - Link), - QUIC_POOL_CIDSLIST); - 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); @@ -317,18 +302,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 = @@ -339,14 +316,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); @@ -361,6 +331,10 @@ QuicConnFree( Connection->ReceiveQueue = 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; @@ -369,6 +343,7 @@ QuicConnFree( CxPlatDispatchLockUninitialize(&Connection->ReceiveQueueLock); QuicOperationQueueUninitialize(&Connection->OperQ); QuicStreamSetUninitialize(&Connection->Streams); + QuicPathIDSetUninitialize(&Connection->PathIDs); QuicSendBufferUninitialize(&Connection->SendBuffer); QuicDatagramSendShutdown(&Connection->Datagram); QuicDatagramUninitialize(&Connection->Datagram); @@ -606,38 +581,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_SLIST_ENTRY* SourceCid = - CXPLAT_CONTAINING_RECORD( - Entry, - QUIC_CID_SLIST_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( @@ -656,6 +599,7 @@ QuicConnTraceRundownOper( } QuicStreamSetTraceRundown(&Connection->Streams); + QuicPathIDSetTraceRundown(&Connection->PathIDs); } _IRQL_requires_max_(PASSIVE_LEVEL) @@ -707,7 +651,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)) { @@ -729,7 +673,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)) { @@ -825,431 +769,6 @@ QuicConnUpdateRtt( (uint32_t)(Path->OneWayDelay / 1000), (uint32_t)(Path->OneWayDelay % 1000)); } -_IRQL_requires_max_(PASSIVE_LEVEL) -QUIC_CID_SLIST_ENTRY* -QuicConnGenerateNewSourceCid( - _In_ QUIC_CONNECTION* Connection, - _In_ BOOLEAN IsInitial - ) -{ - uint8_t TryCount = 0; - QUIC_CID_SLIST_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; - } - - // - // 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 < Connection->PathsCount; ++i) { - if (Connection->Paths[i].Binding != NULL) { - BOOLEAN NewBinding = TRUE; - for (uint8_t j = 0; j < BindingsCount; ++j) { - if (Connection->Paths[i].Binding == Bindings[j]) { - NewBinding = FALSE; - break; - } - } - if (NewBinding) { - Bindings[BindingsCount++] = 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( - 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_SLIST_ENTRY) + MsQuicLib.CidTotalLength); - QuicConnFatalError(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.", - Connection, - "Too many CID collisions"); - QuicConnFatalError(Connection, QUIC_STATUS_INTERNAL_ERROR, NULL); - return NULL; - } - QuicTraceLogConnVerbose( - NewSrcCidNameCollision, - Connection, - "CID collision, trying again"); - } - } while (SourceCid == NULL); - - SourceCid->CID.SequenceNumber = 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)); - - 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 = 0; - CXPLAT_SLIST_ENTRY* Entry = Connection->SourceCids.Next; - while (Entry != NULL) { - QUIC_CID_SLIST_ENTRY* SourceCid = - CXPLAT_CONTAINING_RECORD(Entry, QUIC_CID_SLIST_ENTRY, Link); - SourceCid->CID.Retired = TRUE; - Entry = Entry->Next; - NewCidCount++; - } - } 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_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); - CXPLAT_DBG_ASSERT(Connection->Paths[i].Binding != NULL); - QuicLibraryReleaseBinding(Connection->Paths[i].Binding); - Connection->Paths[i].Binding = NULL; - QuicPathRemove(Connection, i--); - continue; - } - - CXPLAT_DBG_ASSERT(NewDestCid != Path->DestCid); - QUIC_CID_LIST_ENTRY* OldDestCid = Path->DestCid; - Path->DestCid = NewDestCid; - QUIC_CID_SET_PATH(Connection, NewDestCid, Path); - QUIC_CID_VALIDATE_NULL(Connection, OldDestCid); - 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_(PASSIVE_LEVEL) -BOOLEAN -QuicConnAssignCids( - _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->DestCid != NULL || !Path->InUse) { - continue; - } - - QUIC_CID_LIST_ENTRY* NewDestCid = QuicConnGetUnusedDestCid(Connection); - if (NewDestCid == NULL) { - return Assigned; - } - - Path->DestCid = NewDestCid; - QUIC_CID_SET_PATH(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) uint64_t QuicGetEarliestExpirationTime( @@ -1469,31 +988,13 @@ QuicConnOnShutdownComplete( Connection->RemoteHashEntry); } - while (Connection->SourceCids.Next != NULL) { - QUIC_CID_SLIST_ENTRY* CID = - CXPLAT_CONTAINING_RECORD( - CxPlatListPopEntry(&Connection->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); - } + 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); @@ -1642,7 +1143,7 @@ QuicConnTryClose( // uint64_t Pto = QuicLossDetectionComputeProbeTimeout( - &Connection->LossDetection, + &Connection->Paths[0].PathID->LossDetection, &Connection->Paths[0], QUIC_CLOSE_PTO_COUNT); QuicConnTimerSet( @@ -1982,27 +1483,21 @@ QuicConnStart( 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); @@ -2087,14 +1582,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) { @@ -2355,10 +1852,10 @@ QuicConnGenerateLocalTransportParameters( { CXPLAT_TEL_ASSERT(Connection->Configuration != NULL); - CXPLAT_DBG_ASSERT(Connection->SourceCids.Next != NULL); + CXPLAT_DBG_ASSERT(Connection->Paths[0].PathID->SourceCids.Next != NULL); const QUIC_CID_SLIST_ENTRY* SourceCid = CXPLAT_CONTAINING_RECORD( - Connection->SourceCids.Next, + Connection->Paths[0].PathID->SourceCids.Next, QUIC_CID_SLIST_ENTRY, Link); @@ -2447,6 +1944,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) { @@ -2571,10 +2073,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); @@ -2673,9 +2175,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 || @@ -3003,13 +2509,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) { @@ -3037,11 +2548,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( @@ -3277,11 +2788,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); } @@ -3409,95 +2922,6 @@ 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( - _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); - - 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( @@ -3659,10 +3083,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); @@ -3709,7 +3133,7 @@ QuicConnRecvRetry( // // Update the (destination) server's CID. // - if (!QuicConnUpdateDestCid(Connection, Packet)) { + if (!QuicPathIDUpdateDestCid(Connection->Paths[0].PathID, Packet)) { return; } @@ -3724,10 +3148,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); @@ -3786,7 +3210,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 @@ -3815,6 +3248,7 @@ QuicConnGetKeyOrDeferDatagram( *Tail = Packet; (*Tail)->Next = NULL; } + QuicPathIDRelease(PathID, QUIC_PATHID_REF_LOOKUP); } return FALSE; @@ -4150,9 +3584,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; @@ -4175,7 +3624,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) { @@ -4206,11 +3655,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; } @@ -4252,10 +3703,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. @@ -4278,39 +3737,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; } } @@ -4373,8 +3848,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()) { @@ -4432,7 +3909,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. @@ -4452,7 +3929,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); @@ -4624,11 +4101,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, @@ -5016,9 +4494,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.", @@ -5032,13 +4511,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. // @@ -5064,20 +4554,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.", @@ -5092,21 +4576,27 @@ QuicConnRecvFrames( } } - if (ReplaceRetiredCids && !QuicConnReplaceRetiredCids(Connection)) { + if (ReplaceRetiredCids && !QuicPathIDReplaceRetiredCids(PathID)) { return FALSE; } - if (QuicConnAssignCids(Connection)) { + if (QuicConnIsMultipathEnabled(Connection)) { + 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.", @@ -5119,11 +4609,20 @@ 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_SLIST_ENTRY* SourceCid = - QuicConnGetSourceCidFromSeq( - Connection, + QuicPathIDGetSourceCidFromSeq( + PathID, Frame.Sequence, TRUE, &IsLastCid); @@ -5146,7 +4645,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; } } @@ -5154,6 +4653,7 @@ QuicConnRecvFrames( AckEliciting = TRUE; Packet->HasNonProbingFrame = TRUE; + QuicPathIDRelease(PathID, QUIC_PATHID_REF_LOOKUP); break; } @@ -5204,6 +4704,9 @@ QuicConnRecvFrames( !memcmp(Frame.Data, TempPath->Challenge, sizeof(Frame.Data))) { QuicPerfCounterIncrement(QUIC_PERF_COUNTER_PATH_VALIDATED); QuicPathSetValid(Connection, TempPath, QUIC_PATH_VALID_PATH_RESPONSE); + if (QuicConnIsMultipathEnabled(Connection)) { + QuicPathSetActive(Connection, TempPath); + } break; } } @@ -5212,6 +4715,109 @@ QuicConnRecvFrames( break; } + case QUIC_FRAME_PATH_ABANDON: { + if (!QuicConnIsMultipathEnabled(Connection)) { + 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_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; @@ -5421,7 +5027,7 @@ QuicConnRecvFrames( Done: if (UpdatedFlowControl) { - QuicConnLogOutFlowStats(Connection); + QuicConnLogOutFlowStats(Path->PathID); } if (Connection->State.ShutdownComplete || Connection->State.HandleClosed) { @@ -5431,10 +5037,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; } @@ -5448,7 +5054,7 @@ QuicConnRecvFrames( } QuicAckTrackerAckPacket( - &Connection->Packets[EncryptLevel]->AckTracker, + &Path->PathID->Packets[EncryptLevel]->AckTracker, Packet->PacketNumber, RecvTime, ECN, @@ -5471,8 +5077,8 @@ QuicConnRecvPostProcessing( BOOLEAN PeerUpdatedCid = FALSE; if (Packet->DestCidLen != 0) { QUIC_CID_SLIST_ENTRY* SourceCid = - QuicConnGetSourceCidFromBuf( - Connection, + QuicPathIDGetSourceCidFromBuf( + (*Path)->PathID, Packet->DestCidLen, Packet->DestCid); if (SourceCid != NULL && !SourceCid->CID.UsedByPeer) { @@ -5506,7 +5112,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, @@ -5558,13 +5164,14 @@ 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 (QuicConnIsServer(Connection) && + !QuicConnIsMultipathEnabled(Connection) && Packet->HasNonProbingFrame && Packet->NewLargestPacketNumber && !(*Path)->IsActive) { @@ -5973,7 +5580,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; } } @@ -6028,7 +5635,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; @@ -6069,7 +5677,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; @@ -6212,7 +5821,7 @@ QuicConnResetIdleTimeout( // uint64_t MinIdleTimeoutMs = US_TO_MS(QuicLossDetectionComputeProbeTimeout( - &Connection->LossDetection, + &Path->PathID->LossDetection, Path, QUIC_CLOSE_PTO_COUNT)); if (IdleTimeoutMs < MinIdleTimeoutMs) { @@ -6296,6 +5905,37 @@ 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( @@ -6334,29 +5974,36 @@ QuicConnOpenNewPath( CxPlatCopyMemory(&Path->Route.RemoteAddress, &Connection->Paths[0].Route.RemoteAddress, sizeof(QUIC_ADDR)); + if (QuicConnIsMultipathEnabled(Connection)) { + 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(Connection); + QUIC_CID_SLIST_ENTRY* SourceCid = QuicCidNewNullSource(Path->PathID); if (SourceCid == NULL) { return QUIC_STATUS_OUT_OF_MEMORY; } - 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, FALSE); if (!QuicBindingAddSourceConnectionID(NewBinding, SourceCid)) { return QUIC_STATUS_OUT_OF_MEMORY; } } else { if (!QuicBindingAddAllSourceConnectionIDs(NewBinding, Connection)) { - QuicConnGenerateNewSourceCids(Connection, TRUE); + QuicPathIDSetGenerateNewSourceCids(&Connection->PathIDs, TRUE); } } @@ -6367,7 +6014,9 @@ QuicConnOpenNewPath( CASTED_CLOG_BYTEARRAY(sizeof(Path->Route.LocalAddress), &Path->Route.LocalAddress)); - QUIC_CID_LIST_ENTRY* NewDestCid = QuicConnGetUnusedDestCid(Connection); + 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. // @@ -6540,25 +6189,31 @@ QuicConnRemoveLocalAddress( QUIC_PATH* Path = &Connection->Paths[PathIndex]; - if (Path->IsActive && Connection->State.Started) { - return QUIC_STATUS_INVALID_STATE; - } + if (!QuicConnIsMultipathEnabled(Connection)) { + if (Path->IsActive && Connection->State.Started) { + return QUIC_STATUS_INVALID_STATE; + } - if (Path->DestCid != NULL) { - QuicConnRetireCid(Connection, Path->DestCid); - } + if (Path->DestCid != NULL) { + QuicPathIDRetireCid(Path->PathID, Path->DestCid); + } - if (Path->Binding != NULL) { - QuicBindingRemoveAllSourceConnectionIDs(Path->Binding, Connection); - QuicLibraryReleaseBinding(Path->Binding); - Path->Binding = NULL; - } + 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; + if (Connection->PathsCount == 1) { + CXPLAT_DBG_ASSERT(!Connection->State.Started); + Connection->State.LocalAddressSet = FALSE; + } else { + QuicPathRemove(Connection, PathIndex); + } } else { - QuicPathRemove(Connection, PathIndex); + Path->LocalClose = TRUE; + Path->SendAbandon = TRUE; + QuicSendSetSendFlag(&Connection->Send, QUIC_CONN_SEND_FLAG_PATH_ABANDON); } return QUIC_STATUS_SUCCESS; @@ -6645,7 +6300,7 @@ QuicConnParamSet( break; } - if (!QuicConnRetireCurrentDestCid(Connection, &Connection->Paths[0])) { + if (!QuicPathIDRetireCurrentDestCid(Connection->Paths[0].PathID, &Connection->Paths[0])) { QuicLibraryReleaseBinding(Connection->Paths[0].Binding); Connection->Paths[0].Binding = OldBinding; Status = QUIC_STATUS_INVALID_STATE; @@ -6666,7 +6321,7 @@ QuicConnParamSet( } } else { if (!QuicBindingAddAllSourceConnectionIDs(Connection->Paths[0].Binding, Connection)) { - QuicConnGenerateNewSourceCids(Connection, TRUE); + QuicPathIDSetGenerateNewSourceCids(&Connection->PathIDs, TRUE); } } QuicBindingRemoveAllSourceConnectionIDs(OldBinding, Connection); @@ -6688,7 +6343,7 @@ QuicConnParamSet( Connection, CASTED_CLOG_BYTEARRAY(sizeof(Connection->Paths[0].Route.LocalAddress), &Connection->Paths[0].Route.LocalAddress)); - QuicCongestionControlReset(&Connection->CongestionControl, FALSE); + QuicCongestionControlReset(&Connection->Paths[0].PathID->CongestionControl, FALSE); QuicSendSetSendFlag(&Connection->Send, QUIC_CONN_SEND_FLAG_PING); } @@ -7084,8 +6739,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; @@ -7124,7 +6779,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; } @@ -7203,7 +6858,12 @@ QuicConnParamSet( break; } - QuicConnGenerateNewSourceCids(Connection, FALSE); + if (BufferLength != sizeof(BOOLEAN) || Buffer == NULL) { + Status = QUIC_STATUS_INVALID_PARAMETER; + break; + } + + QuicPathIDSetGenerateNewSourceCids(&Connection->PathIDs, *(BOOLEAN*)Buffer); Status = QUIC_STATUS_SUCCESS; break; #endif @@ -7302,7 +6962,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; @@ -7766,7 +7426,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]; @@ -8044,11 +7704,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 c5fd763e3e..e6e4854fbd 100644 --- a/src/core/connection.h +++ b/src/core/connection.h @@ -239,6 +239,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 @@ -402,22 +403,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. // @@ -471,17 +456,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 @@ -489,16 +463,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. // @@ -583,21 +547,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. // @@ -668,6 +617,8 @@ typedef struct QUIC_CONNECTION { QUIC_FLOW_BLOCKED_TIMING_TRACKER FlowControl; } BlockedTimings; + QUIC_PATHID_SET PathIDs; + } QUIC_CONNECTION; typedef struct QUIC_SERIALIZED_RESUMPTION_STATE { @@ -739,6 +690,18 @@ QuicConnIsClosed( return Connection->State.ClosedLocally || Connection->State.ClosedRemotely; } +// +// Helper to determine if a connection is multipath enabled +// +inline +BOOLEAN +QuicConnIsMultipathEnabled( + _In_ const QUIC_CONNECTION * const Connection + ) +{ + return Connection->Settings.MultipathEnabled && Connection->PathIDs.Flags.InitialMaxPathRecvd; +} + // // Helper to get the owning QUIC_CONNECTION for the stream set module. // @@ -783,12 +746,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); } // @@ -796,12 +759,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); } // @@ -817,28 +780,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); } @@ -875,8 +851,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( @@ -1182,143 +1158,6 @@ QuicConnQueueHighestPriorityOper( _In_ QUIC_OPERATION* Oper ); -// -// Generates a new source connection ID. -// -_IRQL_requires_max_(PASSIVE_LEVEL) -QUIC_CID_SLIST_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_SLIST_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_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] (SeqNum=%llu) Removed Source CID: %!CID!", - Connection, - SourceCid->CID.SequenceNumber, - CASTED_CLOG_BYTEARRAY(SourceCid->CID.Length, SourceCid->CID.Data)); - *Entry = (*Entry)->Next; - } - *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_SLIST_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_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; -} - -// -// 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. @@ -1604,6 +1443,12 @@ QuicConnUpdatePeerPacketTolerance( _In_ uint8_t NewPacketTolerance ); +_IRQL_requires_max_(PASSIVE_LEVEL) +BOOLEAN +QuicConnAssignPathIDs( + _In_ QUIC_CONNECTION* Connection + ); + // // Open a new path for the connection. // diff --git a/src/core/crypto.c b/src/core/crypto.c index 9e0922cc10..c6846f41e3 100644 --- a/src/core/crypto.c +++ b/src/core/crypto.c @@ -160,10 +160,10 @@ QuicCryptoInitialize( RecvBufferInitialized = TRUE; if (QuicConnIsServer(Connection)) { - CXPLAT_DBG_ASSERT(Connection->SourceCids.Next != NULL); + CXPLAT_DBG_ASSERT(Connection->Paths[0].PathID->SourceCids.Next != NULL); QUIC_CID_SLIST_ENTRY* SourceCid = CXPLAT_CONTAINING_RECORD( - Connection->SourceCids.Next, + Connection->Paths[0].PathID->SourceCids.Next, QUIC_CID_SLIST_ENTRY, Link); @@ -171,10 +171,10 @@ QuicCryptoInitialize( 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,10 +415,10 @@ QuicCryptoOnVersionChange( } if (QuicConnIsServer(Connection)) { - CXPLAT_DBG_ASSERT(Connection->SourceCids.Next != NULL); + CXPLAT_DBG_ASSERT(Connection->Paths[0].PathID->SourceCids.Next != NULL); QUIC_CID_SLIST_ENTRY* SourceCid = CXPLAT_CONTAINING_RECORD( - Connection->SourceCids.Next, + Connection->Paths[0].PathID->SourceCids.Next, QUIC_CID_SLIST_ENTRY, Link); @@ -426,10 +426,10 @@ QuicCryptoOnVersionChange( 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); @@ -545,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. @@ -1409,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); } @@ -1597,22 +1598,22 @@ 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); + 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, + 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_CIDSLIST); @@ -1628,10 +1629,10 @@ QuicCryptoProcessTlsCompletion( #if QUIC_TEST_MANUAL_CONN_ID_GENERATION if (!Connection->State.DisableConnIDGen) { - QuicConnGenerateNewSourceCids(Connection, FALSE); + QuicPathIDSetGenerateNewSourceCids(&Connection->PathIDs, FALSE); } #else - QuicConnGenerateNewSourceCids(Connection, FALSE); + QuicPathIDSetGenerateNewSourceCids(&Connection->PathIDs, FALSE); #endif CXPLAT_DBG_ASSERT(Crypto->TlsState.NegotiatedAlpn != NULL); @@ -2133,8 +2134,6 @@ QuicCryptoUpdateKeyPhase( Connection->Stats.Misc.KeyUpdateCount++; } - QUIC_PACKET_SPACE* PacketSpace = Connection->Packets[QUIC_ENCRYPT_LEVEL_1_RTT]; - UNREFERENCED_PARAMETER(LocalUpdate); QuicTraceEvent( ConnKeyPhaseChange, @@ -2142,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 da1b459030..aeafe1bc90 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..b381aab5b8 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,14 @@ CubicCongestionControlReset( { 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); 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 +172,8 @@ CubicCongestionControlReset( Cubic->BytesInFlight = 0; } - QuicConnLogOutFlowStats(Connection); - QuicConnLogCubic(Connection); + QuicConnLogOutFlowStats(PathID); + QuicConnLogCubic(PathID); } _IRQL_requires_max_(DISPATCH_LEVEL) @@ -185,7 +187,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 +198,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 +233,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 +254,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 +281,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 +318,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 +386,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 +429,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 +446,7 @@ CubicCongestionControlOnDataAcknowledged( QuicTraceEvent( ConnRecoveryExit, "[conn][%p] Recovery complete", - Connection); + PathID->Connection); Cubic->IsInRecovery = FALSE; Cubic->IsInPersistentCongestion = FALSE; Cubic->TimeOfCongAvoidStart = TimeNowUs; @@ -454,7 +459,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 +508,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 +555,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 +566,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 +675,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 +696,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 +734,7 @@ CubicCongestionControlOnDataLost( Cubic->BytesInFlight -= LossEvent->NumRetransmittableBytes; CubicCongestionControlUpdateBlockedState(Cc, PreviousCanSendState); - QuicConnLogCubic(QuicCongestionControlGetConnection(Cc)); + QuicConnLogCubic(QuicCongestionControlGetPathID(Cc)); } _IRQL_requires_max_(DISPATCH_LEVEL) @@ -752,7 +757,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 +766,7 @@ CubicCongestionControlOnEcn( } CubicCongestionControlUpdateBlockedState(Cc, PreviousCanSendState); - QuicConnLogCubic(QuicCongestionControlGetConnection(Cc)); + QuicConnLogCubic(QuicCongestionControlGetPathID(Cc)); } _IRQL_requires_max_(DISPATCH_LEVEL) @@ -776,7 +781,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 +805,7 @@ CubicCongestionControlOnSpuriousCongestionEvent( Cubic->HasHadCongestionEvent = FALSE; BOOLEAN Result = CubicCongestionControlUpdateBlockedState(Cc, PreviousCanSendState); - QuicConnLogCubic(Connection); + QuicConnLogCubic(PathID); return Result; } @@ -808,20 +814,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 +907,21 @@ CubicCongestionControlInitialize( 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); 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 7e1a923e11..f2cee06bcc 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,95 @@ 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 +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( @@ -1412,26 +1557,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( @@ -1794,7 +1963,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]", @@ -1817,9 +1986,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]", @@ -1839,6 +2034,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)) { @@ -1883,6 +2101,51 @@ 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_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 277177cbe9..ed1d878be3 100644 --- a/src/core/frame.h +++ b/src/core/frame.h @@ -159,6 +159,15 @@ typedef enum QUIC_FRAME_TYPE { QUIC_FRAME_IMMEDIATE_ACK = 0xacULL, /* 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,21 @@ 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_ABANDON || \ + X == QUIC_FRAME_PATH_NEW_CONNECTION_ID || \ + 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 +222,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 +242,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 +668,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 +686,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 +697,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 +711,7 @@ QuicNewConnectionIDFrameDecode( typedef struct QUIC_RETIRE_CONNECTION_ID_EX { + QUIC_VAR_INT PathID; QUIC_VAR_INT Sequence; } QUIC_RETIRE_CONNECTION_ID_EX; @@ -697,6 +719,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 +730,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 +776,67 @@ 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_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 // @@ -901,6 +986,7 @@ QuicTimestampFrameDecode( _Out_ QUIC_TIMESTAMP_EX* Frame ); + // // Helper functions // diff --git a/src/core/inline.c b/src/core/inline.c index 4aeb7e7eb1..a38737d621 100644 --- a/src/core/inline.c +++ b/src/core/inline.c @@ -29,7 +29,7 @@ QuicCidNewDestination( 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 @@ -37,12 +37,12 @@ QuicCidNewSource( QUIC_CID_SLIST_ENTRY* QuicCidNewNullSource( - _In_ QUIC_CONNECTION* Connection + _In_ QUIC_PATHID* PathID ); 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 @@ -728,7 +740,7 @@ QuicConnLogStatistics( BOOLEAN QuicPacketBuilderAddFrame( _Inout_ QUIC_PACKET_BUILDER* Builder, - _In_ uint8_t FrameType, + _In_ uint32_t FrameType, _In_ BOOLEAN IsAckEliciting ); @@ -750,24 +762,24 @@ QuicPacketBuilderHasAllowance( ); QUIC_CID_SLIST_ENTRY* -QuicConnGetSourceCidFromSeq( - _In_ QUIC_CONNECTION* Connection, +QuicPathIDGetSourceCidFromSeq( + _In_ QUIC_PATHID* PathID, _In_ QUIC_VAR_INT SequenceNumber, _In_ BOOLEAN RemoveFromList, _Out_ BOOLEAN* IsLastCid ); QUIC_CID_SLIST_ENTRY* -QuicConnGetSourceCidFromBuf( - _In_ QUIC_CONNECTION* Connection, +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 c911b26f1a..a6c18eb7ea 100644 --- a/src/core/library.h +++ b/src/core/library.h @@ -453,7 +453,7 @@ inline _Success_(return != NULL) 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, @@ -474,7 +474,7 @@ QuicCidNewRandomSource( 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 e4ccb0a4d1..b78680a5d1 100644 --- a/src/core/lookup.c +++ b/src/core/lookup.c @@ -175,32 +175,38 @@ QuicLookupRebalance( // if (PreviousLookup != NULL) { - CXPLAT_SLIST_ENTRY* Entry = - ((QUIC_CONNECTION*)PreviousLookup)->SourceCids.Next; + QUIC_PATHID* PathIDs[QUIC_ACTIVE_PATH_ID_LIMIT]; + uint8_t PathIDCount = QUIC_ACTIVE_PATH_ID_LIMIT; + QuicPathIDSetGetPathIDs(&((QUIC_CONNECTION*)PreviousLookup)->PathIDs, PathIDs, &PathIDCount); - 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 = + 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( - Entry1, - QUIC_CID_HASH_ENTRY, + Entry, + QUIC_CID_SLIST_ENTRY, Link); - if (CID1->Binding == QuicLookupGetBinding(Lookup)) { - (void)QuicLookupInsertLocalCid( - Lookup, - CxPlatHashSimple(CID->CID.Length, CID->CID.Data), - CID1, - FALSE); + 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; } - Entry1 = Entry1->Next; + Entry = Entry->Next; } - Entry = Entry->Next; + QuicPathIDRelease(PathIDs[i], QUIC_PATHID_REF_LOOKUP); } } @@ -288,38 +294,55 @@ _IRQL_requires_max_(DISPATCH_LEVEL) BOOLEAN QuicCidMatchConnection( _In_ QUIC_LOOKUP* Lookup, - _In_ const QUIC_CONNECTION* const Connection, + _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_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); + 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 (Entry1->Binding != QuicLookupGetBinding(Lookup)) { - continue; + if (Length == Entry1->CID->CID.Length && + (Length == 0 || memcmp(DestCid, Entry1->CID->CID.Data, Length) == 0)) { + Match = TRUE; + goto Match; + } + } } - - if (Length == Entry1->CID->CID.Length && - (Length == 0 || memcmp(DestCid, Entry1->CID->CID.Data, Length) == 0)) { - return TRUE; +Match: + if (Match) { + *PathId = PathIDs[i]->ID; } } + QuicPathIDRelease(PathIDs[i], QUIC_PATHID_REF_LOOKUP); } - return FALSE; + return Match; } // @@ -333,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); @@ -346,7 +371,8 @@ QuicHashLookupConnection( if (CIDEntry->CID->CID.Length == Length && memcmp(DestCid, CIDEntry->CID->CID.Data, Length) == 0) { - return CIDEntry->Connection; + *PathId = CIDEntry->PathID->ID; + return CIDEntry->PathID->Connection; } TableEntry = CxPlatHashtableLookupNext(Table, &Context); @@ -362,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) { @@ -373,7 +401,7 @@ QuicLookupFindConnectionByLocalCidInternal( // destination connection ID matches that connection. // if (Lookup->SINGLE.Connection != NULL && - QuicCidMatchConnection(Lookup, Lookup->SINGLE.Connection, CID, CIDLen)) { + QuicCidMatchConnection(Lookup, Lookup->SINGLE.Connection, CID, CIDLen, PathId)) { Connection = Lookup->SINGLE.Connection; } @@ -399,7 +427,8 @@ QuicLookupFindConnectionByLocalCidInternal( &Table->Table, CID, CIDLen, - Hash); + Hash, + PathId); CxPlatDispatchRwLockReleaseShared(&Table->RwLock, PrevIrql); } @@ -486,7 +515,7 @@ QuicLookupInsertLocalCid( _In_ BOOLEAN UpdateRefCount ) { - if (!QuicLookupRebalance(Lookup, SourceCid->Connection)) { + if (!QuicLookupRebalance(Lookup, SourceCid->PathID->Connection)) { return FALSE; } @@ -495,7 +524,7 @@ 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 { @@ -522,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 @@ -619,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 @@ -651,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); @@ -663,7 +693,8 @@ QuicLookupFindConnectionByLocalCid( Lookup, CID, CIDLen, - Hash); + Hash, + PathId); if (ExistingConnection != NULL) { QuicConnAddRef(ExistingConnection, QUIC_CONN_REF_LOOKUP_RESULT); @@ -681,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); @@ -699,6 +732,7 @@ QuicLookupFindConnectionByRemoteHash( Hash); if (ExistingConnection != NULL) { + *PathId = 0; QuicConnAddRef(ExistingConnection, QUIC_CONN_REF_LOOKUP_RESULT); } @@ -760,12 +794,14 @@ 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) { QUIC_CID_HASH_ENTRY* CID = @@ -775,7 +811,7 @@ QuicLookupAddLocalCid( if (CID != NULL) { CID->CID = SourceCid; CID->Binding = QuicLookupGetBinding(Lookup); - CID->Connection = SourceCid->Connection; + CID->PathID = SourceCid->PathID; Result = QuicLookupInsertLocalCid(Lookup, Hash, CID, TRUE); if (Result) { @@ -866,7 +902,7 @@ QuicLookupRemoveLocalCid( CxPlatDispatchRwLockAcquireExclusive(&Lookup->RwLock, PrevIrql); QuicLookupRemoveLocalCidInt(Lookup, SourceCid); 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) diff --git a/src/core/lookup.h b/src/core/lookup.h index 6440992fb4..636d602b0f 100644 --- a/src/core/lookup.h +++ b/src/core/lookup.h @@ -108,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 ); // @@ -121,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 ); // @@ -179,3 +181,16 @@ QuicLookupRemoveRemoteHash( _In_ QUIC_LOOKUP* Lookup, _In_ QUIC_REMOTE_HASH_ENTRY* RemoteHashEntry ); + +// +// Inserts a source connection ID into the lookup table. Requires the +// Lookup->RwLock to be exlusively held. +// +_IRQL_requires_max_(DISPATCH_LEVEL) +BOOLEAN +QuicLookupInsertLocalCid( + _In_ QUIC_LOOKUP* Lookup, + _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 f0e8982a5e..4f6617ad6e 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_SLIST_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_SLIST_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; } @@ -855,6 +914,32 @@ 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_MAX_PATH_ID: + NewDataQueued |= + QuicSendSetSendFlag( + &Connection->Send, + QUIC_CONN_SEND_FLAG_MAX_PATH_ID); + break; + case QUIC_FRAME_HANDSHAKE_DONE: NewDataQueued |= QuicSendSetSendFlag( @@ -900,7 +985,7 @@ QuicLossDetectionOnPacketDiscarded( _In_ BOOLEAN DiscardedForLoss ) { - QUIC_CONNECTION* Connection = QuicLossDetectionGetConnection(LossDetection); + QUIC_CONNECTION* Connection = QuicLossDetectionGetPathID(LossDetection)->Connection; if (Packet->Flags.IsMtuProbe && DiscardedForLoss) { uint8_t PathIndex; @@ -928,7 +1013,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; @@ -969,7 +1056,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; @@ -1072,7 +1159,7 @@ QuicLossDetectionDetectAndHandleLostPackets( LossDetection->ProbeCount > QUIC_PERSISTENT_CONGESTION_THRESHOLD }; - QuicCongestionControlOnDataLost(&Connection->CongestionControl, &LossEvent); + QuicCongestionControlOnDataLost(&PathID->CongestionControl, &LossEvent); // // Send packets from any previously blocked streams. // @@ -1092,7 +1179,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; @@ -1218,7 +1307,7 @@ QuicLossDetectionDiscardPackets( .MinRttValid = FALSE }; - if (QuicCongestionControlOnDataAcknowledged(&Connection->CongestionControl, &AckEvent)) { + if (QuicCongestionControlOnDataAcknowledged(&PathID->CongestionControl, &AckEvent)) { // // We were previously blocked and are now unblocked. // @@ -1233,7 +1322,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; @@ -1285,7 +1376,7 @@ QuicLossDetectionOnZeroRttRejected( if (CountRetransmittableBytes > 0) { if (QuicCongestionControlOnDataInvalidated( - &Connection->CongestionControl, + &PathID->CongestionControl, CountRetransmittableBytes)) { // // We were previously blocked and are now unblocked. @@ -1312,7 +1403,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; @@ -1374,7 +1466,7 @@ QuicLossDetectionProcessAckBlocks( // spuriously lost. Inform congestion control. // if (QuicCongestionControlOnSpuriousCongestionEvent( - &Connection->CongestionControl)) { + &PathID->CongestionControl)) { // // We were previously blocked and are now unblocked. // @@ -1517,7 +1609,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) { @@ -1552,7 +1644,7 @@ QuicLossDetectionProcessAckBlocks( .LargestPacketNumberAcked = LargestAckedPacketNum, .LargestSentPacketNumber = LossDetection->LargestSentPacketNumber, }; - QuicCongestionControlOnEcn(&Connection->CongestionControl, &EcnEvent); + QuicCongestionControlOnEcn(&PathID->CongestionControl, &EcnEvent); } } } else { @@ -1606,7 +1698,7 @@ QuicLossDetectionProcessAckBlocks( .MinRttValid = TRUE, }; - if (QuicCongestionControlOnDataAcknowledged(&Connection->CongestionControl, &AckEvent)) { + if (QuicCongestionControlOnDataAcknowledged(&PathID->CongestionControl, &AckEvent)) { // // We were previously blocked and are now unblocked. // @@ -1630,76 +1722,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. // @@ -1709,7 +1731,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( @@ -1733,7 +1756,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; @@ -1796,7 +1819,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 e502b6ce4a..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,7 +116,7 @@ QuicPacketBuilderInitialize( Builder->SourceCid = CXPLAT_CONTAINING_RECORD( - Connection->SourceCids.Next, + Path->PathID->SourceCids.Next, QUIC_CID_SLIST_ENTRY, Link); @@ -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); // @@ -972,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 2d3c7faed5..0ecc4cd844 100644 --- a/src/core/packet_builder.h +++ b/src/core/packet_builder.h @@ -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 842030a2a9..b8ebf7886d 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 { @@ -213,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( @@ -224,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]; } @@ -258,6 +268,7 @@ QuicConnGetPathForPacket( } if (!QuicLibraryTryAddRefBinding(Connection->Paths[0].Binding)) { + QuicPathIDRelease(PathID, QUIC_PATHID_REF_LOOKUP); return NULL; } @@ -280,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 (QuicConnIsMultipathEnabled(Connection) && 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; } @@ -294,7 +345,10 @@ QuicPathSetActive( ) { BOOLEAN UdpPortChangeOnly = FALSE; - if (Path == &Connection->Paths[0]) { + + if (QuicConnIsMultipathEnabled(Connection)) { + Path->IsActive = TRUE; + } else if (Path == &Connection->Paths[0]) { CXPLAT_DBG_ASSERT(!Path->IsActive); Path->IsActive = TRUE; } else { @@ -326,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); @@ -341,7 +395,7 @@ QuicPathUpdateQeo( ) { const QUIC_CID_SLIST_ENTRY* SourceCid = - CXPLAT_CONTAINING_RECORD(Connection->SourceCids.Next, QUIC_CID_SLIST_ENTRY, Link); + CXPLAT_CONTAINING_RECORD(Path->PathID->SourceCids.Next, QUIC_CID_SLIST_ENTRY, Link); CXPLAT_QEO_CONNECTION Offloads[2] = { { Operation, @@ -350,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, }, @@ -369,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 283f6ce079..8bb14b6cd4 100644 --- a/src/core/path.h +++ b/src/core/path.h @@ -101,6 +101,13 @@ typedef struct QUIC_PATH { // BOOLEAN SendResponse : 1; + BOOLEAN LocalClose : 1; + BOOLEAN LocalCloseAcked : 1; + + BOOLEAN SendAbandon : 1; + + BOOLEAN RemoteClose : 1; + // // Indicates the partition has updated for this path. // @@ -136,6 +143,8 @@ typedef struct QUIC_PATH { // QUIC_MTU_DISCOVERY MtuDiscovery; + QUIC_PATHID *PathID; + // // The binding used for sending/receiving UDP packets. // @@ -313,6 +322,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..6d7be98bc4 --- /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 = + QuicConnIsMultipathEnabled(PathID->Connection) ? + 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 = + QuicConnIsMultipathEnabled(PathID->Connection) ? + 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..d8bd313005 --- /dev/null +++ b/src/core/pathid.h @@ -0,0 +1,459 @@ +/*++ + 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 +} 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..c6a366893f --- /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 (QuicConnIsMultipathEnabled(QuicPathIDSetGetConnection(PathIDSet))) { + 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 6942944743..0d66c4e68b 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; @@ -374,6 +375,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. // @@ -537,6 +543,11 @@ CXPLAT_STATIC_ASSERT( // #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. // @@ -594,6 +605,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 @@ -616,6 +628,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 *************************************************************/ @@ -644,6 +662,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" diff --git a/src/core/send.c b/src/core/send.c index 2a1c3f89d2..cdd058a6da 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,44 @@ 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 (Is1RttEncryptionLevel) { if (Builder->Metadata->Flags.KeyType == QUIC_PACKET_KEY_1_RTT && Send->SendFlags & QUIC_CONN_SEND_FLAG_HANDSHAKE_DONE) { @@ -775,61 +826,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_SLIST_ENTRY* SourceCid = - CXPLAT_CONTAINING_RECORD( - Entry, - QUIC_CID_SLIST_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 +845,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 +863,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; @@ -1166,6 +1158,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); } @@ -1189,7 +1195,7 @@ QuicSendFlush( ) { QUIC_CONNECTION* Connection = QuicSendGetConnection(Send); - QUIC_PATH* Path = &Connection->Paths[0]; + QUIC_PATH* Path = QuicConnChoosePath(Connection); CXPLAT_DBG_ASSERT(!Connection->State.HandleClosed); @@ -1225,7 +1231,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; @@ -1262,7 +1268,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; @@ -1312,7 +1318,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. @@ -1382,14 +1388,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. @@ -1542,12 +1547,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..4276194729 100644 --- a/src/core/send.h +++ b/src/core/send.h @@ -145,6 +145,12 @@ 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_ACK 0x00040000U +#define QUIC_CONN_SEND_FLAG_PATH_ABANDON 0x00080000U +#define QUIC_CONN_SEND_FLAG_PATH_BACKUP 0x00100000U +#define QUIC_CONN_SEND_FLAG_PATH_AVAILABLE 0x00200000U +#define QUIC_CONN_SEND_FLAG_MAX_PATH_ID 0x00400000U +#define QUIC_CONN_SEND_FLAG_PATHS_BLOCKED 0x00800000U #define QUIC_CONN_SEND_FLAG_DPLPMTUD 0x80000000U // @@ -262,11 +268,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..5051c0c651 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,9 @@ typedef struct QUIC_SENT_FRAME_METADATA { struct { uint8_t Data[8]; } PATH_RESPONSE; + struct { + uint32_t PathID; + } PATH_ABANDON; struct { void* ClientContext; } DATAGRAM; @@ -75,14 +80,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 cb906e3199..75b5713e2e 100644 --- a/src/core/settings.c +++ b/src/core/settings.c @@ -173,6 +173,9 @@ QuicSettingsSetDefault( Settings->ConnIDGenDisabled = QUIC_DEFAULT_CONN_ID_GENERATION_DISABLED; } #endif + if (!Settings->IsSet.MultipathEnabled) { + Settings->MultipathEnabled = QUIC_DEFAULT_MULTIPATH_ENABLED; + } } _IRQL_requires_max_(PASSIVE_LEVEL) @@ -346,6 +349,9 @@ QuicSettingsCopy( Destination->ConnIDGenDisabled = Source->ConnIDGenDisabled; } #endif + if (!Destination->IsSet.MultipathEnabled) { + Destination->MultipathEnabled = Source->MultipathEnabled; + } } _IRQL_requires_max_(PASSIVE_LEVEL) @@ -731,6 +737,11 @@ QuicSettingApply( Destination->IsSet.ConnIDGenDisabled = TRUE; } #endif + + if (Source->IsSet.MultipathEnabled && (!Destination->IsSet.MultipathEnabled || OverWrite)) { + Destination->MultipathEnabled = Source->MultipathEnabled; + Destination->IsSet.MultipathEnabled = TRUE; + } return TRUE; } @@ -1411,6 +1422,16 @@ QuicSettingsLoad( 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) @@ -1480,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) @@ -1649,6 +1671,9 @@ QuicSettingsDumpNew( 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) \ @@ -1913,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 3f016b482d..ba2c9a43a0 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -63,7 +63,8 @@ typedef struct QUIC_SETTINGS_INTERNAL { uint64_t NetStatsEventEnabled : 1; uint64_t StreamMultiReceiveEnabled : 1; uint64_t ConnIDGenDisabled : 1; - uint64_t RESERVED : 15; + uint64_t MultipathEnabled : 1; + uint64_t RESERVED : 14; } IsSet; }; @@ -115,6 +116,7 @@ typedef struct QUIC_SETTINGS_INTERNAL { 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 7daff1d250..0e3fd0e483 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); } @@ -924,7 +926,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; @@ -935,9 +937,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); @@ -1071,7 +1073,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/connection.c.clog.h b/src/generated/linux/connection.c.clog.h index a6cf39afc4..4d80f9af71 100644 --- a/src/generated/linux/connection.c.clog.h +++ b/src/generated/linux/connection.c.clog.h @@ -41,24 +41,6 @@ #ifdef __cplusplus extern "C" { #endif -/*---------------------------------------------------------- -// Decoder Ring for PacketRxStatelessReset -// [S][RX][-] SR %s -// QuicTraceLogVerbose( - 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 -#define _clog_3_ARGS_TRACE_PacketRxStatelessReset(uniqueId, encoded_arg_string, arg2)\ -tracepoint(CLOG_CONNECTION_C, PacketRxStatelessReset , arg2);\ - -#endif - - - - /*---------------------------------------------------------- // Decoder Ring for PacketRxNotAcked // [%c][RX][%llu] not acked (connection is closed) @@ -321,42 +303,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 +552,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 @@ -903,42 +849,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] @@ -1598,50 +1508,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 +1702,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 +1851,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 37095d84b3..9dd4ec2d97 100644 --- a/src/generated/linux/connection.c.clog.h.lttng.h +++ b/src/generated/linux/connection.c.clog.h.lttng.h @@ -1,25 +1,6 @@ -/*---------------------------------------------------------- -// Decoder Ring for PacketRxStatelessReset -// [S][RX][-] SR %s -// QuicTraceLogVerbose( - 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, - TP_ARGS( - const char *, arg2), - TP_FIELDS( - ctf_string(arg2, arg2) - ) -) - - - /*---------------------------------------------------------- // Decoder Ring for PacketRxNotAcked // [%c][RX][%llu] not acked (connection is closed) @@ -323,44 +304,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 +578,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, @@ -981,44 +924,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] @@ -1779,64 +1684,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 +1902,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 +2082,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..27b01ecefe 100644 --- a/src/generated/linux/connection.h.clog.h +++ b/src/generated/linux/connection.h.clog.h @@ -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..e1a250286a 100644 --- a/src/generated/linux/connection.h.clog.h.lttng.h +++ b/src/generated/linux/connection.h.clog.h.lttng.h @@ -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/frame.c.clog.h b/src/generated/linux/frame.c.clog.h index 99477a4200..d74ee7fbb8 100644 --- a/src/generated/linux/frame.c.clog.h +++ b/src/generated/linux/frame.c.clog.h @@ -871,6 +871,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:%u Seq:%llu RPT:%llu CID:%s Token:%s +// QuicTraceLogVerbose( + FrameLogPathNewConnectionID, + "[%c][%cX][%llu] PATH_NEW_CONN_ID PathID:%u 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] diff --git a/src/generated/linux/frame.c.clog.h.lttng.h b/src/generated/linux/frame.c.clog.h.lttng.h index 5c25f96c93..0f1588c364 100644 --- a/src/generated/linux/frame.c.clog.h.lttng.h +++ b/src/generated/linux/frame.c.clog.h.lttng.h @@ -1098,6 +1098,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:%u Seq:%llu RPT:%llu CID:%s Token:%s +// QuicTraceLogVerbose( + FrameLogPathNewConnectionID, + "[%c][%cX][%llu] PATH_NEW_CONN_ID PathID:%u 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 int, 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(unsigned int, 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] diff --git a/src/generated/linux/pathid.c.clog.h b/src/generated/linux/pathid.c.clog.h new file mode 100644 index 0000000000..197c8b3960 --- /dev/null +++ b/src/generated/linux/pathid.c.clog.h @@ -0,0 +1,243 @@ +#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_QuicTraceLogVerbose +#define _clog_MACRO_QuicTraceLogVerbose 1 +#define QuicTraceLogVerbose(a, ...) _clog_CAT(_clog_ARGN_SELECTOR(__VA_ARGS__), _clog_CAT(_,a(#a, __VA_ARGS__))) +#endif +#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 PacketRxStatelessReset +// [S][RX][-] SR %s +// QuicTraceLogVerbose( + PacketRxStatelessReset, + "[S][RX][-] SR %s", + QuicCidBufToStr(ResetToken, QUIC_STATELESS_RESET_TOKEN_LENGTH).Buffer); +// arg2 = arg2 = QuicCidBufToStr(ResetToken, QUIC_STATELESS_RESET_TOKEN_LENGTH).Buffer = arg2 +----------------------------------------------------------*/ +#ifndef _clog_3_ARGS_TRACE_PacketRxStatelessReset +#define _clog_3_ARGS_TRACE_PacketRxStatelessReset(uniqueId, encoded_arg_string, arg2)\ +tracepoint(CLOG_PATHID_C, PacketRxStatelessReset , arg2);\ + +#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 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 + + + + +#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..ba6a4d5363 --- /dev/null +++ b/src/generated/linux/pathid.c.clog.h.lttng.h @@ -0,0 +1,240 @@ + + + +/*---------------------------------------------------------- +// Decoder Ring for PacketRxStatelessReset +// [S][RX][-] SR %s +// QuicTraceLogVerbose( + PacketRxStatelessReset, + "[S][RX][-] SR %s", + QuicCidBufToStr(ResetToken, QUIC_STATELESS_RESET_TOKEN_LENGTH).Buffer); +// arg2 = arg2 = QuicCidBufToStr(ResetToken, QUIC_STATELESS_RESET_TOKEN_LENGTH).Buffer = arg2 +----------------------------------------------------------*/ +TRACEPOINT_EVENT(CLOG_PATHID_C, PacketRxStatelessReset, + TP_ARGS( + const char *, arg2), + TP_FIELDS( + ctf_string(arg2, arg2) + ) +) + + + +/*---------------------------------------------------------- +// 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 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) + ) +) 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..4605f0988b --- /dev/null +++ b/src/generated/linux/pathid_set.c.clog.h @@ -0,0 +1,89 @@ +#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_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 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 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 ConnPathIDCreated +// [conn][%p] New PathID %u +// QuicTraceEvent( + ConnPathIDCreated, + "[conn][%p] New PathID %u", + Connection, + PathID->ID); +// arg2 = arg2 = Connection = arg2 +// arg3 = arg3 = PathID->ID = arg3 +----------------------------------------------------------*/ +#ifndef _clog_4_ARGS_TRACE_ConnPathIDCreated +#define _clog_4_ARGS_TRACE_ConnPathIDCreated(uniqueId, encoded_arg_string, arg2, arg3)\ +tracepoint(CLOG_PATHID_SET_C, ConnPathIDCreated , 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..f7fde023ed --- /dev/null +++ b/src/generated/linux/pathid_set.c.clog.h.lttng.h @@ -0,0 +1,69 @@ + + + +/*---------------------------------------------------------- +// 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 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 ConnPathIDCreated +// [conn][%p] New PathID %u +// QuicTraceEvent( + ConnPathIDCreated, + "[conn][%p] New PathID %u", + Connection, + PathID->ID); +// arg2 = arg2 = Connection = arg2 +// arg3 = arg3 = PathID->ID = arg3 +----------------------------------------------------------*/ +TRACEPOINT_EVENT(CLOG_PATHID_SET_C, ConnPathIDCreated, + 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 3501062ef2..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 diff --git a/src/generated/linux/settings.c.clog.h.lttng.h b/src/generated/linux/settings.c.clog.h.lttng.h index 40aaf98930..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 diff --git a/src/inc/msquic.h b/src/inc/msquic.h index e5f8e34bc4..aaddc8c4f7 100644 --- a/src/inc/msquic.h +++ b/src/inc/msquic.h @@ -692,7 +692,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 +744,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 diff --git a/src/inc/msquic.hpp b/src/inc/msquic.hpp index 41fadab557..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 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/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 4f351ca641..dede8ea1c6 100644 --- a/src/inc/quic_platform.h +++ b/src/inc/quic_platform.h @@ -148,7 +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' // Qc0D - QUIC CID SLIST Entry +#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/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 c30ab5166d..45cf730530 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,16 @@ "MacroVariableName": "arg2" }, { - "DefinationEncoding": "llu", + "DefinationEncoding": "u", "MacroVariableName": "arg3" }, { - "DefinationEncoding": "!CID!", + "DefinationEncoding": "llu", "MacroVariableName": "arg4" + }, + { + "DefinationEncoding": "!CID!", + "MacroVariableName": "arg5" } ], "macroName": "QuicTraceEvent" @@ -1839,6 +1847,22 @@ ], "macroName": "QuicTraceEvent" }, + "ConnPathIDCreated": { + "ModuleProperites": {}, + "TraceString": "[conn][%p] New PathID %u", + "UniqueId": "ConnPathIDCreated", + "splitArgs": [ + { + "DefinationEncoding": "p", + "MacroVariableName": "arg2" + }, + { + "DefinationEncoding": "u", + "MacroVariableName": "arg3" + } + ], + "macroName": "QuicTraceEvent" + }, "ConnPersistentCongestion": { "ModuleProperites": {}, "TraceString": "[conn][%p] Persistent congestion event", @@ -2033,7 +2057,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 +2065,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 +2089,16 @@ "MacroVariableName": "arg2" }, { - "DefinationEncoding": "llu", + "DefinationEncoding": "u", "MacroVariableName": "arg3" }, { - "DefinationEncoding": "!CID!", + "DefinationEncoding": "llu", "MacroVariableName": "arg4" + }, + { + "DefinationEncoding": "!CID!", + "MacroVariableName": "arg5" } ], "macroName": "QuicTraceEvent" @@ -3239,6 +3271,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 +3835,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)", @@ -5012,6 +5076,66 @@ ], "macroName": "QuicTraceLogVerbose" }, + "FrameLogPathNewConnectionID": { + "ModuleProperites": {}, + "TraceString": "[%c][%cX][%llu] PATH_NEW_CONN_ID PathID:%u Seq:%llu RPT:%llu CID:%s Token:%s", + "UniqueId": "FrameLogPathNewConnectionID", + "splitArgs": [ + { + "DefinationEncoding": "c", + "MacroVariableName": "arg2" + }, + { + "DefinationEncoding": "c", + "MacroVariableName": "arg3" + }, + { + "DefinationEncoding": "llu", + "MacroVariableName": "arg4" + }, + { + "DefinationEncoding": "u", + "MacroVariableName": "arg5" + }, + { + "DefinationEncoding": "llu", + "MacroVariableName": "arg6" + }, + { + "DefinationEncoding": "llu", + "MacroVariableName": "arg7" + }, + { + "DefinationEncoding": "s", + "MacroVariableName": "arg8" + }, + { + "DefinationEncoding": "s", + "MacroVariableName": "arg9" + } + ], + "macroName": "QuicTraceLogVerbose" + }, + "FrameLogPathNewConnectionIDInvalid": { + "ModuleProperites": {}, + "TraceString": "[%c][%cX][%llu] PATH_NEW_CONN_ID [Invalid]", + "UniqueId": "FrameLogPathNewConnectionIDInvalid", + "splitArgs": [ + { + "DefinationEncoding": "c", + "MacroVariableName": "arg2" + }, + { + "DefinationEncoding": "c", + "MacroVariableName": "arg3" + }, + { + "DefinationEncoding": "llu", + "MacroVariableName": "arg4" + } + ], + "macroName": "QuicTraceLogVerbose" + }, "FrameLogPathResponse": { "ModuleProperites": {}, "TraceString": "[%c][%cX][%llu] PATH_RESPONSE [%llu]", @@ -8119,6 +8243,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", @@ -10930,6 +11150,18 @@ ], "macroName": "QuicTraceLogVerbose" }, + "SettingMultipathEnabled": { + "ModuleProperites": {}, + "TraceString": "[sett] MultipathEnabled = %hhu", + "UniqueId": "SettingMultipathEnabled", + "splitArgs": [ + { + "DefinationEncoding": "hhu", + "MacroVariableName": "arg2" + } + ], + "macroName": "QuicTraceLogVerbose" + }, "SettingNetStatsEventEnabled": { "ModuleProperites": {}, "TraceString": "[sett] NetStatsEventEnabled = %hhu", @@ -13776,14 +14008,14 @@ "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": "3903cc44-b387-b5f6-17fc-62d5aee48015", @@ -13950,6 +14182,11 @@ "TraceID": "ConnPacketStats", "EncodingString": "[conn][%p] STATS: SendTotalPackets=%llu SendSuspectedLostPackets=%llu SendSpuriousLostPackets=%llu RecvTotalPackets=%llu RecvReorderedPackets=%llu RecvDroppedPackets=%llu RecvDuplicatePackets=%llu RecvDecryptionFailures=%llu" }, + { + "UniquenessHash": "03ab7814-30a8-e2f0-69bc-24a671996e5b", + "TraceID": "ConnPathIDCreated", + "EncodingString": "[conn][%p] New PathID %u" + }, { "UniquenessHash": "c339eadc-2eef-8e45-4a51-1fc84a3c198e", "TraceID": "ConnPersistentCongestion", @@ -14011,14 +14248,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", @@ -14380,6 +14617,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", @@ -14555,6 +14797,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", @@ -14870,6 +15117,16 @@ "TraceID": "FrameLogPathChallengeInvalid", "EncodingString": "[%c][%cX][%llu] PATH_CHALLENGE [Invalid]" }, + { + "UniquenessHash": "80accc44-ecef-a74e-cef2-f13e7a389abf", + "TraceID": "FrameLogPathNewConnectionID", + "EncodingString": "[%c][%cX][%llu] PATH_NEW_CONN_ID PathID:%u 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", @@ -15795,6 +16052,26 @@ "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", @@ -16750,6 +17027,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/test/MsQuicTests.h b/src/test/MsQuicTests.h index 2db058f241..09f86d1f3b 100644 --- a/src/test/MsQuicTests.h +++ b/src/test/MsQuicTests.h @@ -387,6 +387,11 @@ QuicTestMultipleLocalAddresses( _In_ uint32_t DropPacketCount ); +void +QuicTestMultipath( + _In_ int Family + ); + void QuicTestNatPortRebind( _In_ int Family, @@ -1375,4 +1380,11 @@ typedef struct { QUIC_CTL_CODE(127, METHOD_BUFFERED, FILE_WRITE_DATA) // QUIC_RUN_MIGRATION -#define QUIC_MAX_IOCTL_FUNC_CODE 127 +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 4afd543d4c..c387c33fc8 100644 --- a/src/test/bin/quic_gtest.cpp +++ b/src/test/bin/quic_gtest.cpp @@ -1717,6 +1717,18 @@ TEST_P(WithProbePathArgs, MultipleLocalAddresses) { 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 @@ -2492,6 +2504,11 @@ 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 469670f821..344bb036f1 100644 --- a/src/test/bin/quic_gtest.h +++ b/src/test/bin/quic_gtest.h @@ -981,4 +981,22 @@ std::ostream& operator << (std::ostream& o, const MigrationArgs& args) { 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/lib/PathTest.cpp b/src/test/lib/PathTest.cpp index ca0089efc8..8c92909466 100644 --- a/src/test/lib/PathTest.cpp +++ b/src/test/lib/PathTest.cpp @@ -192,11 +192,12 @@ QuicTestProbePath( TEST_EQUAL(Status, QUIC_STATUS_SUCCESS); if (DeferConnIDGen) { + BOOLEAN ReplaceExistingCids = FALSE; TEST_QUIC_SUCCEEDED( Context.Connection->SetParam( QUIC_PARAM_CONN_GENERATE_CONN_ID, - 0, - NULL)); + sizeof(ReplaceExistingCids), + &ReplaceExistingCids)); } TEST_TRUE(ProbeHelper->ServerReceiveProbeEvent.WaitTimeout(TestWaitTimeout * 10)); @@ -394,7 +395,12 @@ QuicTestMultipleLocalAddresses( TEST_NOT_EQUAL(nullptr, Context.Connection); if (DeferConnIDGen) { - TEST_QUIC_SUCCEEDED(Context.Connection->SetParam(QUIC_PARAM_CONN_GENERATE_CONN_ID, 0, NULL)); + 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)); @@ -404,4 +410,98 @@ QuicTestMultipleLocalAddresses( 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/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, From bf1a2f795a2bbfca4f2cfe8f04cc5f103599d2dd Mon Sep 17 00:00:00 2001 From: Masahiro Kozuka Date: Tue, 31 Dec 2024 15:53:24 +0900 Subject: [PATCH 15/29] Refactor congestion control code to remove unused connection references and add multipath support functions --- src/core/bbr.c | 2 - src/core/cubic.c | 2 - src/core/inline.c | 17 + src/generated/linux/bbr.c.clog.h | 4 +- src/generated/linux/bbr.c.clog.h.lttng.h | 4 +- .../linux/congestion_control.c.clog.h | 4 +- .../linux/congestion_control.c.clog.h.lttng.h | 4 +- src/generated/linux/connection.c.clog.h | 18 + .../linux/connection.c.clog.h.lttng.h | 19 + src/generated/linux/connection.h.clog.h | 12 +- .../linux/connection.h.clog.h.lttng.h | 12 +- src/generated/linux/cubic.c.clog.h | 32 +- src/generated/linux/cubic.c.clog.h.lttng.h | 32 +- src/generated/linux/frame.c.clog.h | 220 ++++++++++- src/generated/linux/frame.c.clog.h.lttng.h | 280 ++++++++++++- src/generated/linux/path.c.clog.h | 20 + src/generated/linux/path.c.clog.h.lttng.h | 23 ++ src/generated/linux/pathid.c.clog.h | 66 ++-- src/generated/linux/pathid.c.clog.h.lttng.h | 75 +++- src/generated/linux/pathid_set.c.clog.h | 62 ++- .../linux/pathid_set.c.clog.h.lttng.h | 60 ++- src/manifest/clog.sidecar | 374 +++++++++++++++++- 22 files changed, 1195 insertions(+), 147 deletions(-) diff --git a/src/core/bbr.c b/src/core/bbr.c index 2de907acf0..fb6403ab14 100644 --- a/src/core/bbr.c +++ b/src/core/bbr.c @@ -475,7 +475,6 @@ BbrCongestionControlUpdateRecoveryWindow( { QUIC_CONGESTION_CONTROL_BBR* Bbr = &Cc->Bbr; QUIC_PATHID* PathID = QuicCongestionControlGetPathID(Cc); - QUIC_CONNECTION* Connection = PathID->Connection; const uint16_t DatagramPayloadLength = QuicPathGetDatagramPayloadSize(PathID->Path); @@ -505,7 +504,6 @@ BbrCongestionControlHandleAckInProbeRtt( { QUIC_CONGESTION_CONTROL_BBR* Bbr = &Cc->Bbr; QUIC_PATHID* PathID = QuicCongestionControlGetPathID(Cc); - QUIC_CONNECTION* Connection = PathID->Connection; Bbr->BandwidthFilter.AppLimited = TRUE; Bbr->BandwidthFilter.AppLimitedExitTarget = LargestSentPacketNumber; diff --git a/src/core/cubic.c b/src/core/cubic.c index b381aab5b8..4b86e3cb18 100644 --- a/src/core/cubic.c +++ b/src/core/cubic.c @@ -154,7 +154,6 @@ CubicCongestionControlReset( QUIC_CONGESTION_CONTROL_CUBIC* Cubic = &Cc->Cubic; QUIC_PATHID* PathID = QuicCongestionControlGetPathID(Cc); - QUIC_CONNECTION* Connection = PathID->Connection; const uint16_t DatagramPayloadLength = QuicPathGetDatagramPayloadSize(PathID->Path); @@ -908,7 +907,6 @@ CubicCongestionControlInitialize( QUIC_CONGESTION_CONTROL_CUBIC* Cubic = &Cc->Cubic; QUIC_PATHID* PathID = QuicCongestionControlGetPathID(Cc); - QUIC_CONNECTION* Connection = PathID->Connection; const uint16_t DatagramPayloadLength = QuicPathGetDatagramPayloadSize(PathID->Path); Cubic->SlowStartThreshold = UINT32_MAX; diff --git a/src/core/inline.c b/src/core/inline.c index a38737d621..0aa938fd1c 100644 --- a/src/core/inline.c +++ b/src/core/inline.c @@ -100,6 +100,11 @@ QuicConnIsClient( _In_ const QUIC_CONNECTION * const Connection ); +BOOLEAN +QuicConnIsMultipathEnabled( + _In_ const QUIC_CONNECTION * const Connection + ); + _IRQL_requires_max_(PASSIVE_LEVEL) void QuicConnTransportError( @@ -761,6 +766,18 @@ QuicPacketBuilderHasAllowance( _In_ const QUIC_PACKET_BUILDER* Builder ); +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, 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 4d80f9af71..b3fdc839df 100644 --- a/src/generated/linux/connection.c.clog.h +++ b/src/generated/linux/connection.c.clog.h @@ -41,6 +41,24 @@ #ifdef __cplusplus extern "C" { #endif +/*---------------------------------------------------------- +// Decoder Ring for PacketRxStatelessReset +// [S][RX][-] SR %s +// QuicTraceLogVerbose( + 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 +#define _clog_3_ARGS_TRACE_PacketRxStatelessReset(uniqueId, encoded_arg_string, arg2)\ +tracepoint(CLOG_CONNECTION_C, PacketRxStatelessReset , arg2);\ + +#endif + + + + /*---------------------------------------------------------- // Decoder Ring for PacketRxNotAcked // [%c][RX][%llu] not acked (connection is closed) diff --git a/src/generated/linux/connection.c.clog.h.lttng.h b/src/generated/linux/connection.c.clog.h.lttng.h index 9dd4ec2d97..5b7c3d53ff 100644 --- a/src/generated/linux/connection.c.clog.h.lttng.h +++ b/src/generated/linux/connection.c.clog.h.lttng.h @@ -1,6 +1,25 @@ +/*---------------------------------------------------------- +// Decoder Ring for PacketRxStatelessReset +// [S][RX][-] SR %s +// QuicTraceLogVerbose( + 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, + TP_ARGS( + const char *, arg2), + TP_FIELDS( + ctf_string(arg2, arg2) + ) +) + + + /*---------------------------------------------------------- // Decoder Ring for PacketRxNotAcked // [%c][RX][%llu] not acked (connection is closed) diff --git a/src/generated/linux/connection.h.clog.h b/src/generated/linux/connection.h.clog.h index 27b01ecefe..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 diff --git a/src/generated/linux/connection.h.clog.h.lttng.h b/src/generated/linux/connection.h.clog.h.lttng.h index e1a250286a..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, 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 d74ee7fbb8..6ddec4986f 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 @@ -895,10 +945,10 @@ tracepoint(CLOG_FRAME_C, FrameLogPathNewConnectionIDInvalid , arg2, arg3, arg4); /*---------------------------------------------------------- // Decoder Ring for FrameLogPathNewConnectionID -// [%c][%cX][%llu] PATH_NEW_CONN_ID PathID:%u Seq:%llu RPT:%llu CID:%s Token:%s +// [%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:%u Seq:%llu RPT:%llu CID:%s Token:%s", + "[%c][%cX][%llu] PATH_NEW_CONN_ID PathID:%llu Seq:%llu RPT:%llu CID:%s Token:%s", PtkConnPre(Connection), PktRxPre(Rx), PacketNumber, @@ -971,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] @@ -1063,6 +1161,100 @@ 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 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 0f1588c364..90632ef4f8 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 @@ -1127,10 +1193,10 @@ TRACEPOINT_EVENT(CLOG_FRAME_C, FrameLogPathNewConnectionIDInvalid, /*---------------------------------------------------------- // Decoder Ring for FrameLogPathNewConnectionID -// [%c][%cX][%llu] PATH_NEW_CONN_ID PathID:%u Seq:%llu RPT:%llu CID:%s Token:%s +// [%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:%u Seq:%llu RPT:%llu CID:%s Token:%s", + "[%c][%cX][%llu] PATH_NEW_CONN_ID PathID:%llu Seq:%llu RPT:%llu CID:%s Token:%s", PtkConnPre(Connection), PktRxPre(Rx), PacketNumber, @@ -1153,7 +1219,7 @@ TRACEPOINT_EVENT(CLOG_FRAME_C, FrameLogPathNewConnectionID, unsigned char, arg2, unsigned char, arg3, unsigned long long, arg4, - unsigned int, arg5, + unsigned long long, arg5, unsigned long long, arg6, unsigned long long, arg7, const char *, arg8, @@ -1162,7 +1228,7 @@ TRACEPOINT_EVENT(CLOG_FRAME_C, FrameLogPathNewConnectionID, ctf_integer(unsigned char, arg2, arg2) ctf_integer(unsigned char, arg3, arg3) ctf_integer(uint64_t, arg4, arg4) - ctf_integer(unsigned int, arg5, arg5) + ctf_integer(uint64_t, arg5, arg5) ctf_integer(uint64_t, arg6, arg6) ctf_integer(uint64_t, arg7, arg7) ctf_string(arg8, arg8) @@ -1230,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] @@ -1346,6 +1474,126 @@ 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 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 index 197c8b3960..ec5b1628fc 100644 --- a/src/generated/linux/pathid.c.clog.h +++ b/src/generated/linux/pathid.c.clog.h @@ -14,10 +14,6 @@ #include "pathid.c.clog.h.lttng.h" #endif #include -#ifndef _clog_MACRO_QuicTraceLogVerbose -#define _clog_MACRO_QuicTraceLogVerbose 1 -#define QuicTraceLogVerbose(a, ...) _clog_CAT(_clog_ARGN_SELECTOR(__VA_ARGS__), _clog_CAT(_,a(#a, __VA_ARGS__))) -#endif #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__))) @@ -33,24 +29,6 @@ #ifdef __cplusplus extern "C" { #endif -/*---------------------------------------------------------- -// Decoder Ring for PacketRxStatelessReset -// [S][RX][-] SR %s -// QuicTraceLogVerbose( - PacketRxStatelessReset, - "[S][RX][-] SR %s", - QuicCidBufToStr(ResetToken, QUIC_STATELESS_RESET_TOKEN_LENGTH).Buffer); -// arg2 = arg2 = QuicCidBufToStr(ResetToken, QUIC_STATELESS_RESET_TOKEN_LENGTH).Buffer = arg2 -----------------------------------------------------------*/ -#ifndef _clog_3_ARGS_TRACE_PacketRxStatelessReset -#define _clog_3_ARGS_TRACE_PacketRxStatelessReset(uniqueId, encoded_arg_string, arg2)\ -tracepoint(CLOG_PATHID_C, PacketRxStatelessReset , arg2);\ - -#endif - - - - /*---------------------------------------------------------- // Decoder Ring for NoReplacementCidForRetire // [conn][%p] Can't retire current CID because we don't have a replacement @@ -123,6 +101,26 @@ tracepoint(CLOG_PATHID_C, ZeroLengthCidRetire , 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 +----------------------------------------------------------*/ +#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! @@ -235,6 +233,30 @@ tracepoint(CLOG_PATHID_C, ConnDestCidRemoved , arg2, arg3, arg4, arg5_len, arg5) +/*---------------------------------------------------------- +// 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 diff --git a/src/generated/linux/pathid.c.clog.h.lttng.h b/src/generated/linux/pathid.c.clog.h.lttng.h index ba6a4d5363..0820c27512 100644 --- a/src/generated/linux/pathid.c.clog.h.lttng.h +++ b/src/generated/linux/pathid.c.clog.h.lttng.h @@ -1,25 +1,6 @@ -/*---------------------------------------------------------- -// Decoder Ring for PacketRxStatelessReset -// [S][RX][-] SR %s -// QuicTraceLogVerbose( - PacketRxStatelessReset, - "[S][RX][-] SR %s", - QuicCidBufToStr(ResetToken, QUIC_STATELESS_RESET_TOKEN_LENGTH).Buffer); -// arg2 = arg2 = QuicCidBufToStr(ResetToken, QUIC_STATELESS_RESET_TOKEN_LENGTH).Buffer = arg2 -----------------------------------------------------------*/ -TRACEPOINT_EVENT(CLOG_PATHID_C, PacketRxStatelessReset, - TP_ARGS( - const char *, arg2), - TP_FIELDS( - ctf_string(arg2, arg2) - ) -) - - - /*---------------------------------------------------------- // Decoder Ring for NoReplacementCidForRetire // [conn][%p] Can't retire current CID because we don't have a replacement @@ -96,6 +77,29 @@ TRACEPOINT_EVENT(CLOG_PATHID_C, ZeroLengthCidRetire, +/*---------------------------------------------------------- +// 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! @@ -238,3 +242,36 @@ TRACEPOINT_EVENT(CLOG_PATHID_C, ConnDestCidRemoved, 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_set.c.clog.h b/src/generated/linux/pathid_set.c.clog.h index 4605f0988b..8ebe3f4a79 100644 --- a/src/generated/linux/pathid_set.c.clog.h +++ b/src/generated/linux/pathid_set.c.clog.h @@ -14,6 +14,10 @@ #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__))) @@ -21,6 +25,26 @@ #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) @@ -41,6 +65,26 @@ tracepoint(CLOG_PATHID_SET_C, AllocFailure , arg2, 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 +----------------------------------------------------------*/ +#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. @@ -62,19 +106,19 @@ tracepoint(CLOG_PATHID_SET_C, ConnError , arg2, arg3);\ /*---------------------------------------------------------- -// Decoder Ring for ConnPathIDCreated -// [conn][%p] New PathID %u +// Decoder Ring for ConnPathIDAdd +// [conn][%p] Added New PathID %u // QuicTraceEvent( - ConnPathIDCreated, - "[conn][%p] New PathID %u", - Connection, + ConnPathIDAdd, + "[conn][%p] Added New PathID %u", + QuicPathIDSetGetConnection(PathIDSet), PathID->ID); -// arg2 = arg2 = Connection = arg2 +// arg2 = arg2 = QuicPathIDSetGetConnection(PathIDSet) = arg2 // arg3 = arg3 = PathID->ID = arg3 ----------------------------------------------------------*/ -#ifndef _clog_4_ARGS_TRACE_ConnPathIDCreated -#define _clog_4_ARGS_TRACE_ConnPathIDCreated(uniqueId, encoded_arg_string, arg2, arg3)\ -tracepoint(CLOG_PATHID_SET_C, ConnPathIDCreated , arg2, 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 diff --git a/src/generated/linux/pathid_set.c.clog.h.lttng.h b/src/generated/linux/pathid_set.c.clog.h.lttng.h index f7fde023ed..c365c0ca21 100644 --- a/src/generated/linux/pathid_set.c.clog.h.lttng.h +++ b/src/generated/linux/pathid_set.c.clog.h.lttng.h @@ -1,6 +1,29 @@ +/*---------------------------------------------------------- +// 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) @@ -24,6 +47,29 @@ TRACEPOINT_EVENT(CLOG_PATHID_SET_C, AllocFailure, +/*---------------------------------------------------------- +// 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. @@ -48,17 +94,17 @@ TRACEPOINT_EVENT(CLOG_PATHID_SET_C, ConnError, /*---------------------------------------------------------- -// Decoder Ring for ConnPathIDCreated -// [conn][%p] New PathID %u +// Decoder Ring for ConnPathIDAdd +// [conn][%p] Added New PathID %u // QuicTraceEvent( - ConnPathIDCreated, - "[conn][%p] New PathID %u", - Connection, + ConnPathIDAdd, + "[conn][%p] Added New PathID %u", + QuicPathIDSetGetConnection(PathIDSet), PathID->ID); -// arg2 = arg2 = Connection = arg2 +// arg2 = arg2 = QuicPathIDSetGetConnection(PathIDSet) = arg2 // arg3 = arg3 = PathID->ID = arg3 ----------------------------------------------------------*/ -TRACEPOINT_EVENT(CLOG_PATHID_SET_C, ConnPathIDCreated, +TRACEPOINT_EVENT(CLOG_PATHID_SET_C, ConnPathIDAdd, TP_ARGS( const void *, arg2, unsigned int, arg3), diff --git a/src/manifest/clog.sidecar b/src/manifest/clog.sidecar index 45cf730530..e2197c645d 100644 --- a/src/manifest/clog.sidecar +++ b/src/manifest/clog.sidecar @@ -1195,6 +1195,30 @@ ], "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" + }, "ConnDestroyed": { "ModuleProperites": {}, "TraceString": "[conn][%p] Destroyed", @@ -1847,6 +1871,38 @@ ], "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", @@ -1863,6 +1919,22 @@ ], "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", @@ -4812,6 +4884,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", @@ -5032,6 +5148,106 @@ ], "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" + }, "FrameLogPathChallenge": { "ModuleProperites": {}, "TraceString": "[%c][%cX][%llu] PATH_CHALLENGE [%llu]", @@ -5078,7 +5294,7 @@ }, "FrameLogPathNewConnectionID": { "ModuleProperites": {}, - "TraceString": "[%c][%cX][%llu] PATH_NEW_CONN_ID PathID:%u Seq:%llu RPT:%llu CID:%s Token:%s", + "TraceString": "[%c][%cX][%llu] PATH_NEW_CONN_ID PathID:%llu Seq:%llu RPT:%llu CID:%s Token:%s", "UniqueId": "FrameLogPathNewConnectionID", "splitArgs": [ { @@ -5094,7 +5310,7 @@ "MacroVariableName": "arg4" }, { - "DefinationEncoding": "u", + "DefinationEncoding": "llu", "MacroVariableName": "arg5" }, { @@ -5180,6 +5396,54 @@ ], "macroName": "QuicTraceLogVerbose" }, + "FrameLogPathRetireConnectionID": { + "ModuleProperites": {}, + "TraceString": "[%c][%cX][%llu] PATH_RETIRE_CONN_ID PathID:%llu Seq:%llu", + "UniqueId": "FrameLogPathRetireConnectionID", + "splitArgs": [ + { + "DefinationEncoding": "c", + "MacroVariableName": "arg2" + }, + { + "DefinationEncoding": "c", + "MacroVariableName": "arg3" + }, + { + "DefinationEncoding": "llu", + "MacroVariableName": "arg4" + }, + { + "DefinationEncoding": "llu", + "MacroVariableName": "arg5" + }, + { + "DefinationEncoding": "llu", + "MacroVariableName": "arg6" + } + ], + "macroName": "QuicTraceLogVerbose" + }, + "FrameLogPathRetireConnectionIDInvalid": { + "ModuleProperites": {}, + "TraceString": "[%c][%cX][%llu] PATH_RETIRE_CONN_ID [Invalid]", + "UniqueId": "FrameLogPathRetireConnectionIDInvalid", + "splitArgs": [ + { + "DefinationEncoding": "c", + "MacroVariableName": "arg2" + }, + { + "DefinationEncoding": "c", + "MacroVariableName": "arg3" + }, + { + "DefinationEncoding": "llu", + "MacroVariableName": "arg4" + } + ], + "macroName": "QuicTraceLogVerbose" + }, "FrameLogPing": { "ModuleProperites": {}, "TraceString": "[%c][%cX][%llu] PING", @@ -8227,6 +8491,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]", @@ -8491,6 +8771,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!", @@ -14017,6 +14313,11 @@ "TraceID": "ConnDestCidRemoved", "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", "TraceID": "ConnDestroyed", @@ -14182,11 +14483,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", @@ -15062,6 +15378,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", @@ -15107,6 +15433,26 @@ "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": "230959d3-aa58-0944-8287-6120bebac2f0", "TraceID": "FrameLogPathChallenge", @@ -15118,9 +15464,9 @@ "EncodingString": "[%c][%cX][%llu] PATH_CHALLENGE [Invalid]" }, { - "UniquenessHash": "80accc44-ecef-a74e-cef2-f13e7a389abf", + "UniquenessHash": "551b1ae9-51b6-70f3-76c1-e428c25d5885", "TraceID": "FrameLogPathNewConnectionID", - "EncodingString": "[%c][%cX][%llu] PATH_NEW_CONN_ID PathID:%u Seq:%llu RPT:%llu CID:%s Token:%s" + "EncodingString": "[%c][%cX][%llu] PATH_NEW_CONN_ID PathID:%llu Seq:%llu RPT:%llu CID:%s Token:%s" }, { "UniquenessHash": "24e192ff-90cd-4918-4bec-529eb9a41789", @@ -15137,6 +15483,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", @@ -16047,6 +16403,11 @@ "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", @@ -16117,6 +16478,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", From 610318951b3cd81c05b4bd181e4f0ba49409eb29 Mon Sep 17 00:00:00 2001 From: Masahiro Kozuka Date: Tue, 31 Dec 2024 23:01:32 +0900 Subject: [PATCH 16/29] Refactor multipath handling to use negotiated state --- src/core/ack_tracker.c | 2 +- src/core/connection.c | 22 ++++++++++++++++------ src/core/connection.h | 17 +++++------------ src/core/frame.h | 2 +- src/core/inline.c | 5 ----- src/core/path.c | 4 ++-- src/core/pathid.c | 4 ++-- src/core/pathid_set.c | 4 ++-- 8 files changed, 29 insertions(+), 31 deletions(-) diff --git a/src/core/ack_tracker.c b/src/core/ack_tracker.c index 0310cd2095..a7c752973c 100644 --- a/src/core/ack_tracker.c +++ b/src/core/ack_tracker.c @@ -248,7 +248,7 @@ QuicAckTrackerAckFrameEncode( } if (!QuicAckFrameEncode( - QuicConnIsMultipathEnabled(PacketSpace->Connection) && + PacketSpace->Connection->State.MultipathNegotiated && Builder->EncryptLevel == QUIC_ENCRYPT_LEVEL_1_RTT, PacketSpace->PathID->ID, &Tracker->PacketNumbersToAck, diff --git a/src/core/connection.c b/src/core/connection.c index 1ae5844256..c4c632d980 100644 --- a/src/core/connection.c +++ b/src/core/connection.c @@ -2629,6 +2629,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. // @@ -4580,7 +4585,7 @@ QuicConnRecvFrames( return FALSE; } - if (QuicConnIsMultipathEnabled(Connection)) { + if (Connection->State.MultipathNegotiated) { QuicConnAssignPathIDs(Connection); } @@ -4704,7 +4709,7 @@ QuicConnRecvFrames( !memcmp(Frame.Data, TempPath->Challenge, sizeof(Frame.Data))) { QuicPerfCounterIncrement(QUIC_PERF_COUNTER_PATH_VALIDATED); QuicPathSetValid(Connection, TempPath, QUIC_PATH_VALID_PATH_RESPONSE); - if (QuicConnIsMultipathEnabled(Connection)) { + if (Connection->State.MultipathNegotiated) { QuicPathSetActive(Connection, TempPath); } break; @@ -4716,7 +4721,7 @@ QuicConnRecvFrames( } case QUIC_FRAME_PATH_ABANDON: { - if (!QuicConnIsMultipathEnabled(Connection)) { + if (!Connection->State.MultipathNegotiated) { QuicTraceEvent( ConnError, "[conn][%p] ERROR, %s.", @@ -5171,7 +5176,7 @@ QuicConnRecvPostProcessing( } if (QuicConnIsServer(Connection) && - !QuicConnIsMultipathEnabled(Connection) && + !Connection->State.MultipathNegotiated && Packet->HasNonProbingFrame && Packet->NewLargestPacketNumber && !(*Path)->IsActive) { @@ -5974,7 +5979,7 @@ QuicConnOpenNewPath( CxPlatCopyMemory(&Path->Route.RemoteAddress, &Connection->Paths[0].Route.RemoteAddress, sizeof(QUIC_ADDR)); - if (QuicConnIsMultipathEnabled(Connection)) { + if (Connection->State.MultipathNegotiated) { Path->PathID = QuicPathIDSetGetUnusedPathID(&Connection->PathIDs); if (Path->PathID != NULL) { QuicPathIDAddRef(Path->PathID, QUIC_PATHID_REF_PATH); @@ -6189,7 +6194,7 @@ QuicConnRemoveLocalAddress( QUIC_PATH* Path = &Connection->Paths[PathIndex]; - if (!QuicConnIsMultipathEnabled(Connection)) { + if (!Connection->State.MultipathNegotiated) { if (Path->IsActive && Connection->State.Started) { return QUIC_STATUS_INVALID_STATE; } @@ -7497,6 +7502,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; diff --git a/src/core/connection.h b/src/core/connection.h index e6e4854fbd..919de0e45d 100644 --- a/src/core/connection.h +++ b/src/core/connection.h @@ -194,6 +194,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. @@ -690,18 +695,6 @@ QuicConnIsClosed( return Connection->State.ClosedLocally || Connection->State.ClosedRemotely; } -// -// Helper to determine if a connection is multipath enabled -// -inline -BOOLEAN -QuicConnIsMultipathEnabled( - _In_ const QUIC_CONNECTION * const Connection - ) -{ - return Connection->Settings.MultipathEnabled && Connection->PathIDs.Flags.InitialMaxPathRecvd; -} - // // Helper to get the owning QUIC_CONNECTION for the stream set module. // diff --git a/src/core/frame.h b/src/core/frame.h index ed1d878be3..74da77ff55 100644 --- a/src/core/frame.h +++ b/src/core/frame.h @@ -183,7 +183,7 @@ CXPLAT_STATIC_ASSERT( X == QUIC_FRAME_ACK_FREQUENCY || X == QUIC_FRAME_IMMEDIATE_ACK || \ X == QUIC_FRAME_RELIABLE_RESET_STREAM || \ X == QUIC_FRAME_TIMESTAMP || \ - X == QUIC_FRAME_PATH_ACK || \ + (X >= QUIC_FRAME_PATH_ACK && X <= QUIC_FRAME_PATH_ACK_1) || \ X == QUIC_FRAME_PATH_ABANDON || \ X == QUIC_FRAME_PATH_NEW_CONNECTION_ID || \ X == QUIC_FRAME_PATH_RETIRE_CONNECTION_ID || \ diff --git a/src/core/inline.c b/src/core/inline.c index 0aa938fd1c..f26e7d26b1 100644 --- a/src/core/inline.c +++ b/src/core/inline.c @@ -100,11 +100,6 @@ QuicConnIsClient( _In_ const QUIC_CONNECTION * const Connection ); -BOOLEAN -QuicConnIsMultipathEnabled( - _In_ const QUIC_CONNECTION * const Connection - ); - _IRQL_requires_max_(PASSIVE_LEVEL) void QuicConnTransportError( diff --git a/src/core/path.c b/src/core/path.c index b8ebf7886d..68995e9542 100644 --- a/src/core/path.c +++ b/src/core/path.c @@ -311,7 +311,7 @@ QuicConnChoosePath( { QUIC_PATH* Path = &Connection->Paths[0]; - if (QuicConnIsMultipathEnabled(Connection) && Connection->State.HandshakeConfirmed) { + 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) { @@ -346,7 +346,7 @@ QuicPathSetActive( { BOOLEAN UdpPortChangeOnly = FALSE; - if (QuicConnIsMultipathEnabled(Connection)) { + if (Connection->State.MultipathNegotiated) { Path->IsActive = TRUE; } else if (Path == &Connection->Paths[0]) { CXPLAT_DBG_ASSERT(!Path->IsActive); diff --git a/src/core/pathid.c b/src/core/pathid.c index 6d7be98bc4..169b9e9fde 100644 --- a/src/core/pathid.c +++ b/src/core/pathid.c @@ -759,7 +759,7 @@ QuicPathIDWriteNewConnectionIDFrame( ) { QUIC_FRAME_TYPE FrameType = - QuicConnIsMultipathEnabled(PathID->Connection) ? + 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; @@ -834,7 +834,7 @@ QuicPathIDWriteRetireConnectionIDFrame( ) { QUIC_FRAME_TYPE FrameType = - QuicConnIsMultipathEnabled(PathID->Connection) ? + 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; diff --git a/src/core/pathid_set.c b/src/core/pathid_set.c index c6a366893f..6908af4bce 100644 --- a/src/core/pathid_set.c +++ b/src/core/pathid_set.c @@ -320,7 +320,7 @@ QuicPathIDSetGenerateNewSourceCids( _In_ BOOLEAN ReplaceExistingCids ) { - if (QuicConnIsMultipathEnabled(QuicPathIDSetGetConnection(PathIDSet))) { + if (QuicPathIDSetGetConnection(PathIDSet)->State.MultipathNegotiated) { uint16_t NewPathIDCount = 0; if (PathIDSet->CurrentPathIDCount < PathIDSet->MaxCurrentPathIDCount) { NewPathIDCount = PathIDSet->MaxCurrentPathIDCount - PathIDSet->CurrentPathIDCount; @@ -596,7 +596,7 @@ QuicPathIDSetNewLocalPathID( if (NewPathIDBlocked) { if (Connection->State.PeerTransportParameterValid) { - QuicSendSetSendFlag(&Connection->Send, QUIC_CONN_SEND_FLAG_PATHS_BLOCKED); + // QuicSendSetSendFlag(&Connection->Send, QUIC_CONN_SEND_FLAG_PATHS_BLOCKED); } Status = QUIC_STATUS_PATHID_LIMIT_REACHED; goto Exit; From 24d468e804bcfdf3b603720e810d10aa53c2d5dd Mon Sep 17 00:00:00 2001 From: Masahiro Kozuka Date: Fri, 3 Jan 2025 23:07:43 +0900 Subject: [PATCH 17/29] Add support for path status management and new frame types for multipath handling --- src/core/connection.c | 213 ++++++++++++++++++ src/core/frame.c | 136 +++++++++++ src/core/frame.h | 65 +++++- src/core/loss_detection.c | 38 ++++ src/core/path.h | 2 + src/core/pathid.h | 5 + src/core/send.c | 86 +++++++ src/core/send.h | 11 +- src/core/sent_packet_metadata.h | 8 + src/generated/linux/connection.c.clog.h | 36 +++ .../linux/connection.c.clog.h.lttng.h | 38 ++++ src/generated/linux/frame.c.clog.h | 96 ++++++++ src/generated/linux/frame.c.clog.h.lttng.h | 124 ++++++++++ src/inc/msquic.h | 27 +++ src/manifest/clog.sidecar | 150 ++++++++++++ 15 files changed, 1027 insertions(+), 8 deletions(-) diff --git a/src/core/connection.c b/src/core/connection.c index c4c632d980..b75ce57ce3 100644 --- a/src/core/connection.c +++ b/src/core/connection.c @@ -4711,6 +4711,17 @@ QuicConnRecvFrames( 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; } @@ -4788,6 +4799,134 @@ QuicConnRecvFrames( 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)) { @@ -6737,6 +6876,49 @@ QuicConnParamSet( 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 // @@ -7378,6 +7560,37 @@ QuicConnParamGet( 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; diff --git a/src/core/frame.c b/src/core/frame.c index f2cee06bcc..f8196205e8 100644 --- a/src/core/frame.c +++ b/src/core/frame.c @@ -1199,6 +1199,96 @@ QuicPathAbandonFrameDecode( 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( @@ -2124,6 +2214,52 @@ QuicFrameLog( 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)) { diff --git a/src/core/frame.h b/src/core/frame.h index 74da77ff55..9df628ac1a 100644 --- a/src/core/frame.h +++ b/src/core/frame.h @@ -185,8 +185,7 @@ CXPLAT_STATIC_ASSERT( X == QUIC_FRAME_TIMESTAMP || \ (X >= QUIC_FRAME_PATH_ACK && X <= QUIC_FRAME_PATH_ACK_1) || \ X == QUIC_FRAME_PATH_ABANDON || \ - X == QUIC_FRAME_PATH_NEW_CONNECTION_ID || \ - X == QUIC_FRAME_PATH_RETIRE_CONNECTION_ID || \ + (X >= QUIC_FRAME_PATH_BACKUP && X <= QUIC_FRAME_PATH_RETIRE_CONNECTION_ID) || \ X == QUIC_FRAME_MAX_PATH_ID \ ) @@ -807,6 +806,68 @@ QuicPathAbandonFrameDecode( _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 // diff --git a/src/core/loss_detection.c b/src/core/loss_detection.c index 4f6617ad6e..3b48a6f838 100644 --- a/src/core/loss_detection.c +++ b/src/core/loss_detection.c @@ -933,6 +933,44 @@ QuicLossDetectionRetransmitFrames( 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( diff --git a/src/core/path.h b/src/core/path.h index 8bb14b6cd4..f5fd4107a0 100644 --- a/src/core/path.h +++ b/src/core/path.h @@ -101,6 +101,8 @@ typedef struct QUIC_PATH { // BOOLEAN SendResponse : 1; + BOOLEAN SendStatus : 1; + BOOLEAN LocalClose : 1; BOOLEAN LocalCloseAcked : 1; diff --git a/src/core/pathid.h b/src/core/pathid.h index d8bd313005..6d7df55f02 100644 --- a/src/core/pathid.h +++ b/src/core/pathid.h @@ -132,6 +132,11 @@ typedef struct QUIC_PATHID { #if DEBUG short RefTypeCount[QUIC_PATHID_REF_COUNT]; #endif + + uint64_t StatusSendSeq; + + uint64_t StatusRecvSeq; + } QUIC_PATHID; // diff --git a/src/core/send.c b/src/core/send.c index cdd058a6da..e25ce6ac02 100644 --- a/src/core/send.c +++ b/src/core/send.c @@ -679,6 +679,92 @@ QuicSendWriteFrames( } } + 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) { diff --git a/src/core/send.h b/src/core/send.h index 4276194729..900b575ccc 100644 --- a/src/core/send.h +++ b/src/core/send.h @@ -145,12 +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_ACK 0x00040000U -#define QUIC_CONN_SEND_FLAG_PATH_ABANDON 0x00080000U -#define QUIC_CONN_SEND_FLAG_PATH_BACKUP 0x00100000U -#define QUIC_CONN_SEND_FLAG_PATH_AVAILABLE 0x00200000U -#define QUIC_CONN_SEND_FLAG_MAX_PATH_ID 0x00400000U -#define QUIC_CONN_SEND_FLAG_PATHS_BLOCKED 0x00800000U +#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 // diff --git a/src/core/sent_packet_metadata.h b/src/core/sent_packet_metadata.h index 5051c0c651..23fad5aa27 100644 --- a/src/core/sent_packet_metadata.h +++ b/src/core/sent_packet_metadata.h @@ -63,6 +63,14 @@ typedef struct QUIC_SENT_FRAME_METADATA { 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; diff --git a/src/generated/linux/connection.c.clog.h b/src/generated/linux/connection.c.clog.h index b3fdc839df..2f80f91e95 100644 --- a/src/generated/linux/connection.c.clog.h +++ b/src/generated/linux/connection.c.clog.h @@ -1288,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 diff --git a/src/generated/linux/connection.c.clog.h.lttng.h b/src/generated/linux/connection.c.clog.h.lttng.h index 5b7c3d53ff..b671703563 100644 --- a/src/generated/linux/connection.c.clog.h.lttng.h +++ b/src/generated/linux/connection.c.clog.h.lttng.h @@ -1427,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 diff --git a/src/generated/linux/frame.c.clog.h b/src/generated/linux/frame.c.clog.h index 6ddec4986f..b48691c676 100644 --- a/src/generated/linux/frame.c.clog.h +++ b/src/generated/linux/frame.c.clog.h @@ -1209,6 +1209,102 @@ tracepoint(CLOG_FRAME_C, FrameLogPathAbandon , arg2, arg3, arg4, arg5, 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 +----------------------------------------------------------*/ +#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] diff --git a/src/generated/linux/frame.c.clog.h.lttng.h b/src/generated/linux/frame.c.clog.h.lttng.h index 90632ef4f8..eb3261afa9 100644 --- a/src/generated/linux/frame.c.clog.h.lttng.h +++ b/src/generated/linux/frame.c.clog.h.lttng.h @@ -1536,6 +1536,130 @@ TRACEPOINT_EVENT(CLOG_FRAME_C, FrameLogPathAbandon, +/*---------------------------------------------------------- +// 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] diff --git a/src/inc/msquic.h b/src/inc/msquic.h index aaddc8c4f7..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 { @@ -927,6 +934,7 @@ typedef struct QUIC_SCHANNEL_CREDENTIAL_ATTRIBUTE_W { #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 // @@ -1185,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; @@ -1275,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/manifest/clog.sidecar b/src/manifest/clog.sidecar index e2197c645d..7eb9118ac0 100644 --- a/src/manifest/clog.sidecar +++ b/src/manifest/clog.sidecar @@ -5248,6 +5248,102 @@ ], "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]", @@ -6244,6 +6340,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", @@ -15453,6 +15573,26 @@ "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", @@ -15688,6 +15828,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", From c1dd089fc20dd7fc24b25647615faeb7e3d12742 Mon Sep 17 00:00:00 2001 From: Masahiro Kozuka Date: Sat, 4 Jan 2025 22:45:12 +0900 Subject: [PATCH 18/29] Implement Debug trait for Addr and add new connection event structures for path management --- src/lib.rs | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 9a5e00b1d3..5dfe775537 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; @@ -969,6 +980,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 +1114,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 +1188,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)] From 8f9accaf22e71a637ad0564739d7ea1cd989874d Mon Sep 17 00:00:00 2001 From: Masahiro Kozuka Date: Sat, 4 Jan 2025 23:11:19 +0900 Subject: [PATCH 19/29] Add VersionSettings and PathStatus structures for preview API support --- src/lib.rs | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 5dfe775537..a9da4c664f 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -790,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)] @@ -893,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; From 62d3d9b266b6ecaadd6aba2fcbf30520fb788b01 Mon Sep 17 00:00:00 2001 From: Masahiro Kozuka Date: Sat, 4 Jan 2025 23:27:49 +0900 Subject: [PATCH 20/29] Add set_multipath_enabled method to Settings for preview API support --- src/lib.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index a9da4c664f..9fd0f0d9d3 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -1590,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 { From e0691f333fb20f89951cb2fc86c9cd3cee8c6c53 Mon Sep 17 00:00:00 2001 From: Masahiro Kozuka Date: Thu, 9 Jan 2025 16:27:25 +0900 Subject: [PATCH 21/29] Refactoring --- src/core/binding.c | 35 +++++++----------- src/core/binding.h | 1 + src/core/cid.h | 5 +-- src/core/connection.c | 33 +++++++++-------- src/core/library.h | 1 - src/core/lookup.c | 83 ++++++++++++++++++++++--------------------- src/core/lookup.h | 1 + 7 files changed, 77 insertions(+), 82 deletions(-) diff --git a/src/core/binding.c b/src/core/binding.c index 24a5c641b3..c873096d7a 100644 --- a/src/core/binding.c +++ b/src/core/binding.c @@ -560,10 +560,11 @@ _IRQL_requires_max_(DISPATCH_LEVEL) BOOLEAN QuicBindingAddSourceConnectionID( _In_ QUIC_BINDING* Binding, + _In_ QUIC_CONNECTION* Connection, _In_ QUIC_CID_SLIST_ENTRY* SourceCid ) { - return QuicLookupAddLocalCid(&Binding->Lookup, SourceCid, NULL); + return QuicLookupAddLocalCid(&Binding->Lookup, Connection, SourceCid, NULL); } _IRQL_requires_max_(DISPATCH_LEVEL) @@ -582,7 +583,7 @@ QuicBindingAddAllSourceConnectionIDs( Link, QUIC_CID_SLIST_ENTRY, Link); - if (!QuicBindingAddSourceConnectionID(Binding, Entry)) { + if (!QuicBindingAddSourceConnectionID(Binding, Connection, Entry)) { return FALSE; } } @@ -607,8 +608,6 @@ QuicBindingRemoveAllSourceConnectionIDs( _In_ QUIC_CONNECTION* Connection ) { - CXPLAT_SLIST_ENTRY EntriesToFree = {0}; - for (CXPLAT_SLIST_ENTRY* Link = Connection->SourceCids.Next; Link != NULL; Link = Link->Next) { @@ -619,31 +618,23 @@ QuicBindingRemoveAllSourceConnectionIDs( QUIC_CID_SLIST_ENTRY, Link); - CXPLAT_SLIST_ENTRY** Link1 = &Entry->HashEntries.Next; - while (*Link1 != NULL) { - QUIC_CID_HASH_ENTRY* Entry1 = + CXPLAT_SLIST_ENTRY** HashLink = &Entry->HashEntries.Next; + while (*HashLink != NULL) { + QUIC_CID_HASH_ENTRY* HashEntry = CXPLAT_CONTAINING_RECORD( - *Link1, + *HashLink, QUIC_CID_HASH_ENTRY, Link); - if (Entry1->Binding == Binding) { - QuicBindingRemoveSourceConnectionID(Binding, Entry1); - *Link1 = (*Link1)->Next; - CxPlatListPushEntry(&EntriesToFree, &Entry1->Link); + if (HashEntry->Binding == Binding) { + QuicBindingRemoveSourceConnectionID(Binding, HashEntry); + *HashLink = (*HashLink)->Next; + CXPLAT_FREE(HashEntry, QUIC_POOL_CIDHASH); + HashEntry = NULL; } else { - Link1 = &(*Link1)->Next; + HashLink = &(*HashLink)->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); - } } _IRQL_requires_max_(DISPATCH_LEVEL) diff --git a/src/core/binding.h b/src/core/binding.h index 795ab815e1..2e5f8847d4 100644 --- a/src/core/binding.h +++ b/src/core/binding.h @@ -373,6 +373,7 @@ _IRQL_requires_max_(DISPATCH_LEVEL) BOOLEAN QuicBindingAddSourceConnectionID( _In_ QUIC_BINDING* Binding, + _In_ QUIC_CONNECTION* Connection, _In_ QUIC_CID_SLIST_ENTRY* SourceCid ); diff --git a/src/core/cid.h b/src/core/cid.h index b5fcc47ee9..2dcf66e057 100644 --- a/src/core/cid.h +++ b/src/core/cid.h @@ -166,7 +166,6 @@ typedef struct QUIC_CID_LIST_ENTRY { typedef struct QUIC_CID_SLIST_ENTRY { CXPLAT_SLIST_ENTRY Link; - QUIC_CONNECTION* Connection; CXPLAT_SLIST_ENTRY HashEntries; QUIC_CID CID; @@ -178,7 +177,7 @@ typedef struct QUIC_CID_HASH_ENTRY { CXPLAT_SLIST_ENTRY Link; QUIC_CONNECTION* Connection; QUIC_BINDING* Binding; - QUIC_CID_SLIST_ENTRY* CID; + QUIC_CID_SLIST_ENTRY* Parent; } QUIC_CID_HASH_ENTRY; @@ -199,7 +198,6 @@ QuicCidNewNullSource( QUIC_POOL_CIDSLIST); if (Entry != NULL) { - Entry->Connection = Connection; Entry->HashEntries.Next = NULL; CxPlatZeroMemory(&Entry->CID, sizeof(Entry->CID)); } @@ -228,7 +226,6 @@ QuicCidNewSource( QUIC_POOL_CIDSLIST); if (Entry != NULL) { - Entry->Connection = Connection; Entry->HashEntries.Next = NULL; CxPlatZeroMemory(&Entry->CID, sizeof(Entry->CID)); Entry->CID.Length = Length; diff --git a/src/core/connection.c b/src/core/connection.c index 69274396e6..d19884065d 100644 --- a/src/core/connection.c +++ b/src/core/connection.c @@ -890,7 +890,7 @@ QuicConnGenerateNewSourceCid( BOOLEAN Collision = FALSE; int8_t Revert = -1; for (uint8_t i = 0; i < BindingsCount; ++i) { - if (!QuicBindingAddSourceConnectionID(Bindings[i], SourceCid)) { + if (!QuicBindingAddSourceConnectionID(Bindings[i], Connection, SourceCid)) { Collision = TRUE; if (i > 0) { Revert = i - 1; @@ -2004,7 +2004,7 @@ QuicConnStart( CASTED_CLOG_BYTEARRAY(SourceCid->CID.Length, SourceCid->CID.Data)); CxPlatListPushEntry(&Connection->SourceCids, &SourceCid->Link); - if (!QuicBindingAddSourceConnectionID(Path->Binding, SourceCid)) { + if (!QuicBindingAddSourceConnectionID(Path->Binding, Connection, SourceCid)) { QuicLibraryReleaseBinding(Path->Binding); Path->Binding = NULL; Status = QUIC_STATUS_OUT_OF_MEMORY; @@ -6351,7 +6351,7 @@ QuicConnOpenNewPath( CASTED_CLOG_BYTEARRAY(SourceCid->CID.Length, SourceCid->CID.Data)); CxPlatListPushEntry(&Connection->SourceCids, &SourceCid->Link); - if (!QuicBindingAddSourceConnectionID(NewBinding, SourceCid)) { + if (!QuicBindingAddSourceConnectionID(NewBinding, Connection, SourceCid)) { return QUIC_STATUS_OUT_OF_MEMORY; } } else { @@ -6366,7 +6366,6 @@ QuicConnOpenNewPath( Connection, CASTED_CLOG_BYTEARRAY(sizeof(Path->Route.LocalAddress), &Path->Route.LocalAddress)); - QUIC_CID_LIST_ENTRY* NewDestCid = QuicConnGetUnusedDestCid(Connection); // // If we can't get a unused CID, we defer sending a path challange until we receieve a new CID. @@ -6432,10 +6431,6 @@ QuicConnAddLocalAddress( 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) { @@ -6516,10 +6511,6 @@ QuicConnRemoveLocalAddress( return QUIC_STATUS_INVALID_STATE; } - if (!QuicAddrIsValid(LocalAddress)) { - return QUIC_STATUS_INVALID_PARAMETER; - } - if (!Connection->State.LocalAddressSet) { return QUIC_STATUS_NOT_FOUND; } @@ -7062,7 +7053,14 @@ QuicConnParamSet( break; } - Status = QuicConnAddLocalAddress(Connection, (QUIC_ADDR*)Buffer); + QUIC_ADDR* LocalAddress = (QUIC_ADDR*)Buffer; + + if (!QuicAddrIsValid(LocalAddress)) { + Status = QUIC_STATUS_INVALID_PARAMETER; + break; + } + + Status = QuicConnAddLocalAddress(Connection, LocalAddress); break; } @@ -7073,7 +7071,14 @@ QuicConnParamSet( break; } - Status = QuicConnRemoveLocalAddress(Connection, (QUIC_ADDR*)Buffer); + QUIC_ADDR* LocalAddress = (QUIC_ADDR*)Buffer; + + if (!QuicAddrIsValid(LocalAddress)) { + Status = QUIC_STATUS_INVALID_PARAMETER; + break; + } + + Status = QuicConnRemoveLocalAddress(Connection, LocalAddress); break; } diff --git a/src/core/library.h b/src/core/library.h index c911b26f1a..80c21da2b2 100644 --- a/src/core/library.h +++ b/src/core/library.h @@ -474,7 +474,6 @@ QuicCidNewRandomSource( QUIC_POOL_CIDSLIST); if (Entry != NULL) { - Entry->Connection = Connection; Entry->HashEntries.Next = NULL; CxPlatZeroMemory(&Entry->CID, sizeof(Entry->CID)); Entry->CID.Length = MsQuicLib.CidTotalLength; diff --git a/src/core/lookup.c b/src/core/lookup.c index e4ccb0a4d1..21de48ed53 100644 --- a/src/core/lookup.c +++ b/src/core/lookup.c @@ -175,32 +175,32 @@ QuicLookupRebalance( // if (PreviousLookup != NULL) { - CXPLAT_SLIST_ENTRY* Entry = + CXPLAT_SLIST_ENTRY* Link = ((QUIC_CONNECTION*)PreviousLookup)->SourceCids.Next; - while (Entry != NULL) { - QUIC_CID_SLIST_ENTRY *CID = + while (Link != NULL) { + QUIC_CID_SLIST_ENTRY* Entry = CXPLAT_CONTAINING_RECORD( - Entry, + Link, QUIC_CID_SLIST_ENTRY, Link); - CXPLAT_SLIST_ENTRY* Entry1 = CID->HashEntries.Next; - while (Entry1 != NULL) { - QUIC_CID_HASH_ENTRY *CID1 = + CXPLAT_SLIST_ENTRY* HashLink = Entry->HashEntries.Next; + while (HashLink != NULL) { + QUIC_CID_HASH_ENTRY *HashEntry = CXPLAT_CONTAINING_RECORD( - Entry1, + HashLink, QUIC_CID_HASH_ENTRY, Link); - if (CID1->Binding == QuicLookupGetBinding(Lookup)) { + if (HashEntry->Binding == QuicLookupGetBinding(Lookup)) { (void)QuicLookupInsertLocalCid( Lookup, - CxPlatHashSimple(CID->CID.Length, CID->CID.Data), - CID1, + CxPlatHashSimple(Entry->CID.Length, Entry->CID.Data), + HashEntry, FALSE); } - Entry1 = Entry1->Next; + HashLink = HashLink->Next; } - Entry = Entry->Next; + Link = Link->Next; } } @@ -227,15 +227,15 @@ QuicLookupRebalance( } CxPlatHashtableRemove(&PreviousTable[i].Table, Entry, NULL); - QUIC_CID_HASH_ENTRY* CID = + QUIC_CID_HASH_ENTRY* HashEntry = CXPLAT_CONTAINING_RECORD( Entry, QUIC_CID_HASH_ENTRY, Entry); (void)QuicLookupInsertLocalCid( Lookup, - CxPlatHashSimple(CID->CID->CID.Length, CID->CID->CID.Data), - CID, + CxPlatHashSimple(HashEntry->Parent->CID.Length, HashEntry->Parent->CID.Data), + HashEntry, FALSE); } #pragma warning(push) @@ -301,19 +301,19 @@ QuicCidMatchConnection( 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) { + for (CXPLAT_SLIST_ENTRY* HashLink = Entry->HashEntries.Next; + HashLink != NULL; + HashLink = HashLink->Next) { - const QUIC_CID_HASH_ENTRY* const Entry1 = - CXPLAT_CONTAINING_RECORD(Link1, const QUIC_CID_HASH_ENTRY, Link); + const QUIC_CID_HASH_ENTRY* const HashEntry = + CXPLAT_CONTAINING_RECORD(HashLink, const QUIC_CID_HASH_ENTRY, Link); - if (Entry1->Binding != QuicLookupGetBinding(Lookup)) { + if (HashEntry->Binding != QuicLookupGetBinding(Lookup)) { continue; } - if (Length == Entry1->CID->CID.Length && - (Length == 0 || memcmp(DestCid, Entry1->CID->CID.Data, Length) == 0)) { + if (Length == HashEntry->Parent->CID.Length && + (Length == 0 || memcmp(DestCid, HashEntry->Parent->CID.Data, Length) == 0)) { return TRUE; } } @@ -341,12 +341,12 @@ QuicHashLookupConnection( CxPlatHashtableLookup(Table, Hash, &Context); while (TableEntry != NULL) { - QUIC_CID_HASH_ENTRY* CIDEntry = + QUIC_CID_HASH_ENTRY* HashEntry = CXPLAT_CONTAINING_RECORD(TableEntry, QUIC_CID_HASH_ENTRY, Entry); - if (CIDEntry->CID->CID.Length == Length && - memcmp(DestCid, CIDEntry->CID->CID.Data, Length) == 0) { - return CIDEntry->Connection; + if (HashEntry->Parent->CID.Length == Length && + memcmp(DestCid, HashEntry->Parent->CID.Data, Length) == 0) { + return HashEntry->Connection; } TableEntry = CxPlatHashtableLookupNext(Table, &Context); @@ -499,14 +499,14 @@ QuicLookupInsertLocalCid( } } else { - CXPLAT_DBG_ASSERT(SourceCid->CID->CID.Length >= MsQuicLib.CidServerIdLength + QUIC_CID_PID_LENGTH); + CXPLAT_DBG_ASSERT(SourceCid->Parent->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->CID.Data + MsQuicLib.CidServerIdLength, 2); + CxPlatCopyMemory(&PartitionIndex, SourceCid->Parent->CID.Data + MsQuicLib.CidServerIdLength, 2); PartitionIndex &= MsQuicLib.PartitionMask; PartitionIndex %= Lookup->PartitionCount; QUIC_PARTITIONED_HASHTABLE* Table = &Lookup->HASH.Tables[PartitionIndex]; @@ -606,7 +606,7 @@ QuicLookupRemoveLocalCidInt( _In_ QUIC_CID_HASH_ENTRY* SourceCid ) { - CXPLAT_DBG_ASSERT(SourceCid->CID != NULL); + CXPLAT_DBG_ASSERT(SourceCid->Parent != NULL); CXPLAT_DBG_ASSERT(Lookup->CidCount != 0); Lookup->CidCount--; @@ -628,14 +628,14 @@ QuicLookupRemoveLocalCidInt( Lookup->SINGLE.Connection = NULL; } } else { - CXPLAT_DBG_ASSERT(SourceCid->CID->CID.Length >= MsQuicLib.CidServerIdLength + QUIC_CID_PID_LENGTH); + CXPLAT_DBG_ASSERT(SourceCid->Parent->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->CID.Data + MsQuicLib.CidServerIdLength, 2); + CxPlatCopyMemory(&PartitionIndex, SourceCid->Parent->CID.Data + MsQuicLib.CidServerIdLength, 2); PartitionIndex &= MsQuicLib.PartitionMask; PartitionIndex %= Lookup->PartitionCount; QUIC_PARTITIONED_HASHTABLE* Table = &Lookup->HASH.Tables[PartitionIndex]; @@ -748,6 +748,7 @@ _IRQL_requires_max_(DISPATCH_LEVEL) BOOLEAN QuicLookupAddLocalCid( _In_ QUIC_LOOKUP* Lookup, + _In_ QUIC_CONNECTION* Connection, _In_ QUIC_CID_SLIST_ENTRY* SourceCid, _Out_opt_ QUIC_CONNECTION** Collision ) @@ -768,20 +769,20 @@ QuicLookupAddLocalCid( Hash); if (ExistingConnection == NULL) { - QUIC_CID_HASH_ENTRY* CID = + QUIC_CID_HASH_ENTRY* HashEntry = (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->Connection = SourceCid->Connection; + if (HashEntry != NULL) { + HashEntry->Parent = SourceCid; + HashEntry->Binding = QuicLookupGetBinding(Lookup); + HashEntry->Connection = Connection; Result = - QuicLookupInsertLocalCid(Lookup, Hash, CID, TRUE); + QuicLookupInsertLocalCid(Lookup, Hash, HashEntry, TRUE); if (Result) { - CxPlatListPushEntry(&SourceCid->HashEntries, &CID->Link); + CxPlatListPushEntry(&SourceCid->HashEntries, &HashEntry->Link); } else { - CXPLAT_FREE(CID, QUIC_POOL_CIDHASH); + CXPLAT_FREE(HashEntry, QUIC_POOL_CIDHASH); } } else { Result = FALSE; diff --git a/src/core/lookup.h b/src/core/lookup.h index 6440992fb4..598733180a 100644 --- a/src/core/lookup.h +++ b/src/core/lookup.h @@ -141,6 +141,7 @@ _IRQL_requires_max_(DISPATCH_LEVEL) BOOLEAN QuicLookupAddLocalCid( _In_ QUIC_LOOKUP* Lookup, + _In_ QUIC_CONNECTION* Connection, _In_ QUIC_CID_SLIST_ENTRY* SourceCid, _Out_opt_ QUIC_CONNECTION** Collision ); From 1cd0b789fe8e8f2f67e3ecedaa438e4139c9c44e Mon Sep 17 00:00:00 2001 From: Masahiro Kozuka Date: Thu, 9 Jan 2025 17:44:21 +0900 Subject: [PATCH 22/29] Enhance UdpPortChangeOnly condition for server connections in QuicPathSetActive --- src/core/path.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/path.c b/src/core/path.c index 842030a2a9..5fa8242540 100644 --- a/src/core/path.c +++ b/src/core/path.c @@ -300,6 +300,7 @@ QuicPathSetActive( } else { CXPLAT_DBG_ASSERT(Path->DestCid != NULL); UdpPortChangeOnly = + QuicConnIsServer(Connection) && QuicAddrGetFamily(&Path->Route.RemoteAddress) == QuicAddrGetFamily(&Connection->Paths[0].Route.RemoteAddress) && QuicAddrCompareIp(&Path->Route.RemoteAddress, &Connection->Paths[0].Route.RemoteAddress); From 64a35a7477b5eda957b0243aecdea2c005402155 Mon Sep 17 00:00:00 2001 From: Masahiro Kozuka Date: Fri, 10 Jan 2025 10:37:20 +0900 Subject: [PATCH 23/29] Refactor migration test to use QUIC_MIGRATION_TYPE and improve path management logic --- src/core/connection.c | 67 +++++++++-- src/core/path.c | 9 +- src/test/MsQuicTests.h | 10 +- src/test/bin/quic_gtest.cpp | 4 +- src/test/bin/quic_gtest.h | 8 +- src/test/bin/winkernel/control.cpp | 2 +- src/test/lib/ApiTest.cpp | 182 ++++++++++++++++++++++++++++- src/test/lib/PathTest.cpp | 25 ++-- 8 files changed, 279 insertions(+), 28 deletions(-) diff --git a/src/core/connection.c b/src/core/connection.c index d19884065d..4dcca44c66 100644 --- a/src/core/connection.c +++ b/src/core/connection.c @@ -6531,11 +6531,8 @@ QuicConnRemoveLocalAddress( QUIC_PATH* Path = &Connection->Paths[PathIndex]; - if (Path->IsActive && Connection->State.Started) { - return QUIC_STATUS_INVALID_STATE; - } - - if (Path->DestCid != NULL) { + if (Path->DestCid != NULL && + Connection->State.Started && Connection->State.HandshakeConfirmed) { QuicConnRetireCid(Connection, Path->DestCid); } @@ -6546,9 +6543,65 @@ QuicConnRemoveLocalAddress( } if (Connection->PathsCount == 1) { - CXPLAT_DBG_ASSERT(!Connection->State.Started); - Connection->State.LocalAddressSet = FALSE; + if (!Connection->State.Started) { + Connection->State.LocalAddressSet = FALSE; + } else { + QuicTraceEvent( + ConnError, + "[conn][%p] ERROR, %s.", + Connection, + "Last Local Address Removed!"); + QuicConnSilentlyAbort(Connection); + return QUIC_STATUS_ABORTED; + } } else { + if (Path->IsActive) { + CXPLAT_DBG_ASSERT(PathIndex == 0); + if (!Connection->State.Started) { + CXPLAT_DBG_ASSERT(Path->DestCid != NULL); + CXPLAT_DBG_ASSERT(!Path->DestCid->CID.Retired); +#if DEBUG + QUIC_CID_CLEAR_PATH(Path->DestCid); +#endif + // Move the dest CID to the new active path. + QUIC_CID_LIST_ENTRY* DestCid = Path->DestCid; + Path->DestCid = NULL; + QUIC_PATH* NewActivePath = &Connection->Paths[1]; + NewActivePath->DestCid = DestCid; + QUIC_CID_SET_PATH(Connection, NewActivePath->DestCid, NewActivePath); + + QuicPathSetActive(Connection, NewActivePath); + PathIndex = 1; // The removing path is now at index 1. + } else if (!Connection->State.HandshakeConfirmed) { + QuicTraceEvent( + ConnError, + "[conn][%p] ERROR, %s.", + Connection, + "Active Local Address Removed during Handshake!"); + QuicConnSilentlyAbort(Connection); + return QUIC_STATUS_ABORTED; + } else { + uint8_t NewActivePathIndex = Connection->PathsCount; + for (uint8_t i = 0; i < Connection->PathsCount; ++i) { + if (i != PathIndex && Connection->Paths[i].DestCid != NULL) { + NewActivePathIndex = i; + break; + } + } + if (NewActivePathIndex == Connection->PathsCount) { + QuicTraceEvent( + ConnError, + "[conn][%p] ERROR, %s.", + Connection, + "No Active Local Address Remaining!"); + QuicConnSilentlyAbort(Connection); + return QUIC_STATUS_ABORTED; + } + QUIC_PATH* NewActivePath = &Connection->Paths[NewActivePathIndex]; + QuicPathSetActive(Connection, NewActivePath); + PathIndex = NewActivePathIndex; // The removing path is now at the new active index. + } + } QuicPathRemove(Connection, PathIndex); } diff --git a/src/core/path.c b/src/core/path.c index 5fa8242540..58ff940b18 100644 --- a/src/core/path.c +++ b/src/core/path.c @@ -231,6 +231,11 @@ QuicConnGetPathForPacket( return &Connection->Paths[i]; } + if (!QuicConnIsServer(Connection)) { + // Client doesn't create a new path. + return NULL; + } + if (Connection->PathsCount == QUIC_MAX_PATH_COUNT) { // // See if any old paths share the same remote address, and is just a rebind. @@ -329,8 +334,8 @@ QuicPathSetActive( if (!UdpPortChangeOnly) { QuicCongestionControlReset(&Connection->CongestionControl, FALSE); } - CXPLAT_DBG_ASSERT(Path->DestCid != NULL); - CXPLAT_DBG_ASSERT(!Path->DestCid->CID.Retired); + CXPLAT_DBG_ASSERT(Connection->Paths[0].DestCid != NULL); + CXPLAT_DBG_ASSERT(!Connection->Paths[0].DestCid->CID.Retired); } _IRQL_requires_max_(PASSIVE_LEVEL) diff --git a/src/test/MsQuicTests.h b/src/test/MsQuicTests.h index 2db058f241..e24c68fa6b 100644 --- a/src/test/MsQuicTests.h +++ b/src/test/MsQuicTests.h @@ -372,11 +372,17 @@ QuicTestProbePath( _In_ uint32_t DropPacketCount ); +typedef enum QUIC_MIGRATION_TYPE { + MigrateWithProbe, + MigrateWithoutProbe, + DeleteAndMigrate, +} QUIC_MIGRATION_TYPE; + void QuicTestMigration( _In_ int Family, _In_ BOOLEAN ShareBinding, - _In_ BOOLEAN PathProbe + _In_ QUIC_MIGRATION_TYPE Type ); void @@ -1368,7 +1374,7 @@ typedef struct { typedef struct { int Family; BOOLEAN ShareBinding; - BOOLEAN Smooth; + QUIC_MIGRATION_TYPE Type; } QUIC_RUN_MIGRATION_PARAMS; #define IOCTL_QUIC_RUN_MIGRATION \ diff --git a/src/test/bin/quic_gtest.cpp b/src/test/bin/quic_gtest.cpp index 4afd543d4c..7aba769c22 100644 --- a/src/test/bin/quic_gtest.cpp +++ b/src/test/bin/quic_gtest.cpp @@ -1692,11 +1692,11 @@ TEST_P(WithMigrationArgs, Migration) { QUIC_RUN_MIGRATION_PARAMS Params = { GetParam().Family, GetParam().ShareBinding, - GetParam().Smooth + GetParam().Type }; ASSERT_TRUE(DriverClient.Run(IOCTL_QUIC_RUN_MIGRATION, Params)); } else { - QuicTestMigration(GetParam().Family, GetParam().ShareBinding, GetParam().Smooth); + QuicTestMigration(GetParam().Family, GetParam().ShareBinding, GetParam().Type); } } diff --git a/src/test/bin/quic_gtest.h b/src/test/bin/quic_gtest.h index 469670f821..ced759f682 100644 --- a/src/test/bin/quic_gtest.h +++ b/src/test/bin/quic_gtest.h @@ -961,13 +961,13 @@ class WithProbePathArgs : public testing::Test, struct MigrationArgs { int Family; BOOLEAN ShareBinding; - BOOLEAN Smooth; + QUIC_MIGRATION_TYPE Type; 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 }); + for (QUIC_MIGRATION_TYPE Type : { MigrateWithProbe, MigrateWithoutProbe, DeleteAndMigrate }) + list.push_back({ Family, ShareBinding, Type }); return list; } }; @@ -975,7 +975,7 @@ struct MigrationArgs { 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"); + << (args.Type ? (args.Type == MigrateWithoutProbe ? "Migrate without Probe" : "Delete and Migrate") : "Migrate with Probe"); } class WithMigrationArgs : public testing::Test, diff --git a/src/test/bin/winkernel/control.cpp b/src/test/bin/winkernel/control.cpp index 613b5b6465..22ffcd3c12 100644 --- a/src/test/bin/winkernel/control.cpp +++ b/src/test/bin/winkernel/control.cpp @@ -975,7 +975,7 @@ QuicTestCtlEvtIoDeviceControl( QuicTestMigration( Params->MigrationParams.Family, Params->MigrationParams.ShareBinding, - Params->MigrationParams.Smooth)); + Params->MigrationParams.Type)); break; case IOCTL_QUIC_RUN_NAT_PORT_REBIND: diff --git a/src/test/lib/ApiTest.cpp b/src/test/lib/ApiTest.cpp index 19a0543f4f..9a68c48f9a 100644 --- a/src/test/lib/ApiTest.cpp +++ b/src/test/lib/ApiTest.cpp @@ -4594,12 +4594,14 @@ void QuicTest_QUIC_PARAM_CONN_ADD_LOCAL_ADDRESS(MsQuicRegistration& Registration 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( @@ -4627,6 +4629,36 @@ void QuicTest_QUIC_PARAM_CONN_ADD_LOCAL_ADDRESS(MsQuicRegistration& Registration &ClientAddr)); } } + + // + // Too many local addresses + // + { + TestScopeLogger LogScope2("Too many local addresses"); + MsQuicConnection Connection(Registration); + TEST_QUIC_SUCCEEDED(Connection.GetInitStatus()); + uint16_t Port = 4433; + + for (uint8_t i = 0; i < 5; i++) { + QUIC_ADDR ClientAddr; + QuicAddrFromString("127.0.0.1", Port++, &ClientAddr); + if (i < 4) { + TEST_QUIC_SUCCEEDED( + Connection.SetParam( + QUIC_PARAM_CONN_ADD_LOCAL_ADDRESS, + sizeof(ClientAddr), + &ClientAddr)); + } else { + TEST_QUIC_STATUS( + QUIC_STATUS_OUT_OF_MEMORY, + Connection.SetParam( + QUIC_PARAM_CONN_ADD_LOCAL_ADDRESS, + sizeof(ClientAddr), + &ClientAddr)); + } + } + } + } } @@ -4656,6 +4688,28 @@ void QuicTest_QUIC_PARAM_CONN_REMOVE_LOCAL_ADDRESS(MsQuicRegistration& Registrat &Dummy)); } + // + // Set and remove a local address + // + { + TestScopeLogger LogScope2("Set and remove a local address"); + MsQuicConnection Connection(Registration); + TEST_QUIC_SUCCEEDED(Connection.GetInitStatus()); + + QUIC_ADDR Dummy = {}; + TEST_QUIC_SUCCEEDED( + Connection.SetParam( + QUIC_PARAM_CONN_LOCAL_ADDRESS, + sizeof(Dummy), + &Dummy)); + + TEST_QUIC_SUCCEEDED( + Connection.SetParam( + QUIC_PARAM_CONN_REMOVE_LOCAL_ADDRESS, + sizeof(Dummy), + &Dummy)); + } + // // Add and remove a local address // @@ -4663,6 +4717,7 @@ void QuicTest_QUIC_PARAM_CONN_REMOVE_LOCAL_ADDRESS(MsQuicRegistration& Registrat TestScopeLogger LogScope2("Add and remove a local address"); MsQuicConnection Connection(Registration); TEST_QUIC_SUCCEEDED(Connection.GetInitStatus()); + QUIC_ADDR Dummy = {}; TEST_QUIC_SUCCEEDED( Connection.SetParam( @@ -4678,10 +4733,62 @@ void QuicTest_QUIC_PARAM_CONN_REMOVE_LOCAL_ADDRESS(MsQuicRegistration& Registrat } // - // Remove a local address that belongs to another the active path + // Add two local addresses and remove the first local address // { - TestScopeLogger LogScope2("Remove a local address that belongs to another the active path"); + TestScopeLogger LogScope2("Add two local addresses and remove the first local address"); + MsQuicConnection Connection(Registration); + TEST_QUIC_SUCCEEDED(Connection.GetInitStatus()); + + uint16_t Port = 4433; + QUIC_ADDR ClientAddr[2]; + for (uint8_t i = 0; i < 2; i++) { + QuicAddrFromString("127.0.0.1", Port++, &ClientAddr[i]); + TEST_QUIC_SUCCEEDED( + Connection.SetParam( + QUIC_PARAM_CONN_ADD_LOCAL_ADDRESS, + sizeof(ClientAddr[i]), + &ClientAddr[i])); + } + + TEST_QUIC_SUCCEEDED( + Connection.SetParam( + QUIC_PARAM_CONN_REMOVE_LOCAL_ADDRESS, + sizeof(ClientAddr[0]), + &ClientAddr[0])); + } + + // + // Add two local addresses and remove the second local address + // + { + TestScopeLogger LogScope2("Add two local addresses and remove the second local address"); + MsQuicConnection Connection(Registration); + TEST_QUIC_SUCCEEDED(Connection.GetInitStatus()); + + uint16_t Port = 4433; + QUIC_ADDR ClientAddr[2]; + for (uint8_t i = 0; i < 2; i++) { + QuicAddrFromString("127.0.0.1", Port++, &ClientAddr[i]); + TEST_QUIC_SUCCEEDED( + Connection.SetParam( + QUIC_PARAM_CONN_ADD_LOCAL_ADDRESS, + sizeof(ClientAddr[i]), + &ClientAddr[i])); + } + + TEST_QUIC_SUCCEEDED( + Connection.SetParam( + QUIC_PARAM_CONN_REMOVE_LOCAL_ADDRESS, + sizeof(ClientAddr[1]), + &ClientAddr[0])); + } + + // + // Remove a local address that belongs to the active path dusring handshake + // + { + TestScopeLogger LogScope2("Remove the last one local address after start"); MsQuicConnection Connection(Registration); TEST_QUIC_SUCCEEDED(Connection.GetInitStatus()); TEST_QUIC_SUCCEEDED( @@ -4694,13 +4801,82 @@ void QuicTest_QUIC_PARAM_CONN_REMOVE_LOCAL_ADDRESS(MsQuicRegistration& Registrat QuicAddr ClientLocalAddr; TEST_QUIC_SUCCEEDED(Connection.GetLocalAddr(ClientLocalAddr)); + TEST_QUIC_STATUS( - QUIC_STATUS_INVALID_STATE, + QUIC_STATUS_ABORTED, + Connection.SetParam( + QUIC_PARAM_CONN_REMOVE_LOCAL_ADDRESS, + sizeof(ClientLocalAddr.SockAddr), + &ClientLocalAddr.SockAddr)); + } + + // + // Remove a local address that belongs to the active path dusring handshake + // + { + TestScopeLogger LogScope2("Remove a local address that belongs to the active path during handshake"); + MsQuicConnection Connection(Registration); + TEST_QUIC_SUCCEEDED(Connection.GetInitStatus()); + TEST_QUIC_SUCCEEDED( + MsQuic->ConnectionStart( + Connection.Handle, + ClientConfiguration, + QUIC_ADDRESS_FAMILY_INET, + "localhost", + 4433)); + + QuicAddr SecondLocalAddr; + TEST_QUIC_SUCCEEDED(Connection.GetLocalAddr(SecondLocalAddr)); + SecondLocalAddr.IncrementPort(); + + TEST_QUIC_SUCCEEDED( + Connection.SetParam( + QUIC_PARAM_CONN_ADD_LOCAL_ADDRESS, + sizeof(SecondLocalAddr.SockAddr), + &SecondLocalAddr.SockAddr)); + + QuicAddr ClientLocalAddr; + TEST_QUIC_SUCCEEDED(Connection.GetLocalAddr(ClientLocalAddr)); + + TEST_QUIC_STATUS( + QUIC_STATUS_ABORTED, Connection.SetParam( QUIC_PARAM_CONN_REMOVE_LOCAL_ADDRESS, sizeof(ClientLocalAddr.SockAddr), &ClientLocalAddr.SockAddr)); } + + // + // Remove a local address that belongs to the non-active path dusring handshake + // + { + TestScopeLogger LogScope2("Remove a local address that belongs to the non-active path during handshake"); + MsQuicConnection Connection(Registration); + TEST_QUIC_SUCCEEDED(Connection.GetInitStatus()); + TEST_QUIC_SUCCEEDED( + MsQuic->ConnectionStart( + Connection.Handle, + ClientConfiguration, + QUIC_ADDRESS_FAMILY_INET, + "localhost", + 4433)); + + QuicAddr SecondLocalAddr; + TEST_QUIC_SUCCEEDED(Connection.GetLocalAddr(SecondLocalAddr)); + SecondLocalAddr.IncrementPort(); + + TEST_QUIC_SUCCEEDED( + Connection.SetParam( + QUIC_PARAM_CONN_ADD_LOCAL_ADDRESS, + sizeof(SecondLocalAddr.SockAddr), + &SecondLocalAddr.SockAddr)); + + TEST_QUIC_SUCCEEDED( + Connection.SetParam( + QUIC_PARAM_CONN_REMOVE_LOCAL_ADDRESS, + sizeof(SecondLocalAddr.SockAddr), + &SecondLocalAddr.SockAddr)); + } } } #endif diff --git a/src/test/lib/PathTest.cpp b/src/test/lib/PathTest.cpp index ca0089efc8..398549147b 100644 --- a/src/test/lib/PathTest.cpp +++ b/src/test/lib/PathTest.cpp @@ -216,7 +216,7 @@ void QuicTestMigration( _In_ int Family, _In_ BOOLEAN ShareBinding, - _In_ BOOLEAN Smooth + _In_ QUIC_MIGRATION_TYPE Type ) { PathTestContext Context; @@ -258,7 +258,7 @@ QuicTestMigration( PathProbeHelper* ProbeHelper = new PathProbeHelper(SecondLocalAddr.GetPort()); - if (Smooth) { + if (Type == MigrateWithProbe || Type == DeleteAndMigrate) { QUIC_STATUS Status = QUIC_STATUS_SUCCESS; int Try = 0; do { @@ -288,11 +288,22 @@ QuicTestMigration( &Stats)); TEST_EQUAL(Stats.RecvDroppedPackets, 0); - TEST_QUIC_SUCCEEDED( - Connection.SetParam( - QUIC_PARAM_CONN_LOCAL_ADDRESS, - sizeof(SecondLocalAddr.SockAddr), - &SecondLocalAddr.SockAddr)); + if (Type == MigrateWithProbe) { + TEST_QUIC_SUCCEEDED( + Connection.SetParam( + QUIC_PARAM_CONN_LOCAL_ADDRESS, + sizeof(SecondLocalAddr.SockAddr), + &SecondLocalAddr.SockAddr)); + } else { + QuicAddr ClientLocalAddr; + TEST_QUIC_SUCCEEDED(Connection.GetLocalAddr(ClientLocalAddr)); + + TEST_QUIC_SUCCEEDED( + Connection.SetParam( + QUIC_PARAM_CONN_REMOVE_LOCAL_ADDRESS, + sizeof(ClientLocalAddr.SockAddr), + &ClientLocalAddr.SockAddr)); + } } else { // // Wait for handshake confirmation. From 01f7e15998d70506d94e1e10f7ca30ef05c7d2bc Mon Sep 17 00:00:00 2001 From: Masahiro Kozuka Date: Fri, 10 Jan 2025 10:57:01 +0900 Subject: [PATCH 24/29] Validate buffer and address in local address add/remove functions --- src/core/connection.c | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/src/core/connection.c b/src/core/connection.c index 9c65d2422b..63271509dc 100644 --- a/src/core/connection.c +++ b/src/core/connection.c @@ -7107,37 +7107,25 @@ QuicConnParamSet( case QUIC_PARAM_CONN_ADD_LOCAL_ADDRESS: { - if (BufferLength != sizeof(QUIC_ADDR)) { - Status = QUIC_STATUS_INVALID_PARAMETER; - break; - } - - QUIC_ADDR* LocalAddress = (QUIC_ADDR*)Buffer; - - if (!QuicAddrIsValid(LocalAddress)) { + if (BufferLength != sizeof(QUIC_ADDR) || Buffer == NULL || + !QuicAddrIsValid((QUIC_ADDR*)Buffer)) { Status = QUIC_STATUS_INVALID_PARAMETER; break; } - Status = QuicConnAddLocalAddress(Connection, LocalAddress); + 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; - } - - QUIC_ADDR* LocalAddress = (QUIC_ADDR*)Buffer; - - if (!QuicAddrIsValid(LocalAddress)) { + if (BufferLength != sizeof(QUIC_ADDR) || Buffer == NULL || + !QuicAddrIsValid((QUIC_ADDR*)Buffer)) { Status = QUIC_STATUS_INVALID_PARAMETER; break; } - Status = QuicConnRemoveLocalAddress(Connection, LocalAddress); + Status = QuicConnRemoveLocalAddress(Connection, (QUIC_ADDR*)Buffer); break; } From 6d53d038e7412e792d9aa02398b1ec535033f213 Mon Sep 17 00:00:00 2001 From: Masahiro Kozuka Date: Fri, 10 Jan 2025 15:55:17 +0900 Subject: [PATCH 25/29] Refactor QUIC CID source functions to remove unnecessary connection parameter --- src/core/cid.h | 5 +---- src/core/connection.c | 8 +++----- src/core/inline.c | 6 +----- src/core/library.h | 1 - 4 files changed, 5 insertions(+), 15 deletions(-) diff --git a/src/core/cid.h b/src/core/cid.h index 2dcf66e057..294e801468 100644 --- a/src/core/cid.h +++ b/src/core/cid.h @@ -188,9 +188,7 @@ typedef struct QUIC_CID_HASH_ENTRY { inline _Success_(return != NULL) QUIC_CID_SLIST_ENTRY* -QuicCidNewNullSource( - _In_ QUIC_CONNECTION* Connection - ) +QuicCidNewNullSource() { QUIC_CID_SLIST_ENTRY* Entry = (QUIC_CID_SLIST_ENTRY*)CXPLAT_ALLOC_NONPAGED( @@ -212,7 +210,6 @@ inline _Success_(return != NULL) QUIC_CID_SLIST_ENTRY* QuicCidNewSource( - _In_ QUIC_CONNECTION* Connection, _In_ uint8_t Length, _In_reads_(Length) const uint8_t* const Data diff --git a/src/core/connection.c b/src/core/connection.c index 63271509dc..4b8155fbad 100644 --- a/src/core/connection.c +++ b/src/core/connection.c @@ -217,7 +217,7 @@ QuicConnAlloc( CASTED_CLOG_BYTEARRAY(Path->DestCid->CID.Length, Path->DestCid->CID.Data)); QUIC_CID_SLIST_ENTRY* SourceCid = - QuicCidNewSource(Connection, Packet->DestCidLen, Packet->DestCid); + QuicCidNewSource(Packet->DestCidLen, Packet->DestCid); if (SourceCid == NULL) { Status = QUIC_STATUS_OUT_OF_MEMORY; goto Error; @@ -874,7 +874,6 @@ QuicConnGenerateNewSourceCid( do { SourceCid = QuicCidNewRandomSource( - Connection, Connection->ServerID, Connection->PartitionID, Connection->CibirId[0], @@ -1984,13 +1983,12 @@ QuicConnStart( if (Connection->State.ShareBinding) { SourceCid = QuicCidNewRandomSource( - Connection, NULL, Connection->PartitionID, Connection->CibirId[0], Connection->CibirId+2); } else { - SourceCid = QuicCidNewNullSource(Connection); + SourceCid = QuicCidNewNullSource(); } if (SourceCid == NULL) { Status = QUIC_STATUS_OUT_OF_MEMORY; @@ -6343,7 +6341,7 @@ QuicConnOpenNewPath( } if (!Connection->State.ShareBinding) { - QUIC_CID_SLIST_ENTRY* SourceCid = QuicCidNewNullSource(Connection); + QUIC_CID_SLIST_ENTRY* SourceCid = QuicCidNewNullSource(); if (SourceCid == NULL) { return QUIC_STATUS_OUT_OF_MEMORY; } diff --git a/src/core/inline.c b/src/core/inline.c index 4aeb7e7eb1..c30df3a689 100644 --- a/src/core/inline.c +++ b/src/core/inline.c @@ -29,20 +29,16 @@ QuicCidNewDestination( QUIC_CID_SLIST_ENTRY* QuicCidNewSource( - _In_ QUIC_CONNECTION* Connection, _In_ uint8_t Length, _In_reads_(Length) const uint8_t* const Data ); QUIC_CID_SLIST_ENTRY* -QuicCidNewNullSource( - _In_ QUIC_CONNECTION* Connection - ); +QuicCidNewNullSource(); QUIC_CID_SLIST_ENTRY* QuicCidNewRandomSource( - _In_opt_ QUIC_CONNECTION* Connection, _In_reads_opt_(MsQuicLib.CidServerIdLength) const void* ServerID, _In_ uint16_t PartitionID, diff --git a/src/core/library.h b/src/core/library.h index 80c21da2b2..3d42473491 100644 --- a/src/core/library.h +++ b/src/core/library.h @@ -453,7 +453,6 @@ inline _Success_(return != NULL) QUIC_CID_SLIST_ENTRY* QuicCidNewRandomSource( - _In_opt_ QUIC_CONNECTION* Connection, _In_reads_opt_(MsQuicLib.CidServerIdLength) const void* ServerID, _In_ uint16_t PartitionID, From ce4a86f63e52e33c122b0317ba09511f3dc7af3f Mon Sep 17 00:00:00 2001 From: Masahiro Kozuka Date: Fri, 10 Jan 2025 16:42:11 +0900 Subject: [PATCH 26/29] Add multipath negotiation check before sending path validation challenge --- src/core/connection.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/core/connection.c b/src/core/connection.c index 3fdfb793e8..e2df4dfb5b 100644 --- a/src/core/connection.c +++ b/src/core/connection.c @@ -5291,16 +5291,18 @@ QuicConnRecvPostProcessing( // CxPlatRandom(sizeof((*Path)->Challenge), (*Path)->Challenge); - // - // We need to also send a challenge on the active path to make sure - // it is still good. - // - CXPLAT_DBG_ASSERT(Connection->Paths[0].IsActive); - if (Connection->Paths[0].IsPeerValidated) { // Not already doing peer validation. - Connection->Paths[0].IsPeerValidated = FALSE; - Connection->Paths[0].SendChallenge = TRUE; - Connection->Paths[0].PathValidationStartTime = CxPlatTimeUs64(); - CxPlatRandom(sizeof(Connection->Paths[0].Challenge), Connection->Paths[0].Challenge); + if (!Connection->State.MultipathNegotiated) { + // + // We need to also send a challenge on the active path to make sure + // it is still good. + // + CXPLAT_DBG_ASSERT(Connection->Paths[0].IsActive); + if (Connection->Paths[0].IsPeerValidated) { // Not already doing peer validation. + Connection->Paths[0].IsPeerValidated = FALSE; + Connection->Paths[0].SendChallenge = TRUE; + Connection->Paths[0].PathValidationStartTime = CxPlatTimeUs64(); + CxPlatRandom(sizeof(Connection->Paths[0].Challenge), Connection->Paths[0].Challenge); + } } QuicSendSetSendFlag( From dda0b000ef6da1bb86c449e6bf8f1aaa4b483950 Mon Sep 17 00:00:00 2001 From: Masahiro Kozuka Date: Mon, 13 Jan 2025 22:56:11 +0900 Subject: [PATCH 27/29] Add partition index to UDP configuration for new path binding --- src/core/connection.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/core/connection.c b/src/core/connection.c index 4b8155fbad..d4958a71e1 100644 --- a/src/core/connection.c +++ b/src/core/connection.c @@ -6315,6 +6315,8 @@ QuicConnOpenNewPath( UdpConfig.RemoteAddress = &Connection->Paths[0].Route.RemoteAddress; UdpConfig.Flags = Connection->State.ShareBinding ? CXPLAT_SOCKET_FLAG_SHARE : 0; UdpConfig.InterfaceIndex = 0; + // Open a new binding with the same partition as the connection. + UdpConfig.PartitionIndex = QuicPartitionIdGetIndex(Connection->PartitionID); #ifdef QUIC_COMPARTMENT_ID UdpConfig.CompartmentId = Connection->Configuration->CompartmentId; #endif From 57309455b0f732813fa4c33ee86ac5113c3214bf Mon Sep 17 00:00:00 2001 From: Masahiro Kozuka Date: Sat, 18 Jan 2025 21:05:02 +0900 Subject: [PATCH 28/29] Update PathProbeHelper instantiation to use std::nothrow and fix QUIC_MAX_IOCTL_FUNC_CODE --- src/test/MsQuicTests.h | 2 +- src/test/lib/PathTest.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/test/MsQuicTests.h b/src/test/MsQuicTests.h index d35376afe3..f2d2aec883 100644 --- a/src/test/MsQuicTests.h +++ b/src/test/MsQuicTests.h @@ -1390,4 +1390,4 @@ typedef struct { QUIC_CTL_CODE(128, METHOD_BUFFERED, FILE_WRITE_DATA) // QUIC_RUN_MIGRATION -#define QUIC_MAX_IOCTL_FUNC_CODE 129 +#define QUIC_MAX_IOCTL_FUNC_CODE 128 diff --git a/src/test/lib/PathTest.cpp b/src/test/lib/PathTest.cpp index 398549147b..37458f3b4c 100644 --- a/src/test/lib/PathTest.cpp +++ b/src/test/lib/PathTest.cpp @@ -173,7 +173,7 @@ QuicTestProbePath( TEST_QUIC_SUCCEEDED(Connection.GetLocalAddr(SecondLocalAddr)); SecondLocalAddr.IncrementPort(); - PathProbeHelper *ProbeHelper = new PathProbeHelper(SecondLocalAddr.GetPort(), DropPacketCount, DropPacketCount); + PathProbeHelper *ProbeHelper = new(std::nothrow) PathProbeHelper(SecondLocalAddr.GetPort(), DropPacketCount, DropPacketCount); QUIC_STATUS Status = QUIC_STATUS_SUCCESS; uint32_t Try = 0; @@ -186,7 +186,7 @@ QuicTestProbePath( if (Status != QUIC_STATUS_SUCCESS) { delete ProbeHelper; SecondLocalAddr.IncrementPort(); - ProbeHelper = new PathProbeHelper(SecondLocalAddr.GetPort(), DropPacketCount, DropPacketCount); + ProbeHelper = new(std::nothrow) PathProbeHelper(SecondLocalAddr.GetPort(), DropPacketCount, DropPacketCount); } } while (Status == QUIC_STATUS_ADDRESS_IN_USE && ++Try <= 3); TEST_EQUAL(Status, QUIC_STATUS_SUCCESS); @@ -256,7 +256,7 @@ QuicTestMigration( TEST_QUIC_SUCCEEDED(Connection.GetLocalAddr(SecondLocalAddr)); SecondLocalAddr.IncrementPort(); - PathProbeHelper* ProbeHelper = new PathProbeHelper(SecondLocalAddr.GetPort()); + PathProbeHelper* ProbeHelper = new(std::nothrow) PathProbeHelper(SecondLocalAddr.GetPort()); if (Type == MigrateWithProbe || Type == DeleteAndMigrate) { QUIC_STATUS Status = QUIC_STATUS_SUCCESS; @@ -270,7 +270,7 @@ QuicTestMigration( if (Status != QUIC_STATUS_SUCCESS) { delete ProbeHelper; SecondLocalAddr.IncrementPort(); - ProbeHelper = new PathProbeHelper(SecondLocalAddr.GetPort()); + ProbeHelper = new(std::nothrow) PathProbeHelper(SecondLocalAddr.GetPort()); } } while (Status == QUIC_STATUS_ADDRESS_IN_USE && ++Try <= 3); TEST_QUIC_SUCCEEDED(Status); From 07d3f7c9cd169944b62358660244b6d524123c95 Mon Sep 17 00:00:00 2001 From: Masahiro Kozuka Date: Tue, 18 Feb 2025 10:14:39 +0900 Subject: [PATCH 29/29] Fix QUIC_PARAM_CONN_ADD_LOCAL_ADDRESS and QUIC_PARAM_CONN_REMOVE_LOCAL_ADDRESS definitions --- src/inc/msquic.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/inc/msquic.h b/src/inc/msquic.h index 1edc1b9e7e..4f3975d66d 100644 --- a/src/inc/msquic.h +++ b/src/inc/msquic.h @@ -925,8 +925,8 @@ typedef struct QUIC_SCHANNEL_CREDENTIAL_ATTRIBUTE_W { #define QUIC_PARAM_CONN_ORIG_DEST_CID 0x05000018 // uint8_t[] #define QUIC_PARAM_CONN_SEND_DSCP 0x05000019 // 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_ADD_LOCAL_ADDRESS 0x0500001A // QUIC_ADDR +#define QUIC_PARAM_CONN_REMOVE_LOCAL_ADDRESS 0x0500001B // QUIC_ADDR #endif //