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@cloudbasesolutions.com>
Reported-by: Alin Gabriel Serdean <aserdean@cloudbasesolutions.com>
Reported-at: https://github.com/openvswitch/ovs-issues/issues/64
Acked-by: Eitan Eliahu <eliahue@vmware.com>
Acked-by: Nithin Raju <nithin@vmware.com>
Signed-off-by: Ben Pfaff <blp@nicira.com>
+ * 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.
* --------------------------------------------------------------------------
* OvsDetectTunnelRxPkt --
* Utility function for an RX packet to detect its tunnel type.
* packets only if they are at least VXLAN header size.
*/
if (!flowKey->ipKey.nwFrag &&
* 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;
}
// We might get tunnel packets even before the tunnel gets initialized.
if (tunnelVport) {
ASSERT(ovsFwdCtx->tunnelRxNic == NULL);
ovsFwdCtx->tunnelRxNic = tunnelVport;
+ ovsActionStats.rxVxlan++;
status = OvsTunnelAttrToIPv4TunnelKey((PNL_ATTR)a, &tunKey);
ASSERT(status == NDIS_STATUS_SUCCESS);
tunKey.flow_hash = (uint16)(hash ? *hash : OvsHashFlow(key));
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;
RtlCopyMemory(&ovsFwdCtx->tunKey, &tunKey, sizeof ovsFwdCtx->tunKey);
break;
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);
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) {
status = OvsAllocateFlowTable(&switchContext->datapath, switchContext);
if (status == NDIS_STATUS_SUCCESS) {
switchContext->portNoHashArray == NULL ||
switchContext->ovsPortNameHashArray == NULL ||
switchContext->portIdHashArray== NULL ||
switchContext->portNoHashArray == NULL ||
switchContext->ovsPortNameHashArray == NULL ||
switchContext->portIdHashArray== NULL ||
- switchContext->pidHashArray == NULL) {
+ switchContext->pidHashArray == NULL ||
+ switchContext->tunnelVportsArray == NULL) {
if (switchContext->dispatchLock) {
NdisFreeRWLock(switchContext->dispatchLock);
}
if (switchContext->dispatchLock) {
NdisFreeRWLock(switchContext->dispatchLock);
}
+ if (switchContext->tunnelVportsArray) {
+ OvsFreeMemory(switchContext->tunnelVportsArray);
+ }
+
OvsDeleteFlowTable(&switchContext->datapath);
OvsCleanupBufferPool(switchContext);
OvsDeleteFlowTable(&switchContext->datapath);
OvsCleanupBufferPool(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->ovsPortNameHashArray[i]);
- }
- for (i = 0; i < OVS_MAX_VPORT_ARRAY_SIZE; i++) {
InitializeListHead(&switchContext->portIdHashArray[i]);
InitializeListHead(&switchContext->portIdHashArray[i]);
- }
- for (i = 0; i < OVS_MAX_VPORT_ARRAY_SIZE; i++) {
InitializeListHead(&switchContext->portNoHashArray[i]);
InitializeListHead(&switchContext->portNoHashArray[i]);
+ InitializeListHead(&switchContext->tunnelVportsArray[i]);
}
for (i = 0; i < OVS_MAX_PID_ARRAY_SIZE; i++) {
}
for (i = 0; i < OVS_MAX_PID_ARRAY_SIZE; i++) {
OvsFreeMemoryWithTag(switchContext->pidHashArray,
OVS_SWITCH_POOL_TAG);
switchContext->pidHashArray = NULL;
OvsFreeMemoryWithTag(switchContext->pidHashArray,
OVS_SWITCH_POOL_TAG);
switchContext->pidHashArray = NULL;
+ OvsFreeMemory(switchContext->tunnelVportsArray);
+ switchContext->tunnelVportsArray = NULL;
OvsDeleteFlowTable(&switchContext->datapath);
OvsCleanupBufferPool(switchContext);
OvsDeleteFlowTable(&switchContext->datapath);
OvsCleanupBufferPool(switchContext);
POVS_VPORT_ENTRY virtualExternalVport; // the virtual adapter vport
POVS_VPORT_ENTRY internalVport;
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.
/*
* 'portIdHashArray' ONLY contains ports that exist on the Hyper-V switch,
* namely: VIF (vNIC) ports, external port and Hyper-V internal port.
* exist on the Hyper-V switch, and 'numNonHvVports' counts such ports in
* 'portNoHashArray'.
*
* 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
* '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
PLIST_ENTRY ovsPortNameHashArray; // based on ovsName
PLIST_ENTRY pidHashArray; // based on packet pids
NDIS_SPIN_LOCK pidHashLock; // Lock for pidHash table
SendFlags |= NDIS_SEND_FLAGS_DISPATCH_LEVEL;
SendFlags |= NDIS_SEND_FLAGS_DISPATCH_LEVEL;
- vport = gOvsSwitchContext->vxlanVport;
+ vport = OvsFindTunnelVportByDstPort(gOvsSwitchContext,
+ htons(tunnelKey.dst_port));
if (vport == NULL){
status = STATUS_UNSUCCESSFUL;
if (vport == NULL){
status = STATUS_UNSUCCESSFUL;
+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)
POVS_VPORT_ENTRY
OvsFindVportByOvsName(POVS_SWITCH_CONTEXT switchContext,
PSTR name)
* --------------------------------------------------------------------------
* Functionality common to any port added from OVS userspace.
*
* --------------------------------------------------------------------------
* 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
* --------------------------------------------------------------------------
*/
NDIS_STATUS
switch(vport->ovsType) {
case OVS_VPORT_TYPE_VXLAN:
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;
switchContext->numNonHvVports++;
break;
case OVS_VPORT_TYPE_INTERNAL:
if (vport->isBridgeInternal) {
switchContext->numNonHvVports++;
case OVS_VPORT_TYPE_INTERNAL:
if (vport->isBridgeInternal) {
switchContext->numNonHvVports++;
InitializeListHead(&vport->ovsNameLink);
RemoveEntryList(&vport->portNoLink);
InitializeListHead(&vport->portNoLink);
InitializeListHead(&vport->ovsNameLink);
RemoveEntryList(&vport->portNoLink);
InitializeListHead(&vport->portNoLink);
+ if (OVS_VPORT_TYPE_VXLAN == vport->ovsType) {
+ RemoveEntryList(&vport->tunnelVportLink);
+ InitializeListHead(&vport->tunnelVportLink);
+ }
+
vport,
OvsTunnelVportPendingUninit,
tunnelContext);
vport,
OvsTunnelVportPendingUninit,
tunnelContext);
-
- switchContext->vxlanVport = NULL;
break;
}
case OVS_VPORT_TYPE_GRE:
break;
}
case OVS_VPORT_TYPE_GRE:
OvsRemoveAndDeleteVport(NULL, switchContext, vport, TRUE, TRUE);
}
}
OvsRemoveAndDeleteVport(NULL, switchContext, vport, TRUE, TRUE);
}
}
/*
* Remove 'virtualExternalVport' as well. This port is not part of the
* 'portIdHashArray'.
/*
* Remove 'virtualExternalVport' as well. This port is not part of the
* 'portIdHashArray'.
(POVS_VPORT_ENTRY)switchContext->virtualExternalVport, TRUE, TRUE);
}
(POVS_VPORT_ENTRY)switchContext->virtualExternalVport, TRUE, TRUE);
}
for (UINT hash = 0; hash < OVS_MAX_VPORT_ARRAY_SIZE; hash++) {
PLIST_ENTRY head, link, next;
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;
head = &(switchContext->portNoHashArray[hash & OVS_VPORT_MASK]);
LIST_FORALL_SAFE(head, link, next) {
POVS_VPORT_ENTRY vport;
ASSERT(switchContext->virtualExternalVport == NULL);
ASSERT(switchContext->internalVport == NULL);
ASSERT(switchContext->virtualExternalVport == NULL);
ASSERT(switchContext->internalVport == NULL);
- ASSERT(switchContext->vxlanVport == NULL);
LIST_ENTRY ovsNameLink;
LIST_ENTRY portIdLink;
LIST_ENTRY portNoLink;
LIST_ENTRY ovsNameLink;
LIST_ENTRY portIdLink;
LIST_ENTRY portNoLink;
+ LIST_ENTRY tunnelVportLink;
OVS_VPORT_STATE ovsState;
OVS_VPORT_TYPE ovsType;
OVS_VPORT_STATE ovsState;
OVS_VPORT_TYPE ovsType;
struct _OVS_SWITCH_CONTEXT;
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);
/* "name" is null-terminated */
POVS_VPORT_ENTRY OvsFindVportByOvsName(POVS_SWITCH_CONTEXT switchContext,
PSTR name);
POVS_VPORT_ENTRY OvsFindVportByPortIdAndNicIndex(POVS_SWITCH_CONTEXT switchContext,
NDIS_SWITCH_PORT_ID portId,
NDIS_SWITCH_NIC_INDEX index);
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);
NDIS_STATUS OvsAddConfiguredSwitchPorts(struct _OVS_SWITCH_CONTEXT *switchContext);
NDIS_STATUS OvsInitConfiguredSwitchNics(struct _OVS_SWITCH_CONTEXT *switchContext);
ovsType == OVS_VPORT_TYPE_GRE64;
}
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)
{
static __inline BOOLEAN
OvsIsInternalVportType(OVS_VPORT_TYPE ovsType)
{
/* UDP header */
udpHdr = (UDPHdr *)((PCHAR)ipHdr + sizeof *ipHdr);
udpHdr->source = htons(tunKey->flow_hash | 32768);
/* 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;
udpHdr->len = htons(NET_BUFFER_DATA_LENGTH(curNb) - headRoom +
sizeof *udpHdr + sizeof *vxlanHdr);
udpHdr->check = 0;
#include "NetProto.h"
typedef struct _OVS_VXLAN_VPORT {
#include "NetProto.h"
typedef struct _OVS_VXLAN_VPORT {
UINT64 inPkts;
UINT64 outPkts;
UINT64 slowInPkts;
UINT64 inPkts;
UINT64 outPkts;
UINT64 slowInPkts;