#include "PacketIO.h"
#include "Flow.h"
#include "PacketParser.h"
-#include "Checksum.h"
#pragma warning( push )
#pragma warning( disable:4127 )
/* Move to a header file */
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,
- POVS_VPORT_ADD_REQUEST addReq)
+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;
- ASSERT(addReq->type == OVSWIN_VPORT_TYPE_VXLAN);
-
- vxlanPort = OvsAllocateMemory(sizeof (*vxlanPort));
+ vxlanPort = OvsAllocateMemoryWithTag(sizeof (*vxlanPort),
+ OVS_VXLAN_POOL_TAG);
if (vxlanPort == NULL) {
- status = STATUS_INSUFFICIENT_RESOURCES;
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlZeroMemory(vxlanPort, sizeof(*vxlanPort));
+ vxlanPort->dstPort = udpDestPort;
+ vport->priv = (PVOID)vxlanPort;
+
+ if (!OvsIsTunnelFilterCreated(gOvsSwitchContext, udpDestPort)) {
+ status = OvsTunelFilterCreate(irp,
+ udpDestPort,
+ &vxlanPort->filterID,
+ callback,
+ tunnelContext);
} else {
- RtlZeroMemory(vxlanPort, sizeof (*vxlanPort));
- vxlanPort->dstPort = addReq->dstPort;
- /*
- * 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;
+ 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)
{
- if (vport->ovsType != OVSWIN_VPORT_TYPE_VXLAN ||
+ NTSTATUS status = STATUS_SUCCESS;
+ POVS_VXLAN_VPORT vxlanPort = NULL;
+
+ if (vport->ovsType != OVS_VPORT_TYPE_VXLAN ||
vport->priv == NULL) {
- return;
+ return STATUS_SUCCESS;
}
- OvsFreeMemory(vport->priv);
- vport->priv = NULL;
+ vxlanPort = (POVS_VXLAN_VPORT)vport->priv;
+
+ if (vxlanPort->filterID != 0) {
+ status = OvsTunelFilterDelete(irp,
+ vxlanPort->filterID,
+ callback,
+ tunnelContext);
+ } else {
+ OvsFreeMemoryWithTag(vport->priv, OVS_VXLAN_POOL_TAG);
+ vport->priv = NULL;
+ }
+
+ return status;
}
*----------------------------------------------------------------------------
*/
static __inline NDIS_STATUS
-OvsDoEncapVxlan(PNET_BUFFER_LIST curNbl,
+OvsDoEncapVxlan(POVS_VPORT_ENTRY vport,
+ PNET_BUFFER_LIST curNbl,
OvsIPv4TunnelKey *tunKey,
POVS_FWD_INFO fwdInfo,
POVS_PACKET_HDR_INFO layers,
IPHdr *ipHdr;
UDPHdr *udpHdr;
VXLANHdr *vxlanHdr;
+ POVS_VXLAN_VPORT vportVxlan;
UINT32 headRoom = OvsGetVxlanTunHdrSize();
UINT32 packetLength;
}
}
}
+
+ vportVxlan = (POVS_VXLAN_VPORT) GetOvsVportPriv(vport);
+ ASSERT(vportVxlan);
+
/* If we didn't split the packet above, make a copy now */
if (*newNbl == NULL) {
*newNbl = OvsPartialCopyNBL(switchContext, curNbl, 0, headRoom,
/* L2 header */
ethHdr = (EthHdr *)bufferStart;
- NdisMoveMemory(ethHdr->Destination, fwdInfo->dstMacAddr,
- sizeof ethHdr->Destination + sizeof ethHdr->Source);
ASSERT(((PCHAR)&fwdInfo->dstMacAddr + sizeof fwdInfo->dstMacAddr) ==
(PCHAR)&fwdInfo->srcMacAddr);
+ NdisMoveMemory(ethHdr->Destination, fwdInfo->dstMacAddr,
+ sizeof ethHdr->Destination + sizeof ethHdr->Source);
ethHdr->Type = htons(ETH_TYPE_IPV4);
// XXX: question: there are fields in the OvsIPv4TunnelKey for ttl and such,
/* UDP header */
udpHdr = (UDPHdr *)((PCHAR)ipHdr + sizeof *ipHdr);
udpHdr->source = htons(tunKey->flow_hash | 32768);
- udpHdr->dest = VXLAN_UDP_PORT_NBO;
+ udpHdr->dest = htons(vportVxlan->dstPort);
udpHdr->len = htons(NET_BUFFER_DATA_LENGTH(curNb) - headRoom +
sizeof *udpHdr + sizeof *vxlanHdr);
udpHdr->check = 0;
*----------------------------------------------------------------------------
*/
NDIS_STATUS
-OvsEncapVxlan(PNET_BUFFER_LIST curNbl,
+OvsEncapVxlan(POVS_VPORT_ENTRY vport,
+ PNET_BUFFER_LIST curNbl,
OvsIPv4TunnelKey *tunKey,
POVS_SWITCH_CONTEXT switchContext,
- VOID *completionList,
POVS_PACKET_HDR_INFO layers,
PNET_BUFFER_LIST *newNbl)
{
NTSTATUS status;
OVS_FWD_INFO fwdInfo;
- UNREFERENCED_PARAMETER(completionList);
status = OvsLookupIPFwdInfo(tunKey->dst, &fwdInfo);
if (status != STATUS_SUCCESS) {
return NDIS_STATUS_FAILURE;
}
- return OvsDoEncapVxlan(curNbl, tunKey, &fwdInfo, layers,
+ return OvsDoEncapVxlan(vport, curNbl, tunKey, &fwdInfo, layers,
switchContext, newNbl);
}
-
-/*
- *----------------------------------------------------------------------------
- * OvsIpHlprCbVxlan --
- * Callback function for IP helper.
- * XXX: not used currently
- *----------------------------------------------------------------------------
- */
-static VOID
-OvsIpHlprCbVxlan(PNET_BUFFER_LIST curNbl,
- UINT32 inPort,
- OvsIPv4TunnelKey *tunKey,
- PVOID cbData1,
- PVOID cbData2,
- NTSTATUS result,
- POVS_FWD_INFO fwdInfo)
-{
- OVS_PACKET_HDR_INFO layers;
- OvsFlowKey key;
- NDIS_STATUS status;
- UNREFERENCED_PARAMETER(inPort);
-
- status = OvsExtractFlow(curNbl, inPort, &key, &layers, NULL);
- if (result == STATUS_SUCCESS) {
- status = OvsDoEncapVxlan(curNbl, tunKey, fwdInfo, &layers,
- (POVS_SWITCH_CONTEXT)cbData1, NULL);
- } else {
- status = NDIS_STATUS_FAILURE;
- }
-
- if (status != NDIS_STATUS_SUCCESS) {
- // XXX: Free up the NBL;
- return;
- }
-
- OvsLookupFlowOutput((POVS_SWITCH_CONTEXT)cbData1, cbData2, curNbl);
-}
-
/*
*----------------------------------------------------------------------------
* OvsCalculateUDPChecksum
/*
*----------------------------------------------------------------------------
- * OvsDoDecapVxlan
+ * OvsDecapVxlan
* Decapsulates to tunnel header in 'curNbl' and puts into 'tunKey'.
*----------------------------------------------------------------------------
*/
NDIS_STATUS
-OvsDoDecapVxlan(POVS_SWITCH_CONTEXT switchContext,
- PNET_BUFFER_LIST curNbl,
- OvsIPv4TunnelKey *tunKey,
- PNET_BUFFER_LIST *newNbl)
+OvsDecapVxlan(POVS_SWITCH_CONTEXT switchContext,
+ PNET_BUFFER_LIST curNbl,
+ OvsIPv4TunnelKey *tunKey,
+ PNET_BUFFER_LIST *newNbl)
{
PNET_BUFFER curNb;
PMDL curMdl;
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,