net/mlx5: TC: Offload flow table rules
authorPaul Blakey <paulb@mellanox.com>
Mon, 11 Nov 2019 23:34:30 +0000 (00:34 +0100)
committerSaeed Mahameed <saeedm@mellanox.com>
Wed, 13 Nov 2019 22:25:04 +0000 (14:25 -0800)
Since both tc rules and flow table rules are of the same format,
we can re-use tc parsing for that, and move the flow table rules
to their steering domain - In this case, the next chain after
max tc chain.

Signed-off-by: Paul Blakey <paulb@mellanox.com>
Reviewed-by: Mark Bloch <markb@mellanox.com>
Acked-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
drivers/net/ethernet/mellanox/mlx5/core/en_tc.h

index c7f98f1fd9b12e11fb0557f4d92a0e7307e790e8..f175cb24bb6714a3a39a1e7548a1f1759c089aa1 100644 (file)
@@ -1244,21 +1244,60 @@ static int mlx5e_rep_setup_tc_cb(enum tc_setup_type type, void *type_data,
        }
 }
 
-static LIST_HEAD(mlx5e_rep_block_cb_list);
+static int mlx5e_rep_setup_ft_cb(enum tc_setup_type type, void *type_data,
+                                void *cb_priv)
+{
+       struct flow_cls_offload *f = type_data;
+       struct flow_cls_offload cls_flower;
+       struct mlx5e_priv *priv = cb_priv;
+       struct mlx5_eswitch *esw;
+       unsigned long flags;
+       int err;
+
+       flags = MLX5_TC_FLAG(INGRESS) |
+               MLX5_TC_FLAG(ESW_OFFLOAD) |
+               MLX5_TC_FLAG(FT_OFFLOAD);
+       esw = priv->mdev->priv.eswitch;
 
+       switch (type) {
+       case TC_SETUP_CLSFLOWER:
+               if (!mlx5_eswitch_prios_supported(esw) || f->common.chain_index)
+                       return -EOPNOTSUPP;
+
+               /* Re-use tc offload path by moving the ft flow to the
+                * reserved ft chain.
+                */
+               memcpy(&cls_flower, f, sizeof(*f));
+               cls_flower.common.chain_index = FDB_FT_CHAIN;
+               err = mlx5e_rep_setup_tc_cls_flower(priv, &cls_flower, flags);
+               memcpy(&f->stats, &cls_flower.stats, sizeof(f->stats));
+               return err;
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+static LIST_HEAD(mlx5e_rep_block_tc_cb_list);
+static LIST_HEAD(mlx5e_rep_block_ft_cb_list);
 static int mlx5e_rep_setup_tc(struct net_device *dev, enum tc_setup_type type,
                              void *type_data)
 {
        struct mlx5e_priv *priv = netdev_priv(dev);
        struct flow_block_offload *f = type_data;
 
+       f->unlocked_driver_cb = true;
+
        switch (type) {
        case TC_SETUP_BLOCK:
-               f->unlocked_driver_cb = true;
                return flow_block_cb_setup_simple(type_data,
-                                                 &mlx5e_rep_block_cb_list,
+                                                 &mlx5e_rep_block_tc_cb_list,
                                                  mlx5e_rep_setup_tc_cb,
                                                  priv, priv, true);
+       case TC_SETUP_FT:
+               return flow_block_cb_setup_simple(type_data,
+                                                 &mlx5e_rep_block_ft_cb_list,
+                                                 mlx5e_rep_setup_ft_cb,
+                                                 priv, priv, true);
        default:
                return -EOPNOTSUPP;
        }
index 0c1022cda1283526e7567f36b1578da30b39d737..3a707d7880223ee6e0d9f761cd9f03152dfa96ea 100644 (file)
@@ -74,6 +74,7 @@ enum {
        MLX5E_TC_FLOW_FLAG_INGRESS      = MLX5E_TC_FLAG_INGRESS_BIT,
        MLX5E_TC_FLOW_FLAG_EGRESS       = MLX5E_TC_FLAG_EGRESS_BIT,
        MLX5E_TC_FLOW_FLAG_ESWITCH      = MLX5E_TC_FLAG_ESW_OFFLOAD_BIT,
+       MLX5E_TC_FLOW_FLAG_FT           = MLX5E_TC_FLAG_FT_OFFLOAD_BIT,
        MLX5E_TC_FLOW_FLAG_NIC          = MLX5E_TC_FLAG_NIC_OFFLOAD_BIT,
        MLX5E_TC_FLOW_FLAG_OFFLOADED    = MLX5E_TC_FLOW_BASE,
        MLX5E_TC_FLOW_FLAG_HAIRPIN      = MLX5E_TC_FLOW_BASE + 1,
@@ -276,6 +277,11 @@ static bool mlx5e_is_eswitch_flow(struct mlx5e_tc_flow *flow)
        return flow_flag_test(flow, ESWITCH);
 }
 
+static bool mlx5e_is_ft_flow(struct mlx5e_tc_flow *flow)
+{
+       return flow_flag_test(flow, FT);
+}
+
 static bool mlx5e_is_offloaded_flow(struct mlx5e_tc_flow *flow)
 {
        return flow_flag_test(flow, OFFLOADED);
@@ -1168,7 +1174,12 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv,
                return -EOPNOTSUPP;
        }
 
-       if (attr->chain > max_chain) {
+       /* We check chain range only for tc flows.
+        * For ft flows, we checked attr->chain was originally 0 and set it to
+        * FDB_FT_CHAIN which is outside tc range.
+        * See mlx5e_rep_setup_ft_cb().
+        */
+       if (!mlx5e_is_ft_flow(flow) && attr->chain > max_chain) {
                NL_SET_ERR_MSG(extack, "Requested chain is out of supported range");
                return -EOPNOTSUPP;
        }
@@ -3217,6 +3228,7 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv,
        struct mlx5e_tc_flow_parse_attr *parse_attr = attr->parse_attr;
        struct mlx5e_rep_priv *rpriv = priv->ppriv;
        const struct ip_tunnel_info *info = NULL;
+       bool ft_flow = mlx5e_is_ft_flow(flow);
        const struct flow_action_entry *act;
        bool encap = false;
        u32 action = 0;
@@ -3261,6 +3273,14 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv,
                                return -EINVAL;
                        }
 
+                       if (ft_flow && out_dev == priv->netdev) {
+                               /* Ignore forward to self rules generated
+                                * by adding both mlx5 devs to the flow table
+                                * block on a normal nft offload setup.
+                                */
+                               return -EOPNOTSUPP;
+                       }
+
                        if (attr->out_count >= MLX5_MAX_FLOW_FWD_VPORTS) {
                                NL_SET_ERR_MSG_MOD(extack,
                                                   "can't support more output ports, can't offload forwarding");
@@ -3385,6 +3405,10 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv,
                        u32 dest_chain = act->chain_index;
                        u32 max_chain = mlx5_eswitch_get_chain_range(esw);
 
+                       if (ft_flow) {
+                               NL_SET_ERR_MSG_MOD(extack, "Goto action is not supported");
+                               return -EOPNOTSUPP;
+                       }
                        if (dest_chain <= attr->chain) {
                                NL_SET_ERR_MSG(extack, "Goto earlier chain isn't supported");
                                return -EOPNOTSUPP;
@@ -3475,6 +3499,8 @@ static void get_flags(int flags, unsigned long *flow_flags)
                __flow_flags |= BIT(MLX5E_TC_FLOW_FLAG_ESWITCH);
        if (flags & MLX5_TC_FLAG(NIC_OFFLOAD))
                __flow_flags |= BIT(MLX5E_TC_FLOW_FLAG_NIC);
+       if (flags & MLX5_TC_FLAG(FT_OFFLOAD))
+               __flow_flags |= BIT(MLX5E_TC_FLOW_FLAG_FT);
 
        *flow_flags = __flow_flags;
 }
index 924c6ef86a14bdbcbf5b5f9544714e5f4ea1d5c8..262cdb7b69b17e3d235e3300701ba8e9c9613186 100644 (file)
@@ -44,7 +44,8 @@ enum {
        MLX5E_TC_FLAG_EGRESS_BIT,
        MLX5E_TC_FLAG_NIC_OFFLOAD_BIT,
        MLX5E_TC_FLAG_ESW_OFFLOAD_BIT,
-       MLX5E_TC_FLAG_LAST_EXPORTED_BIT = MLX5E_TC_FLAG_ESW_OFFLOAD_BIT,
+       MLX5E_TC_FLAG_FT_OFFLOAD_BIT,
+       MLX5E_TC_FLAG_LAST_EXPORTED_BIT = MLX5E_TC_FLAG_FT_OFFLOAD_BIT,
 };
 
 #define MLX5_TC_FLAG(flag) BIT(MLX5E_TC_FLAG_##flag##_BIT)