net/mlx5: Split FDB fast path prio to multiple namespaces
authorPaul Blakey <paulb@mellanox.com>
Tue, 3 Jul 2018 08:13:00 +0000 (11:13 +0300)
committerSaeed Mahameed <saeedm@mellanox.com>
Wed, 17 Oct 2018 21:18:16 +0000 (14:18 -0700)
Towards supporting multi-chains and priorities, split the FDB fast path
to multiple namespaces (sub namespaces), each with multiple priorities.

This patch adds a new flow steering type, FS_TYPE_PRIO_CHAINS, which is
like current FS_TYPE_PRIO, but may contain only namespaces, and those
will be in parallel to one another in terms of managing of the flow
tables connections inside them. Meaning, while searching for the next
or previous flow table to connect for a new table inside such namespace
we skip the parallel namespaces in the same level under the
FS_TYPE_PRIO_CHAINS prio we originated from.

We use this new type for splitting the fast path prio into multiple
parallel namespaces, each containing normal prios.
The prios inside them (and their tables) will be connected to one
another, but not from one parallel namespace to another, instead the
last prio in each namespace will be connected to the next prio in
the containing FDB namespace, which is the slow path prio.

Signed-off-by: Paul Blakey <paulb@mellanox.com>
Acked-by: Or Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
drivers/net/ethernet/mellanox/mlx5/core/fs_core.h
include/linux/mlx5/fs.h

index 9c893d7d273e185c01b81076a1979def05191634..d004957328f9ca9daa6b46c375310b1f20d1af31 100644 (file)
@@ -263,7 +263,7 @@ static int esw_create_legacy_fdb_table(struct mlx5_eswitch *esw)
        esw_debug(dev, "Create FDB log_max_size(%d)\n",
                  MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size));
 
