summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--datapath-windows/automake.mk1
-rw-r--r--datapath-windows/ovsext/Actions.c206
-rw-r--r--datapath-windows/ovsext/DpInternal.h12
-rw-r--r--datapath-windows/ovsext/Ethernet.h2
-rw-r--r--datapath-windows/ovsext/Flow.c102
-rw-r--r--datapath-windows/ovsext/Mpls.h56
-rw-r--r--datapath-windows/ovsext/NetProto.h2
-rw-r--r--datapath-windows/ovsext/Netlink/Netlink.h1
-rw-r--r--datapath-windows/ovsext/PacketParser.c12
-rw-r--r--datapath-windows/ovsext/PacketParser.h7
-rw-r--r--datapath-windows/ovsext/ovsext.vcxproj1
11 files changed, 371 insertions, 31 deletions
diff --git a/datapath-windows/automake.mk b/datapath-windows/automake.mk
index 7f12d92d7..fd2221850 100644
--- a/datapath-windows/automake.mk
+++ b/datapath-windows/automake.mk
@@ -31,6 +31,7 @@ EXTRA_DIST += \
datapath-windows/ovsext/IpHelper.h \
datapath-windows/ovsext/Jhash.c \
datapath-windows/ovsext/Jhash.h \
+ datapath-windows/ovsext/Mpls.h \
datapath-windows/ovsext/NetProto.h \
datapath-windows/ovsext/Netlink/Netlink.c \
datapath-windows/ovsext/Netlink/Netlink.h \
diff --git a/datapath-windows/ovsext/Actions.c b/datapath-windows/ovsext/Actions.c
index 650658476..8e41b7455 100644
--- a/datapath-windows/ovsext/Actions.c
+++ b/datapath-windows/ovsext/Actions.c
@@ -20,6 +20,7 @@
#include "Event.h"
#include "Flow.h"
#include "Gre.h"
+#include "Mpls.h"
#include "NetProto.h"
#include "PacketIO.h"
#include "Stt.h"
@@ -1031,28 +1032,29 @@ OvsOutputBeforeSetAction(OvsForwardingContext *ovsFwdCtx)
/*
* --------------------------------------------------------------------------
- * 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 */);
@@ -1064,8 +1066,8 @@ OvsPopVlanInPktBuf(OvsForwardingContext *ovsFwdCtx)
/* 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) {
@@ -1083,16 +1085,142 @@ OvsPopVlanInPktBuf(OvsForwardingContext *ovsFwdCtx)
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*)&ethHdr);
+ 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;
}
@@ -1523,6 +1651,50 @@ OvsActionsExecute(POVS_SWITCH_CONTEXT switchContext,
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;
diff --git a/datapath-windows/ovsext/DpInternal.h b/datapath-windows/ovsext/DpInternal.h
index 466a33a48..72e9b208a 100644
--- a/datapath-windows/ovsext/DpInternal.h
+++ b/datapath-windows/ovsext/DpInternal.h
@@ -20,6 +20,7 @@
#include <netioapi.h>
#define IFNAMSIZ IF_NAMESIZE
#include "../ovsext/Netlink/Netlink.h"
+#include "Mpls.h"
#define OVS_DP_NUMBER ((uint32_t) 0)
@@ -125,7 +126,7 @@ typedef struct L2Key {
uint8_t dlDst[6]; /* Ethernet destination address. */
ovs_be16 vlanTci; /* If 802.1Q, TCI | VLAN_CFI; otherwise 0. */
ovs_be16 dlType; /* Ethernet frame type. */
-} L2Key; /* Size of 24 byte. */
+} L2Key; /* Size of 24 byte. */
/* Number of packet attributes required to store OVS tunnel key. */
#define NUM_PKT_ATTR_REQUIRED 3
@@ -147,16 +148,23 @@ typedef union OvsIPv4TunnelKey {
};
};
uint64_t attr[NUM_PKT_ATTR_REQUIRED];
-} OvsIPv4TunnelKey;
+} OvsIPv4TunnelKey; /* Size of 24 byte. */
+
+typedef struct MplsKey {
+ ovs_be32 lse; /* MPLS topmost label stack entry. */
+ uint8 pad[4];
+} MplsKey; /* Size of 8 bytes. */
typedef __declspec(align(8)) struct OvsFlowKey {
OvsIPv4TunnelKey tunKey; /* 24 bytes */
L2Key l2; /* 24 bytes */
union {
+ /* These headers are mutually exclusive. */
IpKey ipKey; /* size 16 */
ArpKey arpKey; /* size 24 */
Ipv6Key ipv6Key; /* size 48 */
Icmp6Key icmp6Key; /* size 72 */
+ MplsKey mplsKey; /* size 8 */
};
} OvsFlowKey;
diff --git a/datapath-windows/ovsext/Ethernet.h b/datapath-windows/ovsext/Ethernet.h
index 22aa27c9d..1d69d475e 100644
--- a/datapath-windows/ovsext/Ethernet.h
+++ b/datapath-windows/ovsext/Ethernet.h
@@ -66,6 +66,8 @@ typedef enum {
ETH_TYPE_CDP = 0x2000,
ETH_TYPE_802_1PQ = 0x8100, // not really a DIX type, but used as such
ETH_TYPE_LLC = 0xFFFF, // 0xFFFF is IANA reserved, used to mark LLC
+ ETH_TYPE_MPLS = 0x8847,
+ ETH_TYPE_MPLS_MCAST = 0x8848,
} Eth_DixType;
typedef enum {
diff --git a/datapath-windows/ovsext/Flow.c b/datapath-windows/ovsext/Flow.c
index 31ddc6681..a2f053542 100644
--- a/datapath-windows/ovsext/Flow.c
+++ b/datapath-windows/ovsext/Flow.c
@@ -80,6 +80,8 @@ static NTSTATUS _MapFlowIpv6KeyToNlKey(PNL_BUFFER nlBuf,
Icmp6Key *ipv6FlowPutIcmpKey);
static NTSTATUS _MapFlowArpKeyToNlKey(PNL_BUFFER nlBuf,
ArpKey *arpFlowPutKey);
+static NTSTATUS _MapFlowMplsKeyToNlKey(PNL_BUFFER nlBuf,
+ MplsKey *mplsFlowPutKey);
static NTSTATUS OvsDoDumpFlows(OvsFlowDumpInput *dumpInput,
OvsFlowDumpOutput *dumpOutput,
@@ -108,7 +110,7 @@ const NL_POLICY nlFlowPolicy[] = {
/* For Parsing nested OVS_FLOW_ATTR_KEY attributes.
* Some of the attributes like OVS_KEY_ATTR_RECIRC_ID
- * & OVS_KEY_ATTR_MPLS are not supported yet. */
+ * are not supported yet. */
const NL_POLICY nlFlowKeyPolicy[] = {
[OVS_KEY_ATTR_ENCAP] = {.type = NL_A_VAR_LEN, .optional = TRUE},
@@ -872,6 +874,13 @@ MapFlowKeyToNlKey(PNL_BUFFER nlBuf,
break;
}
+ case ETH_TYPE_MPLS:
+ case ETH_TYPE_MPLS_MCAST: {
+ MplsKey *mplsFlowPutKey = &(flowKey->mplsKey);
+ rc = _MapFlowMplsKeyToNlKey(nlBuf, mplsFlowPutKey);
+ break;
+ }
+
default:
break;
}
@@ -1194,6 +1203,31 @@ done:
/*
*----------------------------------------------------------------------------
+ * _MapFlowMplsKeyToNlKey --
+ * Maps _MapFlowMplsKeyToNlKey to OVS_KEY_ATTR_MPLS attribute.
+ *----------------------------------------------------------------------------
+ */
+static NTSTATUS
+_MapFlowMplsKeyToNlKey(PNL_BUFFER nlBuf, MplsKey *mplsFlowPutKey)
+{
+ NTSTATUS rc = STATUS_SUCCESS;
+ struct ovs_key_mpls *mplsKey;
+
+ mplsKey = (struct ovs_key_mpls *)
+ NlMsgPutTailUnspecUninit(nlBuf, OVS_KEY_ATTR_MPLS, sizeof(*mplsKey));
+ if (!mplsKey) {
+ rc = STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ mplsKey->mpls_lse = mplsFlowPutKey->lse;
+
+done:
+ return rc;
+}
+
+/*
+ *----------------------------------------------------------------------------
* _MapNlToFlowPut --
* Maps input netlink message to OvsFlowPut.
*----------------------------------------------------------------------------
@@ -1469,8 +1503,26 @@ _MapKeyAttrToFlowPut(PNL_ATTR *keyAttrs,
arpFlowPutKey->pad[1] = 0;
arpFlowPutKey->pad[2] = 0;
destKey->l2.keyLen += OVS_ARP_KEY_SIZE;
- break;
}
+ break;
+ }
+ case ETH_TYPE_MPLS:
+ case ETH_TYPE_MPLS_MCAST: {
+
+ if (keyAttrs[OVS_KEY_ATTR_MPLS]) {
+ MplsKey *mplsFlowPutKey = &destKey->mplsKey;
+ const struct ovs_key_mpls *mplsKey;
+
+ mplsKey = NlAttrGet(keyAttrs[OVS_KEY_ATTR_MPLS]);
+
+ mplsFlowPutKey->lse = mplsKey->mpls_lse;
+ mplsFlowPutKey->pad[0] = 0;
+ mplsFlowPutKey->pad[1] = 0;
+ mplsFlowPutKey->pad[2] = 0;
+ mplsFlowPutKey->pad[3] = 0;
+ destKey->l2.keyLen += sizeof(MplsKey);
+ }
+ break;
}
}
}
@@ -1734,10 +1786,10 @@ OvsExtractFlow(const NET_BUFFER_LIST *packet,
flow->l2.vlanTci = 0;
}
/*
- * XXX
- * Please note after this point, src mac and dst mac should
- * not be accessed through eth
- */
+ * XXX
+ * Please note after this point, src mac and dst mac should
+ * not be accessed through eth
+ */
eth = (Eth_Header *)((UINT8 *)eth + offset);
}
@@ -1868,6 +1920,44 @@ OvsExtractFlow(const NET_BUFFER_LIST *packet,
memcpy(arpKey->arpTha, arp->arp_tha, ETH_ADDR_LENGTH);
}
}
+ } else if (OvsEthertypeIsMpls(flow->l2.dlType)) {
+ MPLSHdr mplsStorage;
+ const MPLSHdr *mpls;
+ MplsKey *mplsKey = &flow->mplsKey;
+ ((UINT64 *)mplsKey)[0] = 0;
+
+ /*
+ * In the presence of an MPLS label stack the end of the L2
+ * header and the beginning of the L3 header differ.
+ *
+ * A network packet may contain multiple MPLS labels, but we
+ * are only interested in the topmost label stack entry.
+ *
+ * Advance network header to the beginning of the L3 header.
+ * layers->l3Offset corresponds to the end of the L2 header.
+ */
+ for (UINT32 i = 0; i < FLOW_MAX_MPLS_LABELS; i++) {
+ mpls = OvsGetMpls(packet, layers->l3Offset, &mplsStorage);
+ if (!mpls) {
+ break;
+ }
+
+ /* Keep only the topmost MPLS label stack entry. */
+ if (i == 0) {
+ mplsKey->lse = mpls->lse;
+ }
+
+ layers->l3Offset += MPLS_HLEN;
+ layers->l4Offset += MPLS_HLEN;
+
+ if (mpls->lse & htonl(MPLS_BOS_MASK)) {
+ /*
+ * Bottom of Stack bit is set, which means there are no
+ * remaining MPLS labels in the packet.
+ */
+ break;
+ }
+ }
}
return NDIS_STATUS_SUCCESS;
diff --git a/datapath-windows/ovsext/Mpls.h b/datapath-windows/ovsext/Mpls.h
new file mode 100644
index 000000000..6e53e46db
--- /dev/null
+++ b/datapath-windows/ovsext/Mpls.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2015 Cloudbase Solutions Srl
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MPLS_H_
+#define __MPLS_H_ 1
+
+#include "precomp.h"
+#include "Ethernet.h"
+
+/*
+ * MPLS definitions
+ */
+#define FLOW_MAX_MPLS_LABELS 3
+
+#define MPLS_HLEN 4
+#define MPLS_BOS_MASK 0x00000100
+
+/* Reference: RFC 5462, RFC 3032
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Label | TC |S| TTL |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * Label: Label Value, 20 bits
+ * TC: Traffic Class field, 3 bits
+ * S: Bottom of Stack, 1 bit
+ * TTL: Time to Live, 8 bits
+ */
+
+typedef struct MPLSHdr {
+ ovs_be32 lse;
+} MPLSHdr;
+
+__inline BOOLEAN
+OvsEthertypeIsMpls(ovs_be16 ethertype)
+{
+ return ethertype == htons(ETH_TYPE_MPLS) ||
+ ethertype == htons(ETH_TYPE_MPLS_MCAST);
+}
+
+#endif /* __MPLS_H_ */
diff --git a/datapath-windows/ovsext/NetProto.h b/datapath-windows/ovsext/NetProto.h
index e93501666..c18135c53 100644
--- a/datapath-windows/ovsext/NetProto.h
+++ b/datapath-windows/ovsext/NetProto.h
@@ -19,7 +19,9 @@
#include "precomp.h"
#include "Ethernet.h"
+#include "Mpls.h"
+#define ETH_HEADER_LENGTH 14
#define ETH_ADDR_LENGTH 6
/*
* There is a more inclusive definition of ethernet header (Eth_Header) in
diff --git a/datapath-windows/ovsext/Netlink/Netlink.h b/datapath-windows/ovsext/Netlink/Netlink.h
index d27073731..99665fb92 100644
--- a/datapath-windows/ovsext/Netlink/Netlink.h
+++ b/datapath-windows/ovsext/Netlink/Netlink.h
@@ -123,6 +123,7 @@ const PVOID NlAttrGet(const PNL_ATTR nla);
const PVOID NlAttrGetUnspec(const PNL_ATTR nla, UINT32 size);
BE64 NlAttrGetBe64(const PNL_ATTR nla);
BE32 NlAttrGetBe32(const PNL_ATTR nla);
+BE16 NlAttrGetBe16(const PNL_ATTR nla);
UINT8 NlAttrGetU8(const PNL_ATTR nla);
UINT16 NlAttrGetU16(const PNL_ATTR nla);
UINT32 NlAttrGetU32(const PNL_ATTR nla);
diff --git a/datapath-windows/ovsext/PacketParser.c b/datapath-windows/ovsext/PacketParser.c
index bba2631b7..bd6910c6d 100644
--- a/datapath-windows/ovsext/PacketParser.c
+++ b/datapath-windows/ovsext/PacketParser.c
@@ -84,8 +84,8 @@ OvsGetPacketBytes(const NET_BUFFER_LIST *nbl,
NDIS_STATUS
OvsParseIPv6(const NET_BUFFER_LIST *packet,
- OvsFlowKey *key,
- POVS_PACKET_HDR_INFO layers)
+ OvsFlowKey *key,
+ POVS_PACKET_HDR_INFO layers)
{
UINT16 ofs = layers->l3Offset;
IPv6Hdr ipv6HdrStorage;
@@ -178,8 +178,8 @@ OvsParseIPv6(const NET_BUFFER_LIST *packet,
VOID
OvsParseTcp(const NET_BUFFER_LIST *packet,
- L4Key *flow,
- POVS_PACKET_HDR_INFO layers)
+ L4Key *flow,
+ POVS_PACKET_HDR_INFO layers)
{
TCPHdr tcpStorage;
const TCPHdr *tcp = OvsGetTcp(packet, layers->l4Offset, &tcpStorage);
@@ -208,8 +208,8 @@ OvsParseSctp(const NET_BUFFER_LIST *packet,
VOID
OvsParseUdp(const NET_BUFFER_LIST *packet,
- L4Key *flow,
- POVS_PACKET_HDR_INFO layers)
+ L4Key *flow,
+ POVS_PACKET_HDR_INFO layers)
{
UDPHdr udpStorage;
const UDPHdr *udp = OvsGetUdp(packet, layers->l4Offset, &udpStorage);
diff --git a/datapath-windows/ovsext/PacketParser.h b/datapath-windows/ovsext/PacketParser.h
index 7b8e656ed..47d227f59 100644
--- a/datapath-windows/ovsext/PacketParser.h
+++ b/datapath-windows/ovsext/PacketParser.h
@@ -151,4 +151,11 @@ OvsGetIcmp(const NET_BUFFER_LIST *packet,
return OvsGetPacketBytes(packet, sizeof *storage, ofs, storage);
}
+static const MPLSHdr *
+OvsGetMpls(const NET_BUFFER_LIST *packet,
+ UINT32 ofs,
+ MPLSHdr *storage)
+{
+ return OvsGetPacketBytes(packet, sizeof *storage, ofs, storage);
+}
#endif /* __PACKET_PARSER_H_ */
diff --git a/datapath-windows/ovsext/ovsext.vcxproj b/datapath-windows/ovsext/ovsext.vcxproj
index 231ac83b7..fd10809dd 100644
--- a/datapath-windows/ovsext/ovsext.vcxproj
+++ b/datapath-windows/ovsext/ovsext.vcxproj
@@ -83,6 +83,7 @@
<ClInclude Include="Gre.h" />
<ClInclude Include="IpHelper.h" />
<ClInclude Include="Jhash.h" />
+ <ClInclude Include="Mpls.h" />
<ClInclude Include="Netlink/Netlink.h" />
<ClInclude Include="Netlink/NetlinkBuf.h" />
<ClInclude Include="Netlink/NetlinkProto.h" />