Skip to content

Commit 5e5b7ae

Browse files
Pass CIBIR ID to XDP (#2479)
Co-authored-by: Matt Olson <maolson@microsoft.com>
1 parent 0c46907 commit 5e5b7ae

File tree

7 files changed

+162
-54
lines changed

7 files changed

+162
-54
lines changed

scripts/prepare-machine.ps1

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,10 @@ param (
6666
[switch]$NoCodeCoverage,
6767

6868
[Parameter(Mandatory = $false)]
69-
[switch]$Xdp
69+
[switch]$Xdp,
70+
71+
[Parameter(Mandatory = $false)]
72+
[switch]$Force
7073
)
7174

7275
#Requires -RunAsAdministrator
@@ -137,12 +140,13 @@ function Download-CoreNet-Deps {
137140
}
138141

139142
function Download-Xdp-Kit {
143+
if ($Force) { rm -Force -Recurse $ArtifactsPath }
140144
if (!(Test-Path $ArtifactsPath)) { mkdir $ArtifactsPath }
141145
$XdpPath = Join-Path $ArtifactsPath "xdp"
142146
if (!(Test-Path $XdpPath)) {
143147
Write-Host "Downloading XDP Kit"
144148
$ZipPath = Join-Path $ArtifactsPath "xdp.zip"
145-
Invoke-WebRequest -Uri "https://lolafiles.blob.core.windows.net/nibanks/xdp.zip" -OutFile $ZipPath
149+
Invoke-WebRequest -Uri "https://lolafiles.blob.core.windows.net/nibanks/xdp-latest.zip" -OutFile $ZipPath
146150
Expand-Archive -Path $ZipPath -DestinationPath $XdpPath -Force
147151
Remove-Item -Path $ZipPath
148152
}

src/core/listener.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,18 @@ MsQuicListenerStart(
303303
#ifdef QUIC_OWNING_PROCESS
304304
UdpConfig.OwningProcess = NULL; // Owning process not supported for listeners.
305305
#endif
306+
#ifdef QUIC_USE_RAW_DATAPATH
307+
UdpConfig.CibirIdLength = Listener->CibirId[0];
308+
UdpConfig.CibirIdOffsetSrc = MsQuicLib.CidServerIdLength + 2;
309+
UdpConfig.CibirIdOffsetDst = MsQuicLib.CidServerIdLength + 2;
310+
if (UdpConfig.CibirIdLength) {
311+
CXPLAT_DBG_ASSERT(UdpConfig.CibirIdLength <= sizeof(UdpConfig.CibirId));
312+
CxPlatCopyMemory(
313+
UdpConfig.CibirId,
314+
&Listener->CibirId[2],
315+
UdpConfig.CibirIdLength);
316+
}
317+
#endif
306318

307319
CXPLAT_TEL_ASSERT(Listener->Binding == NULL);
308320
Status =

src/inc/quic_datapath.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,12 @@ typedef struct CXPLAT_UDP_CONFIG {
466466
#ifdef QUIC_OWNING_PROCESS
467467
QUIC_PROCESS OwningProcess; // Kernel client-only
468468
#endif
469+
#ifdef QUIC_USE_RAW_DATAPATH
470+
uint8_t CibirIdLength; // CIBIR ID length. Value of 0 indicates CIBIR isn't used
471+
uint8_t CibirIdOffsetSrc; // CIBIR ID offset in source CID
472+
uint8_t CibirIdOffsetDst; // CIBIR ID offset in destination CID
473+
uint8_t CibirId[6]; // CIBIR ID data
474+
#endif
469475
} CXPLAT_UDP_CONFIG;
470476

471477
//

src/platform/datapath_raw.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,12 @@ CxPlatSocketCreateUdp(
286286
CxPlatRundownInitialize(&(*NewSocket)->Rundown);
287287
(*NewSocket)->Datapath = Datapath;
288288
(*NewSocket)->CallbackContext = Config->CallbackContext;
289+
(*NewSocket)->CibirIdLength = Config->CibirIdLength;
290+
(*NewSocket)->CibirIdOffsetSrc = Config->CibirIdOffsetSrc;
291+
(*NewSocket)->CibirIdOffsetDst = Config->CibirIdOffsetDst;
292+
if (Config->CibirIdLength) {
293+
memcpy((*NewSocket)->CibirId, Config->CibirId, Config->CibirIdLength);
294+
}
289295

290296
if (Config->RemoteAddress) {
291297
CXPLAT_FRE_ASSERT(!QuicAddrIsWildCard(Config->RemoteAddress)); // No wildcard remote addresses allowed.

src/platform/datapath_raw.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -256,8 +256,13 @@ typedef struct CXPLAT_SOCKET {
256256
void* CallbackContext;
257257
QUIC_ADDR LocalAddress;
258258
QUIC_ADDR RemoteAddress;
259-
BOOLEAN Wildcard; // Using a wildcard local address. Optimization to avoid always reading LocalAddress.
260-
BOOLEAN Connected; // Bound to a remote address
259+
BOOLEAN Wildcard; // Using a wildcard local address. Optimization
260+
// to avoid always reading LocalAddress.
261+
BOOLEAN Connected; // Bound to a remote address
262+
uint8_t CibirIdLength; // CIBIR ID length. Value of 0 indicates CIBIR isn't used
263+
uint8_t CibirIdOffsetSrc; // CIBIR ID offset in source CID
264+
uint8_t CibirIdOffsetDst; // CIBIR ID offset in destination CID
265+
uint8_t CibirId[6]; // CIBIR ID data
261266

262267
} CXPLAT_SOCKET;
263268

src/platform/datapath_raw_socket.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,27 @@ CxPlatTryAddSocket(
144144
goto Error;
145145
}
146146

147+
if (Socket->CibirIdLength) {
148+
Option = TRUE;
149+
Result =
150+
setsockopt(
151+
Socket->AuxSocket,
152+
SOL_SOCKET,
153+
SO_REUSEADDR,
154+
(char*)&Option,
155+
sizeof(Option));
156+
if (Result == SOCKET_ERROR) {
157+
int Error = SocketError();
158+
QuicTraceEvent(
159+
DatapathErrorStatus,
160+
"[data][%p] ERROR, %u, %s.",
161+
Socket,
162+
Error,
163+
"Set SO_REUSEADDR");
164+
goto Error;
165+
}
166+
}
167+
147168
CxPlatConvertToMappedV6(&Socket->LocalAddress, &MappedAddress);
148169
#if QUIC_ADDRESS_FAMILY_INET6 != AF_INET6
149170
if (MappedAddress.Ipv6.sin6_family == QUIC_ADDRESS_FAMILY_INET6) {

src/platform/datapath_raw_xdp.c

Lines changed: 104 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -755,7 +755,7 @@ CxPlatDpRawInterfaceUpdateRules(
755755
.SubLayer = XDP_HOOK_INSPECT,
756756
};
757757

758-
const UINT32 Flags = 0; // TODO: support native/generic forced flags.
758+
const UINT32 Flags = XDP_CREATE_PROGRAM_FLAG_SHARE; // TODO: support native/generic forced flags.
759759

760760
for (uint32_t i = 0; i < Interface->QueueCount; i++) {
761761

@@ -798,9 +798,10 @@ CxPlatDpRawInterfaceUpdateRules(
798798

799799
_IRQL_requires_max_(PASSIVE_LEVEL)
800800
void
801-
CxPlatDpRawInterfaceAddRule(
801+
CxPlatDpRawInterfaceAddRules(
802802
_In_ XDP_INTERFACE* Interface,
803-
_In_ const XDP_RULE* NewRule
803+
_In_reads_(Count) const XDP_RULE* Rules,
804+
_In_ uint8_t Count
804805
)
805806
{
806807
#pragma warning(push)
@@ -809,7 +810,7 @@ CxPlatDpRawInterfaceAddRule(
809810
CxPlatLockAcquire(&Interface->RuleLock);
810811
// TODO - Don't always allocate a new array?
811812

812-
if (Interface->RuleCount + 1 == 0) {
813+
if ((uint32_t)Interface->RuleCount + (uint32_t)Count > UINT8_MAX) {
813814
QuicTraceEvent(
814815
LibraryError,
815816
"[ lib] ERROR, %s.",
@@ -819,7 +820,7 @@ CxPlatDpRawInterfaceAddRule(
819820
}
820821

821822
const size_t OldSize = sizeof(XDP_RULE) * (size_t)Interface->RuleCount;
822-
const size_t NewSize = sizeof(XDP_RULE) * ((size_t)Interface->RuleCount + 1);
823+
const size_t NewSize = sizeof(XDP_RULE) * ((size_t)Interface->RuleCount + Count);
823824

824825
XDP_RULE* NewRules = CxPlatAlloc(NewSize, RULE_TAG);
825826
if (NewRules == NULL) {
@@ -835,8 +836,9 @@ CxPlatDpRawInterfaceAddRule(
835836
if (Interface->RuleCount > 0) {
836837
memcpy(NewRules, Interface->Rules, OldSize);
837838
}
838-
NewRules[Interface->RuleCount] = *NewRule;
839-
Interface->RuleCount++;
839+
for (uint8_t i = 0; i < Count; i++) {
840+
NewRules[Interface->RuleCount++] = Rules[i];
841+
}
840842

841843
if (Interface->Rules != NULL) {
842844
CxPlatFree(Interface->Rules, RULE_TAG);
@@ -852,46 +854,62 @@ CxPlatDpRawInterfaceAddRule(
852854

853855
_IRQL_requires_max_(PASSIVE_LEVEL)
854856
void
855-
CxPlatDpRawInterfaceRemoveRule(
857+
CxPlatDpRawInterfaceRemoveRules(
856858
_In_ XDP_INTERFACE* Interface,
857-
_In_ const XDP_RULE* Rule
859+
_In_reads_(Count) const XDP_RULE* Rules,
860+
_In_ uint8_t Count
858861
)
859862
{
860863
CxPlatLockAcquire(&Interface->RuleLock);
861864

862-
for (uint8_t i = 0; i < Interface->RuleCount; i++) {
863-
if (Interface->Rules[i].Match != Rule->Match) {
864-
continue;
865-
}
865+
BOOLEAN UpdateRules = FALSE;
866866

867-
if (Rule->Match == XDP_MATCH_UDP_DST) {
868-
if (Rule->Pattern.Port != Interface->Rules[i].Pattern.Port) {
867+
for (uint8_t j = 0; j < Count; j++) {
868+
for (uint8_t i = 0; i < Interface->RuleCount; i++) {
869+
if (Interface->Rules[i].Match != Rules[j].Match) {
869870
continue;
870871
}
871-
} else if (Rule->Match == XDP_MATCH_IPV4_UDP_TUPLE) {
872-
if (Rule->Pattern.Tuple.DestinationPort != Interface->Rules[i].Pattern.Tuple.DestinationPort ||
873-
Rule->Pattern.Tuple.SourcePort != Interface->Rules[i].Pattern.Tuple.SourcePort ||
874-
memcmp(&Rule->Pattern.Tuple.DestinationAddress.Ipv4, &Interface->Rules[i].Pattern.Tuple.DestinationAddress.Ipv4, sizeof(IN_ADDR)) != 0 ||
875-
memcmp(&Rule->Pattern.Tuple.SourceAddress.Ipv4, &Interface->Rules[i].Pattern.Tuple.SourceAddress.Ipv4, sizeof(IN_ADDR)) != 0) {
876-
continue;
872+
873+
if (Rules[j].Match == XDP_MATCH_UDP_DST) {
874+
if (Rules[j].Pattern.Port != Interface->Rules[i].Pattern.Port) {
875+
continue;
876+
}
877+
} else if (Rules[j].Match == XDP_MATCH_QUIC_FLOW_SRC_CID || Rules[j].Match == XDP_MATCH_QUIC_FLOW_DST_CID) {
878+
if (Rules[j].Pattern.QuicFlow.UdpPort != Interface->Rules[i].Pattern.QuicFlow.UdpPort ||
879+
Rules[j].Pattern.QuicFlow.CidLength != Interface->Rules[i].Pattern.QuicFlow.CidLength ||
880+
Rules[j].Pattern.QuicFlow.CidOffset != Interface->Rules[i].Pattern.QuicFlow.CidOffset ||
881+
memcmp(Rules[j].Pattern.QuicFlow.CidData, Interface->Rules[i].Pattern.QuicFlow.CidData, Rules[j].Pattern.QuicFlow.CidLength) != 0) {
882+
continue;
883+
}
884+
} else if (Rules[j].Match == XDP_MATCH_IPV4_UDP_TUPLE) {
885+
if (Rules[j].Pattern.Tuple.DestinationPort != Interface->Rules[i].Pattern.Tuple.DestinationPort ||
886+
Rules[j].Pattern.Tuple.SourcePort != Interface->Rules[i].Pattern.Tuple.SourcePort ||
887+
memcmp(&Rules[j].Pattern.Tuple.DestinationAddress.Ipv4, &Interface->Rules[i].Pattern.Tuple.DestinationAddress.Ipv4, sizeof(IN_ADDR)) != 0 ||
888+
memcmp(&Rules[j].Pattern.Tuple.SourceAddress.Ipv4, &Interface->Rules[i].Pattern.Tuple.SourceAddress.Ipv4, sizeof(IN_ADDR)) != 0) {
889+
continue;
890+
}
891+
} else if (Rules[j].Match == XDP_MATCH_IPV6_UDP_TUPLE) {
892+
if (Rules[j].Pattern.Tuple.DestinationPort != Interface->Rules[i].Pattern.Tuple.DestinationPort ||
893+
Rules[j].Pattern.Tuple.SourcePort != Interface->Rules[i].Pattern.Tuple.SourcePort ||
894+
memcmp(&Rules[j].Pattern.Tuple.DestinationAddress.Ipv6, &Interface->Rules[i].Pattern.Tuple.DestinationAddress.Ipv6, sizeof(IN6_ADDR)) != 0 ||
895+
memcmp(&Rules[j].Pattern.Tuple.SourceAddress.Ipv6, &Interface->Rules[i].Pattern.Tuple.SourceAddress.Ipv6, sizeof(IN6_ADDR)) != 0) {
896+
continue;
897+
}
898+
} else {
899+
CXPLAT_FRE_ASSERT(FALSE); // Should not be possible!
877900
}
878-
} else if (Rule->Match == XDP_MATCH_IPV6_UDP_TUPLE) {
879-
if (Rule->Pattern.Tuple.DestinationPort != Interface->Rules[i].Pattern.Tuple.DestinationPort ||
880-
Rule->Pattern.Tuple.SourcePort != Interface->Rules[i].Pattern.Tuple.SourcePort ||
881-
memcmp(&Rule->Pattern.Tuple.DestinationAddress.Ipv6, &Interface->Rules[i].Pattern.Tuple.DestinationAddress.Ipv6, sizeof(IN6_ADDR)) != 0 ||
882-
memcmp(&Rule->Pattern.Tuple.SourceAddress.Ipv6, &Interface->Rules[i].Pattern.Tuple.SourceAddress.Ipv6, sizeof(IN6_ADDR)) != 0) {
883-
continue;
901+
902+
if (i < Interface->RuleCount - 1) {
903+
memmove(&Interface->Rules[i], &Interface->Rules[i + 1], sizeof(XDP_RULE) * (Interface->RuleCount - i - 1));
884904
}
885-
} else {
886-
CXPLAT_FRE_ASSERT(FALSE); // Should not be possible!
905+
Interface->RuleCount--;
906+
UpdateRules = TRUE;
907+
break;
887908
}
909+
}
888910

889-
if (i < Interface->RuleCount - 1) {
890-
memmove(&Interface->Rules[i], &Interface->Rules[i + 1], sizeof(XDP_RULE) * (Interface->RuleCount - i - 1));
891-
}
892-
Interface->RuleCount--;
911+
if (UpdateRules) {
893912
CxPlatDpRawInterfaceUpdateRules(Interface);
894-
break;
895913
}
896914

897915
CxPlatLockRelease(&Interface->RuleLock);
@@ -1052,21 +1070,57 @@ CxPlatDpRawPlumbRulesOnSocket(
10521070
XDP_DATAPATH* Xdp = (XDP_DATAPATH*)Socket->Datapath;
10531071

10541072
if (Socket->Wildcard) {
1055-
const XDP_RULE Rule = {
1056-
.Match = XDP_MATCH_UDP_DST,
1057-
.Pattern.Port = Socket->LocalAddress.Ipv4.sin_port,
1058-
.Action = XDP_PROGRAM_ACTION_REDIRECT,
1059-
.Redirect.TargetType = XDP_REDIRECT_TARGET_TYPE_XSK,
1060-
.Redirect.Target = NULL,
1061-
};
10621073

1063-
CXPLAT_LIST_ENTRY* Entry;
1064-
for (Entry = Xdp->Interfaces.Flink; Entry != &Xdp->Interfaces; Entry = Entry->Flink) {
1065-
XDP_INTERFACE* Interface = CONTAINING_RECORD(Entry, XDP_INTERFACE, Link);
1066-
if (IsCreated) {
1067-
CxPlatDpRawInterfaceAddRule(Interface, &Rule);
1068-
} else {
1069-
CxPlatDpRawInterfaceRemoveRule(Interface, &Rule);
1074+
if (Socket->CibirIdLength) {
1075+
XDP_RULE Rules[] = {
1076+
{
1077+
.Match = XDP_MATCH_QUIC_FLOW_SRC_CID,
1078+
.Pattern.QuicFlow.UdpPort = Socket->LocalAddress.Ipv4.sin_port,
1079+
.Pattern.QuicFlow.CidLength = Socket->CibirIdLength,
1080+
.Pattern.QuicFlow.CidOffset = Socket->CibirIdOffsetSrc,
1081+
.Action = XDP_PROGRAM_ACTION_REDIRECT,
1082+
.Redirect.TargetType = XDP_REDIRECT_TARGET_TYPE_XSK,
1083+
.Redirect.Target = NULL,
1084+
},
1085+
{
1086+
.Match = XDP_MATCH_QUIC_FLOW_DST_CID,
1087+
.Pattern.QuicFlow.UdpPort = Socket->LocalAddress.Ipv4.sin_port,
1088+
.Pattern.QuicFlow.CidLength = Socket->CibirIdLength,
1089+
.Pattern.QuicFlow.CidOffset = Socket->CibirIdOffsetDst,
1090+
.Action = XDP_PROGRAM_ACTION_REDIRECT,
1091+
.Redirect.TargetType = XDP_REDIRECT_TARGET_TYPE_XSK,
1092+
.Redirect.Target = NULL,
1093+
}
1094+
};
1095+
memcpy(Rules[0].Pattern.QuicFlow.CidData, Socket->CibirId, Socket->CibirIdLength);
1096+
memcpy(Rules[1].Pattern.QuicFlow.CidData, Socket->CibirId, Socket->CibirIdLength);
1097+
1098+
CXPLAT_LIST_ENTRY* Entry;
1099+
for (Entry = Xdp->Interfaces.Flink; Entry != &Xdp->Interfaces; Entry = Entry->Flink) {
1100+
XDP_INTERFACE* Interface = CONTAINING_RECORD(Entry, XDP_INTERFACE, Link);
1101+
if (IsCreated) {
1102+
CxPlatDpRawInterfaceAddRules(Interface, Rules, 2);
1103+
} else {
1104+
CxPlatDpRawInterfaceRemoveRules(Interface, Rules, 2);
1105+
}
1106+
}
1107+
} else {
1108+
const XDP_RULE Rule = {
1109+
.Match = XDP_MATCH_UDP_DST,
1110+
.Pattern.Port = Socket->LocalAddress.Ipv4.sin_port,
1111+
.Action = XDP_PROGRAM_ACTION_REDIRECT,
1112+
.Redirect.TargetType = XDP_REDIRECT_TARGET_TYPE_XSK,
1113+
.Redirect.Target = NULL,
1114+
};
1115+
1116+
CXPLAT_LIST_ENTRY* Entry;
1117+
for (Entry = Xdp->Interfaces.Flink; Entry != &Xdp->Interfaces; Entry = Entry->Flink) {
1118+
XDP_INTERFACE* Interface = CONTAINING_RECORD(Entry, XDP_INTERFACE, Link);
1119+
if (IsCreated) {
1120+
CxPlatDpRawInterfaceAddRules(Interface, &Rule, 1);
1121+
} else {
1122+
CxPlatDpRawInterfaceRemoveRules(Interface, &Rule, 1);
1123+
}
10701124
}
10711125
}
10721126

@@ -1098,9 +1152,9 @@ CxPlatDpRawPlumbRulesOnSocket(
10981152
for (Entry = Xdp->Interfaces.Flink; Entry != &Xdp->Interfaces; Entry = Entry->Flink) {
10991153
XDP_INTERFACE* Interface = CONTAINING_RECORD(Entry, XDP_INTERFACE, Link);
11001154
if (IsCreated) {
1101-
CxPlatDpRawInterfaceAddRule(Interface, &Rule);
1155+
CxPlatDpRawInterfaceAddRules(Interface, &Rule, 1);
11021156
} else {
1103-
CxPlatDpRawInterfaceRemoveRule(Interface, &Rule);
1157+
CxPlatDpRawInterfaceRemoveRules(Interface, &Rule, 1);
11041158
}
11051159
}
11061160
}

0 commit comments

Comments
 (0)