[ovs-dev] [PATCH v1 07/10] datapath-windows/Flow.c: FLOW_NEW command handler.

Ankur Sharma ankursharma at vmware.com
Wed Sep 24 07:15:41 UTC 2014


This patch covers the changes needed to support FLOW_NEW command.
API _OvsFlowMapNlToFlowPutFlags has a bug, which will be fixed
with the patches for FLOW_DEL.
---
 datapath-windows/include/OvsPub.h |   2 +-
 datapath-windows/ovsext/Flow.c    | 384 +++++++++++++++++++++++++++++++++++---
 datapath-windows/ovsext/Flow.h    |   6 +-
 3 files changed, 366 insertions(+), 26 deletions(-)

diff --git a/datapath-windows/include/OvsPub.h b/datapath-windows/include/OvsPub.h
index 36814c4..fa1d6d4 100644
--- a/datapath-windows/include/OvsPub.h
+++ b/datapath-windows/include/OvsPub.h
@@ -420,7 +420,7 @@ typedef struct OvsFlowPut {
     uint32_t actionsLen;
     OvsFlowKey key;
     uint32_t flags;
-    NL_ATTR  actions[0];  /* Variable length indicated by actionsLen. */
+    PNL_ATTR  actions;
 } OvsFlowPut;
 
 #define OVS_MIN_PACKET_SIZE 60
diff --git a/datapath-windows/ovsext/Flow.c b/datapath-windows/ovsext/Flow.c
index 25b39c1..e170de6 100644
--- a/datapath-windows/ovsext/Flow.c
+++ b/datapath-windows/ovsext/Flow.c
@@ -46,6 +46,20 @@ static VOID DeleteAllFlows(OVS_DATAPATH *datapath);
 static NTSTATUS AddFlow(OVS_DATAPATH *datapath, OvsFlow *flow);
 static VOID FreeFlow(OvsFlow *flow);
 static VOID __inline *GetStartAddrNBL(const NET_BUFFER_LIST *_pNB);
+static NTSTATUS _OvsFlowMapNlToFlowPut(POVS_MESSAGE msgIn, PNL_ATTR keyAttr,
+                                       PNL_ATTR actionAttr,
+                                       PNL_ATTR flowAttrClear,
+                                       OvsFlowPut *mappedFlow);
+static VOID _OvsFlowMapKeyAttrToFlowPut(PNL_ATTR *keyAttrs,
+                                        PNL_ATTR *tunnelAttrs,
+                                        OvsFlowPut *mappedFlow);
+
+static VOID _OvsFlowMapTunAttrToFlowPut(PNL_ATTR *keyAttrs,
+                                        PNL_ATTR *tunnelAttrs,
+                                        OvsFlowKey *destKey);
+static VOID _OvsFlowMapNlToFlowPutFlags(PGENL_MSG_HDR genlMsgHdr,
+                                        PNL_ATTR flowAttrClear,
+                                        OvsFlowPut *mappedFlow);
 
 #define OVS_FLOW_TABLE_SIZE 2048
 #define OVS_FLOW_TABLE_MASK (OVS_FLOW_TABLE_SIZE -1)
