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:
Jakub Kicinski 2020-05-09 16:03:26 -07:00
commit 02a5043b22
8 changed files with 332 additions and 17 deletions

View file

@ -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);

View file

@ -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)

View file

@ -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;

View file

@ -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,

View file

@ -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;

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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]}