mlxsw: spectrum_span: Generalize SPAN support
authorPetr Machata <petrm@mellanox.com>
Tue, 27 Feb 2018 13:53:45 +0000 (14:53 +0100)
committerDavid S. Miller <davem@davemloft.net>
Tue, 27 Feb 2018 19:46:27 +0000 (14:46 -0500)
To support mirroring to different device types, the functions that
partake in configuring the port analyzer need to be extended to admit
non-trivial SPAN types.

Create a structure where all details of SPAN configuration are kept,
struct mlxsw_sp_span_parms. Also create struct mlxsw_sp_span_entry_ops
to keep per-SPAN-type operations.

Instantiate the latter once for MLXSW_REG_MPAT_SPAN_TYPE_LOCAL_ETH, and
once for a suite of NOP callbacks used for invalidated SPAN entry. Put
the formet as a sole member of a new array mlxsw_sp_span_entry_types,
where all known SPAN types are kept. Introduce a new function,
mlxsw_sp_span_entry_ops(), to look up the right ops suite given a
netdevice.

Change mlxsw_sp_span_mirror_add() to use both parms and ops structures.
Change mlxsw_sp_span_entry_get() and mlxsw_sp_span_entry_create() to
take these as arguments. Modify mlxsw_sp_span_entry_configure() and
mlxsw_sp_span_entry_deconfigure() to dispatch to ops.

Signed-off-by: Petr Machata <petrm@mellanox.com>
Reviewed-by: Ido Schimmel <idosch@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/mellanox/mlxsw/spectrum.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_span.h

index 86991db..b070cad 100644 (file)
@@ -1266,11 +1266,6 @@ mlxsw_sp_port_add_cls_matchall_mirror(struct mlxsw_sp_port *mlxsw_sp_port,
                return -EINVAL;
        }
 
-       if (!mlxsw_sp_port_dev_check(to_dev)) {
-               netdev_err(mlxsw_sp_port->dev, "Cannot mirror to a non-spectrum port");
-               return -EOPNOTSUPP;
-       }
-
        mirror->ingress = ingress;
        span_type = ingress ? MLXSW_SP_SPAN_INGRESS : MLXSW_SP_SPAN_EGRESS;
        return mlxsw_sp_span_mirror_add(mlxsw_sp_port, to_dev, span_type,
index 50f5eac..9d7197b 100644 (file)
@@ -581,9 +581,6 @@ int mlxsw_sp_acl_rulei_act_mirror(struct mlxsw_sp *mlxsw_sp,
        binding = list_first_entry(&block->binding_list,
                                   struct mlxsw_sp_acl_block_binding, list);
        in_port = binding->mlxsw_sp_port;
-       if (!mlxsw_sp_port_dev_check(out_dev))
-               return -EINVAL;
-
        out_port = netdev_priv(out_dev);
        if (out_port->mlxsw_sp != mlxsw_sp)
                return -EINVAL;
index 9819cdc..c0e0e9a 100644 (file)
@@ -74,40 +74,120 @@ void mlxsw_sp_span_fini(struct mlxsw_sp *mlxsw_sp)
 }
 
 static int
-mlxsw_sp_span_entry_configure(struct mlxsw_sp *mlxsw_sp,
-                             struct mlxsw_sp_span_entry *span_entry,
-                             u8 local_port)
+mlxsw_sp_span_entry_phys_parms(const struct net_device *to_dev,
+                              struct mlxsw_sp_span_parms *sparmsp)
+{
+       sparmsp->dest_port = netdev_priv(to_dev);
+       return 0;
+}
+
+static int
+mlxsw_sp_span_entry_phys_configure(struct mlxsw_sp_span_entry *span_entry,
+                                  struct mlxsw_sp_span_parms sparms)
 {
+       struct mlxsw_sp_port *dest_port = sparms.dest_port;
+       struct mlxsw_sp *mlxsw_sp = dest_port->mlxsw_sp;
+       u8 local_port = dest_port->local_port;
        char mpat_pl[MLXSW_REG_MPAT_LEN];
        int pa_id = span_entry->id;
 
        /* Create a new port analayzer entry for local_port. */
        mlxsw_reg_mpat_pack(mpat_pl, pa_id, local_port, true,
                            MLXSW_REG_MPAT_SPAN_TYPE_LOCAL_ETH);
+
        return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpat), mpat_pl);
 }
 
 static void
-mlxsw_sp_span_entry_deconfigure(struct mlxsw_sp *mlxsw_sp,
-                               struct mlxsw_sp_span_entry *span_entry)
+mlxsw_sp_span_entry_deconfigure_common(struct mlxsw_sp_span_entry *span_entry,
+                                      enum mlxsw_reg_mpat_span_type span_type)
 {
-       struct mlxsw_sp_port *to_port = netdev_priv(span_entry->to_dev);
-       u8 local_port = to_port->local_port;
+       struct mlxsw_sp_port *dest_port = span_entry->parms.dest_port;
+       struct mlxsw_sp *mlxsw_sp = dest_port->mlxsw_sp;
+       u8 local_port = dest_port->local_port;
        char mpat_pl[MLXSW_REG_MPAT_LEN];
        int pa_id = span_entry->id;
 
-       mlxsw_reg_mpat_pack(mpat_pl, pa_id, local_port, false,
-                           MLXSW_REG_MPAT_SPAN_TYPE_LOCAL_ETH);
+       mlxsw_reg_mpat_pack(mpat_pl, pa_id, local_port, false, span_type);
        mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpat), mpat_pl);
 }
 
