[ovs-dev] [PATCH v7 2/3] datapath-windows: Support for multiple VXLAN tunnels

Sorin Vinturis svinturis at cloudbasesolutions.com
Wed May 27 16:08:21 UTC 2015


At the moment the OVS extension supports only one VXLAN tunnel that
is cached in the extension switch context. Replaced the latter
cached pointer with an array list that contains all VXLAN tunnel
vports.

Signed-off-by: Sorin Vinturis <svinturis at cloudbasesolutions.com>
Reported-by: Alin Gabriel Serdean <aserdean at cloudbasesolutions.com>
Reported-at: https://github.com/openvswitch/ovs-issues/issues/64
Acked-by: Eitan Eliahu <eliahue at vmware.com>
Acked-by: Nithin Raju <nithin at vmware.com>
---
 datapath-windows/ovsext/Actions.c | 13 ++++++++----
 datapath-windows/ovsext/Switch.c  | 16 +++++++++-----
 datapath-windows/ovsext/Switch.h  |  6 ++++--
 datapath-windows/ovsext/Tunnel.c  |  3 ++-
 datapath-windows/ovsext/Vport.c   | 44 ++++++++++++++++++++++++++++++++-------
 datapath-windows/ovsext/Vport.h   | 21 +++++--------------
 datapath-windows/ovsext/Vxlan.c   |  2 +-
 datapath-windows/ovsext/Vxlan.h   |  2 +-
 8 files changed, 70 insertions(+), 37 deletions(-)

diff --git a/datapath-windows/ovsext/Actions.c b/datapath-windows/ovsext/Actions.c
index a93fe03..79e464c 100644
--- a/datapath-windows/ovsext/Actions.c
+++ b/datapath-windows/ovsext/Actions.c
@@ -184,6 +184,9 @@ OvsInitForwardingCtx(OvsForwardingContext *ovsFwdCtx,
 }
 
 /*
+ * XXX: When we search for the tunnelVport we also need to specify the
+ * tunnelling protocol or the L4 protocol as key as well, because there are
+ * different protocols that can use the same destination port.
  * --------------------------------------------------------------------------
  * OvsDetectTunnelRxPkt --
  *     Utility function for an RX packet to detect its tunnel type.
@@ -203,16 +206,17 @@ OvsDetectTunnelRxPkt(OvsForwardingContext *ovsFwdCtx,
      * packets only if they are at least VXLAN header size.
      */
     if (!flowKey->ipKey.nwFrag &&
-        flowKey->ipKey.nwProto == IPPROTO_UDP &&
-        flowKey->ipKey.l4.tpDst == VXLAN_UDP_PORT_NBO) {
-        tunnelVport = ovsFwdCtx->switchContext->vxlanVport;
-        ovsActionStats.rxVxlan++;
+        flowKey->ipKey.nwProto == IPPROTO_UDP) {
+        UINT16 dstPort = htons(flowKey->ipKey.l4.tpDst);
+        tunnelVport = OvsFindTunnelVportByDstPort(ovsFwdCtx->switchContext,
+                                                  dstPort);
     }
 
     // We might get tunnel packets even before the tunnel gets initialized.
     if (tunnelVport) {
         ASSERT(ovsFwdCtx->tunnelRxNic == NULL);
         ovsFwdCtx->tunnelRxNic = tunnelVport;
+        ovsActionStats.rxVxlan++;
         return TRUE;
     }
 
