net/mlx5: add fate actions to switch flow rules
authorAdrien Mazarguil <adrien.mazarguil@6wind.com>
Fri, 13 Jul 2018 09:40:41 +0000 (11:40 +0200)
committerThomas Monjalon <thomas@monjalon.net>
Thu, 26 Jul 2018 12:05:52 +0000 (14:05 +0200)
This patch enables creation of rte_flow rules that direct matching traffic
to a different port (e.g. another VF representor) or drop it directly at
the switch level (PORT_ID and DROP actions).

Testpmd examples:

- Directing all traffic to port ID 0:

  flow create 1 ingress transfer pattern end actions port_id id 0 / end

- Dropping all traffic normally received by port ID 1:

  flow create 1 ingress transfer pattern end actions drop / end

Note the presence of the transfer attribute, which requests them to be
applied at the switch level. All traffic is matched due to empty pattern.

Signed-off-by: Adrien Mazarguil <adrien.mazarguil@6wind.com>
Acked-by: Nelio Laranjeiro <nelio.laranjeiro@6wind.com>
Acked-by: Yongseok Koh <yskoh@mellanox.com>
drivers/net/mlx5/mlx5_nl_flow.c

index a9a5bac..42b7c65 100644 (file)
@@ -10,6 +10,8 @@
 #include <linux/pkt_cls.h>
 #include <linux/pkt_sched.h>
 #include <linux/rtnetlink.h>
+#include <linux/tc_act/tc_gact.h>
+#include <linux/tc_act/tc_mirred.h>
 #include <stdalign.h>
 #include <stddef.h>
 #include <stdint.h>
@@ -52,6 +54,8 @@ enum mlx5_nl_flow_trans {
        ITEM_VOID,
        ACTIONS,
        ACTION_VOID,
+       ACTION_PORT_ID,
+       ACTION_DROP,
        END,
 };
 
@@ -60,7 +64,9 @@ enum mlx5_nl_flow_trans {
 #define PATTERN_COMMON \
        ITEM_VOID, ACTIONS
 #define ACTIONS_COMMON \
-       ACTION_VOID, END
+       ACTION_VOID
+#define ACTIONS_FATE \
+       ACTION_PORT_ID, ACTION_DROP
 
 /** Parser state transitions used by mlx5_nl_flow_transpose(). */
 static const enum mlx5_nl_flow_trans *const mlx5_nl_flow_trans[] = {
@@ -69,8 +75,10 @@ static const enum mlx5_nl_flow_trans *const mlx5_nl_flow_trans[] = {
        [ATTR] = TRANS(PATTERN),
        [PATTERN] = TRANS(PATTERN_COMMON),
        [ITEM_VOID] = TRANS(BACK),
-       [ACTIONS] = TRANS(ACTIONS_COMMON),
+       [ACTIONS] = TRANS(ACTIONS_FATE, ACTIONS_COMMON),
        [ACTION_VOID] = TRANS(BACK),
+       [ACTION_PORT_ID] = TRANS(ACTION_VOID, END),
+       [ACTION_DROP] = TRANS(ACTION_VOID, END),
        [END] = NULL,
 };
 
@@ -119,6 +127,7 @@ mlx5_nl_flow_transpose(void *buf,
        const struct rte_flow_item *item;
        const struct rte_flow_action *action;
        unsigned int n;
+       uint32_t act_index_cur;
        struct nlattr *na_flower;
        struct nlattr *na_flower_act;
        const enum mlx5_nl_flow_trans *trans;
@@ -130,14 +139,21 @@ init:
        item = pattern;
        action = actions;
        n = 0;
+       act_index_cur = 0;
        na_flower = NULL;
        na_flower_act = NULL;
        trans = TRANS(ATTR);
        back = trans;
 trans:
        switch (trans[n++]) {
+               union {
+                       const struct rte_flow_action_port_id *port_id;
+               } conf;
                struct nlmsghdr *nlh;
                struct tcmsg *tcm;
+               struct nlattr *act_index;
+               struct nlattr *act;
+               unsigned int i;
 
        case INVALID:
                if (item->type)
@@ -228,12 +244,69 @@ trans:
                        mnl_attr_nest_start_check(buf, size, TCA_FLOWER_ACT);
                if (!na_flower_act)
                        goto error_nobufs;
+               act_index_cur = 1;
                break;
        case ACTION_VOID:
                if (action->type != RTE_FLOW_ACTION_TYPE_VOID)
                        goto trans;
                ++action;
                break;
+       case ACTION_PORT_ID:
+               if (action->type != RTE_FLOW_ACTION_TYPE_PORT_ID)
+                       goto trans;
+               conf.port_id = action->conf;
+               if (conf.port_id->original)
+                       i = 0;
+               else
+                       for (i = 0; ptoi[i].ifindex; ++i)
+                               if (ptoi[i].port_id == conf.port_id->id)
+                                       break;
+               if (!ptoi[i].ifindex)
+                       return rte_flow_error_set
+                               (error, ENODEV, RTE_FLOW_ERROR_TYPE_ACTION_CONF,
+                                conf.port_id,
+                                "missing data to convert port ID to ifindex");
+               act_index =
+                       mnl_attr_nest_start_check(buf, size, act_index_cur++);
+               if (!act_index ||
+                   !mnl_attr_put_strz_check(buf, size, TCA_ACT_KIND, "mirred"))
+                       goto error_nobufs;
+               act = mnl_attr_nest_start_check(buf, size, TCA_ACT_OPTIONS);
+               if (!act)
+                       goto error_nobufs;
+               if (!mnl_attr_put_check(buf, size, TCA_MIRRED_PARMS,
+                                       sizeof(struct tc_mirred),
+                                       &(struct tc_mirred){
+                                               .action = TC_ACT_STOLEN,
+                                               .eaction = TCA_EGRESS_REDIR,
+                                               .ifindex = ptoi[i].ifindex,
+                                       }))
+                       goto error_nobufs;
+               mnl_attr_nest_end(buf, act);
+               mnl_attr_nest_end(buf, act_index);
+               ++action;
+               break;
+       case ACTION_DROP:
+               if (action->type != RTE_FLOW_ACTION_TYPE_DROP)
+                       goto trans;
+               act_index =
+                       mnl_attr_nest_start_check(buf, size, act_index_cur++);
+               if (!act_index ||
+                   !mnl_attr_put_strz_check(buf, size, TCA_ACT_KIND, "gact"))
+                       goto error_nobufs;
+               act = mnl_attr_nest_start_check(buf, size, TCA_ACT_OPTIONS);
+               if (!act)
+                       goto error_nobufs;
+               if (!mnl_attr_put_check(buf, size, TCA_GACT_PARMS,
+                                       sizeof(struct tc_gact),
+                                       &(struct tc_gact){
+                                               .action = TC_ACT_SHOT,
+                                       }))
+                       goto error_nobufs;
+               mnl_attr_nest_end(buf, act);
+               mnl_attr_nest_end(buf, act_index);
+               ++action;
+               break;
        case END:
                if (item->type != RTE_FLOW_ITEM_TYPE_END ||
                    action->type != RTE_FLOW_ACTION_TYPE_END)