[ovs-dev] [PATCH] datapath-windows: Support for OVS_KEY_ATTR_MPLS attribute

Nithin Raju nithin at vmware.com
Tue Dec 8 01:02:56 UTC 2015


Hi Sorin,
I found some bugs in OvsActionMplsPush(). Can you pls. clarify if my
comments are valid? If they are genuine bugs, did your testing not catch
them? Apologies, if I missed anything.

I¹ll review the rest of the patch after the claritification.

Thanks,
-- Nithin

-----Original Message-----
From: dev <dev-bounces at openvswitch.org> on behalf of Sorin Vinturis
<svinturis at cloudbasesolutions.com>
Date: Wednesday, November 11, 2015 at 12:11 PM
To: "dev at openvswitch.org" <dev at openvswitch.org>
Subject: [ovs-dev] [PATCH] datapath-windows: Support for
OVS_KEY_ATTR_MPLS	attribute

>This patch adds OVS_KEY_ATTR_MPLS to the OVS flow mechanism.
>
>Signed-off-by: Sorin Vinturis <svinturis at cloudbasesolutions.com>
>---
> datapath-windows/ovsext/Actions.c      | 176
>+++++++++++++++++++++++++++++++++
> datapath-windows/ovsext/DpInternal.h   |   7 ++
> datapath-windows/ovsext/Ethernet.h     |   2 +
> datapath-windows/ovsext/Flow.c         |  89 ++++++++++++++++-
> datapath-windows/ovsext/NetProto.h     |  33 +++++++
> datapath-windows/ovsext/PacketParser.c |  12 +--
> datapath-windows/ovsext/PacketParser.h |   7 ++
> 7 files changed, 318 insertions(+), 8 deletions(-)
>
>diff --git a/datapath-windows/ovsext/Actions.c
>b/datapath-windows/ovsext/Actions.c
>index ce592b3..9ee1763 100644
>--- a/datapath-windows/ovsext/Actions.c
>+++ b/datapath-windows/ovsext/Actions.c
>@@ -1074,6 +1074,142 @@ OvsPopVlanInPktBuf(OvsForwardingContext
>*ovsFwdCtx)
>     return NDIS_STATUS_SUCCESS;
> }
> 
>+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;
>+    UINT32 packetLen = 0;
>+    PNET_BUFFER_LIST newNbl;
>+
>+    curNb = NET_BUFFER_LIST_FIRST_NB(ovsFwdCtx->curNbl);
>+    ASSERT(curNb->Next == NULL);
>+    packetLen = NET_BUFFER_DATA_LENGTH(curNb);
>+    curMdl = NET_BUFFER_CURRENT_MDL(curNb);
>+    NdisQueryMdl(curMdl, &bufferStart, &mdlLen, LowPagePriority);
>+    if (!bufferStart) {
>+        ovsActionStats.noResource++;
>+        return NDIS_STATUS_RESOURCES;
>+    }
>+    curMdlOffset = NET_BUFFER_CURRENT_MDL_OFFSET(curNb);
>+    mdlLen -= curMdlOffset;
>+    mdlLen -= NET_BUFFER_CURRENT_MDL_OFFSET(curNb);
>+    ASSERT(mdlLen > 0);
>+    /* Bail out if the L2 header is not in a contiguous buffer. */
>+    if (MIN(packetLen, mdlLen) < sizeof *ethHdr) {
>+        ASSERT(FALSE);
>+        return NDIS_STATUS_FAILURE;
>+    }
>+    ASSERT((INT)mdlLen >= 0);

You don¹t need any of these checks if the NBL is going to be copied
anyway. These checks are needed if you are going to modify the packet
inline. Look at OvsUpdateIPv4Header() for correct usage.

>+
>+    newNbl = OvsPartialCopyNBL(ovsFwdCtx->switchContext,
>ovsFwdCtx->curNbl,
>+                               MPLS_HLEN, 0, TRUE /*copy NBL info*/);

What is the intention of this partial copy? Are you trying to allocate
more headroom or creating a copy so as to update the L2 header?

You probably want to do:
newNbl = OvsPartialCopyNBL(ovsFwdCtx->switchContext, ovsFwdCtx->curNbl,
                           L2 Header size + MPLS_HLEN, MPLS_HLEN, TRUE
/*copy NBL info*/);


>+    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);
>+    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);
>+    ethHdr->Type = mpls->mpls_ethertype;
>+
>+    mplsHdr = (MPLSHdr *)(bufferStart + curMdlOffset + MPLS_HLEN);

mplsHdr should be at: (void *)ethHdr + MPLS_HLEN.