@@ -1318,6 +1322,7 @@ OvsExecuteSetAction(OvsForwardingContext *ovsFwdCtx,
 		status = OvsTunnelAttrToIPv4TunnelKey((PNL_ATTR)a, &tunKey);
         ASSERT(status == NDIS_STATUS_SUCCESS);
         tunKey.flow_hash = (uint16)(hash ? *hash : OvsHashFlow(key));
+        tunKey.dst_port = key->ipKey.l4.tpDst;
         RtlCopyMemory(&ovsFwdCtx->tunKey, &tunKey, sizeof ovsFwdCtx->tunKey);
 
         break;
diff --git a/datapath-windows/ovsext/Switch.c b/datapath-windows/ovsext/Switch.c
index 416bcc0..f877854 100644
--- a/datapath-windows/ovsext/Switch.c
+++ b/datapath-windows/ovsext/Switch.c
@@ -367,6 +367,8 @@ OvsInitSwitchContext(POVS_SWITCH_CONTEXT switchContext)
         sizeof(LIST_ENTRY) * OVS_MAX_VPORT_ARRAY_SIZE, OVS_SWITCH_POOL_TAG);
     switchContext->pidHashArray = (PLIST_ENTRY)OvsAllocateMemoryWithTag(
         sizeof(LIST_ENTRY) * OVS_MAX_PID_ARRAY_SIZE, OVS_SWITCH_POOL_TAG);
+    switchContext->tunnelVportsArray = (PLIST_ENTRY)OvsAllocateMemoryWithTag(
+        sizeof(LIST_ENTRY) * OVS_MAX_VPORT_ARRAY_SIZE, OVS_SWITCH_POOL_TAG);
     status = OvsAllocateFlowTable(&switchContext->datapath, switchContext);
 
     if (status == NDIS_STATUS_SUCCESS) {
@@ -377,7 +379,8 @@ OvsInitSwitchContext(POVS_SWITCH_CONTEXT switchContext)
         switchContext->portNoHashArray == NULL ||
         switchContext->ovsPortNameHashArray == NULL ||
         switchContext->portIdHashArray== NULL ||
-        switchContext->pidHashArray == NULL) {
+        switchContext->pidHashArray == NULL ||
+        switchContext->tunnelVportsArray == NULL) {
         if (switchContext->dispatchLock) {
             NdisFreeRWLock(switchContext->dispatchLock);
         }
@@ -398,6 +401,10 @@ OvsInitSwitchContext(POVS_SWITCH_CONTEXT switchContext)
                                  OVS_SWITCH_POOL_TAG);
         }
 
+        if (switchContext->tunnelVportsArray) {
+            OvsFreeMemory(switchContext->tunnelVportsArray);
+        }
+
         OvsDeleteFlowTable(&switchContext->datapath);
         OvsCleanupBufferPool(switchContext);
 
