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

[win-pv-devel] [PATCH 3/4] Add new functionality to VIF interface to support RSS



This patch adds the necessary extra functionality into the VIF interface
to make use of the new control ring to support NDIS RSS in XENNET.

The VIF interface version is bumped to 6 and the PDO revision adjusted
accordingly.

Signed-off-by: Paul Durrant <paul.durrant@xxxxxxxxxx>
---
 include/revision.h       |   7 +-
 include/vif_interface.h  | 146 +++++++++++++++++++-
 src/xenvif/frontend.c    | 316 +++++++++++++++++++++++++++++++++++++++++++-
 src/xenvif/frontend.h    |  44 ++++++-
 src/xenvif/receiver.c    | 336 +++++++++++++++++++++++++++++++++++++++++------
 src/xenvif/receiver.h    |  32 +++++
 src/xenvif/transmitter.c |  38 +++++-
 src/xenvif/vif.c         | 207 +++++++++++++++++++++++++++++
 src/xenvif/vif.h         |   1 +
 9 files changed, 1073 insertions(+), 54 deletions(-)

diff --git a/include/revision.h b/include/revision.h
index 6458bfd..14b7b15 100644
--- a/include/revision.h
+++ b/include/revision.h
@@ -44,9 +44,10 @@
     DEFINE_REVISION(0x08000003,  1,  3,  0,  0),    \
     DEFINE_REVISION(0x08000004,  1,  3,  2,  1),    \
     DEFINE_REVISION(0x08000006,  1,  4,  2,  1),    \
-    DEFINE_REVISION(0x08000009,  1,  5,  2,  1)
+    DEFINE_REVISION(0x08000009,  1,  5,  2,  1),    \
+    DEFINE_REVISION(0x0800000B,  1,  6,  2,  1)
 
-// Revision 0x08000005, 0x08000007 and 0x08000008 are already in use in
-// the staging-8.1 branch.
+// Revision 0x08000005, 0x08000007, 0x08000008 and 0x0800000A are already
+// in use in the staging-8.1 branch.
 
 #endif  // _REVISION_H
diff --git a/include/vif_interface.h b/include/vif_interface.h
index 5a064fd..853554d 100644
--- a/include/vif_interface.h
+++ b/include/vif_interface.h
@@ -50,20 +50,44 @@ typedef enum _XENVIF_PACKET_HASH_ALGORITHM {
     /*! None (value should be ignored) */
     XENVIF_PACKET_HASH_ALGORITHM_NONE = 0,
     /*! Unspecified hash (value can be used) */
-    XENVIF_PACKET_HASH_ALGORITHM_UNSPECIFIED
+    XENVIF_PACKET_HASH_ALGORITHM_UNSPECIFIED,
+    /*! Toeplitz hash */
+    XENVIF_PACKET_HASH_ALGORITHM_TOEPLITZ
 } XENVIF_PACKET_HASH_ALGORITHM, *PXENVIF_PACKET_HASH_ALGORITHM;
 
-/*! \struct _XENVIF_PACKET_HASH_V1
+typedef enum _XENVIF_PACKET_HASH_TYPE {
+    /*! None (value should be ignored) */
+    XENVIF_PACKET_HASH_TYPE_NONE = 0,
+    /*! IPv4 header only */
+    XENVIF_PACKET_HASH_TYPE_IPV4,
+    /*! IPv4 and TCP headers */
+    XENVIF_PACKET_HASH_TYPE_IPV4_TCP,
+    /*! IPv6 header only */
+    XENVIF_PACKET_HASH_TYPE_IPV6,
+    /*! IPv6 and TCP headers */
+    XENVIF_PACKET_HASH_TYPE_IPV6_TCP
+} XENVIF_PACKET_HASH_TYPE, *PXENVIF_PACKET_HASH_TYPE;
+
+struct _XENVIF_PACKET_HASH_V1 {
+    /*! Hash algorithm used to calculate value */
+    XENVIF_PACKET_HASH_ALGORITHM    Algorithm;
+    /*! Calculated value */
+    ULONG                           Value;
+};
+
+/*! \struct _XENVIF_PACKET_HASH_V2
     \brief Hash information
 */
