Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
ee68434
add a comment
ProjectsByJackHe Feb 18, 2026
68a7afe
update code to account for cibir
ProjectsByJackHe Feb 18, 2026
382fba7
clog fixes
ProjectsByJackHe Feb 18, 2026
c1c1445
update docs, update tests
ProjectsByJackHe Feb 19, 2026
df75326
rename reserveauxtcpsock and add explicit check for error code
ProjectsByJackHe Feb 21, 2026
a952c04
always false in kernel mode...
ProjectsByJackHe Feb 21, 2026
a0b20b3
XDP and CIBIR
ProjectsByJackHe Feb 21, 2026
d2bd384
add logs
ProjectsByJackHe Feb 28, 2026
c2ac95b
more logs
ProjectsByJackHe Feb 28, 2026
7f6d88e
more logs
ProjectsByJackHe Feb 28, 2026
b442e8a
return error if xdp not available
ProjectsByJackHe Mar 12, 2026
323d3f0
update docs on proper behavior
ProjectsByJackHe Mar 12, 2026
f55cc25
fix test
ProjectsByJackHe Mar 12, 2026
a70a8c2
get rid of bad artifact
ProjectsByJackHe Mar 12, 2026
cabc5a8
fix nit / clog
ProjectsByJackHe Mar 12, 2026
1557c28
address feedback
ProjectsByJackHe Mar 17, 2026
24e1390
clog
ProjectsByJackHe Mar 17, 2026
b43c894
fix inline def
ProjectsByJackHe Mar 18, 2026
8da485c
clog
ProjectsByJackHe Mar 19, 2026
2f06dad
update to use ifdef
ProjectsByJackHe Mar 21, 2026
a76904d
do not reserve any sockets at all
ProjectsByJackHe Mar 23, 2026
347356e
give it a non-0 local address
ProjectsByJackHe Mar 24, 2026
70a6e9e
proper port reservations
ProjectsByJackHe Mar 24, 2026
e4b5ecc
fix conn pool test case
ProjectsByJackHe Mar 24, 2026
cf4fd8b
fix tests
ProjectsByJackHe Mar 24, 2026
da3dfd6
put ifdef in handshaketest directly
ProjectsByJackHe Mar 26, 2026
4c9753c
update docs, add dbg assert, and fix logic
ProjectsByJackHe Mar 27, 2026
ced6a30
update warning logs
ProjectsByJackHe Mar 27, 2026
8a16a62
Merge branch 'main' into jackhe/sql-cibir-fix-sock-reservation
ProjectsByJackHe Apr 6, 2026
808ea0c
more crisp behavior
ProjectsByJackHe Apr 6, 2026
8a6eef8
Merge branch 'main' into jackhe/sql-cibir-fix-sock-reservation
ProjectsByJackHe Apr 7, 2026
ad2070a
update cibir docs
ProjectsByJackHe Apr 7, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/Settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ These parameters are accessed by calling [GetParam](./api/GetParam.md) or [SetPa
|-------------------------------------------|---------------------------|-----------|-----------------------------------------------------------|
| `QUIC_PARAM_LISTENER_LOCAL_ADDRESS`<br> 0 | QUIC_ADDR | Get-only | Get the full address tuple the server is listening on. |
| `QUIC_PARAM_LISTENER_STATS`<br> 1 | QUIC_LISTENER_STATISTICS | Get-only | Get statistics specific to this Listener instance. |
| `QUIC_PARAM_LISTENER_CIBIR_ID`<br> 2 | uint8_t[] | Both | The CIBIR well-known idenfitier. |
| `QUIC_PARAM_LISTENER_CIBIR_ID`<br> 2 | uint8_t[] | Both | Sets a CIBIR (CID-Based Identification and Routing) well-known identifier. CIBIR does 2 things when set: 1. XDP will now steer packets to the correct process/listener by matching the CIBIR prefix within the packet QUIC Connection ID. 2. In the case of a port collision when reserving OS UDP/TCP sockets, MsQuic will continue with initializing the datapath. If XDP is not available/enabled, then no traffic will flow for the listener that experiences a collision. |
| `QUIC_PARAM_DOS_MODE_EVENTS`<br> 2 | BOOLEAN | Both | The Listener opted in for DoS Mode event. |
| `QUIC_PARAM_LISTENER_PARTITION_INDEX`<br> (preview) | uint16_t | Both | The partition to use for listener callback events and incoming connections. |

Expand Down
20 changes: 20 additions & 0 deletions src/generated/linux/datapath_winuser.c.clog.h
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,26 @@ tracepoint(CLOG_DATAPATH_WINUSER_C, DatapathTestSetIpv6TrafficClassFailed , arg2



/*----------------------------------------------------------
// Decoder Ring for DatapathCibirSkipNoXdp
// [data][%p] CIBIR configured, skipping OS socket reservation but XDP not %s
// QuicTraceLogWarning(
DatapathCibirSkipNoXdp,
"[data][%p] CIBIR configured, skipping OS socket reservation but XDP not %s",
Socket,
!XdpAvailable ? "available" : "enabled");
// arg2 = arg2 = Socket = arg2
// arg3 = arg3 = !XdpAvailable ? "available" : "enabled" = arg3
----------------------------------------------------------*/
#ifndef _clog_4_ARGS_TRACE_DatapathCibirSkipNoXdp
#define _clog_4_ARGS_TRACE_DatapathCibirSkipNoXdp(uniqueId, encoded_arg_string, arg2, arg3)\
tracepoint(CLOG_DATAPATH_WINUSER_C, DatapathCibirSkipNoXdp , arg2, arg3);\

#endif




/*----------------------------------------------------------
// Decoder Ring for DatapathRecvEmpty
// [data][%p] Dropping datagram with empty payload.
Expand Down
23 changes: 23 additions & 0 deletions src/generated/linux/datapath_winuser.c.clog.h.lttng.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,29 @@ TRACEPOINT_EVENT(CLOG_DATAPATH_WINUSER_C, DatapathTestSetIpv6TrafficClassFailed,



/*----------------------------------------------------------
// Decoder Ring for DatapathCibirSkipNoXdp
// [data][%p] CIBIR configured, skipping OS socket reservation but XDP not %s
// QuicTraceLogWarning(
DatapathCibirSkipNoXdp,
"[data][%p] CIBIR configured, skipping OS socket reservation but XDP not %s",
Socket,
!XdpAvailable ? "available" : "enabled");
// arg2 = arg2 = Socket = arg2
// arg3 = arg3 = !XdpAvailable ? "available" : "enabled" = arg3
----------------------------------------------------------*/
TRACEPOINT_EVENT(CLOG_DATAPATH_WINUSER_C, DatapathCibirSkipNoXdp,
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 DatapathRecvEmpty
// [data][%p] Dropping datagram with empty payload.
Expand Down
21 changes: 21 additions & 0 deletions src/manifest/clog.sidecar
Original file line number Diff line number Diff line change
Expand Up @@ -2443,6 +2443,22 @@
],
"macroName": "QuicTraceLogConnVerbose"
},
"DatapathCibirSkipNoXdp": {
"ModuleProperites": {},
"TraceString": "[data][%p] CIBIR configured, skipping OS socket reservation but XDP not %s",
"UniqueId": "DatapathCibirSkipNoXdp",
"splitArgs": [
{
"DefinationEncoding": "p",
"MacroVariableName": "arg2"
},
{
"DefinationEncoding": "s",
"MacroVariableName": "arg3"
}
],
"macroName": "QuicTraceLogWarning"
},
"DatapathCreated": {
"ModuleProperites": {},
"TraceString": "[data][%p] Created, local=%!ADDR!, remote=%!ADDR!",
Expand Down Expand Up @@ -14022,6 +14038,11 @@
"TraceID": "DatagramSendStateChanged",
"EncodingString": "[conn][%p] Indicating DATAGRAM_SEND_STATE_CHANGED to %u"
},
{
"UniquenessHash": "8343563a-502d-077c-44f6-6dfd65e927f5",
"TraceID": "DatapathCibirSkipNoXdp",
"EncodingString": "[data][%p] CIBIR configured, skipping OS socket reservation but XDP not %s"
},
{
"UniquenessHash": "1cde4174-4172-15b7-b59b-dcbb6410b43a",
"TraceID": "DatapathCreated",
Expand Down
12 changes: 10 additions & 2 deletions src/platform/datapath_raw_socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -890,7 +890,7 @@ CxPlatTryAddSocket(
// binding an auxiliary (dual stack) socket.
//

if (Socket->ReserveAuxTcpSock) {
if (Socket->ReserveAuxTcpSock && !Socket->SkipCreatingOsSockets) {
Socket->AuxSocket =
socket(
AF_INET6,
Expand Down Expand Up @@ -929,6 +929,14 @@ CxPlatTryAddSocket(
}

if (Socket->CibirIdLength) {
//
// Setting SO_REUSEADDR does NOT robustly allow
// multiple processes to share the same port on
// Windows (WinSock).
// This code was added primarily for Linux XDP,
// where Linux sockets DO actually allow robust
// port sharing...
//
Option = TRUE;
Result =
setsockopt(
Expand Down Expand Up @@ -960,7 +968,7 @@ CxPlatTryAddSocket(

CxPlatRwLockAcquireExclusive(&Pool->Lock);

if (Socket->ReserveAuxTcpSock) {
if (Socket->ReserveAuxTcpSock && !Socket->SkipCreatingOsSockets) {
QUIC_ADDR_STR LocalAddressString = {0};
QuicAddrToString(&MappedAddress, &LocalAddressString);
QuicTraceLogVerbose(
Expand Down
52 changes: 48 additions & 4 deletions src/platform/datapath_winuser.c
Original file line number Diff line number Diff line change
Expand Up @@ -1273,7 +1273,7 @@ SocketCreateUdp(

if (Socket->ReserveAuxTcpSock && !IsServerSocket) {
//
// Client will skip normal socket settings to use AuxSocket in raw socket.
// QTIP clients will skip normal UDP socket reservation to use AuxSocket (TCP socket reservation) in raw socket.
//
goto Skip;
}
Expand Down Expand Up @@ -1724,6 +1724,27 @@ SocketCreateUdp(
Socket,
WsaError,
"SIO_ACQUIRE_PORT_RESERVATION");

if (Config->CibirIdLength > 0 && IsServerSocket) {
//
// CIBIR is configured. A port collision here is actually
// expected if multiple server processes were configured to share
// the same UDP and/or TCP port.
//
CxPlatRefInitializeEx(&Socket->RefCount, 1);
Socket->SkipCreatingOsSockets = TRUE;
BOOLEAN XdpAvailable = Datapath->RawDataPath != NULL;
BOOLEAN XdpEnabled = Config->Flags & CXPLAT_SOCKET_FLAG_XDP;
if (!XdpAvailable || !XdpEnabled) {
QuicTraceLogWarning(
DatapathCibirSkipNoXdp,
"[data][%p] CIBIR configured, skipping OS socket reservation but XDP not %s",
Socket,
!XdpAvailable ? "available" : "enabled");
}
goto Skip;
}

Status = HRESULT_FROM_WIN32(WsaError);
goto Error;
}
Expand Down Expand Up @@ -1831,6 +1852,25 @@ SocketCreateUdp(

Skip:

if (Socket->SkipCreatingOsSockets) {
//
// Clean up all partially-initialized per-proc sockets since
// we're skipping OS socket creation (XDP-only via CIBIR).
//
for (uint16_t i = 0; i < SocketCount; i++) {
CXPLAT_SOCKET_PROC* Proc = &Socket->PerProcSockets[i];
if (Proc->Socket != INVALID_SOCKET) {
closesocket(Proc->Socket);
Proc->Socket = INVALID_SOCKET;
}
if (Proc->DatapathProc) {
CxPlatProcessorContextRelease(Proc->DatapathProc);
Proc->DatapathProc = NULL;
}
CxPlatRundownUninitialize(&Proc->RundownRef);
}
}

if (Config->RemoteAddress != NULL) {
Socket->RemoteAddress = *Config->RemoteAddress;
} else {
Expand All @@ -1843,7 +1883,7 @@ SocketCreateUdp(
//
*NewSocket = Socket;

if (!Socket->ReserveAuxTcpSock) {
if (!Socket->ReserveAuxTcpSock && !Socket->SkipCreatingOsSockets) {
for (uint16_t i = 0; i < SocketCount; i++) {
CxPlatDataPathStartReceiveAsync(&Socket->PerProcSockets[i]);
Socket->PerProcSockets[i].IoStarted = TRUE;
Expand Down Expand Up @@ -2380,8 +2420,12 @@ SocketDelete(
CXPLAT_DBG_ASSERT(!Socket->Uninitialized);
Socket->Uninitialized = TRUE;

if (Socket->ReserveAuxTcpSock && Socket->HasFixedRemoteAddress) {
// QTIP did not initialize PerProcSockets only for Client sockets.
if ((Socket->ReserveAuxTcpSock && Socket->HasFixedRemoteAddress) ||
Socket->SkipCreatingOsSockets) {
//
// QTIP client or CIBIR skip: PerProcSockets were not initialized
// (or already cleaned up). Just release the socket directly.
//
CxPlatSocketRelease(Socket);
} else {
const uint16_t SocketCount =
Expand Down
6 changes: 6 additions & 0 deletions src/platform/platform_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,8 @@ typedef struct CXPLAT_SOCKET {
uint8_t HasFixedRemoteAddress : 1;
uint8_t RawSocketAvailable : 1;

uint8_t SkipCreatingOsSockets : 1;

CXPLAT_RUNDOWN_REF Rundown[0]; // Per-proc

} CXPLAT_SOCKET;
Expand Down Expand Up @@ -595,6 +597,8 @@ typedef struct CXPLAT_SOCKET {

uint8_t RawSocketAvailable : 1;

uint8_t SkipCreatingOsSockets : 1;

//
// Per-processor socket contexts.
//
Expand Down Expand Up @@ -900,6 +904,8 @@ typedef struct CXPLAT_SOCKET {

uint8_t RawSocketAvailable : 1;

uint8_t SkipCreatingOsSockets : 1;

//
// Set of socket contexts one per proc.
//
Expand Down
28 changes: 28 additions & 0 deletions src/platform/unittest/DataPathTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,7 @@ struct CxPlatSocket {
CXPLAT_SOCKET* Socket {nullptr};
QUIC_STATUS InitStatus {QUIC_STATUS_INVALID_STATE};
CXPLAT_ROUTE Route {0};
uint8_t CibirIdLength {0};
CxPlatSocket() { }
CxPlatSocket(
_In_ CxPlatDataPath& Datapath,
Expand Down Expand Up @@ -571,6 +572,7 @@ struct CxPlatSocket {
UdpConfig.Flags = InternalFlags;
UdpConfig.InterfaceIndex = 0;
UdpConfig.CallbackContext = CallbackContext;
UdpConfig.CibirIdLength = CibirIdLength;
InitStatus =
CxPlatSocketCreateUdp(
Datapath,
Expand Down Expand Up @@ -848,6 +850,32 @@ TEST_P(DataPathTest, UdpData)
ASSERT_TRUE(CxPlatEventWaitWithTimeout(RecvContext.ClientCompletion, 2000));
}

TEST_P(DataPathTest, UdpDataShareCibirUdpPort) {
UdpRecvContext RecvContext;
CxPlatDataPath Datapath(&UdpRecvCallbacks);
VERIFY_QUIC_SUCCESS(Datapath.GetInitStatus());
auto unspecAddress = GetNewUnspecAddr();
CxPlatSocket Server1;
//
// Set CibirIdLength to some non-zero value to trigger the cibir path in the datapath code,
// which should allow multiple cxplat sockets to be created on the same udp port so long as
// cibir is configured.
//
Server1.CibirIdLength = 8;
Server1.CreateUdp(Datapath, &unspecAddress.SockAddr, nullptr, &RecvContext);
while (Server1.GetInitStatus() == QUIC_STATUS_ADDRESS_IN_USE) {
unspecAddress.SockAddr.Ipv4.sin_port = GetNextPort();
Server1.CreateUdp(Datapath, &unspecAddress.SockAddr, nullptr, &RecvContext);
}
VERIFY_QUIC_SUCCESS(Server1.GetInitStatus());
ASSERT_NE(nullptr, Server1.Socket);
CxPlatSocket Server2;
Server2.CibirIdLength = 8;
Server2.CreateUdp(Datapath, &unspecAddress.SockAddr, nullptr, &RecvContext);
VERIFY_QUIC_SUCCESS(Server2.GetInitStatus());
ASSERT_NE(nullptr, Server2.Socket);
}

TEST_P(DataPathTest, UdpDataPolling)
{
QUIC_GLOBAL_EXECUTION_CONFIG Config = { QUIC_GLOBAL_EXECUTION_CONFIG_FLAG_NONE, UINT32_MAX, 0 };
Expand Down
Loading