#include "precomp.h"
-#include "Switch.h"
-#include "Vport.h"
+#include "Checksum.h"
#include "Event.h"
-#include "User.h"
-#include "NetProto.h"
#include "Flow.h"
-#include "Vxlan.h"
-#include "Checksum.h"
+#include "Gre.h"
+#include "NetProto.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
#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.
* 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);
/* 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;
}
/* 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(&missedPackets, num);
* 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);
{
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);
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;
}
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);