Skip to content

Fix DSCP detection on Windows. Add DSCP support to SecNetPerf #5130

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jun 13, 2025
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
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
1 change: 1 addition & 0 deletions src/inc/quic_datapath.h
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,7 @@ typedef enum CXPLAT_DATAPATH_FEATURES {
CXPLAT_DATAPATH_FEATURE_TTL = 0x00000080,
CXPLAT_DATAPATH_FEATURE_SEND_DSCP = 0x00000100,
CXPLAT_DATAPATH_FEATURE_RIO = 0x00000200,
CXPLAT_DATAPATH_FEATURE_RECV_DSCP = 0x00000400,
} CXPLAT_DATAPATH_FEATURES;

DEFINE_ENUM_FLAG_OPERATORS(CXPLAT_DATAPATH_FEATURES)
Expand Down
14 changes: 14 additions & 0 deletions src/perf/lib/PerfClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,20 @@ PerfClientConnection::Initialize() {
}
}

if (PerfDefaultDscpValue != 0) {
Status =
MsQuic->SetParam(
Handle,
QUIC_PARAM_CONN_SEND_DSCP,
sizeof(PerfDefaultDscpValue),
&PerfDefaultDscpValue);
if (QUIC_FAILED(Status)) {
WriteOutput("SetSendDscp failed, 0x%x\n", Status);
Worker.ConnectionPool.Free(this);
return;
}
}

