datapath-windows: Fix small bug in MPLS
[cascardo/ovs.git] / datapath-windows / ovsext / Flow.c
index d3de8cc..5eec513 100644 (file)
@@ -31,7 +31,6 @@
 #pragma warning( push )
 #pragma warning( disable:4127 )
 
-extern PNDIS_SPIN_LOCK gOvsCtrlLock;
 extern POVS_SWITCH_CONTEXT gOvsSwitchContext;
 extern UINT64 ovsTimeIncrementPerTick;
 
@@ -81,10 +80,14 @@ 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,
                                UINT32 *replyLen);
+static NTSTATUS OvsProbeSupportedFeature(POVS_MESSAGE msgIn,
+                                         PNL_ATTR keyAttr);
 
 
 #define OVS_FLOW_TABLE_SIZE 2048
@@ -103,12 +106,13 @@ const NL_POLICY nlFlowPolicy[] = {
                              .maxLen = sizeof(struct ovs_flow_stats),
                              .optional = TRUE},
     [OVS_FLOW_ATTR_TCP_FLAGS] = {NL_A_U8, .optional = TRUE},
-    [OVS_FLOW_ATTR_USED] = {NL_A_U64, .optional = TRUE}
+    [OVS_FLOW_ATTR_USED] = {NL_A_U64, .optional = TRUE},
+    [OVS_FLOW_ATTR_PROBE] = {.type = NL_A_FLAG, .optional = TRUE}
 };
 
 /* 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},
@@ -172,6 +176,7 @@ const NL_POLICY nlFlowKeyPolicy[] = {
                                 .maxLen = 4, .optional = TRUE},
     [OVS_KEY_ATTR_MPLS] = {.type = NL_A_VAR_LEN, .optional = TRUE}
 };
+const UINT32 nlFlowKeyPolicyLen = ARRAY_SIZE(nlFlowKeyPolicy);
 
 /* For Parsing nested OVS_KEY_ATTR_TUNNEL attributes */
 const NL_POLICY nlFlowTunnelKeyPolicy[] = {
@@ -253,7 +258,7 @@ OvsFlowNlCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
     PNL_MSG_HDR nlMsgHdr = &(msgIn->nlMsg);
     PGENL_MSG_HDR genlMsgHdr = &(msgIn->genlMsg);
     POVS_HDR ovsHdr = &(msgIn->ovsHdr);
-    PNL_ATTR nlAttrs[__OVS_FLOW_ATTR_MAX];
+    PNL_ATTR flowAttrs[__OVS_FLOW_ATTR_MAX];
     UINT32 attrOffset = NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN;
     OvsFlowPut mappedFlow;
     OvsFlowStats stats;
@@ -273,7 +278,8 @@ OvsFlowNlCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
 
     /* Get all the top level Flow attributes */
     if ((NlAttrParse(nlMsgHdr, attrOffset, NlMsgAttrsLen(nlMsgHdr),
-                     nlFlowPolicy, nlAttrs, ARRAY_SIZE(nlAttrs)))
+                     nlFlowPolicy, ARRAY_SIZE(nlFlowPolicy),
+                     flowAttrs, ARRAY_SIZE(flowAttrs)))
                      != TRUE) {
         OVS_LOG_ERROR("Attr Parsing failed for msg: %p",
                        nlMsgHdr);
@@ -283,7 +289,7 @@ OvsFlowNlCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
 
     /* FLOW_DEL command w/o any key input is a flush case. */
     if ((genlMsgHdr->cmd == OVS_FLOW_CMD_DEL) &&
-        (!(nlAttrs[OVS_FLOW_ATTR_KEY]))) {
+        (!(flowAttrs[OVS_FLOW_ATTR_KEY]))) {
 
         rc = OvsFlushFlowIoctl(ovsHdr->dp_ifindex);
 
@@ -308,9 +314,18 @@ OvsFlowNlCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
        goto done;
     }
 
-    if ((rc = _MapNlToFlowPut(msgIn, nlAttrs[OVS_FLOW_ATTR_KEY],
-         nlAttrs[OVS_FLOW_ATTR_ACTIONS], nlAttrs[OVS_FLOW_ATTR_CLEAR],
-         &mappedFlow))
+    if (flowAttrs[OVS_FLOW_ATTR_PROBE]) {
+        rc = OvsProbeSupportedFeature(msgIn, flowAttrs[OVS_FLOW_ATTR_KEY]);
+        if (rc != STATUS_SUCCESS) {
+            nlError = NlMapStatusToNlErr(rc);
+            goto done;
+        }
+    }
+
+    if ((rc = _MapNlToFlowPut(msgIn, flowAttrs[OVS_FLOW_ATTR_KEY],
+                              flowAttrs[OVS_FLOW_ATTR_ACTIONS],
+                              flowAttrs[OVS_FLOW_ATTR_CLEAR],
+                              &mappedFlow))
         != STATUS_SUCCESS) {
         OVS_LOG_ERROR("Conversion to OvsFlowPut failed");
         goto done;
@@ -319,7 +334,12 @@ OvsFlowNlCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
     rc = OvsPutFlowIoctl(&mappedFlow, sizeof (struct OvsFlowPut),
                          &stats);
     if (rc != STATUS_SUCCESS) {
-        OVS_LOG_ERROR("OvsFlowPut failed.");
+        OVS_LOG_ERROR("OvsPutFlowIoctl failed.");
+        /*
+         * Report back to the userspace the flow could not be modified,
+         * created or deleted
+         */
+        nlError = NL_ERROR_NOENT;
         goto done;
     }
 
@@ -342,6 +362,15 @@ OvsFlowNlCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
         rc = STATUS_SUCCESS;
     }
 
+    /* Append OVS_FLOW_ATTR_KEY attribute. This is need i.e. for flow delete*/
+    if (!NlMsgPutNested(&nlBuf, OVS_FLOW_ATTR_KEY,
+                        NlAttrData(flowAttrs[OVS_FLOW_ATTR_KEY]),
+                        NlAttrGetSize(flowAttrs[OVS_FLOW_ATTR_KEY]))) {
+        OVS_LOG_ERROR("Adding OVS_FLOW_ATTR_KEY attribute failed.");
+        rc = STATUS_INVALID_BUFFER_SIZE;
+        goto done;
+    }
+
     /* Append OVS_FLOW_ATTR_STATS attribute */
     if (!NlMsgPutTailUnspec(&nlBuf, OVS_FLOW_ATTR_STATS,
         (PCHAR)(&replyStats), sizeof(replyStats))) {
@@ -377,29 +406,13 @@ OvsFlowNlGetCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
                        UINT32 *replyLen)
 {
     NTSTATUS status = STATUS_SUCCESS;
-    NL_ERROR nlError = NL_ERROR_SUCCESS;
-    POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
 
     if (usrParamsCtx->devOp == OVS_TRANSACTION_DEV_OP) {
         status = _FlowNlGetCmdHandler(usrParamsCtx, replyLen);
-
-        /* No trasanctional errors as of now.
-         * If we have something then we need to convert rc to
-         * nlError. */
-        if ((nlError != NL_ERROR_SUCCESS) &&
-            (usrParamsCtx->outputBuffer)) {
-            POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
-                                           usrParamsCtx->outputBuffer;
-            NlBuildErrorMsg(msgIn, msgError, nlError);
-            *replyLen = msgError->nlMsg.nlmsgLen;
-            status = STATUS_SUCCESS;
-            goto done;
-        }
     } else {
         status = _FlowNlDumpCmdHandler(usrParamsCtx, replyLen);
     }
 
-done:
     return status;
 }
 
@@ -434,6 +447,7 @@ _FlowNlGetCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
     UINT32 keyAttrOffset = 0;
     UINT32 tunnelKeyAttrOffset = 0;
     BOOLEAN ok;
+    NL_ERROR nlError = NL_ERROR_SUCCESS;
 
     if (usrParamsCtx->inputLength > usrParamsCtx->outputLength) {
         /* Should not be the case.
@@ -447,7 +461,8 @@ _FlowNlGetCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
 
     /* Get all the top level Flow attributes */
     if ((NlAttrParse(nlMsgHdr, attrOffset, NlMsgAttrsLen(nlMsgHdr),
-                     nlFlowPolicy, nlAttrs, ARRAY_SIZE(nlAttrs)))
+                     nlFlowPolicy, ARRAY_SIZE(nlFlowPolicy),
+                     nlAttrs, ARRAY_SIZE(nlAttrs)))
                      != TRUE) {
         OVS_LOG_ERROR("Attr Parsing failed for msg: %p",
                        nlMsgHdr);
@@ -461,7 +476,8 @@ _FlowNlGetCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
     /* Get flow keys attributes */
     if ((NlAttrParseNested(nlMsgHdr, keyAttrOffset,
                            NlAttrLen(nlAttrs[OVS_FLOW_ATTR_KEY]),
-                           nlFlowKeyPolicy, keyAttrs, ARRAY_SIZE(keyAttrs)))
+                           nlFlowKeyPolicy, ARRAY_SIZE(nlFlowKeyPolicy),
+                           keyAttrs, ARRAY_SIZE(keyAttrs)))
                            != TRUE) {
         OVS_LOG_ERROR("Key Attr Parsing failed for msg: %p",
                        nlMsgHdr);
@@ -477,7 +493,8 @@ _FlowNlGetCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
         /* Get tunnel keys attributes */
         if ((NlAttrParseNested(nlMsgHdr, tunnelKeyAttrOffset,
                                NlAttrLen(keyAttrs[OVS_KEY_ATTR_TUNNEL]),
-                               nlFlowTunnelKeyPolicy,
+                               nlFlowTunnelKeyPolicy, 
+                               ARRAY_SIZE(nlFlowTunnelKeyPolicy),
                                tunnelAttrs, ARRAY_SIZE(tunnelAttrs)))
                                != TRUE) {
             OVS_LOG_ERROR("Tunnel key Attr Parsing failed for msg: %p",
@@ -499,6 +516,10 @@ _FlowNlGetCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
     rc = OvsGetFlowIoctl(&getInput, &getOutput);
     if (rc != STATUS_SUCCESS) {
         OVS_LOG_ERROR("OvsGetFlowIoctl failed.");
+        /*
+         * Report back to the userspace the flow could not be found
+         */
+        nlError = NL_ERROR_NOENT;
         goto done;
     }
 
@@ -532,6 +553,14 @@ _FlowNlGetCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
     *replyLen += NlMsgSize(nlMsgOutHdr);
 
 done:
+    if (nlError != NL_ERROR_SUCCESS) {
+        POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
+                                      usrParamsCtx->outputBuffer;
+        NlBuildErrorMsg(msgIn, msgError, nlError);
+        *replyLen = msgError->nlMsg.nlmsgLen;
+        rc = STATUS_SUCCESS;
+    }
+
     return rc;
 }
 
@@ -547,9 +576,10 @@ _FlowNlDumpCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
 {
     NTSTATUS rc = STATUS_SUCCESS;
     UINT32  temp = 0;   /* To keep compiler happy for calling OvsDoDumpFlows */
-
+    NL_ERROR nlError = NL_ERROR_SUCCESS;
     POVS_OPEN_INSTANCE instance = (POVS_OPEN_INSTANCE)
                                   (usrParamsCtx->ovsInstance);
+    POVS_MESSAGE msgIn = instance->dumpState.ovsMsg;
 
     if (usrParamsCtx->devOp == OVS_WRITE_DEV_OP) {
         /* Dump Start */
@@ -557,7 +587,6 @@ _FlowNlDumpCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
         goto done;
     }
 
-    POVS_MESSAGE msgIn = instance->dumpState.ovsMsg;
     PNL_MSG_HDR nlMsgHdr = &(msgIn->nlMsg);
     PGENL_MSG_HDR genlMsgHdr = &(msgIn->genlMsg);
     POVS_HDR ovsHdr = &(msgIn->ovsHdr);
@@ -589,6 +618,10 @@ _FlowNlDumpCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
         rc = OvsDoDumpFlows(&dumpInput, &dumpOutput, &temp);
         if (rc != STATUS_SUCCESS) {
             OVS_LOG_ERROR("OvsDoDumpFlows failed with rc: %d", rc);
+            /*
+             * Report back to the userspace the flows could not be found
+             */
+            nlError = NL_ERROR_NOENT;
             break;
         }
 
@@ -658,6 +691,14 @@ _FlowNlDumpCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
     } while(TRUE);
 
 done:
+    if (nlError != NL_ERROR_SUCCESS) {
+        POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
+                                      usrParamsCtx->outputBuffer;
+        NlBuildErrorMsg(msgIn, msgError, nlError);
+        *replyLen = msgError->nlMsg.nlmsgLen;
+        rc = STATUS_SUCCESS;
+    }
+
     return rc;
 }
 
@@ -839,6 +880,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;
     }
