rte_flow has 'group' attribute and 'jump' action in order to support
multiple groups. This feature is known as multi-table support ('chain' in
linux TC flower) in general because a group means a table of flows. Example
commands are:

        flow create 0 transfer priority 1 ingress
             pattern eth / vlan vid is 100 / end
             actions jump group 1 / end

        flow create 0 transfer priority 1 ingress
             pattern eth / vlan vid is 200 / end
             actions jump group 2 / end

        flow create 0 transfer group 1 priority 2 ingress
             pattern eth / vlan vid is 100 /
                     ipv4 dst spec 192.168.40.0 dst prefix 24 / end
             actions drop / end

        flow create 0 transfer group 1 priority 2 ingress
             pattern end
             actions of_pop_vlan / port_id id 1 / end

        flow create 0 transfer group 2 priority 2 ingress
             pattern eth / vlan vid is 200 /
                     ipv4 dst spec 192.168.40.0 dst prefix 24 / end
             actions of_pop_vlan / port_id id 2 / end

        flow create 0 transfer group 2 priority 2 ingress
             pattern end
             actions port_id id 2 / end

With theses flows, if a packet having vlan 200 and src_ip as 192.168.40.1,
this packet will firstly hit the 1st flow. Then it will hit the 5th flow
because of the 'jump' action. As a result, the packet will be forwarded to
port 2 (VF representor) with vlan tag being stripped off. If the packet had
vlan 100 instead, it would be dropped by the 3rd flow.

Signed-off-by: Yongseok Koh <ys...@mellanox.com>
---
 drivers/net/mlx5/Makefile        | 10 ++++++
 drivers/net/mlx5/meson.build     |  4 +++
 drivers/net/mlx5/mlx5_flow.h     |  5 +++
 drivers/net/mlx5/mlx5_flow_tcf.c | 78 +++++++++++++++++++++++++++++++++++-----
 4 files changed, 88 insertions(+), 9 deletions(-)

diff --git a/drivers/net/mlx5/Makefile b/drivers/net/mlx5/Makefile
index ca1de9f21..92bae9dfc 100644
--- a/drivers/net/mlx5/Makefile
+++ b/drivers/net/mlx5/Makefile
@@ -347,6 +347,16 @@ mlx5_autoconf.h.new: $(RTE_SDK)/buildtools/auto-config-h.sh
                enum TCA_VLAN_PUSH_VLAN_PRIORITY \
                $(AUTOCONF_OUTPUT)
        $Q sh -- '$<' '$@' \
+               HAVE_TCA_CHAIN \
+               linux/rtnetlink.h \
+               enum TCA_CHAIN \
+               $(AUTOCONF_OUTPUT)
+       $Q sh -- '$<' '$@' \
+               HAVE_TC_ACT_GOTO_CHAIN \
+               linux/pkt_cls.h \
+               define TC_ACT_GOTO_CHAIN \
+               $(AUTOCONF_OUTPUT)
+       $Q sh -- '$<' '$@' \
                HAVE_SUPPORTED_40000baseKR4_Full \
                /usr/include/linux/ethtool.h \
                define SUPPORTED_40000baseKR4_Full \
diff --git a/drivers/net/mlx5/meson.build b/drivers/net/mlx5/meson.build
index fd93ac162..696624838 100644
--- a/drivers/net/mlx5/meson.build
+++ b/drivers/net/mlx5/meson.build
@@ -182,6 +182,10 @@ if build
                'TCA_FLOWER_KEY_VLAN_ETH_TYPE' ],
                [ 'HAVE_TC_ACT_VLAN', 'linux/tc_act/tc_vlan.h',
                'TCA_VLAN_PUSH_VLAN_PRIORITY' ],
