Skip to content

Commit

Permalink
vrouter: implement communication channels with vRouter Agent
Browse files Browse the repository at this point in the history
Changes required to support Contrail on Windows:
- windows/vr_devices.c - common code used to set up named pipes
  used to exchange data between vRouter and Agent on Windows
- windows/vr_ksync.c - Windows-specific implementation of KSync
  messages handling, based on named pipes
- windows/vr_pkt0.c - Windows-specific implementation of Pkt0
  packet handling, based on named pipes
- windows/vr_mem.c - code responsible for allocation of memory
  used for flow table
- windows/vr_flow_device.c - implementation of named pipe
  used as file to map memory from, for flows table

Other changes:
- extract computing oflow table size into function

Initial work:
  https://github.com/codilime/contrail-vrouter/commits/windows

Change-Id: I366eda3d497059aa2963384598ad7ef64dc1661f
Partial-Bug: #1734699
  • Loading branch information
Dariusz Sosnowski committed Dec 1, 2017
1 parent 7e1320e commit 5a0c693
Show file tree
Hide file tree
Showing 7 changed files with 1,155 additions and 6 deletions.
19 changes: 13 additions & 6 deletions dp-core/vr_flow.c
Expand Up @@ -2573,17 +2573,24 @@ vr_flow_table_reset(struct vrouter *router)
return;
}

void
vr_compute_size_oflow_table(int *oentries, int entries)
{
/*
* Overflow entries is 20% of the main flow table
* adjusted to next 1k
*/
if (oentries != NULL && *oentries == 0) {
*oentries = ((entries / 5) + 1023) & ~1023;
}
}

