Show a patch.

GET /api/patches/44088/
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 44088,
    "url": "http://patches.dpdk.org/api/patches/44088/",
    "web_url": "http://patches.dpdk.org/patch/44088/",
    "project": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/projects/1/",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk"
    },
    "msgid": "<20180831092038.23051-9-adrien.mazarguil@6wind.com>",
    "date": "2018-08-31T09:57:42",
    "name": "[8/8] net/mlx5: add VXLAN decap support to switch flow rules",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "69f208a3a9974004cfae8f733c868106e01f8ade",
    "submitter": {
        "id": 165,
        "url": "http://patches.dpdk.org/api/people/165/",
        "name": "Adrien Mazarguil",
        "email": "adrien.mazarguil@6wind.com"
    },
    "delegate": null,
    "mbox": "http://patches.dpdk.org/patch/44088/mbox/",
    "series": [
        {
            "id": 1126,
            "url": "http://patches.dpdk.org/api/series/1126/",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=1126",
            "date": "2018-08-31T09:57:25",
            "name": "net/mlx5: add switch offload for VXLAN encap/decap",
            "version": 1,
            "mbox": "http://patches.dpdk.org/series/1126/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/44088/comments/",
    "check": "success",
    "checks": "http://patches.dpdk.org/api/patches/44088/checks/",
    "tags": {},
    "headers": {
        "X-Mailman-Version": "2.1.15",
        "In-Reply-To": "<20180831092038.23051-1-adrien.mazarguil@6wind.com>",
        "Errors-To": "dev-bounces@dpdk.org",
        "X-Mailer": "git-send-email 2.11.0",
        "Received": [
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id 767D65B12;\n\tFri, 31 Aug 2018 11:58:01 +0200 (CEST)",
            "from mail-wr1-f65.google.com (mail-wr1-f65.google.com\n\t[209.85.221.65]) by dpdk.org (Postfix) with ESMTP id 45CBD56A3\n\tfor <dev@dpdk.org>; Fri, 31 Aug 2018 11:57:59 +0200 (CEST)",
            "by mail-wr1-f65.google.com with SMTP id k5-v6so10645824wre.10\n\tfor <dev@dpdk.org>; Fri, 31 Aug 2018 02:57:59 -0700 (PDT)",
            "from 6wind.com (host.78.145.23.62.rev.coltfrance.com.\n\t[62.23.145.78]) by smtp.gmail.com with ESMTPSA id\n\tw18-v6sm17932841wrc.38.2018.08.31.02.57.57\n\t(version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128);\n\tFri, 31 Aug 2018 02:57:57 -0700 (PDT)"
        ],
        "References": "<20180831092038.23051-1-adrien.mazarguil@6wind.com>",
        "X-Google-Smtp-Source": "ANB0VdY66NKdg9Llreut7pcgCgBoeXobkC+E55FQMPOTSpgfgI8GEA+Bsk/3+NhdenOH9S9/Kd5QtQ==",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=6wind-com.20150623.gappssmtp.com; s=20150623;\n\th=date:from:to:cc:subject:message-id:references:mime-version\n\t:content-disposition:in-reply-to;\n\tbh=LDoEkiB2jjXWLjIFJsSp5wuCcF0Glyx6+3uYifksTa0=;\n\tb=Pt14yg0SA8vZiInpi+SrURIt3ODMOgTBPKDy4o2cRFP6tKcGdjitN/7mc6MmxvZvaN\n\tkVRZpSNZBibPNzCP8XTqOSYPLErbU9H/5W+QCJ85emT1DpH9phqMVOz1yluXPj3uyOmy\n\tiPtgzJTKO7QVC1irYYJIzMUIfZodDHKmnBsc4G8/+MVWoOtYm0ungBgZecdLXGvml+Fw\n\t16JefN+Q2JGsci+sB5sQDQ3hD4BoWF5tNGgE4a5JyV9I3unzCs9h+71yTVtXhN1mXFmX\n\tx9IT7N/6//Yaspe3mIfV7nukfweQiLmXNjW9fZCrCl87GFXt50JBnN4qTPRf6sUWAQCQ\n\twMZw==",
        "MIME-Version": "1.0",
        "X-Received": "by 2002:a5d:6604:: with SMTP id\n\tn4-v6mr10133081wru.281.1535709478668; \n\tFri, 31 Aug 2018 02:57:58 -0700 (PDT)",
        "Message-ID": "<20180831092038.23051-9-adrien.mazarguil@6wind.com>",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:date:from:to:cc:subject:message-id:references\n\t:mime-version:content-disposition:in-reply-to;\n\tbh=LDoEkiB2jjXWLjIFJsSp5wuCcF0Glyx6+3uYifksTa0=;\n\tb=ATj4P6EeIaE+wS3SSBk2hu6tjhLbcey6weVWzAjGdfyWbA7yjqArbTpuH5hbofCkhG\n\txQOLT+xgT+MXIFsFTjYwp+qJlZBjTawrv2iCVeU7YkGnhb6CcrlIGZ0Z1njrtybrTbxl\n\t7DRyRJnfV0S5H436yAnGXUElGoLuo1qJIYOTnx8128sfnNjvYO0WnAZizzr4uhMeJou5\n\tM+TiQ6eY9appOSftA6n9ItNdQhLamz6AMEpmUQPJeHqb4sig0DiYpG++emyJbj4y57I/\n\tdsgQOEksU42R+1C2MFsruh8vmPc1/WsTRodzWCQQeh0a6ZHm7DFOoPuaFKqgMP3YkwIh\n\tG+Fw==",
        "Delivered-To": "patchwork@dpdk.org",
        "Precedence": "list",
        "From": "Adrien Mazarguil <adrien.mazarguil@6wind.com>",
        "X-Original-To": "patchwork@dpdk.org",
        "Content-Type": "text/plain; charset=us-ascii",
        "Content-Disposition": "inline",
        "Return-Path": "<dev-bounces@dpdk.org>",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "To": "Shahaf Shuler <shahafs@mellanox.com>, Yongseok Koh <yskoh@mellanox.com>, \n\tSlava Ovsiienko <viacheslavo@mellanox.com>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "Date": "Fri, 31 Aug 2018 11:57:42 +0200",
        "X-Gm-Message-State": "APzg51DWtc9FlAwfJr5X+6BAbNQzJAuD4jBQctbnI1fkIqvx4eG9+X4g\n\t0S9RMYkv7kfC9P5jO8IT4KCi+nzRng/Mlg==",
        "Cc": "dev@dpdk.org",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "X-BeenThere": "dev@dpdk.org",
        "Subject": "[dpdk-dev] [PATCH 8/8] net/mlx5: add VXLAN decap support to switch\n\tflow rules"
    },
    "content": "This provides support for the VXLAN_DECAP action. Outer tunnel properties\nare specified as the initial part of the flow rule pattern (up to and\nincluding VXLAN item), optionally followed by inner traffic properties.\n\nTestpmd examples:\n\n- Creating a flow on port ID 1 performing VXLAN decapsulation and directing\n  the result to port ID 2 without checking inner properties:\n\n  flow create 1 ingress transfer pattern eth src is 66:77:88:99:aa:bb\n     dst is 00:11:22:33:44:55 / ipv4 src is 2.2.2.2 dst is 1.1.1.1 /\n     udp src is 4789 dst is 4242 / vxlan vni is 0x112233 / end\n     actions vxlan_decap / port_id id 2 / end\n\n- Same as above except only inner TCPv6 packets with destination port 42\n  will be let through:\n\n  flow create 1 ingress transfer pattern eth src is 66:77:88:99:aa:bb\n     dst is 00:11:22:33:44:55 / ipv4 src is 2.2.2.2 dst is 1.1.1.1 /\n     udp src is 4789 dst is 4242 / vxlan vni is 0x112233 /\n     eth / ipv6 / tcp dst is 42 / end\n     actions vxlan_decap / port_id id 2 / end\n\nSigned-off-by: Adrien Mazarguil <adrien.mazarguil@6wind.com>\n---\n drivers/net/mlx5/Makefile       |  65 +++++++\n drivers/net/mlx5/mlx5_nl_flow.c | 344 ++++++++++++++++++++++++++++++++---\n 2 files changed, 379 insertions(+), 30 deletions(-)",
    "diff": "diff --git a/drivers/net/mlx5/Makefile b/drivers/net/mlx5/Makefile\nindex 1ba4ce612..85672abd6 100644\n--- a/drivers/net/mlx5/Makefile\n+++ b/drivers/net/mlx5/Makefile\n@@ -335,6 +335,71 @@ mlx5_autoconf.h.new: $(RTE_SDK)/buildtools/auto-config-h.sh\n \t\tenum TCA_FLOWER_KEY_VLAN_ETH_TYPE \\\n \t\t$(AUTOCONF_OUTPUT)\n \t$Q sh -- '$<' '$@' \\\n+\t\tHAVE_TCA_FLOWER_KEY_ENC_KEY_ID \\\n+\t\tlinux/pkt_cls.h \\\n+\t\tenum TCA_FLOWER_KEY_ENC_KEY_ID \\\n+\t\t$(AUTOCONF_OUTPUT)\n+\t$Q sh -- '$<' '$@' \\\n+\t\tHAVE_TCA_FLOWER_KEY_ENC_IPV4_SRC \\\n+\t\tlinux/pkt_cls.h \\\n+\t\tenum TCA_FLOWER_KEY_ENC_IPV4_SRC \\\n+\t\t$(AUTOCONF_OUTPUT)\n+\t$Q sh -- '$<' '$@' \\\n+\t\tHAVE_TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK \\\n+\t\tlinux/pkt_cls.h \\\n+\t\tenum TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK \\\n+\t\t$(AUTOCONF_OUTPUT)\n+\t$Q sh -- '$<' '$@' \\\n+\t\tHAVE_TCA_FLOWER_KEY_ENC_IPV4_DST \\\n+\t\tlinux/pkt_cls.h \\\n+\t\tenum TCA_FLOWER_KEY_ENC_IPV4_DST \\\n+\t\t$(AUTOCONF_OUTPUT)\n+\t$Q sh -- '$<' '$@' \\\n+\t\tHAVE_TCA_FLOWER_KEY_ENC_IPV4_DST_MASK \\\n+\t\tlinux/pkt_cls.h \\\n+\t\tenum TCA_FLOWER_KEY_ENC_IPV4_DST_MASK \\\n+\t\t$(AUTOCONF_OUTPUT)\n+\t$Q sh -- '$<' '$@' \\\n+\t\tHAVE_TCA_FLOWER_KEY_ENC_IPV6_SRC \\\n+\t\tlinux/pkt_cls.h \\\n+\t\tenum TCA_FLOWER_KEY_ENC_IPV6_SRC \\\n+\t\t$(AUTOCONF_OUTPUT)\n+\t$Q sh -- '$<' '$@' \\\n+\t\tHAVE_TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK \\\n+\t\tlinux/pkt_cls.h \\\n+\t\tenum TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK \\\n+\t\t$(AUTOCONF_OUTPUT)\n+\t$Q sh -- '$<' '$@' \\\n+\t\tHAVE_TCA_FLOWER_KEY_ENC_IPV6_DST \\\n+\t\tlinux/pkt_cls.h \\\n+\t\tenum TCA_FLOWER_KEY_ENC_IPV6_DST \\\n+\t\t$(AUTOCONF_OUTPUT)\n+\t$Q sh -- '$<' '$@' \\\n+\t\tHAVE_TCA_FLOWER_KEY_ENC_IPV6_DST_MASK \\\n+\t\tlinux/pkt_cls.h \\\n+\t\tenum TCA_FLOWER_KEY_ENC_IPV6_DST_MASK \\\n+\t\t$(AUTOCONF_OUTPUT)\n+\t$Q sh -- '$<' '$@' \\\n+\t\tHAVE_TCA_FLOWER_KEY_ENC_UDP_SRC_PORT \\\n+\t\tlinux/pkt_cls.h \\\n+\t\tenum TCA_FLOWER_KEY_ENC_UDP_SRC_PORT \\\n+\t\t$(AUTOCONF_OUTPUT)\n+\t$Q sh -- '$<' '$@' \\\n+\t\tHAVE_TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK \\\n+\t\tlinux/pkt_cls.h \\\n+\t\tenum TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK \\\n+\t\t$(AUTOCONF_OUTPUT)\n+\t$Q sh -- '$<' '$@' \\\n+\t\tHAVE_TCA_FLOWER_KEY_ENC_UDP_DST_PORT \\\n+\t\tlinux/pkt_cls.h \\\n+\t\tenum TCA_FLOWER_KEY_ENC_UDP_DST_PORT \\\n+\t\t$(AUTOCONF_OUTPUT)\n+\t$Q sh -- '$<' '$@' \\\n+\t\tHAVE_TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK \\\n+\t\tlinux/pkt_cls.h \\\n+\t\tenum TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK \\\n+\t\t$(AUTOCONF_OUTPUT)\n+\t$Q sh -- '$<' '$@' \\\n \t\tHAVE_TC_ACT_VLAN \\\n \t\tlinux/tc_act/tc_vlan.h \\\n \t\tenum TCA_VLAN_PUSH_VLAN_PRIORITY \\\ndiff --git a/drivers/net/mlx5/mlx5_nl_flow.c b/drivers/net/mlx5/mlx5_nl_flow.c\nindex 672f92863..12802796a 100644\n--- a/drivers/net/mlx5/mlx5_nl_flow.c\n+++ b/drivers/net/mlx5/mlx5_nl_flow.c\n@@ -201,6 +201,45 @@ struct tc_tunnel_key {\n #ifndef HAVE_TCA_FLOWER_KEY_VLAN_ETH_TYPE\n #define TCA_FLOWER_KEY_VLAN_ETH_TYPE 25\n #endif\n+#ifndef HAVE_TCA_FLOWER_KEY_ENC_KEY_ID\n+#define TCA_FLOWER_KEY_ENC_KEY_ID 26\n+#endif\n+#ifndef HAVE_TCA_FLOWER_KEY_ENC_IPV4_SRC\n+#define TCA_FLOWER_KEY_ENC_IPV4_SRC 27\n+#endif\n+#ifndef HAVE_TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK\n+#define TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK 28\n+#endif\n+#ifndef HAVE_TCA_FLOWER_KEY_ENC_IPV4_DST\n+#define TCA_FLOWER_KEY_ENC_IPV4_DST 29\n+#endif\n+#ifndef HAVE_TCA_FLOWER_KEY_ENC_IPV4_DST_MASK\n+#define TCA_FLOWER_KEY_ENC_IPV4_DST_MASK 30\n+#endif\n+#ifndef HAVE_TCA_FLOWER_KEY_ENC_IPV6_SRC\n+#define TCA_FLOWER_KEY_ENC_IPV6_SRC 31\n+#endif\n+#ifndef HAVE_TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK\n+#define TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK 32\n+#endif\n+#ifndef HAVE_TCA_FLOWER_KEY_ENC_IPV6_DST\n+#define TCA_FLOWER_KEY_ENC_IPV6_DST 33\n+#endif\n+#ifndef HAVE_TCA_FLOWER_KEY_ENC_IPV6_DST_MASK\n+#define TCA_FLOWER_KEY_ENC_IPV6_DST_MASK 34\n+#endif\n+#ifndef HAVE_TCA_FLOWER_KEY_ENC_UDP_SRC_PORT\n+#define TCA_FLOWER_KEY_ENC_UDP_SRC_PORT 43\n+#endif\n+#ifndef HAVE_TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK\n+#define TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK 44\n+#endif\n+#ifndef HAVE_TCA_FLOWER_KEY_ENC_UDP_DST_PORT\n+#define TCA_FLOWER_KEY_ENC_UDP_DST_PORT 45\n+#endif\n+#ifndef HAVE_TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK\n+#define TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK 46\n+#endif\n \n #define BIT(b) (1 << (b))\n #define BIT_ENCAP(e) BIT(MLX5_NL_FLOW_ENCAP_ ## e)\n@@ -278,6 +317,7 @@ struct mlx5_nl_flow_ctx {\n struct mlx5_nl_flow {\n \tuint32_t size; /**< Size of this object. */\n \tuint32_t applied:1; /**< Whether rule is currently applied. */\n+\tuint32_t decap:1; /**< Decapsulate @p encap. */\n \tunsigned int encap_ifindex; /**< Interface to use with @p encap. */\n \tunsigned int *ifindex_src; /**< Source interface. */\n \tunsigned int *ifindex_dst; /**< Destination interface. */\n@@ -301,6 +341,11 @@ enum mlx5_nl_flow_trans {\n \tITEM_TCP,\n \tITEM_UDP,\n \tITEM_VXLAN,\n+\tITEM_VXLAN_END,\n+\tITEM_TUN_ETH,\n+\tITEM_TUN_IPV4,\n+\tITEM_TUN_IPV6,\n+\tITEM_TUN_UDP,\n \tACTIONS,\n \tACTION_VOID,\n \tACTION_PORT_ID,\n@@ -339,7 +384,12 @@ static const enum mlx5_nl_flow_trans *const mlx5_nl_flow_trans[] = {\n \t[ITEM_IPV6] = TRANS(ITEM_TCP, ITEM_UDP, PATTERN_COMMON),\n \t[ITEM_TCP] = TRANS(PATTERN_COMMON),\n \t[ITEM_UDP] = TRANS(ITEM_VXLAN, PATTERN_COMMON),\n-\t[ITEM_VXLAN] = TRANS(PATTERN_COMMON),\n+\t[ITEM_VXLAN] = TRANS(ITEM_TUN_ETH, PATTERN_COMMON),\n+\t[ITEM_VXLAN_END] = TRANS(ITEM_ETH, PATTERN_COMMON),\n+\t[ITEM_TUN_ETH] = TRANS(ITEM_TUN_IPV4, ITEM_TUN_IPV6, PATTERN_COMMON),\n+\t[ITEM_TUN_IPV4] = TRANS(ITEM_TUN_UDP, PATTERN_COMMON),\n+\t[ITEM_TUN_IPV6] = TRANS(ITEM_TUN_UDP, PATTERN_COMMON),\n+\t[ITEM_TUN_UDP] = TRANS(ITEM_VXLAN_END, ITEM_VOID, ITEM_PORT_ID),\n \t[ACTIONS] = TRANS(ACTIONS_FATE, ACTIONS_COMMON),\n \t[ACTION_VOID] = TRANS(BACK),\n \t[ACTION_PORT_ID] = TRANS(ACTION_VOID, END),\n@@ -805,6 +855,7 @@ mlx5_nl_flow_transpose(struct mlx5_nl_flow *nl_flow,\n \tbool vlan_present;\n \tbool vlan_eth_type_set;\n \tbool ip_proto_set;\n+\tbool vxlan_decap;\n \tstruct mlx5_nl_flow_encap encap;\n \tstruct nlattr *na_flower;\n \tstruct nlattr *na_flower_act;\n@@ -819,6 +870,7 @@ mlx5_nl_flow_transpose(struct mlx5_nl_flow *nl_flow,\n \t\tgoto error_nobufs;\n \tnl_flow->size = offsetof(struct mlx5_nl_flow, msg);\n \tnl_flow->applied = 0;\n+\tnl_flow->decap = 0;\n \tnl_flow->encap_ifindex = 0;\n \tnl_flow->ifindex_src = NULL;\n \tnl_flow->ifindex_dst = NULL;\n@@ -833,6 +885,7 @@ mlx5_nl_flow_transpose(struct mlx5_nl_flow *nl_flow,\n \tvlan_present = false;\n \tvlan_eth_type_set = false;\n \tip_proto_set = false;\n+\tvxlan_decap = false;\n \tmemset(&encap, 0, sizeof(encap));\n \tna_flower = NULL;\n \tna_flower_act = NULL;\n@@ -850,6 +903,7 @@ mlx5_nl_flow_transpose(struct mlx5_nl_flow *nl_flow,\n \t\t\tconst struct rte_flow_item_ipv6 *ipv6;\n \t\t\tconst struct rte_flow_item_tcp *tcp;\n \t\t\tconst struct rte_flow_item_udp *udp;\n+\t\t\tconst struct rte_flow_item_vxlan *vxlan;\n \t\t} spec, mask;\n \t\tunion {\n \t\t\tconst struct rte_flow_action_port_id *port_id;\n@@ -943,9 +997,6 @@ mlx5_nl_flow_transpose(struct mlx5_nl_flow *nl_flow,\n \t\tna_flower = mnl_attr_nest_start_check(buf, size, TCA_OPTIONS);\n \t\tif (!na_flower)\n \t\t\tgoto error_nobufs;\n-\t\tif (!mnl_attr_put_u32_check(buf, size, TCA_FLOWER_FLAGS,\n-\t\t\t\t\t    TCA_CLS_FLAGS_SKIP_SW))\n-\t\t\tgoto error_nobufs;\n \t\tbreak;\n \tcase ITEM_VOID:\n \t\tif (item->type != RTE_FLOW_ITEM_TYPE_VOID)\n@@ -1286,16 +1337,215 @@ mlx5_nl_flow_transpose(struct mlx5_nl_flow *nl_flow,\n \t\t++item;\n \t\tbreak;\n \tcase ITEM_VXLAN:\n+\tcase ITEM_VXLAN_END:\n \t\tif (item->type != RTE_FLOW_ITEM_TYPE_VXLAN)\n \t\t\tgoto trans;\n-\t\treturn rte_flow_error_set\n-\t\t\t(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM, item,\n-\t\t\t \"VXLAN header matching is not supported yet\");\n+\t\tif (vxlan_decap) {\n+\t\t\t/* Done with outer, continue with inner. */\n+\t\t\t++item;\n+\t\t\tbreak;\n+\t\t}\n+\t\tif (encap.mask)\n+\t\t\treturn rte_flow_error_set\n+\t\t\t\t(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\t item, \"no support for stacked encapsulation\");\n+\t\tmask.vxlan = mlx5_nl_flow_item_mask\n+\t\t\t(item, &rte_flow_item_vxlan_mask,\n+\t\t\t &mlx5_nl_flow_encap_mask_supported.vxlan,\n+\t\t\t &mlx5_nl_flow_mask_empty.vxlan,\n+\t\t\t sizeof(rte_flow_item_vxlan_mask), error);\n+\t\tif (!mask.vxlan)\n+\t\t\treturn -rte_errno;\n+\t\tspec.vxlan = item->spec;\n+\t\t/*\n+\t\t * No TCA_FLOWER_* to match VXLAN traffic. This can only be\n+\t\t * done indirectly through ACTION_VXLAN_DECAP.\n+\t\t *\n+\t\t * Since tunnel encapsulation information must be collected\n+\t\t * from the previous pattern items, the message built so far\n+\t\t * must be discarded, inner traffic will be matched by\n+\t\t * subsequent pattern items.\n+\t\t *\n+\t\t * Reset inner context and process pattern again through a\n+\t\t * different path.\n+\t\t */\n+\t\teth_type_set = false;\n+\t\tvlan_present = false;\n+\t\tvlan_eth_type_set = false;\n+\t\tip_proto_set = false;\n+\t\tnlh = buf;\n+\t\tmnl_attr_nest_cancel(nlh, na_flower);\n+\t\tna_flower = mnl_attr_nest_start_check(buf, size, TCA_OPTIONS);\n+\t\tif (!na_flower)\n+\t\t\tgoto error_nobufs;\n+\t\tif (memcmp(mask.vxlan->vni, VXLAN_VNI_MASK, 3))\n+\t\t\treturn rte_flow_error_set\n+\t\t\t\t(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM_MASK,\n+\t\t\t\t mask.vxlan,\n+\t\t\t\t \"VXLAN VNI is either incomplete or missing\");\n+\t\tif (!mnl_attr_put_u32_check(buf, size,\n+\t\t\t\t\t    TCA_FLOWER_KEY_ENC_KEY_ID,\n+\t\t\t\t\t    vxlan_vni_as_be32(spec.vxlan->vni)))\n+\t\t\tgoto error_nobufs;\n+\t\tencap.vxlan.vni = vxlan_vni_as_be32(spec.vxlan->vni);\n+\t\tencap.mask |= BIT_ENCAP(VXLAN_VNI);\n+\t\tvxlan_decap = true;\n+\t\titem = pattern;\n+\t\tbreak;\n+\tcase ITEM_TUN_ETH:\n+\t\tif (item->type != RTE_FLOW_ITEM_TYPE_ETH)\n+\t\t\tgoto trans;\n+\t\tmask.eth = mlx5_nl_flow_item_mask\n+\t\t\t(item, &rte_flow_item_eth_mask,\n+\t\t\t &mlx5_nl_flow_encap_mask_supported.eth,\n+\t\t\t &mlx5_nl_flow_mask_empty.eth,\n+\t\t\t sizeof(rte_flow_item_eth_mask), error);\n+\t\tif (!mask.eth)\n+\t\t\treturn -rte_errno;\n+\t\tspec.eth = item->spec;\n+\t\tif ((!is_zero_ether_addr(&mask.eth->dst) ||\n+\t\t     !is_zero_ether_addr(&mask.eth->src)) &&\n+\t\t    nl_flow != (void *)buf_tmp)\n+\t\t\tDRV_LOG(WARNING,\n+\t\t\t\t\"Ethernet source/destination addresses cannot\"\n+\t\t\t\t\" be matched along with VXLAN traffic;\"\n+\t\t\t\t\" parameters ignored\");\n+\t\t/* Source and destination are swapped for decap. */\n+\t\tif (is_broadcast_ether_addr(&mask.eth->dst)) {\n+\t\t\tencap.eth.src = spec.eth->dst;\n+\t\t\tencap.mask |= BIT_ENCAP(ETH_SRC);\n+\t\t}\n+\t\tif (is_broadcast_ether_addr(&mask.eth->src)) {\n+\t\t\tencap.eth.dst = spec.eth->src;\n+\t\t\tencap.mask |= BIT_ENCAP(ETH_DST);\n+\t\t}\n+\t\t++item;\n+\t\tbreak;\n+\tcase ITEM_TUN_IPV4:\n+\t\tif (item->type != RTE_FLOW_ITEM_TYPE_IPV4)\n+\t\t\tgoto trans;\n+\t\tmask.ipv4 = mlx5_nl_flow_item_mask\n+\t\t\t(item, &rte_flow_item_ipv4_mask,\n+\t\t\t &mlx5_nl_flow_encap_mask_supported.ipv4,\n+\t\t\t &mlx5_nl_flow_mask_empty.ipv4,\n+\t\t\t sizeof(rte_flow_item_ipv4_mask), error);\n+\t\tif (!mask.ipv4)\n+\t\t\treturn -rte_errno;\n+\t\tspec.ipv4 = item->spec;\n+\t\tif ((mask.ipv4->hdr.src_addr &&\n+\t\t     (!mnl_attr_put_u32_check(buf, size,\n+\t\t\t\t\t      TCA_FLOWER_KEY_ENC_IPV4_SRC,\n+\t\t\t\t\t      spec.ipv4->hdr.src_addr) ||\n+\t\t      !mnl_attr_put_u32_check(buf, size,\n+\t\t\t\t\t      TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK,\n+\t\t\t\t\t      mask.ipv4->hdr.src_addr))) ||\n+\t\t    (mask.ipv4->hdr.dst_addr &&\n+\t\t     (!mnl_attr_put_u32_check(buf, size,\n+\t\t\t\t\t      TCA_FLOWER_KEY_ENC_IPV4_DST,\n+\t\t\t\t\t      spec.ipv4->hdr.dst_addr) ||\n+\t\t      !mnl_attr_put_u32_check(buf, size,\n+\t\t\t\t\t      TCA_FLOWER_KEY_ENC_IPV4_DST_MASK,\n+\t\t\t\t\t      mask.ipv4->hdr.dst_addr))))\n+\t\t\tgoto error_nobufs;\n+\t\t/* Source and destination are swapped for decap. */\n+\t\tif (mask.ipv4->hdr.src_addr == IN_ADDR_MASK) {\n+\t\t\tencap.ip.dst.v4.s_addr = spec.ipv4->hdr.src_addr;\n+\t\t\tencap.mask |= BIT_ENCAP(IPV4_DST);\n+\t\t}\n+\t\tif (mask.ipv4->hdr.dst_addr == IN_ADDR_MASK) {\n+\t\t\tencap.ip.src.v4.s_addr = spec.ipv4->hdr.dst_addr;\n+\t\t\tencap.mask |= BIT_ENCAP(IPV4_SRC);\n+\t\t}\n+\t\t++item;\n+\t\tbreak;\n+\tcase ITEM_TUN_IPV6:\n+\t\tif (item->type != RTE_FLOW_ITEM_TYPE_IPV6)\n+\t\t\tgoto trans;\n+\t\tmask.ipv6 = mlx5_nl_flow_item_mask\n+\t\t\t(item, &rte_flow_item_ipv6_mask,\n+\t\t\t &mlx5_nl_flow_encap_mask_supported.ipv6,\n+\t\t\t &mlx5_nl_flow_mask_empty.ipv6,\n+\t\t\t sizeof(rte_flow_item_ipv6_mask), error);\n+\t\tif (!mask.ipv6)\n+\t\t\treturn -rte_errno;\n+\t\tspec.ipv6 = item->spec;\n+\t\tif ((!IN6_IS_ADDR_UNSPECIFIED(mask.ipv6->hdr.src_addr) &&\n+\t\t     (!mnl_attr_put_check(buf, size,\n+\t\t\t\t\t  TCA_FLOWER_KEY_ENC_IPV6_SRC,\n+\t\t\t\t\t  sizeof(spec.ipv6->hdr.src_addr),\n+\t\t\t\t\t  spec.ipv6->hdr.src_addr) ||\n+\t\t      !mnl_attr_put_check(buf, size,\n+\t\t\t\t\t  TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK,\n+\t\t\t\t\t  sizeof(mask.ipv6->hdr.src_addr),\n+\t\t\t\t\t  mask.ipv6->hdr.src_addr))) ||\n+\t\t    (!IN6_IS_ADDR_UNSPECIFIED(mask.ipv6->hdr.dst_addr) &&\n+\t\t     (!mnl_attr_put_check(buf, size,\n+\t\t\t\t\t  TCA_FLOWER_KEY_ENC_IPV6_DST,\n+\t\t\t\t\t  sizeof(spec.ipv6->hdr.dst_addr),\n+\t\t\t\t\t  spec.ipv6->hdr.dst_addr) ||\n+\t\t      !mnl_attr_put_check(buf, size,\n+\t\t\t\t\t  TCA_FLOWER_KEY_ENC_IPV6_DST_MASK,\n+\t\t\t\t\t  sizeof(mask.ipv6->hdr.dst_addr),\n+\t\t\t\t\t  mask.ipv6->hdr.dst_addr))))\n+\t\t\tgoto error_nobufs;\n+\t\t/* Source and destination are swapped for decap. */\n+\t\tif (!memcmp(mask.ipv6->hdr.src_addr, IN6_ADDR_MASK, 16)) {\n+\t\t\tencap.ip.dst.v6 =\n+\t\t\t\t*(struct in6_addr *)&spec.ipv6->hdr.src_addr;\n+\t\t\tencap.mask |= BIT_ENCAP(IPV6_DST);\n+\t\t}\n+\t\tif (!memcmp(mask.ipv6->hdr.dst_addr, IN6_ADDR_MASK, 16)) {\n+\t\t\tencap.ip.src.v6 =\n+\t\t\t\t*(struct in6_addr *)&spec.ipv6->hdr.dst_addr;\n+\t\t\tencap.mask |= BIT_ENCAP(IPV6_SRC);\n+\t\t}\n+\t\t++item;\n+\t\tbreak;\n+\tcase ITEM_TUN_UDP:\n+\t\tif (item->type != RTE_FLOW_ITEM_TYPE_UDP)\n+\t\t\tgoto trans;\n+\t\tmask.udp = mlx5_nl_flow_item_mask\n+\t\t\t(item, &rte_flow_item_udp_mask,\n+\t\t\t &mlx5_nl_flow_encap_mask_supported.udp,\n+\t\t\t &mlx5_nl_flow_mask_empty.udp,\n+\t\t\t sizeof(rte_flow_item_udp_mask), error);\n+\t\tif (!mask.udp)\n+\t\t\treturn -rte_errno;\n+\t\tspec.udp = item->spec;\n+\t\tif ((mask.udp->hdr.src_port &&\n+\t\t     (!mnl_attr_put_u16_check(buf, size,\n+\t\t\t\t\t      TCA_FLOWER_KEY_ENC_UDP_SRC_PORT,\n+\t\t\t\t\t      spec.udp->hdr.src_port) ||\n+\t\t      !mnl_attr_put_u16_check\n+\t\t\t(buf, size, TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK,\n+\t\t\t mask.udp->hdr.src_port))) ||\n+\t\t    (mask.udp->hdr.dst_port &&\n+\t\t     (!mnl_attr_put_u16_check(buf, size,\n+\t\t\t\t\t      TCA_FLOWER_KEY_ENC_UDP_DST_PORT,\n+\t\t\t\t\t      spec.udp->hdr.dst_port) ||\n+\t\t      !mnl_attr_put_u16_check\n+\t\t\t(buf, size, TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK,\n+\t\t\t mask.udp->hdr.dst_port))))\n+\t\t\tgoto error_nobufs;\n+\t\t/* Source and destination are swapped for decap. */\n+\t\tif (mask.udp->hdr.src_port == BE16_MASK) {\n+\t\t\tencap.udp.dst = spec.udp->hdr.src_port;\n+\t\t\tencap.mask |= BIT_ENCAP(UDP_DST);\n+\t\t}\n+\t\tif (mask.udp->hdr.dst_port == BE16_MASK) {\n+\t\t\tencap.udp.src = spec.udp->hdr.dst_port;\n+\t\t\tencap.mask |= BIT_ENCAP(UDP_SRC);\n+\t\t}\n+\t\t++item;\n+\t\tbreak;\n \tcase ACTIONS:\n \t\tif (item->type != RTE_FLOW_ITEM_TYPE_END)\n \t\t\tgoto trans;\n \t\tassert(na_flower);\n \t\tassert(!na_flower_act);\n+\t\tif (!mnl_attr_put_u32_check(buf, size, TCA_FLOWER_FLAGS,\n+\t\t\t\t\t    TCA_CLS_FLAGS_SKIP_SW))\n+\t\t\tgoto error_nobufs;\n \t\tna_flower_act =\n \t\t\tmnl_attr_nest_start_check(buf, size, TCA_FLOWER_ACT);\n \t\tif (!na_flower_act)\n@@ -1446,14 +1696,35 @@ mlx5_nl_flow_transpose(struct mlx5_nl_flow *nl_flow,\n \t\t}\n \t\t++action;\n \t\tbreak;\n+\tcase ACTION_VXLAN_DECAP:\n+\t\tif (action->type != RTE_FLOW_ACTION_TYPE_VXLAN_DECAP)\n+\t\t\tgoto trans;\n+\t\tif (!vxlan_decap)\n+\t\t\treturn rte_flow_error_set\n+\t\t\t\t(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION,\n+\t\t\t\t action,\n+\t\t\t\t \"VXLAN decapsulation is only supported after\"\n+\t\t\t\t \" matching VXLAN traffic explicitly first\");\n+\t\ti = TCA_TUNNEL_KEY_ACT_RELEASE;\n+\t\tnl_flow->decap = 1;\n+\t\tconf.vxlan_encap = NULL;\n+\t\tgoto vxlan_encap;\n \tcase ACTION_VXLAN_ENCAP:\n \t\tif (action->type != RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP)\n \t\t\tgoto trans;\n+\t\tif (vxlan_decap)\n+\t\t\treturn rte_flow_error_set\n+\t\t\t\t(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION,\n+\t\t\t\t action,\n+\t\t\t\t \"cannot combine VXLAN header matching with\"\n+\t\t\t\t \" encapsulation\");\n \t\tconf.vxlan_encap = action->conf;\n \t\tif (mlx5_nl_flow_encap_reap(&encap,\n \t\t\t\t\t    conf.vxlan_encap->definition,\n \t\t\t\t\t    error))\n \t\t\treturn -rte_errno;\n+\t\ti = TCA_TUNNEL_KEY_ACT_SET;\n+vxlan_encap:\n \t\tact_index =\n \t\t\tmnl_attr_nest_start_check(buf, size, act_index_cur++);\n \t\tif (!act_index ||\n@@ -1467,10 +1738,11 @@ mlx5_nl_flow_transpose(struct mlx5_nl_flow *nl_flow,\n \t\t\t\t\tsizeof(struct tc_tunnel_key),\n \t\t\t\t\t&(struct tc_tunnel_key){\n \t\t\t\t\t\t.action = TC_ACT_PIPE,\n-\t\t\t\t\t\t.t_action =\n-\t\t\t\t\t\t\tTCA_TUNNEL_KEY_ACT_SET,\n+\t\t\t\t\t\t.t_action = i,\n \t\t\t\t\t}))\n \t\t\tgoto error_nobufs;\n+\t\tif (!conf.vxlan_encap)\n+\t\t\tgoto vxlan_encap_end;\n \t\tif (encap.mask & BIT_ENCAP(IPV4_SRC) &&\n \t\t    !mnl_attr_put_u32_check\n \t\t    (buf, size, TCA_TUNNEL_KEY_ENC_IPV4_SRC,\n@@ -1507,16 +1779,11 @@ mlx5_nl_flow_transpose(struct mlx5_nl_flow *nl_flow,\n \t\tif (!mnl_attr_put_u32_check\n \t\t    (buf, size, TCA_TUNNEL_KEY_ENC_KEY_ID, encap.vxlan.vni))\n \t\t\tgoto error_nobufs;\n+vxlan_encap_end:\n \t\tmnl_attr_nest_end(buf, act);\n \t\tmnl_attr_nest_end(buf, act_index);\n \t\t++action;\n \t\tbreak;\n-\tcase ACTION_VXLAN_DECAP:\n-\t\tif (action->type != RTE_FLOW_ACTION_TYPE_VXLAN_DECAP)\n-\t\t\tgoto trans;\n-\t\treturn rte_flow_error_set\n-\t\t\t(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, action,\n-\t\t\t \"VXLAN decap is not supported yet\");\n \tcase END:\n \t\tif (item->type != RTE_FLOW_ITEM_TYPE_END ||\n \t\t    action->type != RTE_FLOW_ACTION_TYPE_END)\n@@ -1844,15 +2111,26 @@ mlx5_nl_flow_ifindex_vxlan(struct mlx5_nl_flow_ctx *ctx, unsigned int ifindex,\n \t * cannot be worked around by picking a random value here and using\n \t * a different one when creating flow rules later.\n \t *\n-\t * Therefore request a hopefully unique VNI based on the interface\n-\t * index in order to work around EEXIST. VNI will be overridden\n-\t * later on a flow rule basis thanks to IFLA_VXLAN_COLLECT_METADATA.\n+\t * There is another way to work around EEXIST by assigning a unique\n+\t * VNI to the VXLAN interface (e.g. by emitting IFLA_VXLAN_ID based\n+\t * on underlying ifindex), however doing so breaks decap as it\n+\t * prevents the kernel from matching VNI when looking for a VXLAN\n+\t * interface in that direction. Note that iproute2 doesn't allow\n+\t * this combination either.\n+\t *\n+\t * Creating non-external VXLAN interfaces with fixed outer\n+\t * properties was also considered. Problem is that not only it won't\n+\t * scale to large numbers, it appears that only interfaces with\n+\t * dynamic properties (external) can be offloaded to hardware.\n+\t *\n+\t * Hence the following limitation: as long as VXLAN encap/decap flow\n+\t * rules exist on a given DPDK port, the local UDP port they rely on\n+\t * can only be used by flow rules on that port. They will fail with\n+\t * EEXIST on others.\n \t */\n \tif (!mnl_attr_put_u16_check(nlh, sizeof(buf), IFLA_VXLAN_PORT,\n \t\t\t\t    vxlan_port))\n \t\tgoto exit;\n-\tif (!mnl_attr_put_u32_check(nlh, sizeof(buf), IFLA_VXLAN_ID, ifindex))\n-\t\tgoto exit;\n \tmnl_attr_nest_end(nlh, na_vxlan);\n \tmnl_attr_nest_end(nlh, na_info);\n \tret = mlx5_nl_flow_chat(ctx, nlh, NULL, NULL);\n@@ -2022,8 +2300,9 @@ mlx5_nl_flow_encap_neigh(struct mlx5_nl_flow_ctx *ctx,\n \t\tgoto error_nobufs;\n \tif (encap->mask & BIT_ENCAP(ETH_SRC) && enable)\n \t\tDRV_LOG(WARNING,\n-\t\t\t\"Ethernet source address cannot be forced\"\n-\t\t\t\" for VXLAN encap; parameter ignored\");\n+\t\t\t\"Ethernet source address (encap) or destination\"\n+\t\t\t\" address (decap) cannot be forced for VXLAN\"\n+\t\t\t\" encap/decap; parameter ignored\");\n \tif (encap->mask & BIT_ENCAP(ETH_DST) &&\n \t    !mnl_attr_put_check(nlh, sizeof(buf), NDA_LLADDR,\n \t\t\t\tsizeof(encap->eth.dst), &encap->eth.dst))\n@@ -2325,9 +2604,12 @@ mlx5_nl_flow_create(struct mlx5_nl_flow_ctx *ctx, struct mlx5_nl_flow *nl_flow,\n {\n \tstruct nlmsghdr *nlh = (void *)nl_flow->msg;\n \tstruct mlx5_nl_flow_encap *encap =\n-\t\tnl_flow->encap && nl_flow->ifindex_dst ?\n+\t\tnl_flow->encap && nl_flow->ifindex_dst && nl_flow->ifindex_src ?\n \t\tnl_flow->encap : NULL;\n-\tunsigned int ifindex = encap ? *nl_flow->ifindex_dst : 0;\n+\tunsigned int *ifindex_target =\n+\t\tnl_flow->decap ?\n+\t\tnl_flow->ifindex_src : nl_flow->ifindex_dst;\n+\tunsigned int ifindex = encap ? *ifindex_target : 0;\n \tint ret;\n \n \tif (nl_flow->applied)\n@@ -2339,11 +2621,11 @@ mlx5_nl_flow_create(struct mlx5_nl_flow_ctx *ctx, struct mlx5_nl_flow *nl_flow,\n \t\t\t(ctx, encap, ifindex, true, error);\n \t\tif (!nl_flow->encap_ifindex)\n \t\t\treturn -rte_errno;\n-\t\t*nl_flow->ifindex_dst = nl_flow->encap_ifindex;\n+\t\t*ifindex_target = nl_flow->encap_ifindex;\n \t}\n \tret = mlx5_nl_flow_chat(ctx, nlh, NULL, NULL);\n \tif (encap)\n-\t\t*nl_flow->ifindex_dst = ifindex;\n+\t\t*ifindex_target = ifindex;\n \tif (!ret) {\n \t\tnl_flow->applied = 1;\n \t\treturn 0;\n@@ -2378,9 +2660,11 @@ mlx5_nl_flow_destroy(struct mlx5_nl_flow_ctx *ctx, struct mlx5_nl_flow *nl_flow,\n {\n \tstruct nlmsghdr *nlh = (void *)nl_flow->msg;\n \tstruct mlx5_nl_flow_encap *encap =\n-\t\tnl_flow->encap && nl_flow->ifindex_dst ?\n+\t\tnl_flow->encap && nl_flow->ifindex_dst && nl_flow->ifindex_src ?\n \t\tnl_flow->encap : NULL;\n-\tunsigned int ifindex = encap ? *nl_flow->ifindex_dst : 0;\n+\tunsigned int *ifindex_target =\n+\t\tnl_flow->decap ? nl_flow->ifindex_src : nl_flow->ifindex_dst;\n+\tunsigned int ifindex = encap ? *ifindex_target : 0;\n \tint err = 0;\n \tint ret;\n \n@@ -2392,11 +2676,11 @@ mlx5_nl_flow_destroy(struct mlx5_nl_flow_ctx *ctx, struct mlx5_nl_flow *nl_flow,\n \t\tif (!mlx5_nl_flow_encap_ifindex\n \t\t    (ctx, encap, ifindex, false, error))\n \t\t\terr = rte_errno;\n-\t\t*nl_flow->ifindex_dst = nl_flow->encap_ifindex;\n+\t\t*ifindex_target = nl_flow->encap_ifindex;\n \t}\n \tret = mlx5_nl_flow_chat(ctx, nlh, NULL, NULL);\n \tif (encap)\n-\t\t*nl_flow->ifindex_dst = ifindex;\n+\t\t*ifindex_target = ifindex;\n \tnl_flow->applied = 0;\n \tif (err) {\n \t\trte_errno = err;\n",
    "prefixes": [
        "8/8"
    ]
}