if (Client.CibirIdLength) {
Status =
MsQuic->SetParam(
Expand Down
7 changes: 7 additions & 0 deletions src/perf/lib/PerfServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,13 @@ PerfServer::ListenerCallback(
if (Event->Type == QUIC_LISTENER_EVENT_NEW_CONNECTION) {
BOOLEAN value = TRUE;
MsQuic->SetParam(Event->NEW_CONNECTION.Connection, QUIC_PARAM_CONN_DISABLE_1RTT_ENCRYPTION, sizeof(value), &value);
if (PerfDefaultDscpValue != 0) {
MsQuic->SetParam(
Event->NEW_CONNECTION.Connection,
QUIC_PARAM_CONN_SEND_DSCP,
sizeof(PerfDefaultDscpValue),
&PerfDefaultDscpValue);
}
QUIC_CONNECTION_CALLBACK_HANDLER Handler =
[](HQUIC Conn, void* Context, QUIC_CONNECTION_EVENT* Event) -> QUIC_STATUS {
return ((PerfServer*)Context)->ConnectionCallback(Conn, Event);
Expand Down
1 change: 1 addition & 0 deletions src/perf/lib/SecNetPerf.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ extern uint8_t PerfDefaultEcnEnabled;
extern uint8_t PerfDefaultQeoAllowed;
extern uint8_t PerfDefaultHighPriority;
extern uint8_t PerfDefaultAffinitizeThreads;
extern uint8_t PerfDefaultDscpValue;

extern CXPLAT_DATAPATH* Datapath;

Expand Down
7 changes: 7 additions & 0 deletions src/perf/lib/SecNetPerfMain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ uint8_t PerfDefaultEcnEnabled = false;
uint8_t PerfDefaultQeoAllowed = false;
uint8_t PerfDefaultHighPriority = false;
uint8_t PerfDefaultAffinitizeThreads = false;
uint8_t PerfDefaultDscpValue = 0;

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

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

uint32_t WatchdogTimeout = 0;
if (TryGetValue(argc, argv, "watchdog", &WatchdogTimeout) && WatchdogTimeout != 0) {
Expand Down
2 changes: 2 additions & 0 deletions src/perf/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ cibir | `-cibir:<hex_bytes>` | The well-known CIBIR identifier.
cipher | `-cipher:<value>` | Decimal value of 1 or more `QUIC_ALLOWED_CIPHER_SUITE_FLAGS`.
cpu | `-cpu:<cpu_indexes>` | Comma-separated list of CPUs to run on.
ecn | `-ecn:<0,1>` | Enables sender-side ECN support.
dscp | `-dscp:<0-63>` | Sets DSCP value used for outgoing traffic.
exec | `-exec:<lowlat,maxtput,scavenger,realtime>` | The execution profile used for the application.
pollidle | `-pollidle:<time_us>` | The time, in microseconds, to poll while idle before sleeping (falling back to interrupt-driven IO).
stats | `-stats:<0,1>` | Prints out statistics at the end of each connection.
Expand Down Expand Up @@ -81,6 +82,7 @@ tcp | `-tcp:<0,1>` | Disables/enables TCP usage (instead of QUIC).
encrypt | `-encrypt:<0,1>` | Disables/enables encryption.
pacing | `-pacing:<0,1>` | Disables/enables send pacing.
sendbuf | `-sendbuf:<0,1>` | Disables/enables send buffering.
dscp | `-dscp:<0-63>` | Sets DSCP value used for outgoing traffic.
ptput | `-ptput:<0,1>` | Print throughput information.
pconnection, pconn | `-pconn:<0,1>` | Print connection statistics.
pstream | `-pstream:<0,1>` | Print stream statistics.
Expand Down
133 changes: 90 additions & 43 deletions src/platform/datapath_winkernel.c
Original file line number Diff line number Diff line change
Expand Up @@ -593,7 +593,7 @@ CxPlatDataPathQuerySockoptSupport(
} while (FALSE);

do {
DWORD TypeOfService = 1; // Lower Effort
DWORD TypeOfService = CXPLAT_DSCP_LE << 2;

IoReuseIrp(Irp, STATUS_SUCCESS);
IoSetCompletionRoutine(
Expand Down Expand Up @@ -641,10 +641,11 @@ CxPlatDataPathQuerySockoptSupport(
} while (FALSE);

//
// Some USO/URO bug blocks TTL feature support on Windows Server 2022.
// Some USO/URO bug blocks TTL/Recv DSCP feature support on Windows Server 2022.
//
if (CxPlatform.dwBuildNumber != 20348) {
Datapath->Features |= CXPLAT_DATAPATH_FEATURE_TTL;
Datapath->Features |= CXPLAT_DATAPATH_FEATURE_RECV_DSCP;
}

Error:
Expand Down Expand Up @@ -1474,42 +1475,82 @@ SocketCreateUdp(
goto Error;
}

Option = TRUE;
Status =
CxPlatDataPathSetControlSocket(
Binding,
WskSetOption,
IPV6_ECN,
IPPROTO_IPV6,
sizeof(Option),
&Option);
if (QUIC_FAILED(Status)) {
QuicTraceEvent(
DatapathErrorStatus,
"[data][%p] ERROR, %u, %s.",
Binding,
Status,
"Set IPV6_ECN");
goto Error;
}
if (Datapath->Features & CXPLAT_DATAPATH_FEATURE_RECV_DSCP) {
Option = TRUE;
Status =
CxPlatDataPathSetControlSocket(
Binding,
WskSetOption,
IPV6_RECVTCLASS,
IPPROTO_IPV6,
sizeof(Option),
&Option);
if (QUIC_FAILED(Status)) {
QuicTraceEvent(
DatapathErrorStatus,
"[data][%p] ERROR, %u, %s.",
Binding,
Status,
"Set IPV6_RECVTCLASS");
goto Error;
}

Option = TRUE;
Status =
CxPlatDataPathSetControlSocket(
Binding,
WskSetOption,
IP_ECN,
IPPROTO_IP,
sizeof(Option),
&Option);
if (QUIC_FAILED(Status)) {
QuicTraceEvent(
DatapathErrorStatus,
"[data][%p] ERROR, %u, %s.",
Binding,
Status,
"Set IP_ECN");
goto Error;
Option = TRUE;
Status =
CxPlatDataPathSetControlSocket(
Binding,
WskSetOption,
IP_RECVTOS,
IPPROTO_IP,
sizeof(Option),
&Option);
if (QUIC_FAILED(Status)) {
QuicTraceEvent(
DatapathErrorStatus,
"[data][%p] ERROR, %u, %s.",
Binding,
Status,
"Set IP_RECVTOS");
goto Error;
}
} else {
Option = TRUE;
Status =
CxPlatDataPathSetControlSocket(
Binding,
WskSetOption,
IPV6_ECN,
IPPROTO_IPV6,
sizeof(Option),
&Option);
if (QUIC_FAILED(Status)) {
QuicTraceEvent(
DatapathErrorStatus,
"[data][%p] ERROR, %u, %s.",
Binding,
Status,
"Set IPV6_ECN");
goto Error;
}

Option = TRUE;
Status =
CxPlatDataPathSetControlSocket(
Binding,
WskSetOption,
IP_ECN,
IPPROTO_IP,
sizeof(Option),
&Option);
if (QUIC_FAILED(Status)) {
QuicTraceEvent(
DatapathErrorStatus,
"[data][%p] ERROR, %u, %s.",
Binding,
Status,
"Set IP_ECN");
goto Error;
}
}

Option = TRUE;
Expand Down Expand Up @@ -2036,7 +2077,7 @@ CxPlatDataPathSocketReceive(
SOCKADDR_INET LocalAddr = { 0 };
SOCKADDR_INET RemoteAddr;
UINT16 MessageLength = 0;
INT ECN = 0;
INT TypeOfService = 0;
INT HopLimitTTL = 0;

//
Expand Down Expand Up @@ -2066,9 +2107,12 @@ CxPlatDataPathSocketReceive(
IsUnreachableError = TRUE;
break;
}
} else if (CMsg->cmsg_type == IPV6_TCLASS) {
TypeOfService = *(PINT)WSA_CMSG_DATA(CMsg);
CXPLAT_DBG_ASSERT(TypeOfService < UINT8_MAX);
} else if (CMsg->cmsg_type == IPV6_ECN) {
ECN = *(PINT)WSA_CMSG_DATA(CMsg);
CXPLAT_DBG_ASSERT(ECN < UINT8_MAX);
TypeOfService = *(PINT)WSA_CMSG_DATA(CMsg);
CXPLAT_DBG_ASSERT(TypeOfService <= CXPLAT_ECN_CE);
} else if (CMsg->cmsg_type == IPV6_HOPLIMIT) {
HopLimitTTL = *(PINT)WSA_CMSG_DATA(CMsg);
CXPLAT_DBG_ASSERT(HopLimitTTL < 256);
Expand All @@ -2089,9 +2133,12 @@ CxPlatDataPathSocketReceive(
IsUnreachableError = TRUE;
break;
}
} else if (CMsg->cmsg_type == IP_TOS) {
TypeOfService = *(PINT)WSA_CMSG_DATA(CMsg);
CXPLAT_DBG_ASSERT(TypeOfService < UINT8_MAX);
} else if (CMsg->cmsg_type == IP_ECN) {
ECN = *(PINT)WSA_CMSG_DATA(CMsg);
CXPLAT_DBG_ASSERT(ECN < UINT8_MAX);
TypeOfService = *(PINT)WSA_CMSG_DATA(CMsg);
CXPLAT_DBG_ASSERT(TypeOfService <= CXPLAT_ECN_CE);
} else if (CMsg->cmsg_type == IP_TTL) {
HopLimitTTL = *(PINT)WSA_CMSG_DATA(CMsg);
CXPLAT_DBG_ASSERT(HopLimitTTL < 256);
Expand Down Expand Up @@ -2252,7 +2299,7 @@ CxPlatDataPathSocketReceive(
Datagram->IoBlock = IoBlock;
Datagram->Data.Next = NULL;
Datagram->Data.PartitionIndex = (uint16_t)(CurProcNumber % Binding->Datapath->ProcCount);
Datagram->Data.TypeOfService = (uint8_t)ECN;
Datagram->Data.TypeOfService = (uint8_t)TypeOfService;
Datagram->Data.HopLimitTTL = (uint8_t)HopLimitTTL;
Datagram->Data.Allocated = TRUE;
Datagram->Data.QueuedOnConnection = FALSE;
Expand Down
Loading
Loading