[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[win-pv-devel] [PATCH 2/4] Add frontend code for the new netif control ring



My recent patches to Xen's netif.h specify a control ring that can be
used by a frontend driver to configure packet hashing and steering in
a backend.
This patch adds the necessary code to XENVIF to drive this new ring,
however the rest of the code to link this up to new VIF interface
functionality (so that it may be used by XENNET) is deferred to a
subsequent patch.

This patch also pulls in an updated EVTCHN interface from XENBUS and
corrects the PDO binding.

Signed-off-by: Paul Durrant <paul.durrant@xxxxxxxxxx>
---
 include/evtchn_interface.h   |   36 +-
 src/xenvif.inf               |    6 +-
 src/xenvif/controller.c      | 1336 ++++++++++++++++++++++++++++++++++++++++++
 src/xenvif/controller.h      |  126 ++++
 src/xenvif/frontend.c        |   50 +-
 src/xenvif/frontend.h        |    7 +
 vs2012/xenvif/xenvif.vcxproj |    1 +
 vs2013/xenvif/xenvif.vcxproj |    1 +
 8 files changed, 1549 insertions(+), 14 deletions(-)
 create mode 100644 src/xenvif/controller.c
 create mode 100644 src/xenvif/controller.h

diff --git a/include/evtchn_interface.h b/include/evtchn_interface.h
index 6f8fe42..a9952d6 100644
--- a/include/evtchn_interface.h
+++ b/include/evtchn_interface.h
@@ -180,6 +180,20 @@ typedef VOID
     IN  PXENBUS_EVTCHN_CHANNEL  Channel
     );
 
