Merge branch 'selftests-net-bridge-add-tests-for-mldv2'

Nikolay Aleksandrov says:

====================
selftests: net: bridge: add tests for MLDv2

This is the second selftests patch-set for the new multicast functionality
which adds tests for the bridge's MLDv2 support. The tests use full
precooked packets which are sent via mausezahn and the resulting state
after each test is checked for proper X,Y sets, (*,G) source list, source
list entry timers, (S,G) existence and flags, packet forwarding and
blocking, exclude group expiration and (*,G) auto-add. The first 3 patches
factor out common functions which are used by IGMPv3 tests in lib.sh and
add support for IPv6 test UDP packet, then patch 4 adds the first test with
the initial MLDv2 setup.
The following new tests are added:
 - base case: MLDv2 report ff02::cc is_include
 - include -> allow report
 - include -> is_include report
 - include -> is_exclude report
 - include -> to_exclude report
 - exclude -> allow report
 - exclude -> is_include report
 - exclude -> is_exclude report
 - exclude -> to_exclude report
 - include -> block report
 - exclude -> block report
 - exclude timeout (move to include + entry deletion)
 - S,G port entry automatic add to a *,G,exclude port

The variable names and set notation are the same as per RFC 3810,
for more information check RFC 3810 sections 2.3 and 7.
====================

Link: https://lore.kernel.org/r/20201103172412.1044840-1-razor@blackwall.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2020-11-04 16:55:58 -08:00
commit 609cfc7fcf
3 changed files with 721 additions and 155 deletions

View File

