diff options
author | Jakub Kicinski <kuba@kernel.org> | 2020-05-09 16:03:26 -0700 |
---|---|---|
committer | Jakub Kicinski <kuba@kernel.org> | 2020-05-09 16:03:39 -0700 |
commit | 02a5043b22ed2f6ea03b8533b47fdaa5853832c9 (patch) | |
tree | ca77ee82cb0304b50de4fdfb0a150212342db3df | |
parent | 72ef908bb3ff9261dc38d079ef332c91418f8693 (diff) | |
parent | aa7431123fc6f36574d9cc23be24dc802bb4cfa5 (diff) | |
download | linux-02a5043b22ed2f6ea03b8533b47fdaa5853832c9.tar.bz2 |
Merge branch 'mlxsw-spectrum-Enforce-some-HW-limitations-for-matchall-TC-offload'
Ido Schimmel says:
====================
mlxsw: spectrum: Enforce some HW limitations for matchall TC offload
Jiri says:
There are some limitations for TC matchall classifier offload that are
given by the mlxsw HW dataplane. It is not possible to do sampling on
egress and also the mirror/sample vs. ACL (flower) ordering is fixed. So
check this and forbid to offload incorrect setup.
====================
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
-rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 18 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c | 13 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c | 39 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.h | 3 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/spectrum_flow.c | 6 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c | 52 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/spectrum_matchall.c | 86 | ||||
-rwxr-xr-x | tools/testing/selftests/drivers/net/mlxsw/tc_restrictions.sh (renamed from tools/testing/selftests/drivers/net/mlxsw/tc_flower_restrictions.sh) | 132 |
8 files changed, 332 insertions, 17 deletions
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index a12ca673c224..147a5634244b 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -636,7 +636,11 @@ 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; + unsigned int min_prio; + unsigned int max_prio; + } mall; struct mlxsw_sp_acl_ruleset *ruleset_zero; struct mlxsw_sp *mlxsw_sp; unsigned int rule_count; @@ -739,6 +743,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, @@ -887,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); @@ -895,6 +903,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, @@ -912,6 +922,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_flow.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flow.c index ecab581ff956..47b66f347ff1 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; @@ -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_flower.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c index 0897ca1967ab..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); @@ -647,3 +679,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; +} diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_matchall.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_matchall.c index da1c05f44cec..f1a44a8eda55 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 { @@ -37,7 +38,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; @@ -175,13 +176,33 @@ mlxsw_sp_mall_port_rule_del(struct mlxsw_sp_port *mlxsw_sp_port, } } -int mlxsw_sp_mall_replace(struct mlxsw_sp_flow_block *block, +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 *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)) { @@ -199,19 +220,56 @@ 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; 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]; 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 && 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 (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; @@ -239,7 +297,8 @@ 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); + mlxsw_sp_mall_prio_update(block); return 0; rollback: @@ -272,6 +331,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, @@ -280,7 +340,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; @@ -288,7 +348,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; @@ -299,6 +359,20 @@ 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); } + +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; +} diff --git a/tools/testing/selftests/drivers/net/mlxsw/tc_flower_restrictions.sh b/tools/testing/selftests/drivers/net/mlxsw/tc_restrictions.sh index 68c80d0ec1ec..9241250c5921 100755 --- a/tools/testing/selftests/drivers/net/mlxsw/tc_flower_restrictions.sh +++ b/tools/testing/selftests/drivers/net/mlxsw/tc_restrictions.sh @@ -7,6 +7,10 @@ ALL_TESTS=" shared_block_drop_test 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 @@ -155,6 +159,134 @@ 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" +} + +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]} |