>+    mplsHdr->mpls_lse = mpls->mpls_lse;

As I understood, the packet was like:
ETH + IP

The new NBL just after the partial copy looks like:
HEADROOM (4B) + ETH + IP

You want this to look like:
ETH + MPLS + IP

You need to left shift the Eth header, including the source and
destination MAC addresses. Only the ethtype seems to be updated. Nothing
more.

>+
>+    layers->l3Offset += MPLS_HLEN;
>+    layers->isIPv4 = 0;
>+    layers->isIPv6 = 0;

Should we be resetting layers->isIpv4 and isIPv6 to 0? The inner packet is
still intact, right?

>+
>+    NdisRetreatNetBufferDataStart(curNb, MPLS_HLEN, FALSE, NULL);
>+
>+    return NDIS_STATUS_SUCCESS;
>+}
>+
>+static __inline NDIS_STATUS
>+OvsActionMplsPop(OvsForwardingContext *ovsFwdCtx)
>+{
>+    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[sizeof (DL_EUI48) + sizeof (DL_EUI48)];
>+
>+    newNbl = OvsPartialCopyNBL(ovsFwdCtx->switchContext,
>ovsFwdCtx->curNbl,
>+                               0, 0, TRUE /* copy NBL info */);
>+    if (!newNbl) {
>+        ovsActionStats.noCopiedNbl++;
>+        return NDIS_STATUS_RESOURCES;
>+    }
>+
>+    /* 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,
>+                 
>NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(newNbl),
>+                                  NULL, &ovsFwdCtx->layers, FALSE);
>+    if (status != NDIS_STATUS_SUCCESS) {
>+        OvsCompleteNBLForwardingCtx(ovsFwdCtx,
>+                                    L"Dropped due to resouces");
>+        return NDIS_STATUS_RESOURCES;
>+    }
>+
>+    curNb = NET_BUFFER_LIST_FIRST_NB(ovsFwdCtx->curNbl);
>+    packetLen = NET_BUFFER_DATA_LENGTH(curNb);
>+    ASSERT(curNb->Next == NULL);
>+    curMdl = NET_BUFFER_CURRENT_MDL(curNb);
>+    NdisQueryMdl(curMdl, &bufferStart, &mdlLen, LowPagePriority);
>+    if (!bufferStart) {
>+        return NDIS_STATUS_RESOURCES;
>+    }
>+    mdlLen -= NET_BUFFER_CURRENT_MDL_OFFSET(curNb);
>+    /* Bail out if L2 + MPLS header is not contiguous in the first
>buffer. */
>+    if (MIN(packetLen, mdlLen) < sizeof(EthHdr) + MPLS_HLEN) {
>+        ASSERT(FALSE);
>+        return NDIS_STATUS_FAILURE;
>+    }
>+    bufferStart += NET_BUFFER_CURRENT_MDL_OFFSET(curNb);
>+    RtlCopyMemory(tempBuffer, bufferStart, dataLength);
>+    RtlCopyMemory(bufferStart + MPLS_HLEN, tempBuffer, dataLength);
>+    NdisAdvanceNetBufferDataStart(curNb, MPLS_HLEN, FALSE, NULL);
>+
>+    return NDIS_STATUS_SUCCESS;
>+}
>+
> /*
>  * 
>--------------------------------------------------------------------------
>  * OvsTunnelAttrToIPv4TunnelKey --
>@@ -1513,6 +1649,46 @@ 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-set push MPLS failed";
>+                goto dropit;
>+            }
>+            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);
>+            if (status != NDIS_STATUS_SUCCESS) {
>+                dropReason = L"OVS-set pop MPLS failed";
>+                goto dropit;
>+            }
>+            break;
>+        }
>+
>         case OVS_ACTION_ATTR_USERSPACE:
>         {
>             PNL_ATTR userdataAttr;
>diff --git a/datapath-windows/ovsext/DpInternal.h
>b/datapath-windows/ovsext/DpInternal.h
>index 8de48a2..c195494 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 "NetProto.h"
> 
> #define OVS_DP_NUMBER   ((uint32_t) 0)
> 
>@@ -149,6 +150,11 @@ typedef union OvsIPv4TunnelKey {
>     uint64_t attr[NUM_PKT_ATTR_REQUIRED];
> } OvsIPv4TunnelKey;
> 
>+typedef struct MplsKey {
>+    ovs_be32 top_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 */
>@@ -157,6 +163,7 @@ typedef __declspec(align(8)) struct OvsFlowKey {
>         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 22aa27c..1d69d47 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 b629c93..c989c14 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->top_lse;
>+
>+done:
>+    return rc;
>+}
>+
>+/*
>+ 
>*-------------------------------------------------------------------------
>---
>  *  _MapNlToFlowPut --
>  *    Maps input netlink message to OvsFlowPut.
>  
>*-------------------------------------------------------------------------
>---
>@@ -1469,8 +1503,28 @@ _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;
>+            UINT32 size = NlAttrGetSize(keyAttrs[OVS_KEY_ATTR_MPLS]);
>+            UINT32 n = size / sizeof(struct ovs_key_mpls);
>+
>+            mplsKey = NlAttrGet(keyAttrs[OVS_KEY_ATTR_MPLS]);
>+
>+            mplsFlowPutKey->top_lse = mplsKey->mpls_lse;
>+            mplsFlowPutKey->pad[0] = 0;
>+            mplsFlowPutKey->pad[1] = 0;
>+            mplsFlowPutKey->pad[2] = 0;
>+            mplsFlowPutKey->pad[3] = 0;
>+            destKey->l2.keyLen += (UINT16)n * sizeof(MplsKey);
>+        }
>+        break;
>     }
>     }
> }
>@@ -1864,6 +1918,37 @@ OvsExtractFlow(const NET_BUFFER_LIST *packet,
>                 memcpy(arpKey->arpTha, arp->arp_tha, ETH_ADDR_LENGTH);
>             }
>         }
>+    } else if (flow->l2.dlType == htons(ETH_TYPE_MPLS) ||
>+               flow->l2.dlType == htons(ETH_TYPE_MPLS_MCAST)) {
>+        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) {
>+
>+                /* Keep only the topmost MPLS label stack entry. */
>+                if (i == 0) {
>+                    mplsKey->top_lse = mpls->mpls_lse;
>+                }
>+
>+                layers->l3Offset += sizeof(MPLSHdr);
>+
>+                if (mpls->mpls_lse & htonl(MPLS_LS_S_MASK))
>+                    break;
>+            }
>+        }
>     }
> 
>     return NDIS_STATUS_SUCCESS;
>diff --git a/datapath-windows/ovsext/NetProto.h
>b/datapath-windows/ovsext/NetProto.h
>index a364869..12e8bd9 100644
>--- a/datapath-windows/ovsext/NetProto.h
>+++ b/datapath-windows/ovsext/NetProto.h
>@@ -366,4 +366,37 @@ typedef struct IPOpt {
> #define SOCKET_IPPROTO_UDP   17
> #define SOCKET_IPPROTO_GRE   47
> 
>+/* 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 mpls_lse;
>+} MPLSHdr;
>+
>+/*
>+ * MPLS definitions
>+ */
>+#define MPLS_HLEN               4
>+#define FLOW_MAX_MPLS_LABELS    3
>+#define MPLS_LS_LABEL_MASK      0xFFFFF000
>+#define MPLS_LS_LABEL_SHIFT     12
>+#define MPLS_LS_TC_MASK         0x00000E00
>+#define MPLS_LS_TC_SHIFT        9
>+#define MPLS_LS_S_MASK          0x00000100
>+#define MPLS_LS_S_SHIFT         8
>+#define MPLS_LS_TTL_MASK        0x000000FF
>+#define MPLS_LS_TTL_SHIFT       0
>+
>+
> #endif /* __NET_PROTO_H_ */
>diff --git a/datapath-windows/ovsext/PacketParser.c
>b/datapath-windows/ovsext/PacketParser.c
>index e01be17..246c603 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);
>@@ -193,8 +193,8 @@ OvsParseTcp(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 55d110f..96136b7 100644
>--- a/datapath-windows/ovsext/PacketParser.h
>+++ b/datapath-windows/ovsext/PacketParser.h
>@@ -141,4 +141,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_ */
>-- 
>1.9.0.msysgit.0
>_______________________________________________
>dev mailing list
>dev at openvswitch.org
>https://urldefense.proofpoint.com/v2/url?u=http-3A__openvswitch.org_mailma
>n_listinfo_dev&d=BQIGaQ&c=Sqcl0Ez6M0X8aeM67LKIiDJAXVeAw-YihVMNtXt-uEs&r=pN
>HQcdr7B40b4h6Yb7FIedI1dnBsxdDuTLBYD3JqV80&m=nTWi1YZmmSTMCtjYpqMkthOFY5xBca
>i4dNH_JYc9kKs&s=h1Rf2WEWL_eMR1TjEUbBPzkw7OEWRVhCukH_1uWl9NY&e= 




More information about the dev mailing list