+               [ 'HAVE_TCA_CHAIN', 'linux/rtnetlink.h',
+               'TCA_CHAIN' ],
+               [ 'HAVE_TC_ACT_GOTO_CHAIN', 'linux/pkt_cls.h',
+               'TC_ACT_GOTO_CHAIN' ],
                [ 'HAVE_RDMA_NL_NLDEV', 'rdma/rdma_netlink.h',
                'RDMA_NL_NLDEV' ],
                [ 'HAVE_RDMA_NLDEV_CMD_GET', 'rdma/rdma_netlink.h',
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index 7117f1471..d4253110c 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -78,6 +78,7 @@
 #define MLX5_FLOW_ACTION_OF_PUSH_VLAN (1u << 8)
 #define MLX5_FLOW_ACTION_OF_SET_VLAN_VID (1u << 9)
 #define MLX5_FLOW_ACTION_OF_SET_VLAN_PCP (1u << 10)
+#define MLX5_FLOW_ACTION_JUMP (1u << 11)
 
 #define MLX5_FLOW_FATE_ACTIONS \
        (MLX5_FLOW_ACTION_DROP | MLX5_FLOW_ACTION_QUEUE | MLX5_FLOW_ACTION_RSS)
@@ -125,6 +126,10 @@
 /* Max number of actions per DV flow. */
 #define MLX5_DV_MAX_NUMBER_OF_ACTIONS 8
 
+/* Due to a limitation on driver/FW. */
+#define MLX5_FLOW_GROUP_ID_MAX 3
+#define MLX5_FLOW_GROUP_PRIORITY_MAX 14
+
 enum mlx5_flow_drv_type {
        MLX5_FLOW_TYPE_MIN,
        MLX5_FLOW_TYPE_DV,
diff --git a/drivers/net/mlx5/mlx5_flow_tcf.c b/drivers/net/mlx5/mlx5_flow_tcf.c
index 9ad66ac76..5d4a2e857 100644
--- a/drivers/net/mlx5/mlx5_flow_tcf.c
+++ b/drivers/net/mlx5/mlx5_flow_tcf.c
@@ -148,6 +148,12 @@ struct tc_vlan {
 #ifndef HAVE_TCA_FLOWER_KEY_VLAN_ETH_TYPE
 #define TCA_FLOWER_KEY_VLAN_ETH_TYPE 25
 #endif
+#ifndef HAVE_TCA_CHAIN
+#define TCA_CHAIN 11
+#endif
+#ifndef HAVE_TC_ACT_GOTO_CHAIN
+#define TC_ACT_GOTO_CHAIN 0x20000000
+#endif
 
 #ifndef IPV6_ADDR_LEN
 #define IPV6_ADDR_LEN 16
@@ -225,7 +231,9 @@ struct flow_tcf_ptoi {
        unsigned int ifindex; /**< Network interface index. */
 };
 
-#define MLX5_TCF_FATE_ACTIONS (MLX5_FLOW_ACTION_DROP | 
MLX5_FLOW_ACTION_PORT_ID)
+#define MLX5_TCF_FATE_ACTIONS \
+       (MLX5_FLOW_ACTION_DROP | MLX5_FLOW_ACTION_PORT_ID | \
+        MLX5_FLOW_ACTION_JUMP)
 #define MLX5_TCF_VLAN_ACTIONS \
        (MLX5_FLOW_ACTION_OF_POP_VLAN | MLX5_FLOW_ACTION_OF_PUSH_VLAN | \
         MLX5_FLOW_ACTION_OF_SET_VLAN_VID | MLX5_FLOW_ACTION_OF_SET_VLAN_PCP)
@@ -370,14 +378,25 @@ flow_tcf_validate_attributes(const struct rte_flow_attr 
*attr,
                             struct rte_flow_error *error)
 {
        /*
-        * Supported attributes: no groups, some priorities and ingress only.
-        * Don't care about transfer as it is the caller's problem.
+        * Supported attributes: groups, some priorities and ingress only.
+        * group is supported only if kernel supports chain. Don't care about
+        * transfer as it is the caller's problem.
         */
-       if (attr->group)
+       if (attr->group > MLX5_FLOW_GROUP_ID_MAX)
                return rte_flow_error_set(error, ENOTSUP,
                                          RTE_FLOW_ERROR_TYPE_ATTR_GROUP, attr,
-                                         "groups are not supported");
-       if (attr->priority > 0xfffe)
+                                         "group ID larger than "
+                                         RTE_STR(MLX5_FLOW_GROUP_ID_MAX)
+                                         " isn't supported");
+       else if (attr->group > 0 &&
+                attr->priority > MLX5_FLOW_GROUP_PRIORITY_MAX)
+               return rte_flow_error_set(error, ENOTSUP,
+                                         RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY,
+                                         attr,
+                                         "lowest priority level is "
+                                         RTE_STR(MLX5_FLOW_GROUP_PRIORITY_MAX)
+                                         " when group is configured");
+       else if (attr->priority > 0xfffe)
                return rte_flow_error_set(error, ENOTSUP,
                                          RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY,
                                          attr,
@@ -428,6 +447,7 @@ flow_tcf_validate(struct rte_eth_dev *dev,
        } spec, mask;
        union {
                const struct rte_flow_action_port_id *port_id;
+               const struct rte_flow_action_jump *jump;
                const struct rte_flow_action_of_push_vlan *of_push_vlan;
                const struct rte_flow_action_of_set_vlan_vid *
                        of_set_vlan_vid;
@@ -675,6 +695,16 @@ flow_tcf_validate(struct rte_eth_dev *dev,
                        action_flags |= MLX5_FLOW_ACTION_PORT_ID;
                        port_id_dev = &rte_eth_devices[conf.port_id->id];
                        break;
+               case RTE_FLOW_ACTION_TYPE_JUMP:
+                       conf.jump = actions->conf;
+                       if (attr->group >= conf.jump->group)
+                               return rte_flow_error_set
+                                       (error, ENOTSUP,
+                                        RTE_FLOW_ERROR_TYPE_ACTION,
+                                        actions,
+                                        "can't jump to a group backward");
+                       action_flags |= MLX5_FLOW_ACTION_JUMP;
+                       break;
                case RTE_FLOW_ACTION_TYPE_DROP:
                        if (action_flags & MLX5_TCF_FATE_ACTIONS)
                                return rte_flow_error_set
@@ -755,7 +785,8 @@ flow_tcf_validate(struct rte_eth_dev *dev,
  *   Maximum size of memory for items.
  */
 static int
-flow_tcf_get_items_and_size(const struct rte_flow_item items[],
+flow_tcf_get_items_and_size(const struct rte_flow_attr *attr,
+                           const struct rte_flow_item items[],
                            uint64_t *item_flags)
 {
        int size = 0;
@@ -764,6 +795,8 @@ flow_tcf_get_items_and_size(const struct rte_flow_item 
items[],
        size += SZ_NLATTR_STRZ_OF("flower") +
                SZ_NLATTR_NEST + /* TCA_OPTIONS. */
                SZ_NLATTR_TYPE_OF(uint32_t); /* TCA_CLS_FLAGS_SKIP_SW. */
+       if (attr->group > 0)
+               size += SZ_NLATTR_TYPE_OF(uint32_t); /* TCA_CHAIN. */
        for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
                switch (items->type) {
                case RTE_FLOW_ITEM_TYPE_VOID:
@@ -853,6 +886,13 @@ flow_tcf_get_actions_and_size(const struct rte_flow_action 
actions[],
                                SZ_NLATTR_TYPE_OF(struct tc_mirred);
                        flags |= MLX5_FLOW_ACTION_PORT_ID;
                        break;
+               case RTE_FLOW_ACTION_TYPE_JUMP:
+                       size += SZ_NLATTR_NEST + /* na_act_index. */
+                               SZ_NLATTR_STRZ_OF("gact") +
+                               SZ_NLATTR_NEST + /* TCA_ACT_OPTIONS. */
+                               SZ_NLATTR_TYPE_OF(struct tc_gact);
+                       flags |= MLX5_FLOW_ACTION_JUMP;
+                       break;
                case RTE_FLOW_ACTION_TYPE_DROP:
                        size += SZ_NLATTR_NEST + /* na_act_index. */
                                SZ_NLATTR_STRZ_OF("gact") +
@@ -938,7 +978,7 @@ flow_tcf_nl_brand(struct nlmsghdr *nlh, uint32_t handle)
  *   otherwise NULL and rte_ernno is set.
  */
 static struct mlx5_flow *
-flow_tcf_prepare(const struct rte_flow_attr *attr __rte_unused,
+flow_tcf_prepare(const struct rte_flow_attr *attr,
                 const struct rte_flow_item items[],
                 const struct rte_flow_action actions[],
                 uint64_t *item_flags, uint64_t *action_flags,
@@ -951,7 +991,7 @@ flow_tcf_prepare(const struct rte_flow_attr *attr 
__rte_unused,
        struct nlmsghdr *nlh;
        struct tcmsg *tcm;
 
-       size += flow_tcf_get_items_and_size(items, item_flags);
+       size += flow_tcf_get_items_and_size(attr, items, item_flags);
        size += flow_tcf_get_actions_and_size(actions, action_flags);
        dev_flow = rte_zmalloc(__func__, size, MNL_ALIGNTO);
        if (!dev_flow) {
@@ -1022,6 +1062,7 @@ flow_tcf_translate(struct rte_eth_dev *dev, struct 
mlx5_flow *dev_flow,
        } spec, mask;
        union {
                const struct rte_flow_action_port_id *port_id;
+               const struct rte_flow_action_jump *jump;
                const struct rte_flow_action_of_push_vlan *of_push_vlan;
                const struct rte_flow_action_of_set_vlan_vid *
                        of_set_vlan_vid;
@@ -1056,6 +1097,8 @@ flow_tcf_translate(struct rte_eth_dev *dev, struct 
mlx5_flow *dev_flow,
         */
        tcm->tcm_info = TC_H_MAKE((attr->priority + 1) << 16,
                                  RTE_BE16(ETH_P_ALL));
+       if (attr->group > 0)
+               mnl_attr_put_u32(nlh, TCA_CHAIN, attr->group);
        mnl_attr_put_strz(nlh, TCA_KIND, "flower");
        na_flower = mnl_attr_nest_start(nlh, TCA_OPTIONS);
        mnl_attr_put_u32(nlh, TCA_FLOWER_FLAGS, TCA_CLS_FLAGS_SKIP_SW);
@@ -1330,6 +1373,23 @@ flow_tcf_translate(struct rte_eth_dev *dev, struct 
mlx5_flow *dev_flow,
                        mnl_attr_nest_end(nlh, na_act);
                        mnl_attr_nest_end(nlh, na_act_index);
                        break;
+               case RTE_FLOW_ACTION_TYPE_JUMP:
+                       conf.jump = actions->conf;
+                       na_act_index =
+                               mnl_attr_nest_start(nlh, na_act_index_cur++);
+                       assert(na_act_index);
+                       mnl_attr_put_strz(nlh, TCA_ACT_KIND, "gact");
+                       na_act = mnl_attr_nest_start(nlh, TCA_ACT_OPTIONS);
+                       assert(na_act);
+                       mnl_attr_put(nlh, TCA_GACT_PARMS,
+                                    sizeof(struct tc_gact),
+                                    &(struct tc_gact){
+                                       .action = TC_ACT_GOTO_CHAIN |
+                                                 conf.jump->group,
+                                    });
+                       mnl_attr_nest_end(nlh, na_act);
+                       mnl_attr_nest_end(nlh, na_act_index);
+                       break;
                case RTE_FLOW_ACTION_TYPE_DROP:
                        na_act_index =
                                mnl_attr_nest_start(nlh, na_act_index_cur++);
-- 
2.11.0

Reply via email to