@@ -191,20 +205,365 @@ static const NL_POLICY nlFlowActionPolicy[] = {
  * Netlink interface for flow commands.
  *----------------------------------------------------------------------------
  */
+
+/*
+ *----------------------------------------------------------------------------
+ *  OvsFlowNlNewCmdHandler --
+ *    Handler for OVS_FLOW_CMD_NEW command.
+ *----------------------------------------------------------------------------
+ */
 NTSTATUS
 OvsFlowNlNewCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
                        UINT32 *replyLen)
 {
     NTSTATUS rc = STATUS_SUCCESS;
+    POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
+    POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
+    PNL_MSG_HDR nlMsgHdr = &(msgIn->nlMsg);
+    PGENL_MSG_HDR genlMsgHdr = &(msgIn->genlMsg);
+    POVS_HDR ovsHdr = &(msgIn->ovsHdr);
+    PNL_ATTR nlAttrs[__OVS_FLOW_ATTR_MAX];
+    UINT32 attrOffset = NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN;
+    POVS_OPEN_INSTANCE instance = (POVS_OPEN_INSTANCE)
+                                   usrParamsCtx->ovsInstance;
+    OvsFlowPut mappedFlow;
+    OvsFlowStats stats;
+    struct ovs_flow_stats replyStats;
+
+    NL_BUFFER nlBuf;
+
+    UNREFERENCED_PARAMETER(genlMsgHdr);
+    UNREFERENCED_PARAMETER(ovsHdr);
+    UNREFERENCED_PARAMETER(instance);
+
+    RtlZeroMemory(&mappedFlow, sizeof(OvsFlowPut));
+    RtlZeroMemory(&stats, sizeof(stats));
+    RtlZeroMemory(&replyStats, sizeof(replyStats));
+
+    *replyLen = 0;
+
+    /* Get all the top level Flow attributes */
+    if ((NlAttrParse(nlMsgHdr, attrOffset, NlMsgAttrLen(nlMsgHdr),
+                     nlFlowPolicy, nlAttrs, ARRAY_SIZE(nlAttrs)))
+                     != TRUE) {
+        OVS_LOG_ERROR("Attr Parsing failed for msg: %p",
+                       nlMsgHdr);
+        rc = NDIS_STATUS_FAILURE;
+        goto done;
+    }
+
+    if ((_OvsFlowMapNlToFlowPut(msgIn, nlAttrs[OVS_FLOW_ATTR_KEY],
+         nlAttrs[OVS_FLOW_ATTR_ACTIONS], nlAttrs[OVS_FLOW_ATTR_CLEAR],
+         &mappedFlow))
+        != NDIS_STATUS_SUCCESS) {
+        OVS_LOG_ERROR("Conversion to OvsFlowPut failed");
+        goto done;
+    }
+
+    rc = OvsPutFlowIoctl(&mappedFlow, sizeof (struct OvsFlowPut),
+                         &stats);
+    if (rc != STATUS_SUCCESS) {
+        OVS_LOG_ERROR("OvsFlowPut failed.");
+        goto done;
+    }
+
+    if (!(usrParamsCtx->outputBuffer)) {
+        /* No output buffer */
+        OVS_LOG_ERROR("outputBuffer NULL.");
+        goto done;
+    }
+
+    replyStats.n_packets = stats.packetCount;
+    replyStats.n_bytes = stats.byteCount;
+
+    /* So far so good. Prepare the reply for userspace */
+    NlBufInit(&nlBuf, usrParamsCtx->outputBuffer,
+              usrParamsCtx->outputLength);
+
+    /* Prepare nl Msg headers */
+    rc = NlFillOvsMsg(msgOut, &nlBuf, nlMsgHdr->nlmsgType, 0,
+                      nlMsgHdr->nlmsgSeq, nlMsgHdr->nlmsgPid,
+                      genlMsgHdr->cmd, OVS_FLOW_VERSION,
+                      ovsHdr->dp_ifindex);
+    ASSERT(rc);
+
+    /* Append OVS_FLOW_ATTR_STATS attribute */
+    if (!NlMsgPutTailUnspec(&nlBuf, OVS_FLOW_ATTR_STATS,
+        (PCHAR)(&replyStats), sizeof(replyStats))) {
+        OVS_LOG_ERROR("Adding OVS_FLOW_ATTR_STATS attribute failed.");
+        rc = NDIS_STATUS_FAILURE;
+    }
+
+    *replyLen = msgOut->nlMsg.nlmsgLen;
+
+done:
+    return rc;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ *  _OvsFlowMapNlToFlowPut --
+ *    Maps input netlink message to OvsFlowPut.
+ *----------------------------------------------------------------------------
+ */
+static NTSTATUS
+_OvsFlowMapNlToFlowPut(POVS_MESSAGE msgIn, PNL_ATTR keyAttr,
+                       PNL_ATTR actionAttr, PNL_ATTR flowAttrClear,
+                       OvsFlowPut *mappedFlow)
+{
+    NTSTATUS rc = NDIS_STATUS_SUCCESS;
+    PNL_MSG_HDR nlMsgHdr = &(msgIn->nlMsg);
+    PGENL_MSG_HDR genlMsgHdr = &(msgIn->genlMsg);
+    POVS_HDR ovsHdr = &(msgIn->ovsHdr);
+
+    UINT32 keyAttrOffset = (UINT32)((PCHAR)keyAttr - (PCHAR)nlMsgHdr);
+    UINT32 tunnelKeyAttrOffset;
+
+    PNL_ATTR keyAttrs[__OVS_KEY_ATTR_MAX] = {NULL};
+    PNL_ATTR tunnelAttrs[__OVS_TUNNEL_KEY_ATTR_MAX] = {NULL};
+
+    UNREFERENCED_PARAMETER(ovsHdr);
+    UNREFERENCED_PARAMETER(tunnelKeyAttrOffset);
+
+    /* Get flow keys attributes */
+    if ((NlAttrParseNested(nlMsgHdr, keyAttrOffset, NlAttrLen(keyAttr),
+                           nlFlowKeyPolicy, keyAttrs, ARRAY_SIZE(keyAttrs)))
+                           != TRUE) {
+        OVS_LOG_ERROR("Key Attr Parsing failed for msg: %p",
+                       nlMsgHdr);
+        rc = NDIS_STATUS_FAILURE;
+        goto done;
+    }
+
+    if (keyAttrs[OVS_KEY_ATTR_TUNNEL]) {
+        tunnelKeyAttrOffset = (UINT32)((PCHAR)
+                              (keyAttrs[OVS_KEY_ATTR_TUNNEL])
+                              - (PCHAR)nlMsgHdr);
+
+        OVS_LOG_ERROR("Parse Flow Tunnel Key Policy");
+
+        /* Get tunnel keys attributes */
+        if ((NlAttrParseNested(nlMsgHdr, tunnelKeyAttrOffset,
+                               NlAttrLen(keyAttr), nlFlowTunnelKeyPolicy,
+                               tunnelAttrs, ARRAY_SIZE(tunnelAttrs)))
+                               != TRUE) {
+            OVS_LOG_ERROR("Tunnel key Attr Parsing failed for msg: %p",
+                           nlMsgHdr);
+            rc = NDIS_STATUS_FAILURE;
+            goto done;
+        }
+    }
+
+    _OvsFlowMapKeyAttrToFlowPut(keyAttrs, tunnelAttrs,
+                                mappedFlow);
+
+    /* Map the action */
+    mappedFlow->actionsLen = NlAttrGetSize(actionAttr);
+    mappedFlow->actions = NlAttrGet(actionAttr);
+    mappedFlow->dpNo = ovsHdr->dp_ifindex;
 
-    UNREFERENCED_PARAMETER(usrParamsCtx);
-    UNREFERENCED_PARAMETER(replyLen);
+    _OvsFlowMapNlToFlowPutFlags(genlMsgHdr, flowAttrClear,
+                                mappedFlow);
 
+done:
     return rc;
 }
 
 /*
  *----------------------------------------------------------------------------
+ *  _OvsFlowMapNlToFlowPutFlags --
+ *    Maps netlink message to OvsFlowPut->flags.
+ *----------------------------------------------------------------------------
+ */
+static VOID
+_OvsFlowMapNlToFlowPutFlags(PGENL_MSG_HDR genlMsgHdr, PNL_ATTR flowAttrClear,
+                            OvsFlowPut *mappedFlow)
+{
+    uint32_t flags = 0;
+
+    switch (genlMsgHdr->cmd) {
+    case OVS_FLOW_CMD_NEW:
+         flags |= OVSWIN_FLOW_PUT_CREATE;
+         break;
+    case OVS_FLOW_CMD_DEL:
+         flags |= OVSWIN_FLOW_PUT_DELETE;
+         break;
+    case OVS_FLOW_CMD_SET:
+         flags |= OVSWIN_FLOW_PUT_MODIFY;
+         break;
+    default:
+         ASSERT(0);
+    }
+
+    if (flowAttrClear) {
+        flags |= OVSWIN_FLOW_PUT_CLEAR;
+    }
+
+    mappedFlow->flags = flags;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ *  _OvsFlowMapKeyAttrToFlowPut --
+ *    Converts FLOW_KEY attribute to OvsFlowPut->key.
+ *----------------------------------------------------------------------------
+ */
+static VOID
+_OvsFlowMapKeyAttrToFlowPut(PNL_ATTR *keyAttrs,
+                            PNL_ATTR *tunnelAttrs,
+                            OvsFlowPut *mappedFlow)
+{
+    const struct ovs_key_ethernet *eth_key;
+    OvsFlowKey *destKey = &(mappedFlow->key);
+
+    _OvsFlowMapTunAttrToFlowPut(keyAttrs, tunnelAttrs, destKey);
+
+    /* ===== L2 headers ===== */
+    destKey->l2.inPort = NlAttrGetU32(keyAttrs[OVS_KEY_ATTR_IN_PORT]);
+    eth_key = NlAttrGet(keyAttrs[OVS_KEY_ATTR_ETHERNET]);
+    memcpy(destKey->l2.dlSrc, eth_key->eth_src, ETH_ADDR_LEN);
+    memcpy(destKey->l2.dlDst, eth_key->eth_dst, ETH_ADDR_LEN);
+
+    destKey->l2.dlType = ntohs((NlAttrGetU16(keyAttrs
+                          [OVS_KEY_ATTR_ETHERTYPE])));
+
+    if (keyAttrs[OVS_KEY_ATTR_VLAN]) {
+        destKey->l2.vlanTci = NlAttrGetU16(keyAttrs
+                              [OVS_KEY_ATTR_VLAN]);
+    }
+
+    /* ==== L3 + L4. ==== */
+    destKey->l2.keyLen = OVS_WIN_TUNNEL_KEY_SIZE + OVS_L2_KEY_SIZE
+                         - destKey->l2.offset;
+
+    switch (destKey->l2.dlType) {
+    case ETH_TYPE_IPV4: {
+        const struct ovs_key_ipv4 *ipv4Key;
+        const struct ovs_key_tcp *tcpKey;
+
+        ipv4Key = NlAttrGet(keyAttrs[OVS_KEY_ATTR_IPV4]);
+
+        IpKey *ipv4FlowPutKey = &(destKey->ipKey);
+
+        ipv4FlowPutKey->nwSrc = ipv4Key->ipv4_src;
+        ipv4FlowPutKey->nwDst = ipv4Key->ipv4_dst;
+        ipv4FlowPutKey->nwProto = ipv4Key->ipv4_proto;
+        ipv4FlowPutKey->nwTos = ipv4Key->ipv4_tos;
+        ipv4FlowPutKey->nwTtl = ipv4Key->ipv4_ttl;
+        ipv4FlowPutKey->nwFrag = ipv4Key->ipv4_frag;
+
+        if (keyAttrs[OVS_KEY_ATTR_TCP]) {
+            tcpKey = NlAttrGet(keyAttrs[OVS_KEY_ATTR_TCP]);
+            ipv4FlowPutKey->l4.tpSrc = tcpKey->tcp_src;
+            ipv4FlowPutKey->l4.tpDst = tcpKey->tcp_dst;
+        }
+
+        destKey->l2.keyLen += OVS_IP_KEY_SIZE;
+        break;
+    }
+    case ETH_TYPE_IPV6: {
+        const struct ovs_key_ipv6 *ipv6Key;
+        const struct ovs_key_tcp *tcpKey;
+
+        ipv6Key = NlAttrGet(keyAttrs[OVS_KEY_ATTR_IPV6]);
+
+        Ipv6Key *ipv6FlowPutKey = &(destKey->ipv6Key);
+
+        memcpy(&ipv6FlowPutKey->ipv6Src, ipv6Key->ipv6_src, sizeof ipv6Key->ipv6_src);
+        memcpy(&ipv6FlowPutKey->ipv6Dst, ipv6Key->ipv6_dst, sizeof ipv6Key->ipv6_dst);
+        ipv6FlowPutKey->ipv6Label = ipv6Key->ipv6_label;
+        ipv6FlowPutKey->nwProto  = ipv6Key->ipv6_proto;
+        ipv6FlowPutKey->nwTos = ipv6Key->ipv6_tclass;
+        ipv6FlowPutKey->nwTtl = ipv6Key->ipv6_hlimit;
+
+        ipv6FlowPutKey->nwFrag = ipv6Key->ipv6_frag;
+
+        if (keyAttrs[OVS_KEY_ATTR_TCP]) {
+            tcpKey = NlAttrGet(keyAttrs[OVS_KEY_ATTR_TCP]);
+            ipv6FlowPutKey->l4.tpSrc = tcpKey->tcp_src;
+            ipv6FlowPutKey->l4.tpDst = tcpKey->tcp_dst;
+        }
+
+        ipv6FlowPutKey->pad = 0;
+
+        if (ipv6Key->ipv6_proto == IPPROTO_ICMPV6) {
+            const struct ovs_key_nd *ndKey;
+            Icmp6Key *icmp6FlowPutKey= &(destKey->icmp6Key);
+
+            ndKey = NlAttrGet(keyAttrs[OVS_KEY_ATTR_ND]);
+
+            memcpy(&icmp6FlowPutKey->ndTarget, ndKey->nd_target,
+                   sizeof (icmp6FlowPutKey->ndTarget));
+            memcpy(icmp6FlowPutKey->arpSha, ndKey->nd_sll, ETH_ADDR_LEN);
+            memcpy(icmp6FlowPutKey->arpTha, ndKey->nd_tll, ETH_ADDR_LEN);
+
+            destKey->l2.keyLen += OVS_ICMPV6_KEY_SIZE;
+        } else {
+            destKey->l2.keyLen += OVS_IPV6_KEY_SIZE;
+        }
+        break;
+    }
+    case ETH_TYPE_ARP:
+    case ETH_TYPE_RARP: {
+        ArpKey *arpFlowPutKey = &destKey->arpKey;
+        const struct ovs_key_arp *arpKey;
+
+        arpKey = NlAttrGet(keyAttrs[OVS_KEY_ATTR_ARP]);
+
+        arpFlowPutKey->nwSrc = arpKey->arp_sip;
+        arpFlowPutKey->nwDst = arpKey->arp_tip;
+
+        memcpy(arpFlowPutKey->arpSha, arpKey->arp_sha, ETH_ADDR_LEN);
+        memcpy(arpFlowPutKey->arpTha, arpKey->arp_tha, ETH_ADDR_LEN);
+        arpFlowPutKey->nwProto = (UINT8)(arpKey->arp_op);
+        arpFlowPutKey->pad[0] = 0;
+        arpFlowPutKey->pad[1] = 0;
+        arpFlowPutKey->pad[2] = 0;
+        destKey->l2.keyLen += OVS_ARP_KEY_SIZE;
+        break;
+    }
+    }
+}
+
+/*
+ *----------------------------------------------------------------------------
+ *  _OvsFlowMapTunAttrToFlowPut --
+ *    Converts FLOW_TUNNEL_KEY attribute to OvsFlowKey->tunKey.
+ *----------------------------------------------------------------------------
+ */
+static VOID
+_OvsFlowMapTunAttrToFlowPut(PNL_ATTR *keyAttrs,
+                            PNL_ATTR *tunAttrs,
+                            OvsFlowKey *destKey)
+{
+    if (keyAttrs[OVS_KEY_ATTR_TUNNEL]) {
+        destKey->tunKey.tunnelId = NlAttrGetU64
+                                   (tunAttrs[OVS_TUNNEL_KEY_ATTR_ID]);
+        destKey->tunKey.dst = NlAttrGetU32
+                              (tunAttrs[OVS_TUNNEL_KEY_ATTR_IPV4_DST]);
+        destKey->tunKey.src = NlAttrGetU32
+                              (tunAttrs[OVS_TUNNEL_KEY_ATTR_IPV4_SRC]);
+
+        /* XXX: There are no attributes to specify tunnel flags.
+         * Also, i do not see these flags being used anywhere in
+         * flowPut code. */
+        destKey->tunKey.flags = 0;
+        destKey->tunKey.tos = NlAttrGetU8
+                                 (tunAttrs[OVS_TUNNEL_KEY_ATTR_TOS]);
+        destKey->tunKey.ttl = NlAttrGetU8
+                                 (tunAttrs[OVS_TUNNEL_KEY_ATTR_TTL]);
+        destKey->tunKey.pad = 0;
+        destKey->l2.offset = 0;
+    } else {
+        destKey->tunKey.attr[0] = 0;
+        destKey->tunKey.attr[1] = 0;
+        destKey->tunKey.attr[2] = 0;
+        destKey->l2.offset = sizeof destKey->tunKey;
+    }
+}
+
+/*
+ *----------------------------------------------------------------------------
  * OvsDeleteFlowTable --
  * Results:
  *    NDIS_STATUS_SUCCESS always.
@@ -837,13 +1196,10 @@ ReportFlowInfo(OvsFlow *flow,
 NTSTATUS
 OvsPutFlowIoctl(PVOID inputBuffer,
                 UINT32 inputLength,
-                PVOID outputBuffer,
-                UINT32 outputLength,
-                UINT32 *replyLen)
+                struct OvsFlowStats *stats)
 {
     NTSTATUS status = STATUS_SUCCESS;
     OVS_DATAPATH *datapath = NULL;
-    struct OvsFlowStats stats;
     ULONG actionsLen;
     OvsFlowPut *put;
     UINT32 dpNo;
@@ -853,19 +1209,12 @@ OvsPutFlowIoctl(PVOID inputBuffer,
         return STATUS_INFO_LENGTH_MISMATCH;
     }
 
-    if ((outputLength != sizeof(stats)) || (outputBuffer == NULL)) {
-        return STATUS_INFO_LENGTH_MISMATCH;
-    }
-
     put = (OvsFlowPut *)inputBuffer;
     if (put->actionsLen > 0) {
         actionsLen = put->actionsLen;
     } else {
         actionsLen = 0;
     }
-    if (inputLength != actionsLen + sizeof(*put)) {
-        return STATUS_INFO_LENGTH_MISMATCH;
-    }
 
     dpNo = put->dpNo;
     NdisAcquireSpinLock(gOvsCtrlLock);
@@ -877,17 +1226,10 @@ OvsPutFlowIoctl(PVOID inputBuffer,
 
     datapath = &gOvsSwitchContext->datapath;
     ASSERT(datapath);
-    RtlZeroMemory(&stats, sizeof(stats));
     OvsAcquireDatapathWrite(datapath, &dpLockState, FALSE);
-    status = HandleFlowPut(put, datapath, &stats);
+    status = HandleFlowPut(put, datapath, stats);
     OvsReleaseDatapath(datapath, &dpLockState);
 
-    if (status == STATUS_SUCCESS) {
-        // Copy stats to User mode app
-        NdisMoveMemory(outputBuffer, (PVOID)&stats, sizeof(stats));
-        *replyLen = sizeof stats;
-    }
-
 unlock:
     NdisReleaseSpinLock(gOvsCtrlLock);
     return status;
diff --git a/datapath-windows/ovsext/Flow.h b/datapath-windows/ovsext/Flow.h
index 602e567..e62ba40 100644
--- a/datapath-windows/ovsext/Flow.h
+++ b/datapath-windows/ovsext/Flow.h
@@ -64,16 +64,14 @@ NTSTATUS OvsDumpFlowIoctl(PVOID inputBuffer, UINT32 inputLength,
                           PVOID outputBuffer, UINT32 outputLength,
                           UINT32 *replyLen);
 NTSTATUS OvsPutFlowIoctl(PVOID inputBuffer, UINT32 inputLength,
-                         PVOID outputBuffer, UINT32 outputLength,
-                         UINT32 *replyLen);
+                         struct OvsFlowStats *stats);
 NTSTATUS OvsGetFlowIoctl(PVOID inputBuffer, UINT32 inputLength,
                          PVOID outputBuffer, UINT32 outputLength,
                          UINT32 *replyLen);
 NTSTATUS OvsFlushFlowIoctl(PVOID inputBuffer, UINT32 inputLength);
 
 NTSTATUS OvsFlowNlNewCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
-                                 UINT32 *replyLen);
-
+                                UINT32 *replyLen);
 
 /* Flags for tunneling */
 #define OVS_TNL_F_DONT_FRAGMENT         (1 << 0)
-- 
1.9.1




More information about the dev mailing list