@@ -1159,6 +1207,31 @@ done:
     return rc;
 }
 
+/*
+ *----------------------------------------------------------------------------
+ *  _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 --
@@ -1183,10 +1256,11 @@ _MapNlToFlowPut(POVS_MESSAGE msgIn, PNL_ATTR keyAttr,
 
     /* Get flow keys attributes */
     if ((NlAttrParseNested(nlMsgHdr, keyAttrOffset, NlAttrLen(keyAttr),
-                           nlFlowKeyPolicy, keyAttrs, ARRAY_SIZE(keyAttrs)))
+                           nlFlowKeyPolicy, ARRAY_SIZE(nlFlowKeyPolicy),
+                           keyAttrs, ARRAY_SIZE(keyAttrs)))
                            != TRUE) {
         OVS_LOG_ERROR("Key Attr Parsing failed for msg: %p",
-                       nlMsgHdr);
+                      nlMsgHdr);
         rc = STATUS_INVALID_PARAMETER;
         goto done;
     }
@@ -1200,10 +1274,11 @@ _MapNlToFlowPut(POVS_MESSAGE msgIn, PNL_ATTR keyAttr,
         if ((NlAttrParseNested(nlMsgHdr, tunnelKeyAttrOffset,
                                NlAttrLen(keyAttrs[OVS_KEY_ATTR_TUNNEL]),
                                nlFlowTunnelKeyPolicy,
+                               ARRAY_SIZE(nlFlowTunnelKeyPolicy),
                                tunnelAttrs, ARRAY_SIZE(tunnelAttrs)))
                                != TRUE) {
             OVS_LOG_ERROR("Tunnel key Attr Parsing failed for msg: %p",
-                           nlMsgHdr);
+                          nlMsgHdr);
             rc = STATUS_INVALID_PARAMETER;
             goto done;
         }