+static void
+mlxsw_sp_span_entry_phys_deconfigure(struct mlxsw_sp_span_entry *span_entry)
+{
+       mlxsw_sp_span_entry_deconfigure_common(span_entry,
+                                           MLXSW_REG_MPAT_SPAN_TYPE_LOCAL_ETH);
+}
+
+static const
+struct mlxsw_sp_span_entry_ops mlxsw_sp_span_entry_ops_phys = {
+       .can_handle = mlxsw_sp_port_dev_check,
+       .parms = mlxsw_sp_span_entry_phys_parms,
+       .configure = mlxsw_sp_span_entry_phys_configure,
+       .deconfigure = mlxsw_sp_span_entry_phys_deconfigure,
+};
+
+static const
+struct mlxsw_sp_span_entry_ops *const mlxsw_sp_span_entry_types[] = {
+       &mlxsw_sp_span_entry_ops_phys,
+};
+
+static int
+mlxsw_sp_span_entry_nop_parms(const struct net_device *to_dev,
+                             struct mlxsw_sp_span_parms *sparmsp)
+{
+       sparmsp->dest_port = NULL;
+       return 0;
+}
+
+static int
+mlxsw_sp_span_entry_nop_configure(struct mlxsw_sp_span_entry *span_entry,
+                                 struct mlxsw_sp_span_parms sparms)
+{
+       return 0;
+}
+
+static void
+mlxsw_sp_span_entry_nop_deconfigure(struct mlxsw_sp_span_entry *span_entry)
+{
+}
+
+static const struct mlxsw_sp_span_entry_ops mlxsw_sp_span_entry_ops_nop = {
+       .parms = mlxsw_sp_span_entry_nop_parms,
+       .configure = mlxsw_sp_span_entry_nop_configure,
+       .deconfigure = mlxsw_sp_span_entry_nop_deconfigure,
+};
+
+static void
+mlxsw_sp_span_entry_configure(struct mlxsw_sp *mlxsw_sp,
+                             struct mlxsw_sp_span_entry *span_entry,
+                             struct mlxsw_sp_span_parms sparms)
+{
+       if (sparms.dest_port) {
+               if (span_entry->ops->configure(span_entry, sparms)) {
+                       netdev_err(span_entry->to_dev, "Failed to offload mirror to %s",
+                                  sparms.dest_port->dev->name);
+                       sparms.dest_port = NULL;
+               }
+       }
+
+       span_entry->parms = sparms;
+}
+
+static void
+mlxsw_sp_span_entry_deconfigure(struct mlxsw_sp_span_entry *span_entry)
+{
+       if (span_entry->parms.dest_port)
+               span_entry->ops->deconfigure(span_entry);
+}
+
 static struct mlxsw_sp_span_entry *
 mlxsw_sp_span_entry_create(struct mlxsw_sp *mlxsw_sp,
-                          const struct net_device *to_dev)
+                          const struct net_device *to_dev,
+                          const struct mlxsw_sp_span_entry_ops *ops,
+                          struct mlxsw_sp_span_parms sparms)
 {
-       struct mlxsw_sp_port *to_port = netdev_priv(to_dev);
        struct mlxsw_sp_span_entry *span_entry = NULL;
-       u8 local_port = to_port->local_port;
        int i;
 
        /* find a free entry to use */
@@ -120,19 +200,17 @@ mlxsw_sp_span_entry_create(struct mlxsw_sp *mlxsw_sp,
        if (!span_entry)
                return NULL;
 
-       if (mlxsw_sp_span_entry_configure(mlxsw_sp, span_entry, local_port))
-               return NULL;
-
+       span_entry->ops = ops;
        span_entry->ref_count = 1;
        span_entry->to_dev = to_dev;
+       mlxsw_sp_span_entry_configure(mlxsw_sp, span_entry, sparms);
+
        return span_entry;
 }
 
-static void mlxsw_sp_span_entry_destroy(struct mlxsw_sp *mlxsw_sp,
-                                       struct mlxsw_sp_span_entry *span_entry)
+static void mlxsw_sp_span_entry_destroy(struct mlxsw_sp_span_entry *span_entry)
 {
-       if (span_entry->to_dev)
-               mlxsw_sp_span_entry_deconfigure(mlxsw_sp, span_entry);
+       mlxsw_sp_span_entry_deconfigure(span_entry);
 }
 
 struct mlxsw_sp_span_entry *
@@ -153,8 +231,8 @@ mlxsw_sp_span_entry_find_by_port(struct mlxsw_sp *mlxsw_sp,
 void mlxsw_sp_span_entry_invalidate(struct mlxsw_sp *mlxsw_sp,
                                    struct mlxsw_sp_span_entry *span_entry)
 {
-       mlxsw_sp_span_entry_deconfigure(mlxsw_sp, span_entry);
-       span_entry->to_dev = NULL;
+       mlxsw_sp_span_entry_deconfigure(span_entry);
+       span_entry->ops = &mlxsw_sp_span_entry_ops_nop;
 }
 
 static struct mlxsw_sp_span_entry *
@@ -173,7 +251,9 @@ mlxsw_sp_span_entry_find_by_id(struct mlxsw_sp *mlxsw_sp, int span_id)
 
 static struct mlxsw_sp_span_entry *
 mlxsw_sp_span_entry_get(struct mlxsw_sp *mlxsw_sp,
-                       const struct net_device *to_dev)
+                       const struct net_device *to_dev,
+                       const struct mlxsw_sp_span_entry_ops *ops,
+                       struct mlxsw_sp_span_parms sparms)
 {
        struct mlxsw_sp_span_entry *span_entry;
 
@@ -184,7 +264,7 @@ mlxsw_sp_span_entry_get(struct mlxsw_sp *mlxsw_sp,
                return span_entry;
        }
 
-       return mlxsw_sp_span_entry_create(mlxsw_sp, to_dev);
+       return mlxsw_sp_span_entry_create(mlxsw_sp, to_dev, ops, sparms);
 }
 
 static int mlxsw_sp_span_entry_put(struct mlxsw_sp *mlxsw_sp,
@@ -192,7 +272,7 @@ static int mlxsw_sp_span_entry_put(struct mlxsw_sp *mlxsw_sp,
 {
        WARN_ON(!span_entry->ref_count);
        if (--span_entry->ref_count == 0)
-               mlxsw_sp_span_entry_destroy(mlxsw_sp, span_entry);
+               mlxsw_sp_span_entry_destroy(span_entry);
        return 0;
 }
 
@@ -354,16 +434,41 @@ mlxsw_sp_span_inspected_port_del(struct mlxsw_sp_port *port,
        kfree(inspected_port);
 }
 
+static const struct mlxsw_sp_span_entry_ops *
+mlxsw_sp_span_entry_ops(struct mlxsw_sp *mlxsw_sp,
+                       const struct net_device *to_dev)
+{
+       size_t i;
+
+       for (i = 0; i < ARRAY_SIZE(mlxsw_sp_span_entry_types); ++i)
+               if (mlxsw_sp_span_entry_types[i]->can_handle(to_dev))
+                       return mlxsw_sp_span_entry_types[i];
+
+       return NULL;
+}
+
 int mlxsw_sp_span_mirror_add(struct mlxsw_sp_port *from,
                             const struct net_device *to_dev,
                             enum mlxsw_sp_span_type type, bool bind,
                             int *p_span_id)
 {
        struct mlxsw_sp *mlxsw_sp = from->mlxsw_sp;
+       const struct mlxsw_sp_span_entry_ops *ops;
+       struct mlxsw_sp_span_parms sparms = {0};
        struct mlxsw_sp_span_entry *span_entry;
        int err;
 
-       span_entry = mlxsw_sp_span_entry_get(mlxsw_sp, to_dev);
+       ops = mlxsw_sp_span_entry_ops(mlxsw_sp, to_dev);
+       if (!ops) {
+               netdev_err(to_dev, "Cannot mirror to %s", to_dev->name);
+               return -EOPNOTSUPP;
+       }
+
+       err = ops->parms(to_dev, &sparms);
+       if (err)
+               return err;
+
+       span_entry = mlxsw_sp_span_entry_get(mlxsw_sp, to_dev, ops, sparms);
        if (!span_entry)
                return -ENOENT;
 
index 44b307c..9390b05 100644 (file)
@@ -50,13 +50,30 @@ struct mlxsw_sp_span_inspected_port {
        u8 local_port;
 };
 
+struct mlxsw_sp_span_parms {
+       struct mlxsw_sp_port *dest_port; /* NULL for unoffloaded SPAN. */
+};
+
+struct mlxsw_sp_span_entry_ops;
+
 struct mlxsw_sp_span_entry {
        const struct net_device *to_dev;
+       const struct mlxsw_sp_span_entry_ops *ops;
+       struct mlxsw_sp_span_parms parms;
        struct list_head bound_ports_list;
        int ref_count;
        int id;
 };
 
+struct mlxsw_sp_span_entry_ops {
+       bool (*can_handle)(const struct net_device *to_dev);
+       int (*parms)(const struct net_device *to_dev,
+                    struct mlxsw_sp_span_parms *sparmsp);
+       int (*configure)(struct mlxsw_sp_span_entry *span_entry,
+                        struct mlxsw_sp_span_parms sparms);
+       void (*deconfigure)(struct mlxsw_sp_span_entry *span_entry);
+};
+
 int mlxsw_sp_span_init(struct mlxsw_sp *mlxsw_sp);
 void mlxsw_sp_span_fini(struct mlxsw_sp *mlxsw_sp);