-       root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_FDB);
+       root_ns = mlx5_get_fdb_sub_ns(dev, 0);
        if (!root_ns) {
                esw_warn(dev, "Failed to get FDB flow namespace\n");
                return -EOPNOTSUPP;
index c1b6275770038aa090bbcea382426ba052a80704..1698a322a7c461374eefbbca235a5064345d1ff4 100644 (file)
@@ -59,6 +59,9 @@
 #define mlx5_esw_has_fwd_fdb(dev) \
        MLX5_CAP_ESW_FLOWTABLE(dev, fdb_multi_path_to_table)
 
+#define FDB_MAX_CHAIN 3
+#define FDB_MAX_PRIO 16
+
 struct vport_ingress {
        struct mlx5_flow_table *acl;
        struct mlx5_flow_group *allow_untagged_spoofchk_grp;
@@ -319,6 +322,10 @@ static inline void mlx5_eswitch_cleanup(struct mlx5_eswitch *esw) {}
 static inline void mlx5_eswitch_vport_event(struct mlx5_eswitch *esw, struct mlx5_eqe *eqe) {}
 static inline int  mlx5_eswitch_enable_sriov(struct mlx5_eswitch *esw, int nvfs, int mode) { return 0; }
 static inline void mlx5_eswitch_disable_sriov(struct mlx5_eswitch *esw) {}
+
+#define FDB_MAX_CHAIN 1
+#define FDB_MAX_PRIO 1
+
 #endif /* CONFIG_MLX5_ESWITCH */
 
 #endif /* __MLX5_ESWITCH_H__ */
index cdcbf9d0ae6cf08e76be1d45d65842d9bf3095cd..7eb6d58733accb64ffa679a3c20d68d7fa7c2bf1 100644 (file)
@@ -40,6 +40,7 @@
 #include "diag/fs_tracepoint.h"
 #include "accel/ipsec.h"
 #include "fpga/ipsec.h"
+#include "eswitch.h"
 
 #define INIT_TREE_NODE_ARRAY_SIZE(...) (sizeof((struct init_tree_node[]){__VA_ARGS__}) /\
                                         sizeof(struct init_tree_node))
@@ -713,7 +714,7 @@ static struct mlx5_flow_table *find_closest_ft_recursive(struct fs_node  *root,
        struct fs_node *iter = list_entry(start, struct fs_node, list);
        struct mlx5_flow_table *ft = NULL;
 
-       if (!root)
+       if (!root || root->type == FS_TYPE_PRIO_CHAINS)
                return NULL;
 
        list_for_each_advance_continue(iter, &root->children, reverse) {
@@ -1973,6 +1974,18 @@ void mlx5_destroy_flow_group(struct mlx5_flow_group *fg)
                               fg->id);
 }
 
+struct mlx5_flow_namespace *mlx5_get_fdb_sub_ns(struct mlx5_core_dev *dev,
+                                               int n)
+{
+       struct mlx5_flow_steering *steering = dev->priv.steering;
+
+       if (!steering || !steering->fdb_sub_ns)
+               return NULL;
+
+       return steering->fdb_sub_ns[n];
+}
+EXPORT_SYMBOL(mlx5_get_fdb_sub_ns);
+
 struct mlx5_flow_namespace *mlx5_get_flow_namespace(struct mlx5_core_dev *dev,
                                                    enum mlx5_flow_namespace_type type)
 {
@@ -2051,8 +2064,10 @@ struct mlx5_flow_namespace *mlx5_get_flow_vport_acl_namespace(struct mlx5_core_d
        }
 }
 
-static struct fs_prio *fs_create_prio(struct mlx5_flow_namespace *ns,
-                                     unsigned int prio, int num_levels)
+static struct fs_prio *_fs_create_prio(struct mlx5_flow_namespace *ns,
+                                      unsigned int prio,
+                                      int num_levels,
+                                      enum fs_node_type type)
 {
        struct fs_prio *fs_prio;
 
@@ -2060,7 +2075,7 @@ static struct fs_prio *fs_create_prio(struct mlx5_flow_namespace *ns,
        if (!fs_prio)
                return ERR_PTR(-ENOMEM);
 
-       fs_prio->node.type = FS_TYPE_PRIO;
+       fs_prio->node.type = type;
        tree_init_node(&fs_prio->node, NULL, del_sw_prio);
        tree_add_node(&fs_prio->node, &ns->node);
        fs_prio->num_levels = num_levels;
@@ -2070,6 +2085,19 @@ static struct fs_prio *fs_create_prio(struct mlx5_flow_namespace *ns,
        return fs_prio;
 }
 
+static struct fs_prio *fs_create_prio_chained(struct mlx5_flow_namespace *ns,
+                                             unsigned int prio,
+                                             int num_levels)
+{
+       return _fs_create_prio(ns, prio, num_levels, FS_TYPE_PRIO_CHAINS);
+}
+
+static struct fs_prio *fs_create_prio(struct mlx5_flow_namespace *ns,
+                                     unsigned int prio, int num_levels)
+{
+       return _fs_create_prio(ns, prio, num_levels, FS_TYPE_PRIO);
+}
+
 static struct mlx5_flow_namespace *fs_init_namespace(struct mlx5_flow_namespace
                                                     *ns)
 {
@@ -2374,6 +2402,9 @@ void mlx5_cleanup_fs(struct mlx5_core_dev *dev)
        cleanup_egress_acls_root_ns(dev);
        cleanup_ingress_acls_root_ns(dev);
        cleanup_root_ns(steering->fdb_root_ns);
+       steering->fdb_root_ns = NULL;
+       kfree(steering->fdb_sub_ns);
+       steering->fdb_sub_ns = NULL;
        cleanup_root_ns(steering->sniffer_rx_root_ns);
        cleanup_root_ns(steering->sniffer_tx_root_ns);
        cleanup_root_ns(steering->egress_root_ns);
@@ -2419,27 +2450,64 @@ static int init_sniffer_rx_root_ns(struct mlx5_flow_steering *steering)
 
 static int init_fdb_root_ns(struct mlx5_flow_steering *steering)
 {
-       struct fs_prio *prio;
+       struct mlx5_flow_namespace *ns;
+       struct fs_prio *maj_prio;
+       struct fs_prio *min_prio;
+       int levels;
+       int chain;
+       int prio;
+       int err;
 
        steering->fdb_root_ns = create_root_ns(steering, FS_FT_FDB);
        if (!steering->fdb_root_ns)
                return -ENOMEM;
 
-       prio = fs_create_prio(&steering->fdb_root_ns->ns, 0, 2);
-       if (IS_ERR(prio))
+       steering->fdb_sub_ns = kzalloc(sizeof(steering->fdb_sub_ns) *
+                                      FDB_MAX_CHAIN + 1, GFP_KERNEL);
+       if (!steering->fdb_sub_ns)
+               return -ENOMEM;
+
+       levels = 2 * FDB_MAX_PRIO * (FDB_MAX_CHAIN + 1);
+       maj_prio = fs_create_prio_chained(&steering->fdb_root_ns->ns, 0,
+                                         levels);
+       if (IS_ERR(maj_prio)) {
+               err = PTR_ERR(maj_prio);
                goto out_err;
+       }
 
-       prio = fs_create_prio(&steering->fdb_root_ns->ns, 1, 1);
-       if (IS_ERR(prio))
+       for (chain = 0; chain <= FDB_MAX_CHAIN; chain++) {
+               ns = fs_create_namespace(maj_prio);
+               if (IS_ERR(ns)) {
+                       err = PTR_ERR(ns);
+                       goto out_err;
+               }
+
+               for (prio = 0; prio < FDB_MAX_PRIO * (chain + 1); prio++) {
+                       min_prio = fs_create_prio(ns, prio, 2);
+                       if (IS_ERR(min_prio)) {
+                               err = PTR_ERR(min_prio);
+                               goto out_err;
+                       }
+               }
+
+               steering->fdb_sub_ns[chain] = ns;
+       }
+
+       maj_prio = fs_create_prio(&steering->fdb_root_ns->ns, 1, 1);
+       if (IS_ERR(maj_prio)) {
+               err = PTR_ERR(maj_prio);
                goto out_err;
+       }
 
        set_prio_attrs(steering->fdb_root_ns);
        return 0;
 
 out_err:
        cleanup_root_ns(steering->fdb_root_ns);
+       kfree(steering->fdb_sub_ns);
+       steering->fdb_sub_ns = NULL;
        steering->fdb_root_ns = NULL;
-       return PTR_ERR(prio);
+       return err;
 }
 
 static int init_egress_acl_root_ns(struct mlx5_flow_steering *steering, int vport)
index a06f83c0c2b654d1475888fbc8088659f186fd2c..b51ad217da32d608a95a16909fd5577174a755d0 100644 (file)
 #include <linux/rhashtable.h>
 #include <linux/llist.h>
 
+/* FS_TYPE_PRIO_CHAINS is a PRIO that will have namespaces only,
+ * and those are in parallel to one another when going over them to connect
+ * a new flow table. Meaning the last flow table in a TYPE_PRIO prio in one
+ * parallel namespace will not automatically connect to the first flow table
+ * found in any prio in any next namespace, but skip the entire containing
+ * TYPE_PRIO_CHAINS prio.
+ *
+ * This is used to implement tc chains, each chain of prios is a different
+ * namespace inside a containing TYPE_PRIO_CHAINS prio.
+ */
+
 enum fs_node_type {
        FS_TYPE_NAMESPACE,
        FS_TYPE_PRIO,
+       FS_TYPE_PRIO_CHAINS,
        FS_TYPE_FLOW_TABLE,
        FS_TYPE_FLOW_GROUP,
        FS_TYPE_FLOW_ENTRY,
@@ -73,6 +85,7 @@ struct mlx5_flow_steering {
        struct kmem_cache               *ftes_cache;
        struct mlx5_flow_root_namespace *root_ns;
        struct mlx5_flow_root_namespace *fdb_root_ns;
+       struct mlx5_flow_namespace      **fdb_sub_ns;
        struct mlx5_flow_root_namespace **esw_egress_root_ns;
        struct mlx5_flow_root_namespace **esw_ingress_root_ns;
        struct mlx5_flow_root_namespace *sniffer_tx_root_ns;
index a5fc62184195149644142f849034671e81b2aa18..f8d00872c7d370e752971918afcbef9a33fe24a9 100644 (file)
@@ -101,6 +101,8 @@ struct mlx5_flow_destination {
        };
 };
 
+struct mlx5_flow_namespace *
+mlx5_get_fdb_sub_ns(struct mlx5_core_dev *dev, int n);
 struct mlx5_flow_namespace *
 mlx5_get_flow_namespace(struct mlx5_core_dev *dev,
                        enum mlx5_flow_namespace_type type);