/*
- * Copyright (c) 2014 VMware, Inc.
+ * Copyright (c) 2014, 2016 VMware, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include "precomp.h"
-#include "Switch.h"
-#include "Vport.h"
+#include "Debug.h"
#include "Event.h"
-#include "User.h"
-#include "NetProto.h"
#include "Flow.h"
-#include "Vxlan.h"
-#include "Checksum.h"
+#include "Gre.h"
+#include "Mpls.h"
+#include "NetProto.h"
+#include "Offload.h"
#include "PacketIO.h"
+#include "Stt.h"
+#include "Switch.h"
+#include "User.h"
+#include "Vport.h"
+#include "Vxlan.h"
#ifdef OVS_DBG_MOD
#undef OVS_DBG_MOD
#endif
#define OVS_DBG_MOD OVS_DBG_ACTION
-#include "Debug.h"
typedef struct _OVS_ACTION_STATS {
+ UINT64 rxGre;
+ UINT64 txGre;
UINT64 rxVxlan;
UINT64 txVxlan;
+ UINT64 rxStt;
+ UINT64 txStt;
UINT64 flowMiss;
UINT64 flowUserspace;
UINT64 txTcp;
/* XXX: we should also check for the length of the UDP payload to pick
* 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++;
+ if (!flowKey->ipKey.nwFrag) {
+ UINT16 dstPort = htons(flowKey->ipKey.l4.tpDst);
+ switch (flowKey->ipKey.nwProto) {
+ case IPPROTO_GRE:
+ tunnelVport = OvsFindTunnelVportByPortType(ovsFwdCtx->switchContext,
+ OVS_VPORT_TYPE_GRE);
+ if (tunnelVport) {
+ ovsActionStats.rxGre++;
+ }
+ break;
+ case IPPROTO_TCP:
+ tunnelVport = OvsFindTunnelVportByDstPort(ovsFwdCtx->switchContext,
+ dstPort,
+ OVS_VPORT_TYPE_STT);
+ if (tunnelVport) {
+ ovsActionStats.rxStt++;
+ }
+ break;
+ case IPPROTO_UDP:
+ tunnelVport = OvsFindTunnelVportByDstPort(ovsFwdCtx->switchContext,
+ dstPort,
+ OVS_VPORT_TYPE_VXLAN);
+ if (tunnelVport) {
+ ovsActionStats.rxVxlan++;
+ }
+ break;
+ }
}
// We might get tunnel packets even before the tunnel gets initialized.
* port or if it is being executed from userspace, the source port is
* default port.
*/
- BOOLEAN validSrcPort = (ovsFwdCtx->fwdDetail->SourcePortId ==
- ovsFwdCtx->switchContext->externalPortId) ||
- (ovsFwdCtx->fwdDetail->SourcePortId ==
- NDIS_SWITCH_DEFAULT_PORT_ID);
+ BOOLEAN validSrcPort =
+ (ovsFwdCtx->fwdDetail->SourcePortId ==
+ ovsFwdCtx->switchContext->virtualExternalPortId) ||
+ (ovsFwdCtx->fwdDetail->SourcePortId ==
+ NDIS_SWITCH_DEFAULT_PORT_ID);
if (validSrcPort && OvsDetectTunnelRxPkt(ovsFwdCtx, flowKey)) {
ASSERT(ovsFwdCtx->tunnelTxNic == NULL);
/*
* Tx:
* The destination port is a tunnel port. Encapsulation must be
- * performed only on packets that originate from a VIF port or from
- * userspace (default port)
+ * performed only on packets that originate from:
+ * - a VIF port
+ * - a bridge-internal port (packets generated from userspace)
+ * - no port.
*
* If the packet will not be encapsulated, consume the tunnel context
* by clearing it.
*/
- if (ovsFwdCtx->srcVportNo != OVS_DEFAULT_PORT_NO) {
+ if (ovsFwdCtx->srcVportNo != OVS_DPPORT_NUMBER_INVALID) {
POVS_VPORT_ENTRY vport = OvsFindVportByPortNo(
ovsFwdCtx->switchContext, ovsFwdCtx->srcVportNo);
- if (!vport || vport->ovsType != OVS_VPORT_TYPE_NETDEV) {
+ if (!vport ||
+ (vport->ovsType != OVS_VPORT_TYPE_NETDEV &&
+ !OvsIsBridgeInternalVport(vport))) {
ovsFwdCtx->tunKey.dst = 0;
}
}
/* Tunnel the packet only if tunnel context is set. */
if (ovsFwdCtx->tunKey.dst != 0) {
- ovsActionStats.txVxlan++;
+ switch(dstVport->ovsType) {
+ case OVS_VPORT_TYPE_GRE:
+ ovsActionStats.txGre++;
+ break;
+ case OVS_VPORT_TYPE_VXLAN:
+ ovsActionStats.txVxlan++;
+ break;
+ case OVS_VPORT_TYPE_STT:
+ ovsActionStats.txStt++;
+ break;
+ }
ovsFwdCtx->tunnelTxNic = dstVport;
}
vport->stats.txBytes +=
NET_BUFFER_DATA_LENGTH(NET_BUFFER_LIST_FIRST_NB(ovsFwdCtx->curNbl));
+ if (OvsIsBridgeInternalVport(vport)) {
+ return NDIS_STATUS_SUCCESS;
+ }
+
if (OvsDetectTunnelPkt(ovsFwdCtx, vport, flowKey)) {
return NDIS_STATUS_SUCCESS;
}
POVS_VPORT_ENTRY vport =
OvsFindVportByPortNo(ovsFwdCtx->switchContext, ovsFwdCtx->srcVportNo);
if (vport == NULL || vport->ovsState != OVS_STATE_CONNECTED) {
- ASSERT(FALSE); // XXX: let's catch this for now
OvsCompleteNBLForwardingCtx(ovsFwdCtx,
L"OVS-Dropped due to internal/tunnel port removal");
ovsActionStats.noVport++;
/* Assert that in the Rx direction, key is always setup. */
ASSERT(ovsFwdCtx->tunnelRxNic == NULL || ovsFwdCtx->tunKey.dst != 0);
- status = OvsExtractFlow(ovsFwdCtx->curNbl, ovsFwdCtx->srcVportNo,
- &key, &ovsFwdCtx->layers, ovsFwdCtx->tunKey.dst != 0 ?
- &ovsFwdCtx->tunKey : NULL);
+ status =
+ OvsExtractFlow(ovsFwdCtx->curNbl, ovsFwdCtx->srcVportNo,
+ &key, &ovsFwdCtx->layers,
+ ovsFwdCtx->tunKey.dst != 0 ? &ovsFwdCtx->tunKey : NULL);
if (status != NDIS_STATUS_SUCCESS) {
OvsCompleteNBLForwardingCtx(ovsFwdCtx,
L"OVS-Flow extract failed");
OvsFlowUsed(flow, ovsFwdCtx->curNbl, &ovsFwdCtx->layers);
ovsFwdCtx->switchContext->datapath.hits++;
status = OvsActionsExecute(ovsFwdCtx->switchContext,
- ovsFwdCtx->completionList, ovsFwdCtx->curNbl,
- ovsFwdCtx->srcVportNo, ovsFwdCtx->sendFlags,
- &key, &hash, &ovsFwdCtx->layers,
- flow->actions, flow->actionsLen);
+ ovsFwdCtx->completionList, ovsFwdCtx->curNbl,
+ ovsFwdCtx->srcVportNo, ovsFwdCtx->sendFlags,
+ &key, &hash, &ovsFwdCtx->layers,
+ flow->actions, flow->actionsLen);
ovsFwdCtx->curNbl = NULL;
} else {
LIST_ENTRY missedPackets;
UINT32 num = 0;
ovsFwdCtx->switchContext->datapath.misses++;
InitializeListHead(&missedPackets);
- status = OvsCreateAndAddPackets(NULL, 0, OVS_PACKET_CMD_MISS,
- ovsFwdCtx->srcVportNo,
+ status = OvsCreateAndAddPackets(NULL, 0, OVS_PACKET_CMD_MISS, vport,
&key,ovsFwdCtx->curNbl,
- ovsFwdCtx->tunnelRxNic != NULL, &ovsFwdCtx->layers,
+ FALSE, &ovsFwdCtx->layers,
ovsFwdCtx->switchContext, &missedPackets, &num);
if (num) {
- OvsQueuePackets(OVS_DEFAULT_PACKET_QUEUE, &missedPackets, num);
+ OvsQueuePackets(&missedPackets, num);
}
if (status == NDIS_STATUS_SUCCESS) {
/* Complete the packet since it was copied to user buffer. */
* Setup the source port to be the internal port to as to facilitate the
* second OvsLookupFlow.
*/
- if (ovsFwdCtx->switchContext->internalVport == NULL) {
+ if (ovsFwdCtx->switchContext->internalVport == NULL ||
+ ovsFwdCtx->switchContext->virtualExternalVport == NULL) {
OvsClearTunTxCtx(ovsFwdCtx);
OvsCompleteNBLForwardingCtx(ovsFwdCtx,
- L"OVS-Dropped since internal port is absent");
+ L"OVS-Dropped since either internal or external port is absent");
return NDIS_STATUS_FAILURE;
}
ovsFwdCtx->srcVportNo =
/* Do the encap. Encap function does not consume the NBL. */
switch(ovsFwdCtx->tunnelTxNic->ovsType) {
+ case OVS_VPORT_TYPE_GRE:
+ status = OvsEncapGre(ovsFwdCtx->tunnelTxNic, ovsFwdCtx->curNbl,
+ &ovsFwdCtx->tunKey, ovsFwdCtx->switchContext,
+ &ovsFwdCtx->layers, &newNbl);
+ break;
case OVS_VPORT_TYPE_VXLAN:
- status = OvsEncapVxlan(ovsFwdCtx->curNbl, &ovsFwdCtx->tunKey,
- ovsFwdCtx->switchContext,
- (VOID *)ovsFwdCtx->completionList,
+ status = OvsEncapVxlan(ovsFwdCtx->tunnelTxNic, ovsFwdCtx->curNbl,
+ &ovsFwdCtx->tunKey, ovsFwdCtx->switchContext,
&ovsFwdCtx->layers, &newNbl);
break;
+ case OVS_VPORT_TYPE_STT:
+ status = OvsEncapStt(ovsFwdCtx->tunnelTxNic, ovsFwdCtx->curNbl,
+ &ovsFwdCtx->tunKey, ovsFwdCtx->switchContext,
+ &ovsFwdCtx->layers, &newNbl);
+ break;
default:
ASSERT(! "Tx: Unhandled tunnel type");
}
NDIS_STATUS status = NDIS_STATUS_SUCCESS;
PNET_BUFFER_LIST newNbl = NULL;
POVS_VPORT_ENTRY tunnelRxVport = ovsFwdCtx->tunnelRxNic;
+ PCWSTR dropReason = L"OVS-dropped due to new decap packet";
if (OvsValidateIPChecksum(ovsFwdCtx->curNbl, &ovsFwdCtx->layers)
!= NDIS_STATUS_SUCCESS) {
goto dropNbl;
}
+ /*
+ * Decap port functions should return a new NBL if it was copied, and
+ * this new NBL should be setup as the ovsFwdCtx->curNbl.
+ */
+
switch(tunnelRxVport->ovsType) {
+ case OVS_VPORT_TYPE_GRE:
+ status = OvsDecapGre(ovsFwdCtx->switchContext, ovsFwdCtx->curNbl,
+ &ovsFwdCtx->tunKey, &newNbl);
+ break;
case OVS_VPORT_TYPE_VXLAN:
- /*
- * OvsDoDecapVxlan should return a new NBL if it was copied, and
- * this new NBL should be setup as the ovsFwdCtx->curNbl.
- */
- status = OvsDoDecapVxlan(ovsFwdCtx->switchContext, ovsFwdCtx->curNbl,
- &ovsFwdCtx->tunKey, &newNbl);
+ status = OvsDecapVxlan(ovsFwdCtx->switchContext, ovsFwdCtx->curNbl,
+ &ovsFwdCtx->tunKey, &newNbl);
+ break;
+ case OVS_VPORT_TYPE_STT:
+ status = OvsDecapStt(ovsFwdCtx->switchContext, ovsFwdCtx->curNbl,
+ &ovsFwdCtx->tunKey, &newNbl);
+ if (status == NDIS_STATUS_SUCCESS && newNbl == NULL) {
+ /* This was an STT-LSO Fragment */
+ dropReason = L"OVS-STT segment is cached";
+ }
break;
default:
OVS_LOG_ERROR("Rx: Unhandled tunnel type: %d\n",
* tunnelRxNic and other fields will be cleared, re-init the context
* before usage.
*/
- OvsCompleteNBLForwardingCtx(ovsFwdCtx,
- L"OVS-dropped due to new decap packet");
+ OvsCompleteNBLForwardingCtx(ovsFwdCtx, dropReason);
- /* Decapsulated packet is in a new NBL */
- ovsFwdCtx->tunnelRxNic = tunnelRxVport;
- OvsInitForwardingCtx(ovsFwdCtx, ovsFwdCtx->switchContext,
- newNbl, tunnelRxVport->portNo, 0,
- NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(newNbl),
- ovsFwdCtx->completionList,
- &ovsFwdCtx->layers, FALSE);
+ if (newNbl) {
+ /* Decapsulated packet is in a new NBL */
+ ovsFwdCtx->tunnelRxNic = tunnelRxVport;
+ OvsInitForwardingCtx(ovsFwdCtx, ovsFwdCtx->switchContext,
+ newNbl, tunnelRxVport->portNo, 0,
+ NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(newNbl),
+ ovsFwdCtx->completionList,
+ &ovsFwdCtx->layers, FALSE);
- /*
- * Set the NBL's SourcePortId and SourceNicIndex to default values to
- * keep NDIS happy when we forward the packet.
- */
- ovsFwdCtx->fwdDetail->SourcePortId = NDIS_SWITCH_DEFAULT_PORT_ID;
- ovsFwdCtx->fwdDetail->SourceNicIndex = 0;
+ /*
+ * Set the NBL's SourcePortId and SourceNicIndex to default values to
+ * keep NDIS happy when we forward the packet.
+ */
+ ovsFwdCtx->fwdDetail->SourcePortId = NDIS_SWITCH_DEFAULT_PORT_ID;
+ ovsFwdCtx->fwdDetail->SourceNicIndex = 0;
- status = OvsDoFlowLookupOutput(ovsFwdCtx);
+ status = OvsDoFlowLookupOutput(ovsFwdCtx);
+ }
ASSERT(ovsFwdCtx->curNbl == NULL);
OvsClearTunRxCtx(ovsFwdCtx);
{
NDIS_STATUS status = STATUS_SUCCESS;
POVS_SWITCH_CONTEXT switchContext = ovsFwdCtx->switchContext;
+ PCWSTR dropReason;
/*
* Handle the case where the some of the destination ports are tunneled
if (newNbl == NULL) {
status = NDIS_STATUS_RESOURCES;
ovsActionStats.noCopiedNbl++;
+ dropReason = L"Dropped due to failure to create NBL copy.";
goto dropit;
}
}
if (status != NDIS_STATUS_SUCCESS) {
OvsCompleteNBL(ovsFwdCtx->switchContext, newNbl, TRUE);
ovsActionStats.cannotGrowDest++;
+ dropReason = L"Dropped due to failure to update destinations.";
goto dropit;
}
ovsFwdCtx->completionList,
&ovsFwdCtx->layers, FALSE);
if (status != NDIS_STATUS_SUCCESS) {
- OvsCompleteNBLForwardingCtx(ovsFwdCtx,
- L"Dropped due to resouces");
+ dropReason = L"Dropped due to resouces.";
goto dropit;
}
}
dropit:
if (status != NDIS_STATUS_SUCCESS) {
- OvsCompleteNBLForwardingCtx(ovsFwdCtx, L"Dropped due to XXX");
+ OvsCompleteNBLForwardingCtx(ovsFwdCtx, dropReason);
}
return status;
{
PNET_BUFFER_LIST newNbl;
NDIS_STATUS status = NDIS_STATUS_SUCCESS;
- PNET_BUFFER nb;
/*
* Create a copy and work on the copy after this point. The original NBL is
* XXX Head room needs to include the additional encap.
* XXX copySize check is not considering multiple NBs.
*/
- nb = NET_BUFFER_LIST_FIRST_NB(ovsFwdCtx->curNbl);
newNbl = OvsPartialCopyNBL(ovsFwdCtx->switchContext, ovsFwdCtx->curNbl,
0, 0, TRUE /*copy NBL info*/);
ASSERT(ovsFwdCtx->destPortsSizeOut > 0 ||
ovsFwdCtx->tunnelTxNic != NULL || ovsFwdCtx->tunnelRxNic != NULL);
- /* Send the original packet out */
+ /* Send the original packet out and save the original source port number */
+ UINT32 tempVportNo = ovsFwdCtx->srcVportNo;
status = OvsOutputForwardingCtx(ovsFwdCtx);
ASSERT(ovsFwdCtx->curNbl == NULL);
ASSERT(ovsFwdCtx->destPortsSizeOut == 0);
OvsCompleteNBL(ovsFwdCtx->switchContext, newNbl, TRUE);
} else {
status = OvsInitForwardingCtx(ovsFwdCtx, ovsFwdCtx->switchContext,
- newNbl, ovsFwdCtx->srcVportNo, 0,
+ newNbl, tempVportNo, 0,
NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(newNbl),
ovsFwdCtx->completionList,
&ovsFwdCtx->layers, FALSE);
/*
* --------------------------------------------------------------------------
- * OvsPopVlanInPktBuf --
- * Function to pop a VLAN tag when the tag is in the packet buffer.
+ * OvsPopFieldInPacketBuf --
+ * Function to pop a specified field of length 'shiftLength' located at
+ * 'shiftOffset' from the ethernet header. The data on the left of the
+ * 'shiftOffset' is right shifted.
+ *
+ * Returns a pointer to the new start in 'bufferData'.
* --------------------------------------------------------------------------
*/
static __inline NDIS_STATUS
-OvsPopVlanInPktBuf(OvsForwardingContext *ovsFwdCtx)
+OvsPopFieldInPacketBuf(OvsForwardingContext *ovsFwdCtx,
+ UINT32 shiftOffset,
+ UINT32 shiftLength,
+ PUINT8 *bufferData)
{
PNET_BUFFER curNb;
PMDL curMdl;
PUINT8 bufferStart;
- ULONG dataLength = sizeof (DL_EUI48) + sizeof (DL_EUI48);
UINT32 packetLen, mdlLen;
PNET_BUFFER_LIST newNbl;
NDIS_STATUS status;
+ PUINT8 tempBuffer[ETH_HEADER_LENGTH];
- /*
- * Declare a dummy vlanTag structure since we need to compute the size
- * of shiftLength. The NDIS one is a unionized structure.
- */
- NDIS_PACKET_8021Q_INFO vlanTag = {0};
- ULONG shiftLength = sizeof (vlanTag.TagHeader);
- PUINT8 tempBuffer[sizeof (DL_EUI48) + sizeof (DL_EUI48)];
+ ASSERT(shiftOffset > ETH_ADDR_LENGTH);
newNbl = OvsPartialCopyNBL(ovsFwdCtx->switchContext, ovsFwdCtx->curNbl,
0, 0, TRUE /* copy NBL info */);
/* Complete the original NBL and create a copy to modify. */
OvsCompleteNBLForwardingCtx(ovsFwdCtx, L"OVS-Dropped due to copy");
- status = OvsInitForwardingCtx(ovsFwdCtx, ovsFwdCtx->switchContext,
- newNbl, ovsFwdCtx->srcVportNo, 0,
+ status = OvsInitForwardingCtx(ovsFwdCtx, ovsFwdCtx->switchContext, newNbl,
+ ovsFwdCtx->srcVportNo, 0,
NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(newNbl),
NULL, &ovsFwdCtx->layers, FALSE);
if (status != NDIS_STATUS_SUCCESS) {
return NDIS_STATUS_RESOURCES;
}
mdlLen -= NET_BUFFER_CURRENT_MDL_OFFSET(curNb);
- /* Bail out if L2 + VLAN header is not contiguous in the first buffer. */
- if (MIN(packetLen, mdlLen) < sizeof (EthHdr) + shiftLength) {
+ /* Bail out if L2 + shiftLength is not contiguous in the first buffer. */
+ if (MIN(packetLen, mdlLen) < sizeof(EthHdr) + shiftLength) {
ASSERT(FALSE);
return NDIS_STATUS_FAILURE;
}
bufferStart += NET_BUFFER_CURRENT_MDL_OFFSET(curNb);
- RtlCopyMemory(tempBuffer, bufferStart, dataLength);
- RtlCopyMemory(bufferStart + shiftLength, tempBuffer, dataLength);
+ RtlCopyMemory(tempBuffer, bufferStart, shiftOffset);
+ RtlCopyMemory(bufferStart + shiftLength, tempBuffer, shiftOffset);
NdisAdvanceNetBufferDataStart(curNb, shiftLength, FALSE, NULL);
+ if (bufferData) {
+ *bufferData = bufferStart + shiftLength;
+ }
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+/*
+ * --------------------------------------------------------------------------
+ * OvsPopVlanInPktBuf --
+ * Function to pop a VLAN tag when the tag is in the packet buffer.
+ * --------------------------------------------------------------------------
+ */
+static __inline NDIS_STATUS
+OvsPopVlanInPktBuf(OvsForwardingContext *ovsFwdCtx)
+{
+ /*
+ * Declare a dummy vlanTag structure since we need to compute the size
+ * of shiftLength. The NDIS one is a unionized structure.
+ */
+ NDIS_PACKET_8021Q_INFO vlanTag = {0};
+ UINT32 shiftLength = sizeof(vlanTag.TagHeader);
+ UINT32 shiftOffset = sizeof(DL_EUI48) + sizeof(DL_EUI48);
+
+ return OvsPopFieldInPacketBuf(ovsFwdCtx, shiftOffset, shiftLength, NULL);
+}
+
+
+/*
+ * --------------------------------------------------------------------------
+ * OvsActionMplsPop --
+ * Function to pop the first MPLS label from the current packet.
+ * --------------------------------------------------------------------------
+ */
+static __inline NDIS_STATUS
+OvsActionMplsPop(OvsForwardingContext *ovsFwdCtx,
+ ovs_be16 ethertype)
+{
+ NDIS_STATUS status = NDIS_STATUS_SUCCESS;
+ OVS_PACKET_HDR_INFO *layers = &ovsFwdCtx->layers;
+ EthHdr *ethHdr = NULL;
+
+ status = OvsPopFieldInPacketBuf(ovsFwdCtx, sizeof(*ethHdr),
+ MPLS_HLEN, (PUINT8*)ðHdr);
+ if (status == NDIS_STATUS_SUCCESS) {
+ if (ethHdr && OvsEthertypeIsMpls(ethHdr->Type)) {
+ ethHdr->Type = ethertype;
+ }
+
+ layers->l3Offset -= MPLS_HLEN;
+ layers->l4Offset -= MPLS_HLEN;
+ }
+
+ return status;
+}
+
+
+/*
+ * --------------------------------------------------------------------------
+ * OvsActionMplsPush --
+ * Function to push the MPLS label into the current packet.
+ * --------------------------------------------------------------------------
+ */
+static __inline NDIS_STATUS
+OvsActionMplsPush(OvsForwardingContext *ovsFwdCtx,
+ const struct ovs_action_push_mpls *mpls)
+{
+ NDIS_STATUS status;
+ PNET_BUFFER curNb = NULL;
+ PMDL curMdl = NULL;
+ PUINT8 bufferStart = NULL;
+ OVS_PACKET_HDR_INFO *layers = &ovsFwdCtx->layers;
+ EthHdr *ethHdr = NULL;
+ MPLSHdr *mplsHdr = NULL;
+ UINT32 mdlLen = 0, curMdlOffset = 0;
+ PNET_BUFFER_LIST newNbl;
+
+ newNbl = OvsPartialCopyNBL(ovsFwdCtx->switchContext, ovsFwdCtx->curNbl,
+ layers->l3Offset, MPLS_HLEN, TRUE);
+ if (!newNbl) {
+ ovsActionStats.noCopiedNbl++;
+ return NDIS_STATUS_RESOURCES;
+ }
+ OvsCompleteNBLForwardingCtx(ovsFwdCtx,
+ L"Complete after partial copy.");
+
+ status = OvsInitForwardingCtx(ovsFwdCtx, ovsFwdCtx->switchContext,
+ newNbl, ovsFwdCtx->srcVportNo, 0,
+ NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(newNbl),
+ NULL, &ovsFwdCtx->layers, FALSE);
+ if (status != NDIS_STATUS_SUCCESS) {
+ OvsCompleteNBLForwardingCtx(ovsFwdCtx,
+ L"OVS-Dropped due to resources");
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ curNb = NET_BUFFER_LIST_FIRST_NB(ovsFwdCtx->curNbl);
+ ASSERT(curNb->Next == NULL);
+
+ status = NdisRetreatNetBufferDataStart(curNb, MPLS_HLEN, 0, NULL);
+ if (status != NDIS_STATUS_SUCCESS) {
+ return status;
+ }
+
+ curMdl = NET_BUFFER_CURRENT_MDL(curNb);
+ NdisQueryMdl(curMdl, &bufferStart, &mdlLen, LowPagePriority);
+ if (!curMdl) {
+ ovsActionStats.noResource++;
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ curMdlOffset = NET_BUFFER_CURRENT_MDL_OFFSET(curNb);
+ mdlLen -= curMdlOffset;
+ ASSERT(mdlLen >= MPLS_HLEN);
+
+ ethHdr = (EthHdr *)(bufferStart + curMdlOffset);
+ RtlMoveMemory(ethHdr, (UINT8*)ethHdr + MPLS_HLEN, sizeof(*ethHdr));
+ ethHdr->Type = mpls->mpls_ethertype;
+
+ mplsHdr = (MPLSHdr *)(ethHdr + 1);
+ mplsHdr->lse = mpls->mpls_lse;
+
+ layers->l3Offset += MPLS_HLEN;
+ layers->l4Offset += MPLS_HLEN;
+
return NDIS_STATUS_SUCCESS;
}
case OVS_KEY_ATTR_TUNNEL:
{
OvsIPv4TunnelKey tunKey;
-
- status = OvsTunnelAttrToIPv4TunnelKey((PNL_ATTR)a, &tunKey);
+ 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;
}
- case OVS_KEY_ATTR_SKB_MARK:
- /* XXX: Not relevant to Hyper-V. Return OK */
- break;
- case OVS_KEY_ATTR_UNSPEC:
- case OVS_KEY_ATTR_ENCAP:
- case OVS_KEY_ATTR_ETHERTYPE:
- case OVS_KEY_ATTR_IN_PORT:
- case OVS_KEY_ATTR_VLAN:
- case OVS_KEY_ATTR_ICMP:
- case OVS_KEY_ATTR_ICMPV6:
- case OVS_KEY_ATTR_ARP:
- case OVS_KEY_ATTR_ND:
- case __OVS_KEY_ATTR_MAX:
+
default:
- OVS_LOG_INFO("Unhandled attribute %#x", type);
- ASSERT(FALSE);
+ OVS_LOG_INFO("Unhandled attribute %#x", type);
+ break;
}
return status;
}
break;
}
+ case OVS_ACTION_ATTR_PUSH_MPLS:
+ {
+ if (ovsFwdCtx.destPortsSizeOut > 0 || ovsFwdCtx.tunnelTxNic != NULL
+ || ovsFwdCtx.tunnelRxNic != NULL) {
+ status = OvsOutputBeforeSetAction(&ovsFwdCtx);
+ if (status != NDIS_STATUS_SUCCESS) {
+ dropReason = L"OVS-adding destination failed";
+ goto dropit;
+ }
+ }
+
+ status = OvsActionMplsPush(&ovsFwdCtx,
+ (struct ovs_action_push_mpls *)NlAttrGet
+ ((const PNL_ATTR)a));
+ if (status != NDIS_STATUS_SUCCESS) {
+ dropReason = L"OVS-push MPLS action failed";
+ goto dropit;
+ }
+ layers->l3Offset += MPLS_HLEN;
+ layers->l4Offset += MPLS_HLEN;
+ break;
+ }
+
+ case OVS_ACTION_ATTR_POP_MPLS:
+ {
+ if (ovsFwdCtx.destPortsSizeOut > 0 || ovsFwdCtx.tunnelTxNic != NULL
+ || ovsFwdCtx.tunnelRxNic != NULL) {
+ status = OvsOutputBeforeSetAction(&ovsFwdCtx);
+ if (status != NDIS_STATUS_SUCCESS) {
+ dropReason = L"OVS-adding destination failed";
+ goto dropit;
+ }
+ }
+
+ status = OvsActionMplsPop(&ovsFwdCtx, NlAttrGetBe16(a));
+ if (status != NDIS_STATUS_SUCCESS) {
+ dropReason = L"OVS-pop MPLS action failed";
+ goto dropit;
+ }
+ layers->l3Offset -= MPLS_HLEN;
+ layers->l4Offset -= MPLS_HLEN;
+ break;
+ }
+
case OVS_ACTION_ATTR_USERSPACE:
{
PNL_ATTR userdataAttr;
elem = OvsCreateQueueNlPacket((PVOID)userdataAttr,
userdataAttr->nlaLen,
OVS_PACKET_CMD_ACTION,
- portNo, key,ovsFwdCtx.curNbl,
+ vport, key, ovsFwdCtx.curNbl,
NET_BUFFER_LIST_FIRST_NB(ovsFwdCtx.curNbl),
isRecv,
layers);
LIST_ENTRY missedPackets;
InitializeListHead(&missedPackets);
InsertTailList(&missedPackets, &elem->link);
- OvsQueuePackets(OVS_DEFAULT_PACKET_QUEUE, &missedPackets, 1);
+ OvsQueuePackets(&missedPackets, 1);
dropReason = L"OVS-Completed since packet was copied to "
L"userspace";
} else {