diff options
author | Sorin Vinturis <svinturis@cloudbasesolutions.com> | 2015-05-27 16:58:25 +0000 |
---|---|---|
committer | Ben Pfaff <blp@nicira.com> | 2015-05-27 12:36:27 -0700 |
commit | 5e82ceefd12dfcb954da48d027b47d98dc53676a (patch) | |
tree | a13059a1a95de2ffb35b8bd94783cee4338ad484 /datapath-windows/ovsext/Vxlan.c | |
parent | b6ec827fe0edb5478ac0f580eaa0597b1166a0fb (diff) | |
download | openvswitch-5e82ceefd12dfcb954da48d027b47d98dc53676a.tar.gz |
datapath-windows: Support for custom VXLAN tunnel port
The kernel datapath supports only port 4789 for VXLAN tunnel creation.
Added support in order to allow for the VXLAN tunnel port to be
configurable to any port number set by the userspace.
The patch also checks to see if an existing WFP filter, for the
necessary UDP tunnel port, is already created before adding a new one.
This is a double check, because currently the userspace also verifies
this, but it is necessary to avoid future issues.
Custom VXLAN tunnel port requires the addition of a new WFP filter
with the new UDP tunnel port. The creation of a new WFP filter is
triggered in OvsInitVxlanTunnel function and the removal of the WFP
filter in OvsCleanupVxlanTunnel function.
But the latter functions are running at IRQL = DISPATCH_LEVEL, due
to the NDIS RW lock acquisition, and all WFP calls must be running at
IRQL = PASSIVE_LEVEL. This is why I have created a system thread which
records all filter addition/removal requests into a list for later
processing by the system thread. The ThreadStart routine processes all
received requests at IRQL = PASSIVE_LEVEL, which is the required IRQL
for the necessary WFP calls for adding/removal of the WFP filters.
The WFP filter for the default VXLAN port 4789 is not added anymore at
filter attach. All WFP filters for the tunnel ports are added when the
tunnel ports are initialized and are removed at cleanup. WFP operation
status is then reported to userspace.
It is necessary that OvsTunnelFilterUninitialize function is called
after OvsClearAllSwitchVports in order to allow for the added WFP
filters to be removed. OvsTunnelFilterUninitialize function closes the
global engine handle used by most of the WFP calls, including filter
removal.
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/66
Acked-by: Nithin Raju <nithin@vmware.com>
Signed-off-by: Ben Pfaff <blp@nicira.com>
Diffstat (limited to 'datapath-windows/ovsext/Vxlan.c')
-rw-r--r-- | datapath-windows/ovsext/Vxlan.c | 102 |
1 files changed, 85 insertions, 17 deletions
diff --git a/datapath-windows/ovsext/Vxlan.c b/datapath-windows/ovsext/Vxlan.c index 8c5718506..9d4266544 100644 --- a/datapath-windows/ovsext/Vxlan.c +++ b/datapath-windows/ovsext/Vxlan.c @@ -50,14 +50,57 @@ extern POVS_SWITCH_CONTEXT gOvsSwitchContext; /* + *---------------------------------------------------------------------------- + * This function verifies if the VXLAN tunnel already exists, in order to + * avoid sending a duplicate request to the WFP base filtering engine. + *---------------------------------------------------------------------------- + */ +static BOOLEAN +OvsIsTunnelFilterCreated(POVS_SWITCH_CONTEXT switchContext, + UINT16 udpPortDest) +{ + 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 = NULL; + POVS_VXLAN_VPORT vxlanPort = NULL; + vport = CONTAINING_RECORD(link, OVS_VPORT_ENTRY, portNoLink); + vxlanPort = (POVS_VXLAN_VPORT)vport->priv; + if (vxlanPort) { + if ((udpPortDest == vxlanPort->dstPort)) { + /* The VXLAN tunnel was already created. */ + return TRUE; + } + } + } + } + + return FALSE; +} + +/* + *---------------------------------------------------------------------------- + * This function allocates and initializes the OVS_VXLAN_VPORT. The function + * also creates a WFP tunnel filter for the necessary destination port. The + * tunnel filter create request is passed to the tunnel filter threads that + * will complete the request at a later time when IRQL is lowered to + * PASSIVE_LEVEL. + * * udpDestPort: the vxlan is set as payload to a udp frame. If the destination * port of an udp frame is udpDestPort, we understand it to be vxlan. + *---------------------------------------------------------------------------- */ NTSTATUS -OvsInitVxlanTunnel(POVS_VPORT_ENTRY vport, - UINT16 udpDestPort) +OvsInitVxlanTunnel(PIRP irp, + POVS_VPORT_ENTRY vport, + UINT16 udpDestPort, + PFNTunnelVportPendingOp callback, + PVOID tunnelContext) { - POVS_VXLAN_VPORT vxlanPort; + NTSTATUS status = STATUS_SUCCESS; + POVS_VXLAN_VPORT vxlanPort = NULL; vxlanPort = OvsAllocateMemoryWithTag(sizeof (*vxlanPort), OVS_VXLAN_POOL_TAG); @@ -67,28 +110,56 @@ OvsInitVxlanTunnel(POVS_VPORT_ENTRY vport, RtlZeroMemory(vxlanPort, sizeof(*vxlanPort)); vxlanPort->dstPort = udpDestPort; - /* - * since we are installing the WFP filter before the port is created - * We need to check if it is the same number - * XXX should be removed later - */ - ASSERT(vxlanPort->dstPort == VXLAN_UDP_PORT); vport->priv = (PVOID)vxlanPort; - return STATUS_SUCCESS; -} + if (!OvsIsTunnelFilterCreated(gOvsSwitchContext, udpDestPort)) { + status = OvsTunelFilterCreate(irp, + udpDestPort, + &vxlanPort->filterID, + callback, + tunnelContext); + } else { + status = STATUS_OBJECT_NAME_EXISTS; + } + return status; +} -VOID -OvsCleanupVxlanTunnel(POVS_VPORT_ENTRY vport) +/* + *---------------------------------------------------------------------------- + * This function releases the OVS_VXLAN_VPORT. The function also deletes the + * WFP tunnel filter previously created. The tunnel filter delete request is + * passed to the tunnel filter threads that will complete the request at a + * later time when IRQL is lowered to PASSIVE_LEVEL. + *---------------------------------------------------------------------------- + */ +NTSTATUS +OvsCleanupVxlanTunnel(PIRP irp, + POVS_VPORT_ENTRY vport, + PFNTunnelVportPendingOp callback, + PVOID tunnelContext) { + NTSTATUS status = STATUS_SUCCESS; + POVS_VXLAN_VPORT vxlanPort = NULL; + if (vport->ovsType != OVS_VPORT_TYPE_VXLAN || vport->priv == NULL) { - return; + return STATUS_SUCCESS; + } + + vxlanPort = (POVS_VXLAN_VPORT)vport->priv; + + if (vxlanPort->filterID != 0) { + status = OvsTunelFilterDelete(irp, + vxlanPort->filterID, + callback, + tunnelContext); } OvsFreeMemoryWithTag(vport->priv, OVS_VXLAN_POOL_TAG); vport->priv = NULL; + + return status; } @@ -475,9 +546,6 @@ OvsSlowPathDecapVxlan(const PNET_BUFFER_LIST packet, break; } - /* XXX Should be tested against the dynamic port # in the VXLAN vport */ - ASSERT(udp->dest == RtlUshortByteSwap(VXLAN_UDP_PORT)); - VxlanHeader = (VXLANHdr *)OvsGetPacketBytes(packet, sizeof(*VxlanHeader), layers.l7Offset, |