Files
linux/tools/testing/selftests/drivers/net/mlxsw/spectrum-2/tc_flower.sh
Ido Schimmel 75d8d7a630 mlxsw: spectrum_acl: Fix ACL scale regression and firmware errors
ACLs that reside in the algorithmic TCAM (A-TCAM) in Spectrum-2 and
newer ASICs can share the same mask if their masks only differ in up to
8 consecutive bits. For example, consider the following filters:

 # tc filter add dev swp1 ingress pref 1 proto ip flower dst_ip 192.0.2.0/24 action drop
 # tc filter add dev swp1 ingress pref 1 proto ip flower dst_ip 198.51.100.128/25 action drop

The second filter can use the same mask as the first (dst_ip/24) with a
delta of 1 bit.

However, the above only works because the two filters have different
values in the common unmasked part (dst_ip/24). When entries have the
same value in the common unmasked part they create undesired collisions
in the device since many entries now have the same key. This leads to
firmware errors such as [1] and to a reduced scale.

Fix by adjusting the hash table key to only include the value in the
common unmasked part. That is, without including the delta bits. That
way the driver will detect the collision during filter insertion and
spill the filter into the circuit TCAM (C-TCAM).

Add a test case that fails without the fix and adjust existing cases
that check C-TCAM spillage according to the above limitation.

[1]
mlxsw_spectrum2 0000:06:00.0: EMAD reg access failed (tid=3379b18a00003394,reg_id=3027(ptce3),type=write,status=8(resource not available))

Fixes: c22291f7cf ("mlxsw: spectrum: acl: Implement delta for ERP")
Reported-by: Alexander Zubkov <green@qrator.net>
Signed-off-by: Ido Schimmel <idosch@nvidia.com>
Reviewed-by: Amit Cohen <amcohen@nvidia.com>
Tested-by: Alexander Zubkov <green@qrator.net>
Signed-off-by: Petr Machata <petrm@nvidia.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
2024-06-10 11:14:52 +01:00

1177 lines
33 KiB
Bash
Executable File

