Skip to content

Commit

Permalink
Support multiple instances of secnetperf in kernel mode (#1374)
Browse files Browse the repository at this point in the history
* Support multiple instances of secnetperf in kernel mode

This way loopback tests can be supported. Done by allowing user to supply driver name

* Get working with loopback and remote

* Run for infinite time
  • Loading branch information
ThadHouse authored Mar 25, 2021
1 parent a2f7892 commit 19980a5
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 31 deletions.
2 changes: 1 addition & 1 deletion scripts/performance-helper.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ function Invoke-RemoteExe {
} -ArgumentList $Exe

if ($Kernel) {
$RunArgs = "--kernelPriv $RunArgs"
$RunArgs = "-driverNamePriv:secnetperfdrvpriv $RunArgs"
}

Write-Debug "Running Remote: $Exe $RunArgs"
Expand Down
33 changes: 19 additions & 14 deletions src/perf/bin/appmain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,6 @@ typedef struct {
} QUIC_RUN_CERTIFICATE_PARAMS;
#include "quic_driver_helpers.h"

#define QUIC_DRIVER_NAME "secnetperfdrv"
#define QUIC_DRIVER_NAME_PRIVATE "secnetperfdrvpriv"

#endif

extern "C" _IRQL_requires_max_(PASSIVE_LEVEL) void QuicTraceRundown(void) { }
Expand Down Expand Up @@ -177,6 +174,7 @@ QuicKernelMain(
_In_ bool /*KeyboardWait*/,
_In_ const QUIC_CREDENTIAL_CONFIG* SelfSignedParams,
_In_ bool PrivateTestLibrary,
_In_z_ const char* DriverName,
_In_opt_z_ const char* FileName
)
{
Expand Down Expand Up @@ -226,13 +224,10 @@ QuicKernelMain(
QuicDriverService DriverService;
QuicDriverClient DriverClient;

const char* DriverName;
const char* DependentDriverNames;
if (PrivateTestLibrary) {
DriverName = QUIC_DRIVER_NAME_PRIVATE;
DependentDriverNames = "msquicpriv\0";
} else {
DriverName = QUIC_DRIVER_NAME;
DependentDriverNames = "msquic\0";
}

Expand Down Expand Up @@ -295,7 +290,7 @@ QuicKernelMain(
OutBuffer,
OutBufferSize,
&OutBufferWritten,
240000);
INFINITE);
if (RunSuccess) {
printf("%s\n", OutBuffer);

Expand Down Expand Up @@ -359,10 +354,12 @@ main(
) {
const QUIC_CREDENTIAL_CONFIG* SelfSignedCredConfig = nullptr;
QUIC_STATUS RetVal = 0;
bool TestingKernelMode = false;
bool KeyboardWait = false;
const char* FileName = nullptr;
const char* DriverName = nullptr;
bool PrivateTestLibrary = false;
constexpr const char* DriverSearch = "driverName";
size_t DriverLen = strlen(DriverSearch);

UniquePtr<char*[]> ArgValues = UniquePtr<char*[]>(new char*[argc]);

Expand All @@ -378,11 +375,19 @@ main(
}

for (int i = 0; i < argc; ++i) {
if (strcmp("--kernel", argv[i]) == 0 || strcmp("--kernelPriv", argv[i]) == 0) {

if (_strnicmp(argv[i] + 1, DriverSearch, DriverLen) == 0) {
#ifdef _WIN32
TestingKernelMode = true;
if (strcmp("--kernelPriv", argv[i]) == 0) {
//
// See if private driver
//
constexpr const char* DriverSearchPriv = "driverNamePriv";
size_t DriverLenPriv = strlen(DriverSearchPriv);
if (_strnicmp(argv[i] + 1, DriverSearchPriv, DriverLenPriv) == 0) {
PrivateTestLibrary = true;
DriverName = argv[i] + 1 + DriverLenPriv + 1;
} else {
DriverName = argv[i] + 1 + DriverLen + 1;
}
#else
printf("Cannot run kernel mode tests on non windows platforms\n");
Expand All @@ -401,7 +406,7 @@ main(

SelfSignedCredConfig =
CxPlatGetSelfSignedCert(
TestingKernelMode ?
DriverName != nullptr ?
CXPLAT_SELF_SIGN_CERT_MACHINE :
CXPLAT_SELF_SIGN_CERT_USER,
FALSE);
Expand All @@ -411,10 +416,10 @@ main(
goto Exit;
}

if (TestingKernelMode) {
if (DriverName != nullptr) {
#ifdef _WIN32
printf("Entering kernel mode main\n");
RetVal = QuicKernelMain(ArgCount, ArgValues.get(), KeyboardWait, SelfSignedCredConfig, PrivateTestLibrary, FileName);
RetVal = QuicKernelMain(ArgCount, ArgValues.get(), KeyboardWait, SelfSignedCredConfig, PrivateTestLibrary, DriverName, FileName);
#else
UNREFERENCED_PARAMETER(PrivateTestLibrary);
CXPLAT_FRE_ASSERT(FALSE);
Expand Down
112 changes: 99 additions & 13 deletions src/perf/bin/drvmain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,8 @@
#include "drivermain.cpp.clog.h"
#endif

#ifdef PRIVATE_LIBRARY
DECLARE_CONST_UNICODE_STRING(SecNetPerfCtlDeviceName, L"\\Device\\secnetperfdrv");
DECLARE_CONST_UNICODE_STRING(SecNetPerfCtlDeviceSymLink, L"\\DosDevices\\secnetperfdrvpriv");
#else
DECLARE_CONST_UNICODE_STRING(SecNetPerfCtlDeviceName, L"\\Device\\secnetperfdrv");
DECLARE_CONST_UNICODE_STRING(SecNetPerfCtlDeviceSymLink, L"\\DosDevices\\secnetperfdrvpriv");
#endif
DECLARE_CONST_UNICODE_STRING(SecNetPerfCtlDeviceNameBase, L"\\Device\\");
DECLARE_CONST_UNICODE_STRING(SecNetPerfCtlDeviceSymLinkBase, L"\\DosDevices\\");

typedef struct QUIC_DEVICE_EXTENSION {
EX_PUSH_LOCK Lock;
Expand Down Expand Up @@ -69,7 +64,8 @@ _No_competing_thread_
INITCODE
NTSTATUS
SecNetPerfCtlInitialize(
_In_ WDFDRIVER Driver
_In_ WDFDRIVER Driver,
_In_ PUNICODE_STRING BaseRegPath
);

_IRQL_requires_max_(PASSIVE_LEVEL)
Expand Down Expand Up @@ -178,7 +174,7 @@ DriverEntry(
//
// Initialize the device control interface.
//
Status = SecNetPerfCtlInitialize(Driver);
Status = SecNetPerfCtlInitialize(Driver, RegistryPath);
if (!NT_SUCCESS(Status)) {
goto Error;
}
Expand Down Expand Up @@ -219,11 +215,45 @@ SecNetPerfDriverUnload(
CxPlatSystemUnload();
}

#define PERF_REG_PATH L"\\Parameters"

_No_competing_thread_
INITCODE
NTSTATUS
SecNetPerfGetServiceName(
_In_ PUNICODE_STRING BaseRegPath,
_Inout_ PUNICODE_STRING ServiceName
)
{
USHORT BaseRegPathLength = BaseRegPath->Length / sizeof(WCHAR);
if (BaseRegPath->Buffer[BaseRegPathLength - 1] == L'\\') {
//LogWarning("[config] Trimming trailing '\\' from registry!");
BaseRegPathLength--;
}

//
// Get the service name from the base registry path.
//
USHORT ServiceNameLength = 0;
while (BaseRegPath->Buffer[BaseRegPathLength - ServiceNameLength - 1] != L'\\') {
ServiceNameLength++;
}
if (ServiceNameLength == 0) {
//LogError("[config] Empty service name!");
return STATUS_INVALID_PARAMETER;
}

*ServiceName = { ServiceNameLength * sizeof(WCHAR), ServiceNameLength * sizeof(WCHAR), BaseRegPath->Buffer + (BaseRegPathLength - ServiceNameLength) };

return STATUS_SUCCESS;
}

_No_competing_thread_
INITCODE
NTSTATUS
SecNetPerfCtlInitialize(
_In_ WDFDRIVER Driver
_In_ WDFDRIVER Driver,
_In_ PUNICODE_STRING BaseRegPath
)
{
NTSTATUS Status = STATUS_SUCCESS;
Expand All @@ -234,6 +264,8 @@ SecNetPerfCtlInitialize(
QUIC_DEVICE_EXTENSION* DeviceContext;
WDF_IO_QUEUE_CONFIG QueueConfig;
WDFQUEUE Queue;
DECLARE_UNICODE_STRING_SIZE(ServiceName, 64);
DECLARE_UNICODE_STRING_SIZE(DeviceName, 100);

DeviceInit =
WdfControlDeviceInitAllocate(
Expand All @@ -248,10 +280,43 @@ SecNetPerfCtlInitialize(
goto Error;
}

Status =
SecNetPerfGetServiceName(
BaseRegPath,
&ServiceName);
if (!NT_SUCCESS(Status)) {
QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
Status,
"SecNetPerfGetServiceName failed");
goto Error;
}

Status = RtlUnicodeStringCopy(&DeviceName, &SecNetPerfCtlDeviceNameBase);
if (!NT_SUCCESS(Status)) {
QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
Status,
"RtlUnicodeStringCopy failed");
goto Error;
}

Status = RtlUnicodeStringCat(&DeviceName, &ServiceName);
if (!NT_SUCCESS(Status)) {
QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
Status,
"RtlUnicodeStringCat failed");
goto Error;
}

Status =
WdfDeviceInitAssignName(
DeviceInit,
&SecNetPerfCtlDeviceName);
&DeviceName);
if (!NT_SUCCESS(Status)) {
QuicTraceEvent(
LibraryErrorStatus,
Expand All @@ -263,7 +328,7 @@ SecNetPerfCtlInitialize(

QuicTraceLogVerbose(
PerfControlInitialized,
"[perf] Control interface initialized with %.*S", SecNetPerfCtlDeviceName.Length, SecNetPerfCtlDeviceName.Buffer);
"[perf] Control interface initialized with %.*S", DeviceName.Length, DeviceName.Buffer);

WDF_FILEOBJECT_CONFIG_INIT(
&FileConfig,
Expand Down Expand Up @@ -298,7 +363,28 @@ SecNetPerfCtlInitialize(
ExInitializePushLock(&DeviceContext->Lock);
InitializeListHead(&DeviceContext->ClientList);

Status = WdfDeviceCreateSymbolicLink(Device, &SecNetPerfCtlDeviceSymLink);
DeviceName.Length = 0;
Status = RtlUnicodeStringCopy(&DeviceName, &SecNetPerfCtlDeviceSymLinkBase);
if (!NT_SUCCESS(Status)) {
QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
Status,
"RtlUnicodeStringCopy failed");
goto Error;
}

Status = RtlUnicodeStringCat(&DeviceName, &ServiceName);
if (!NT_SUCCESS(Status)) {
QuicTraceEvent(
LibraryErrorStatus,
"[ lib] ERROR, %u, %s.",
Status,
"RtlUnicodeStringCat failed");
goto Error;
}

Status = WdfDeviceCreateSymbolicLink(Device, &DeviceName);
if (!NT_SUCCESS(Status)) {
QuicTraceEvent(
LibraryErrorStatus,
Expand Down
6 changes: 3 additions & 3 deletions src/perf/bin/secnetperfdriver.kernel.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@
<ProjectReference Include="..\lib\perflib.kernel.vcxproj">
<Project>{11633785-79cc-4c7d-ab6a-aecdf29a1fa7}</Project>
</ProjectReference>
<ProjectReference Include="..\..\bin\winkernel\msquicpriv.kernel.vcxproj">
<Project>{e2ddb0a8-594d-424d-9add-4ef211f7fc3f}</Project>
<ProjectReference Include="..\..\bin\winkernel\msquic.kernel.vcxproj">
<Project>{C31B028C-E91C-4CF7-A8E7-F385B2AF5F85}</Project>
</ProjectReference>
</ItemGroup>
<PropertyGroup Label="Globals">
Expand Down Expand Up @@ -93,7 +93,7 @@
</ClCompile>
<Link>
<AdditionalLibraryDirectories>$(SolutionDir)artifacts\bin\winkernel\$(Platform)_$(Configuration)_schannel\</AdditionalLibraryDirectories>
<AdditionalDependencies>cng.lib;ksecdd.lib;msnetioid.lib;netio.lib;wdmsec.lib;uuid.lib;msquicpriv.lib;ndis.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>cng.lib;ksecdd.lib;msnetioid.lib;netio.lib;wdmsec.lib;uuid.lib;msquic.lib;ndis.lib;%(AdditionalDependencies)</AdditionalDependencies>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
</Link>
</ItemDefinitionGroup>
Expand Down
5 changes: 5 additions & 0 deletions src/perf/lib/SecNetPerfMain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,11 @@ QuicMainStart(
if (QUIC_FAILED(Status)) {
CxPlatDataPathUninitialize(Datapath);
Datapath = nullptr;
//
// Must explicitly set binding to null, as CxPlatSocketCreateUdp
// can set the Binding variable even in invalid cases.
//
Binding = nullptr;
WriteOutput("Datapath Binding for shutdown failed to initialize: %d\n", Status);
return Status;
}
Expand Down

0 comments on commit 19980a5

Please sign in to comment.