Skip to content

Commit e08fd6e

Browse files
authored
Fix DSCP detection on Windows. Add DSCP support to SecNetPerf (#5130)
* Fix DSCP detection on Windows. Add DSCP support to SecNetPerf * Add TypeOfService/TrafficClass on receive to test DSCP * Don't attempt to receive TOS/TCLASS on Windows Server 2022 * Also mark epoll and raw datapaths as supporting recv DSCP
1 parent 04b7537 commit e08fd6e

File tree

11 files changed

+232
-96
lines changed

11 files changed

+232
-96
lines changed

src/inc/quic_datapath.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,7 @@ typedef enum CXPLAT_DATAPATH_FEATURES {
436436
CXPLAT_DATAPATH_FEATURE_TTL = 0x00000080,
437437
CXPLAT_DATAPATH_FEATURE_SEND_DSCP = 0x00000100,
438438
CXPLAT_DATAPATH_FEATURE_RIO = 0x00000200,
439+
CXPLAT_DATAPATH_FEATURE_RECV_DSCP = 0x00000400,
439440
} CXPLAT_DATAPATH_FEATURES;
440441

441442
DEFINE_ENUM_FLAG_OPERATORS(CXPLAT_DATAPATH_FEATURES)

src/perf/lib/PerfClient.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,20 @@ PerfClientConnection::Initialize() {
535535
}
536536
}
537537

