diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c index 6a979a09ab72d562548ede70faccb49dbf8549bd..b698fb481b2ecb4d7f79da60775b063f7da58dfc 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c +++ b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c @@ -310,9 +310,33 @@ struct mlxsw_afa_block { struct mlxsw_afa_set *first_set; struct mlxsw_afa_set *cur_set; unsigned int cur_act_index; /* In current set. */ - struct list_head fwd_entry_ref_list; + struct list_head resource_list; /* List of resources held by actions + * in this block. + */ }; +struct mlxsw_afa_resource { + struct list_head list; + void (*destructor)(struct mlxsw_afa_block *block, + struct mlxsw_afa_resource *resource); +}; + +static void mlxsw_afa_resource_add(struct mlxsw_afa_block *block, + struct mlxsw_afa_resource *resource) +{ + list_add(&resource->list, &block->resource_list); +} + +static void mlxsw_afa_resources_destroy(struct mlxsw_afa_block *block) +{ + struct mlxsw_afa_resource *resource, *tmp; + + list_for_each_entry_safe(resource, tmp, &block->resource_list, list) { + list_del(&resource->list); + resource->destructor(block, resource); + } +} + struct mlxsw_afa_block *mlxsw_afa_block_create(struct mlxsw_afa *mlxsw_afa) { struct mlxsw_afa_block *block; @@ -320,7 +344,7 @@ struct mlxsw_afa_block *mlxsw_afa_block_create(struct mlxsw_afa *mlxsw_afa) block = kzalloc(sizeof(*block), GFP_KERNEL); if (!block) return NULL; - INIT_LIST_HEAD(&block->fwd_entry_ref_list); + INIT_LIST_HEAD(&block->resource_list); block->afa = mlxsw_afa; /* At least one action set is always present, so just create it here */ @@ -336,8 +360,6 @@ struct mlxsw_afa_block *mlxsw_afa_block_create(struct mlxsw_afa *mlxsw_afa) } EXPORT_SYMBOL(mlxsw_afa_block_create); -static void mlxsw_afa_fwd_entry_refs_destroy(struct mlxsw_afa_block *block); - void mlxsw_afa_block_destroy(struct mlxsw_afa_block *block) { struct mlxsw_afa_set *set = block->first_set; @@ -348,7 +370,7 @@ void mlxsw_afa_block_destroy(struct mlxsw_afa_block *block) mlxsw_afa_set_put(block->afa, set); set = next_set; } while (set); - mlxsw_afa_fwd_entry_refs_destroy(block); + mlxsw_afa_resources_destroy(block); kfree(block); } EXPORT_SYMBOL(mlxsw_afa_block_destroy); @@ -489,10 +511,29 @@ static void mlxsw_afa_fwd_entry_put(struct mlxsw_afa *mlxsw_afa, } struct mlxsw_afa_fwd_entry_ref { - struct list_head list; + struct mlxsw_afa_resource resource; struct mlxsw_afa_fwd_entry *fwd_entry; }; +static void +mlxsw_afa_fwd_entry_ref_destroy(struct mlxsw_afa_block *block, + struct mlxsw_afa_fwd_entry_ref *fwd_entry_ref) +{ + mlxsw_afa_fwd_entry_put(block->afa, fwd_entry_ref->fwd_entry); + kfree(fwd_entry_ref); +} + +static void +mlxsw_afa_fwd_entry_ref_destructor(struct mlxsw_afa_block *block, + struct mlxsw_afa_resource *resource) +{ + struct mlxsw_afa_fwd_entry_ref *fwd_entry_ref; + + fwd_entry_ref = container_of(resource, struct mlxsw_afa_fwd_entry_ref, + resource); + mlxsw_afa_fwd_entry_ref_destroy(block, fwd_entry_ref); +} + static struct mlxsw_afa_fwd_entry_ref * mlxsw_afa_fwd_entry_ref_create(struct mlxsw_afa_block *block, u8 local_port) { @@ -509,7 +550,8 @@ mlxsw_afa_fwd_entry_ref_create(struct mlxsw_afa_block *block, u8 local_port) goto err_fwd_entry_get; } fwd_entry_ref->fwd_entry = fwd_entry; - list_add(&fwd_entry_ref->list, &block->fwd_entry_ref_list); + fwd_entry_ref->resource.destructor = mlxsw_afa_fwd_entry_ref_destructor; + mlxsw_afa_resource_add(block, &fwd_entry_ref->resource); return fwd_entry_ref; err_fwd_entry_get: @@ -517,23 +559,51 @@ mlxsw_afa_fwd_entry_ref_create(struct mlxsw_afa_block *block, u8 local_port) return ERR_PTR(err); } +struct mlxsw_afa_counter { + struct mlxsw_afa_resource resource; + u32 counter_index; +}; + static void -mlxsw_afa_fwd_entry_ref_destroy(struct mlxsw_afa_block *block, - struct mlxsw_afa_fwd_entry_ref *fwd_entry_ref) +mlxsw_afa_counter_destroy(struct mlxsw_afa_block *block, + struct mlxsw_afa_counter *counter) { - list_del(&fwd_entry_ref->list); - mlxsw_afa_fwd_entry_put(block->afa, fwd_entry_ref->fwd_entry); - kfree(fwd_entry_ref); + block->afa->ops->counter_index_put(block->afa->ops_priv, + counter->counter_index); + kfree(counter); +} + +static void +mlxsw_afa_counter_destructor(struct mlxsw_afa_block *block, + struct mlxsw_afa_resource *resource) +{ + struct mlxsw_afa_counter *counter; + + counter = container_of(resource, struct mlxsw_afa_counter, resource); + mlxsw_afa_counter_destroy(block, counter); } -static void mlxsw_afa_fwd_entry_refs_destroy(struct mlxsw_afa_block *block) +static struct mlxsw_afa_counter * +mlxsw_afa_counter_create(struct mlxsw_afa_block *block) { - struct mlxsw_afa_fwd_entry_ref *fwd_entry_ref; - struct mlxsw_afa_fwd_entry_ref *tmp; + struct mlxsw_afa_counter *counter; + int err; + + counter = kzalloc(sizeof(*counter), GFP_KERNEL); + if (!counter) + return ERR_PTR(-ENOMEM); + + err = block->afa->ops->counter_index_get(block->afa->ops_priv, + &counter->counter_index); + if (err) + goto err_counter_index_get; + counter->resource.destructor = mlxsw_afa_counter_destructor; + mlxsw_afa_resource_add(block, &counter->resource); + return counter; - list_for_each_entry_safe(fwd_entry_ref, tmp, - &block->fwd_entry_ref_list, list) - mlxsw_afa_fwd_entry_ref_destroy(block, fwd_entry_ref); +err_counter_index_get: + kfree(counter); + return ERR_PTR(err); } #define MLXSW_AFA_ONE_ACTION_LEN 32 @@ -690,6 +760,16 @@ MLXSW_ITEM32(afa, trapdisc, forward_action, 0x00, 0, 4); */ MLXSW_ITEM32(afa, trapdisc, trap_id, 0x04, 0, 9); +/* afa_trapdisc_mirror_agent + * Mirror agent. + */ +MLXSW_ITEM32(afa, trapdisc, mirror_agent, 0x08, 29, 3); + +/* afa_trapdisc_mirror_enable + * Mirror enable. + */ +MLXSW_ITEM32(afa, trapdisc, mirror_enable, 0x08, 24, 1); + static inline void mlxsw_afa_trapdisc_pack(char *payload, enum mlxsw_afa_trapdisc_trap_action trap_action, @@ -701,6 +781,14 @@ mlxsw_afa_trapdisc_pack(char *payload, mlxsw_afa_trapdisc_trap_id_set(payload, trap_id); } +static inline void +mlxsw_afa_trapdisc_mirror_pack(char *payload, bool mirror_enable, + u8 mirror_agent) +{ + mlxsw_afa_trapdisc_mirror_enable_set(payload, mirror_enable); + mlxsw_afa_trapdisc_mirror_agent_set(payload, mirror_agent); +} + int mlxsw_afa_block_append_drop(struct mlxsw_afa_block *block) { char *act = mlxsw_afa_block_append_action(block, @@ -746,6 +834,104 @@ int mlxsw_afa_block_append_trap_and_forward(struct mlxsw_afa_block *block, } EXPORT_SYMBOL(mlxsw_afa_block_append_trap_and_forward); +struct mlxsw_afa_mirror { + struct mlxsw_afa_resource resource; + int span_id; + u8 local_in_port; + u8 local_out_port; + bool ingress; +}; + +static void +mlxsw_afa_mirror_destroy(struct mlxsw_afa_block *block, + struct mlxsw_afa_mirror *mirror) +{ + block->afa->ops->mirror_del(block->afa->ops_priv, + mirror->local_in_port, + mirror->local_out_port, + mirror->ingress); + kfree(mirror); +} + +static void +mlxsw_afa_mirror_destructor(struct mlxsw_afa_block *block, + struct mlxsw_afa_resource *resource) +{ + struct mlxsw_afa_mirror *mirror; + + mirror = container_of(resource, struct mlxsw_afa_mirror, resource); + mlxsw_afa_mirror_destroy(block, mirror); +} + +static struct mlxsw_afa_mirror * +mlxsw_afa_mirror_create(struct mlxsw_afa_block *block, + u8 local_in_port, u8 local_out_port, + bool ingress) +{ + struct mlxsw_afa_mirror *mirror; + int err; + + mirror = kzalloc(sizeof(*mirror), GFP_KERNEL); + if (!mirror) + return ERR_PTR(-ENOMEM); + + err = block->afa->ops->mirror_add(block->afa->ops_priv, + local_in_port, local_out_port, + ingress, &mirror->span_id); + if (err) + goto err_mirror_add; + + mirror->ingress = ingress; + mirror->local_out_port = local_out_port; + mirror->local_in_port = local_in_port; + mirror->resource.destructor = mlxsw_afa_mirror_destructor; + mlxsw_afa_resource_add(block, &mirror->resource); + return mirror; + +err_mirror_add: + kfree(mirror); + return ERR_PTR(err); +} + +static int +mlxsw_afa_block_append_allocated_mirror(struct mlxsw_afa_block *block, + u8 mirror_agent) +{ + char *act = mlxsw_afa_block_append_action(block, + MLXSW_AFA_TRAPDISC_CODE, + MLXSW_AFA_TRAPDISC_SIZE); + if (!act) + return -ENOBUFS; + mlxsw_afa_trapdisc_pack(act, MLXSW_AFA_TRAPDISC_TRAP_ACTION_NOP, + MLXSW_AFA_TRAPDISC_FORWARD_ACTION_FORWARD, 0); + mlxsw_afa_trapdisc_mirror_pack(act, true, mirror_agent); + return 0; +} + +int +mlxsw_afa_block_append_mirror(struct mlxsw_afa_block *block, + u8 local_in_port, u8 local_out_port, bool ingress) +{ + struct mlxsw_afa_mirror *mirror; + int err; + + mirror = mlxsw_afa_mirror_create(block, local_in_port, local_out_port, + ingress); + if (IS_ERR(mirror)) + return PTR_ERR(mirror); + + err = mlxsw_afa_block_append_allocated_mirror(block, mirror->span_id); + if (err) + goto err_append_allocated_mirror; + + return 0; + +err_append_allocated_mirror: + mlxsw_afa_mirror_destroy(block, mirror); + return err; +} +EXPORT_SYMBOL(mlxsw_afa_block_append_mirror); + /* Forwarding Action * ----------------- * Forwarding Action can be used to implement Policy Based Switching (PBS) @@ -853,11 +1039,10 @@ mlxsw_afa_polcnt_pack(char *payload, mlxsw_afa_polcnt_counter_index_set(payload, counter_index); } -int mlxsw_afa_block_append_counter(struct mlxsw_afa_block *block, - u32 counter_index) +int mlxsw_afa_block_append_allocated_counter(struct mlxsw_afa_block *block, + u32 counter_index) { - char *act = mlxsw_afa_block_append_action(block, - MLXSW_AFA_POLCNT_CODE, + char *act = mlxsw_afa_block_append_action(block, MLXSW_AFA_POLCNT_CODE, MLXSW_AFA_POLCNT_SIZE); if (!act) return -ENOBUFS; @@ -865,6 +1050,32 @@ int mlxsw_afa_block_append_counter(struct mlxsw_afa_block *block, counter_index); return 0; } +EXPORT_SYMBOL(mlxsw_afa_block_append_allocated_counter); + +int mlxsw_afa_block_append_counter(struct mlxsw_afa_block *block, + u32 *p_counter_index) +{ + struct mlxsw_afa_counter *counter; + u32 counter_index; + int err; + + counter = mlxsw_afa_counter_create(block); + if (IS_ERR(counter)) + return PTR_ERR(counter); + counter_index = counter->counter_index; + + err = mlxsw_afa_block_append_allocated_counter(block, counter_index); + if (err) + goto err_append_allocated_counter; + + if (p_counter_index) + *p_counter_index = counter_index; + return 0; + +err_append_allocated_counter: + mlxsw_afa_counter_destroy(block, counter); + return err; +} EXPORT_SYMBOL(mlxsw_afa_block_append_counter); /* Virtual Router and Forwarding Domain Action diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.h b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.h index a8d3314c3a2477ae52b9a7f6e32c11686bff6d5f..43132293475ce9ce916eac0b49b8a9c822ffb214 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.h +++ b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.h @@ -46,6 +46,12 @@ struct mlxsw_afa_ops { void (*kvdl_set_del)(void *priv, u32 kvdl_index, bool is_first); int (*kvdl_fwd_entry_add)(void *priv, u32 *p_kvdl_index, u8 local_port); void (*kvdl_fwd_entry_del)(void *priv, u32 kvdl_index); + int (*counter_index_get)(void *priv, unsigned int *p_counter_index); + void (*counter_index_put)(void *priv, unsigned int counter_index); + int (*mirror_add)(void *priv, u8 locol_in_port, u8 local_out_port, + bool ingress, int *p_span_id); + void (*mirror_del)(void *priv, u8 locol_in_port, u8 local_out_port, + bool ingress); }; struct mlxsw_afa *mlxsw_afa_create(unsigned int max_acts_per_set, @@ -63,12 +69,17 @@ int mlxsw_afa_block_append_drop(struct mlxsw_afa_block *block); int mlxsw_afa_block_append_trap(struct mlxsw_afa_block *block, u16 trap_id); int mlxsw_afa_block_append_trap_and_forward(struct mlxsw_afa_block *block, u16 trap_id); +int mlxsw_afa_block_append_mirror(struct mlxsw_afa_block *block, + u8 local_in_port, u8 local_out_port, + bool ingress); int mlxsw_afa_block_append_fwd(struct mlxsw_afa_block *block, u8 local_port, bool in_port); int mlxsw_afa_block_append_vlan_modify(struct mlxsw_afa_block *block, u16 vid, u8 pcp, u8 et); +int mlxsw_afa_block_append_allocated_counter(struct mlxsw_afa_block *block, + u32 counter_index); int mlxsw_afa_block_append_counter(struct mlxsw_afa_block *block, - u32 counter_index); + u32 *p_counter_index); int mlxsw_afa_block_append_fid_set(struct mlxsw_afa_block *block, u16 fid); int mlxsw_afa_block_append_mcrouter(struct mlxsw_afa_block *block, u16 expected_irif, u16 min_mtu, diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 7e2b552c2237c6cb5e3cf0942eb8a49f77b46a46..833cd0a96fd9d20581175a4d01f88fa43a5f9cc1 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -568,7 +568,7 @@ static void mlxsw_sp_span_entry_destroy(struct mlxsw_sp *mlxsw_sp, span_entry->used = false; } -static struct mlxsw_sp_span_entry * +struct mlxsw_sp_span_entry * mlxsw_sp_span_entry_find(struct mlxsw_sp *mlxsw_sp, u8 local_port) { int i; @@ -669,13 +669,28 @@ mlxsw_sp_span_entry_bound_port_find(struct mlxsw_sp_port *port, static int mlxsw_sp_span_inspected_port_bind(struct mlxsw_sp_port *port, struct mlxsw_sp_span_entry *span_entry, - enum mlxsw_sp_span_type type) + enum mlxsw_sp_span_type type, + bool bind) { - struct mlxsw_sp_span_inspected_port *inspected_port; struct mlxsw_sp *mlxsw_sp = port->mlxsw_sp; char mpar_pl[MLXSW_REG_MPAR_LEN]; - char sbib_pl[MLXSW_REG_SBIB_LEN]; int pa_id = span_entry->id; + + /* bind the port to the SPAN entry */ + mlxsw_reg_mpar_pack(mpar_pl, port->local_port, + (enum mlxsw_reg_mpar_i_e) type, bind, pa_id); + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpar), mpar_pl); +} + +static int +mlxsw_sp_span_inspected_port_add(struct mlxsw_sp_port *port, + struct mlxsw_sp_span_entry *span_entry, + enum mlxsw_sp_span_type type, + bool bind) +{ + struct mlxsw_sp_span_inspected_port *inspected_port; + struct mlxsw_sp *mlxsw_sp = port->mlxsw_sp; + char sbib_pl[MLXSW_REG_SBIB_LEN]; int err; /* if it is an egress SPAN, bind a shared buffer to it */ @@ -691,12 +706,12 @@ mlxsw_sp_span_inspected_port_bind(struct mlxsw_sp_port *port, } } - /* bind the port to the SPAN entry */ - mlxsw_reg_mpar_pack(mpar_pl, port->local_port, - (enum mlxsw_reg_mpar_i_e) type, true, pa_id); - err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpar), mpar_pl); - if (err) - goto err_mpar_reg_write; + if (bind) { + err = mlxsw_sp_span_inspected_port_bind(port, span_entry, type, + true); + if (err) + goto err_port_bind; + } inspected_port = kzalloc(sizeof(*inspected_port), GFP_KERNEL); if (!inspected_port) { @@ -709,8 +724,11 @@ mlxsw_sp_span_inspected_port_bind(struct mlxsw_sp_port *port, return 0; -err_mpar_reg_write: err_inspected_port_alloc: + if (bind) + mlxsw_sp_span_inspected_port_bind(port, span_entry, type, + false); +err_port_bind: if (type == MLXSW_SP_SPAN_EGRESS) { mlxsw_reg_sbib_pack(sbib_pl, port->local_port, 0); mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbib), sbib_pl); @@ -719,25 +737,22 @@ mlxsw_sp_span_inspected_port_bind(struct mlxsw_sp_port *port, } static void -mlxsw_sp_span_inspected_port_unbind(struct mlxsw_sp_port *port, - struct mlxsw_sp_span_entry *span_entry, - enum mlxsw_sp_span_type type) +mlxsw_sp_span_inspected_port_del(struct mlxsw_sp_port *port, + struct mlxsw_sp_span_entry *span_entry, + enum mlxsw_sp_span_type type, + bool bind) { struct mlxsw_sp_span_inspected_port *inspected_port; struct mlxsw_sp *mlxsw_sp = port->mlxsw_sp; - char mpar_pl[MLXSW_REG_MPAR_LEN]; char sbib_pl[MLXSW_REG_SBIB_LEN]; - int pa_id = span_entry->id; inspected_port = mlxsw_sp_span_entry_bound_port_find(port, span_entry); if (!inspected_port) return; - /* remove the inspected port */ - mlxsw_reg_mpar_pack(mpar_pl, port->local_port, - (enum mlxsw_reg_mpar_i_e) type, false, pa_id); - mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpar), mpar_pl); - + if (bind) + mlxsw_sp_span_inspected_port_bind(port, span_entry, type, + false); /* remove the SBIB buffer if it was egress SPAN */ if (type == MLXSW_SP_SPAN_EGRESS) { mlxsw_reg_sbib_pack(sbib_pl, port->local_port, 0); @@ -750,9 +765,9 @@ mlxsw_sp_span_inspected_port_unbind(struct mlxsw_sp_port *port, kfree(inspected_port); } -static int mlxsw_sp_span_mirror_add(struct mlxsw_sp_port *from, - struct mlxsw_sp_port *to, - enum mlxsw_sp_span_type type) +int mlxsw_sp_span_mirror_add(struct mlxsw_sp_port *from, + struct mlxsw_sp_port *to, + enum mlxsw_sp_span_type type, bool bind) { struct mlxsw_sp *mlxsw_sp = from->mlxsw_sp; struct mlxsw_sp_span_entry *span_entry; @@ -765,7 +780,7 @@ static int mlxsw_sp_span_mirror_add(struct mlxsw_sp_port *from, netdev_dbg(from->dev, "Adding inspected port to SPAN entry %d\n", span_entry->id); - err = mlxsw_sp_span_inspected_port_bind(from, span_entry, type); + err = mlxsw_sp_span_inspected_port_add(from, span_entry, type, bind); if (err) goto err_port_bind; @@ -776,9 +791,8 @@ static int mlxsw_sp_span_mirror_add(struct mlxsw_sp_port *from, return err; } -static void mlxsw_sp_span_mirror_remove(struct mlxsw_sp_port *from, - u8 destination_port, - enum mlxsw_sp_span_type type) +void mlxsw_sp_span_mirror_del(struct mlxsw_sp_port *from, u8 destination_port, + enum mlxsw_sp_span_type type, bool bind) { struct mlxsw_sp_span_entry *span_entry; @@ -791,7 +805,7 @@ static void mlxsw_sp_span_mirror_remove(struct mlxsw_sp_port *from, netdev_dbg(from->dev, "removing inspected port from SPAN entry %d\n", span_entry->id); - mlxsw_sp_span_inspected_port_unbind(from, span_entry, type); + mlxsw_sp_span_inspected_port_del(from, span_entry, type, bind); } static int mlxsw_sp_port_sample_set(struct mlxsw_sp_port *mlxsw_sp_port, @@ -1582,7 +1596,8 @@ mlxsw_sp_port_add_cls_matchall_mirror(struct mlxsw_sp_port *mlxsw_sp_port, mirror->to_local_port = to_port->local_port; mirror->ingress = ingress; span_type = ingress ? MLXSW_SP_SPAN_INGRESS : MLXSW_SP_SPAN_EGRESS; - return mlxsw_sp_span_mirror_add(mlxsw_sp_port, to_port, span_type); + return mlxsw_sp_span_mirror_add(mlxsw_sp_port, to_port, span_type, + true); } static void @@ -1593,8 +1608,8 @@ mlxsw_sp_port_del_cls_matchall_mirror(struct mlxsw_sp_port *mlxsw_sp_port, span_type = mirror->ingress ? MLXSW_SP_SPAN_INGRESS : MLXSW_SP_SPAN_EGRESS; - mlxsw_sp_span_mirror_remove(mlxsw_sp_port, mirror->to_local_port, - span_type); + mlxsw_sp_span_mirror_del(mlxsw_sp_port, mirror->to_local_port, + span_type, true); } static int diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index 58ff79211c09e33e742462ce79891b0962f850bb..bdd8f94a452cc8057a17effb672d8e7a55ee288a 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -396,6 +396,16 @@ struct mlxsw_sp_port *mlxsw_sp_port_dev_lower_find(struct net_device *dev); struct mlxsw_sp_port *mlxsw_sp_port_lower_dev_hold(struct net_device *dev); void mlxsw_sp_port_dev_put(struct mlxsw_sp_port *mlxsw_sp_port); struct mlxsw_sp_port *mlxsw_sp_port_dev_lower_find_rcu(struct net_device *dev); +int mlxsw_sp_span_mirror_add(struct mlxsw_sp_port *from, + struct mlxsw_sp_port *to, + enum mlxsw_sp_span_type type, + bool bind); +void mlxsw_sp_span_mirror_del(struct mlxsw_sp_port *from, + u8 destination_port, + enum mlxsw_sp_span_type type, + bool bind); +struct mlxsw_sp_span_entry * +mlxsw_sp_span_entry_find(struct mlxsw_sp *mlxsw_sp, u8 local_port); /* spectrum_dcb.c */ #ifdef CONFIG_MLXSW_SPECTRUM_DCB @@ -457,7 +467,6 @@ struct mlxsw_sp_acl_rule_info { struct mlxsw_afk_element_values values; struct mlxsw_afa_block *act_block; unsigned int counter_index; - bool counter_valid; }; enum mlxsw_sp_acl_profile { @@ -545,6 +554,10 @@ int mlxsw_sp_acl_rulei_act_jump(struct mlxsw_sp_acl_rule_info *rulei, u16 group_id); int mlxsw_sp_acl_rulei_act_drop(struct mlxsw_sp_acl_rule_info *rulei); int mlxsw_sp_acl_rulei_act_trap(struct mlxsw_sp_acl_rule_info *rulei); +int mlxsw_sp_acl_rulei_act_mirror(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_acl_rule_info *rulei, + struct mlxsw_sp_acl_block *block, + struct net_device *out_dev); int mlxsw_sp_acl_rulei_act_fwd(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_rule_info *rulei, struct net_device *out_dev); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c index 9439bfa4ecc29e2d18463d4cf6503ea895a3e522..0897a5435cc2e205957d2158d184b3bc465a71ac 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c @@ -462,27 +462,6 @@ u16 mlxsw_sp_acl_ruleset_group_id(struct mlxsw_sp_acl_ruleset *ruleset) return ops->ruleset_group_id(ruleset->priv); } -static int -mlxsw_sp_acl_rulei_counter_alloc(struct mlxsw_sp *mlxsw_sp, - struct mlxsw_sp_acl_rule_info *rulei) -{ - int err; - - err = mlxsw_sp_flow_counter_alloc(mlxsw_sp, &rulei->counter_index); - if (err) - return err; - rulei->counter_valid = true; - return 0; -} - -static void -mlxsw_sp_acl_rulei_counter_free(struct mlxsw_sp *mlxsw_sp, - struct mlxsw_sp_acl_rule_info *rulei) -{ - rulei->counter_valid = false; - mlxsw_sp_flow_counter_free(mlxsw_sp, rulei->counter_index); -} - struct mlxsw_sp_acl_rule_info * mlxsw_sp_acl_rulei_create(struct mlxsw_sp_acl *acl) { @@ -587,6 +566,34 @@ int mlxsw_sp_acl_rulei_act_fwd(struct mlxsw_sp *mlxsw_sp, local_port, in_port); } +int mlxsw_sp_acl_rulei_act_mirror(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_acl_rule_info *rulei, + struct mlxsw_sp_acl_block *block, + struct net_device *out_dev) +{ + struct mlxsw_sp_acl_block_binding *binding; + struct mlxsw_sp_port *out_port; + struct mlxsw_sp_port *in_port; + + if (!list_is_singular(&block->binding_list)) + return -EOPNOTSUPP; + + 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; + + return mlxsw_afa_block_append_mirror(rulei->act_block, + in_port->local_port, + out_port->local_port, + binding->ingress); +} + int mlxsw_sp_acl_rulei_act_vlan(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_rule_info *rulei, u32 action, u16 vid, u16 proto, u8 prio) @@ -619,7 +626,7 @@ int mlxsw_sp_acl_rulei_act_count(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_rule_info *rulei) { return mlxsw_afa_block_append_counter(rulei->act_block, - rulei->counter_index); + &rulei->counter_index); } int mlxsw_sp_acl_rulei_act_fid_set(struct mlxsw_sp *mlxsw_sp, @@ -653,13 +660,8 @@ mlxsw_sp_acl_rule_create(struct mlxsw_sp *mlxsw_sp, goto err_rulei_create; } - err = mlxsw_sp_acl_rulei_counter_alloc(mlxsw_sp, rule->rulei); - if (err) - goto err_counter_alloc; return rule; -err_counter_alloc: - mlxsw_sp_acl_rulei_destroy(rule->rulei); err_rulei_create: kfree(rule); err_alloc: @@ -672,7 +674,6 @@ void mlxsw_sp_acl_rule_destroy(struct mlxsw_sp *mlxsw_sp, { struct mlxsw_sp_acl_ruleset *ruleset = rule->ruleset; - mlxsw_sp_acl_rulei_counter_free(mlxsw_sp, rule->rulei); mlxsw_sp_acl_rulei_destroy(rule->rulei); kfree(rule); mlxsw_sp_acl_ruleset_ref_dec(mlxsw_sp, ruleset); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_actions.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_actions.c index 4d3340ed029197761437963185cce7ae2039e90d..6ca6894125f0c1f188c56994ecb253d1311b9dd0 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_actions.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_actions.c @@ -108,11 +108,77 @@ static void mlxsw_sp_act_kvdl_fwd_entry_del(void *priv, u32 kvdl_index) mlxsw_sp_kvdl_free(mlxsw_sp, kvdl_index); } +static int +mlxsw_sp_act_counter_index_get(void *priv, unsigned int *p_counter_index) +{ + struct mlxsw_sp *mlxsw_sp = priv; + + return mlxsw_sp_flow_counter_alloc(mlxsw_sp, p_counter_index); +} + +static void +mlxsw_sp_act_counter_index_put(void *priv, unsigned int counter_index) +{ + struct mlxsw_sp *mlxsw_sp = priv; + + mlxsw_sp_flow_counter_free(mlxsw_sp, counter_index); +} + +static int +mlxsw_sp_act_mirror_add(void *priv, u8 local_in_port, u8 local_out_port, + bool ingress, int *p_span_id) +{ + struct mlxsw_sp_port *in_port, *out_port; + struct mlxsw_sp_span_entry *span_entry; + struct mlxsw_sp *mlxsw_sp = priv; + enum mlxsw_sp_span_type type; + int err; + + type = ingress ? MLXSW_SP_SPAN_INGRESS : MLXSW_SP_SPAN_EGRESS; + out_port = mlxsw_sp->ports[local_out_port]; + in_port = mlxsw_sp->ports[local_in_port]; + + err = mlxsw_sp_span_mirror_add(in_port, out_port, type, false); + if (err) + return err; + + span_entry = mlxsw_sp_span_entry_find(mlxsw_sp, local_out_port); + if (!span_entry) { + err = -ENOENT; + goto err_span_entry_find; + } + + *p_span_id = span_entry->id; + return 0; + +err_span_entry_find: + mlxsw_sp_span_mirror_del(in_port, local_out_port, type, false); + return err; +} + +static void +mlxsw_sp_act_mirror_del(void *priv, u8 local_in_port, u8 local_out_port, + bool ingress) +{ + struct mlxsw_sp *mlxsw_sp = priv; + struct mlxsw_sp_port *in_port; + enum mlxsw_sp_span_type type; + + type = ingress ? MLXSW_SP_SPAN_INGRESS : MLXSW_SP_SPAN_EGRESS; + in_port = mlxsw_sp->ports[local_in_port]; + + mlxsw_sp_span_mirror_del(in_port, local_out_port, type, false); +} + static const struct mlxsw_afa_ops mlxsw_sp_act_afa_ops = { .kvdl_set_add = mlxsw_sp_act_kvdl_set_add, .kvdl_set_del = mlxsw_sp_act_kvdl_set_del, .kvdl_fwd_entry_add = mlxsw_sp_act_kvdl_fwd_entry_add, .kvdl_fwd_entry_del = mlxsw_sp_act_kvdl_fwd_entry_del, + .counter_index_get = mlxsw_sp_act_counter_index_get, + .counter_index_put = mlxsw_sp_act_counter_index_put, + .mirror_add = mlxsw_sp_act_mirror_add, + .mirror_del = mlxsw_sp_act_mirror_del, }; int mlxsw_sp_afa_init(struct mlxsw_sp *mlxsw_sp) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c index cf7b97d40d78c304bb54fe238911370bcaca5f22..6ce00e28d4eac8043abb8a77c86a0aabe30531b3 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c @@ -108,6 +108,13 @@ static int mlxsw_sp_flower_parse_actions(struct mlxsw_sp *mlxsw_sp, out_dev); if (err) return err; + } else if (is_tcf_mirred_egress_mirror(a)) { + struct net_device *out_dev = tcf_mirred_dev(a); + + err = mlxsw_sp_acl_rulei_act_mirror(mlxsw_sp, rulei, + block, out_dev); + if (err) + return err; } else if (is_tcf_vlan(a)) { u16 proto = be16_to_cpu(tcf_vlan_push_proto(a)); u32 action = tcf_vlan_action(a); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_mr_tcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_mr_tcam.c index 34a0b632e5dd34038b8edb4fb3b31b58adb54f75..4c7f32d4288d472d3e76ad5378fc82b7abd7b256 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_mr_tcam.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_mr_tcam.c @@ -243,7 +243,8 @@ mlxsw_sp_mr_tcam_afa_block_create(struct mlxsw_sp *mlxsw_sp, if (!afa_block) return ERR_PTR(-ENOMEM); - err = mlxsw_afa_block_append_counter(afa_block, counter_index); + err = mlxsw_afa_block_append_allocated_counter(afa_block, + counter_index); if (err) goto err;