static int
vr_flow_table_init(struct vrouter *router)
{
if (!router->vr_flow_table) {

/*
* Overflow entries is 20% of the main flow table
* adjusted to next 1k
*/
if (!vr_oflow_entries)
vr_oflow_entries = ((vr_flow_entries / 5) + 1023) & ~1023;
vr_compute_size_oflow_table(&vr_oflow_entries, vr_flow_entries);

if (!vr_flow_table && vr_huge_page_mem_get) {

Expand Down
2 changes: 2 additions & 0 deletions include/vr_flow.h
Expand Up @@ -510,4 +510,6 @@ unsigned int vr_flow_table_burst_step_configured(struct vrouter *);
unsigned int vr_flow_table_burst_tokens_configured(struct vrouter *);
unsigned int vr_flow_table_burst_time_configured(struct vrouter *);

void vr_compute_size_oflow_table(int *oentries, int entries);

#endif /* __VR_FLOW_H__ */
70 changes: 70 additions & 0 deletions windows/vr_devices.c
@@ -0,0 +1,70 @@
/*
* Copyright (c) 2017 Juniper Networks, Inc. All rights reserved.
*/
#include "precomp.h"
#include "windows_devices.h"

NTSTATUS
VRouterSetUpNamedDevice(NDIS_HANDLE DriverHandle,
PCWSTR DeviceName,
PCWSTR DeviceSymlink,
PVR_DEVICE_DISPATCH_CALLBACKS Callbacks,
PDEVICE_OBJECT *DeviceObject,
NDIS_HANDLE *DeviceHandle)
{
NTSTATUS status;
UNICODE_STRING device_name;
UNICODE_STRING device_symlink;

status = RtlUnicodeStringInit(&device_name, DeviceName);
if (!NT_SUCCESS(status)) {
return status;
}

status = RtlUnicodeStringInit(&device_symlink, DeviceSymlink);
if (!NT_SUCCESS(status)) {
return status;
}

PDRIVER_DISPATCH dispatch_table[IRP_MJ_MAXIMUM_FUNCTION + 1];
NdisZeroMemory(dispatch_table, (IRP_MJ_MAXIMUM_FUNCTION + 1) * sizeof(PDRIVER_DISPATCH));

dispatch_table[IRP_MJ_CREATE] = Callbacks->create;
dispatch_table[IRP_MJ_CLEANUP] = Callbacks->cleanup;
dispatch_table[IRP_MJ_CLOSE] = Callbacks->close;
dispatch_table[IRP_MJ_WRITE] = Callbacks->write;
dispatch_table[IRP_MJ_READ] = Callbacks->read;
dispatch_table[IRP_MJ_DEVICE_CONTROL] = Callbacks->device_control;

NDIS_DEVICE_OBJECT_ATTRIBUTES attributes;
NdisZeroMemory(&attributes, sizeof(NDIS_DEVICE_OBJECT_ATTRIBUTES));

attributes.Header.Type = NDIS_OBJECT_TYPE_DEVICE_OBJECT_ATTRIBUTES;
attributes.Header.Revision = NDIS_DEVICE_OBJECT_ATTRIBUTES_REVISION_1;
attributes.Header.Size = NDIS_SIZEOF_DEVICE_OBJECT_ATTRIBUTES_REVISION_1;

attributes.DeviceName = &device_name;
attributes.SymbolicName = &device_symlink;
attributes.MajorFunctions = &dispatch_table[0];
attributes.ExtensionSize = 0;
attributes.DefaultSDDLString = &SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RWX_RES_RWX;
attributes.DeviceClassGuid = NULL;

status = NdisRegisterDeviceEx(DriverHandle, &attributes, DeviceObject, DeviceHandle);
if (NT_SUCCESS(status)) {
(*DeviceObject)->Flags |= DO_DIRECT_IO;
}

return status;
}

VOID
VRouterTearDownNamedDevice(NDIS_HANDLE *DeviceHandle)
{
if (*DeviceHandle == NULL) {
return;
}

NdisDeregisterDeviceEx(*DeviceHandle);
*DeviceHandle = NULL;
}
204 changes: 204 additions & 0 deletions windows/vr_flow_device.c
@@ -0,0 +1,204 @@
/*
* Copyright (c) 2017 Juniper Networks, Inc. All rights reserved.
*/
#include "precomp.h"

#include "windows_devices.h"
#include "windows_flow_ioctl.h"
#include "windows_ksync.h"
#include "windows_mem.h"

static const WCHAR FlowDeviceName[] = L"\\Device\\vrouterFlow";
static const WCHAR FlowDeviceSymLink[] = L"\\DosDevices\\vrouterFlow";

static PDEVICE_OBJECT FlowDeviceObject = NULL;
static NDIS_HANDLE FlowDeviceHandle = NULL;

static ULONG FlowAllocationTag = 'LFRV';

static PFLOW_DEVICE_CONTEXT
FlowAllocateContext()
{
PFLOW_DEVICE_CONTEXT ctx;

ctx = ExAllocatePoolWithTag(NonPagedPoolNx, sizeof(*ctx), FlowAllocationTag);
if (ctx == NULL)
return NULL;

ctx->UserVirtualAddress = NULL;

return ctx;
}

static VOID
FlowFreeContext(PFLOW_DEVICE_CONTEXT ctx)
{
if (ctx != NULL) {
ExFreePool(ctx);
}
}

static VOID
FlowAttachContextToFileContext(PFLOW_DEVICE_CONTEXT ctx, PIRP irp)
{
PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(irp);
PFILE_OBJECT fileObj = ioStack->FileObject;
fileObj->FsContext = ctx;
}

static PFLOW_DEVICE_CONTEXT
FlowGetContextFromFileContext(PIRP irp)
{
PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(irp);
PFILE_OBJECT fileObj = ioStack->FileObject;
return fileObj->FsContext;
}

static NTSTATUS
FlowCompleteIrp(PIRP Irp, NTSTATUS Status, ULONG_PTR Information)
{
Irp->IoStatus.Status = Status;
Irp->IoStatus.Information = Information;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}

static NTSTATUS
FlowDispatchCreate(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
PFLOW_DEVICE_CONTEXT ctx = FlowAllocateContext();
if (ctx == NULL)
goto Failure;
FlowAttachContextToFileContext(ctx, Irp);

PMDL flowMemoryMdl = GetFlowMemoryMdl();
if (flowMemoryMdl == NULL)
goto Failure;

MM_PAGE_PRIORITY pagePriority = NormalPagePriority | MdlMappingNoExecute;
PVOID userVirtualAddress = MmMapLockedPagesSpecifyCache(flowMemoryMdl,
UserMode,
MmNonCached,
NULL,
FALSE,
pagePriority);
if (userVirtualAddress == NULL)
goto Failure;

ctx->UserVirtualAddress = userVirtualAddress;
ctx->FlowMemoryMdl = flowMemoryMdl;

return FlowCompleteIrp(Irp, STATUS_SUCCESS, (ULONG_PTR)(FILE_OPENED));

Failure:
if (ctx != NULL) {
FlowAttachContextToFileContext(NULL, Irp);
FlowFreeContext(ctx);
}

return FlowCompleteIrp(Irp, STATUS_INSUFFICIENT_RESOURCES, (ULONG_PTR)(0));
}

static NTSTATUS
FlowDispatchClose(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
PFLOW_DEVICE_CONTEXT ctx = FlowGetContextFromFileContext(Irp);

ASSERT(ctx != NULL);
ASSERT(ctx->UserVirtualAddress != NULL);
ASSERT(ctx->FlowMemoryMdl != NULL);

MmUnmapLockedPages(ctx->UserVirtualAddress, ctx->FlowMemoryMdl);
FlowAttachContextToFileContext(NULL, Irp);
FlowFreeContext(ctx);

return FlowCompleteIrp(Irp, STATUS_SUCCESS, (ULONG_PTR)(0));
}

static NTSTATUS
FlowDispatchCleanup(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
return FlowCompleteIrp(Irp, STATUS_SUCCESS, (ULONG_PTR)(0));
}

static NTSTATUS
FlowHandleGetAddress(PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PFLOW_DEVICE_CONTEXT ctx)
{
NTSTATUS status;

PMDL bufferMdl = Irp->MdlAddress;
ULONG expectedLength = sizeof(ctx->UserVirtualAddress);
ULONG bufferLength = MmGetMdlByteCount(bufferMdl);
if (bufferLength != expectedLength) {
status = STATUS_INVALID_PARAMETER;
goto Failure;
}

PVOID buffer = MmGetSystemAddressForMdlSafe(bufferMdl,
NormalPagePriority | MdlMappingNoExecute);
if (buffer == NULL) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto Failure;
}
RtlCopyMemory(buffer, &ctx->UserVirtualAddress, expectedLength);

return FlowCompleteIrp(Irp, STATUS_SUCCESS, expectedLength);

Failure:
return FlowCompleteIrp(Irp, status, (ULONG_PTR)(0));
}

static NTSTATUS
FlowDispatchDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
PIO_STACK_LOCATION ioStack;
PFLOW_DEVICE_CONTEXT ctx;
PVOID buffer;

ctx = FlowGetContextFromFileContext(Irp);
ASSERT(ctx != NULL);

ioStack = IoGetCurrentIrpStackLocation(Irp);
switch (ioStack->Parameters.DeviceIoControl.IoControlCode) {
case IOCTL_FLOW_GET_ADDRESS:
return FlowHandleGetAddress(DeviceObject, Irp, ctx);
default:
return FlowCompleteIrp(Irp, STATUS_INVALID_DEVICE_REQUEST, (ULONG_PTR)(0));
}
}

static NTSTATUS
FlowDispatchRead(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
return FlowCompleteIrp(Irp, STATUS_INVALID_DEVICE_REQUEST, (ULONG_PTR)(0));
}

static NTSTATUS
FlowDispatchWrite(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
return FlowCompleteIrp(Irp, STATUS_INVALID_DEVICE_REQUEST, (ULONG_PTR)(0));
}

NTSTATUS
FlowCreateDevice(NDIS_HANDLE DriverHandle)
{
VR_DEVICE_DISPATCH_CALLBACKS callbacks = {
.create = FlowDispatchCreate,
.cleanup = FlowDispatchCleanup,
.close = FlowDispatchClose,
.write = FlowDispatchWrite,
.read = FlowDispatchRead,
.device_control = FlowDispatchDeviceControl,
};

return VRouterSetUpNamedDevice(DriverHandle, FlowDeviceName, FlowDeviceSymLink,
&callbacks, &FlowDeviceObject, &FlowDeviceHandle);
}

VOID
FlowDestroyDevice(VOID)
{
VRouterTearDownNamedDevice(&FlowDeviceHandle);
}

0 comments on commit 5a0c693

Please sign in to comment.