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>
This commit is contained in:
commit
02a5043b22
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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]}
|
Loading…
Reference in New Issue