@@ -407,12 +414,9 @@ OvsInitSwitchContext(POVS_SWITCH_CONTEXT switchContext)
 
     for (i = 0; i < OVS_MAX_VPORT_ARRAY_SIZE; i++) {
         InitializeListHead(&switchContext->ovsPortNameHashArray[i]);
-    }
-    for (i = 0; i < OVS_MAX_VPORT_ARRAY_SIZE; i++) {
         InitializeListHead(&switchContext->portIdHashArray[i]);
-    }
-    for (i = 0; i < OVS_MAX_VPORT_ARRAY_SIZE; i++) {
         InitializeListHead(&switchContext->portNoHashArray[i]);
+        InitializeListHead(&switchContext->tunnelVportsArray[i]);
     }
 
     for (i = 0; i < OVS_MAX_PID_ARRAY_SIZE; i++) {
@@ -465,6 +469,8 @@ OvsDeleteSwitchContext(POVS_SWITCH_CONTEXT switchContext)
     OvsFreeMemoryWithTag(switchContext->pidHashArray,
                          OVS_SWITCH_POOL_TAG);
     switchContext->pidHashArray = NULL;
+    OvsFreeMemory(switchContext->tunnelVportsArray);
+    switchContext->tunnelVportsArray = NULL;
     OvsDeleteFlowTable(&switchContext->datapath);
     OvsCleanupBufferPool(switchContext);
 
diff --git a/datapath-windows/ovsext/Switch.h b/datapath-windows/ovsext/Switch.h
index 6ec34e1..8e1eb5f 100644
--- a/datapath-windows/ovsext/Switch.h
+++ b/datapath-windows/ovsext/Switch.h
@@ -132,8 +132,6 @@ typedef struct _OVS_SWITCH_CONTEXT
     POVS_VPORT_ENTRY        virtualExternalVport;   // the virtual adapter vport
     POVS_VPORT_ENTRY        internalVport;
 
-    POVS_VPORT_ENTRY        vxlanVport;
-
     /*
      * 'portIdHashArray' ONLY contains ports that exist on the Hyper-V switch,
      * namely: VIF (vNIC) ports, external port and Hyper-V internal port.
@@ -148,11 +146,15 @@ typedef struct _OVS_SWITCH_CONTEXT
      * exist on the Hyper-V switch, and 'numNonHvVports' counts such ports in
      * 'portNoHashArray'.
      *
+     * 'tunnelVportsArray' contains tunnel ports that are added from OVS
+     * userspace. Currently only VXLAN tunnels are added in this list.
+     *
      * 'ovsPortNameHashArray' contains the same entries as 'portNoHashArray' but
      * hashed on a different key.
      */
     PLIST_ENTRY             portIdHashArray;        // based on Hyper-V portId
     PLIST_ENTRY             portNoHashArray;        // based on ovs port number
+    PLIST_ENTRY             tunnelVportsArray;      // based on ovs dst port number
     PLIST_ENTRY             ovsPortNameHashArray;   // based on ovsName
     PLIST_ENTRY             pidHashArray;           // based on packet pids
     NDIS_SPIN_LOCK          pidHashLock;            // Lock for pidHash table
diff --git a/datapath-windows/ovsext/Tunnel.c b/datapath-windows/ovsext/Tunnel.c
index fed58f1..002f180 100644
--- a/datapath-windows/ovsext/Tunnel.c
+++ b/datapath-windows/ovsext/Tunnel.c
@@ -285,7 +285,8 @@ OvsInjectPacketThroughActions(PNET_BUFFER_LIST pNbl,
 
         SendFlags |= NDIS_SEND_FLAGS_DISPATCH_LEVEL;
 
-        vport = gOvsSwitchContext->vxlanVport;
+        vport = OvsFindTunnelVportByDstPort(gOvsSwitchContext,
+                                            htons(tunnelKey.dst_port));
 
         if (vport == NULL){
             status = STATUS_UNSUCCESSFUL;
diff --git a/datapath-windows/ovsext/Vport.c b/datapath-windows/ovsext/Vport.c
index 66f9189..5a1b64f 100644
--- a/datapath-windows/ovsext/Vport.c
+++ b/datapath-windows/ovsext/Vport.c
@@ -601,6 +601,25 @@ OvsFindVportByPortNo(POVS_SWITCH_CONTEXT switchContext,
 
 
 POVS_VPORT_ENTRY
+OvsFindTunnelVportByDstPort(POVS_SWITCH_CONTEXT switchContext,
+                            UINT16 dstPort)
+{
+    POVS_VPORT_ENTRY vport;
+    PLIST_ENTRY head, link;
+    UINT32 hash = OvsJhashBytes((const VOID *)&dstPort, sizeof(dstPort),
+                                OVS_HASH_BASIS);
+    head = &(switchContext->tunnelVportsArray[hash & OVS_VPORT_MASK]);
+    LIST_FORALL(head, link) {
+        vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, tunnelVportLink);
+        if (((POVS_VXLAN_VPORT)vport->priv)->dstPort == dstPort) {
+            return vport;
+        }
+    }
+    return NULL;
+}
+
+
+POVS_VPORT_ENTRY
 OvsFindVportByOvsName(POVS_SWITCH_CONTEXT switchContext,
                       PSTR name)
 {
@@ -1048,8 +1067,8 @@ InitHvVportCommon(POVS_SWITCH_CONTEXT switchContext,
  * --------------------------------------------------------------------------
  * Functionality common to any port added from OVS userspace.
  *
- * Inserts the port into 'portIdHashArray', 'ovsPortNameHashArray' and caches
- * the pointer in the 'switchContext' if needed.
+ * Inserts the port into 'portNoHashArray', 'ovsPortNameHashArray' and in
+ * 'tunnelVportsArray' if appropriate.
  * --------------------------------------------------------------------------
  */
 NDIS_STATUS
@@ -1060,9 +1079,17 @@ InitOvsVportCommon(POVS_SWITCH_CONTEXT switchContext,
 
     switch(vport->ovsType) {
     case OVS_VPORT_TYPE_VXLAN:
-        switchContext->vxlanVport = vport;
+    {
+        POVS_VXLAN_VPORT vxlanVport = (POVS_VXLAN_VPORT)vport->priv;
+        hash = OvsJhashBytes(&vxlanVport->dstPort,
+                             sizeof(vxlanVport->dstPort),
+                             OVS_HASH_BASIS);
+        InsertHeadList(
+            &gOvsSwitchContext->tunnelVportsArray[hash & OVS_VPORT_MASK],
+            &vport->tunnelVportLink);
         switchContext->numNonHvVports++;
         break;
+    }
     case OVS_VPORT_TYPE_INTERNAL:
         if (vport->isBridgeInternal) {
             switchContext->numNonHvVports++;
@@ -1131,6 +1158,11 @@ OvsCleanupVportCommon(POVS_SWITCH_CONTEXT switchContext,
         InitializeListHead(&vport->ovsNameLink);
         RemoveEntryList(&vport->portNoLink);
         InitializeListHead(&vport->portNoLink);
+        if (OVS_VPORT_TYPE_VXLAN == vport->ovsType) {
+            RemoveEntryList(&vport->tunnelVportLink);
+            InitializeListHead(&vport->tunnelVportLink);
+        }
+
         deletedOnOvs = TRUE;
     }
 
@@ -1224,8 +1256,6 @@ OvsRemoveAndDeleteVport(PVOID usrParamsContext,
                                        vport,
                                        OvsTunnelVportPendingUninit,
                                        tunnelContext);
-
-        switchContext->vxlanVport = NULL;
         break;
     }
     case OVS_VPORT_TYPE_GRE:
@@ -1386,6 +1416,7 @@ OvsClearAllSwitchVports(POVS_SWITCH_CONTEXT switchContext)
             OvsRemoveAndDeleteVport(NULL, switchContext, vport, TRUE, TRUE);
         }
     }
+
     /*
      * Remove 'virtualExternalVport' as well. This port is not part of the
      * 'portIdHashArray'.
@@ -1395,9 +1426,9 @@ OvsClearAllSwitchVports(POVS_SWITCH_CONTEXT switchContext)
             (POVS_VPORT_ENTRY)switchContext->virtualExternalVport, TRUE, TRUE);
     }
 
+
     for (UINT hash = 0; hash < OVS_MAX_VPORT_ARRAY_SIZE; hash++) {
         PLIST_ENTRY head, link, next;
-
         head = &(switchContext->portNoHashArray[hash & OVS_VPORT_MASK]);
         LIST_FORALL_SAFE(head, link, next) {
             POVS_VPORT_ENTRY vport;
@@ -1411,7 +1442,6 @@ OvsClearAllSwitchVports(POVS_SWITCH_CONTEXT switchContext)
 
     ASSERT(switchContext->virtualExternalVport == NULL);
     ASSERT(switchContext->internalVport == NULL);
-    ASSERT(switchContext->vxlanVport == NULL);
 }
 
 
diff --git a/datapath-windows/ovsext/Vport.h b/datapath-windows/ovsext/Vport.h
index 4cfda30..086f03f 100644
--- a/datapath-windows/ovsext/Vport.h
+++ b/datapath-windows/ovsext/Vport.h
@@ -84,6 +84,7 @@ typedef struct _OVS_VPORT_ENTRY {
     LIST_ENTRY             ovsNameLink;
     LIST_ENTRY             portIdLink;
     LIST_ENTRY             portNoLink;
+    LIST_ENTRY             tunnelVportLink;
 
     OVS_VPORT_STATE        ovsState;
     OVS_VPORT_TYPE         ovsType;
@@ -135,10 +136,8 @@ typedef struct _OVS_VPORT_ENTRY {
 
 struct _OVS_SWITCH_CONTEXT;
 
-POVS_VPORT_ENTRY
-OvsFindVportByPortNo(struct _OVS_SWITCH_CONTEXT *switchContext,
-                     UINT32 portNo);
-
+POVS_VPORT_ENTRY OvsFindVportByPortNo(POVS_SWITCH_CONTEXT switchContext,
+                                      UINT32 portNo);
 /* "name" is null-terminated */
 POVS_VPORT_ENTRY OvsFindVportByOvsName(POVS_SWITCH_CONTEXT switchContext,
                                        PSTR name);
@@ -147,6 +146,8 @@ POVS_VPORT_ENTRY OvsFindVportByHvNameA(POVS_SWITCH_CONTEXT switchContext,
 POVS_VPORT_ENTRY OvsFindVportByPortIdAndNicIndex(POVS_SWITCH_CONTEXT switchContext,
                                                  NDIS_SWITCH_PORT_ID portId,
                                                  NDIS_SWITCH_NIC_INDEX index);
+POVS_VPORT_ENTRY OvsFindTunnelVportByDstPort(POVS_SWITCH_CONTEXT switchContext,
+                                             UINT16 dstPort);
 
 NDIS_STATUS OvsAddConfiguredSwitchPorts(struct _OVS_SWITCH_CONTEXT *switchContext);
 NDIS_STATUS OvsInitConfiguredSwitchNics(struct _OVS_SWITCH_CONTEXT *switchContext);
@@ -180,18 +181,6 @@ OvsIsTunnelVportType(OVS_VPORT_TYPE ovsType)
            ovsType == OVS_VPORT_TYPE_GRE64;
 }
 
-static __inline POVS_VPORT_ENTRY
-OvsGetTunnelVport(POVS_SWITCH_CONTEXT switchContext,
-                  OVS_VPORT_TYPE ovsType)
-{
-    switch(ovsType) {
-    case OVS_VPORT_TYPE_VXLAN:
-        return switchContext->vxlanVport;
-    default:
-        return NULL;
-    }
-}
-
 static __inline BOOLEAN
 OvsIsInternalVportType(OVS_VPORT_TYPE ovsType)
 {
diff --git a/datapath-windows/ovsext/Vxlan.c b/datapath-windows/ovsext/Vxlan.c
index bf16e35..d9d8521 100644
--- a/datapath-windows/ovsext/Vxlan.c
+++ b/datapath-windows/ovsext/Vxlan.c
@@ -274,7 +274,7 @@ OvsDoEncapVxlan(PNET_BUFFER_LIST curNbl,
         /* UDP header */
         udpHdr = (UDPHdr *)((PCHAR)ipHdr + sizeof *ipHdr);
         udpHdr->source = htons(tunKey->flow_hash | 32768);
-        udpHdr->dest = VXLAN_UDP_PORT_NBO;
+        udpHdr->dest = htons(tunKey->dst_port);
         udpHdr->len = htons(NET_BUFFER_DATA_LENGTH(curNb) - headRoom +
                             sizeof *udpHdr + sizeof *vxlanHdr);
         udpHdr->check = 0;
diff --git a/datapath-windows/ovsext/Vxlan.h b/datapath-windows/ovsext/Vxlan.h
index 248a5dc..0e28304 100644
--- a/datapath-windows/ovsext/Vxlan.h
+++ b/datapath-windows/ovsext/Vxlan.h
@@ -19,7 +19,7 @@
 
 #include "NetProto.h"
 typedef struct _OVS_VXLAN_VPORT {
-    UINT32 dstPort;
+    UINT16 dstPort;
     UINT64 inPkts;
     UINT64 outPkts;
     UINT64 slowInPkts;
-- 
1.9.0.msysgit.0



More information about the dev mailing list