Skip to content

Commit b632469

Browse files
ProjectsByJackHeguhetierCopilot
authored
[2/3] Integrate XSK maps into the core XDP datapath (#6003)
## Description **Full E2E demo using tools from this [PR ](#5999 [DEMO](https://microsoft.sharepoint.com/:v:/t/OSPlatformNetworking/cQoKsihSVC3kQ63QHixCTQ7hEgUCS3dPKZahhfyXC9GFfx8OFQ?nav=eyJyZWZlcnJhbEluZm8iOnsicmVmZXJyYWxBcHAiOiJTdHJlYW1XZWJBcHAiLCJyZWZlcnJhbFZpZXciOiJTaGFyZURpYWxvZy1MaW5rIiwicmVmZXJyYWxBcHBQbGF0Zm9ybSI6IldlYiIsInJlZmVycmFsTW9kZSI6InZpZXcifX0=&) Part 2 of the plan: #5982 Fixes #5972 Adds the core msquic datapath integrations for the new API contract defined in #5983 **Key design decisions:** - If map mode is enabled, then we do not create the WinSock or Epoll or .... datapaths. No more best effort! - Init failures in map mode hard fails the datapath initialization. No silent failures! ## Testing Added datapath unit tests. See the E2E demo. Additionally, the plan is to leverage some supporting PRs that included code to ingest the latest XDP version, and kicking off a couple of manual CI runs based on that: https://github.com/microsoft/msquic/actions/runs/27313685557/job/80690420168 ## Documentation Will come as part 3 in the plan: #5982 --------- Co-authored-by: Guillaume Hetier <guhetier@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 07bbcb7 commit b632469

38 files changed

Lines changed: 2029 additions & 57 deletions

.github/workflows/test.yml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ jobs:
144144
{ config: "Debug", plat: "windows", os: "windows-2022", arch: "x64", tls: "schannel", xdp: "xdp-v1.1", sanitize: "-SanitizeAddress", build: "-Test" },
145145
{ config: "Debug", plat: "windows", os: "windows-2022", arch: "x64", tls: "schannel", xdp: "xdp-v1.1", qtip: "-UseQtip", sanitize: "-SanitizeAddress", build: "-Test" },
146146
{ config: "Debug", plat: "windows", os: "windows-2022", arch: "x64", tls: "schannel", xdp: "xdp-prerelease", build: "-Test" },
147+
{ config: "Debug", plat: "windows", os: "windows-2022", arch: "x64", tls: "schannel", xdp: "xdp-prerelease", qtip: "-UseQtip", build: "-Test" },
147148
{ config: "Debug", plat: "windows", os: "windows-2022", arch: "x64", tls: "quictls", build: "-Test", log: "Full.Verbose" },
148149
{ config: "Debug", plat: "windows", os: "windows-2022", arch: "x64", tls: "quictls", xdp: "xdp-v1.1", build: "-Test" },
149150
{ config: "Debug", plat: "windows", os: "windows-2022", arch: "x64", tls: "quictls", xdp: "xdp-v1.1", qtip: "-UseQtip", build: "-Test" },
@@ -202,16 +203,21 @@ jobs:
202203
shell: pwsh
203204
timeout-minutes: 120
204205
run: scripts/test.ps1 -Config ${{ matrix.vec.config }} -Arch ${{ matrix.vec.arch }} -Tls ${{ matrix.vec.tls }} -GHA -LogProfile ${{ matrix.vec.log || (inputs.log_level || 'Full.Light') }} -GenerateXmlResults ${{ matrix.vec.xdp && '-UseXdp' }} ${{ matrix.vec.xdp }} ${{ matrix.vec.qtip }} ${{ inputs.filter && '-Filter' }} ${{ inputs.filter || '' }}
206+
- name: Test (Map Mode Tests Only)
207+
if: matrix.vec.xdp == 'xdp-prerelease'
208+
shell: pwsh
209+
timeout-minutes: 120
210+
run: scripts/test.ps1 -Config ${{ matrix.vec.config }} -Arch ${{ matrix.vec.arch }} -Tls ${{ matrix.vec.tls }} -OsRunner ${{ matrix.vec.os }} -GHA -LogProfile ${{ matrix.vec.log || (inputs.log_level || 'Full.Light') }} -GenerateXmlResults ${{ matrix.vec.xdp && '-UseXdp' }} ${{ matrix.vec.xdp }} ${{ matrix.vec.qtip }} -Filter '*XdpMapMode*' -XdpMapMode
205211
- name: Test
206212
if: matrix.vec.os != 'WinServerPrerelease'
207213
shell: pwsh
208214
timeout-minutes: 120
209-
run: scripts/test.ps1 -Config ${{ matrix.vec.config }} -Arch ${{ matrix.vec.arch }} -Tls ${{ matrix.vec.tls }} -OsRunner ${{ matrix.vec.os }} -GHA -LogProfile ${{ matrix.vec.log || (inputs.log_level || 'Full.Light') }} -GenerateXmlResults ${{ matrix.vec.xdp && '-UseXdp' }} ${{ matrix.vec.xdp }} ${{ matrix.vec.qtip }} ${{ inputs.filter && '-Filter' }} ${{ inputs.filter || '' }}
215+
run: scripts/test.ps1 -Config ${{ matrix.vec.config }} -Arch ${{ matrix.vec.arch }} -Tls ${{ matrix.vec.tls }} -OsRunner ${{ matrix.vec.os }} -GHA -LogProfile ${{ matrix.vec.log || (inputs.log_level || 'Full.Light') }} -GenerateXmlResults ${{ matrix.vec.xdp && '-UseXdp' }} ${{ matrix.vec.xdp }} ${{ matrix.vec.qtip }} ${{ matrix.vec.xdpmapmode }} ${{ inputs.filter && '-Filter' }} ${{ inputs.filter || '' }}
210216
- name: Upload on Failure or Cancellation
211217
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
212218
if: failure() || cancelled()
213219
with:
214-
name: BVT-${{ matrix.vec.config }}-${{ matrix.vec.plat }}-${{ matrix.vec.os }}-${{ matrix.vec.arch }}-${{ matrix.vec.tls }}${{ matrix.vec.xdp }}${{ matrix.vec.iouring }}${{ matrix.vec.qtip }}${{ matrix.vec.systemcrypto }}${{ matrix.vec.sanitize }}
220+
name: BVT-${{ matrix.vec.config }}-${{ matrix.vec.plat }}-${{ matrix.vec.os }}-${{ matrix.vec.arch }}-${{ matrix.vec.tls }}${{ matrix.vec.xdp }}${{ matrix.vec.iouring }}${{ matrix.vec.qtip }}${{ matrix.vec.xdpmapmode }}${{ matrix.vec.systemcrypto }}${{ matrix.vec.sanitize }}
215221
path: artifacts
216222

217223
bvt-kernel:

scripts/run-gtest.ps1

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ as necessary.
6262
.PARAMETER DuoNic
6363
Uses DuoNic instead of loopback.
6464
65+
.PARAMETER XdpMapMode
66+
Uses XDP map mode with DuoNic.
67+
6568
#>
6669

6770
param (
@@ -133,6 +136,9 @@ param (
133136
[Parameter(Mandatory = $false)]
134137
[switch]$DuoNic = $false,
135138

139+
[Parameter(Mandatory = $false)]
140+
[switch]$XdpMapMode = $false,
141+
136142
[Parameter(Mandatory = $false)]
137143
[string]$OsRunner = "",
138144

@@ -403,6 +409,9 @@ function Start-TestCase([String]$Name) {
403409
if ($DuoNic) {
404410
$Arguments += " --duoNic"
405411
}
412+
if ($XdpMapMode) {
413+
$Arguments += " --xdpMapMode"
414+
}
406415
if ($UseQtip) {
407416
$Arguments += " --useQTIP"
408417
}
@@ -450,6 +459,9 @@ function Start-AllTestCases {
450459
if ($DuoNic) {
451460
$Arguments += " --duoNic"
452461
}
462+
if ($XdpMapMode) {
463+
$Arguments += " --xdpMapMode"
464+
}
453465
if ($UseQtip) {
454466
$Arguments += " --useQTIP"
455467
}

scripts/test.ps1

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ This script runs the MsQuic tests.
7070
.Parameter DuoNic
7171
Uses DuoNic instead of loopback (DuoNic must already be installed via 'prepare-machine.ps1 -InstallDuoNic').
7272
73+
.Parameter XdpMapMode
74+
Uses XDP map mode with DuoNic (Windows user-mode only, requires XDP + DuoNic).
75+
7376
.Parameter NumIterations
7477
Number of times to run this particular command. Catches tricky edge cases due to random nature of networks.
7578
@@ -178,6 +181,9 @@ param (
178181
[Parameter(Mandatory = $false)]
179182
[switch]$DuoNic = $false,
180183

184+
[Parameter(Mandatory = $false)]
185+
[switch]$XdpMapMode = $false,
186+
181187
[Parameter(Mandatory = $false)]
182188
[string]$UseXdp = "",
183189

@@ -230,9 +236,14 @@ $Tls = $BuildConfig.Tls
230236
$Arch = $BuildConfig.Arch
231237
$RootArtifactDir = $BuildConfig.ArtifactsDir
232238

239+
if ($XdpMapMode) {
240+
if ([string]::IsNullOrEmpty($UseXdp)) {
241+
Write-Error "-XdpMapMode requires -UseXdp to specify an XDP version (e.g. 'xdp-prerelease')."
242+
}
243+
}
244+
233245
if ($UseXdp) {
234-
# Helper for XDP usage (every XDP version runs over the same datapath; only
235-
# the installed driver differs).
246+
# XDP usage (and map mode) implies DuoNic.
236247
$DuoNic = $true
237248
}
238249

@@ -299,6 +310,9 @@ $TestArguments = "-IsolationMode $IsolationMode -PfxPath $PfxFile"
299310
if ($DuoNic) {
300311
$TestArguments += " -DuoNic"
301312
}
313+
if ($XdpMapMode) {
314+
$TestArguments += " -XdpMapMode"
315+
}
302316
if ($Kernel) {
303317
$TestArguments += " -Kernel $KernelPath"
304318
}

scripts/update-sidecar.ps1

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,15 @@ if (Test-Path $OutputDir) {
3333
}
3434
}
3535

36+
$TmpOutputDir = Join-Path $RootDir "build" "tmp"
37+
38+
# Clean stale generated files so removed/renamed sources don't leave orphans
39+
if (Test-Path $TmpOutputDir) {
40+
Remove-Item $TmpOutputDir -Recurse -Force
41+
}
42+
3643
$Sidecar = Join-Path $SrcDir "manifest" "clog.sidecar"
3744
$ConfigFile = Join-Path $SrcDir "manifest" "msquic.clog_config"
38-
39-
$TmpOutputDir = Join-Path $RootDir "build" "tmp"
4045
$ClogDir = Join-Path $RootDir "build" "clog"
4146

4247
# Create directories

src/core/library.c

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -915,6 +915,8 @@ QuicLibraryLazyInitialize(
915915

916916
CXPLAT_DATAPATH_INIT_CONFIG InitConfig = {0};
917917
InitConfig.EnableDscpOnRecv = MsQuicLib.EnableDscpOnRecv;
918+
InitConfig.XdpMapConfigs = MsQuicLib.XdpMapConfigs;
919+
InitConfig.XdpMapConfigCount = MsQuicLib.XdpMapConfigCount;
918920

919921
Status =
920922
CxPlatDataPathInitialize(
@@ -1057,6 +1059,34 @@ QuicLibApplyLoadBalancingSetting(
10571059
MsQuicLib.CidTotalLength);
10581060
}
10591061

1062+
static
1063+
void
1064+
QuicLibXdpMapConfigToPlat(
1065+
_Out_writes_(Count) CXPLAT_XDP_MAP_CONFIG* Dest,
1066+
_In_reads_(Count) const QUIC_XDP_MAP_CONFIG* Src,
1067+
_In_ uint32_t Count
1068+
)
1069+
{
1070+
for (uint32_t i = 0; i < Count; i++) {
1071+
Dest[i].InterfaceIndex = Src[i].InterfaceIndex;
1072+
Dest[i].MapHandle = Src[i].MapHandle;
1073+
}
1074+
}
1075+
1076+
static
1077+
void
1078+
QuicLibXdpMapConfigFromPlat(
1079+
_Out_writes_(Count) QUIC_XDP_MAP_CONFIG* Dest,
1080+
_In_reads_(Count) const CXPLAT_XDP_MAP_CONFIG* Src,
1081+
_In_ uint32_t Count
1082+
)
1083+
{
1084+
for (uint32_t i = 0; i < Count; i++) {
1085+
Dest[i].InterfaceIndex = Src[i].InterfaceIndex;
1086+
Dest[i].MapHandle = Src[i].MapHandle;
1087+
}
1088+
}
1089+
10601090
_IRQL_requires_max_(PASSIVE_LEVEL)
10611091
QUIC_STATUS
10621092
QuicLibrarySetGlobalParam(
@@ -1473,20 +1503,23 @@ QuicLibrarySetGlobalParam(
14731503
break;
14741504
}
14751505

1476-
QUIC_XDP_MAP_CONFIG* NewConfigs =
1477-
CXPLAT_ALLOC_NONPAGED(BufferLength, QUIC_POOL_XDP_MAP_CONFIG);
1506+
const size_t AllocSize = Count * sizeof(CXPLAT_XDP_MAP_CONFIG);
1507+
CXPLAT_XDP_MAP_CONFIG* NewConfigs =
1508+
CXPLAT_ALLOC_NONPAGED(
1509+
AllocSize,
1510+
QUIC_POOL_XDP_MAP_CONFIG);
14781511
if (NewConfigs == NULL) {
14791512
CxPlatLockRelease(&MsQuicLib.Lock);
14801513
QuicTraceEvent(
14811514
AllocFailure,
14821515
"Allocation of '%s' failed. (%llu bytes)",
14831516
"XDP map config",
1484-
BufferLength);
1517+
AllocSize);
14851518
Status = QUIC_STATUS_OUT_OF_MEMORY;
14861519
break;
14871520
}
14881521

1489-
CxPlatCopyMemory(NewConfigs, Configs, BufferLength);
1522+
QuicLibXdpMapConfigToPlat(NewConfigs, Configs, Count);
14901523

14911524
if (MsQuicLib.XdpMapConfigs != NULL) {
14921525
CXPLAT_FREE(MsQuicLib.XdpMapConfigs, QUIC_POOL_XDP_MAP_CONFIG);
@@ -1507,6 +1540,7 @@ QuicLibrarySetGlobalParam(
15071540
}
15081541

15091542
_IRQL_requires_max_(PASSIVE_LEVEL)
1543+
_Success_(return == QUIC_STATUS_SUCCESS)
15101544
QUIC_STATUS
15111545
QuicLibraryGetGlobalParam(
15121546
_In_ uint32_t Param,
@@ -1871,7 +1905,10 @@ QuicLibraryGetGlobalParam(
18711905
break;
18721906
}
18731907
*BufferLength = RequiredLength;
1874-
CxPlatCopyMemory(Buffer, MsQuicLib.XdpMapConfigs, RequiredLength);
1908+
QuicLibXdpMapConfigFromPlat(
1909+
(QUIC_XDP_MAP_CONFIG*)Buffer,
1910+
MsQuicLib.XdpMapConfigs,
1911+
MsQuicLib.XdpMapConfigCount);
18751912
CxPlatLockRelease(&MsQuicLib.Lock);
18761913
Status = QUIC_STATUS_SUCCESS;
18771914
break;

src/core/library.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ typedef struct QUIC_LIBRARY {
208208
// Set via QUIC_PARAM_GLOBAL_XDP_MAP_CONFIG before any registration.
209209
// May be updated multiple times before the first registration is opened.
210210
//
211-
const QUIC_XDP_MAP_CONFIG* XdpMapConfigs;
211+
const CXPLAT_XDP_MAP_CONFIG* XdpMapConfigs;
212212
uint32_t XdpMapConfigCount;
213213

214214
//
@@ -538,6 +538,7 @@ QuicLibrarySetGlobalParam(
538538
);
539539

540540
_IRQL_requires_max_(PASSIVE_LEVEL)
541+
_Success_(return == QUIC_STATUS_SUCCESS)
541542
QUIC_STATUS
542543
QuicLibraryGetGlobalParam(
543544
_In_ uint32_t Param,

src/core/settings.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -712,6 +712,18 @@ QuicSettingApply(
712712
Destination->IsSet.ReliableResetEnabled = TRUE;
713713
}
714714

715+
//
716+
// If XDP map mode is active (XdpMapConfigCount > 0), XDP is implicitly
717+
// enabled for all sockets. Reject an explicit XdpEnabled = FALSE since
718+
// it contradicts map mode — there is no OS datapath to fall back to.
719+
//
720+
if (Source->IsSet.XdpEnabled && !Source->XdpEnabled && MsQuicLib.XdpMapConfigCount > 0) {
721+
QuicTraceLogError(
722+
SettingXdpDisabledInMapMode,
723+
"[ lib] Error: Xdp must be enabled when an XDP map was configured.");
724+
return FALSE;
725+
}
726+
715727
if (Source->IsSet.XdpEnabled && (!Destination->IsSet.XdpEnabled || OverWrite)) {
716728
Destination->XdpEnabled = Source->XdpEnabled;
717729
Destination->IsSet.XdpEnabled = TRUE;

src/generated/linux/datapath_raw.c.clog.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,35 @@
1414
#include "datapath_raw.c.clog.h.lttng.h"
1515
#endif
1616
#include <lttng/tracepoint-event.h>
17+
#ifndef _clog_MACRO_QuicTraceLogVerbose
18+
#define _clog_MACRO_QuicTraceLogVerbose 1
19+
#define QuicTraceLogVerbose(a, ...) _clog_CAT(_clog_ARGN_SELECTOR(__VA_ARGS__), _clog_CAT(_,a(#a, __VA_ARGS__)))
20+
#endif
1721
#ifndef _clog_MACRO_QuicTraceEvent
1822
#define _clog_MACRO_QuicTraceEvent 1
1923
#define QuicTraceEvent(a, ...) _clog_CAT(_clog_ARGN_SELECTOR(__VA_ARGS__), _clog_CAT(_,a(#a, __VA_ARGS__)))
2024
#endif
2125
#ifdef __cplusplus
2226
extern "C" {
2327
#endif
28+
/*----------------------------------------------------------
29+
// Decoder Ring for DatapathRawMapInsertFail
30+
// [ dp] XDP map mode: failed to insert XSK sockets into map, status:%d
31+
// QuicTraceLogVerbose(
32+
DatapathRawMapInsertFail,
33+
"[ dp] XDP map mode: failed to insert XSK sockets into map, status:%d",
34+
Status);
35+
// arg2 = arg2 = Status = arg2
36+
----------------------------------------------------------*/
37+
#ifndef _clog_3_ARGS_TRACE_DatapathRawMapInsertFail
38+
#define _clog_3_ARGS_TRACE_DatapathRawMapInsertFail(uniqueId, encoded_arg_string, arg2)\
39+
tracepoint(CLOG_DATAPATH_RAW_C, DatapathRawMapInsertFail , arg2);\
40+
41+
#endif
42+
43+
44+
45+
2446
/*----------------------------------------------------------
2547
// Decoder Ring for AllocFailure
2648
// Allocation of '%s' failed. (%llu bytes)

src/generated/linux/datapath_raw.c.clog.h.lttng.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,25 @@
11

22

33

4+
/*----------------------------------------------------------
5+
// Decoder Ring for DatapathRawMapInsertFail
6+
// [ dp] XDP map mode: failed to insert XSK sockets into map, status:%d
7+
// QuicTraceLogVerbose(
8+
DatapathRawMapInsertFail,
9+
"[ dp] XDP map mode: failed to insert XSK sockets into map, status:%d",
10+
Status);
11+
// arg2 = arg2 = Status = arg2
12+
----------------------------------------------------------*/
13+
TRACEPOINT_EVENT(CLOG_DATAPATH_RAW_C, DatapathRawMapInsertFail,
14+
TP_ARGS(
15+
int, arg2),
16+
TP_FIELDS(
17+
ctf_integer(int, arg2, arg2)
18+
)
19+
)
20+
21+
22+
423
/*----------------------------------------------------------
524
// Decoder Ring for AllocFailure
625
// Allocation of '%s' failed. (%llu bytes)

0 commit comments

Comments
 (0)