@@ -1221,7 +1296,7 @@ _MapNlToFlowPut(POVS_MESSAGE msgIn, PNL_ATTR keyAttr,
     mappedFlow->dpNo = ovsHdr->dp_ifindex;
 
     _MapNlToFlowPutFlags(genlMsgHdr, flowAttrClear,
-                                mappedFlow);
+                         mappedFlow);
 
 done:
     return rc;
@@ -1434,8 +1509,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;
     }
     }
 }
@@ -1512,8 +1605,13 @@ OvsDeleteFlowTable(OVS_DATAPATH *datapath)
     }
 
     DeleteAllFlows(datapath);
-    OvsFreeMemory(datapath->flowTable);
+    OvsFreeMemoryWithTag(datapath->flowTable, OVS_FLOW_POOL_TAG);
     datapath->flowTable = NULL;
+
+    if (datapath->lock == NULL) {
+        return NDIS_STATUS_SUCCESS;
+    }
+
     NdisFreeRWLock(datapath->lock);
 
     return NDIS_STATUS_SUCCESS;
@@ -1534,8 +1632,8 @@ OvsAllocateFlowTable(OVS_DATAPATH *datapath,
     PLIST_ENTRY bucket;
     int i;
 
-    datapath->flowTable = OvsAllocateMemory(OVS_FLOW_TABLE_SIZE *
-                                            sizeof (LIST_ENTRY));
+    datapath->flowTable = OvsAllocateMemoryWithTag(
+        OVS_FLOW_TABLE_SIZE * sizeof(LIST_ENTRY), OVS_FLOW_POOL_TAG);
     if (!datapath->flowTable) {
         return NDIS_STATUS_RESOURCES;
     }
@@ -1545,6 +1643,10 @@ OvsAllocateFlowTable(OVS_DATAPATH *datapath,
     }
     datapath->lock = NdisAllocateRWLock(switchContext->NdisFilterHandle);
 
+    if (!datapath->lock) {
+        return NDIS_STATUS_RESOURCES;
+    }
+
     return NDIS_STATUS_SUCCESS;
 }
 
