From 169b5d95c15e01e08e1665bd8ceaff9bf8331c33 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 27 Feb 2018 14:53:45 +0100 Subject: [PATCH] mlxsw: spectrum_span: Generalize SPAN support 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 Reviewed-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- .../net/ethernet/mellanox/mlxsw/spectrum.c | 5 - .../ethernet/mellanox/mlxsw/spectrum_acl.c | 3 - .../ethernet/mellanox/mlxsw/spectrum_span.c | 155 +++++++++++++++--- .../ethernet/mellanox/mlxsw/spectrum_span.h | 17 ++ 4 files changed, 147 insertions(+), 33 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 86991db3478c..b070cad8dba7 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -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, diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c index 50f5eacdfa24..9d7197b9abb1 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c @@ -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; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c index 9819cdcf9e5c..c0e0e9af2da7 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c @@ -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; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.h index 44b307c59d0e..9390b05a7919 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.h @@ -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); -- 2.30.2