-struct _XENVIF_PACKET_HASH_V1 {
+struct _XENVIF_PACKET_HASH_V2 {
     /*! Hash algorithm used to calculate value */
     XENVIF_PACKET_HASH_ALGORITHM    Algorithm;
+    /*! Scope of hash */
+    XENVIF_PACKET_HASH_TYPE         Type;
     /*! Calculated value */
     ULONG                           Value;
 };
 
-typedef struct _XENVIF_PACKET_HASH_V1 XENVIF_PACKET_HASH, *PXENVIF_PACKET_HASH;
+typedef struct _XENVIF_PACKET_HASH_V2 XENVIF_PACKET_HASH, *PXENVIF_PACKET_HASH;
 
 /*! \struct _XENVIF_PACKET_HEADER_V1
     \brief Packet header information
@@ -366,6 +390,7 @@ typedef VOID
     \param MaximumSegmentSize The TCP MSS (used only if 
OffloadOptions.OffloadIpVersion[4|6]LargePacket is set)
     \param TagControlInformation The VLAN TCI (used only if 
OffloadOptions.OffloadTagManipulation is set)
     \param Info Header information for the packet
+    \param Hash Hash information for the packet
     \param Cookie Cookie that should be passed to 
XENVIF_RECEIVER_RETURN_PACKET method
 
     \b XENVIF_MAC_STATE_CHANGE:
@@ -427,6 +452,35 @@ typedef NTSTATUS
     OUT PULONGLONG              Value
     );
 
+/*! \typedef XENVIF_VIF_QUERY_RING_COUNT
+    \brief Query the number of shared rings between frontend
+    and backend
+
+    \param Interface The interface header
+    \param Count Buffer to receive the count
+*/
+typedef VOID
+(*XENVIF_VIF_QUERY_RING_COUNT)(
+    IN  PINTERFACE  Interface,
+    OUT PULONG      Count
+    );
+
+/*! \typedef XENVIF_VIF_UPDATE_HASH_MAPPING
+    \brief Update the mapping of hash to transmitter/receiver ring
+
+    The default mapping is hash % number-of-rings
+
+    \param Interface The interface header
+    \param Mapping The mapping table
+    \param Size The size of the mapping table
+*/
+typedef NTSTATUS
+(*XENVIF_VIF_UPDATE_HASH_MAPPING)(
+    IN  PINTERFACE          Interface,
+    IN  PPROCESSOR_NUMBER   Mapping,
+    IN  ULONG               Size
+    );
+
 typedef VOID
 (*XENVIF_VIF_RECEIVER_RETURN_PACKETS_V1)(
     IN  PINTERFACE  Interface,
@@ -579,6 +633,52 @@ typedef VOID
     OUT PULONG      Size
     );
 
+/*! \typedef XENVIF_VIF_RECEIVER_SET_HASH_ALGORITHM
+    \brief Select a hash alorithm
+
+    \param Interface The interface header
+    \param Algorithm The algorithm to enable (or
+    XENVIF_PACKET_HASH_ALGORITHM_NONE to disable hashing)
+*/
+typedef NTSTATUS
+(*XENVIF_VIF_RECEIVER_SET_HASH_ALGORITHM)(
+    IN  PINTERFACE                      Interface,
+    IN  XENVIF_PACKET_HASH_ALGORITHM    Algorithm
+    );
+
+/*! \typedef XENVIF_VIF_RECEIVER_QUERY_HASH_CAPABILITIES
+    \brief Query any algorithm-specific capabilities.
+
+    \param Interface The interface header
+    \param ... Additional capabilities reported by the selected algorithm
+
+    \b XENVIF_PACKET_HASH_ALGORITHM_TOEPLITZ:
+    \param Types Mask of hash types supported
+*/
+typedef NTSTATUS
+(*XENVIF_VIF_RECEIVER_QUERY_HASH_CAPABILITIES)(
+    IN  PINTERFACE  Interface,
+    ...
+    );
+
+/*! \typedef XENVIF_VIF_RECEIVER_UPDATE_HASH_PARAMETERS
+    \brief Set parameters of currently selected algorithm.
+
+    \param Interface The interface header
+    \param ... Additional parameters required by the selected algorithm
+
+    \b XENVIF_PACKET_HASH_ALGORITHM_TOEPLITZ:
+    \param Types Mask of hash types enabled
+    \param Key Pointer to a 40-byte array containing the hash key
+*/
+typedef NTSTATUS
+(*XENVIF_VIF_RECEIVER_UPDATE_HASH_PARAMETERS)(
+    IN  PINTERFACE  Interface,
+    ...
+    );
+
+#define XENVIF_VIF_HASH_KEY_SIZE    40
+
 /*! \typedef XENVIF_VIF_MAC_QUERY_STATE
     \brief Query the current MAC (link) state
 
@@ -822,7 +922,41 @@ struct _XENVIF_VIF_INTERFACE_V5 {
     XENVIF_VIF_MAC_QUERY_FILTER_LEVEL               MacQueryFilterLevel;
 };
 
-typedef struct _XENVIF_VIF_INTERFACE_V5 XENVIF_VIF_INTERFACE, 
*PXENVIF_VIF_INTERFACE;
+/*! \struct _XENVIF_VIF_INTERFACE_V6
+    \brief VIF interface version 6
+    \ingroup interfaces
+*/
+struct _XENVIF_VIF_INTERFACE_V6 {
+    INTERFACE                                       Interface;
+    XENVIF_VIF_ACQUIRE                              Acquire;
+    XENVIF_VIF_RELEASE                              Release;
+    XENVIF_VIF_ENABLE                               Enable;
+    XENVIF_VIF_DISABLE                              Disable;
+    XENVIF_VIF_QUERY_STATISTIC                      QueryStatistic;
+    XENVIF_VIF_QUERY_RING_COUNT                     QueryRingCount;
+    XENVIF_VIF_UPDATE_HASH_MAPPING                  UpdateHashMapping;
+    XENVIF_VIF_RECEIVER_RETURN_PACKET               ReceiverReturnPacket;
+    XENVIF_VIF_RECEIVER_SET_OFFLOAD_OPTIONS         ReceiverSetOffloadOptions;
+    XENVIF_VIF_RECEIVER_SET_BACKFILL_SIZE           ReceiverSetBackfillSize;
+    XENVIF_VIF_RECEIVER_QUERY_RING_SIZE             ReceiverQueryRingSize;
+    XENVIF_VIF_RECEIVER_SET_HASH_ALGORITHM          ReceiverSetHashAlgorithm;
+    XENVIF_VIF_RECEIVER_QUERY_HASH_CAPABILITIES     
ReceiverQueryHashCapabilities;
+    XENVIF_VIF_RECEIVER_UPDATE_HASH_PARAMETERS      
ReceiverUpdateHashParameters;
+    XENVIF_VIF_TRANSMITTER_QUEUE_PACKET             TransmitterQueuePacket;
+    XENVIF_VIF_TRANSMITTER_QUERY_OFFLOAD_OPTIONS    
TransmitterQueryOffloadOptions;
+    XENVIF_VIF_TRANSMITTER_QUERY_LARGE_PACKET_SIZE  
TransmitterQueryLargePacketSize;
+    XENVIF_VIF_TRANSMITTER_QUERY_RING_SIZE          TransmitterQueryRingSize;
+    XENVIF_VIF_MAC_QUERY_STATE                      MacQueryState;
+    XENVIF_VIF_MAC_QUERY_MAXIMUM_FRAME_SIZE         MacQueryMaximumFrameSize;
+    XENVIF_VIF_MAC_QUERY_PERMANENT_ADDRESS          MacQueryPermanentAddress;
+    XENVIF_VIF_MAC_QUERY_CURRENT_ADDRESS            MacQueryCurrentAddress;
+    XENVIF_VIF_MAC_QUERY_MULTICAST_ADDRESSES        MacQueryMulticastAddresses;
+    XENVIF_VIF_MAC_SET_MULTICAST_ADDRESSES          MacSetMulticastAddresses;
+    XENVIF_VIF_MAC_SET_FILTER_LEVEL                 MacSetFilterLevel;
+    XENVIF_VIF_MAC_QUERY_FILTER_LEVEL               MacQueryFilterLevel;
+};
+
+typedef struct _XENVIF_VIF_INTERFACE_V6 XENVIF_VIF_INTERFACE, 
*PXENVIF_VIF_INTERFACE;
 
 /*! \def XENVIF_VIF
     \brief Macro at assist in method invocation
@@ -833,6 +967,6 @@ typedef struct _XENVIF_VIF_INTERFACE_V5 
XENVIF_VIF_INTERFACE, *PXENVIF_VIF_INTER
 #endif  // _WINDLL
 
 #define XENVIF_VIF_INTERFACE_VERSION_MIN    2
-#define XENVIF_VIF_INTERFACE_VERSION_MAX    5
+#define XENVIF_VIF_INTERFACE_VERSION_MAX    6
 
 #endif  // _XENVIF_INTERFACE_H
diff --git a/src/xenvif/frontend.c b/src/xenvif/frontend.c
index e950552..b682b2c 100644
--- a/src/xenvif/frontend.c
+++ b/src/xenvif/frontend.c
@@ -56,6 +56,15 @@ typedef struct _XENVIF_FRONTEND_STATISTICS {
     ULONGLONG   Value[XENVIF_VIF_STATISTIC_COUNT];
 } XENVIF_FRONTEND_STATISTICS, *PXENVIF_FRONTEND_STATISTICS;
 
+#define XENVIF_FRONTEND_MAXIMUM_HASH_MAPPING_SIZE   128
+
+typedef struct _XENVIF_FRONTEND_HASH {
+    XENVIF_PACKET_HASH_ALGORITHM    Algorithm;
+    ULONG                           Flags;
+    UCHAR                           Key[XENVIF_VIF_HASH_KEY_SIZE];
+    ULONG                           
Mapping[XENVIF_FRONTEND_MAXIMUM_HASH_MAPPING_SIZE];
+    ULONG                           Size;
+} XENVIF_FRONTEND_HASH, *PXENVIF_FRONTEND_HASH;
 
 struct _XENVIF_FRONTEND {
     PXENVIF_PDO                 Pdo;
@@ -95,6 +104,8 @@ struct _XENVIF_FRONTEND {
     NET_IFINDEX                 InterfaceIndex;
     PSOCKADDR_INET              AddressTable;
     ULONG                       AddressCount;
+
+    XENVIF_FRONTEND_HASH        Hash;
 };
 
 static const PCHAR
@@ -1790,6 +1801,295 @@ FrontendIsSplit(
     return __FrontendIsSplit(Frontend);
 }
 
+static FORCEINLINE NTSTATUS
+__FrontendUpdateHash(
+    IN  PXENVIF_FRONTEND                Frontend
+    )
+{
+    PXENVIF_FRONTEND_HASH               Hash = &Frontend->Hash;
+    PXENVIF_CONTROLLER                  Controller;
+    ULONG                               Zero = 0;
+    ULONG                               Size;
+    PULONG                              Mapping;
+    ULONG                               Flags;
+    NTSTATUS                            status;
+
+    Controller = __FrontendGetController(Frontend);
+
+    switch (Hash->Algorithm) {
+    case XENVIF_PACKET_HASH_ALGORITHM_NONE:
+        Size = 1;
+        Mapping = &Zero;
+        Flags = 0;
+        break;
+
+    case XENVIF_PACKET_HASH_ALGORITHM_TOEPLITZ:
+        Size = Hash->Size;
+        Mapping = Hash->Mapping;
+        Flags = Hash->Flags;
+        break;
+
+    case XENVIF_PACKET_HASH_ALGORITHM_UNSPECIFIED:
+    default:
+        (VOID) ControllerSetHashAlgorithm(Controller,
+                                          XEN_NETIF_CTRL_HASH_ALGORITHM_NONE);
+        goto done;
+    }
+
+    status = ControllerSetHashAlgorithm(Controller,
+                                        
XEN_NETIF_CTRL_HASH_ALGORITHM_TOEPLITZ);
+    if (!NT_SUCCESS(status))
+        goto fail1;
+
+    status = ControllerSetHashMappingSize(Controller, Size);
+    if (!NT_SUCCESS(status))
+        goto fail2;
+
+    status = ControllerSetHashMapping(Controller, Mapping, Size, 0);
+    if (!NT_SUCCESS(status))
+        goto fail3;
+
+    status = ControllerSetHashKey(Controller, Hash->Key, 
XENVIF_VIF_HASH_KEY_SIZE);
+    if (!NT_SUCCESS(status))
+        goto fail4;
+
+    status = ControllerSetHashFlags(Controller, Flags);
+    if (!NT_SUCCESS(status))
+        goto fail5;
+
+done:
+    return STATUS_SUCCESS;
+
+fail5:
+    Error("fail5\n");
+
+fail4:
+    Error("fail4\n");
+
+fail3:
+    Error("fail3\n");
+
+fail2:
+    Error("fail2\n");
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
+}
+
+NTSTATUS
+FrontendUpdateHash(
+    IN  PXENVIF_FRONTEND                Frontend
+    )
+{
+    KIRQL                               Irql;
+    NTSTATUS                            status;
+
+    KeAcquireSpinLock(&Frontend->Lock, &Irql);
+    status = __FrontendUpdateHash(Frontend);
+    KeReleaseSpinLock(&Frontend->Lock, Irql);
+
+    return status;
+}
+
+NTSTATUS
+FrontendSetHashAlgorithm(
+    IN  PXENVIF_FRONTEND                Frontend,
+    IN  XENVIF_PACKET_HASH_ALGORITHM    Algorithm
+    )
+{
+    PXENVIF_FRONTEND_HASH               Hash = &Frontend->Hash;
+    KIRQL                               Irql;
+    NTSTATUS                            status;
+
+    KeAcquireSpinLock(&Frontend->Lock, &Irql);
+
+    if (Algorithm == Hash->Algorithm)
+        goto done;
+
+    switch (Algorithm) {
+    case XENVIF_PACKET_HASH_ALGORITHM_NONE:
+    case XENVIF_PACKET_HASH_ALGORITHM_UNSPECIFIED:
+    case XENVIF_PACKET_HASH_ALGORITHM_TOEPLITZ:
+        status = STATUS_SUCCESS;
+        break;
+
+    default:
+        status = STATUS_NOT_SUPPORTED;
+        break;
+    }
+
+    if (!NT_SUCCESS(status))
+        goto fail1;
+
+    Info("%s: %s\n", __FrontendGetPath(Frontend),
+         (Algorithm == XENVIF_PACKET_HASH_ALGORITHM_NONE) ? "NONE" :
+         (Algorithm == XENVIF_PACKET_HASH_ALGORITHM_UNSPECIFIED) ? 
"UNSPECIFIED" :
+         (Algorithm == XENVIF_PACKET_HASH_ALGORITHM_TOEPLITZ) ? "TOEPLITZ" :
+         "");
+
+    Hash->Algorithm = Algorithm;
+
+done:
+    KeReleaseSpinLock(&Frontend->Lock, Irql);
+
+    return STATUS_SUCCESS;
+
+fail1:
+    Error("fail1 (%08x)\n");
+
+    KeReleaseSpinLock(&Frontend->Lock, Irql);
+
+    return status;
+}
+
+NTSTATUS
+FrontendQueryHashTypes(
+    IN  PXENVIF_FRONTEND    Frontend,
+    OUT PULONG              Types
+    )
+{
+    KIRQL                   Irql;
+    ULONG                   Flags;
+    NTSTATUS                status;
+
+    KeAcquireSpinLock(&Frontend->Lock, &Irql);
+
+    status = ControllerGetHashFlags(__FrontendGetController(Frontend),
+                                    &Flags);
+    if (!NT_SUCCESS(status))
+        goto fail1;
+
+    *Types = 0;
+    if (Flags & XEN_NETIF_CTRL_HASH_TYPE_IPV4)
+        *Types |= 1 << XENVIF_PACKET_HASH_TYPE_IPV4;
+    if (Flags & XEN_NETIF_CTRL_HASH_TYPE_IPV4_TCP)
+        *Types |= 1 << XENVIF_PACKET_HASH_TYPE_IPV4_TCP;
+    if (Flags & XEN_NETIF_CTRL_HASH_TYPE_IPV6)
+        *Types |= 1 << XENVIF_PACKET_HASH_TYPE_IPV6;
+    if (Flags & XEN_NETIF_CTRL_HASH_TYPE_IPV6_TCP)
+        *Types |= 1 << XENVIF_PACKET_HASH_TYPE_IPV6_TCP;
+
+    KeReleaseSpinLock(&Frontend->Lock, Irql);
+
+    return STATUS_SUCCESS;
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    KeReleaseSpinLock(&Frontend->Lock, Irql);
+
+    return status;
+}
+
+NTSTATUS
+FrontendSetHashMapping(
+    IN  PXENVIF_FRONTEND    Frontend,
+    IN  PULONG              Mapping,
+    IN  ULONG               Size
+    )
+{
+    PXENVIF_FRONTEND_HASH   Hash = &Frontend->Hash;
+    KIRQL                   Irql;
+    NTSTATUS                status;
+
+    KeAcquireSpinLock(&Frontend->Lock, &Irql);
+
+    status = STATUS_INVALID_PARAMETER;
+    if (Size > XENVIF_FRONTEND_MAXIMUM_HASH_MAPPING_SIZE)
+        goto fail1;
+
+    RtlCopyMemory(Hash->Mapping, Mapping, sizeof (ULONG) * Size);
+    Hash->Size = Size;
+
+    KeReleaseSpinLock(&Frontend->Lock, Irql);
+
+    return STATUS_SUCCESS;
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    KeReleaseSpinLock(&Frontend->Lock, Irql);
+
+    return status;
+}
+
+NTSTATUS
+FrontendSetHashKey(
+    IN  PXENVIF_FRONTEND    Frontend,
+    IN  PUCHAR              Key
+    )
+{
+    PXENVIF_FRONTEND_HASH   Hash = &Frontend->Hash;
+    KIRQL                   Irql;
+
+    KeAcquireSpinLock(&Frontend->Lock, &Irql);
+
+    RtlCopyMemory(Hash->Key, Key, XENVIF_VIF_HASH_KEY_SIZE);
+
+    KeReleaseSpinLock(&Frontend->Lock, Irql);
+
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+FrontendSetHashTypes(
+    IN  PXENVIF_FRONTEND    Frontend,
+    IN  ULONG               Types
+    )
+{
+    PXENVIF_FRONTEND_HASH   Hash = &Frontend->Hash;
+    KIRQL                   Irql;
+    ULONG                   Flags;
+
+    KeAcquireSpinLock(&Frontend->Lock, &Irql);
+
+    Flags = 0;
+    if (Types & (1 << XENVIF_PACKET_HASH_TYPE_IPV4))
+        Flags |= XEN_NETIF_CTRL_HASH_TYPE_IPV4;
+    if (Types & (1 << XENVIF_PACKET_HASH_TYPE_IPV4_TCP))
+        Flags |= XEN_NETIF_CTRL_HASH_TYPE_IPV4_TCP;
+    if (Types & (1 << XENVIF_PACKET_HASH_TYPE_IPV6))
+        Flags |= XEN_NETIF_CTRL_HASH_TYPE_IPV6;
+    if (Types & (1 << XENVIF_PACKET_HASH_TYPE_IPV6_TCP))
+        Flags |= XEN_NETIF_CTRL_HASH_TYPE_IPV6_TCP;
+
+    Hash->Flags = Flags;
+
+    KeReleaseSpinLock(&Frontend->Lock, Irql);
+
+    return STATUS_SUCCESS;
+}
+
+ULONG
+FrontendGetQueue(
+    IN  PXENVIF_FRONTEND    Frontend,
+    IN  ULONG               Value
+    )
+{
+    PXENVIF_FRONTEND_HASH   Hash = &Frontend->Hash;
+    ULONG                   Queue;
+
+    switch (Hash->Algorithm) {
+    case XENVIF_PACKET_HASH_ALGORITHM_NONE:
+    case XENVIF_PACKET_HASH_ALGORITHM_UNSPECIFIED:
+        Queue = Value % __FrontendGetNumQueues(Frontend);
+        break;
+
+    case XENVIF_PACKET_HASH_ALGORITHM_TOEPLITZ:
+        Queue = Hash->Mapping[Value % Hash->Size];
+        break;
+
+    default:
+        ASSERT(FALSE);
+        Queue = 0;
+        break;
+    }
+
+    return Queue;
+}
+
 static NTSTATUS
 FrontendConnect(
     IN  PXENVIF_FRONTEND    Frontend
@@ -2045,11 +2345,20 @@ FrontendEnable(
     if (!NT_SUCCESS(status))
         goto fail3;
 
-    FrontendNotifyMulticastAddresses(Frontend, TRUE);
+    status = __FrontendUpdateHash(Frontend);
+    if (!NT_SUCCESS(status))
+        goto fail4;
+
+    (VOID) FrontendNotifyMulticastAddresses(Frontend, TRUE);
 
     Trace("<====\n");
     return STATUS_SUCCESS;
 
+fail4:
+    Error("fail4\n");
+
+    TransmitterDisable(__FrontendGetTransmitter(Frontend));
+
 fail3:
     Error("fail3\n");
 
@@ -2073,7 +2382,7 @@ FrontendDisable(
 {
     Trace("====>\n");
 
-    FrontendNotifyMulticastAddresses(Frontend, FALSE);
+    (VOID) FrontendNotifyMulticastAddresses(Frontend, FALSE);
 
     TransmitterDisable(__FrontendGetTransmitter(Frontend));
     ReceiverDisable(__FrontendGetReceiver(Frontend));
@@ -2461,6 +2770,7 @@ FrontendInitialize(
     FdoGetStoreInterface(PdoGetFdo(Pdo), &(*Frontend)->StoreInterface);
 
     FrontendSetMaxQueues(*Frontend);
+    (*Frontend)->Hash.Algorithm = XENVIF_PACKET_HASH_ALGORITHM_UNSPECIFIED;
 
     status = MacInitialize(*Frontend, &(*Frontend)->Mac);
     if (!NT_SUCCESS(status))
@@ -2526,6 +2836,7 @@ fail7:
 fail6:
     Error("fail6\n");
 
+    RtlZeroMemory(&(*Frontend)->Hash, sizeof (XENVIF_FRONTEND_HASH));
     (*Frontend)->MaxQueues = 0;
 
     RtlZeroMemory(&(*Frontend)->StoreInterface,
@@ -2616,6 +2927,7 @@ FrontendTeardown(
     MacTeardown(__FrontendGetMac(Frontend));
     Frontend->Mac = NULL;
 
+    RtlZeroMemory(&Frontend->Hash, sizeof (XENVIF_FRONTEND_HASH));
     Frontend->MaxQueues = 0;
 
     RtlZeroMemory(&Frontend->StoreInterface,
diff --git a/src/xenvif/frontend.h b/src/xenvif/frontend.h
index 65daac4..513e812 100644
--- a/src/xenvif/frontend.h
+++ b/src/xenvif/frontend.h
@@ -202,7 +202,49 @@ FrontendSetFilterLevel(
 
 extern VOID
 FrontendAdvertiseIpAddresses(
-    IN  PXENVIF_FRONTEND        Frontend
+    IN  PXENVIF_FRONTEND    Frontend
+    );
+
+extern NTSTATUS
+FrontendUpdateHash(
+    IN  PXENVIF_FRONTEND    Frontend
+    );
+
+extern NTSTATUS
+FrontendSetHashAlgorithm(
+    IN  PXENVIF_FRONTEND                Frontend,
+    IN  XENVIF_PACKET_HASH_ALGORITHM    Algorithm
+    );
+
+extern NTSTATUS
+FrontendQueryHashTypes(
+    IN  PXENVIF_FRONTEND    Frontend,
+    OUT PULONG              Types
+    );
+
+extern NTSTATUS
+FrontendSetHashMapping(
+    IN  PXENVIF_FRONTEND    Frontend,
+    IN  PULONG              Mapping,
+    IN  ULONG               Order
+    );
+
+extern NTSTATUS
+FrontendSetHashKey(
+    IN  PXENVIF_FRONTEND    Frontend,
+    IN  PUCHAR              Key
+    );
+
+extern NTSTATUS
+FrontendSetHashTypes(
+    IN  PXENVIF_FRONTEND    Frontend,
+    IN  ULONG               Types
+    );
+
+extern ULONG
+FrontendGetQueue(
+    IN  PXENVIF_FRONTEND    Frontend,
+    IN  ULONG               Index
     );
 
 #endif  // _XENVIF_FRONTEND_H
diff --git a/src/xenvif/receiver.c b/src/xenvif/receiver.c
index 9b4c3b3..3d37ad2 100644
--- a/src/xenvif/receiver.c
+++ b/src/xenvif/receiver.c
@@ -67,6 +67,11 @@ typedef struct _XENVIF_RECEIVER_FRAGMENT {
     PXENBUS_GNTTAB_ENTRY    Entry;
 } XENVIF_RECEIVER_FRAGMENT, *PXENVIF_RECEIVER_FRAGMENT;
 
+typedef struct _XENVIF_RECEIVER_HASH {
+    XENVIF_PACKET_HASH_ALGORITHM    Algorithm;
+    ULONG                           Types;
+} XENVIF_RECEIVER_HASH, *PXENVIF_RECEIVER_HASH;
+
 #define XENVIF_RECEIVER_RING_SIZE   (__CONST_RING_SIZE(netif_rx, PAGE_SIZE))
 
 #define XENVIF_RECEIVER_MAXIMUM_FRAGMENT_ID (XENVIF_RECEIVER_RING_SIZE - 1)
@@ -101,11 +106,13 @@ typedef struct _XENVIF_RECEIVER_RING {
     PXENBUS_DEBUG_CALLBACK      DebugCallback;
     PXENVIF_THREAD              WatchdogThread;
     LIST_ENTRY                  PacketList;
+    XENVIF_RECEIVER_HASH        Hash;
 } XENVIF_RECEIVER_RING, *PXENVIF_RECEIVER_RING;
 
 typedef struct _XENVIF_RECEIVER_PACKET {
     LIST_ENTRY                      ListEntry;
     XENVIF_PACKET_INFO              Info;
+    XENVIF_PACKET_HASH              Hash;
     ULONG                           Offset;
     ULONG                           Length;
     XENVIF_PACKET_CHECKSUM_FLAGS    Flags;
@@ -117,23 +124,23 @@ typedef struct _XENVIF_RECEIVER_PACKET {
 } XENVIF_RECEIVER_PACKET, *PXENVIF_RECEIVER_PACKET;
 
 struct _XENVIF_RECEIVER {
-    PXENVIF_FRONTEND        Frontend;
-    XENBUS_CACHE_INTERFACE  CacheInterface;
-    XENBUS_GNTTAB_INTERFACE GnttabInterface;
-    XENBUS_EVTCHN_INTERFACE EvtchnInterface;
-    PXENVIF_RECEIVER_RING   *Ring;
-    LONG                    Loaned;
-    LONG                    Returned;
-    KEVENT                  Event;
-    ULONG                   CalculateChecksums;
-    ULONG                   AllowGsoPackets;
-    ULONG                   DisableIpVersion4Gso;
-    ULONG                   DisableIpVersion6Gso;
-    ULONG                   IpAlignOffset;
-    ULONG                   AlwaysPullup;
-    XENBUS_STORE_INTERFACE  StoreInterface;
-    XENBUS_DEBUG_INTERFACE  DebugInterface;
-    PXENBUS_DEBUG_CALLBACK  DebugCallback;
+    PXENVIF_FRONTEND                Frontend;
+    XENBUS_CACHE_INTERFACE          CacheInterface;
+    XENBUS_GNTTAB_INTERFACE         GnttabInterface;
+    XENBUS_EVTCHN_INTERFACE         EvtchnInterface;
+    PXENVIF_RECEIVER_RING           *Ring;
+    LONG                            Loaned;
+    LONG                            Returned;
+    KEVENT                          Event;
+    ULONG                           CalculateChecksums;
+    ULONG                           AllowGsoPackets;
+    ULONG                           DisableIpVersion4Gso;
+    ULONG                           DisableIpVersion6Gso;
+    ULONG                           IpAlignOffset;
+    ULONG                           AlwaysPullup;
+    XENBUS_STORE_INTERFACE          StoreInterface;
+    XENBUS_DEBUG_INTERFACE          DebugInterface;
+    PXENBUS_DEBUG_CALLBACK          DebugCallback;
 };
 
 #define XENVIF_RECEIVER_TAG 'ECER'
@@ -269,6 +276,7 @@ __ReceiverRingPutPacket(
     Packet->TagControlInformation = 0;
 
     RtlZeroMemory(&Packet->Info, sizeof (XENVIF_PACKET_INFO));
+    RtlZeroMemory(&Packet->Hash, sizeof (XENVIF_PACKET_HASH));
 
     Mdl->MappedSystemVa = Mdl->StartVa;
     Mdl->ByteOffset = 0;
@@ -746,11 +754,12 @@ __ReceiverRingBuildSegment(
     if (Segment == NULL)
         goto fail1;
 
-    Segment->Info = Packet->Info;
-    Segment->Offset = Packet->Offset;
-    Segment->Flags = Packet->Flags;
-    Segment->MaximumSegmentSize = Packet->MaximumSegmentSize;
-    Segment->TagControlInformation = Packet->TagControlInformation;
+    RtlCopyMemory(Segment,
+                  Packet,
+                  FIELD_OFFSET(XENVIF_RECEIVER_PACKET, Mdl));
+
+    // The segment contains no data as yet
+    Segment->Length = 0;
 
     Mdl = &Segment->Mdl;
 
@@ -1178,9 +1187,8 @@ ReceiverRingProcessPacket(
     PXENVIF_FRONTEND                Frontend;
     PXENVIF_MAC                     Mac;
     ULONG                           Length;
-    XENVIF_PACKET_CHECKSUM_FLAGS    Flags;
-    USHORT                          MaximumSegmentSize;
     XENVIF_PACKET_PAYLOAD           Payload;
+    PXENVIF_RECEIVER_PACKET         New;
     PXENVIF_PACKET_INFO             Info;
     PUCHAR                          StartVa;
     PETHERNET_HEADER                EthernetHeader;
@@ -1194,16 +1202,25 @@ ReceiverRingProcessPacket(
 
     ASSERT3U(Packet->Offset, ==, 0);
     Length = Packet->Length;
-    Flags = Packet->Flags;
-    MaximumSegmentSize = Packet->MaximumSegmentSize;
     ASSERT3U(Packet->TagControlInformation, ==, 0);
 
     Payload.Mdl = &Packet->Mdl;
     Payload.Offset = 0;
     Payload.Length = Length;
 
-    // Get a new packet structure that will just contain the header after 
parsing
-    Packet = __ReceiverRingGetPacket(Ring, TRUE);
+    // Get a new packet structure that will just contain the header after
+    // parsing. We need to preserve metadata from the original.
+
+    New = __ReceiverRingGetPacket(Ring, TRUE);
+
+    RtlCopyMemory(New,
+                  Packet,
+                  FIELD_OFFSET(XENVIF_RECEIVER_PACKET, Mdl));
+
+    Packet = New;
+
+    // Override offset to align
+    Packet->Offset = Receiver->IpAlignOffset;
 
     status = STATUS_NO_MEMORY;
     if (Packet == NULL) {
@@ -1213,12 +1230,6 @@ ReceiverRingProcessPacket(
         goto fail1;
     }
 
-    // Copy in the extracted metadata
-    Packet->Offset = Receiver->IpAlignOffset;
-    Packet->Length = Length;
-    Packet->Flags = Flags;
-    Packet->MaximumSegmentSize = MaximumSegmentSize;
-
     StartVa = MmGetSystemAddressForMdlSafe(&Packet->Mdl, NormalPagePriority);
     ASSERT(StartVa != NULL);
     StartVa += Packet->Offset;
@@ -1432,6 +1443,7 @@ __ReceiverRingReleaseLock(
                                Packet->MaximumSegmentSize,
                                Packet->TagControlInformation,
                                &Packet->Info,
+                               &Packet->Hash,
                                Packet);
     }
 
@@ -1472,17 +1484,24 @@ __ReceiverRingIsStopped(
 
 static FORCEINLINE VOID
 __ReceiverRingTrigger(
-    IN  PXENVIF_RECEIVER_RING   Ring
+    IN  PXENVIF_RECEIVER_RING   Ring,
+    IN  BOOLEAN                 Locked
     )
 {
     PXENVIF_RECEIVER            Receiver;
 
     Receiver = Ring->Receiver;
 
+    if (!Locked)
+        __ReceiverRingAcquireLock(Ring);
+
     if (Ring->Connected)
         (VOID) XENBUS_EVTCHN(Trigger,
                              &Receiver->EvtchnInterface,
                              Ring->Channel);
+
+    if (!Locked)
+        __ReceiverRingReleaseLock(Ring);
 }
 
 static FORCEINLINE VOID
@@ -1539,7 +1558,7 @@ __ReceiverRingReturnPacket(
 
         if (__ReceiverRingIsStopped(Ring)) {
             __ReceiverRingStart(Ring);
-            __ReceiverRingTrigger(Ring);
+            __ReceiverRingTrigger(Ring, TRUE);
         }
 
         if (!Locked)
@@ -1809,6 +1828,7 @@ ReceiverRingPoll(
         BOOLEAN                 Extra;
         ULONG                   Info;
         USHORT                  MaximumSegmentSize;
+        XENVIF_PACKET_HASH      Hash;
         PXENVIF_RECEIVER_PACKET Packet;
         uint16_t                flags;
         PMDL                    TailMdl;
@@ -1820,6 +1840,7 @@ ReceiverRingPoll(
         Extra = FALSE;
         Info = 0;
         MaximumSegmentSize = 0;
+        RtlZeroMemory(&Hash, sizeof (Hash));
         Packet = NULL;
         flags = 0;
         TailMdl = NULL;
@@ -1884,6 +1905,35 @@ ReceiverRingPoll(
                     MaximumSegmentSize = extra->u.gso.size;
                     break;
 
+                case XEN_NETIF_EXTRA_TYPE_HASH:
+                    Hash.Algorithm = XENVIF_PACKET_HASH_ALGORITHM_TOEPLITZ;
+
+                    switch (extra->u.hash.type) {
+                    case _XEN_NETIF_CTRL_HASH_TYPE_IPV4:
+                        Hash.Type = XENVIF_PACKET_HASH_TYPE_IPV4;
+                        break;
+
+                    case _XEN_NETIF_CTRL_HASH_TYPE_IPV4_TCP:
+                        Hash.Type = XENVIF_PACKET_HASH_TYPE_IPV4_TCP;
+                        break;
+
+                    case _XEN_NETIF_CTRL_HASH_TYPE_IPV6:
+                        Hash.Type = XENVIF_PACKET_HASH_TYPE_IPV6;
+                        break;
+
+                    case _XEN_NETIF_CTRL_HASH_TYPE_IPV6_TCP:
+                        Hash.Type = XENVIF_PACKET_HASH_TYPE_IPV6_TCP;
+                        break;
+
+                    default:
+                        ASSERT(FALSE);
+                        Hash.Type = XENVIF_PACKET_HASH_TYPE_NONE;
+                        break;
+                    }
+
+                    Hash.Value = *(uint32_t *)extra->u.hash.value;
+                    break;
+
                 default:
                     ASSERT(FALSE);
                     break;
@@ -1940,6 +1990,14 @@ ReceiverRingPoll(
                         Packet->MaximumSegmentSize = MaximumSegmentSize;
                     }
 
+                    if (Info & (1 << XEN_NETIF_EXTRA_TYPE_HASH)) {
+                        ASSERT3U(Hash.Algorithm, ==, 
XENVIF_PACKET_HASH_ALGORITHM_TOEPLITZ);
+
+                        if (Hash.Algorithm == Ring->Hash.Algorithm &&
+                            ((1u << Hash.Type) & Ring->Hash.Types))
+                            Packet->Hash = Hash;
+                    }
+
                     Packet->Flags.Value = flags;
 
                     ASSERT(IsZeroMemory(&Packet->ListEntry, sizeof 
(LIST_ENTRY)));
@@ -1952,6 +2010,7 @@ ReceiverRingPoll(
                 Error = FALSE;
                 Info = 0;
                 MaximumSegmentSize = 0;
+                RtlZeroMemory(&Hash, sizeof (Hash));
                 Packet = NULL;
                 flags = 0;
                 TailMdl = NULL;
@@ -1963,6 +2022,7 @@ ReceiverRingPoll(
         ASSERT3P(Packet, ==, NULL);
         ASSERT3U(flags, ==, 0);
         ASSERT3U(MaximumSegmentSize, ==, 0);
+        ASSERT(IsZeroMemory(&Hash, sizeof (Hash)));
         ASSERT3P(TailMdl, ==, NULL);
         ASSERT(EOP);
 
@@ -2158,7 +2218,7 @@ ReceiverRingWatchdog(
                              Ring->DebugCallback);
 
                 // Try to move things along
-                ReceiverRingPoll(Ring);
+                __ReceiverRingTrigger(Ring, TRUE);
                 __ReceiverRingSend(Ring, TRUE);
             }
 
@@ -2679,6 +2739,7 @@ __ReceiverRingTeardown(
     Receiver = Ring->Receiver;
     Frontend = Receiver->Frontend;
 
+    RtlZeroMemory(&Ring->Hash, sizeof (XENVIF_RECEIVER_HASH));
     RtlZeroMemory(&Ring->TimerDpc, sizeof (KDPC));
     RtlZeroMemory(&Ring->Timer, sizeof (KTIMER));
     RtlZeroMemory(&Ring->Dpc, sizeof (KDPC));
@@ -3486,6 +3547,19 @@ ReceiverWaitForPackets(
 }
 
 VOID
+ReceiverTrigger(
+    IN  PXENVIF_RECEIVER    Receiver,
+    IN  ULONG               Index
+    )
+{
+    PXENVIF_RECEIVER_RING   Ring;
+
+    Ring = Receiver->Ring[Index];
+
+    __ReceiverRingTrigger(Ring, FALSE);
+}
+
+VOID
 ReceiverSend(
     IN  PXENVIF_RECEIVER    Receiver,
     IN  ULONG               Index
@@ -3497,3 +3571,191 @@ ReceiverSend(
 
     __ReceiverRingSend(Ring, FALSE);
 }
+
+NTSTATUS
+ReceiverSetHashAlgorithm(
+    IN  PXENVIF_RECEIVER                Receiver,
+    IN  XENVIF_PACKET_HASH_ALGORITHM    Algorithm
+    )
+{
+    PXENVIF_FRONTEND                    Frontend;
+    KIRQL                               Irql;
+    LONG                                Index;
+    NTSTATUS                            status;
+
+    Frontend = Receiver->Frontend;
+
+    KeRaiseIrql(DISPATCH_LEVEL, &Irql);
+
+    for (Index = 0;
+         Index < (LONG)FrontendGetMaxQueues(Frontend);
+         ++Index) {
+        PXENVIF_RECEIVER_RING   Ring;
+
+        Ring = Receiver->Ring[Index];
+        if (Ring == NULL)
+            break;
+
+        __ReceiverRingAcquireLock(Ring);
+        Ring->Hash.Algorithm = Algorithm;
+        __ReceiverRingReleaseLock(Ring);
+    }
+
+    KeLowerIrql(Irql);
+
+    status = FrontendSetHashAlgorithm(Frontend, Algorithm);
+    if (!NT_SUCCESS(status))
+        goto fail1;
+
+    status = FrontendUpdateHash(Frontend);
+    if (!NT_SUCCESS(status))
+        goto fail2;
+
+    return STATUS_SUCCESS;
+
+fail2:
+    Error("fail2\n");
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
+}
+
+NTSTATUS
+ReceiverQueryHashCapabilities(
+    IN  PXENVIF_RECEIVER    Receiver,
+    OUT PULONG              Types
+    )
+{
+    PXENVIF_FRONTEND        Frontend;
+    NTSTATUS                status;
+
+    Frontend = Receiver->Frontend;
+
+    status = FrontendQueryHashTypes(Frontend, Types);
+    if (!NT_SUCCESS(status))
+        goto fail1;
+
+    return STATUS_SUCCESS;
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
+}
+
+NTSTATUS
+ReceiverUpdateHashParameters(
+    IN  PXENVIF_RECEIVER    Receiver,
+    IN  ULONG               Types,
+    IN  PUCHAR              Key
+    )
+{
+    PXENVIF_FRONTEND        Frontend;
+    KIRQL                   Irql;
+    LONG                    Index;
+    NTSTATUS                status;
+
+    Frontend = Receiver->Frontend;
+
+    KeRaiseIrql(DISPATCH_LEVEL, &Irql);
+
+    for (Index = 0;
+         Index < (LONG)FrontendGetMaxQueues(Frontend);
+         ++Index) {
+        PXENVIF_RECEIVER_RING   Ring;
+
+        Ring = Receiver->Ring[Index];
+        if (Ring == NULL)
+            break;
+
+        __ReceiverRingAcquireLock(Ring);
+        Ring->Hash.Types = Types;
+        __ReceiverRingReleaseLock(Ring);
+    }
+
+    KeLowerIrql(Irql);
+
+    status = FrontendSetHashTypes(Frontend, Types);
+    if (!NT_SUCCESS(status))
+        goto fail1;
+
+    status = FrontendSetHashKey(Frontend, Key);
+    if (!NT_SUCCESS(status))
+        goto fail1;
+
+    status = FrontendUpdateHash(Frontend);
+    if (!NT_SUCCESS(status))
+        goto fail2;
+
+    return STATUS_SUCCESS;
+
+fail2:
+    Error("fail2\n");
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
+}
+
+NTSTATUS
+ReceiverUpdateHashMapping(
+    IN  PXENVIF_RECEIVER    Receiver,
+    IN  PPROCESSOR_NUMBER   ProcessorMapping,
+    IN  ULONG               Size
+    )
+{
+    PXENVIF_FRONTEND        Frontend;
+    PULONG                  QueueMapping;
+    ULONG                   NumQueues;
+    ULONG                   Index;
+    NTSTATUS                status;
+
+    Frontend = Receiver->Frontend;
+
+    QueueMapping = __ReceiverAllocate(sizeof (ULONG) * Size);
+
+    status = STATUS_NO_MEMORY;
+    if (QueueMapping == NULL)
+        goto fail1;
+
+    NumQueues = FrontendGetNumQueues(Frontend);
+
+    status = STATUS_INVALID_PARAMETER;
+    for (Index = 0; Index < Size; Index++) {
+        QueueMapping[Index] = 
KeGetProcessorIndexFromNumber(&ProcessorMapping[Index]);
+
+        if (QueueMapping[Index] >= NumQueues)
+            goto fail2;
+    }
+
+    status = FrontendSetHashMapping(Frontend, QueueMapping, Size);
+    if (!NT_SUCCESS(status))
+        goto fail3;
+
+    status = FrontendUpdateHash(Frontend);
+    if (!NT_SUCCESS(status))
+        goto fail4;
+
+    __ReceiverFree(QueueMapping);
+
+    return STATUS_SUCCESS;
+
+fail4:
+    Error("fail4\n");
+
+fail3:
+    Error("fail3\n");
+
+fail2:
+    Error("fail2\n");
+
+    __ReceiverFree(QueueMapping);
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
+}
diff --git a/src/xenvif/receiver.h b/src/xenvif/receiver.h
index 7188dfa..7846f0b 100644
--- a/src/xenvif/receiver.h
+++ b/src/xenvif/receiver.h
@@ -107,9 +107,41 @@ ReceiverReturnPacket(
     );
 
 extern VOID
+ReceiverTrigger(
+    IN  PXENVIF_RECEIVER    Receiver,
+    IN  ULONG               Index
+    );
+
+extern VOID
 ReceiverSend(
     IN  PXENVIF_RECEIVER    Receiver,
     IN  ULONG               Index
     );
 
+NTSTATUS
+ReceiverSetHashAlgorithm(
+    IN  PXENVIF_RECEIVER                Receiver,
+    IN  XENVIF_PACKET_HASH_ALGORITHM    Algorithm
+    );
+
+NTSTATUS
+ReceiverQueryHashCapabilities(
+    IN  PXENVIF_RECEIVER    Receiver,
+    OUT PULONG              Types
+    );
+
+NTSTATUS
+ReceiverUpdateHashParameters(
+    IN  PXENVIF_RECEIVER    Receiver,
+    IN  ULONG               Types,
+    IN  PUCHAR              Key
+    );
+
+NTSTATUS
+ReceiverUpdateHashMapping(
+    IN  PXENVIF_RECEIVER    Receiver,
+    IN  PPROCESSOR_NUMBER   ProcessorMapping,
+    IN  ULONG               Order
+    );
+
 #endif  // _XENVIF_RECEIVER_H
diff --git a/src/xenvif/transmitter.c b/src/xenvif/transmitter.c
index 9406cab..18f664d 100644
--- a/src/xenvif/transmitter.c
+++ b/src/xenvif/transmitter.c
@@ -2524,6 +2524,32 @@ done:
 }
 
 static FORCEINLINE VOID
+__TransmitterRingTrigger(
+    IN  PXENVIF_TRANSMITTER_RING    Ring
+    )
+{
+    PXENVIF_TRANSMITTER             Transmitter;
+    PXENVIF_FRONTEND                Frontend;
+
+    Transmitter = Ring->Transmitter;
+    Frontend = Transmitter->Frontend;
+
+    if (!Ring->Connected)
+        return;
+
+    if (FrontendIsSplit(Frontend)) {
+        ASSERT(Ring->Channel != NULL);
+
+        (VOID) XENBUS_EVTCHN(Trigger,
+                             &Transmitter->EvtchnInterface,
+                             Ring->Channel);
+    } else {
+        ReceiverTrigger(FrontendGetReceiver(Frontend),
+                        Ring->Index);
+    }
+}
+
+static FORCEINLINE VOID
 __TransmitterRingSend(
     IN  PXENVIF_TRANSMITTER_RING    Ring
     )
@@ -3087,8 +3113,8 @@ TransmitterRingWatchdog(
                              Ring->DebugCallback);
 
                 // Try to move things along
+                __TransmitterRingTrigger(Ring);
                 __TransmitterRingSend(Ring);
-                (VOID) TransmitterRingPoll(Ring);
             }
 
             PacketsQueued = Ring->PacketsQueued;
@@ -4772,6 +4798,7 @@ TransmitterQueuePacket(
     PUCHAR                          StartVa;
     PXENVIF_PACKET_PAYLOAD          Payload;
     PXENVIF_PACKET_INFO             Info;
+    ULONG                           Value;
     ULONG                           Index;
     PXENVIF_TRANSMITTER_RING        Ring;
     NTSTATUS                        status;
@@ -4805,20 +4832,21 @@ TransmitterQueuePacket(
 
     switch (Hash->Algorithm) {
     case XENVIF_PACKET_HASH_ALGORITHM_NONE:
-        Index = __TransmitterHashPacket(Packet);
+        Value = __TransmitterHashPacket(Packet);
         break;
 
     case XENVIF_PACKET_HASH_ALGORITHM_UNSPECIFIED:
-        Index = Hash->Value;
+    case XENVIF_PACKET_HASH_ALGORITHM_TOEPLITZ:
+        Value = Hash->Value;
         break;
 
     default:
         ASSERT(FALSE);
-        Index = 0;
+        Value = 0;
         break;
     }
 
-    Index %= FrontendGetNumQueues(Frontend);
+    Index = FrontendGetQueue(Frontend, Value);
     Ring = Transmitter->Ring[Index];
 
     __TransmitterRingQueuePacket(Ring, Packet);
diff --git a/src/xenvif/vif.c b/src/xenvif/vif.c
index ce94a56..5501e25 100644
--- a/src/xenvif/vif.c
+++ b/src/xenvif/vif.c
@@ -319,6 +319,42 @@ done:
 }
 
 static VOID
+VifQueryRingCount(
+    IN  PINTERFACE      Interface,
+    OUT PULONG          Count
+    )
+{
+    PXENVIF_VIF_CONTEXT Context = Interface->Context;
+
+    AcquireMrswLockShared(&Context->Lock);
+
+    *Count = FrontendGetNumQueues(Context->Frontend);
+
+    ReleaseMrswLockShared(&Context->Lock);
+}
+
+static NTSTATUS
+VifUpdateHashMapping(
+    IN  PINTERFACE          Interface,
+    IN  PPROCESSOR_NUMBER   Mapping,
+    IN  ULONG               Order
+    )
+{
+    PXENVIF_VIF_CONTEXT     Context = Interface->Context;
+    NTSTATUS                status;
+
+    AcquireMrswLockShared(&Context->Lock);
+
+    status = ReceiverUpdateHashMapping(FrontendGetReceiver(Context->Frontend),
+                                       Mapping,
+                                       Order);
+
+    ReleaseMrswLockShared(&Context->Lock);
+
+    return status;
+}
+
+static VOID
 VifReceiverReturnPacketsVersion1(
     IN  PINTERFACE      Interface,
     IN  PLIST_ENTRY     List
@@ -671,6 +707,82 @@ VifReceiverSetBackfillSize(
     ReleaseMrswLockShared(&Context->Lock);
 }
 
+static NTSTATUS
+VifReceiverSetHashAlgorithm(
+    IN  PINTERFACE                      Interface,
+    IN  XENVIF_PACKET_HASH_ALGORITHM    Algorithm
+    )
+{
+    PXENVIF_VIF_CONTEXT                 Context = Interface->Context;
+    NTSTATUS                            status;
+
+    AcquireMrswLockShared(&Context->Lock);
+
+    status = ReceiverSetHashAlgorithm(FrontendGetReceiver(Context->Frontend),
+                                      Algorithm);
+
+    ReleaseMrswLockShared(&Context->Lock);
+
+    return status;
+}
+
+static NTSTATUS
+VifReceiverQueryHashCapabilities(
+    IN  PINTERFACE      Interface,
+    ...
+    )
+{
+    PXENVIF_VIF_CONTEXT Context = Interface->Context;
+    va_list             Arguments;
+    PULONG              Types;
+    NTSTATUS            status;
+
+    AcquireMrswLockShared(&Context->Lock);
+
+    va_start(Arguments, Interface);
+
+    Types = va_arg(Arguments, PULONG);
+
+    status = 
ReceiverQueryHashCapabilities(FrontendGetReceiver(Context->Frontend),
+                                           Types);
+
+    va_end(Arguments);
+
+    ReleaseMrswLockShared(&Context->Lock);
+
+    return status;
+}
+
+static NTSTATUS
+VifReceiverUpdateHashParameters(
+    IN  PINTERFACE      Interface,
+    ...
+    )
+{
+    PXENVIF_VIF_CONTEXT Context = Interface->Context;
+    va_list             Arguments;
+    ULONG               Types;
+    PUCHAR              Key;
+    NTSTATUS            status;
+
+    AcquireMrswLockShared(&Context->Lock);
+
+    va_start(Arguments, Interface);
+
+    Types = va_arg(Arguments, ULONG);
+    Key = va_arg(Arguments, PUCHAR);
+
+    status = 
ReceiverUpdateHashParameters(FrontendGetReceiver(Context->Frontend),
+                                          Types,
+                                          Key);
+
+    va_end(Arguments);
+
+    ReleaseMrswLockShared(&Context->Lock);
+
+    return status;
+}
+
 static VOID
 VifMacQueryState(
     IN  PINTERFACE                  Interface,
@@ -1009,6 +1121,36 @@ static struct _XENVIF_VIF_INTERFACE_V5 
VifInterfaceVersion5 = {
     VifMacQueryFilterLevel
 };
 
+static struct _XENVIF_VIF_INTERFACE_V6 VifInterfaceVersion6 = {
+    { sizeof (struct _XENVIF_VIF_INTERFACE_V6), 6, NULL, NULL, NULL },
+    VifAcquire,
+    VifRelease,
+    VifEnable,
+    VifDisable,
+    VifQueryStatistic,
+    VifQueryRingCount,
+    VifUpdateHashMapping,
+    VifReceiverReturnPacket,
+    VifReceiverSetOffloadOptions,
+    VifReceiverSetBackfillSize,
+    VifReceiverQueryRingSize,
+    VifReceiverSetHashAlgorithm,
+    VifReceiverQueryHashCapabilities,
+    VifReceiverUpdateHashParameters,
+    VifTransmitterQueuePacket,
+    VifTransmitterQueryOffloadOptions,
+    VifTransmitterQueryLargePacketSize,
+    VifTransmitterQueryRingSize,
+    VifMacQueryState,
+    VifMacQueryMaximumFrameSize,
+    VifMacQueryPermanentAddress,
+    VifMacQueryCurrentAddress,
+    VifMacQueryMulticastAddresses,
+    VifMacSetMulticastAddresses,
+    VifMacSetFilterLevel,
+    VifMacQueryFilterLevel
+};
+
 NTSTATUS
 VifInitialize(
     IN  PXENVIF_PDO         Pdo,
@@ -1141,6 +1283,23 @@ VifGetInterface(
         status = STATUS_SUCCESS;
         break;
     }
+    case 6: {
+        struct _XENVIF_VIF_INTERFACE_V6 *VifInterface;
+
+        VifInterface = (struct _XENVIF_VIF_INTERFACE_V6 *)Interface;
+
+        status = STATUS_BUFFER_OVERFLOW;
+        if (Size < sizeof (struct _XENVIF_VIF_INTERFACE_V6))
+            break;
+
+        *VifInterface = VifInterfaceVersion6;
+
+        ASSERT3U(Interface->Version, ==, Version);
+        Interface->Context = Context;
+
+        status = STATUS_SUCCESS;
+        break;
+    }
     default:
         status = STATUS_NOT_SUPPORTED;
         break;
@@ -1186,6 +1345,7 @@ __VifReceiverQueuePacketVersion1(
     IN  USHORT                          MaximumSegmentSize,
     IN  USHORT                          TagControlInformation,
     IN  PXENVIF_PACKET_INFO             Info,
+    IN  PXENVIF_PACKET_HASH             Hash,
     IN  PVOID                           Cookie
     )
 {
@@ -1194,6 +1354,8 @@ __VifReceiverQueuePacketVersion1(
     LIST_ENTRY                          List;
     NTSTATUS                            status;
 
+    UNREFERENCED_PARAMETER(Hash);
+
     InfoVersion1 = __VifAllocate(sizeof (struct _XENVIF_PACKET_INFO_V1));
 
     status = STATUS_NO_MEMORY;
@@ -1247,6 +1409,34 @@ fail1:
                          Cookie);
 }
 
+static FORCEINLINE VOID
+__VifReceiverQueuePacketVersion4(
+    IN  PXENVIF_VIF_CONTEXT             Context,
+    IN  PMDL                            Mdl,
+    IN  ULONG                           Offset,
+    IN  ULONG                           Length,
+    IN  XENVIF_PACKET_CHECKSUM_FLAGS    Flags,
+    IN  USHORT                          MaximumSegmentSize,
+    IN  USHORT                          TagControlInformation,
+    IN  PXENVIF_PACKET_INFO             Info,
+    IN  PXENVIF_PACKET_HASH             Hash,
+    IN  PVOID                           Cookie
+    )
+{
+    UNREFERENCED_PARAMETER(Hash);
+
+    Context->Callback(Context->Argument,
+                      XENVIF_RECEIVER_QUEUE_PACKET,
+                      Mdl,
+                      Offset,
+                      Length,
+                      Flags,
+                      MaximumSegmentSize,
+                      TagControlInformation,
+                      Info,
+                      Cookie);
+}
+
 VOID
 VifReceiverQueuePacket(
     IN  PXENVIF_VIF_CONTEXT             Context,
@@ -1257,6 +1447,7 @@ VifReceiverQueuePacket(
     IN  USHORT                          MaximumSegmentSize,
     IN  USHORT                          TagControlInformation,
     IN  PXENVIF_PACKET_INFO             Info,
+    IN  PXENVIF_PACKET_HASH             Hash,
     IN  PVOID                           Cookie
     )
 {
@@ -1271,11 +1462,25 @@ VifReceiverQueuePacket(
                                          MaximumSegmentSize,
                                          TagControlInformation,
                                          Info,
+                                         Hash,
                                          Cookie);
         break;
 
     case 4:
     case 5:
+        __VifReceiverQueuePacketVersion4(Context,
+                                         Mdl,
+                                         Offset,
+                                         Length,
+                                         Flags,
+                                         MaximumSegmentSize,
+                                         TagControlInformation,
+                                         Info,
+                                         Hash,
+                                         Cookie);
+        break;
+
+    case 6:
         Context->Callback(Context->Argument,
                           XENVIF_RECEIVER_QUEUE_PACKET,
                           Mdl,
@@ -1285,6 +1490,7 @@ VifReceiverQueuePacket(
                           MaximumSegmentSize,
                           TagControlInformation,
                           Info,
+                          Hash,
                           Cookie);
         break;
 
@@ -1334,6 +1540,7 @@ VifTransmitterReturnPacket(
 
     case 4:
     case 5:
+    case 6:
         Context->Callback(Context->Argument,
                           XENVIF_TRANSMITTER_RETURN_PACKET,
                           Cookie,
diff --git a/src/xenvif/vif.h b/src/xenvif/vif.h
index 6cda4b7..6894ca2 100644
--- a/src/xenvif/vif.h
+++ b/src/xenvif/vif.h
@@ -78,6 +78,7 @@ VifReceiverQueuePacket(
     IN  USHORT                          MaximumSegmentSize,
     IN  USHORT                          TagControlInformation,
     IN  PXENVIF_PACKET_INFO             Info,
+    IN  PXENVIF_PACKET_HASH             Hash,
     IN  PVOID                           Cookie
     );
 
-- 
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®.