@ -105,38 +105,6 @@ cleanup()
vrf_cleanup vrf_cleanup
} }
# return 0 if the packet wasn't seen on host2_if or 1 if it was
mcast_packet_test()
{
local mac=$1
local src_ip=$2
local ip=$3
local host1_if=$4
local host2_if=$5
local seen=0
# Add an ACL on `host2_if` which will tell us whether the packet
# was received by it or not.
tc qdisc add dev $host2_if ingress
tc filter add dev $host2_if ingress protocol ip pref 1 handle 101 \
flower ip_proto udp dst_mac $mac action drop
$MZ $host1_if -c 1 -p 64 -b $mac -A $src_ip -B $ip -t udp "dp=4096,sp=2048" -q
sleep 1
tc -j -s filter show dev $host2_if ingress \
| jq -e ".[] | select(.options.handle == 101) \
| select(.options.actions[0].stats.packets == 1)" &> /dev/null
if [[ $? -eq 0 ]]; then
seen=1
fi
tc filter del dev $host2_if ingress protocol ip pref 1 handle 101 flower
tc qdisc del dev $host2_if ingress
return $seen
}
v2reportleave_test() v2reportleave_test()
{ {
RET=0 RET=0
@ -169,73 +137,6 @@ v2reportleave_test()
log_test "IGMPv2 leave $TEST_GROUP" log_test "IGMPv2 leave $TEST_GROUP"
} }
check_sg_entries()
{
local report=$1; shift
local slist=("$@")
local sarg=""
for src in "${slist[@]}"; do
sarg="${sarg} and .source_list[].address == \"$src\""
done
bridge -j -d -s mdb show dev br0 \
| jq -e ".[].mdb[] | \
select(.grp == \"$TEST_GROUP\" and .source_list != null $sarg)" &>/dev/null
check_err $? "Wrong *,G entry source list after $report report"
for sgent in "${slist[@]}"; do
bridge -j -d -s mdb show dev br0 \
| jq -e ".[].mdb[] | \
select(.grp == \"$TEST_GROUP\" and .src == \"$sgent\")" &>/dev/null
check_err $? "Missing S,G entry ($sgent, $TEST_GROUP)"
done
}
check_sg_fwding()
{
local should_fwd=$1; shift
local sources=("$@")
for src in "${sources[@]}"; do
local retval=0
mcast_packet_test $TEST_GROUP_MAC $src $TEST_GROUP $h2 $h1
retval=$?
if [ $should_fwd -eq 1 ]; then
check_fail $retval "Didn't forward traffic from S,G ($src, $TEST_GROUP)"
else
check_err $retval "Forwarded traffic for blocked S,G ($src, $TEST_GROUP)"
fi
done
}
check_sg_state()
{
local is_blocked=$1; shift
local sources=("$@")
local should_fail=1
if [ $is_blocked -eq 1 ]; then
should_fail=0
fi
for src in "${sources[@]}"; do
bridge -j -d -s mdb show dev br0 \
| jq -e ".[].mdb[] | \
select(.grp == \"$TEST_GROUP\" and .source_list != null) |
.source_list[] |
select(.address == \"$src\") |
select(.timer == \"0.00\")" &>/dev/null
check_err_fail $should_fail $? "Entry $src has zero timer"
bridge -j -d -s mdb show dev br0 \
| jq -e ".[].mdb[] | \
select(.grp == \"$TEST_GROUP\" and .src == \"$src\" and \
.flags[] == \"blocked\")" &>/dev/null
check_err_fail $should_fail $? "Entry $src has blocked flag"
done
}
v3include_prepare() v3include_prepare()
{ {
local host1_if=$1 local host1_if=$1
@ -257,7 +158,7 @@ v3include_prepare()
select(.grp == \"$TEST_GROUP\" and \ select(.grp == \"$TEST_GROUP\" and \
.source_list != null and .filter_mode == \"include\")" &>/dev/null .source_list != null and .filter_mode == \"include\")" &>/dev/null
check_err $? "Wrong *,G entry filter mode" check_err $? "Wrong *,G entry filter mode"
check_sg_entries "is_include" "${X[@]}" brmcast_check_sg_entries "is_include" "${X[@]}"
} }
v3exclude_prepare() v3exclude_prepare()
@ -279,10 +180,10 @@ v3exclude_prepare()
.source_list != null and .filter_mode == \"exclude\")" &>/dev/null .source_list != null and .filter_mode == \"exclude\")" &>/dev/null
check_err $? "Wrong *,G entry filter mode" check_err $? "Wrong *,G entry filter mode"
check_sg_entries "is_exclude" "${X[@]}" "${Y[@]}" brmcast_check_sg_entries "is_exclude" "${X[@]}" "${Y[@]}"
check_sg_state 0 "${X[@]}" brmcast_check_sg_state 0 "${X[@]}"
check_sg_state 1 "${Y[@]}" brmcast_check_sg_state 1 "${Y[@]}"
bridge -j -d -s mdb show dev br0 \ bridge -j -d -s mdb show dev br0 \
| jq -e ".[].mdb[] | \ | jq -e ".[].mdb[] | \
@ -308,10 +209,10 @@ v3include_test()
v3include_prepare $h1 $ALL_MAC $ALL_GROUP v3include_prepare $h1 $ALL_MAC $ALL_GROUP
check_sg_state 0 "${X[@]}" brmcast_check_sg_state 0 "${X[@]}"
check_sg_fwding 1 "${X[@]}" brmcast_check_sg_fwding 1 "${X[@]}"
check_sg_fwding 0 "192.0.2.100" brmcast_check_sg_fwding 0 "192.0.2.100"
log_test "IGMPv3 report $TEST_GROUP is_include" log_test "IGMPv3 report $TEST_GROUP is_include"
@ -327,12 +228,12 @@ v3inc_allow_test()
$MZ $h1 -c 1 -b $ALL_MAC -B $ALL_GROUP -t ip "proto=2,p=$MZPKT_ALLOW" -q $MZ $h1 -c 1 -b $ALL_MAC -B $ALL_GROUP -t ip "proto=2,p=$MZPKT_ALLOW" -q
sleep 1 sleep 1
check_sg_entries "allow" "${X[@]}" brmcast_check_sg_entries "allow" "${X[@]}"
check_sg_state 0 "${X[@]}" brmcast_check_sg_state 0 "${X[@]}"
check_sg_fwding 1 "${X[@]}" brmcast_check_sg_fwding 1 "${X[@]}"
check_sg_fwding 0 "192.0.2.100" brmcast_check_sg_fwding 0 "192.0.2.100"
log_test "IGMPv3 report $TEST_GROUP include -> allow" log_test "IGMPv3 report $TEST_GROUP include -> allow"
@ -348,12 +249,12 @@ v3inc_is_include_test()
$MZ $h1 -c 1 -b $ALL_MAC -B $ALL_GROUP -t ip "proto=2,p=$MZPKT_IS_INC2" -q $MZ $h1 -c 1 -b $ALL_MAC -B $ALL_GROUP -t ip "proto=2,p=$MZPKT_IS_INC2" -q
sleep 1 sleep 1
check_sg_entries "is_include" "${X[@]}" brmcast_check_sg_entries "is_include" "${X[@]}"
check_sg_state 0 "${X[@]}" brmcast_check_sg_state 0 "${X[@]}"
check_sg_fwding 1 "${X[@]}" brmcast_check_sg_fwding 1 "${X[@]}"
check_sg_fwding 0 "192.0.2.100" brmcast_check_sg_fwding 0 "192.0.2.100"
log_test "IGMPv3 report $TEST_GROUP include -> is_include" log_test "IGMPv3 report $TEST_GROUP include -> is_include"
@ -366,8 +267,8 @@ v3inc_is_exclude_test()
v3exclude_prepare $h1 $ALL_MAC $ALL_GROUP v3exclude_prepare $h1 $ALL_MAC $ALL_GROUP
check_sg_fwding 1 "${X[@]}" 192.0.2.100 brmcast_check_sg_fwding 1 "${X[@]}" 192.0.2.100
check_sg_fwding 0 "${Y[@]}" brmcast_check_sg_fwding 0 "${Y[@]}"
log_test "IGMPv3 report $TEST_GROUP include -> is_exclude" log_test "IGMPv3 report $TEST_GROUP include -> is_exclude"
@ -393,10 +294,10 @@ v3inc_to_exclude_test()
.source_list != null and .filter_mode == \"exclude\")" &>/dev/null .source_list != null and .filter_mode == \"exclude\")" &>/dev/null
check_err $? "Wrong *,G entry filter mode" check_err $? "Wrong *,G entry filter mode"
check_sg_entries "to_exclude" "${X[@]}" "${Y[@]}" brmcast_check_sg_entries "to_exclude" "${X[@]}" "${Y[@]}"
check_sg_state 0 "${X[@]}" brmcast_check_sg_state 0 "${X[@]}"
check_sg_state 1 "${Y[@]}" brmcast_check_sg_state 1 "${Y[@]}"
bridge -j -d -s mdb show dev br0 \ bridge -j -d -s mdb show dev br0 \
| jq -e ".[].mdb[] | \ | jq -e ".[].mdb[] | \
@ -411,8 +312,8 @@ v3inc_to_exclude_test()
.source_list[].address == \"192.0.2.21\")" &>/dev/null .source_list[].address == \"192.0.2.21\")" &>/dev/null
check_fail $? "Wrong *,G entry source list, 192.0.2.21 entry still exists" check_fail $? "Wrong *,G entry source list, 192.0.2.21 entry still exists"
check_sg_fwding 1 "${X[@]}" 192.0.2.100 brmcast_check_sg_fwding 1 "${X[@]}" 192.0.2.100
check_sg_fwding 0 "${Y[@]}" brmcast_check_sg_fwding 0 "${Y[@]}"
log_test "IGMPv3 report $TEST_GROUP include -> to_exclude" log_test "IGMPv3 report $TEST_GROUP include -> to_exclude"
@ -431,13 +332,13 @@ v3exc_allow_test()
$MZ $h1 -c 1 -b $ALL_MAC -B $ALL_GROUP -t ip "proto=2,p=$MZPKT_ALLOW2" -q $MZ $h1 -c 1 -b $ALL_MAC -B $ALL_GROUP -t ip "proto=2,p=$MZPKT_ALLOW2" -q
sleep 1 sleep 1
check_sg_entries "allow" "${X[@]}" "${Y[@]}" brmcast_check_sg_entries "allow" "${X[@]}" "${Y[@]}"
check_sg_state 0 "${X[@]}" brmcast_check_sg_state 0 "${X[@]}"
check_sg_state 1 "${Y[@]}" brmcast_check_sg_state 1 "${Y[@]}"
check_sg_fwding 1 "${X[@]}" 192.0.2.100 brmcast_check_sg_fwding 1 "${X[@]}" 192.0.2.100
check_sg_fwding 0 "${Y[@]}" brmcast_check_sg_fwding 0 "${Y[@]}"
log_test "IGMPv3 report $TEST_GROUP exclude -> allow" log_test "IGMPv3 report $TEST_GROUP exclude -> allow"
@ -454,13 +355,13 @@ v3exc_is_include_test()
$MZ $h1 -c 1 -b $ALL_MAC -B $ALL_GROUP -t ip "proto=2,p=$MZPKT_IS_INC3" -q $MZ $h1 -c 1 -b $ALL_MAC -B $ALL_GROUP -t ip "proto=2,p=$MZPKT_IS_INC3" -q
sleep 1 sleep 1
check_sg_entries "is_include" "${X[@]}" "${Y[@]}" brmcast_check_sg_entries "is_include" "${X[@]}" "${Y[@]}"
check_sg_state 0 "${X[@]}" brmcast_check_sg_state 0 "${X[@]}"
check_sg_state 1 "${Y[@]}" brmcast_check_sg_state 1 "${Y[@]}"
check_sg_fwding 1 "${X[@]}" 192.0.2.100 brmcast_check_sg_fwding 1 "${X[@]}" 192.0.2.100
check_sg_fwding 0 "${Y[@]}" brmcast_check_sg_fwding 0 "${Y[@]}"
log_test "IGMPv3 report $TEST_GROUP exclude -> is_include" log_test "IGMPv3 report $TEST_GROUP exclude -> is_include"
@ -477,13 +378,13 @@ v3exc_is_exclude_test()
$MZ $h1 -c 1 -b $ALL_MAC -B $ALL_GROUP -t ip "proto=2,p=$MZPKT_IS_EXC2" -q $MZ $h1 -c 1 -b $ALL_MAC -B $ALL_GROUP -t ip "proto=2,p=$MZPKT_IS_EXC2" -q
sleep 1 sleep 1
check_sg_entries "is_exclude" "${X[@]}" "${Y[@]}" brmcast_check_sg_entries "is_exclude" "${X[@]}" "${Y[@]}"
check_sg_state 0 "${X[@]}" brmcast_check_sg_state 0 "${X[@]}"
check_sg_state 1 "${Y[@]}" brmcast_check_sg_state 1 "${Y[@]}"
check_sg_fwding 1 "${X[@]}" 192.0.2.100 brmcast_check_sg_fwding 1 "${X[@]}" 192.0.2.100
check_sg_fwding 0 "${Y[@]}" brmcast_check_sg_fwding 0 "${Y[@]}"
log_test "IGMPv3 report $TEST_GROUP exclude -> is_exclude" log_test "IGMPv3 report $TEST_GROUP exclude -> is_exclude"
@ -503,13 +404,13 @@ v3exc_to_exclude_test()
$MZ $h1 -c 1 -b $ALL_MAC -B $ALL_GROUP -t ip "proto=2,p=$MZPKT_TO_EXC" -q $MZ $h1 -c 1 -b $ALL_MAC -B $ALL_GROUP -t ip "proto=2,p=$MZPKT_TO_EXC" -q
sleep 1 sleep 1
check_sg_entries "to_exclude" "${X[@]}" "${Y[@]}" brmcast_check_sg_entries "to_exclude" "${X[@]}" "${Y[@]}"
check_sg_state 0 "${X[@]}" brmcast_check_sg_state 0 "${X[@]}"
check_sg_state 1 "${Y[@]}" brmcast_check_sg_state 1 "${Y[@]}"
check_sg_fwding 1 "${X[@]}" 192.0.2.100 brmcast_check_sg_fwding 1 "${X[@]}" 192.0.2.100
check_sg_fwding 0 "${Y[@]}" brmcast_check_sg_fwding 0 "${Y[@]}"
log_test "IGMPv3 report $TEST_GROUP exclude -> to_exclude" log_test "IGMPv3 report $TEST_GROUP exclude -> to_exclude"
@ -528,9 +429,9 @@ v3inc_block_test()
$MZ $h1 -c 1 -b $ALL_MAC -B $ALL_GROUP -t ip "proto=2,p=$MZPKT_BLOCK" -q $MZ $h1 -c 1 -b $ALL_MAC -B $ALL_GROUP -t ip "proto=2,p=$MZPKT_BLOCK" -q
# make sure the lowered timers have expired (by default 2 seconds) # make sure the lowered timers have expired (by default 2 seconds)
sleep 3 sleep 3
check_sg_entries "block" "${X[@]}" brmcast_check_sg_entries "block" "${X[@]}"
check_sg_state 0 "${X[@]}" brmcast_check_sg_state 0 "${X[@]}"
bridge -j -d -s mdb show dev br0 \ bridge -j -d -s mdb show dev br0 \
| jq -e ".[].mdb[] | \ | jq -e ".[].mdb[] | \
@ -539,8 +440,8 @@ v3inc_block_test()
.source_list[].address == \"192.0.2.1\")" &>/dev/null .source_list[].address == \"192.0.2.1\")" &>/dev/null
check_fail $? "Wrong *,G entry source list, 192.0.2.1 entry still exists" check_fail $? "Wrong *,G entry source list, 192.0.2.1 entry still exists"
check_sg_fwding 1 "${X[@]}" brmcast_check_sg_fwding 1 "${X[@]}"
check_sg_fwding 0 "192.0.2.100" brmcast_check_sg_fwding 0 "192.0.2.100"
log_test "IGMPv3 report $TEST_GROUP include -> block" log_test "IGMPv3 report $TEST_GROUP include -> block"
@ -560,13 +461,13 @@ v3exc_block_test()
$MZ $h1 -c 1 -b $ALL_MAC -B $ALL_GROUP -t ip "proto=2,p=$MZPKT_BLOCK" -q $MZ $h1 -c 1 -b $ALL_MAC -B $ALL_GROUP -t ip "proto=2,p=$MZPKT_BLOCK" -q
sleep 1 sleep 1
check_sg_entries "block" "${X[@]}" "${Y[@]}" brmcast_check_sg_entries "block" "${X[@]}" "${Y[@]}"
check_sg_state 0 "${X[@]}" brmcast_check_sg_state 0 "${X[@]}"
check_sg_state 1 "${Y[@]}" brmcast_check_sg_state 1 "${Y[@]}"
check_sg_fwding 1 "${X[@]}" 192.0.2.100 brmcast_check_sg_fwding 1 "${X[@]}" 192.0.2.100
check_sg_fwding 0 "${Y[@]}" brmcast_check_sg_fwding 0 "${Y[@]}"
log_test "IGMPv3 report $TEST_GROUP exclude -> block" log_test "IGMPv3 report $TEST_GROUP exclude -> block"
@ -606,12 +507,12 @@ v3exc_timeout_test()
.source_list[].address == \"192.0.2.2\")" &>/dev/null .source_list[].address == \"192.0.2.2\")" &>/dev/null
check_fail $? "Wrong *,G entry source list, 192.0.2.2 entry still exists" check_fail $? "Wrong *,G entry source list, 192.0.2.2 entry still exists"
check_sg_entries "allow" "${X[@]}" brmcast_check_sg_entries "allow" "${X[@]}"
check_sg_state 0 "${X[@]}" brmcast_check_sg_state 0 "${X[@]}"
check_sg_fwding 1 "${X[@]}" brmcast_check_sg_fwding 1 "${X[@]}"
check_sg_fwding 0 192.0.2.100 brmcast_check_sg_fwding 0 192.0.2.100
log_test "IGMPv3 group $TEST_GROUP exclude timeout" log_test "IGMPv3 group $TEST_GROUP exclude timeout"
@ -642,7 +543,7 @@ v3star_ex_auto_add_test()
.flags[] == \"added_by_star_ex\")" &>/dev/null .flags[] == \"added_by_star_ex\")" &>/dev/null
check_err $? "Auto-added S,G entry doesn't have added_by_star_ex flag" check_err $? "Auto-added S,G entry doesn't have added_by_star_ex flag"
check_sg_fwding 1 192.0.2.3 brmcast_check_sg_fwding 1 192.0.2.3
log_test "IGMPv3 S,G port entry automatic add to a *,G port" log_test "IGMPv3 S,G port entry automatic add to a *,G port"

View File

@ -0,0 +1,558 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
ALL_TESTS="mldv2include_test mldv2inc_allow_test mldv2inc_is_include_test mldv2inc_is_exclude_test \
mldv2inc_to_exclude_test mldv2exc_allow_test mldv2exc_is_include_test \
mldv2exc_is_exclude_test mldv2exc_to_exclude_test mldv2inc_block_test \
mldv2exc_block_test mldv2exc_timeout_test mldv2star_ex_auto_add_test"
NUM_NETIFS=4
CHECK_TC="yes"
TEST_GROUP="ff02::cc"
TEST_GROUP_MAC="33:33:00:00:00:cc"
# MLDv2 is_in report: grp ff02::cc is_include 2001:db8:1::1,2001:db8:1::2,2001:db8:1::3
MZPKT_IS_INC="33:33:00:00:00:01:fe:54:00:04:5e:ba:86:dd:60:0a:2d:ae:00:54:00:01:fe:80:00:\
00:00:00:00:00:fc:54:00:ff:fe:04:5e:ba:ff:02:00:00:00:00:00:00:00:00:00:00:00:00:00:01:3a:\
00:05:02:00:00:00:00:8f:00:8e:d9:00:00:00:01:01:00:00:03:ff:02:00:00:00:00:00:00:00:00:00:\
00:00:00:00:cc:20:01:0d:b8:00:01:00:00:00:00:00:00:00:00:00:01:20:01:0d:b8:00:01:00:00:00:\
00:00:00:00:00:00:02:20:01:0d:b8:00:01:00:00:00:00:00:00:00:00:00:03"
# MLDv2 is_in report: grp ff02::cc is_include 2001:db8:1::10,2001:db8:1::11,2001:db8:1::12
MZPKT_IS_INC2="33:33:00:00:00:01:fe:54:00:04:5e:ba:86:dd:60:0a:2d:ae:00:54:00:01:fe:80:00:\
00:00:00:00:00:fc:54:00:ff:fe:04:5e:ba:ff:02:00:00:00:00:00:00:00:00:00:00:00:00:00:01:3a:00:\
05:02:00:00:00:00:8f:00:8e:ac:00:00:00:01:01:00:00:03:ff:02:00:00:00:00:00:00:00:00:00:00:00:\
00:00:cc:20:01:0d:b8:00:01:00:00:00:00:00:00:00:00:00:10:20:01:0d:b8:00:01:00:00:00:00:00:00:\
00:00:00:11:20:01:0d:b8:00:01:00:00:00:00:00:00:00:00:00:12"
# MLDv2 is_in report: grp ff02::cc is_include 2001:db8:1::20,2001:db8:1::30
MZPKT_IS_INC3="33:33:00:00:00:01:fe:54:00:04:5e:ba:86:dd:60:0a:2d:ae:00:44:00:01:fe:80:00:00:00:\
00:00:00:fc:54:00:ff:fe:04:5e:ba:ff:02:00:00:00:00:00:00:00:00:00:00:00:00:00:01:3a:00:05:02:00:\
00:00:00:8f:00:bc:5a:00:00:00:01:01:00:00:02:ff:02:00:00:00:00:00:00:00:00:00:00:00:00:00:cc:20:\
01:0d:b8:00:01:00:00:00:00:00:00:00:00:00:20:20:01:0d:b8:00:01:00:00:00:00:00:00:00:00:00:30"
# MLDv2 allow report: grp ff02::cc allow 2001:db8:1::10,2001:db8:1::11,2001:db8:1::12
MZPKT_ALLOW="33:33:00:00:00:01:fe:54:00:04:5e:ba:86:dd:60:0a:2d:ae:00:54:00:01:fe:80:00:00:\
00:00:00:00:fc:54:00:ff:fe:04:5e:ba:ff:02:00:00:00:00:00:00:00:00:00:00:00:00:00:01:3a:00:05:\
02:00:00:00:00:8f:00:8a:ac:00:00:00:01:05:00:00:03:ff:02:00:00:00:00:00:00:00:00:00:00:00:00:\
00:cc:20:01:0d:b8:00:01:00:00:00:00:00:00:00:00:00:10:20:01:0d:b8:00:01:00:00:00:00:00:00:00:\
00:00:11:20:01:0d:b8:00:01:00:00:00:00:00:00:00:00:00:12"
# MLDv2 allow report: grp ff02::cc allow 2001:db8:1::20,2001:db8:1::30
MZPKT_ALLOW2="33:33:00:00:00:01:fe:54:00:04:5e:ba:86:dd:60:0a:2d:ae:00:44:00:01:fe:80:00:00:00:\
00:00:00:fc:54:00:ff:fe:04:5e:ba:ff:02:00:00:00:00:00:00:00:00:00:00:00:00:00:01:3a:00:05:02:00:\
00:00:00:8f:00:b8:5a:00:00:00:01:05:00:00:02:ff:02:00:00:00:00:00:00:00:00:00:00:00:00:00:cc:20:\
01:0d:b8:00:01:00:00:00:00:00:00:00:00:00:20:20:01:0d:b8:00:01:00:00:00:00:00:00:00:00:00:30"
# MLDv2 is_ex report: grp ff02::cc is_exclude 2001:db8:1::1,2001:db8:1::2,2001:db8:1::20,2001:db8:1::21
MZPKT_IS_EXC="33:33:00:00:00:01:fe:54:00:04:5e:ba:86:dd:60:0a:2d:ae:00:64:00:01:fe:80:00:00:00:\
00:00:00:fc:54:00:ff:fe:04:5e:ba:ff:02:00:00:00:00:00:00:00:00:00:00:00:00:00:01:3a:00:05:02:00:\
00:00:00:8f:00:5f:d0:00:00:00:01:02:00:00:04:ff:02:00:00:00:00:00:00:00:00:00:00:00:00:00:cc:20:\
01:0d:b8:00:01:00:00:00:00:00:00:00:00:00:01:20:01:0d:b8:00:01:00:00:00:00:00:00:00:00:00:02:20:\
01:0d:b8:00:01:00:00:00:00:00:00:00:00:00:20:20:01:0d:b8:00:01:00:00:00:00:00:00:00:00:00:21"
# MLDv2 is_ex report: grp ff02::cc is_exclude 2001:db8:1::20,2001:db8:1::30
MZPKT_IS_EXC2="33:33:00:00:00:01:fe:54:00:04:5e:ba:86:dd:60:0a:2d:ae:00:44:00:01:fe:80:00:00:00:\
00:00:00:fc:54:00:ff:fe:04:5e:ba:ff:02:00:00:00:00:00:00:00:00:00:00:00:00:00:01:3a:00:05:02:00:\
00:00:00:8f:00:bb:5a:00:00:00:01:02:00:00:02:ff:02:00:00:00:00:00:00:00:00:00:00:00:00:00:cc:20:\
01:0d:b8:00:01:00:00:00:00:00:00:00:00:00:20:20:01:0d:b8:00:01:00:00:00:00:00:00:00:00:00:30"
# MLDv2 to_ex report: grp ff02::cc to_exclude 2001:db8:1::1,2001:db8:1::20,2001:db8:1::30
MZPKT_TO_EXC="33:33:00:00:00:01:fe:54:00:04:5e:ba:86:dd:60:0a:2d:ae:00:54:00:01:fe:80:00:00:00:\
00:00:00:fc:54:00:ff:fe:04:5e:ba:ff:02:00:00:00:00:00:00:00:00:00:00:00:00:00:01:3a:00:05:02:00:\
00:00:00:8f:00:8b:8e:00:00:00:01:04:00:00:03:ff:02:00:00:00:00:00:00:00:00:00:00:00:00:00:cc:20:\
01:0d:b8:00:01:00:00:00:00:00:00:00:00:00:01:20:01:0d:b8:00:01:00:00:00:00:00:00:00:00:00:20:20:\
01:0d:b8:00:01:00:00:00:00:00:00:00:00:00:30"
# MLDv2 block report: grp ff02::cc block 2001:db8:1::1,2001:db8:1::20,2001:db8:1::30
MZPKT_BLOCK="33:33:00:00:00:01:fe:54:00:04:5e:ba:86:dd:60:0a:2d:ae:00:54:00:01:fe:80:00:00:00:00:\
00:00:fc:54:00:ff:fe:04:5e:ba:ff:02:00:00:00:00:00:00:00:00:00:00:00:00:00:01:3a:00:05:02:00:00:\
00:00:8f:00:89:8e:00:00:00:01:06:00:00:03:ff:02:00:00:00:00:00:00:00:00:00:00:00:00:00:cc:20:01:\
0d:b8:00:01:00:00:00:00:00:00:00:00:00:01:20:01:0d:b8:00:01:00:00:00:00:00:00:00:00:00:20:20:01:\
0d:b8:00:01:00:00:00:00:00:00:00:00:00:30"
source lib.sh
h1_create()
{
simple_if_init $h1 2001:db8:1::1/64
}
h1_destroy()
{
simple_if_fini $h1 2001:db8:1::1/64
}
h2_create()
{
simple_if_init $h2 2001:db8:1::2/64
}
h2_destroy()
{
simple_if_fini $h2 2001:db8:1::2/64
}
switch_create()
{
ip link add dev br0 type bridge mcast_snooping 1 mcast_query_response_interval 100 \
mcast_mld_version 2 mcast_startup_query_interval 300 \
mcast_querier 1
ip link set dev $swp1 master br0
ip link set dev $swp2 master br0
ip link set dev br0 up
ip link set dev $swp1 up
ip link set dev $swp2 up
# make sure a query has been generated
sleep 5
}
switch_destroy()
{
ip link set dev $swp2 down
ip link set dev $swp1 down
ip link del dev br0
}
setup_prepare()
{
h1=${NETIFS[p1]}
swp1=${NETIFS[p2]}
swp2=${NETIFS[p3]}
h2=${NETIFS[p4]}
vrf_prepare
h1_create
h2_create
switch_create
}
cleanup()
{
pre_cleanup
switch_destroy
h2_destroy
h1_destroy
vrf_cleanup
}
mldv2include_prepare()
{
local host1_if=$1
local X=("2001:db8:1::1" "2001:db8:1::2" "2001:db8:1::3")
ip link set dev br0 type bridge mcast_mld_version 2
check_err $? "Could not change bridge MLD version to 2"
$MZ $host1_if $MZPKT_IS_INC -q
sleep 1
bridge -j -d -s mdb show dev br0 \
| jq -e ".[].mdb[] | \
select(.grp == \"$TEST_GROUP\" and .source_list != null)" &>/dev/null
check_err $? "Missing *,G entry with source list"
bridge -j -d -s mdb show dev br0 \
| jq -e ".[].mdb[] | \
select(.grp == \"$TEST_GROUP\" and \
.source_list != null and .filter_mode == \"include\")" &>/dev/null
check_err $? "Wrong *,G entry filter mode"
brmcast_check_sg_entries "is_include" "${X[@]}"
}
mldv2exclude_prepare()
{
local host1_if=$1
local mac=$2
local group=$3
local pkt=$4
local X=("2001:db8:1::1" "2001:db8:1::2")
local Y=("2001:db8:1::20" "2001:db8:1::21")
mldv2include_prepare $h1
$MZ $host1_if -c 1 $MZPKT_IS_EXC -q
sleep 1
bridge -j -d -s mdb show dev br0 \
| jq -e ".[].mdb[] | \
select(.grp == \"$TEST_GROUP\" and \
.source_list != null and .filter_mode == \"exclude\")" &>/dev/null
check_err $? "Wrong *,G entry filter mode"
brmcast_check_sg_entries "is_exclude" "${X[@]}" "${Y[@]}"
brmcast_check_sg_state 0 "${X[@]}"
brmcast_check_sg_state 1 "${Y[@]}"
bridge -j -d -s mdb show dev br0 \
| jq -e ".[].mdb[] | \
select(.grp == \"$TEST_GROUP\" and \
.source_list != null and
.source_list[].address == \"2001:db8:1::3\")" &>/dev/null
check_fail $? "Wrong *,G entry source list, 2001:db8:1::3 entry still exists"
}
mldv2cleanup()
{
local port=$1
bridge mdb del dev br0 port $port grp $TEST_GROUP
ip link set dev br0 type bridge mcast_mld_version 1
}
mldv2include_test()
{
RET=0
local X=("2001:db8:1::1" "2001:db8:1::2" "2001:db8:1::3")
mldv2include_prepare $h1
brmcast_check_sg_state 0 "${X[@]}"
brmcast_check_sg_fwding 1 "${X[@]}"
brmcast_check_sg_fwding 0 "2001:db8:1::100"
log_test "MLDv2 report $TEST_GROUP is_include"
mldv2cleanup $swp1
}
mldv2inc_allow_test()
{
RET=0
local X=("2001:db8:1::10" "2001:db8:1::11" "2001:db8:1::12")
mldv2include_prepare $h1
$MZ $h1 -c 1 $MZPKT_ALLOW -q
sleep 1
brmcast_check_sg_entries "allow" "${X[@]}"
brmcast_check_sg_state 0 "${X[@]}"
brmcast_check_sg_fwding 1 "${X[@]}"
brmcast_check_sg_fwding 0 "2001:db8:1::100"
log_test "MLDv2 report $TEST_GROUP include -> allow"
mldv2cleanup $swp1
}
mldv2inc_is_include_test()
{
RET=0
local X=("2001:db8:1::10" "2001:db8:1::11" "2001:db8:1::12")
mldv2include_prepare $h1
$MZ $h1 -c 1 $MZPKT_IS_INC2 -q
sleep 1
brmcast_check_sg_entries "is_include" "${X[@]}"
brmcast_check_sg_state 0 "${X[@]}"
brmcast_check_sg_fwding 1 "${X[@]}"
brmcast_check_sg_fwding 0 "2001:db8:1::100"
log_test "MLDv2 report $TEST_GROUP include -> is_include"
mldv2cleanup $swp1
}
mldv2inc_is_exclude_test()
{
RET=0
mldv2exclude_prepare $h1
brmcast_check_sg_fwding 1 "${X[@]}" 2001:db8:1::100
brmcast_check_sg_fwding 0 "${Y[@]}"
log_test "MLDv2 report $TEST_GROUP include -> is_exclude"
mldv2cleanup $swp1
}
mldv2inc_to_exclude_test()
{
RET=0
local X=("2001:db8:1::1")
local Y=("2001:db8:1::20" "2001:db8:1::30")
mldv2include_prepare $h1
ip link set dev br0 type bridge mcast_last_member_interval 500
check_err $? "Could not change mcast_last_member_interval to 5s"
$MZ $h1 -c 1 $MZPKT_TO_EXC -q
sleep 1
bridge -j -d -s mdb show dev br0 \
| jq -e ".[].mdb[] | \
select(.grp == \"$TEST_GROUP\" and \
.source_list != null and .filter_mode == \"exclude\")" &>/dev/null
check_err $? "Wrong *,G entry filter mode"
brmcast_check_sg_entries "to_exclude" "${X[@]}" "${Y[@]}"
brmcast_check_sg_state 0 "${X[@]}"
brmcast_check_sg_state 1 "${Y[@]}"
bridge -j -d -s mdb show dev br0 \
| jq -e ".[].mdb[] | \
select(.grp == \"$TEST_GROUP\" and \
.source_list != null and
.source_list[].address == \"2001:db8:1::2\")" &>/dev/null
check_fail $? "Wrong *,G entry source list, 2001:db8:1::2 entry still exists"
bridge -j -d -s mdb show dev br0 \
| jq -e ".[].mdb[] | \
select(.grp == \"$TEST_GROUP\" and \
.source_list != null and
.source_list[].address == \"2001:db8:1::21\")" &>/dev/null
check_fail $? "Wrong *,G entry source list, 2001:db8:1::21 entry still exists"
brmcast_check_sg_fwding 1 "${X[@]}" 2001:db8:1::100
brmcast_check_sg_fwding 0 "${Y[@]}"
log_test "MLDv2 report $TEST_GROUP include -> to_exclude"
ip link set dev br0 type bridge mcast_last_member_interval 100
mldv2cleanup $swp1
}
mldv2exc_allow_test()
{
RET=0
local X=("2001:db8:1::1" "2001:db8:1::2" "2001:db8:1::20" "2001:db8:1::30")
local Y=("2001:db8:1::21")
mldv2exclude_prepare $h1
$MZ $h1 -c 1 $MZPKT_ALLOW2 -q
sleep 1
brmcast_check_sg_entries "allow" "${X[@]}" "${Y[@]}"
brmcast_check_sg_state 0 "${X[@]}"
brmcast_check_sg_state 1 "${Y[@]}"
brmcast_check_sg_fwding 1 "${X[@]}" 2001:db8:1::100
brmcast_check_sg_fwding 0 "${Y[@]}"
log_test "MLDv2 report $TEST_GROUP exclude -> allow"
mldv2cleanup $swp1
}
mldv2exc_is_include_test()
{
RET=0
local X=("2001:db8:1::1" "2001:db8:1::2" "2001:db8:1::20" "2001:db8:1::30")
local Y=("2001:db8:1::21")
mldv2exclude_prepare $h1
$MZ $h1 -c 1 $MZPKT_IS_INC3 -q
sleep 1
brmcast_check_sg_entries "is_include" "${X[@]}" "${Y[@]}"
brmcast_check_sg_state 0 "${X[@]}"
brmcast_check_sg_state 1 "${Y[@]}"
brmcast_check_sg_fwding 1 "${X[@]}" 2001:db8:1::100
brmcast_check_sg_fwding 0 "${Y[@]}"
log_test "MLDv2 report $TEST_GROUP exclude -> is_include"
mldv2cleanup $swp1
}
mldv2exc_is_exclude_test()
{
RET=0
local X=("2001:db8:1::30")
local Y=("2001:db8:1::20")
mldv2exclude_prepare $h1
$MZ $h1 -c 1 $MZPKT_IS_EXC2 -q
sleep 1
brmcast_check_sg_entries "is_exclude" "${X[@]}" "${Y[@]}"
brmcast_check_sg_state 0 "${X[@]}"
brmcast_check_sg_state 1 "${Y[@]}"
brmcast_check_sg_fwding 1 "${X[@]}" 2001:db8:1::100
brmcast_check_sg_fwding 0 "${Y[@]}"
log_test "MLDv2 report $TEST_GROUP exclude -> is_exclude"
mldv2cleanup $swp1
}
mldv2exc_to_exclude_test()
{
RET=0
local X=("2001:db8:1::1" "2001:db8:1::30")
local Y=("2001:db8:1::20")
mldv2exclude_prepare $h1
ip link set dev br0 type bridge mcast_last_member_interval 500
check_err $? "Could not change mcast_last_member_interval to 5s"
$MZ $h1 -c 1 $MZPKT_TO_EXC -q
sleep 1
brmcast_check_sg_entries "to_exclude" "${X[@]}" "${Y[@]}"
brmcast_check_sg_state 0 "${X[@]}"
brmcast_check_sg_state 1 "${Y[@]}"
brmcast_check_sg_fwding 1 "${X[@]}" 2001:db8:1::100
brmcast_check_sg_fwding 0 "${Y[@]}"
log_test "MLDv2 report $TEST_GROUP exclude -> to_exclude"
ip link set dev br0 type bridge mcast_last_member_interval 100
mldv2cleanup $swp1
}
mldv2inc_block_test()
{
RET=0
local X=("2001:db8:1::2" "2001:db8:1::3")
mldv2include_prepare $h1
$MZ $h1 -c 1 $MZPKT_BLOCK -q
# make sure the lowered timers have expired (by default 2 seconds)
sleep 3
brmcast_check_sg_entries "block" "${X[@]}"
brmcast_check_sg_state 0 "${X[@]}"
bridge -j -d -s mdb show dev br0 \
| jq -e ".[].mdb[] | \
select(.grp == \"$TEST_GROUP\" and \
.source_list != null and
.source_list[].address == \"2001:db8:1::1\")" &>/dev/null
check_fail $? "Wrong *,G entry source list, 2001:db8:1::1 entry still exists"
brmcast_check_sg_fwding 1 "${X[@]}"
brmcast_check_sg_fwding 0 2001:db8:1::100
log_test "MLDv2 report $TEST_GROUP include -> block"
mldv2cleanup $swp1
}
mldv2exc_block_test()
{
RET=0
local X=("2001:db8:1::1" "2001:db8:1::2" "2001:db8:1::30")
local Y=("2001:db8:1::20" "2001:db8:1::21")
mldv2exclude_prepare $h1
ip link set dev br0 type bridge mcast_last_member_interval 500
check_err $? "Could not change mcast_last_member_interval to 5s"
$MZ $h1 -c 1 $MZPKT_BLOCK -q
sleep 1
brmcast_check_sg_entries "block" "${X[@]}" "${Y[@]}"
brmcast_check_sg_state 0 "${X[@]}"
brmcast_check_sg_state 1 "${Y[@]}"
brmcast_check_sg_fwding 1 "${X[@]}" 2001:db8:1::100
brmcast_check_sg_fwding 0 "${Y[@]}"
log_test "MLDv2 report $TEST_GROUP exclude -> block"
ip link set dev br0 type bridge mcast_last_member_interval 100
mldv2cleanup $swp1
}
mldv2exc_timeout_test()
{
RET=0
local X=("2001:db8:1::20" "2001:db8:1::30")
# GMI should be 3 seconds
ip link set dev br0 type bridge mcast_query_interval 100 mcast_query_response_interval 100
mldv2exclude_prepare $h1
ip link set dev br0 type bridge mcast_query_interval 500 mcast_query_response_interval 500
$MZ $h1 -c 1 $MZPKT_ALLOW2 -q
sleep 3
bridge -j -d -s mdb show dev br0 \
| jq -e ".[].mdb[] | \
select(.grp == \"$TEST_GROUP\" and \
.source_list != null and .filter_mode == \"include\")" &>/dev/null
check_err $? "Wrong *,G entry filter mode"
bridge -j -d -s mdb show dev br0 \
| jq -e ".[].mdb[] | \
select(.grp == \"$TEST_GROUP\" and \
.source_list != null and
.source_list[].address == \"2001:db8:1::1\")" &>/dev/null
check_fail $? "Wrong *,G entry source list, 2001:db8:1::1 entry still exists"
bridge -j -d -s mdb show dev br0 \
| jq -e ".[].mdb[] | \
select(.grp == \"$TEST_GROUP\" and \
.source_list != null and
.source_list[].address == \"2001:db8:1::2\")" &>/dev/null
check_fail $? "Wrong *,G entry source list, 2001:db8:1::2 entry still exists"
brmcast_check_sg_entries "allow" "${X[@]}"
brmcast_check_sg_state 0 "${X[@]}"
brmcast_check_sg_fwding 1 "${X[@]}"
brmcast_check_sg_fwding 0 2001:db8:1::100
log_test "MLDv2 group $TEST_GROUP exclude timeout"
ip link set dev br0 type bridge mcast_query_interval 12500 \
mcast_query_response_interval 1000
mldv2cleanup $swp1
}
mldv2star_ex_auto_add_test()
{
RET=0
mldv2exclude_prepare $h1
$MZ $h2 -c 1 $MZPKT_IS_INC -q
sleep 1
bridge -j -d -s mdb show dev br0 \
| jq -e ".[].mdb[] | \
select(.grp == \"$TEST_GROUP\" and .src == \"2001:db8:1::3\" and \
.port == \"$swp1\")" &>/dev/null
check_err $? "S,G entry for *,G port doesn't exist"
bridge -j -d -s mdb show dev br0 \
| jq -e ".[].mdb[] | \
select(.grp == \"$TEST_GROUP\" and .src == \"2001:db8:1::3\" and \
.port == \"$swp1\" and \
.flags[] == \"added_by_star_ex\")" &>/dev/null
check_err $? "Auto-added S,G entry doesn't have added_by_star_ex flag"
brmcast_check_sg_fwding 1 2001:db8:1::3
log_test "MLDv2 S,G port entry automatic add to a *,G port"
mldv2cleanup $swp1
mldv2cleanup $swp2
}
trap cleanup EXIT
setup_prepare
setup_wait
tests_run
exit $EXIT_STATUS

View File

@ -1270,3 +1270,110 @@ tcpdump_show()
{ {
tcpdump -e -n -r $capfile 2>&1 tcpdump -e -n -r $capfile 2>&1
} }
# return 0 if the packet wasn't seen on host2_if or 1 if it was
mcast_packet_test()
{
local mac=$1
local src_ip=$2
local ip=$3
local host1_if=$4
local host2_if=$5
local seen=0
local tc_proto="ip"
local mz_v6arg=""
# basic check to see if we were passed an IPv4 address, if not assume IPv6
if [[ ! $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
tc_proto="ipv6"
mz_v6arg="-6"
fi
# Add an ACL on `host2_if` which will tell us whether the packet
# was received by it or not.
tc qdisc add dev $host2_if ingress
tc filter add dev $host2_if ingress protocol $tc_proto pref 1 handle 101 \
flower ip_proto udp dst_mac $mac action drop
$MZ $host1_if $mz_v6arg -c 1 -p 64 -b $mac -A $src_ip -B $ip -t udp "dp=4096,sp=2048" -q
sleep 1
tc -j -s filter show dev $host2_if ingress \
| jq -e ".[] | select(.options.handle == 101) \
| select(.options.actions[0].stats.packets == 1)" &> /dev/null
if [[ $? -eq 0 ]]; then
seen=1
fi
tc filter del dev $host2_if ingress protocol $tc_proto pref 1 handle 101 flower
tc qdisc del dev $host2_if ingress
return $seen
}
brmcast_check_sg_entries()
{
local report=$1; shift
local slist=("$@")
local sarg=""
for src in "${slist[@]}"; do
sarg="${sarg} and .source_list[].address == \"$src\""
done
bridge -j -d -s mdb show dev br0 \
| jq -e ".[].mdb[] | \
select(.grp == \"$TEST_GROUP\" and .source_list != null $sarg)" &>/dev/null
check_err $? "Wrong *,G entry source list after $report report"
for sgent in "${slist[@]}"; do
bridge -j -d -s mdb show dev br0 \
| jq -e ".[].mdb[] | \
select(.grp == \"$TEST_GROUP\" and .src == \"$sgent\")" &>/dev/null
check_err $? "Missing S,G entry ($sgent, $TEST_GROUP)"
done
}
brmcast_check_sg_fwding()
{
local should_fwd=$1; shift
local sources=("$@")
for src in "${sources[@]}"; do
local retval=0
mcast_packet_test $TEST_GROUP_MAC $src $TEST_GROUP $h2 $h1
retval=$?
if [ $should_fwd -eq 1 ]; then
check_fail $retval "Didn't forward traffic from S,G ($src, $TEST_GROUP)"
else
check_err $retval "Forwarded traffic for blocked S,G ($src, $TEST_GROUP)"
fi
done
}
brmcast_check_sg_state()
{
local is_blocked=$1; shift
local sources=("$@")
local should_fail=1
if [ $is_blocked -eq 1 ]; then
should_fail=0
fi
for src in "${sources[@]}"; do
bridge -j -d -s mdb show dev br0 \
| jq -e ".[].mdb[] | \
select(.grp == \"$TEST_GROUP\" and .source_list != null) |
.source_list[] |
select(.address == \"$src\") |
select(.timer == \"0.00\")" &>/dev/null
check_err_fail $should_fail $? "Entry $src has zero timer"
bridge -j -d -s mdb show dev br0 \
| jq -e ".[].mdb[] | \
select(.grp == \"$TEST_GROUP\" and .src == \"$src\" and \
.flags[] == \"blocked\")" &>/dev/null
check_err_fail $should_fail $? "Entry $src has blocked flag"
done
}