538+
if (PerfDefaultDscpValue != 0) {
539+
Status =
540+
MsQuic->SetParam(
541+
Handle,
542+
QUIC_PARAM_CONN_SEND_DSCP,
543+
sizeof(PerfDefaultDscpValue),
544+
&PerfDefaultDscpValue);
545+
if (QUIC_FAILED(Status)) {
546+
WriteOutput("SetSendDscp failed, 0x%x\n", Status);
547+
Worker.ConnectionPool.Free(this);
548+
return;
549+
}
550+
}
551+
538552
if (Client.CibirIdLength) {
539553
Status =
540554
MsQuic->SetParam(

src/perf/lib/PerfServer.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,13 @@ PerfServer::ListenerCallback(
183183
if (Event->Type == QUIC_LISTENER_EVENT_NEW_CONNECTION) {
184184
BOOLEAN value = TRUE;
185185
MsQuic->SetParam(Event->NEW_CONNECTION.Connection, QUIC_PARAM_CONN_DISABLE_1RTT_ENCRYPTION, sizeof(value), &value);
186+
if (PerfDefaultDscpValue != 0) {
187+
MsQuic->SetParam(
188+
Event->NEW_CONNECTION.Connection,
189+
QUIC_PARAM_CONN_SEND_DSCP,
190+
sizeof(PerfDefaultDscpValue),
191+
&PerfDefaultDscpValue);
192+
}
186193
QUIC_CONNECTION_CALLBACK_HANDLER Handler =
187194
[](HQUIC Conn, void* Context, QUIC_CONNECTION_EVENT* Event) -> QUIC_STATUS {
188195
return ((PerfServer*)Context)->ConnectionCallback(Conn, Event);

src/perf/lib/SecNetPerf.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ extern uint8_t PerfDefaultEcnEnabled;
5454
extern uint8_t PerfDefaultQeoAllowed;
5555
extern uint8_t PerfDefaultHighPriority;
5656
extern uint8_t PerfDefaultAffinitizeThreads;
57+
extern uint8_t PerfDefaultDscpValue;
5758

5859
extern CXPLAT_DATAPATH* Datapath;
5960

src/perf/lib/SecNetPerfMain.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ uint8_t PerfDefaultEcnEnabled = false;
2929
uint8_t PerfDefaultQeoAllowed = false;
3030
uint8_t PerfDefaultHighPriority = false;
3131
uint8_t PerfDefaultAffinitizeThreads = false;
32+
uint8_t PerfDefaultDscpValue = 0;
3233

3334
#ifdef _KERNEL_MODE
3435
volatile int BufferCurrent;
@@ -142,6 +143,7 @@ PrintHelp(
142143
" -cpu:<cpu_index> Specify the processor(s) to use.\n"
143144
" -cipher:<value> Decimal value of 1 or more QUIC_ALLOWED_CIPHER_SUITE_FLAGS.\n"
144145
" -highpri:<0/1> Configures MsQuic to run threads at high priority. (def:0)\n"
146+
" -dscp:<0-63> Specify DSCP value to mark sent packets with. (def:0)\n"
145147
"\n",
146148
PERF_DEFAULT_PORT,
147149
PERF_DEFAULT_PORT
@@ -290,6 +292,11 @@ QuicMainStart(
290292

291293
TryGetValue(argc, argv, "ecn", &PerfDefaultEcnEnabled);
292294
TryGetValue(argc, argv, "qeo", &PerfDefaultQeoAllowed);
295+
TryGetValue(argc, argv, "dscp", &PerfDefaultDscpValue);
296+
if (PerfDefaultDscpValue > CXPLAT_MAX_DSCP) {
297+
WriteOutput("DSCP Value %u is outside the valid range (0-63). Using 0.\n", PerfDefaultDscpValue);
298+
PerfDefaultDscpValue = 0;
299+
}
293300

294301
uint32_t WatchdogTimeout = 0;
295302
if (TryGetValue(argc, argv, "watchdog", &WatchdogTimeout) && WatchdogTimeout != 0) {

src/perf/readme.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ cibir | `-cibir:<hex_bytes>` | The well-known CIBIR identifier.
2626
cipher | `-cipher:<value>` | Decimal value of 1 or more `QUIC_ALLOWED_CIPHER_SUITE_FLAGS`.
2727
cpu | `-cpu:<cpu_indexes>` | Comma-separated list of CPUs to run on.
2828
ecn | `-ecn:<0,1>` | Enables sender-side ECN support.
29+
dscp | `-dscp:<0-63>` | Sets DSCP value used for outgoing traffic.
2930
exec | `-exec:<lowlat,maxtput,scavenger,realtime>` | The execution profile used for the application.
3031
pollidle | `-pollidle:<time_us>` | The time, in microseconds, to poll while idle before sleeping (falling back to interrupt-driven IO).
3132
stats | `-stats:<0,1>` | Prints out statistics at the end of each connection.
@@ -81,6 +82,7 @@ tcp | `-tcp:<0,1>` | Disables/enables TCP usage (instead of QUIC).
8182
encrypt | `-encrypt:<0,1>` | Disables/enables encryption.
8283
pacing | `-pacing:<0,1>` | Disables/enables send pacing.
8384
sendbuf | `-sendbuf:<0,1>` | Disables/enables send buffering.
85+
dscp | `-dscp:<0-63>` | Sets DSCP value used for outgoing traffic.
8486
ptput | `-ptput:<0,1>` | Print throughput information.
8587
pconnection, pconn | `-pconn:<0,1>` | Print connection statistics.
8688
pstream | `-pstream:<0,1>` | Print stream statistics.

src/platform/datapath_epoll.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,7 @@ CxPlatDataPathCalculateFeatureSupport(
336336
Datapath->Features |= CXPLAT_DATAPATH_FEATURE_TCP;
337337
Datapath->Features |= CXPLAT_DATAPATH_FEATURE_TTL;
338338
Datapath->Features |= CXPLAT_DATAPATH_FEATURE_SEND_DSCP;
339+
Datapath->Features |= CXPLAT_DATAPATH_FEATURE_RECV_DSCP;
339340
}
340341

341342
void

src/platform/datapath_raw.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,8 @@ RawDataPathGetSupportedFeatures(
136136
)
137137
{
138138
UNREFERENCED_PARAMETER(Datapath);
139-
return CXPLAT_DATAPATH_FEATURE_RAW | CXPLAT_DATAPATH_FEATURE_TTL | CXPLAT_DATAPATH_FEATURE_SEND_DSCP;
139+
return CXPLAT_DATAPATH_FEATURE_RAW | CXPLAT_DATAPATH_FEATURE_TTL |
140+
CXPLAT_DATAPATH_FEATURE_SEND_DSCP | CXPLAT_DATAPATH_FEATURE_RECV_DSCP;
140141
}
141142

142143
_IRQL_requires_max_(DISPATCH_LEVEL)

src/platform/datapath_winkernel.c

Lines changed: 90 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -593,7 +593,7 @@ CxPlatDataPathQuerySockoptSupport(
593593
} while (FALSE);
594594

595595
do {
596-
DWORD TypeOfService = 1; // Lower Effort
596+
DWORD TypeOfService = CXPLAT_DSCP_LE << 2;
597597

598598
IoReuseIrp(Irp, STATUS_SUCCESS);
599599
IoSetCompletionRoutine(
@@ -641,10 +641,11 @@ CxPlatDataPathQuerySockoptSupport(
641641
} while (FALSE);
642642

643643
//
644-
// Some USO/URO bug blocks TTL feature support on Windows Server 2022.
644+
// Some USO/URO bug blocks TTL/Recv DSCP feature support on Windows Server 2022.
645645
//
646646
if (CxPlatform.dwBuildNumber != 20348) {
647647
Datapath->Features |= CXPLAT_DATAPATH_FEATURE_TTL;
648+
Datapath->Features |= CXPLAT_DATAPATH_FEATURE_RECV_DSCP;
648649
}
649650

650651
Error:
@@ -1474,42 +1475,82 @@ SocketCreateUdp(
14741475
goto Error;
14751476
}
14761477

1477-
Option = TRUE;
1478-
Status =
1479-
CxPlatDataPathSetControlSocket(
1480-
Binding,
1481-
WskSetOption,
1482-
IPV6_ECN,
1483-
IPPROTO_IPV6,
1484-
sizeof(Option),
1485-
&Option);
1486-
if (QUIC_FAILED(Status)) {
1487-
QuicTraceEvent(
1488-
DatapathErrorStatus,
1489-
"[data][%p] ERROR, %u, %s.",
1490-
Binding,
1491-
Status,
1492-
"Set IPV6_ECN");
1493-
goto Error;
1494-
}
1478+
if (Datapath->Features & CXPLAT_DATAPATH_FEATURE_RECV_DSCP) {
1479+
Option = TRUE;
1480+
Status =
1481+
CxPlatDataPathSetControlSocket(
1482+
Binding,
1483+
WskSetOption,
1484+
IPV6_RECVTCLASS,
1485+
IPPROTO_IPV6,
1486+
sizeof(Option),
1487+
&Option);
1488+
if (QUIC_FAILED(Status)) {
1489+
QuicTraceEvent(
1490+
DatapathErrorStatus,
1491+
"[data][%p] ERROR, %u, %s.",
1492+
Binding,
1493+
Status,
1494+
"Set IPV6_RECVTCLASS");
1495+
goto Error;
1496+
}
14951497

1496-
Option = TRUE;
1497-
Status =
1498-
CxPlatDataPathSetControlSocket(
1499-
Binding,
1500-
WskSetOption,
1501-
IP_ECN,
1502-
IPPROTO_IP,
1503-
sizeof(Option),
1504-
&Option);
1505-
if (QUIC_FAILED(Status)) {
1506-
QuicTraceEvent(
1507-
DatapathErrorStatus,
1508-
"[data][%p] ERROR, %u, %s.",
1509-
Binding,
1510-
Status,
1511-
"Set IP_ECN");
1512-
goto Error;
1498+
Option = TRUE;
1499+
Status =
1500+
CxPlatDataPathSetControlSocket(
1501+
Binding,
1502+
WskSetOption,
1503+
IP_RECVTOS,
1504+
IPPROTO_IP,
1505+
sizeof(Option),
1506+
&Option);
1507+
if (QUIC_FAILED(Status)) {
1508+
QuicTraceEvent(
1509+
DatapathErrorStatus,
1510+
"[data][%p] ERROR, %u, %s.",
1511+
Binding,
1512+
Status,
1513+
"Set IP_RECVTOS");
1514+
goto Error;
1515+
}
1516+
} else {
1517+
Option = TRUE;
1518+
Status =
1519+
CxPlatDataPathSetControlSocket(
1520+
Binding,
1521+
WskSetOption,
1522+
IPV6_ECN,
1523+
IPPROTO_IPV6,
1524+
sizeof(Option),
1525+
&Option);
1526+
if (QUIC_FAILED(Status)) {
1527+
QuicTraceEvent(
1528+
DatapathErrorStatus,
1529+
"[data][%p] ERROR, %u, %s.",
1530+
Binding,
1531+
Status,
1532+
"Set IPV6_ECN");
1533+
goto Error;
1534+
}
1535+
1536+
Option = TRUE;
1537+
Status =
1538+
CxPlatDataPathSetControlSocket(
1539+
Binding,
1540+
WskSetOption,
1541+
IP_ECN,
1542+
IPPROTO_IP,
1543+
sizeof(Option),
1544+
&Option);
1545+
if (QUIC_FAILED(Status)) {
1546+
QuicTraceEvent(
1547+
DatapathErrorStatus,
1548+
"[data][%p] ERROR, %u, %s.",
1549+
Binding,
1550+
Status,
1551+
"Set IP_ECN");
1552+
goto Error;
1553+
}
15131554
}
15141555

15151556
Option = TRUE;
@@ -2036,7 +2077,7 @@ CxPlatDataPathSocketReceive(
20362077
SOCKADDR_INET LocalAddr = { 0 };
20372078
SOCKADDR_INET RemoteAddr;
20382079
UINT16 MessageLength = 0;
2039-
INT ECN = 0;
2080+
INT TypeOfService = 0;
20402081
INT HopLimitTTL = 0;
20412082

20422083
//
@@ -2066,9 +2107,12 @@ CxPlatDataPathSocketReceive(
20662107
IsUnreachableError = TRUE;
20672108
break;
20682109
}
2110+
} else if (CMsg->cmsg_type == IPV6_TCLASS) {
2111+
TypeOfService = *(PINT)WSA_CMSG_DATA(CMsg);
2112+
CXPLAT_DBG_ASSERT(TypeOfService < UINT8_MAX);
20692113
} else if (CMsg->cmsg_type == IPV6_ECN) {
2070-
ECN = *(PINT)WSA_CMSG_DATA(CMsg);
2071-
CXPLAT_DBG_ASSERT(ECN < UINT8_MAX);
2114+
TypeOfService = *(PINT)WSA_CMSG_DATA(CMsg);
2115+
CXPLAT_DBG_ASSERT(TypeOfService <= CXPLAT_ECN_CE);
20722116
} else if (CMsg->cmsg_type == IPV6_HOPLIMIT) {
20732117
HopLimitTTL = *(PINT)WSA_CMSG_DATA(CMsg);
20742118
CXPLAT_DBG_ASSERT(HopLimitTTL < 256);
@@ -2089,9 +2133,12 @@ CxPlatDataPathSocketReceive(
20892133
IsUnreachableError = TRUE;
20902134
break;
20912135
}
2136+
} else if (CMsg->cmsg_type == IP_TOS) {
2137+
TypeOfService = *(PINT)WSA_CMSG_DATA(CMsg);
2138+
CXPLAT_DBG_ASSERT(TypeOfService < UINT8_MAX);
20922139
} else if (CMsg->cmsg_type == IP_ECN) {
2093-
ECN = *(PINT)WSA_CMSG_DATA(CMsg);
2094-
CXPLAT_DBG_ASSERT(ECN < UINT8_MAX);
2140+
TypeOfService = *(PINT)WSA_CMSG_DATA(CMsg);
2141+
CXPLAT_DBG_ASSERT(TypeOfService <= CXPLAT_ECN_CE);
20952142
} else if (CMsg->cmsg_type == IP_TTL) {
20962143
HopLimitTTL = *(PINT)WSA_CMSG_DATA(CMsg);
20972144
CXPLAT_DBG_ASSERT(HopLimitTTL < 256);
@@ -2252,7 +2299,7 @@ CxPlatDataPathSocketReceive(
22522299
Datagram->IoBlock = IoBlock;
22532300
Datagram->Data.Next = NULL;
22542301
Datagram->Data.PartitionIndex = (uint16_t)(CurProcNumber % Binding->Datapath->ProcCount);
2255-
Datagram->Data.TypeOfService = (uint8_t)ECN;
2302+
Datagram->Data.TypeOfService = (uint8_t)TypeOfService;
22562303
Datagram->Data.HopLimitTTL = (uint8_t)HopLimitTTL;
22572304
Datagram->Data.Allocated = TRUE;
22582305
Datagram->Data.QueuedOnConnection = FALSE;

0 commit comments

Comments
 (0)