#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
# This test is for checking the A-TCAM and C-TCAM operation in Spectrum-2.
# It tries to exercise as many code paths in the eRP state machine as
# possible.
lib_dir=$(dirname $0)/../../../../net/forwarding
ALL_TESTS="single_mask_test identical_filters_test two_masks_test \
multiple_masks_test ctcam_edge_cases_test delta_simple_test \
delta_two_masks_one_key_test delta_simple_rehash_test \
bloom_simple_test bloom_complex_test bloom_delta_test \
max_erp_entries_test max_group_size_test collision_test"
NUM_NETIFS=2
source $lib_dir/lib.sh
source $lib_dir/tc_common.sh
source $lib_dir/devlink_lib.sh
tcflags="skip_hw"
h1_create()
{
simple_if_init $h1 192.0.2.1/24 198.51.100.1/24
}
h1_destroy()
{
simple_if_fini $h1 192.0.2.1/24 198.51.100.1/24
}
h2_create()
{
simple_if_init $h2 192.0.2.2/24 198.51.100.2/24
tc qdisc add dev $h2 clsact
}
h2_destroy()
{
tc qdisc del dev $h2 clsact
simple_if_fini $h2 192.0.2.2/24 198.51.100.2/24
}
tp_record()
{
local tracepoint=$1
local cmd=$2
perf record -q -e $tracepoint $cmd
return $?
}
tp_record_all()
{
local tracepoint=$1
local seconds=$2
perf record -a -q -e $tracepoint sleep $seconds
return $?
}
__tp_hit_count()
{
local tracepoint=$1
local perf_output=`perf script -F trace:event,trace`
return `echo $perf_output | grep "$tracepoint:" | wc -l`
}
tp_check_hits()
{
local tracepoint=$1
local count=$2
__tp_hit_count $tracepoint
if [[ "$?" -ne "$count" ]]; then
return 1
fi
return 0
}
tp_check_hits_any()
{
local tracepoint=$1
__tp_hit_count $tracepoint
if [[ "$?" -eq "0" ]]; then
return 1
fi
return 0
}
single_mask_test()
{
# When only a single mask is required, the device uses the master
# mask and not the eRP table. Verify that under this mode the right
# filter is matched
RET=0
tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \
$tcflags dst_ip 192.0.2.2 action drop
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
-t ip -q
tc_check_packets "dev $h2 ingress" 101 1
check_err $? "Single filter - did not match"
tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \
$tcflags dst_ip 198.51.100.2 action drop
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
-t ip -q
tc_check_packets "dev $h2 ingress" 101 2
check_err $? "Two filters - did not match highest priority"
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 198.51.100.1 -B 198.51.100.2 \
-t ip -q
tc_check_packets "dev $h2 ingress" 102 1
check_err $? "Two filters - did not match lowest priority"
tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 198.51.100.1 -B 198.51.100.2 \
-t ip -q
tc_check_packets "dev $h2 ingress" 102 2
check_err $? "Single filter - did not match after delete"
tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower
log_test "single mask test ($tcflags)"
}
identical_filters_test()
{
# When two filters that only differ in their priority are used,
# one needs to be inserted into the C-TCAM. This test verifies
# that filters are correctly spilled to C-TCAM and that the right
# filter is matched
RET=0
tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \
$tcflags dst_ip 192.0.2.2 action drop
tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \
$tcflags dst_ip 192.0.2.2 action drop
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
-t ip -q
tc_check_packets "dev $h2 ingress" 101 1
check_err $? "Did not match A-TCAM filter"
tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
-t ip -q
tc_check_packets "dev $h2 ingress" 102 1
check_err $? "Did not match C-TCAM filter after A-TCAM delete"
tc filter add dev $h2 ingress protocol ip pref 3 handle 103 flower \
$tcflags dst_ip 192.0.2.2 action drop
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
-t ip -q
tc_check_packets "dev $h2 ingress" 102 2
check_err $? "Did not match C-TCAM filter after A-TCAM add"
tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
-t ip -q
tc_check_packets "dev $h2 ingress" 103 1
check_err $? "Did not match A-TCAM filter after C-TCAM delete"
tc filter del dev $h2 ingress protocol ip pref 3 handle 103 flower
log_test "identical filters test ($tcflags)"
}
two_masks_test()
{
# When more than one mask is required, the eRP table is used. This
# test verifies that the eRP table is correctly allocated and used
RET=0
tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \
$tcflags dst_ip 192.0.2.2 action drop
tc filter add dev $h2 ingress protocol ip pref 3 handle 103 flower \
$tcflags dst_ip 192.0.0.0/8 action drop
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
-t ip -q
tc_check_packets "dev $h2 ingress" 101 1
check_err $? "Two filters - did not match highest priority"
tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
-t ip -q
tc_check_packets "dev $h2 ingress" 103 1
check_err $? "Single filter - did not match"
tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \
$tcflags dst_ip 192.0.2.0/24 action drop
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
-t ip -q
tc_check_packets "dev $h2 ingress" 102 1
check_err $? "Two filters - did not match highest priority after add"
tc filter del dev $h2 ingress protocol ip pref 3 handle 103 flower
tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower
log_test "two masks test ($tcflags)"
}
multiple_masks_test()
{
# The number of masks in a region is limited. Once the maximum
# number of masks has been reached filters that require new
# masks are spilled to the C-TCAM. This test verifies that
# spillage is performed correctly and that the right filter is
# matched
if [[ "$tcflags" != "skip_sw" ]]; then
return 0;
fi
local index
RET=0
NUM_MASKS=32
NUM_ERPS=16
BASE_INDEX=100
for i in $(eval echo {1..$NUM_MASKS}); do
index=$((BASE_INDEX - i))
if ((i > NUM_ERPS)); then
exp_hits=1
err_msg="$i filters - C-TCAM spill did not happen when it was expected"
else
exp_hits=0
err_msg="$i filters - C-TCAM spill happened when it should not"
fi
tp_record "mlxsw:mlxsw_sp_acl_atcam_entry_add_ctcam_spill" \
"tc filter add dev $h2 ingress protocol ip pref $index \
handle $index \
flower $tcflags \
dst_ip 192.0.2.2/${i} src_ip 192.0.2.1/${i} \
action drop"
tp_check_hits "mlxsw:mlxsw_sp_acl_atcam_entry_add_ctcam_spill" \
$exp_hits
check_err $? "$err_msg"
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 \
-B 192.0.2.2 -t ip -q
tc_check_packets "dev $h2 ingress" $index 1
check_err $? "$i filters - did not match highest priority (add)"
done
for i in $(eval echo {$NUM_MASKS..1}); do
index=$((BASE_INDEX - i))
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 \
-B 192.0.2.2 -t ip -q
tc_check_packets "dev $h2 ingress" $index 2
check_err $? "$i filters - did not match highest priority (del)"
tc filter del dev $h2 ingress protocol ip pref $index \
handle $index flower
done
log_test "multiple masks test ($tcflags)"
}
ctcam_two_atcam_masks_test()
{
RET=0
# First case: C-TCAM is disabled when there are two A-TCAM masks.
# We push a filter into the C-TCAM by using two identical filters
# as in identical_filters_test()
# Filter goes into A-TCAM
tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \
$tcflags dst_ip 192.0.2.2 action drop
# Filter goes into C-TCAM
tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \
$tcflags dst_ip 192.0.2.2 action drop
# Filter goes into A-TCAM
tc filter add dev $h2 ingress protocol ip pref 3 handle 103 flower \
$tcflags dst_ip 192.0.0.0/16 action drop
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
-t ip -q
tc_check_packets "dev $h2 ingress" 101 1
check_err $? "Did not match A-TCAM filter"
# Delete both A-TCAM and C-TCAM filters and make sure the remaining
# A-TCAM filter still works
tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower
tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
-t ip -q
tc_check_packets "dev $h2 ingress" 103 1
check_err $? "Did not match A-TCAM filter"
tc filter del dev $h2 ingress protocol ip pref 3 handle 103 flower
log_test "ctcam with two atcam masks test ($tcflags)"
}
ctcam_one_atcam_mask_test()
{
RET=0
# Second case: C-TCAM is disabled when there is one A-TCAM mask.
# The test is similar to identical_filters_test()
# Filter goes into A-TCAM
tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \
$tcflags dst_ip 192.0.2.2 action drop
# Filter goes into C-TCAM
tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \
$tcflags dst_ip 192.0.2.2 action drop
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
-t ip -q
tc_check_packets "dev $h2 ingress" 101 1
check_err $? "Did not match C-TCAM filter"
tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
-t ip -q
tc_check_packets "dev $h2 ingress" 102 1
check_err $? "Did not match A-TCAM filter"
tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower
log_test "ctcam with one atcam mask test ($tcflags)"
}
ctcam_no_atcam_masks_test()
{
RET=0
# Third case: C-TCAM is disabled when there are no A-TCAM masks
# This test exercises the code path that transitions the eRP table
# to its initial state after deleting the last C-TCAM mask
# Filter goes into A-TCAM
tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \
$tcflags dst_ip 192.0.2.2 action drop
# Filter goes into C-TCAM
tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \
$tcflags dst_ip 192.0.2.2 action drop
tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower
tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower
log_test "ctcam with no atcam masks test ($tcflags)"
}
ctcam_edge_cases_test()
{
# When the C-TCAM is disabled after deleting the last C-TCAM
# mask, we want to make sure the eRP state machine is put in
# the correct state
ctcam_two_atcam_masks_test
ctcam_one_atcam_mask_test
ctcam_no_atcam_masks_test
}
delta_simple_test()
{
# The first filter will create eRP, the second filter will fit into
# the first eRP with delta. Remove the first rule then and check that
# the eRP stays (referenced by the second filter).
RET=0
if [[ "$tcflags" != "skip_sw" ]]; then
return 0;
fi
tp_record "objagg:*" "tc filter add dev $h2 ingress protocol ip \
pref 1 handle 101 flower $tcflags dst_ip 192.0.0.0/24 \
action drop"
tp_check_hits "objagg:objagg_obj_root_create" 1
check_err $? "eRP was not created"
tp_record "objagg:*" "tc filter add dev $h2 ingress protocol ip \
pref 2 handle 102 flower $tcflags dst_ip 192.0.2.2 \
action drop"
tp_check_hits "objagg:objagg_obj_root_create" 0
check_err $? "eRP was incorrectly created"
tp_check_hits "objagg:objagg_obj_parent_assign" 1
check_err $? "delta was not created"
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
-t ip -q
tc_check_packets "dev $h2 ingress" 101 1
check_fail $? "Matched a wrong filter"
tc_check_packets "dev $h2 ingress" 102 1
check_err $? "Did not match on correct filter"
tp_record "objagg:*" "tc filter del dev $h2 ingress protocol ip \
pref 1 handle 101 flower"
tp_check_hits "objagg:objagg_obj_root_destroy" 0
check_err $? "eRP was incorrectly destroyed"
tp_check_hits "objagg:objagg_obj_parent_unassign" 0
check_err $? "delta was incorrectly destroyed"
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
-t ip -q
tc_check_packets "dev $h2 ingress" 102 2
check_err $? "Did not match on correct filter after the first was removed"
tp_record "objagg:*" "tc filter del dev $h2 ingress protocol ip \
pref 2 handle 102 flower"
tp_check_hits "objagg:objagg_obj_parent_unassign" 1
check_err $? "delta was not destroyed"
tp_check_hits "objagg:objagg_obj_root_destroy" 1
check_err $? "eRP was not destroyed"
log_test "delta simple test ($tcflags)"
}
delta_two_masks_one_key_test()
{
# If 2 keys are the same and only differ in mask in a way that
# they belong under the same ERP (second is delta of the first),
# there should be C-TCAM spill.
RET=0
if [[ "$tcflags" != "skip_sw" ]]; then
return 0;
fi
tp_record "mlxsw:*" "tc filter add dev $h2 ingress protocol ip \
pref 1 handle 101 flower $tcflags dst_ip 192.0.2.0/24 \
action drop"
tp_check_hits "mlxsw:mlxsw_sp_acl_atcam_entry_add_ctcam_spill" 0
check_err $? "incorrect C-TCAM spill while inserting the first rule"
tp_record "mlxsw:*" "tc filter add dev $h2 ingress protocol ip \
pref 2 handle 102 flower $tcflags dst_ip 192.0.2.2 \
action drop"
tp_check_hits "mlxsw:mlxsw_sp_acl_atcam_entry_add_ctcam_spill" 1
check_err $? "C-TCAM spill did not happen while inserting the second rule"
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
-t ip -q
tc_check_packets "dev $h2 ingress" 101 1
check_err $? "Did not match on correct filter"
tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
-t ip -q
tc_check_packets "dev $h2 ingress" 102 1
check_err $? "Did not match on correct filter"
tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower
log_test "delta two masks one key test ($tcflags)"
}
delta_simple_rehash_test()
{
RET=0
if [[ "$tcflags" != "skip_sw" ]]; then
return 0;
fi
devlink dev param set $DEVLINK_DEV \
name acl_region_rehash_interval cmode runtime value 0
check_err $? "Failed to set ACL region rehash interval"
tp_record_all mlxsw:mlxsw_sp_acl_tcam_vregion_rehash 7
tp_check_hits_any mlxsw:mlxsw_sp_acl_tcam_vregion_rehash
check_fail $? "Rehash trace was hit even when rehash should be disabled"
devlink dev param set $DEVLINK_DEV \
name acl_region_rehash_interval cmode runtime value 3000
check_err $? "Failed to set ACL region rehash interval"
sleep 1
tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \
$tcflags dst_ip 192.0.1.0/25 action drop
tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \
$tcflags dst_ip 192.0.2.2 action drop
tc filter add dev $h2 ingress protocol ip pref 3 handle 103 flower \
$tcflags dst_ip 192.0.3.0/24 action drop
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
-t ip -q
tc_check_packets "dev $h2 ingress" 101 1
check_fail $? "Matched a wrong filter"
tc_check_packets "dev $h2 ingress" 103 1
check_fail $? "Matched a wrong filter"
tc_check_packets "dev $h2 ingress" 102 1
check_err $? "Did not match on correct filter"
tp_record_all mlxsw:* 3
tp_check_hits_any mlxsw:mlxsw_sp_acl_tcam_vregion_rehash
check_err $? "Rehash trace was not hit"
tp_check_hits_any mlxsw:mlxsw_sp_acl_tcam_vregion_migrate
check_err $? "Migrate trace was not hit"
tp_check_hits_any mlxsw:mlxsw_sp_acl_tcam_vregion_migrate_end
check_err $? "Migrate end trace was not hit"
tp_record_all mlxsw:* 3
tp_check_hits_any mlxsw:mlxsw_sp_acl_tcam_vregion_rehash
check_err $? "Rehash trace was not hit"
tp_check_hits_any mlxsw:mlxsw_sp_acl_tcam_vregion_migrate
check_fail $? "Migrate trace was hit when no migration should happen"
tp_check_hits_any mlxsw:mlxsw_sp_acl_tcam_vregion_migrate_end
check_fail $? "Migrate end trace was hit when no migration should happen"
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
-t ip -q
tc_check_packets "dev $h2 ingress" 101 1
check_fail $? "Matched a wrong filter after rehash"
tc_check_packets "dev $h2 ingress" 103 1
check_fail $? "Matched a wrong filter after rehash"
tc_check_packets "dev $h2 ingress" 102 2
check_err $? "Did not match on correct filter after rehash"
tc filter del dev $h2 ingress protocol ip pref 3 handle 103 flower
tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower
tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower
log_test "delta simple rehash test ($tcflags)"
}
delta_simple_ipv6_rehash_test()
{
RET=0
if [[ "$tcflags" != "skip_sw" ]]; then
return 0;
fi
devlink dev param set $DEVLINK_DEV \
name acl_region_rehash_interval cmode runtime value 0
check_err $? "Failed to set ACL region rehash interval"
tp_record_all mlxsw:mlxsw_sp_acl_tcam_vregion_rehash 7
tp_check_hits_any mlxsw:mlxsw_sp_acl_tcam_vregion_rehash
check_fail $? "Rehash trace was hit even when rehash should be disabled"
devlink dev param set $DEVLINK_DEV \
name acl_region_rehash_interval cmode runtime value 3000
check_err $? "Failed to set ACL region rehash interval"
sleep 1
tc filter add dev $h2 ingress protocol ipv6 pref 1 handle 101 flower \
$tcflags dst_ip 2001:db8:1::0/121 action drop
tc filter add dev $h2 ingress protocol ipv6 pref 2 handle 102 flower \
$tcflags dst_ip 2001:db8:2::2 action drop
tc filter add dev $h2 ingress protocol ipv6 pref 3 handle 103 flower \
$tcflags dst_ip 2001:db8:3::0/120 action drop
$MZ $h1 -6 -c 1 -p 64 -a $h1mac -b $h2mac \
-A 2001:db8:2::1 -B 2001:db8:2::2 -t udp -q
tc_check_packets "dev $h2 ingress" 101 1
check_fail $? "Matched a wrong filter"
tc_check_packets "dev $h2 ingress" 103 1
check_fail $? "Matched a wrong filter"
tc_check_packets "dev $h2 ingress" 102 1
check_err $? "Did not match on correct filter"
tp_record_all mlxsw:* 3
tp_check_hits_any mlxsw:mlxsw_sp_acl_tcam_vregion_rehash
check_err $? "Rehash trace was not hit"
tp_check_hits_any mlxsw:mlxsw_sp_acl_tcam_vregion_migrate
check_err $? "Migrate trace was not hit"
tp_check_hits_any mlxsw:mlxsw_sp_acl_tcam_vregion_migrate_end
check_err $? "Migrate end trace was not hit"
tp_record_all mlxsw:* 3
tp_check_hits_any mlxsw:mlxsw_sp_acl_tcam_vregion_rehash
check_err $? "Rehash trace was not hit"
tp_check_hits_any mlxsw:mlxsw_sp_acl_tcam_vregion_migrate
check_fail $? "Migrate trace was hit when no migration should happen"
tp_check_hits_any mlxsw:mlxsw_sp_acl_tcam_vregion_migrate_end
check_fail $? "Migrate end trace was hit when no migration should happen"
$MZ $h1 -6 -c 1 -p 64 -a $h1mac -b $h2mac \
-A 2001:db8:2::1 -B 2001:db8:2::2 -t udp -q
tc_check_packets "dev $h2 ingress" 101 1
check_fail $? "Matched a wrong filter after rehash"
tc_check_packets "dev $h2 ingress" 103 1
check_fail $? "Matched a wrong filter after rehash"
tc_check_packets "dev $h2 ingress" 102 2
check_err $? "Did not match on correct filter after rehash"
tc filter del dev $h2 ingress protocol ipv6 pref 3 handle 103 flower
tc filter del dev $h2 ingress protocol ipv6 pref 2 handle 102 flower
tc filter del dev $h2 ingress protocol ipv6 pref 1 handle 101 flower
log_test "delta simple IPv6 rehash test ($tcflags)"
}
TEST_RULE_BASE=256
declare -a test_rules_inserted
test_rule_add()
{
local iface=$1
local tcflags=$2
local index=$3
if ! [ ${test_rules_inserted[$index]} ] ; then
test_rules_inserted[$index]=false
fi
if ${test_rules_inserted[$index]} ; then
return
fi
local number=$(( $index + $TEST_RULE_BASE ))
printf -v hexnumber '%x' $number
batch="${batch}filter add dev $iface ingress protocol ipv6 pref 1 \
handle $number flower $tcflags \
src_ip 2001:db8:1::$hexnumber action drop\n"
test_rules_inserted[$index]=true
}
test_rule_del()
{
local iface=$1
local index=$2
if ! [ ${test_rules_inserted[$index]} ] ; then
test_rules_inserted[$index]=false
fi
if ! ${test_rules_inserted[$index]} ; then
return
fi
local number=$(( $index + $TEST_RULE_BASE ))
printf -v hexnumber '%x' $number
batch="${batch}filter del dev $iface ingress protocol ipv6 pref 1 \
handle $number flower\n"
test_rules_inserted[$index]=false
}
test_rule_add_or_remove()
{
local iface=$1
local tcflags=$2
local index=$3
if ! [ ${test_rules_inserted[$index]} ] ; then
test_rules_inserted[$index]=false
fi
if ${test_rules_inserted[$index]} ; then
test_rule_del $iface $index
else
test_rule_add $iface $tcflags $index
fi
}
test_rule_add_or_remove_random_batch()
{
local iface=$1
local tcflags=$2
local total_count=$3
local skip=0
local count=0
local MAXSKIP=20
local MAXCOUNT=20
for ((i=1;i<=total_count;i++)); do
if (( $skip == 0 )) && (($count == 0)); then
((skip=$RANDOM % $MAXSKIP + 1))
((count=$RANDOM % $MAXCOUNT + 1))
fi
if (( $skip != 0 )); then
((skip-=1))
else
((count-=1))
test_rule_add_or_remove $iface $tcflags $i
fi
done
}
delta_massive_ipv6_rehash_test()
{
RET=0
if [[ "$tcflags" != "skip_sw" ]]; then
return 0;
fi
devlink dev param set $DEVLINK_DEV \
name acl_region_rehash_interval cmode runtime value 0
check_err $? "Failed to set ACL region rehash interval"
tp_record_all mlxsw:mlxsw_sp_acl_tcam_vregion_rehash 7
tp_check_hits_any mlxsw:mlxsw_sp_acl_tcam_vregion_rehash
check_fail $? "Rehash trace was hit even when rehash should be disabled"
RANDOM=4432897
declare batch=""
test_rule_add_or_remove_random_batch $h2 $tcflags 5000
echo -n -e $batch | tc -b -
declare batch=""
test_rule_add_or_remove_random_batch $h2 $tcflags 5000
devlink dev param set $DEVLINK_DEV \
name acl_region_rehash_interval cmode runtime value 3000
check_err $? "Failed to set ACL region rehash interval"
sleep 1
tc filter add dev $h2 ingress protocol ipv6 pref 1 handle 101 flower \
$tcflags dst_ip 2001:db8:1::0/121 action drop
tc filter add dev $h2 ingress protocol ipv6 pref 2 handle 102 flower \
$tcflags dst_ip 2001:db8:2::2 action drop
tc filter add dev $h2 ingress protocol ipv6 pref 3 handle 103 flower \
$tcflags dst_ip 2001:db8:3::0/120 action drop
$MZ $h1 -6 -c 1 -p 64 -a $h1mac -b $h2mac \
-A 2001:db8:2::1 -B 2001:db8:2::2 -t udp -q
tc_check_packets "dev $h2 ingress" 101 1
check_fail $? "Matched a wrong filter"
tc_check_packets "dev $h2 ingress" 103 1
check_fail $? "Matched a wrong filter"
tc_check_packets "dev $h2 ingress" 102 1
check_err $? "Did not match on correct filter"
echo -n -e $batch | tc -b -
devlink dev param set $DEVLINK_DEV \
name acl_region_rehash_interval cmode runtime value 0
check_err $? "Failed to set ACL region rehash interval"
$MZ $h1 -6 -c 1 -p 64 -a $h1mac -b $h2mac \
-A 2001:db8:2::1 -B 2001:db8:2::2 -t udp -q
tc_check_packets "dev $h2 ingress" 101 1
check_fail $? "Matched a wrong filter after rehash"
tc_check_packets "dev $h2 ingress" 103 1
check_fail $? "Matched a wrong filter after rehash"
tc_check_packets "dev $h2 ingress" 102 2
check_err $? "Did not match on correct filter after rehash"
tc filter del dev $h2 ingress protocol ipv6 pref 3 handle 103 flower
tc filter del dev $h2 ingress protocol ipv6 pref 2 handle 102 flower
tc filter del dev $h2 ingress protocol ipv6 pref 1 handle 101 flower
declare batch=""
for i in {1..5000}; do
test_rule_del $h2 $tcflags $i
done
echo -e $batch | tc -b -
log_test "delta massive IPv6 rehash test ($tcflags)"
}
bloom_simple_test()
{
# Bloom filter requires that the eRP table is used. This test
# verifies that Bloom filter is not harming correctness of ACLs.
# First, make sure that eRP table is used and then set rule patterns
# which are distant enough and will result skipping a lookup after
# consulting the Bloom filter. Although some eRP lookups are skipped,
# the correct filter should be hit.
RET=0
tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \
$tcflags dst_ip 192.0.2.2 action drop
tc filter add dev $h2 ingress protocol ip pref 5 handle 104 flower \
$tcflags dst_ip 198.51.100.2 action drop
tc filter add dev $h2 ingress protocol ip pref 3 handle 103 flower \
$tcflags dst_ip 192.0.0.0/8 action drop
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
-t ip -q
tc_check_packets "dev $h2 ingress" 101 1
check_err $? "Two filters - did not match highest priority"
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 198.51.100.1 -B 198.51.100.2 \
-t ip -q
tc_check_packets "dev $h2 ingress" 104 1
check_err $? "Single filter - did not match"
tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
-t ip -q
tc_check_packets "dev $h2 ingress" 103 1
check_err $? "Low prio filter - did not match"
tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \
$tcflags dst_ip 198.0.0.0/8 action drop
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 198.51.100.1 -B 198.51.100.2 \
-t ip -q
tc_check_packets "dev $h2 ingress" 102 1
check_err $? "Two filters - did not match highest priority after add"
tc filter del dev $h2 ingress protocol ip pref 3 handle 103 flower
tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower
tc filter del dev $h2 ingress protocol ip pref 5 handle 104 flower
log_test "bloom simple test ($tcflags)"
}
bloom_complex_test()
{
# Bloom filter index computation is affected from region ID, eRP
# ID and from the region key size. In order to exercise those parts
# of the Bloom filter code, use a series of regions, each with a
# different key size and send packet that should hit all of them.
local index
RET=0
NUM_CHAINS=4
BASE_INDEX=100
# Create chain with up to 2 key blocks (ip_proto only)
tc chain add dev $h2 ingress chain 1 protocol ip flower \
ip_proto tcp &> /dev/null
# Create chain with 2-4 key blocks (ip_proto, src MAC)
tc chain add dev $h2 ingress chain 2 protocol ip flower \
ip_proto tcp \
src_mac 00:00:00:00:00:00/FF:FF:FF:FF:FF:FF &> /dev/null
# Create chain with 4-8 key blocks (ip_proto, src & dst MAC, IPv4 dest)
tc chain add dev $h2 ingress chain 3 protocol ip flower \
ip_proto tcp \
dst_mac 00:00:00:00:00:00/FF:FF:FF:FF:FF:FF \
src_mac 00:00:00:00:00:00/FF:FF:FF:FF:FF:FF \
dst_ip 0.0.0.0/32 &> /dev/null
# Default chain contains all fields and therefore is 8-12 key blocks
tc chain add dev $h2 ingress chain 4
# We need at least 2 rules in every region to have eRP table active
# so create a dummy rule per chain using a different pattern
for i in $(eval echo {0..$NUM_CHAINS}); do
index=$((BASE_INDEX - 1 - i))
tc filter add dev $h2 ingress chain $i protocol ip \
pref 2 handle $index flower \
$tcflags ip_proto tcp action drop
done
# Add rules to test Bloom filter, each in a different chain
index=$BASE_INDEX
tc filter add dev $h2 ingress protocol ip \
pref 1 handle $((++index)) flower \
$tcflags dst_ip 192.0.0.0/16 action goto chain 1
tc filter add dev $h2 ingress chain 1 protocol ip \
pref 1 handle $((++index)) flower \
$tcflags action goto chain 2
tc filter add dev $h2 ingress chain 2 protocol ip \
pref 1 handle $((++index)) flower \
$tcflags src_mac $h1mac action goto chain 3
tc filter add dev $h2 ingress chain 3 protocol ip \
pref 1 handle $((++index)) flower \
$tcflags dst_ip 192.0.0.0/8 action goto chain 4
tc filter add dev $h2 ingress chain 4 protocol ip \
pref 1 handle $((++index)) flower \
$tcflags src_ip 192.0.2.0/24 action drop
# Send a packet that is supposed to hit all chains
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
-t ip -q
for i in $(eval echo {0..$NUM_CHAINS}); do
index=$((BASE_INDEX + i + 1))
tc_check_packets "dev $h2 ingress" $index 1
check_err $? "Did not match chain $i"
done
# Rules cleanup
for i in $(eval echo {$NUM_CHAINS..0}); do
index=$((BASE_INDEX - i - 1))
tc filter del dev $h2 ingress chain $i \
pref 2 handle $index flower
index=$((BASE_INDEX + i + 1))
tc filter del dev $h2 ingress chain $i \
pref 1 handle $index flower
done
# Chains cleanup
for i in $(eval echo {$NUM_CHAINS..1}); do
tc chain del dev $h2 ingress chain $i
done
log_test "bloom complex test ($tcflags)"
}
bloom_delta_test()
{
# When multiple masks are used, the eRP table is activated. When
# masks are close enough (delta) the masks reside on the same
# eRP table. This test verifies that the eRP table is correctly
# allocated and used in delta condition and that Bloom filter is
# still functional with delta.
RET=0
tc filter add dev $h2 ingress protocol ip pref 3 handle 103 flower \
$tcflags dst_ip 192.1.0.0/16 action drop
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.1.2.1 -B 192.1.2.2 \
-t ip -q
tc_check_packets "dev $h2 ingress" 103 1
check_err $? "Single filter - did not match"
tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \
$tcflags dst_ip 192.2.1.0/24 action drop
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.2.1.1 -B 192.2.1.2 \
-t ip -q
tc_check_packets "dev $h2 ingress" 102 1
check_err $? "Delta filters - did not match second filter"
tc filter del dev $h2 ingress protocol ip pref 3 handle 103 flower
tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower
log_test "bloom delta test ($tcflags)"
}
max_erp_entries_test()
{
# The number of eRP entries is limited. Once the maximum number of eRPs
# has been reached, filters cannot be added. This test verifies that
# when this limit is reached, inserstion fails without crashing.
RET=0
local num_masks=32
local num_regions=15
local chain_failed
local mask_failed
local ret
if [[ "$tcflags" != "skip_sw" ]]; then
return 0;
fi
for ((i=1; i < $num_regions; i++)); do
for ((j=$num_masks; j >= 0; j--)); do
tc filter add dev $h2 ingress chain $i protocol ip \
pref $i handle $j flower $tcflags \
dst_ip 192.1.0.0/$j &> /dev/null
ret=$?
if [ $ret -ne 0 ]; then
chain_failed=$i
mask_failed=$j
break 2
fi
done
done
# We expect to exceed the maximum number of eRP entries, so that
# insertion eventually fails. Otherwise, the test should be adjusted to
# add more filters.
check_fail $ret "expected to exceed number of eRP entries"
for ((; i >= 1; i--)); do
for ((j=0; j <= $num_masks; j++)); do
tc filter del dev $h2 ingress chain $i protocol ip \
pref $i handle $j flower &> /dev/null
done
done
log_test "max eRP entries test ($tcflags). " \
"max chain $chain_failed, mask $mask_failed"
}
max_group_size_test()
{
# The number of ACLs in an ACL group is limited. Once the maximum
# number of ACLs has been reached, filters cannot be added. This test
# verifies that when this limit is reached, insertion fails without
# crashing.
RET=0
local num_acls=32
local max_size
local ret
if [[ "$tcflags" != "skip_sw" ]]; then
return 0;
fi
for ((i=1; i < $num_acls; i++)); do
if [[ $(( i % 2 )) == 1 ]]; then
tc filter add dev $h2 ingress pref $i proto ipv4 \
flower $tcflags dst_ip 198.51.100.1/32 \
ip_proto tcp tcp_flags 0x01/0x01 \
action drop &> /dev/null
else
tc filter add dev $h2 ingress pref $i proto ipv6 \
flower $tcflags dst_ip 2001:db8:1::1/128 \
action drop &> /dev/null
fi
ret=$?
[[ $ret -ne 0 ]] && max_size=$((i - 1)) && break
done
# We expect to exceed the maximum number of ACLs in a group, so that
# insertion eventually fails. Otherwise, the test should be adjusted to
# add more filters.
check_fail $ret "expected to exceed number of ACLs in a group"
for ((; i >= 1; i--)); do
if [[ $(( i % 2 )) == 1 ]]; then
tc filter del dev $h2 ingress pref $i proto ipv4 \
flower $tcflags dst_ip 198.51.100.1/32 \
ip_proto tcp tcp_flags 0x01/0x01 \
action drop &> /dev/null
else
tc filter del dev $h2 ingress pref $i proto ipv6 \
flower $tcflags dst_ip 2001:db8:1::1/128 \
action drop &> /dev/null
fi
done
log_test "max ACL group size test ($tcflags). max size $max_size"
}
collision_test()
{
# Filters cannot share an eRP if in the common unmasked part (i.e.,
# without the delta bits) they have the same values. If the driver does
# not prevent such configuration (by spilling into the C-TCAM), then
# multiple entries will be present in the device with the same key,
# leading to collisions and a reduced scale.
#
# Create such a scenario and make sure all the filters are successfully
# added.
RET=0
local ret
if [[ "$tcflags" != "skip_sw" ]]; then
return 0;
fi
# Add a single dst_ip/24 filter and multiple dst_ip/32 filters that all
# have the same values in the common unmasked part (dst_ip/24).
tc filter add dev $h2 ingress pref 1 proto ipv4 handle 101 \
flower $tcflags dst_ip 198.51.100.0/24 \
action drop
for i in {0..255}; do
tc filter add dev $h2 ingress pref 2 proto ipv4 \
handle $((102 + i)) \
flower $tcflags dst_ip 198.51.100.${i}/32 \
action drop
ret=$?
[[ $ret -ne 0 ]] && break
done
check_err $ret "failed to add all the filters"
for i in {255..0}; do
tc filter del dev $h2 ingress pref 2 proto ipv4 \
handle $((102 + i)) flower
done
tc filter del dev $h2 ingress pref 1 proto ipv4 handle 101 flower
log_test "collision test ($tcflags)"
}
setup_prepare()
{
h1=${NETIFS[p1]}
h2=${NETIFS[p2]}
h1mac=$(mac_get $h1)
h2mac=$(mac_get $h2)
vrf_prepare
h1_create
h2_create
}
cleanup()
{
pre_cleanup
h2_destroy
h1_destroy
vrf_cleanup
}
trap cleanup EXIT
setup_prepare
setup_wait
tests_run
if ! tc_offload_check; then
check_err 1 "Could not test offloaded functionality"
log_test "mlxsw-specific tests for tc flower"
exit
else
tcflags="skip_sw"
tests_run
fi
exit $EXIT_STATUS