From 18aa23b31f6c8e3f4b01b70a8a4eab873e2eb710 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sat, 9 May 2020 23:06:02 +0300 Subject: [PATCH 1/9] mlxsw: spectrum_matchall: Restrict sample action to be allowed only on ingress HW supports packet sampling on ingress only. Check and fail if user is adding sample on egress. Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlxsw/spectrum_matchall.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_matchall.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_matchall.c index da1c05f44cec..c75661521bbc 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_matchall.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_matchall.c @@ -212,6 +212,11 @@ int mlxsw_sp_mall_replace(struct mlxsw_sp_flow_block *block, mall_entry->mirror.to_dev = act->dev; } else if (act->id == FLOW_ACTION_SAMPLE && protocol == htons(ETH_P_ALL)) { + if (!mall_entry->ingress) { + NL_SET_ERR_MSG(f->common.extack, "Sample is not supported on egress"); + err = -EOPNOTSUPP; + goto errout; + } if (act->sample.rate > MLXSW_REG_MPSC_RATE_MAX) { NL_SET_ERR_MSG(f->common.extack, "Sample rate not supported"); err = -EOPNOTSUPP; From 593bb843798636131bd6d9eb1633b1ee55a8a53b Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sat, 9 May 2020 23:06:03 +0300 Subject: [PATCH 2/9] mlxsw: spectrum_flower: Expose a function to get min and max rule priority Introduce an infrastructure that allows to get minimum and maximum rule priority for specified chain. This is going to be used by a subsequent patch to enforce ordering between flower and matchall filters. Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: Jakub Kicinski --- .../net/ethernet/mellanox/mlxsw/spectrum.h | 7 ++++ .../ethernet/mellanox/mlxsw/spectrum_acl.c | 13 ++++++- .../mellanox/mlxsw/spectrum_acl_tcam.c | 39 ++++++++++++++++--- .../mellanox/mlxsw/spectrum_acl_tcam.h | 3 +- .../ethernet/mellanox/mlxsw/spectrum_flower.c | 20 ++++++++++ 5 files changed, 75 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index a12ca673c224..d9a963c77401 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -739,6 +739,9 @@ mlxsw_sp_acl_ruleset_get(struct mlxsw_sp *mlxsw_sp, void mlxsw_sp_acl_ruleset_put(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_ruleset *ruleset); u16 mlxsw_sp_acl_ruleset_group_id(struct mlxsw_sp_acl_ruleset *ruleset); +void mlxsw_sp_acl_ruleset_prio_get(struct mlxsw_sp_acl_ruleset *ruleset, + unsigned int *p_min_prio, + unsigned int *p_max_prio); struct mlxsw_sp_acl_rule_info * mlxsw_sp_acl_rulei_create(struct mlxsw_sp_acl *acl, @@ -912,6 +915,10 @@ int mlxsw_sp_flower_tmplt_create(struct mlxsw_sp *mlxsw_sp, void mlxsw_sp_flower_tmplt_destroy(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_flow_block *block, struct flow_cls_offload *f); +int mlxsw_sp_flower_prio_get(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_flow_block *block, + u32 chain_index, unsigned int *p_min_prio, + unsigned int *p_max_prio); /* spectrum_qdisc.c */ int mlxsw_sp_tc_qdisc_init(struct mlxsw_sp_port *mlxsw_sp_port); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c index c61f78e30397..47da9ee0045d 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c @@ -51,6 +51,8 @@ struct mlxsw_sp_acl_ruleset { struct mlxsw_sp_acl_ruleset_ht_key ht_key; struct rhashtable rule_ht; unsigned int ref_count; + unsigned int min_prio; + unsigned int max_prio; unsigned long priv[]; /* priv has to be always the last item */ }; @@ -178,7 +180,8 @@ mlxsw_sp_acl_ruleset_create(struct mlxsw_sp *mlxsw_sp, goto err_rhashtable_init; err = ops->ruleset_add(mlxsw_sp, &acl->tcam, ruleset->priv, - tmplt_elusage); + tmplt_elusage, &ruleset->min_prio, + &ruleset->max_prio); if (err) goto err_ops_ruleset_add; @@ -293,6 +296,14 @@ u16 mlxsw_sp_acl_ruleset_group_id(struct mlxsw_sp_acl_ruleset *ruleset) return ops->ruleset_group_id(ruleset->priv); } +void mlxsw_sp_acl_ruleset_prio_get(struct mlxsw_sp_acl_ruleset *ruleset, + unsigned int *p_min_prio, + unsigned int *p_max_prio) +{ + *p_min_prio = ruleset->min_prio; + *p_max_prio = ruleset->max_prio; +} + struct mlxsw_sp_acl_rule_info * mlxsw_sp_acl_rulei_create(struct mlxsw_sp_acl *acl, struct mlxsw_afa_block *afa_block) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c index a6e30e020b5c..5c020403342f 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c @@ -179,6 +179,8 @@ struct mlxsw_sp_acl_tcam_vgroup { bool tmplt_elusage_set; struct mlxsw_afk_element_usage tmplt_elusage; bool vregion_rehash_enabled; + unsigned int *p_min_prio; + unsigned int *p_max_prio; }; struct mlxsw_sp_acl_tcam_rehash_ctx { @@ -316,13 +318,17 @@ mlxsw_sp_acl_tcam_vgroup_add(struct mlxsw_sp *mlxsw_sp, const struct mlxsw_sp_acl_tcam_pattern *patterns, unsigned int patterns_count, struct mlxsw_afk_element_usage *tmplt_elusage, - bool vregion_rehash_enabled) + bool vregion_rehash_enabled, + unsigned int *p_min_prio, + unsigned int *p_max_prio) { int err; vgroup->patterns = patterns; vgroup->patterns_count = patterns_count; vgroup->vregion_rehash_enabled = vregion_rehash_enabled; + vgroup->p_min_prio = p_min_prio; + vgroup->p_max_prio = p_max_prio; if (tmplt_elusage) { vgroup->tmplt_elusage_set = true; @@ -416,6 +422,21 @@ mlxsw_sp_acl_tcam_vregion_max_prio(struct mlxsw_sp_acl_tcam_vregion *vregion) return vchunk->priority; } +static void +mlxsw_sp_acl_tcam_vgroup_prio_update(struct mlxsw_sp_acl_tcam_vgroup *vgroup) +{ + struct mlxsw_sp_acl_tcam_vregion *vregion; + + if (list_empty(&vgroup->vregion_list)) + return; + vregion = list_first_entry(&vgroup->vregion_list, + typeof(*vregion), list); + *vgroup->p_min_prio = mlxsw_sp_acl_tcam_vregion_prio(vregion); + vregion = list_last_entry(&vgroup->vregion_list, + typeof(*vregion), list); + *vgroup->p_max_prio = mlxsw_sp_acl_tcam_vregion_max_prio(vregion); +} + static int mlxsw_sp_acl_tcam_group_region_attach(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_tcam_group *group, @@ -1035,6 +1056,7 @@ mlxsw_sp_acl_tcam_vchunk_create(struct mlxsw_sp *mlxsw_sp, } list_add_tail(&vchunk->list, pos); mutex_unlock(&vregion->lock); + mlxsw_sp_acl_tcam_vgroup_prio_update(vgroup); return vchunk; @@ -1066,6 +1088,7 @@ mlxsw_sp_acl_tcam_vchunk_destroy(struct mlxsw_sp *mlxsw_sp, mlxsw_sp_acl_tcam_vchunk_ht_params); mlxsw_sp_acl_tcam_vregion_put(mlxsw_sp, vchunk->vregion); kfree(vchunk); + mlxsw_sp_acl_tcam_vgroup_prio_update(vgroup); } static struct mlxsw_sp_acl_tcam_vchunk * @@ -1582,14 +1605,17 @@ static int mlxsw_sp_acl_tcam_flower_ruleset_add(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_tcam *tcam, void *ruleset_priv, - struct mlxsw_afk_element_usage *tmplt_elusage) + struct mlxsw_afk_element_usage *tmplt_elusage, + unsigned int *p_min_prio, + unsigned int *p_max_prio) { struct mlxsw_sp_acl_tcam_flower_ruleset *ruleset = ruleset_priv; return mlxsw_sp_acl_tcam_vgroup_add(mlxsw_sp, tcam, &ruleset->vgroup, mlxsw_sp_acl_tcam_patterns, MLXSW_SP_ACL_TCAM_PATTERNS_COUNT, - tmplt_elusage, true); + tmplt_elusage, true, + p_min_prio, p_max_prio); } static void @@ -1698,7 +1724,9 @@ static int mlxsw_sp_acl_tcam_mr_ruleset_add(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_tcam *tcam, void *ruleset_priv, - struct mlxsw_afk_element_usage *tmplt_elusage) + struct mlxsw_afk_element_usage *tmplt_elusage, + unsigned int *p_min_prio, + unsigned int *p_max_prio) { struct mlxsw_sp_acl_tcam_mr_ruleset *ruleset = ruleset_priv; int err; @@ -1706,7 +1734,8 @@ mlxsw_sp_acl_tcam_mr_ruleset_add(struct mlxsw_sp *mlxsw_sp, err = mlxsw_sp_acl_tcam_vgroup_add(mlxsw_sp, tcam, &ruleset->vgroup, mlxsw_sp_acl_tcam_patterns, MLXSW_SP_ACL_TCAM_PATTERNS_COUNT, - tmplt_elusage, false); + tmplt_elusage, false, + p_min_prio, p_max_prio); if (err) return err; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.h index 96437992b102..a41df10ade9b 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.h @@ -42,7 +42,8 @@ struct mlxsw_sp_acl_profile_ops { size_t ruleset_priv_size; int (*ruleset_add)(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_tcam *tcam, void *ruleset_priv, - struct mlxsw_afk_element_usage *tmplt_elusage); + struct mlxsw_afk_element_usage *tmplt_elusage, + unsigned int *p_min_prio, unsigned int *p_max_prio); void (*ruleset_del)(struct mlxsw_sp *mlxsw_sp, void *ruleset_priv); int (*ruleset_bind)(struct mlxsw_sp *mlxsw_sp, void *ruleset_priv, struct mlxsw_sp_port *mlxsw_sp_port, diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c index 0897ca1967ab..18d22217e435 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c @@ -647,3 +647,23 @@ void mlxsw_sp_flower_tmplt_destroy(struct mlxsw_sp *mlxsw_sp, mlxsw_sp_acl_ruleset_put(mlxsw_sp, ruleset); mlxsw_sp_acl_ruleset_put(mlxsw_sp, ruleset); } + +int mlxsw_sp_flower_prio_get(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_flow_block *block, + u32 chain_index, unsigned int *p_min_prio, + unsigned int *p_max_prio) +{ + struct mlxsw_sp_acl_ruleset *ruleset; + + ruleset = mlxsw_sp_acl_ruleset_lookup(mlxsw_sp, block, + chain_index, + MLXSW_SP_ACL_PROFILE_FLOWER); + if (IS_ERR(ruleset)) + /* In case there are no flower rules, the caller + * receives -ENOENT to indicate there is no need + * to check the priorities. + */ + return PTR_ERR(ruleset); + mlxsw_sp_acl_ruleset_prio_get(ruleset, p_min_prio, p_max_prio); + return 0; +} From 5a2939b9d7ddbdc399ce42cae8150c424e0bd764 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sat, 9 May 2020 23:06:04 +0300 Subject: [PATCH 3/9] mlxsw: spectrum_matchall: Put matchall list into substruct of flow struct As there are going to be other matchall specific fields in flow structure, put the existing list field into matchall substruct. Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 4 +++- drivers/net/ethernet/mellanox/mlxsw/spectrum_flow.c | 2 +- .../net/ethernet/mellanox/mlxsw/spectrum_matchall.c | 10 +++++----- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index d9a963c77401..553693469805 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -636,7 +636,9 @@ struct mlxsw_sp_acl_rule_info { /* spectrum_flow.c */ struct mlxsw_sp_flow_block { struct list_head binding_list; - struct list_head mall_list; + struct { + struct list_head list; + } mall; struct mlxsw_sp_acl_ruleset *ruleset_zero; struct mlxsw_sp *mlxsw_sp; unsigned int rule_count; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flow.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flow.c index ecab581ff956..76644f6a8121 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flow.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flow.c @@ -18,7 +18,7 @@ mlxsw_sp_flow_block_create(struct mlxsw_sp *mlxsw_sp, struct net *net) if (!block) return NULL; INIT_LIST_HEAD(&block->binding_list); - INIT_LIST_HEAD(&block->mall_list); + INIT_LIST_HEAD(&block->mall.list); block->mlxsw_sp = mlxsw_sp; block->net = net; return block; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_matchall.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_matchall.c index c75661521bbc..d64ee31a611c 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_matchall.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_matchall.c @@ -37,7 +37,7 @@ mlxsw_sp_mall_entry_find(struct mlxsw_sp_flow_block *block, unsigned long cookie { struct mlxsw_sp_mall_entry *mall_entry; - list_for_each_entry(mall_entry, &block->mall_list, list) + list_for_each_entry(mall_entry, &block->mall.list, list) if (mall_entry->cookie == cookie) return mall_entry; @@ -244,7 +244,7 @@ int mlxsw_sp_mall_replace(struct mlxsw_sp_flow_block *block, block->egress_blocker_rule_count++; else block->ingress_blocker_rule_count++; - list_add_tail(&mall_entry->list, &block->mall_list); + list_add_tail(&mall_entry->list, &block->mall.list); return 0; rollback: @@ -285,7 +285,7 @@ int mlxsw_sp_mall_port_bind(struct mlxsw_sp_flow_block *block, struct mlxsw_sp_mall_entry *mall_entry; int err; - list_for_each_entry(mall_entry, &block->mall_list, list) { + list_for_each_entry(mall_entry, &block->mall.list, list) { err = mlxsw_sp_mall_port_rule_add(mlxsw_sp_port, mall_entry); if (err) goto rollback; @@ -293,7 +293,7 @@ int mlxsw_sp_mall_port_bind(struct mlxsw_sp_flow_block *block, return 0; rollback: - list_for_each_entry_continue_reverse(mall_entry, &block->mall_list, + list_for_each_entry_continue_reverse(mall_entry, &block->mall.list, list) mlxsw_sp_mall_port_rule_del(mlxsw_sp_port, mall_entry); return err; @@ -304,6 +304,6 @@ void mlxsw_sp_mall_port_unbind(struct mlxsw_sp_flow_block *block, { struct mlxsw_sp_mall_entry *mall_entry; - list_for_each_entry(mall_entry, &block->mall_list, list) + list_for_each_entry(mall_entry, &block->mall.list, list) mlxsw_sp_mall_port_rule_del(mlxsw_sp_port, mall_entry); } From aed65285fb9e16328f9bbf14394fef5ddbe82815 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sat, 9 May 2020 23:06:05 +0300 Subject: [PATCH 4/9] mlxsw: spectrum_matchall: Expose a function to get min and max rule priority Introduce an infrastructure that allows to get minimum and maximum rule priority for specified chain. This is going to be used by a subsequent patch to enforce ordering between flower and matchall filters. Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: Jakub Kicinski --- .../net/ethernet/mellanox/mlxsw/spectrum.h | 4 +++ .../mellanox/mlxsw/spectrum_matchall.c | 34 +++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index 553693469805..456dbaa5ee26 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -638,6 +638,8 @@ struct mlxsw_sp_flow_block { struct list_head binding_list; struct { struct list_head list; + unsigned int min_prio; + unsigned int max_prio; } mall; struct mlxsw_sp_acl_ruleset *ruleset_zero; struct mlxsw_sp *mlxsw_sp; @@ -900,6 +902,8 @@ int mlxsw_sp_mall_port_bind(struct mlxsw_sp_flow_block *block, struct mlxsw_sp_port *mlxsw_sp_port); void mlxsw_sp_mall_port_unbind(struct mlxsw_sp_flow_block *block, struct mlxsw_sp_port *mlxsw_sp_port); +int mlxsw_sp_mall_prio_get(struct mlxsw_sp_flow_block *block, u32 chain_index, + unsigned int *p_min_prio, unsigned int *p_max_prio); /* spectrum_flower.c */ int mlxsw_sp_flower_replace(struct mlxsw_sp *mlxsw_sp, diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_matchall.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_matchall.c index d64ee31a611c..b11bab76b2e1 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_matchall.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_matchall.c @@ -23,6 +23,7 @@ struct mlxsw_sp_mall_mirror_entry { struct mlxsw_sp_mall_entry { struct list_head list; unsigned long cookie; + unsigned int priority; enum mlxsw_sp_mall_action_type type; bool ingress; union { @@ -175,6 +176,22 @@ mlxsw_sp_mall_port_rule_del(struct mlxsw_sp_port *mlxsw_sp_port, } } +static void mlxsw_sp_mall_prio_update(struct mlxsw_sp_flow_block *block) +{ + struct mlxsw_sp_mall_entry *mall_entry; + + if (list_empty(&block->mall.list)) + return; + block->mall.min_prio = UINT_MAX; + block->mall.max_prio = 0; + list_for_each_entry(mall_entry, &block->mall.list, list) { + if (mall_entry->priority < block->mall.min_prio) + block->mall.min_prio = mall_entry->priority; + if (mall_entry->priority > block->mall.max_prio) + block->mall.max_prio = mall_entry->priority; + } +} + int mlxsw_sp_mall_replace(struct mlxsw_sp_flow_block *block, struct tc_cls_matchall_offload *f) { @@ -203,6 +220,7 @@ int mlxsw_sp_mall_replace(struct mlxsw_sp_flow_block *block, if (!mall_entry) return -ENOMEM; mall_entry->cookie = f->cookie; + mall_entry->priority = f->common.prio; mall_entry->ingress = mlxsw_sp_flow_block_is_ingress_bound(block); act = &f->rule->action.entries[0]; @@ -245,6 +263,7 @@ int mlxsw_sp_mall_replace(struct mlxsw_sp_flow_block *block, else block->ingress_blocker_rule_count++; list_add_tail(&mall_entry->list, &block->mall.list); + mlxsw_sp_mall_prio_update(block); return 0; rollback: @@ -277,6 +296,7 @@ void mlxsw_sp_mall_destroy(struct mlxsw_sp_flow_block *block, list_for_each_entry(binding, &block->binding_list, list) mlxsw_sp_mall_port_rule_del(binding->mlxsw_sp_port, mall_entry); kfree_rcu(mall_entry, rcu); /* sample RX packets may be in-flight */ + mlxsw_sp_mall_prio_update(block); } int mlxsw_sp_mall_port_bind(struct mlxsw_sp_flow_block *block, @@ -307,3 +327,17 @@ void mlxsw_sp_mall_port_unbind(struct mlxsw_sp_flow_block *block, list_for_each_entry(mall_entry, &block->mall.list, list) mlxsw_sp_mall_port_rule_del(mlxsw_sp_port, mall_entry); } + +int mlxsw_sp_mall_prio_get(struct mlxsw_sp_flow_block *block, u32 chain_index, + unsigned int *p_min_prio, unsigned int *p_max_prio) +{ + if (chain_index || list_empty(&block->mall.list)) + /* In case there are no matchall rules, the caller + * receives -ENOENT to indicate there is no need + * to check the priorities. + */ + return -ENOENT; + *p_min_prio = block->mall.min_prio; + *p_max_prio = block->mall.max_prio; + return 0; +} From 18346b70ab776fa2cbb9a5f0f0f9c4700c470c5e Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sat, 9 May 2020 23:06:06 +0300 Subject: [PATCH 5/9] mlxsw: spectrum_matchall: Forbid to insert matchall rules in collision with flower rules On ingress, the matchall rules doing mirroring and sampling are offloaded into hardware blocks that are processed before any flower rules. On egress, the matchall mirroring rules are offloaded into hardware block that is processed after all flower rules. Therefore check the priorities of inserted matchall rules against existing flower rules and ensure the correct ordering. Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: Jakub Kicinski --- .../net/ethernet/mellanox/mlxsw/spectrum.h | 3 +- .../ethernet/mellanox/mlxsw/spectrum_flow.c | 4 +- .../mellanox/mlxsw/spectrum_matchall.c | 37 ++++++++++++++++++- 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index 456dbaa5ee26..147a5634244b 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -894,7 +894,8 @@ extern const struct mlxsw_afk_ops mlxsw_sp1_afk_ops; extern const struct mlxsw_afk_ops mlxsw_sp2_afk_ops; /* spectrum_matchall.c */ -int mlxsw_sp_mall_replace(struct mlxsw_sp_flow_block *block, +int mlxsw_sp_mall_replace(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_flow_block *block, struct tc_cls_matchall_offload *f); void mlxsw_sp_mall_destroy(struct mlxsw_sp_flow_block *block, struct tc_cls_matchall_offload *f); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flow.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flow.c index 76644f6a8121..47b66f347ff1 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flow.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flow.c @@ -135,9 +135,11 @@ static int mlxsw_sp_flow_block_unbind(struct mlxsw_sp *mlxsw_sp, static int mlxsw_sp_flow_block_mall_cb(struct mlxsw_sp_flow_block *flow_block, struct tc_cls_matchall_offload *f) { + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_flow_block_mlxsw_sp(flow_block); + switch (f->command) { case TC_CLSMATCHALL_REPLACE: - return mlxsw_sp_mall_replace(flow_block, f); + return mlxsw_sp_mall_replace(mlxsw_sp, flow_block, f); case TC_CLSMATCHALL_DESTROY: mlxsw_sp_mall_destroy(flow_block, f); return 0; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_matchall.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_matchall.c index b11bab76b2e1..f1a44a8eda55 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_matchall.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_matchall.c @@ -192,13 +192,17 @@ static void mlxsw_sp_mall_prio_update(struct mlxsw_sp_flow_block *block) } } -int mlxsw_sp_mall_replace(struct mlxsw_sp_flow_block *block, +int mlxsw_sp_mall_replace(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_flow_block *block, struct tc_cls_matchall_offload *f) { struct mlxsw_sp_flow_block_binding *binding; struct mlxsw_sp_mall_entry *mall_entry; __be16 protocol = f->common.protocol; struct flow_action_entry *act; + unsigned int flower_min_prio; + unsigned int flower_max_prio; + bool flower_prio_valid; int err; if (!flow_offload_has_one_action(&f->rule->action)) { @@ -216,6 +220,19 @@ int mlxsw_sp_mall_replace(struct mlxsw_sp_flow_block *block, return -EOPNOTSUPP; } + err = mlxsw_sp_flower_prio_get(mlxsw_sp, block, f->common.chain_index, + &flower_min_prio, &flower_max_prio); + if (err) { + if (err != -ENOENT) { + NL_SET_ERR_MSG(f->common.extack, "Failed to get flower priorities"); + return err; + } + flower_prio_valid = false; + /* No flower filters are installed in specified chain. */ + } else { + flower_prio_valid = true; + } + mall_entry = kzalloc(sizeof(*mall_entry), GFP_KERNEL); if (!mall_entry) return -ENOMEM; @@ -226,6 +243,18 @@ int mlxsw_sp_mall_replace(struct mlxsw_sp_flow_block *block, act = &f->rule->action.entries[0]; if (act->id == FLOW_ACTION_MIRRED && protocol == htons(ETH_P_ALL)) { + if (flower_prio_valid && mall_entry->ingress && + mall_entry->priority >= flower_min_prio) { + NL_SET_ERR_MSG(f->common.extack, "Failed to add behind existing flower rules"); + err = -EOPNOTSUPP; + goto errout; + } + if (flower_prio_valid && !mall_entry->ingress && + mall_entry->priority <= flower_max_prio) { + NL_SET_ERR_MSG(f->common.extack, "Failed to add in front of existing flower rules"); + err = -EOPNOTSUPP; + goto errout; + } mall_entry->type = MLXSW_SP_MALL_ACTION_TYPE_MIRROR; mall_entry->mirror.to_dev = act->dev; } else if (act->id == FLOW_ACTION_SAMPLE && @@ -235,6 +264,12 @@ int mlxsw_sp_mall_replace(struct mlxsw_sp_flow_block *block, err = -EOPNOTSUPP; goto errout; } + if (flower_prio_valid && + mall_entry->priority >= flower_min_prio) { + NL_SET_ERR_MSG(f->common.extack, "Failed to add behind existing flower rules"); + err = -EOPNOTSUPP; + goto errout; + } if (act->sample.rate > MLXSW_REG_MPSC_RATE_MAX) { NL_SET_ERR_MSG(f->common.extack, "Sample rate not supported"); err = -EOPNOTSUPP; From 67ed68fc0c9aa4a456d03df216e571e0c6177097 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sat, 9 May 2020 23:06:07 +0300 Subject: [PATCH 6/9] mlxsw: spectrum_flower: Forbid to insert flower rules in collision with matchall rules On ingress, the matchall rules doing mirroring and sampling are offloaded into hardware blocks that are processed before any flower rules. On egress, the matchall mirroring rules are offloaded into hardware block that is processed after all flower rules. Therefore check the priorities of inserted flower rules against existing matchall rules and ensure the correct ordering. Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: Jakub Kicinski --- .../ethernet/mellanox/mlxsw/spectrum_flower.c | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c index 18d22217e435..b286fe158820 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c @@ -505,6 +505,34 @@ static int mlxsw_sp_flower_parse(struct mlxsw_sp *mlxsw_sp, f->common.extack); } +static int mlxsw_sp_flower_mall_prio_check(struct mlxsw_sp_flow_block *block, + struct flow_cls_offload *f) +{ + bool ingress = mlxsw_sp_flow_block_is_ingress_bound(block); + unsigned int mall_min_prio; + unsigned int mall_max_prio; + int err; + + err = mlxsw_sp_mall_prio_get(block, f->common.chain_index, + &mall_min_prio, &mall_max_prio); + if (err) { + if (err == -ENOENT) + /* No matchall filters installed on this chain. */ + return 0; + NL_SET_ERR_MSG(f->common.extack, "Failed to get matchall priorities"); + return err; + } + if (ingress && f->common.prio <= mall_min_prio) { + NL_SET_ERR_MSG(f->common.extack, "Failed to add in front of existing matchall rules"); + return -EOPNOTSUPP; + } + if (!ingress && f->common.prio >= mall_max_prio) { + NL_SET_ERR_MSG(f->common.extack, "Failed to add behind of existing matchall rules"); + return -EOPNOTSUPP; + } + return 0; +} + int mlxsw_sp_flower_replace(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_flow_block *block, struct flow_cls_offload *f) @@ -514,6 +542,10 @@ int mlxsw_sp_flower_replace(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_rule *rule; int err; + err = mlxsw_sp_flower_mall_prio_check(block, f); + if (err) + return err; + ruleset = mlxsw_sp_acl_ruleset_get(mlxsw_sp, block, f->common.chain_index, MLXSW_SP_ACL_PROFILE_FLOWER, NULL); From b886dea37b78debeea7019c649c05c7e2ba027fc Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sat, 9 May 2020 23:06:08 +0300 Subject: [PATCH 7/9] selftests: mlxsw: rename tc_flower_restrictions.sh to tc_restrictions.sh The file is about to contain matchall restrictions too, so change the name to make it more generic. Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: Jakub Kicinski --- .../net/mlxsw/{tc_flower_restrictions.sh => tc_restrictions.sh} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tools/testing/selftests/drivers/net/mlxsw/{tc_flower_restrictions.sh => tc_restrictions.sh} (100%) diff --git a/tools/testing/selftests/drivers/net/mlxsw/tc_flower_restrictions.sh b/tools/testing/selftests/drivers/net/mlxsw/tc_restrictions.sh similarity index 100% rename from tools/testing/selftests/drivers/net/mlxsw/tc_flower_restrictions.sh rename to tools/testing/selftests/drivers/net/mlxsw/tc_restrictions.sh From 240fe73457fbfc13cb30d1d16064f19590ff10f6 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sat, 9 May 2020 23:06:09 +0300 Subject: [PATCH 8/9] selftests: mlxsw: tc_restrictions: add test to check sample action restrictions Check that matchall rules with sample actions are not possible to be inserted to egress. Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: Jakub Kicinski --- .../drivers/net/mlxsw/tc_restrictions.sh | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tools/testing/selftests/drivers/net/mlxsw/tc_restrictions.sh b/tools/testing/selftests/drivers/net/mlxsw/tc_restrictions.sh index 68c80d0ec1ec..a67e80315e47 100755 --- a/tools/testing/selftests/drivers/net/mlxsw/tc_restrictions.sh +++ b/tools/testing/selftests/drivers/net/mlxsw/tc_restrictions.sh @@ -7,6 +7,7 @@ ALL_TESTS=" shared_block_drop_test egress_redirect_test multi_mirror_test + matchall_sample_egress_test " NUM_NETIFS=2 @@ -155,6 +156,30 @@ multi_mirror_test() log_test "multi mirror" } +matchall_sample_egress_test() +{ + RET=0 + + # It is forbidden in mlxsw driver to have matchall with sample action + # bound on egress + + tc qdisc add dev $swp1 clsact + + tc filter add dev $swp1 ingress protocol all pref 1 handle 101 \ + matchall skip_sw action sample rate 100 group 1 + check_err $? "Failed to add rule with sample action on ingress" + + tc filter del dev $swp1 ingress protocol all pref 1 handle 101 matchall + + tc filter add dev $swp1 egress protocol all pref 1 handle 101 \ + matchall skip_sw action sample rate 100 group 1 + check_fail $? "Incorrect success to add rule with sample action on egress" + + tc qdisc del dev $swp1 clsact + + log_test "matchall sample egress" +} + setup_prepare() { swp1=${NETIFS[p1]} From aa7431123fc6f36574d9cc23be24dc802bb4cfa5 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sat, 9 May 2020 23:06:10 +0300 Subject: [PATCH 9/9] selftests: mlxsw: tc_restrictions: add couple of test for the correct matchall-flower ordering Make sure that the drive restricts incorrect order of inserted matchall vs. flower rules. Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: Jakub Kicinski --- .../drivers/net/mlxsw/tc_restrictions.sh | 107 ++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/tools/testing/selftests/drivers/net/mlxsw/tc_restrictions.sh b/tools/testing/selftests/drivers/net/mlxsw/tc_restrictions.sh index a67e80315e47..9241250c5921 100755 --- a/tools/testing/selftests/drivers/net/mlxsw/tc_restrictions.sh +++ b/tools/testing/selftests/drivers/net/mlxsw/tc_restrictions.sh @@ -8,6 +8,9 @@ ALL_TESTS=" egress_redirect_test multi_mirror_test matchall_sample_egress_test + matchall_mirror_behind_flower_ingress_test + matchall_sample_behind_flower_ingress_test + matchall_mirror_behind_flower_egress_test " NUM_NETIFS=2 @@ -180,6 +183,110 @@ matchall_sample_egress_test() log_test "matchall sample egress" } +matchall_behind_flower_ingress_test() +{ + local action=$1 + local action_args=$2 + + RET=0 + + # On ingress, all matchall-mirror and matchall-sample + # rules have to be in front of the flower rules + + tc qdisc add dev $swp1 clsact + + tc filter add dev $swp1 ingress protocol ip pref 10 handle 101 flower \ + skip_sw dst_ip 192.0.2.2 action drop + + tc filter add dev $swp1 ingress protocol all pref 9 handle 102 \ + matchall skip_sw action $action_args + check_err $? "Failed to add matchall rule in front of a flower rule" + + tc filter del dev $swp1 ingress protocol all pref 9 handle 102 matchall + + tc filter add dev $swp1 ingress protocol all pref 11 handle 102 \ + matchall skip_sw action $action_args + check_fail $? "Incorrect success to add matchall rule behind a flower rule" + + tc filter del dev $swp1 ingress protocol ip pref 10 handle 101 flower + + tc filter add dev $swp1 ingress protocol all pref 9 handle 102 \ + matchall skip_sw action $action_args + + tc filter add dev $swp1 ingress protocol ip pref 10 handle 101 flower \ + skip_sw dst_ip 192.0.2.2 action drop + check_err $? "Failed to add flower rule behind a matchall rule" + + tc filter del dev $swp1 ingress protocol ip pref 10 handle 101 flower + + tc filter add dev $swp1 ingress protocol ip pref 8 handle 101 flower \ + skip_sw dst_ip 192.0.2.2 action drop + check_fail $? "Incorrect success to add flower rule in front of a matchall rule" + + tc qdisc del dev $swp1 clsact + + log_test "matchall $action flower ingress" +} + +matchall_mirror_behind_flower_ingress_test() +{ + matchall_behind_flower_ingress_test "mirror" "mirred egress mirror dev $swp2" +} + +matchall_sample_behind_flower_ingress_test() +{ + matchall_behind_flower_ingress_test "sample" "sample rate 100 group 1" +} + +matchall_behind_flower_egress_test() +{ + local action=$1 + local action_args=$2 + + RET=0 + + # On egress, all matchall-mirror rules have to be behind the flower rules + + tc qdisc add dev $swp1 clsact + + tc filter add dev $swp1 egress protocol ip pref 10 handle 101 flower \ + skip_sw dst_ip 192.0.2.2 action drop + + tc filter add dev $swp1 egress protocol all pref 11 handle 102 \ + matchall skip_sw action $action_args + check_err $? "Failed to add matchall rule in front of a flower rule" + + tc filter del dev $swp1 egress protocol all pref 11 handle 102 matchall + + tc filter add dev $swp1 egress protocol all pref 9 handle 102 \ + matchall skip_sw action $action_args + check_fail $? "Incorrect success to add matchall rule behind a flower rule" + + tc filter del dev $swp1 egress protocol ip pref 10 handle 101 flower + + tc filter add dev $swp1 egress protocol all pref 11 handle 102 \ + matchall skip_sw action $action_args + + tc filter add dev $swp1 egress protocol ip pref 10 handle 101 flower \ + skip_sw dst_ip 192.0.2.2 action drop + check_err $? "Failed to add flower rule behind a matchall rule" + + tc filter del dev $swp1 egress protocol ip pref 10 handle 101 flower + + tc filter add dev $swp1 egress protocol ip pref 12 handle 101 flower \ + skip_sw dst_ip 192.0.2.2 action drop + check_fail $? "Incorrect success to add flower rule in front of a matchall rule" + + tc qdisc del dev $swp1 clsact + + log_test "matchall $action flower egress" +} + +matchall_mirror_behind_flower_egress_test() +{ + matchall_behind_flower_egress_test "mirror" "mirred egress mirror dev $swp2" +} + setup_prepare() { swp1=${NETIFS[p1]}