@@ -1629,7 +1731,7 @@ DeleteAllFlows(OVS_DATAPATH *datapath)
  *    - packet->l4 to just past the IPv4 header, if one is present and has a
  *      correct length, and otherwise NULL.
  *
- *    - packet->l7 to just past the TCP or UDP or ICMP header, if one is
+ *    - packet->l7 to just past the TCP, UDP, SCTP or ICMP header, if one is
  *      present and has a correct length, and otherwise NULL.
  *
  * Returns NDIS_STATUS_SUCCESS normally.  Fails only if packet data cannot be accessed
@@ -1690,10 +1792,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);
     }
 
@@ -1741,12 +1843,12 @@ OvsExtractFlow(const NET_BUFFER_LIST *packet,
 
             ipKey->nwTos = nh->tos;
             if (nh->frag_off & htons(IP_MF | IP_OFFSET)) {
-                ipKey->nwFrag = OVSWIN_NW_FRAG_ANY;
+                ipKey->nwFrag = OVS_FRAG_TYPE_FIRST;
                 if (nh->frag_off & htons(IP_OFFSET)) {
-                    ipKey->nwFrag |= OVSWIN_NW_FRAG_LATER;
+                    ipKey->nwFrag = OVS_FRAG_TYPE_LATER;
                 }
             } else {
-                ipKey->nwFrag = 0;
+                ipKey->nwFrag = OVS_FRAG_TYPE_NONE;
             }
 
             ipKey->nwTtl = nh->ttl;
@@ -1758,6 +1860,8 @@ OvsExtractFlow(const NET_BUFFER_LIST *packet,
                     OvsParseTcp(packet, &ipKey->l4, layers);
                 } else if (ipKey->nwProto == SOCKET_IPPROTO_UDP) {
                     OvsParseUdp(packet, &ipKey->l4, layers);
+                } else if (ipKey->nwProto == SOCKET_IPPROTO_SCTP) {
+                    OvsParseSctp(packet, &ipKey->l4, layers);
                 } else if (ipKey->nwProto == SOCKET_IPPROTO_ICMP) {
                     ICMPHdr icmpStorage;
                     const ICMPHdr *icmp;
@@ -1791,6 +1895,8 @@ OvsExtractFlow(const NET_BUFFER_LIST *packet,
             OvsParseTcp(packet, &(flow->ipv6Key.l4), layers);
         } else if (flow->ipv6Key.nwProto == SOCKET_IPPROTO_UDP) {
             OvsParseUdp(packet, &(flow->ipv6Key.l4), layers);
+        } else if (flow->ipv6Key.nwProto == SOCKET_IPPROTO_SCTP) {
+            OvsParseSctp(packet, &flow->ipv6Key.l4, layers);
         } else if (flow->ipv6Key.nwProto == SOCKET_IPPROTO_ICMPV6) {
             OvsParseIcmpV6(packet, flow, layers);
             flow->l2.keyLen += (OVS_ICMPV6_KEY_SIZE - OVS_IPV6_KEY_SIZE);
@@ -1820,6 +1926,45 @@ 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;
+        flow->l2.keyLen += OVS_MPLS_KEY_SIZE;
+
+        /*
+         * 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;
@@ -1976,7 +2121,7 @@ VOID
 FreeFlow(OvsFlow *flow)
 {
     ASSERT(flow);
-    OvsFreeMemory(flow);
+    OvsFreeMemoryWithTag(flow, OVS_FLOW_POOL_TAG);
 }
 
 NTSTATUS
@@ -1995,25 +2140,23 @@ OvsDoDumpFlows(OvsFlowDumpInput *dumpInput,
     BOOLEAN findNextNonEmpty = FALSE;
 
     dpNo = dumpInput->dpNo;
-    NdisAcquireSpinLock(gOvsCtrlLock);
     if (gOvsSwitchContext->dpNo != dpNo) {
         status = STATUS_INVALID_PARAMETER;
-        goto unlock;
+        goto exit;
     }
 
     rowIndex = dumpInput->position[0];
     if (rowIndex >= OVS_FLOW_TABLE_SIZE) {
         dumpOutput->n = 0;
         *replyLen = sizeof(*dumpOutput);
-        goto unlock;
+        goto exit;
     }
 
     columnIndex = dumpInput->position[1];
 
     datapath = &gOvsSwitchContext->datapath;
     ASSERT(datapath);
-    ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
-    OvsAcquireDatapathRead(datapath, &dpLockState, TRUE);
+    OvsAcquireDatapathRead(datapath, &dpLockState, FALSE);
 
     head = &datapath->flowTable[rowIndex];
     node = head->Flink;
@@ -2062,8 +2205,7 @@ OvsDoDumpFlows(OvsFlowDumpInput *dumpInput,
 dp_unlock:
     OvsReleaseDatapath(datapath, &dpLockState);
 
-unlock:
-    NdisReleaseSpinLock(gOvsCtrlLock);
+exit:
     return status;
 }
 
@@ -2124,21 +2266,18 @@ OvsPutFlowIoctl(PVOID inputBuffer,
     }
 
     dpNo = put->dpNo;
-    NdisAcquireSpinLock(gOvsCtrlLock);
     if (gOvsSwitchContext->dpNo != dpNo) {
         status = STATUS_INVALID_PARAMETER;
-        goto unlock;
+        goto exit;
     }
 
     datapath = &gOvsSwitchContext->datapath;
     ASSERT(datapath);
-    ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
-    OvsAcquireDatapathWrite(datapath, &dpLockState, TRUE);
+    OvsAcquireDatapathWrite(datapath, &dpLockState, FALSE);
     status = HandleFlowPut(put, datapath, stats);
     OvsReleaseDatapath(datapath, &dpLockState);
 
-unlock:
-    NdisReleaseSpinLock(gOvsCtrlLock);
+exit:
     return status;
 }
 
@@ -2170,7 +2309,6 @@ HandleFlowPut(OvsFlowPut *put,
 
         status = OvsPrepareFlow(&KernelFlow, put, hash);
         if (status != STATUS_SUCCESS) {
-            FreeFlow(KernelFlow);
             return STATUS_UNSUCCESSFUL;
         }
 
@@ -2259,7 +2397,8 @@ OvsPrepareFlow(OvsFlow **flow,
 
     do {
         *flow = localFlow =
-            OvsAllocateMemory(sizeof(OvsFlow) + put->actionsLen);
+            OvsAllocateMemoryWithTag(sizeof(OvsFlow) + put->actionsLen,
+                                     OVS_FLOW_POOL_TAG);
         if (localFlow == NULL) {
             status = STATUS_NO_MEMORY;
             break;
@@ -2305,16 +2444,14 @@ OvsGetFlowIoctl(PVOID inputBuffer,
     }
 
     dpNo = getInput->dpNo;
-    NdisAcquireSpinLock(gOvsCtrlLock);
     if (gOvsSwitchContext->dpNo != dpNo) {
         status = STATUS_INVALID_PARAMETER;
-        goto unlock;
+        goto exit;
     }
 
     datapath = &gOvsSwitchContext->datapath;
     ASSERT(datapath);
-    ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
-    OvsAcquireDatapathRead(datapath, &dpLockState, TRUE);
+    OvsAcquireDatapathRead(datapath, &dpLockState, FALSE);
     flow = OvsLookupFlow(datapath, &getInput->key, &hash, FALSE);
     if (!flow) {
         status = STATUS_INVALID_PARAMETER;
@@ -2326,8 +2463,7 @@ OvsGetFlowIoctl(PVOID inputBuffer,
 
 dp_unlock:
     OvsReleaseDatapath(datapath, &dpLockState);
-unlock:
-    NdisReleaseSpinLock(gOvsCtrlLock);
+exit:
     return status;
 }
 
@@ -2338,21 +2474,18 @@ OvsFlushFlowIoctl(UINT32 dpNo)
     OVS_DATAPATH *datapath = NULL;
     LOCK_STATE_EX dpLockState;
 
-    NdisAcquireSpinLock(gOvsCtrlLock);
     if (gOvsSwitchContext->dpNo != dpNo) {
         status = STATUS_INVALID_PARAMETER;
-        goto unlock;
+        goto exit;
     }
 
     datapath = &gOvsSwitchContext->datapath;
     ASSERT(datapath);
-    ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
-    OvsAcquireDatapathWrite(datapath, &dpLockState, TRUE);
+    OvsAcquireDatapathWrite(datapath, &dpLockState, FALSE);
     DeleteAllFlows(datapath);
     OvsReleaseDatapath(datapath, &dpLockState);
 
-unlock:
-    NdisReleaseSpinLock(gOvsCtrlLock);
+exit:
     return status;
 }
 
@@ -2395,4 +2528,56 @@ OvsTunKeyAttrSize(void)
          + NlAttrTotalSize(2);   /* OVS_TUNNEL_KEY_ATTR_TP_DST */
 }
 
+/*
+ *----------------------------------------------------------------------------
+ *  OvsProbeSupportedFeature --
+ *    Verifies if the probed feature is supported.
+ * 
+ * Results:
+ *   STATUS_SUCCESS if the probed feature is supported.
+ *----------------------------------------------------------------------------
+ */
+static NTSTATUS
+OvsProbeSupportedFeature(POVS_MESSAGE msgIn,
+                         PNL_ATTR keyAttr)
+{
+    NTSTATUS status = STATUS_SUCCESS;
+    PNL_MSG_HDR nlMsgHdr = &(msgIn->nlMsg);
+
+    UINT32 keyAttrOffset = (UINT32)((PCHAR)keyAttr - (PCHAR)nlMsgHdr);
+    PNL_ATTR keyAttrs[__OVS_KEY_ATTR_MAX] = { NULL };
+
+    /* Get flow keys attributes */
+    if ((NlAttrParseNested(nlMsgHdr, keyAttrOffset, NlAttrLen(keyAttr),
+                           nlFlowKeyPolicy, ARRAY_SIZE(nlFlowKeyPolicy),
+                           keyAttrs, ARRAY_SIZE(keyAttrs)))
+                           != TRUE) {
+        OVS_LOG_ERROR("Key Attr Parsing failed for msg: %p",
+                      nlMsgHdr);
+        status = STATUS_INVALID_PARAMETER;
+        goto done;
+    }
+
+    if (keyAttrs[OVS_KEY_ATTR_MPLS] &&
+        keyAttrs[OVS_KEY_ATTR_ETHERTYPE]) {
+        ovs_be16 ethType = NlAttrGetU16(keyAttrs[OVS_KEY_ATTR_ETHERTYPE]);
+
+        if (OvsEthertypeIsMpls(ethType)) {
+            if (!OvsCountMplsLabels(keyAttrs[OVS_KEY_ATTR_MPLS])) {
+                OVS_LOG_ERROR("Maximum supported MPLS labels exceeded.");
+                status = STATUS_INVALID_MESSAGE;
+            }
+        } else {
+            OVS_LOG_ERROR("Wrong ethertype for MPLS attribute.");
+            status = STATUS_INVALID_PARAMETER;
+        }
+    } else {
+        OVS_LOG_ERROR("Probed feature not supported.");
+        status = STATUS_INVALID_PARAMETER;
+    }
+
+done:
+    return status;
+}
+
 #pragma warning( pop )