+/*! \typedef XENBUS_EVTCHN_WAIT
+    \brief Wait for an event to the local end of the channel
+
+    \param Interface The interface header
+    \param Channel The channel handle
+    \param Timeout An optional timeout value (similar to 
KeWaitForSingleObject(), but non-zero values are allowed at DISPATCH_LEVEL).
+*/
+typedef NTSTATUS
+(*XENBUS_EVTCHN_WAIT)(
+    IN  PINTERFACE              Interface,
+    IN  PXENBUS_EVTCHN_CHANNEL  Channel,
+    IN  PLARGE_INTEGER          Timeout OPTIONAL
+    );
+
 /*! \typedef XENBUS_EVTCHN_GET_PORT
     \brief Get the local port number bound to the channel
 
@@ -276,7 +290,25 @@ struct _XENBUS_EVTCHN_INTERFACE_V4 {
     XENBUS_EVTCHN_CLOSE     EvtchnClose;
 };
 
-typedef struct _XENBUS_EVTCHN_INTERFACE_V4 XENBUS_EVTCHN_INTERFACE, 
*PXENBUS_EVTCHN_INTERFACE;
+/*! \struct _XENBUS_EVTCHN_INTERFACE_V5
+    \brief EVTCHN interface version 5
+    \ingroup interfaces
+*/
+struct _XENBUS_EVTCHN_INTERFACE_V5 {
+    INTERFACE               Interface;
+    XENBUS_EVTCHN_ACQUIRE   EvtchnAcquire;
+    XENBUS_EVTCHN_RELEASE   EvtchnRelease;
+    XENBUS_EVTCHN_OPEN      EvtchnOpen;
+    XENBUS_EVTCHN_BIND      EvtchnBind;
+    XENBUS_EVTCHN_UNMASK    EvtchnUnmask;
+    XENBUS_EVTCHN_SEND      EvtchnSend;
+    XENBUS_EVTCHN_TRIGGER   EvtchnTrigger;
+    XENBUS_EVTCHN_WAIT      EvtchnWait;
+    XENBUS_EVTCHN_GET_PORT  EvtchnGetPort;
+    XENBUS_EVTCHN_CLOSE     EvtchnClose;
+};
+
+typedef struct _XENBUS_EVTCHN_INTERFACE_V5 XENBUS_EVTCHN_INTERFACE, 
*PXENBUS_EVTCHN_INTERFACE;
 
 /*! \def XENBUS_EVTCHN
     \brief Macro at assist in method invocation
@@ -287,7 +319,7 @@ typedef struct _XENBUS_EVTCHN_INTERFACE_V4 
XENBUS_EVTCHN_INTERFACE, *PXENBUS_EVT
 #endif  // _WINDLL
 
 #define XENBUS_EVTCHN_INTERFACE_VERSION_MIN 1
-#define XENBUS_EVTCHN_INTERFACE_VERSION_MAX 4
+#define XENBUS_EVTCHN_INTERFACE_VERSION_MAX 5
 
 #endif  // _XENBUS_EVTCHN_INTERFACE_H
 
diff --git a/src/xenvif.inf b/src/xenvif.inf
index 0fa4c98..899260e 100644
--- a/src/xenvif.inf
+++ b/src/xenvif.inf
@@ -58,9 +58,9 @@ 
xenvif_coinst_@MAJOR_VERSION@_@MINOR_VERSION@_@MICRO_VERSION@_@BUILD_NUMBER@.dll
 ; DisplayName          Section         DeviceID
 ; -----------          -------         --------
 
-%XenVifDesc%           =XenVif_Inst,   
XENBUS\VEN_@VENDOR_PREFIX@@VENDOR_DEVICE_ID@&DEV_VIF&REV_08000009
-%XenVifDesc%           =XenVif_Inst,   
XENBUS\VEN_@VENDOR_PREFIX@0001&DEV_VIF&REV_08000009
-%XenVifDesc%           =XenVif_Inst,   
XENBUS\VEN_@VENDOR_PREFIX@0002&DEV_VIF&REV_08000009
+%XenVifDesc%           =XenVif_Inst,   
XENBUS\VEN_@VENDOR_PREFIX@@VENDOR_DEVICE_ID@&DEV_VIF&REV_0800000B
+%XenVifDesc%           =XenVif_Inst,   
XENBUS\VEN_@VENDOR_PREFIX@0001&DEV_VIF&REV_0800000B
+%XenVifDesc%           =XenVif_Inst,   
XENBUS\VEN_@VENDOR_PREFIX@0002&DEV_VIF&REV_0800000B
 
 [XenVif_Inst] 
 CopyFiles=XenVif_Copyfiles
diff --git a/src/xenvif/controller.c b/src/xenvif/controller.c
new file mode 100644
index 0000000..6c6bb3e
--- /dev/null
+++ b/src/xenvif/controller.c
@@ -0,0 +1,1336 @@
+/* Copyright (c) Citrix Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms,
+ * with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * *   Redistributions of source code must retain the above
+ *     copyright notice, this list of conditions and the
+ *     following disclaimer.
+ * *   Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the
+ *     following disclaimer in the documetation and/or other
+ *     materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <ntddk.h>
+#include <procgrp.h>
+#include <ntstrsafe.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <xen.h>
+
+#include <debug_interface.h>
+#include <store_interface.h>
+#include <cache_interface.h>
+#include <gnttab_interface.h>
+#include <evtchn_interface.h>
+
+#include "pdo.h"
+#include "frontend.h"
+#include "controller.h"
+#include "vif.h"
+#include "thread.h"
+#include "registry.h"
+#include "dbg_print.h"
+#include "assert.h"
+#include "util.h"
+
+extern ULONG
+NTAPI
+RtlRandomEx (
+    __inout PULONG Seed
+    );
+
+#define MAXNAMELEN  128
+
+struct _XENVIF_CONTROLLER {
+    PXENVIF_FRONTEND                    Frontend;
+    KSPIN_LOCK                          Lock;
+    PXENBUS_GNTTAB_CACHE                GnttabCache;
+    PMDL                                Mdl;
+    xen_netif_ctrl_front_ring_t         Front;
+    xen_netif_ctrl_sring_t              *Shared;
+    PXENBUS_GNTTAB_ENTRY                Entry;
+    PXENBUS_EVTCHN_CHANNEL              Channel;
+    KDPC                                Dpc;
+    ULONG                               Dpcs;
+    ULONG                               Events;
+    BOOLEAN                             Connected;
+    BOOLEAN                             Enabled;
+    USHORT                              RequestId;
+    struct xen_netif_ctrl_request       Request;
+    struct xen_netif_ctrl_response      Response;
+    XENBUS_GNTTAB_INTERFACE             GnttabInterface;
+    XENBUS_EVTCHN_INTERFACE             EvtchnInterface;
+    XENBUS_STORE_INTERFACE              StoreInterface;
+    XENBUS_DEBUG_INTERFACE              DebugInterface;
+    PXENBUS_DEBUG_CALLBACK              DebugCallback;
+    PXENVIF_THREAD                      WatchdogThread;
+};
+
+#define XENVIF_CONTROLLER_TAG  'TNOC'
+
+static FORCEINLINE PVOID
+__ControllerAllocate(
+    IN  ULONG   Length
+    )
+{
+    return __AllocatePoolWithTag(NonPagedPool, Length, XENVIF_CONTROLLER_TAG);
+}
+
+static FORCEINLINE VOID
+__ControllerFree(
+    IN  PVOID   Buffer
+    )
+{
+    __FreePoolWithTag(Buffer, XENVIF_CONTROLLER_TAG);
+}
+
+static FORCEINLINE VOID
+__drv_requiresIRQL(DISPATCH_LEVEL)
+__ControllerAcquireLock(
+    IN  PXENVIF_CONTROLLER  Controller
+    )
+{
+    ASSERT3U(KeGetCurrentIrql(), ==, DISPATCH_LEVEL);
+
+    KeAcquireSpinLockAtDpcLevel(&Controller->Lock);
+}
+
+static FORCEINLINE VOID
+__drv_requiresIRQL(DISPATCH_LEVEL)
+__ControllerReleaseLock(
+    IN  PXENVIF_CONTROLLER  Controller
+    )
+{
+    KeReleaseSpinLockFromDpcLevel(&Controller->Lock);
+}
+
+static VOID
+ControllerAcquireLock(
+    IN  PXENVIF_CONTROLLER  Controller
+    )
+{
+    __ControllerAcquireLock(Controller);
+}
+
+static VOID
+ControllerReleaseLock(
+    IN  PXENVIF_CONTROLLER  Controller
+    )
+{
+    __ControllerReleaseLock(Controller);
+}
+
+static FORCEINLINE VOID
+__ControllerSend(
+    IN  PXENVIF_CONTROLLER  Controller
+    )
+{
+    (VOID) XENBUS_EVTCHN(Send,
+                         &Controller->EvtchnInterface,
+                         Controller->Channel);
+}
+
+VOID
+ControllerPoll(
+    IN  PXENVIF_CONTROLLER          Controller
+    )
+{
+    RING_IDX                        rsp_prod;
+    RING_IDX                        rsp_cons;
+    struct xen_netif_ctrl_response  *rsp;
+
+    KeMemoryBarrier();
+
+    rsp_prod = Controller->Shared->rsp_prod;
+    rsp_cons = Controller->Front.rsp_cons;
+
+    KeMemoryBarrier();
+
+    if (rsp_cons == rsp_prod)
+        return;
+
+    rsp = RING_GET_RESPONSE(&Controller->Front, rsp_cons);
+    rsp_cons++;
+
+    Controller->Response = *rsp;
+
+    KeMemoryBarrier();
+
+    Controller->Front.rsp_cons = rsp_cons;
+    Controller->Shared->rsp_event = rsp_cons + 1;
+}
+
+static NTSTATUS
+ControllerPutRequest(
+    IN  PXENVIF_CONTROLLER          Controller,
+    IN  USHORT                      Type,
+    IN  ULONG                       Data0,
+    IN  ULONG                       Data1,
+    IN  ULONG                       Data2
+    )
+{
+    RING_IDX                        req_prod;
+    struct xen_netif_ctrl_request   *req;
+    BOOLEAN                         Notify;
+    NTSTATUS                        status;
+
+    status = STATUS_INSUFFICIENT_RESOURCES;
+    if (RING_FULL(&Controller->Front))
+        goto fail1;
+
+    Controller->Request.type = Type;
+    Controller->Request.id = Controller->RequestId++;
+    Controller->Request.data[0] = Data0;
+    Controller->Request.data[1] = Data1;
+    Controller->Request.data[2] = Data2;
+
+    req_prod = Controller->Front.req_prod_pvt;
+
+    req = RING_GET_REQUEST(&Controller->Front, req_prod);
+    req_prod++;
+
+    *req = Controller->Request;
+
+    KeMemoryBarrier();
+
+    Controller->Front.req_prod_pvt = req_prod;
+
+#pragma warning (push)
+#pragma warning (disable:4244)
+
+    // Make the requests visible to the backend
+    RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&Controller->Front, Notify);
+
+#pragma warning (pop)
+
+    if (Notify)
+        __ControllerSend(Controller);
+
+    return STATUS_SUCCESS;
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
+}
+
+#define TIME_US(_us)        ((_us) * 10)
+#define TIME_MS(_ms)        (TIME_US((_ms) * 1000))
+#define TIME_S(_s)          (TIME_MS((_s) * 1000))
+#define TIME_RELATIVE(_t)   (-(_t))
+
+#define XENVIF_CONTROLLER_POLL_PERIOD 5
+
+static NTSTATUS
+ControllerGetResponse(
+    IN  PXENVIF_CONTROLLER          Controller,
+    OUT PULONG                      Data OPTIONAL
+    )
+{
+    LARGE_INTEGER                   Timeout;
+    NTSTATUS                        status;
+
+    Timeout.QuadPart = TIME_RELATIVE(TIME_S(XENVIF_CONTROLLER_POLL_PERIOD));
+
+    for (;;) {
+        ControllerPoll(Controller);
+        KeMemoryBarrier();
+
+        if (Controller->Response.id == Controller->Request.id)
+            break;
+
+        status = XENBUS_EVTCHN(Wait,
+                               &Controller->EvtchnInterface,
+                               Controller->Channel,
+                               &Timeout);
+        if (status == STATUS_TIMEOUT)
+            Warning("TIMED OUT\n");
+    }
+
+    ASSERT3U(Controller->Response.type, ==, Controller->Request.type);
+
+    switch (Controller->Response.status) {
+    case XEN_NETIF_CTRL_STATUS_SUCCESS:
+        status = STATUS_SUCCESS;
+        break;
+
+    case XEN_NETIF_CTRL_STATUS_NOT_SUPPORTED:
+        status = STATUS_NOT_SUPPORTED;
+        break;
+
+    case XEN_NETIF_CTRL_STATUS_INVALID_PARAMETER:
+        status = STATUS_INVALID_PARAMETER;
+        break;
+
+    case XEN_NETIF_CTRL_STATUS_BUFFER_OVERFLOW:
+        status = STATUS_BUFFER_OVERFLOW;
+        break;
+
+    default:
+        status = STATUS_UNSUCCESSFUL;
+        break;
+    }
+
+    if (NT_SUCCESS(status) && Data != NULL)
+        *Data = Controller->Response.data;
+
+    RtlZeroMemory(&Controller->Request,
+                  sizeof (struct xen_netif_ctrl_request));
+    RtlZeroMemory(&Controller->Response,
+                  sizeof (struct xen_netif_ctrl_response));
+
+    return status;
+}
+
+#define XENVIF_CONTROLLER_WATCHDOG_PERIOD 15
+
+static NTSTATUS
+ControllerWatchdog(
+    IN  PXENVIF_THREAD  Self,
+    IN  PVOID           Context
+    )
+{
+    PXENVIF_CONTROLLER  Controller = Context;
+    LARGE_INTEGER       Timeout;
+    RING_IDX            rsp_prod;
+    RING_IDX            rsp_cons;
+
+    Trace("====>\n");
+
+    Timeout.QuadPart = 
TIME_RELATIVE(TIME_S(XENVIF_CONTROLLER_WATCHDOG_PERIOD));
+
+    rsp_prod = 0;
+    rsp_cons = 0;
+
+    for (;;) {
+        PKEVENT Event;
+        KIRQL   Irql;
+
+        Event = ThreadGetEvent(Self);
+
+        (VOID) KeWaitForSingleObject(Event,
+                                     Executive,
+                                     KernelMode,
+                                     FALSE,
+                                     &Timeout);
+        KeClearEvent(Event);
+
+        if (ThreadIsAlerted(Self))
+            break;
+
+        KeRaiseIrql(DISPATCH_LEVEL, &Irql);
+        __ControllerAcquireLock(Controller);
+
+        if (Controller->Enabled) {
+            KeMemoryBarrier();
+
+            if (Controller->Shared->rsp_prod != rsp_prod &&
+                 Controller->Front.rsp_cons == rsp_cons) {
+                XENBUS_DEBUG(Trigger,
+                             &Controller->DebugInterface,
+                             Controller->DebugCallback);
+
+                // Try to move things along
+                ControllerPoll(Controller);
+                __ControllerSend(Controller);
+            }
+
+            KeMemoryBarrier();
+
+            rsp_prod = Controller->Shared->rsp_prod;
+            rsp_cons = Controller->Front.rsp_cons;
+        }
+
+        __ControllerReleaseLock(Controller);
+        KeLowerIrql(Irql);
+    }
+
+    Trace("<====\n");
+
+    return STATUS_SUCCESS;
+}
+
+__drv_maxIRQL(DISPATCH_LEVEL)
+__drv_minIRQL(DISPATCH_LEVEL)
+__drv_requiresIRQL(DISPATCH_LEVEL)
+__drv_sameIRQL
+static VOID
+ControllerDpc(
+    IN  PKDPC                   Dpc,
+    IN  PVOID                   Context,
+    IN  PVOID                   Argument1,
+    IN  PVOID                   Argument2
+    )
+{
+    PXENVIF_CONTROLLER          Controller = Context;
+
+    UNREFERENCED_PARAMETER(Dpc);
+    UNREFERENCED_PARAMETER(Argument1);
+    UNREFERENCED_PARAMETER(Argument2);
+
+    ASSERT(Controller != NULL);
+
+    __ControllerAcquireLock(Controller);
+
+    if (Controller->Enabled)
+        ControllerPoll(Controller);
+
+    __ControllerReleaseLock(Controller);
+}
+
+KSERVICE_ROUTINE    TransmitterRingEvtchnCallback;
+
+BOOLEAN
+ControllerEvtchnCallback(
+    IN  PKINTERRUPT             InterruptObject,
+    IN  PVOID                   Argument
+    )
+{
+    PXENVIF_CONTROLLER          Controller = Argument;
+
+    UNREFERENCED_PARAMETER(InterruptObject);
+
+    ASSERT(Controller != NULL);
+
+    Controller->Events++;
+
+    if (KeInsertQueueDpc(&Controller->Dpc, NULL, NULL))
+        Controller->Dpcs++;
+
+    return TRUE;
+}
+
+static VOID
+ControllerDebugCallback(
+    IN  PVOID           Argument,
+    IN  BOOLEAN         Crashing
+    )
+{
+    UNREFERENCED_PARAMETER(Argument);
+    UNREFERENCED_PARAMETER(Crashing);
+}
+
+NTSTATUS
+ControllerInitialize(
+    IN  PXENVIF_FRONTEND    Frontend,
+    OUT PXENVIF_CONTROLLER  *Controller
+    )
+{
+    LARGE_INTEGER           Now;
+    ULONG                   Seed;
+    NTSTATUS                status;
+
+    *Controller = __ControllerAllocate(sizeof (XENVIF_CONTROLLER));
+
+    status = STATUS_NO_MEMORY;
+    if (*Controller == NULL)
+        goto fail1;
+
+    FdoGetDebugInterface(PdoGetFdo(FrontendGetPdo(Frontend)),
+                         &(*Controller)->DebugInterface);
+
+    FdoGetStoreInterface(PdoGetFdo(FrontendGetPdo(Frontend)),
+                         &(*Controller)->StoreInterface);
+
+    FdoGetGnttabInterface(PdoGetFdo(FrontendGetPdo(Frontend)),
+                          &(*Controller)->GnttabInterface);
+
+    FdoGetEvtchnInterface(PdoGetFdo(FrontendGetPdo(Frontend)),
+                          &(*Controller)->EvtchnInterface);
+
+    KeInitializeSpinLock(&(*Controller)->Lock);
+    KeInitializeDpc(&(*Controller)->Dpc, ControllerDpc, *Controller);
+
+    KeQuerySystemTime(&Now);
+    Seed = Now.LowPart;
+
+    (*Controller)->RequestId = (USHORT)RtlRandomEx(&Seed);
+
+    status = ThreadCreate(ControllerWatchdog,
+                          *Controller,
+                          &(*Controller)->WatchdogThread);
+    if (!NT_SUCCESS(status))
+        goto fail2;
+
+    (*Controller)->Frontend = Frontend;
+
+    return STATUS_SUCCESS;
+
+fail2:
+    Error("fail2\n");
+
+    RtlZeroMemory(&(*Controller)->Lock,
+                  sizeof (KSPIN_LOCK));
+
+    RtlZeroMemory(&(*Controller)->GnttabInterface,
+                  sizeof (XENBUS_GNTTAB_INTERFACE));
+
+    RtlZeroMemory(&(*Controller)->StoreInterface,
+                  sizeof (XENBUS_STORE_INTERFACE));
+
+    RtlZeroMemory(&(*Controller)->DebugInterface,
+                  sizeof (XENBUS_DEBUG_INTERFACE));
+
+    RtlZeroMemory(&(*Controller)->EvtchnInterface,
+                  sizeof (XENBUS_EVTCHN_INTERFACE));
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
+}
+
+NTSTATUS
+ControllerConnect(
+    IN  PXENVIF_CONTROLLER      Controller
+    )
+{
+    PXENVIF_FRONTEND            Frontend;
+    PCHAR                       Buffer;
+    BOOLEAN                     Feature;
+    PFN_NUMBER                  Pfn;
+    CHAR                        Name[MAXNAMELEN];
+    ULONG                       Index;
+    NTSTATUS                    status;
+
+    Trace("====>\n");
+
+    Frontend = Controller->Frontend;
+
+    status = XENBUS_DEBUG(Acquire, &Controller->DebugInterface);
+    if (!NT_SUCCESS(status))
+        goto fail1;
+
+    status = XENBUS_STORE(Acquire, &Controller->StoreInterface);
+    if (!NT_SUCCESS(status))
+        goto fail2;
+
+    status = XENBUS_EVTCHN(Acquire, &Controller->EvtchnInterface);
+    if (!NT_SUCCESS(status))
+        goto fail3;
+
+    status = XENBUS_GNTTAB(Acquire, &Controller->GnttabInterface);
+    if (!NT_SUCCESS(status))
+        goto fail4;
+
+    status = XENBUS_STORE(Read,
+                          &Controller->StoreInterface,
+                          NULL,
+                          FrontendGetBackendPath(Frontend),
+                          "feature-ctrl-ring",
+                          &Buffer);
+    if (!NT_SUCCESS(status)) {
+        Feature = FALSE;
+    } else {
+        Feature = (BOOLEAN)strtol(Buffer, NULL, 2);
+
+        XENBUS_STORE(Free,
+                     &Controller->StoreInterface,
+                     Buffer);
+    }
+
+    if (!Feature)
+        goto done;
+
+    status = RtlStringCbPrintfA(Name,
+                                sizeof (Name),
+                                "%s_controller",
+                                FrontendGetPath(Frontend));
+    if (!NT_SUCCESS(status))
+        goto fail5;
+
+    for (Index = 0; Name[Index] != '\0'; Index++)
+        if (Name[Index] == '/')
+            Name[Index] = '_';
+
+    status = XENBUS_GNTTAB(CreateCache,
+                           &Controller->GnttabInterface,
+                           Name,
+                           0,
+                           ControllerAcquireLock,
+                           ControllerReleaseLock,
+                           Controller,
+                           &Controller->GnttabCache);
+    if (!NT_SUCCESS(status))
+        goto fail6;
+
+    Controller->Mdl = __AllocatePage();
+
+    status = STATUS_NO_MEMORY;
+    if (Controller->Mdl == NULL)
+        goto fail7;
+
+    Controller->Shared = MmGetSystemAddressForMdlSafe(Controller->Mdl,
+                                                      NormalPagePriority);
+    ASSERT(Controller->Shared != NULL);
+
+    SHARED_RING_INIT(Controller->Shared);
+    FRONT_RING_INIT(&Controller->Front, Controller->Shared, PAGE_SIZE);
+    ASSERT3P(Controller->Front.sring, ==, Controller->Shared);
+
+    Pfn = MmGetMdlPfnArray(Controller->Mdl)[0];
+
+    status = XENBUS_GNTTAB(PermitForeignAccess,
+                           &Controller->GnttabInterface,
+                           Controller->GnttabCache,
+                           TRUE,
+                           FrontendGetBackendDomain(Frontend),
+                           Pfn,
+                           FALSE,
+                           &Controller->Entry);
+    if (!NT_SUCCESS(status))
+        goto fail8;
+
+    Controller->Channel = XENBUS_EVTCHN(Open,
+                                        &Controller->EvtchnInterface,
+                                        XENBUS_EVTCHN_TYPE_UNBOUND,
+                                        ControllerEvtchnCallback,
+                                        Controller,
+                                        FrontendGetBackendDomain(Frontend),
+                                        FALSE);
+
+    status = STATUS_UNSUCCESSFUL;
+    if (Controller->Channel == NULL)
+        goto fail9;
+
+    XENBUS_EVTCHN(Unmask,
+                  &Controller->EvtchnInterface,
+                  Controller->Channel,
+                  FALSE);
+
+    status = XENBUS_DEBUG(Register,
+                          &Controller->DebugInterface,
+                          __MODULE__ "|CONTROLLER",
+                          ControllerDebugCallback,
+                          Controller,
+                          &Controller->DebugCallback);
+    if (!NT_SUCCESS(status))
+        goto fail10;
+
+    __ControllerAcquireLock(Controller);
+
+    Controller->Connected = TRUE;
+
+    if (KeInsertQueueDpc(&Controller->Dpc, NULL, NULL))
+        Controller->Dpcs++;
+
+    __ControllerReleaseLock(Controller);
+
+done:
+    Trace("<====\n");
+    return STATUS_SUCCESS;
+
+fail10:
+    Error("fail10\n");
+
+    XENBUS_EVTCHN(Close,
+                  &Controller->EvtchnInterface,
+                  Controller->Channel);
+    Controller->Channel = NULL;
+
+    Controller->Events = 0;
+    Controller->Dpcs = 0;
+
+fail9:
+    Error("fail9\n");
+
+    (VOID) XENBUS_GNTTAB(RevokeForeignAccess,
+                         &Controller->GnttabInterface,
+                         Controller->GnttabCache,
+                         TRUE,
+                         Controller->Entry);
+    Controller->Entry = NULL;
+
+fail8:
+    Error("fail8\n");
+
+    RtlZeroMemory(&Controller->Front,
+                  sizeof (struct xen_netif_ctrl_front_ring));
+    RtlZeroMemory(Controller->Shared, PAGE_SIZE);
+
+    Controller->Shared = NULL;
+    __FreePage(Controller->Mdl);
+    Controller->Mdl = NULL;
+
+fail7:
+    Error("fail7\n");
+
+    XENBUS_GNTTAB(DestroyCache,
+                  &Controller->GnttabInterface,
+                  Controller->GnttabCache);
+    Controller->GnttabCache = NULL;
+
+fail6:
+    Error("fail6\n");
+
+fail5:
+    Error("fail5\n");
+
+    XENBUS_GNTTAB(Release, &Controller->GnttabInterface);
+
+fail4:
+    Error("fail4\n");
+
+    XENBUS_EVTCHN(Release, &Controller->EvtchnInterface);
+
+fail3:
+    Error("fail3\n");
+
+    XENBUS_STORE(Release, &Controller->StoreInterface);
+
+fail2:
+    Error("fail2\n");
+
+    XENBUS_DEBUG(Release, &Controller->DebugInterface);
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
+}
+
+NTSTATUS
+ControllerStoreWrite(
+    IN  PXENVIF_CONTROLLER          Controller,
+    IN  PXENBUS_STORE_TRANSACTION   Transaction
+    )
+{
+    PXENVIF_FRONTEND                Frontend;
+    ULONG                           Port;
+    NTSTATUS                        status;
+
+    if (!Controller->Connected)
+        goto done;
+
+    Frontend = Controller->Frontend;
+
+    status = XENBUS_STORE(Printf,
+                          &Controller->StoreInterface,
+                          Transaction,
+                          FrontendGetPath(Frontend),
+                          "ctrl-ring-ref",
+                          "%u",
+                          XENBUS_GNTTAB(GetReference,
+                                        &Controller->GnttabInterface,
+                                        Controller->Entry));
+    if (!NT_SUCCESS(status))
+        goto fail1;
+
+    Port = XENBUS_EVTCHN(GetPort,
+                         &Controller->EvtchnInterface,
+                         Controller->Channel);
+
+    status = XENBUS_STORE(Printf,
+                          &Controller->StoreInterface,
+                          Transaction,
+                          FrontendGetPath(Frontend),
+                          "event-channel-ctrl",
+                          "%u",
+                          Port);
+    if (!NT_SUCCESS(status))
+        goto fail2;
+
+done:
+    return STATUS_SUCCESS;
+
+fail2:
+    Error("fail2\n");
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
+}
+
+VOID
+ControllerEnable(
+    IN  PXENVIF_CONTROLLER      Controller
+    )
+{
+    Trace("====>\n");
+
+    __ControllerAcquireLock(Controller);
+
+    Controller->Enabled = TRUE;
+
+    __ControllerReleaseLock(Controller);
+
+    Trace("<====\n");
+}
+
+VOID
+ControllerDisable(
+    IN  PXENVIF_CONTROLLER      Controller
+    )
+{
+    Trace("====>\n");
+
+    __ControllerAcquireLock(Controller);
+
+    Controller->Enabled = FALSE;
+
+    __ControllerReleaseLock(Controller);
+
+    Trace("<====\n");
+}
+
+VOID
+ControllerDisconnect(
+    IN  PXENVIF_CONTROLLER  Controller
+    )
+{
+    Trace("====>\n");
+
+    __ControllerAcquireLock(Controller);
+
+    if (!Controller->Connected)
+        goto done;
+
+    Controller->Connected = FALSE;
+
+    __ControllerReleaseLock(Controller);
+
+    XENBUS_DEBUG(Deregister,
+                 &Controller->DebugInterface,
+                 Controller->DebugCallback);
+    Controller->DebugCallback = NULL;
+
+    XENBUS_EVTCHN(Close,
+                  &Controller->EvtchnInterface,
+                  Controller->Channel);
+    Controller->Channel = NULL;
+
+    Controller->Events = 0;
+    Controller->Dpcs = 0;
+
+    (VOID) XENBUS_GNTTAB(RevokeForeignAccess,
+                         &Controller->GnttabInterface,
+                         Controller->GnttabCache,
+                         TRUE,
+                         Controller->Entry);
+    Controller->Entry = NULL;
+
+    RtlZeroMemory(&Controller->Front,
+                  sizeof (struct xen_netif_ctrl_front_ring));
+    RtlZeroMemory(Controller->Shared, PAGE_SIZE);
+
+    Controller->Shared = NULL;
+    __FreePage(Controller->Mdl);
+    Controller->Mdl = NULL;
+
+    XENBUS_GNTTAB(DestroyCache,
+                  &Controller->GnttabInterface,
+                  Controller->GnttabCache);
+    Controller->GnttabCache = NULL;
+
+    XENBUS_GNTTAB(Release, &Controller->GnttabInterface);
+
+    XENBUS_EVTCHN(Release, &Controller->EvtchnInterface);
+
+    XENBUS_STORE(Release, &Controller->StoreInterface);
+
+    XENBUS_DEBUG(Release, &Controller->DebugInterface);
+
+done:
+    Trace("<====\n");
+}
+
+VOID
+ControllerTeardown(
+    IN  PXENVIF_CONTROLLER  Controller
+    )
+{
+    ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
+    KeFlushQueuedDpcs();
+
+    Controller->Frontend = NULL;
+
+    ThreadAlert(Controller->WatchdogThread);
+    ThreadJoin(Controller->WatchdogThread);
+    Controller->WatchdogThread = NULL;
+
+    Controller->RequestId = 0;
+
+    RtlZeroMemory(&Controller->Dpc,
+                  sizeof (KDPC));
+
+    RtlZeroMemory(&Controller->Lock,
+                  sizeof (KSPIN_LOCK));
+
+    RtlZeroMemory(&Controller->GnttabInterface,
+                  sizeof (XENBUS_GNTTAB_INTERFACE));
+
+    RtlZeroMemory(&Controller->StoreInterface,
+                  sizeof (XENBUS_STORE_INTERFACE));
+
+    RtlZeroMemory(&Controller->DebugInterface,
+                  sizeof (XENBUS_DEBUG_INTERFACE));
+
+    RtlZeroMemory(&Controller->EvtchnInterface,
+                  sizeof (XENBUS_EVTCHN_INTERFACE));
+
+    ASSERT(IsZeroMemory(Controller, sizeof (XENVIF_CONTROLLER)));
+    __ControllerFree(Controller);
+}
+
+NTSTATUS
+ControllerSetHashAlgorithm(
+    IN  PXENVIF_CONTROLLER  Controller,
+    IN  ULONG               Algorithm
+    )
+{
+    PXENVIF_FRONTEND        Frontend;
+    NTSTATUS                status;
+
+    Frontend = Controller->Frontend;
+
+    __ControllerAcquireLock(Controller);
+
+    status = STATUS_NOT_SUPPORTED;
+    if (!Controller->Connected)
+        goto fail1;
+
+    status = ControllerPutRequest(Controller,
+                                  XEN_NETIF_CTRL_TYPE_SET_HASH_ALGORITHM,
+                                  Algorithm,
+                                  0,
+                                  0);
+    if (!NT_SUCCESS(status))
+        goto fail2;
+
+    status = ControllerGetResponse(Controller, NULL);
+    if (!NT_SUCCESS(status))
+        goto fail3;
+
+    __ControllerReleaseLock(Controller);
+
+    return STATUS_SUCCESS;
+
+fail3:
+    Error("fail3\n");
+
+fail2:
+    Error("fail2\n");
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    __ControllerReleaseLock(Controller);
+
+    return status;
+}
+
+NTSTATUS
+ControllerGetHashFlags(
+    IN  PXENVIF_CONTROLLER  Controller,
+    IN  PULONG              Flags
+    )
+{
+    PXENVIF_FRONTEND        Frontend;
+    NTSTATUS                status;
+
+    Frontend = Controller->Frontend;
+
+    __ControllerAcquireLock(Controller);
+
+    status = STATUS_NOT_SUPPORTED;
+    if (!Controller->Enabled)
+        goto fail1;
+
+    status = ControllerPutRequest(Controller,
+                                  XEN_NETIF_CTRL_TYPE_GET_HASH_FLAGS,
+                                  0,
+                                  0,
+                                  0);
+    if (!NT_SUCCESS(status))
+        goto fail2;
+
+    status = ControllerGetResponse(Controller, Flags);
+    if (!NT_SUCCESS(status))
+        goto fail3;
+
+    __ControllerReleaseLock(Controller);
+
+    return STATUS_SUCCESS;
+
+fail3:
+    Error("fail3\n");
+
+fail2:
+    Error("fail2\n");
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    __ControllerReleaseLock(Controller);
+
+    return status;
+}
+
+NTSTATUS
+ControllerSetHashFlags(
+    IN  PXENVIF_CONTROLLER  Controller,
+    IN  ULONG               Flags
+    )
+{
+    PXENVIF_FRONTEND        Frontend;
+    NTSTATUS                status;
+
+    Frontend = Controller->Frontend;
+
+    __ControllerAcquireLock(Controller);
+
+    status = STATUS_NOT_SUPPORTED;
+    if (!Controller->Connected)
+        goto fail1;
+
+    status = ControllerPutRequest(Controller,
+                                  XEN_NETIF_CTRL_TYPE_SET_HASH_FLAGS,
+                                  Flags,
+                                  0,
+                                  0);
+    if (!NT_SUCCESS(status))
+        goto fail2;
+
+    status = ControllerGetResponse(Controller, NULL);
+    if (!NT_SUCCESS(status))
+        goto fail3;
+
+    __ControllerReleaseLock(Controller);
+
+    return STATUS_SUCCESS;
+
+fail3:
+    Error("fail3\n");
+
+fail2:
+    Error("fail2\n");
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    __ControllerReleaseLock(Controller);
+
+    return status;
+}
+
+NTSTATUS
+ControllerSetHashKey(
+    IN  PXENVIF_CONTROLLER  Controller,
+    IN  PUCHAR              Key,
+    IN  ULONG               Size
+    )
+{
+    PXENVIF_FRONTEND        Frontend;
+    PMDL                    Mdl;
+    PUCHAR                  Buffer;
+    PFN_NUMBER              Pfn;
+    PXENBUS_GNTTAB_ENTRY    Entry;
+    NTSTATUS                status;
+
+    Frontend = Controller->Frontend;
+
+    __ControllerAcquireLock(Controller);
+
+    status = STATUS_NOT_SUPPORTED;
+    if (!Controller->Enabled)
+        goto fail1;
+
+    Mdl = __AllocatePage();
+
+    status = STATUS_NO_MEMORY;
+    if (Controller->Mdl == NULL)
+        goto fail2;
+
+    Buffer = MmGetSystemAddressForMdlSafe(Mdl, NormalPagePriority);
+    ASSERT(Buffer != NULL);
+
+    RtlCopyMemory(Buffer, Key, Size);
+
+    Pfn = MmGetMdlPfnArray(Mdl)[0];
+
+    status = XENBUS_GNTTAB(PermitForeignAccess,
+                           &Controller->GnttabInterface,
+                           Controller->GnttabCache,
+                           TRUE,
+                           FrontendGetBackendDomain(Frontend),
+                           Pfn,
+                           FALSE,
+                           &Entry);
+    if (!NT_SUCCESS(status))
+        goto fail3;
+
+    status = ControllerPutRequest(Controller,
+                                  XEN_NETIF_CTRL_TYPE_SET_HASH_KEY,
+                                  XENBUS_GNTTAB(GetReference,
+                                                &Controller->GnttabInterface,
+                                                Entry),
+                                  Size,
+                                  0);
+    if (!NT_SUCCESS(status))
+        goto fail4;
+
+    status = ControllerGetResponse(Controller, NULL);
+    if (!NT_SUCCESS(status))
+        goto fail5;
+
+    (VOID) XENBUS_GNTTAB(RevokeForeignAccess,
+                         &Controller->GnttabInterface,
+                         Controller->GnttabCache,
+                         TRUE,
+                         Entry);
+
+    __FreePage(Mdl);
+
+    __ControllerReleaseLock(Controller);
+
+    return STATUS_SUCCESS;
+
+fail5:
+    Error("fail5\n");
+
+fail4:
+    Error("fail4\n");
+
+    (VOID) XENBUS_GNTTAB(RevokeForeignAccess,
+                         &Controller->GnttabInterface,
+                         Controller->GnttabCache,
+                         TRUE,
+                         Entry);
+
+fail3:
+    Error("fail3\n");
+
+    __FreePage(Mdl);
+
+fail2:
+    Error("fail2\n");
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    __ControllerReleaseLock(Controller);
+
+    return status;
+}
+
+NTSTATUS
+ControllerGetHashMappingSize(
+    IN  PXENVIF_CONTROLLER  Controller,
+    IN  PULONG              Size
+    )
+{
+    PXENVIF_FRONTEND        Frontend;
+    NTSTATUS                status;
+
+    Frontend = Controller->Frontend;
+
+    __ControllerAcquireLock(Controller);
+
+    status = STATUS_NOT_SUPPORTED;
+    if (!Controller->Enabled)
+        goto fail1;
+
+    status = ControllerPutRequest(Controller,
+                                  XEN_NETIF_CTRL_TYPE_GET_HASH_MAPPING_SIZE,
+                                  0,
+                                  0,
+                                  0);
+    if (!NT_SUCCESS(status))
+        goto fail2;
+
+    status = ControllerGetResponse(Controller, Size);
+    if (!NT_SUCCESS(status))
+        goto fail3;
+
+    __ControllerReleaseLock(Controller);
+
+    return STATUS_SUCCESS;
+
+fail3:
+    Error("fail3\n");
+
+fail2:
+    Error("fail2\n");
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    __ControllerReleaseLock(Controller);
+
+    return status;
+}
+
+NTSTATUS
+ControllerSetHashMappingSize(
+    IN  PXENVIF_CONTROLLER  Controller,
+    IN  ULONG               Size
+    )
+{
+    PXENVIF_FRONTEND        Frontend;
+    NTSTATUS                status;
+
+    Frontend = Controller->Frontend;
+
+    __ControllerAcquireLock(Controller);
+
+    status = STATUS_NOT_SUPPORTED;
+    if (!Controller->Enabled)
+        goto fail1;
+
+    status = ControllerPutRequest(Controller,
+                                  XEN_NETIF_CTRL_TYPE_SET_HASH_MAPPING_SIZE,
+                                  Size,
+                                  0,
+                                  0);
+    if (!NT_SUCCESS(status))
+        goto fail2;
+
+    status = ControllerGetResponse(Controller, NULL);
+    if (!NT_SUCCESS(status))
+        goto fail3;
+
+    __ControllerReleaseLock(Controller);
+
+    return STATUS_SUCCESS;
+
+fail3:
+    Error("fail3\n");
+
+fail2:
+    Error("fail2\n");
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    __ControllerReleaseLock(Controller);
+
+    return status;
+}
+
+NTSTATUS
+ControllerSetHashMapping(
+    IN  PXENVIF_CONTROLLER  Controller,
+    IN  PULONG              Mapping,
+    IN  ULONG               Size,
+    IN  ULONG               Offset
+    )
+{
+    PXENVIF_FRONTEND        Frontend;
+    PMDL                    Mdl;
+    PUCHAR                  Buffer;
+    PFN_NUMBER              Pfn;
+    PXENBUS_GNTTAB_ENTRY    Entry;
+    NTSTATUS                status;
+
+    Frontend = Controller->Frontend;
+
+    __ControllerAcquireLock(Controller);
+
+    status = STATUS_NOT_SUPPORTED;
+    if (!Controller->Enabled)
+        goto fail1;
+
+    status = STATUS_INVALID_PARAMETER;
+    if (Size * sizeof (ULONG) > PAGE_SIZE)
+        goto fail2;
+
+    Mdl = __AllocatePage();
+
+    status = STATUS_NO_MEMORY;
+    if (Controller->Mdl == NULL)
+        goto fail3;
+
+    Buffer = MmGetSystemAddressForMdlSafe(Mdl, NormalPagePriority);
+    ASSERT(Buffer != NULL);
+
+    RtlCopyMemory(Buffer, Mapping, Size * sizeof (ULONG));
+
+    Pfn = MmGetMdlPfnArray(Mdl)[0];
+
+    status = XENBUS_GNTTAB(PermitForeignAccess,
+                           &Controller->GnttabInterface,
+                           Controller->GnttabCache,
+                           TRUE,
+                           FrontendGetBackendDomain(Frontend),
+                           Pfn,
+                           FALSE,
+                           &Entry);
+    if (!NT_SUCCESS(status))
+        goto fail4;
+
+    status = ControllerPutRequest(Controller,
+                                  XEN_NETIF_CTRL_TYPE_SET_HASH_MAPPING,
+                                  XENBUS_GNTTAB(GetReference,
+                                                &Controller->GnttabInterface,
+                                                Entry),
+                                  Size,
+                                  Offset);
+    if (!NT_SUCCESS(status))
+        goto fail5;
+
+    status = ControllerGetResponse(Controller, NULL);
+    if (!NT_SUCCESS(status))
+        goto fail6;
+
+    (VOID) XENBUS_GNTTAB(RevokeForeignAccess,
+                         &Controller->GnttabInterface,
+                         Controller->GnttabCache,
+                         TRUE,
+                         Entry);
+
+    __FreePage(Mdl);
+
+    __ControllerReleaseLock(Controller);
+
+    return STATUS_SUCCESS;
+
+fail6:
+    Error("fail6\n");
+
+fail5:
+    Error("fail5\n");
+
+    (VOID) XENBUS_GNTTAB(RevokeForeignAccess,
+                         &Controller->GnttabInterface,
+                         Controller->GnttabCache,
+                         TRUE,
+                         Entry);
+
+fail4:
+    Error("fail4\n");
+
+    __FreePage(Mdl);
+
+fail3:
+    Error("fail3\n");
+
+fail2:
+    Error("fail2\n");
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    __ControllerReleaseLock(Controller);
+
+    return status;
+}
diff --git a/src/xenvif/controller.h b/src/xenvif/controller.h
new file mode 100644
index 0000000..5a7b688
--- /dev/null
+++ b/src/xenvif/controller.h
@@ -0,0 +1,126 @@
+/* Copyright (c) Citrix Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms,
+ * with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * *   Redistributions of source code must retain the above
+ *     copyright notice, this list of conditions and the
+ *     following disclaimer.
+ * *   Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the
+ *     following disclaimer in the documentation and/or other
+ *     materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _XENVIF_CONTROLLER_H
+#define _XENVIF_CONTROLLER_H
+
+#include <ntddk.h>
+
+#include <vif_interface.h>
+
+#include "frontend.h"
+
+typedef struct _XENVIF_CONTROLLER XENVIF_CONTROLLER, *PXENVIF_CONTROLLER;
+
+extern NTSTATUS
+ControllerInitialize(
+    IN  PXENVIF_FRONTEND    Frontend,
+    OUT PXENVIF_CONTROLLER  *Controller
+    );
+
+extern NTSTATUS
+ControllerConnect(
+    IN  PXENVIF_CONTROLLER  Controller
+    );
+
+extern NTSTATUS
+ControllerStoreWrite(
+    IN  PXENVIF_CONTROLLER          Controller,
+    IN  PXENBUS_STORE_TRANSACTION   Transaction
+    );
+
+extern VOID
+ControllerEnable(
+    IN  PXENVIF_CONTROLLER  Controller
+    );
+
+extern VOID
+ControllerDisable(
+    IN  PXENVIF_CONTROLLER  Controller
+    );
+
+extern VOID
+ControllerDisconnect(
+    IN  PXENVIF_CONTROLLER  Controller
+    );
+
+extern VOID
+ControllerTeardown(
+    IN  PXENVIF_CONTROLLER  Controller
+    );
+
+extern NTSTATUS
+ControllerSetHashAlgorithm(
+    IN  PXENVIF_CONTROLLER  Controller,
+    IN  ULONG               Algorithm
+    );
+
+extern NTSTATUS
+ControllerGetHashFlags(
+    IN  PXENVIF_CONTROLLER  Controller,
+    IN  PULONG              Flags
+    );
+
+extern NTSTATUS
+ControllerSetHashFlags(
+    IN  PXENVIF_CONTROLLER  Controller,
+    IN  ULONG               Flags
+    );
+
+extern NTSTATUS
+ControllerSetHashKey(
+    IN  PXENVIF_CONTROLLER  Controller,
+    IN  PUCHAR              Key,
+    IN  ULONG               Size
+    );
+
+extern NTSTATUS
+ControllerGetHashMappingSize(
+    IN  PXENVIF_CONTROLLER  Controller,
+    IN  PULONG              Size
+    );
+
+extern NTSTATUS
+ControllerSetHashMappingSize(
+    IN  PXENVIF_CONTROLLER  Controller,
+    IN  ULONG               Size
+    );
+
+extern NTSTATUS
+ControllerSetHashMapping(
+    IN  PXENVIF_CONTROLLER  Controller,
+    IN  PULONG              Mapping,
+    IN  ULONG               Size,
+    IN  ULONG               Offset
+    );
+
+
+#endif  // _XENVIF_CONTROLLER_H
diff --git a/src/xenvif/frontend.c b/src/xenvif/frontend.c
index 5a29736..e950552 100644
--- a/src/xenvif/frontend.c
+++ b/src/xenvif/frontend.c
@@ -76,6 +76,7 @@ struct _XENVIF_FRONTEND {
     PXENVIF_MAC                 Mac;
     PXENVIF_RECEIVER            Receiver;
     PXENVIF_TRANSMITTER         Transmitter;
+    PXENVIF_CONTROLLER          Controller;
 
     XENBUS_DEBUG_INTERFACE      DebugInterface;
     XENBUS_SUSPEND_INTERFACE    SuspendInterface;
@@ -323,8 +324,9 @@ FrontendGet ## _Function(                               \
 }
 
 DEFINE_FRONTEND_GET_FUNCTION(Mac, PXENVIF_MAC)
-DEFINE_FRONTEND_GET_FUNCTION(Transmitter, PXENVIF_TRANSMITTER)
 DEFINE_FRONTEND_GET_FUNCTION(Receiver, PXENVIF_RECEIVER)
+DEFINE_FRONTEND_GET_FUNCTION(Transmitter, PXENVIF_TRANSMITTER)
+DEFINE_FRONTEND_GET_FUNCTION(Controller, PXENVIF_CONTROLLER)
 
 static BOOLEAN
 FrontendIsOnline(
@@ -1834,6 +1836,10 @@ FrontendConnect(
     if (!NT_SUCCESS(status))
         goto fail6;
 
+    status = ControllerConnect(__FrontendGetController(Frontend));
+    if (!NT_SUCCESS(status))
+        goto fail7;
+
     Attempt = 0;
     do {
         PXENBUS_STORE_TRANSACTION   Transaction;
@@ -1854,6 +1860,11 @@ FrontendConnect(
         if (!NT_SUCCESS(status))
             goto abort;
 
+        status = ControllerStoreWrite(__FrontendGetController(Frontend),
+                                      Transaction);
+        if (!NT_SUCCESS(status))
+            goto abort;
+
         status = XENBUS_STORE(Printf,
                               &Frontend->StoreInterface,
                               Transaction,
@@ -1882,7 +1893,7 @@ abort:
     } while (status == STATUS_RETRY);
 
     if (!NT_SUCCESS(status))
-        goto fail7;
+        goto fail8;
 
     State = XenbusStateUnknown;
     while (State != XenbusStateConnected) {
@@ -1920,16 +1931,23 @@ abort:
 
     status = STATUS_UNSUCCESSFUL;
     if (State != XenbusStateConnected)
-        goto fail8;
+        goto fail9;
+
+    ControllerEnable(__FrontendGetController(Frontend));
 
     ThreadWake(Frontend->MibThread);
 
     Trace("<====\n");
     return STATUS_SUCCESS;
 
+fail9:
+    Error("fail9\n");
+
 fail8:
     Error("fail8\n");
 
+    ControllerDisconnect(__FrontendGetController(Frontend));
+
 fail7:
     Error("fail7\n");
 
@@ -1982,6 +2000,9 @@ FrontendDisconnect(
 {
     Trace("====>\n");
 
+    ControllerDisable(__FrontendGetController(Frontend));
+
+    ControllerDisconnect(__FrontendGetController(Frontend));
     TransmitterDisconnect(__FrontendGetTransmitter(Frontend));
     ReceiverDisconnect(__FrontendGetReceiver(Frontend));
     MacDisconnect(__FrontendGetMac(Frontend));
@@ -2453,32 +2474,40 @@ FrontendInitialize(
     if (!NT_SUCCESS(status))
         goto fail8;
 
+    status = ControllerInitialize(*Frontend, &(*Frontend)->Controller);
+    if (!NT_SUCCESS(status))
+        goto fail9;
+
     KeInitializeEvent(&(*Frontend)->EjectEvent, NotificationEvent, FALSE);
 
     status = ThreadCreate(FrontendEject, *Frontend, &(*Frontend)->EjectThread);
     if (!NT_SUCCESS(status))
-        goto fail9;
+        goto fail10;
 
     status = ThreadCreate(FrontendMib, *Frontend, &(*Frontend)->MibThread);
     if (!NT_SUCCESS(status))
-        goto fail10;
+        goto fail11;
 
     Trace("<====\n");
 
     return STATUS_SUCCESS;
 
-fail10:
-    Error("fail10\n");
+fail11:
+    Error("fail11\n");
 
     ThreadAlert((*Frontend)->EjectThread);
     ThreadJoin((*Frontend)->EjectThread);
     (*Frontend)->EjectThread = NULL;
 
-fail9:
-    Error("fail9\n");
+fail10:
+    Error("fail10\n");
 
     RtlZeroMemory(&(*Frontend)->EjectEvent, sizeof (KEVENT));
 
+    ControllerTeardown(__FrontendGetController(*Frontend));
+    (*Frontend)->Controller = NULL;
+
+fail9:
     TransmitterTeardown(__FrontendGetTransmitter(*Frontend));
     (*Frontend)->Transmitter = NULL;
 
@@ -2575,6 +2604,9 @@ FrontendTeardown(
 
     RtlZeroMemory(&Frontend->EjectEvent, sizeof (KEVENT));
 
+    ControllerTeardown(__FrontendGetController(Frontend));
+    Frontend->Controller = NULL;
+
     TransmitterTeardown(__FrontendGetTransmitter(Frontend));
     Frontend->Transmitter = NULL;
 
diff --git a/src/xenvif/frontend.h b/src/xenvif/frontend.h
index 9cac412..65daac4 100644
--- a/src/xenvif/frontend.h
+++ b/src/xenvif/frontend.h
@@ -165,6 +165,13 @@ FrontendGetTransmitter(
     IN  PXENVIF_FRONTEND    Frontend
     );
 
+#include "controller.h"
+
+extern PXENVIF_CONTROLLER
+FrontendGetController(
+    IN  PXENVIF_FRONTEND    Frontend
+    );
+
 extern VOID
 FrontendQueryStatistic(
     IN  PXENVIF_FRONTEND        Frontend,
diff --git a/vs2012/xenvif/xenvif.vcxproj b/vs2012/xenvif/xenvif.vcxproj
index e3df309..170ab53 100644
--- a/vs2012/xenvif/xenvif.vcxproj
+++ b/vs2012/xenvif/xenvif.vcxproj
@@ -80,6 +80,7 @@
     <ClCompile Include="../../src/xenvif/settings.c" />
     <ClCompile Include="../../src/xenvif/thread.c" />
     <ClCompile Include="../../src/xenvif/transmitter.c" />
+    <ClCompile Include="../../src/xenvif/controller.c" />
     <ClCompile Include="../../src/xenvif/vif.c" />
   </ItemGroup>
   <ItemGroup>
diff --git a/vs2013/xenvif/xenvif.vcxproj b/vs2013/xenvif/xenvif.vcxproj
index 61265a2..9d1dba3 100644
--- a/vs2013/xenvif/xenvif.vcxproj
+++ b/vs2013/xenvif/xenvif.vcxproj
@@ -83,6 +83,7 @@
     <ClCompile Include="../../src/xenvif/settings.c" />
     <ClCompile Include="../../src/xenvif/thread.c" />
     <ClCompile Include="../../src/xenvif/transmitter.c" />
+    <ClCompile Include="../../src/xenvif/controller.c" />
     <ClCompile Include="../../src/xenvif/vif.c" />
   </ItemGroup>
   <ItemGroup>
-- 
2.1.1


_______________________________________________
win-pv-devel mailing list
win-pv-devel@xxxxxxxxxxxxxxxxxxxx
http://lists.xenproject.org/cgi-bin/mailman/listinfo/win-pv-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.