{"id":814768,"url":"http://patchwork.ozlabs.org/api/1.2/patches/814768/?format=json","web_url":"http://patchwork.ozlabs.org/project/openvswitch/patch/1505708164-10270-5-git-send-email-roid@mellanox.com/","project":{"id":47,"url":"http://patchwork.ozlabs.org/api/1.2/projects/47/?format=json","name":"Open vSwitch","link_name":"openvswitch","list_id":"ovs-dev.openvswitch.org","list_email":"ovs-dev@openvswitch.org","web_url":"http://openvswitch.org/","scm_url":"git@github.com:openvswitch/ovs.git","webscm_url":"https://github.com/openvswitch/ovs","list_archive_url":"","list_archive_url_format":"","commit_url_format":""},"msgid":"<1505708164-10270-5-git-send-email-roid@mellanox.com>","list_archive_url":null,"date":"2017-09-18T04:16:04","name":"[ovs-dev,V2,4/4] netdev-tc-offloads: Add support for action set","commit_ref":null,"pull_url":null,"state":"changes-requested","archived":false,"hash":"bac3dd33e44ec752ab37ebea8bd8f1536df34455","submitter":{"id":70307,"url":"http://patchwork.ozlabs.org/api/1.2/people/70307/?format=json","name":"Roi Dayan","email":"roid@mellanox.com"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/openvswitch/patch/1505708164-10270-5-git-send-email-roid@mellanox.com/mbox/","series":[{"id":3557,"url":"http://patchwork.ozlabs.org/api/1.2/series/3557/?format=json","web_url":"http://patchwork.ozlabs.org/project/openvswitch/list/?series=3557","date":"2017-09-18T04:16:00","name":"Add offload support for action set","version":2,"mbox":"http://patchwork.ozlabs.org/series/3557/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/814768/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/814768/checks/","tags":{},"related":[],"headers":{"Return-Path":"<ovs-dev-bounces@openvswitch.org>","X-Original-To":["incoming@patchwork.ozlabs.org","dev@openvswitch.org"],"Delivered-To":["patchwork-incoming@bilbo.ozlabs.org","ovs-dev@mail.linuxfoundation.org"],"Authentication-Results":"ozlabs.org;\n\tspf=pass (mailfrom) smtp.mailfrom=openvswitch.org\n\t(client-ip=140.211.169.12; helo=mail.linuxfoundation.org;\n\tenvelope-from=ovs-dev-bounces@openvswitch.org;\n\treceiver=<UNKNOWN>)","Received":["from mail.linuxfoundation.org (mail.linuxfoundation.org\n\t[140.211.169.12])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256\n\tbits)) (No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3xwXmm3x6fz9s7G\n\tfor <incoming@patchwork.ozlabs.org>;\n\tMon, 18 Sep 2017 14:18:16 +1000 (AEST)","from mail.linux-foundation.org (localhost [127.0.0.1])\n\tby mail.linuxfoundation.org (Postfix) with ESMTP id B19DAA73;\n\tMon, 18 Sep 2017 04:16:22 +0000 (UTC)","from smtp1.linuxfoundation.org (smtp1.linux-foundation.org\n\t[172.17.192.35])\n\tby mail.linuxfoundation.org (Postfix) with ESMTPS id 73226941\n\tfor <dev@openvswitch.org>; Mon, 18 Sep 2017 04:16:18 +0000 (UTC)","from mellanox.co.il (mail-il-dmz.mellanox.com [193.47.165.129])\n\tby smtp1.linuxfoundation.org (Postfix) with ESMTP id 4A50E157\n\tfor <dev@openvswitch.org>; Mon, 18 Sep 2017 04:16:17 +0000 (UTC)","from Internal Mail-Server by MTLPINE1 (envelope-from\n\troid@mellanox.com)\n\twith ESMTPS (AES256-SHA encrypted); 18 Sep 2017 07:16:12 +0300","from dev-r-vrt-189.mtr.labs.mlnx (dev-r-vrt-189.mtr.labs.mlnx\n\t[10.212.189.1])\n\tby labmailer.mlnx (8.13.8/8.13.8) with ESMTP id v8I4GBDU001186;\n\tMon, 18 Sep 2017 07:16:11 +0300"],"X-Greylist":"domain auto-whitelisted by SQLgrey-1.7.6","From":"Roi Dayan <roid@mellanox.com>","To":"dev@openvswitch.org","Date":"Mon, 18 Sep 2017 07:16:04 +0300","Message-Id":"<1505708164-10270-5-git-send-email-roid@mellanox.com>","X-Mailer":"git-send-email 2.7.5","In-Reply-To":"<1505708164-10270-1-git-send-email-roid@mellanox.com>","References":"<1505708164-10270-1-git-send-email-roid@mellanox.com>","X-Spam-Status":"No, score=0.0 required=5.0 tests=RP_MATCHES_RCVD,\n\tUNPARSEABLE_RELAY autolearn=disabled version=3.3.1","X-Spam-Checker-Version":"SpamAssassin 3.3.1 (2010-03-16) on\n\tsmtp1.linux-foundation.org","Cc":"Simon Horman <simon.horman@netronome.com>","Subject":"[ovs-dev] [PATCH V2 4/4] netdev-tc-offloads: Add support for action\n\tset","X-BeenThere":"ovs-dev@openvswitch.org","X-Mailman-Version":"2.1.12","Precedence":"list","List-Id":"<ovs-dev.openvswitch.org>","List-Unsubscribe":"<https://mail.openvswitch.org/mailman/options/ovs-dev>,\n\t<mailto:ovs-dev-request@openvswitch.org?subject=unsubscribe>","List-Archive":"<http://mail.openvswitch.org/pipermail/ovs-dev/>","List-Post":"<mailto:ovs-dev@openvswitch.org>","List-Help":"<mailto:ovs-dev-request@openvswitch.org?subject=help>","List-Subscribe":"<https://mail.openvswitch.org/mailman/listinfo/ovs-dev>,\n\t<mailto:ovs-dev-request@openvswitch.org?subject=subscribe>","MIME-Version":"1.0","Content-Type":"text/plain; charset=\"us-ascii\"","Content-Transfer-Encoding":"7bit","Sender":"ovs-dev-bounces@openvswitch.org","Errors-To":"ovs-dev-bounces@openvswitch.org"},"content":"From: Paul Blakey <paulb@mellanox.com>\n\nImplement support for offloading ovs action set using\ntc header rewrite action.\n\nSigned-off-by: Paul Blakey <paulb@mellanox.com>\nReviewed-by: Roi Dayan <roid@mellanox.com>\n---\n lib/netdev-tc-offloads.c | 201 +++++++++++++++++++++++++++++++++++++++++++++--\n 1 file changed, 195 insertions(+), 6 deletions(-)","diff":"diff --git a/lib/netdev-tc-offloads.c b/lib/netdev-tc-offloads.c\nindex 3c145c2..4044a77 100644\n--- a/lib/netdev-tc-offloads.c\n+++ b/lib/netdev-tc-offloads.c\n@@ -27,11 +27,13 @@\n #include \"openvswitch/ofpbuf.h\"\n #include \"openvswitch/thread.h\"\n #include \"openvswitch/types.h\"\n+#include \"openvswitch/util.h\"\n #include \"openvswitch/vlog.h\"\n #include \"netdev-linux.h\"\n #include \"netlink.h\"\n #include \"netlink-socket.h\"\n #include \"odp-netlink.h\"\n+#include \"odp-util.h\"\n #include \"tc.h\"\n #include \"unaligned.h\"\n #include \"util.h\"\n@@ -41,6 +43,76 @@ VLOG_DEFINE_THIS_MODULE(netdev_tc_offloads);\n static struct vlog_rate_limit error_rl = VLOG_RATE_LIMIT_INIT(60, 5);\n \n static struct hmap ufid_tc = HMAP_INITIALIZER(&ufid_tc);\n+\n+struct netlink_field {\n+    int offset;\n+    int flower_offset;\n+    int size;\n+};\n+\n+static struct netlink_field set_flower_map[][3] = {\n+    [OVS_KEY_ATTR_IPV4] = {\n+        { offsetof(struct ovs_key_ipv4, ipv4_src),\n+          offsetof(struct tc_flower_key, ipv4.ipv4_src),\n+          MEMBER_SIZEOF(struct tc_flower_key, ipv4.ipv4_src)\n+        },\n+        { offsetof(struct ovs_key_ipv4, ipv4_dst),\n+          offsetof(struct tc_flower_key, ipv4.ipv4_dst),\n+          MEMBER_SIZEOF(struct tc_flower_key, ipv4.ipv4_dst)\n+        },\n+        { offsetof(struct ovs_key_ipv4, ipv4_ttl),\n+          offsetof(struct tc_flower_key, ipv4.rewrite_ttl),\n+          MEMBER_SIZEOF(struct tc_flower_key, ipv4.rewrite_ttl)\n+        },\n+    },\n+    [OVS_KEY_ATTR_IPV6] = {\n+        { offsetof(struct ovs_key_ipv6, ipv6_src),\n+          offsetof(struct tc_flower_key, ipv6.ipv6_src),\n+          MEMBER_SIZEOF(struct tc_flower_key, ipv6.ipv6_src)\n+        },\n+        { offsetof(struct ovs_key_ipv6, ipv6_dst),\n+          offsetof(struct tc_flower_key, ipv6.ipv6_dst),\n+          MEMBER_SIZEOF(struct tc_flower_key, ipv6.ipv6_dst)\n+        },\n+    },\n+    [OVS_KEY_ATTR_ETHERNET] = {\n+        { offsetof(struct ovs_key_ethernet, eth_src),\n+          offsetof(struct tc_flower_key, src_mac),\n+          MEMBER_SIZEOF(struct tc_flower_key, src_mac)\n+        },\n+        { offsetof(struct ovs_key_ethernet, eth_dst),\n+          offsetof(struct tc_flower_key, dst_mac),\n+          MEMBER_SIZEOF(struct tc_flower_key, dst_mac)\n+        },\n+    },\n+    [OVS_KEY_ATTR_ETHERTYPE] = {\n+        { 0,\n+          offsetof(struct tc_flower_key, eth_type),\n+          MEMBER_SIZEOF(struct tc_flower_key, eth_type)\n+        },\n+    },\n+    [OVS_KEY_ATTR_TCP] = {\n+        { offsetof(struct ovs_key_tcp, tcp_src),\n+          offsetof(struct tc_flower_key, tcp_src),\n+          MEMBER_SIZEOF(struct tc_flower_key, tcp_src)\n+        },\n+        { offsetof(struct ovs_key_tcp, tcp_dst),\n+          offsetof(struct tc_flower_key, tcp_dst),\n+          MEMBER_SIZEOF(struct tc_flower_key, tcp_dst)\n+        },\n+    },\n+    [OVS_KEY_ATTR_UDP] = {\n+        { offsetof(struct ovs_key_udp, udp_src),\n+          offsetof(struct tc_flower_key, udp_src),\n+          MEMBER_SIZEOF(struct tc_flower_key, udp_src)\n+        },\n+        { offsetof(struct ovs_key_udp, udp_dst),\n+          offsetof(struct tc_flower_key, udp_dst),\n+          MEMBER_SIZEOF(struct tc_flower_key, udp_dst)\n+        },\n+    },\n+};\n+\n static struct ovs_mutex ufid_lock = OVS_MUTEX_INITIALIZER;\n \n /**\n@@ -274,6 +346,48 @@ netdev_tc_flow_dump_destroy(struct netdev_flow_dump *dump)\n     return 0;\n }\n \n+static void\n+parse_flower_rewrite_to_netlink_action(struct ofpbuf *buf,\n+                                       struct tc_flower *flower)\n+{\n+    char *mask = (char *) &flower->rewrite.mask;\n+    char *data = (char *) &flower->rewrite.key;\n+\n+    for (int type = 0; type < ARRAY_SIZE(set_flower_map); type++) {\n+        char *put = NULL;\n+        size_t nested = 0;\n+        int len = ovs_flow_key_attr_lens[type].len;\n+\n+        if (len <= 0) {\n+            continue;\n+        }\n+\n+        for (int j = 0; j < ARRAY_SIZE(set_flower_map[type]); j++) {\n+            struct netlink_field *f = &set_flower_map[type][j];\n+\n+            if (!f->size) {\n+                break;\n+            }\n+\n+            if (!is_all_zeros(mask + f->flower_offset, f->size)) {\n+                if (!put) {\n+                    nested = nl_msg_start_nested(buf,\n+                                                 OVS_ACTION_ATTR_SET_MASKED);\n+                    put = nl_msg_put_unspec_zero(buf, type, len * 2);\n+                }\n+\n+                memcpy(put + f->offset, data + f->flower_offset, f->size);\n+                memcpy(put + len + f->offset,\n+                       mask + f->flower_offset, f->size);\n+            }\n+        }\n+\n+        if (put) {\n+            nl_msg_end_nested(buf, nested);\n+        }\n+    }\n+}\n+\n static int\n parse_tc_flower_to_match(struct tc_flower *flower,\n                          struct match *match,\n@@ -367,6 +481,10 @@ parse_tc_flower_to_match(struct tc_flower *flower,\n                                    | VLAN_CFI);\n         }\n \n+        if (flower->rewrite.rewrite) {\n+            parse_flower_rewrite_to_netlink_action(buf, flower);\n+        }\n+\n         if (flower->set.set) {\n             size_t set_offset = nl_msg_start_nested(buf, OVS_ACTION_ATTR_SET);\n             size_t tunnel_offset =\n@@ -457,14 +575,77 @@ netdev_tc_flow_dump_next(struct netdev_flow_dump *dump,\n }\n \n static int\n+parse_put_flow_set_masked_action(struct tc_flower *flower,\n+                                 const struct nlattr *set,\n+                                 size_t set_len,\n+                                 bool hasmask)\n+{\n+    static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20);\n+    char *set_buff[set_len], *set_data, *set_mask;\n+    char *key = (char *) &flower->rewrite.key;\n+    char *mask = (char *) &flower->rewrite.mask;\n+    const struct nlattr *attr;\n+    int i, j, type;\n+    size_t size;\n+\n+    /* copy so we can set attr mask to 0 for used ovs key struct members  */\n+    memcpy(set_buff, set, set_len);\n+    attr = (struct nlattr *) set_buff;\n+\n+    type = nl_attr_type(attr);\n+    size = nl_attr_get_size(attr) / 2;\n+    set_data = CONST_CAST(char *, nl_attr_get(attr));\n+    set_mask = set_data + size;\n+\n+    if (type >= ARRAY_SIZE(set_flower_map)\n+        || !set_flower_map[type][0].size) {\n+        VLOG_DBG_RL(&rl, \"unsupported set action type: %d\", type);\n+        return EOPNOTSUPP;\n+    }\n+\n+    for (i = 0; i < ARRAY_SIZE(set_flower_map[type]); i++) {\n+        struct netlink_field *f = &set_flower_map[type][i];\n+\n+        if (!f->size) {\n+            break;\n+        }\n+\n+        /* copy masked value */\n+        for (j = 0; j < f->size; j++) {\n+            char maskval = hasmask ? set_mask[f->offset + j] : 0xFF;\n+\n+            key[f->flower_offset + j] = maskval & set_data[f->offset + j];\n+            mask[f->flower_offset + j] = maskval;\n+\n+        }\n+\n+        /* set its mask to 0 to show it's been used. */\n+        if (hasmask) {\n+            memset(set_mask + f->offset, 0, f->size);\n+        }\n+    }\n+\n+    if (!is_all_zeros(&flower->rewrite, sizeof flower->rewrite)) {\n+        flower->rewrite.rewrite = true;\n+    }\n+\n+    if (hasmask && !is_all_zeros(set_mask, size)) {\n+        VLOG_DBG_RL(&rl, \"unsupported sub attribute of set action type %d\",\n+                    type);\n+        return EOPNOTSUPP;\n+    }\n+\n+    return 0;\n+}\n+\n+static int\n parse_put_flow_set_action(struct tc_flower *flower, const struct nlattr *set,\n                           size_t set_len)\n {\n-    static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20);\n     const struct nlattr *set_attr;\n     size_t set_left;\n \n-    NL_ATTR_FOR_EACH_UNSAFE(set_attr, set_left, set, set_len) {\n+    NL_ATTR_FOR_EACH_UNSAFE (set_attr, set_left, set, set_len) {\n         if (nl_attr_type(set_attr) == OVS_KEY_ATTR_TUNNEL) {\n             const struct nlattr *tunnel = nl_attr_get(set_attr);\n             const size_t tunnel_len = nl_attr_get_size(set_attr);\n@@ -472,7 +653,7 @@ parse_put_flow_set_action(struct tc_flower *flower, const struct nlattr *set,\n             size_t tun_left;\n \n             flower->set.set = true;\n-            NL_ATTR_FOR_EACH_UNSAFE(tun_attr, tun_left, tunnel, tunnel_len) {\n+            NL_ATTR_FOR_EACH_UNSAFE (tun_attr, tun_left, tunnel, tunnel_len) {\n                 switch (nl_attr_type(tun_attr)) {\n                 case OVS_TUNNEL_KEY_ATTR_ID: {\n                     flower->set.id = nl_attr_get_be64(tun_attr);\n@@ -507,9 +688,8 @@ parse_put_flow_set_action(struct tc_flower *flower, const struct nlattr *set,\n                 }\n             }\n         } else {\n-            VLOG_DBG_RL(&rl, \"unsupported set action type: %d\",\n-                        nl_attr_type(set_attr));\n-            return EOPNOTSUPP;\n+            return parse_put_flow_set_masked_action(flower, set, set_len,\n+                                                    false);\n         }\n     }\n     return 0;\n@@ -827,6 +1007,15 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match,\n             if (err) {\n                 return err;\n             }\n+        } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_SET_MASKED) {\n+            const struct nlattr *set = nl_attr_get(nla);\n+            const size_t set_len = nl_attr_get_size(nla);\n+\n+            err = parse_put_flow_set_masked_action(&flower, set, set_len,\n+                                                   true);\n+            if (err) {\n+                return err;\n+            }\n         } else {\n             VLOG_DBG_RL(&rl, \"unsupported put action type: %d\",\n                         nl_attr_type(nla));\n","prefixes":["ovs-dev","V2","4/4"]}