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

Sorin Vinturis svinturis at cloudbasesolutions.com
Thu Nov 19 12:31:46 UTC 2015


Hi Sai,

I manage to test the MPLS patch using a Devstack machine on which I have installed OVS. I had also added flows to push up to 3 MPLS labels on the network packets and then ping a Hyper-V machine, which had installed the custom extension containing the MPLS support.

Regarding your review comments, please see my answers inline.

Thanks for your review,
-Sorin

-----Original Message-----
From: Sairam Venugopal [mailto:vsairam at vmware.com] 
Sent: Thursday, 19 November, 2015 00:35
To: Sorin Vinturis; dev at openvswitch.org
Subject: Re: [ovs-dev] [PATCH] datapath-windows: Support for OVS_KEY_ATTR_MPLS attribute

Hey Sorin,

Were you able to test out the changes? Can you clarify how we can reproduce it? It will be nice to have documentation around testing this since it¹s a new feature. I remember you having difficulties with testing this earlier, hopefully that is now resolved.

I took a look at your changes and have mentioned my comments inline.

Thanks,
Sairam

On 11/11/15, 12:11 PM, "Sorin Vinturis" <svinturis at cloudbasesolutions.com>
wrote:

>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;
> }

I think we should move the MPLS-Push and POP functions to a separate file mpls.h/mpls.c to keep Actions.c limited to what it does.
SV: Currently all actions related functions are kept in Actions.c. I don't think we need to separate MPLS functionality yet, as there are
not many features related to MPLS besides push and pop.

> 
>+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);
>+
>+    newNbl = OvsPartialCopyNBL(ovsFwdCtx->switchContext,
>ovsFwdCtx->curNbl,
>+                               MPLS_HLEN, 0, 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->mpls_lse = mpls->mpls_lse;
>+
>+    layers->l3Offset += MPLS_HLEN;
>+    layers->isIPv4 = 0;
>+    layers->isIPv6 = 0;
>+

Should we introduce an isMpls label in OVS_PACKET_HDR_INFO to identify this?
SV: There is no current need to have such a flag.

>+    NdisRetreatNetBufferDataStart(curNb, MPLS_HLEN, FALSE, NULL);
>+
>+    return NDIS_STATUS_SUCCESS;
>+}
>+

This function seems like a copy of OvsPopVlanInPktBuf(OvsForwardingContext
*ovsFwdCtx)
except for the shiftLength/MPLS_HLEN. You can have 1 function that takes in the length instead.
SV: Sure. Will do that.

>+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
>+ */
>+

Can¹t you simply define the structure with the respective bits that are used instead of the mask and shift?
You can name it lse instead of redundant mpls_lse.
SV: I can do that, sure.

>+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_mai
>lma 
>n_listinfo_dev&d=BQIGaQ&c=Sqcl0Ez6M0X8aeM67LKIiDJAXVeAw-YihVMNtXt-uEs&r
>=Dc 
>ruz40PROJ40ROzSpxyQSLw6fcrOWpJgEcEmNR3JEQ&m=4jij1GpaBzb8M2GdcLn47dOarUO
>1na f-2Is_kWuRby4&s=XYH34q49hUVRrnPrL3HqLDdPj3AJPM0N_ab6JxhriJk&e=




More information about the dev mailing list