xref: /linux/tools/testing/selftests/net/forwarding/bridge_mld.sh (revision ab93e0dd72c37d378dd936f031ffb83ff2bd87ce)
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4ALL_TESTS="
5	mldv2include_test
6	mldv2inc_allow_test
7	mldv2inc_is_include_test
8	mldv2inc_is_exclude_test
9	mldv2inc_to_exclude_test
10	mldv2exc_allow_test
11	mldv2exc_is_include_test
12	mldv2exc_is_exclude_test
13	mldv2exc_to_exclude_test
14	mldv2inc_block_test
15	mldv2exc_block_test
16	mldv2exc_timeout_test
17	mldv2star_ex_auto_add_test
18	mldv2per_vlan_snooping_port_stp_test
19	mldv2per_vlan_snooping_vlan_stp_test
20"
21NUM_NETIFS=4
22CHECK_TC="yes"
23TEST_GROUP="ff02::cc"
24TEST_GROUP_MAC="33:33:00:00:00:cc"
25
26# MLDv2 is_in report: grp ff02::cc is_include 2001:db8:1::1,2001:db8:1::2,2001:db8:1::3
27MZPKT_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:\
2800: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:\
2900: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:\
3000: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:\
3100:00:00:00:00:00:02:20:01:0d:b8:00:01:00:00:00:00:00:00:00:00:00:03"
32# MLDv2 is_in report: grp ff02::cc is_include 2001:db8:1::10,2001:db8:1::11,2001:db8:1::12
33MZPKT_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:\
3400: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:\
3505: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:\
3600: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:\
3700:00:00:11:20:01:0d:b8:00:01:00:00:00:00:00:00:00:00:00:12"
38# MLDv2 is_in report: grp ff02::cc is_include 2001:db8:1::20,2001:db8:1::30
39MZPKT_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:\
4000: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:\
4100: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:\
4201: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"
43# MLDv2 allow report: grp ff02::cc allow 2001:db8:1::10,2001:db8:1::11,2001:db8:1::12
44MZPKT_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:\
4500: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:\
4602: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:\
4700: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:\
4800:00:11:20:01:0d:b8:00:01:00:00:00:00:00:00:00:00:00:12"
49# MLDv2 allow report: grp ff02::cc allow 2001:db8:1::20,2001:db8:1::30
50MZPKT_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:\
5100: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:\
5200: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:\
5301: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"
54# 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
55MZPKT_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:\
5600: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:\
5700: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:\
5801: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:\
5901: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"
60# MLDv2 is_ex report: grp ff02::cc is_exclude 2001:db8:1::20,2001:db8:1::30
61MZPKT_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:\
6200: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:\
6300: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:\
6401: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"
65# MLDv2 to_ex report: grp ff02::cc to_exclude 2001:db8:1::1,2001:db8:1::20,2001:db8:1::30
66MZPKT_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:\
6700: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:\
6800: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:\
6901: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:\
7001:0d:b8:00:01:00:00:00:00:00:00:00:00:00:30"
71# MLDv2 block report: grp ff02::cc block 2001:db8:1::1,2001:db8:1::20,2001:db8:1::30
72MZPKT_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:\
7300: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:\
7400: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:\
750d: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:\
760d:b8:00:01:00:00:00:00:00:00:00:00:00:30"
77
78source lib.sh
79
80h1_create()
81{
82	simple_if_init $h1 2001:db8:1::1/64
83}
84
85h1_destroy()
86{
87	simple_if_fini $h1 2001:db8:1::1/64
88}
89
90h2_create()
91{
92	simple_if_init $h2 2001:db8:1::2/64
93}
94
95h2_destroy()
96{
97	simple_if_fini $h2 2001:db8:1::2/64
98}
99
100switch_create()
101{
102	ip link add dev br0 type bridge mcast_snooping 1 mcast_query_response_interval 100 \
103					mcast_mld_version 2 mcast_startup_query_interval 300 \
104					mcast_querier 1
105
106	ip link set dev $swp1 master br0
107	ip link set dev $swp2 master br0
108
109	ip link set dev br0 up
110	ip link set dev $swp1 up
111	ip link set dev $swp2 up
112
113	# make sure a query has been generated
114	sleep 5
115}
116
117switch_destroy()
118{
119	ip link set dev $swp2 down
120	ip link set dev $swp1 down
121
122	ip link del dev br0
123}
124
125setup_prepare()
126{
127	h1=${NETIFS[p1]}
128	swp1=${NETIFS[p2]}
129
130	swp2=${NETIFS[p3]}
131	h2=${NETIFS[p4]}
132
133	vrf_prepare
134
135	h1_create
136	h2_create
137
138	switch_create
139}
140
141cleanup()
142{
143	pre_cleanup
144
145	switch_destroy
146
147	h2_destroy
148	h1_destroy
149
150	vrf_cleanup
151}
152
153mldv2include_prepare()
154{
155	local host1_if=$1
156	local X=("2001:db8:1::1" "2001:db8:1::2" "2001:db8:1::3")
157
158	ip link set dev br0 type bridge mcast_mld_version 2
159	check_err $? "Could not change bridge MLD version to 2"
160
161	$MZ $host1_if $MZPKT_IS_INC -q
162	sleep 1
163	bridge -j -d -s mdb show dev br0 \
164		| jq -e ".[].mdb[] | \
165			 select(.grp == \"$TEST_GROUP\" and .source_list != null)" &>/dev/null
166	check_err $? "Missing *,G entry with source list"
167	bridge -j -d -s mdb show dev br0 \
168		| jq -e ".[].mdb[] | \
169			 select(.grp == \"$TEST_GROUP\" and \
170				.source_list != null and .filter_mode == \"include\")" &>/dev/null
171	check_err $? "Wrong *,G entry filter mode"
172	brmcast_check_sg_entries "is_include" "${X[@]}"
173}
174
175mldv2exclude_prepare()
176{
177	local host1_if=$1
178	local mac=$2
179	local group=$3
180	local pkt=$4
181	local X=("2001:db8:1::1" "2001:db8:1::2")
182	local Y=("2001:db8:1::20" "2001:db8:1::21")
183
184	mldv2include_prepare $h1
185
186	$MZ $host1_if -c 1 $MZPKT_IS_EXC -q
187	sleep 1
188	bridge -j -d -s mdb show dev br0 \
189		| jq -e ".[].mdb[] | \
190			 select(.grp == \"$TEST_GROUP\" and \
191			 .source_list != null and .filter_mode == \"exclude\")" &>/dev/null
192	check_err $? "Wrong *,G entry filter mode"
193
194	brmcast_check_sg_entries "is_exclude" "${X[@]}" "${Y[@]}"
195
196	brmcast_check_sg_state 0 "${X[@]}"
197	brmcast_check_sg_state 1 "${Y[@]}"
198
199	bridge -j -d -s mdb show dev br0 \
200		| jq -e ".[].mdb[] | \
201			 select(.grp == \"$TEST_GROUP\" and \
202				.source_list != null and
203				.source_list[].address == \"2001:db8:1::3\")" &>/dev/null
204	check_fail $? "Wrong *,G entry source list, 2001:db8:1::3 entry still exists"
205}
206
207mldv2cleanup()
208{
209	local port=$1
210
211	bridge mdb del dev br0 port $port grp $TEST_GROUP
212	ip link set dev br0 type bridge mcast_mld_version 1
213}
214
215mldv2include_test()
216{
217	RET=0
218	local X=("2001:db8:1::1" "2001:db8:1::2" "2001:db8:1::3")
219
220	mldv2include_prepare $h1
221
222	brmcast_check_sg_state 0 "${X[@]}"
223
224	brmcast_check_sg_fwding 1 "${X[@]}"
225	brmcast_check_sg_fwding 0 "2001:db8:1::100"
226
227	log_test "MLDv2 report $TEST_GROUP is_include"
228
229	mldv2cleanup $swp1
230}
231
232mldv2inc_allow_test()
233{
234	RET=0
235	local X=("2001:db8:1::10" "2001:db8:1::11" "2001:db8:1::12")
236
237	mldv2include_prepare $h1
238
239	$MZ $h1 -c 1 $MZPKT_ALLOW -q
240	sleep 1
241	brmcast_check_sg_entries "allow" "${X[@]}"
242
243	brmcast_check_sg_state 0 "${X[@]}"
244
245	brmcast_check_sg_fwding 1 "${X[@]}"
246	brmcast_check_sg_fwding 0 "2001:db8:1::100"
247
248	log_test "MLDv2 report $TEST_GROUP include -> allow"
249
250	mldv2cleanup $swp1
251}
252
253mldv2inc_is_include_test()
254{
255	RET=0
256	local X=("2001:db8:1::10" "2001:db8:1::11" "2001:db8:1::12")
257
258	mldv2include_prepare $h1
259
260	$MZ $h1 -c 1 $MZPKT_IS_INC2 -q
261	sleep 1
262	brmcast_check_sg_entries "is_include" "${X[@]}"
263
264	brmcast_check_sg_state 0 "${X[@]}"
265
266	brmcast_check_sg_fwding 1 "${X[@]}"
267	brmcast_check_sg_fwding 0 "2001:db8:1::100"
268
269	log_test "MLDv2 report $TEST_GROUP include -> is_include"
270
271	mldv2cleanup $swp1
272}
273
274mldv2inc_is_exclude_test()
275{
276	RET=0
277
278	mldv2exclude_prepare $h1
279
280	brmcast_check_sg_fwding 1 "${X[@]}" 2001:db8:1::100
281	brmcast_check_sg_fwding 0 "${Y[@]}"
282
283	log_test "MLDv2 report $TEST_GROUP include -> is_exclude"
284
285	mldv2cleanup $swp1
286}
287
288mldv2inc_to_exclude_test()
289{
290	RET=0
291	local X=("2001:db8:1::1")
292	local Y=("2001:db8:1::20" "2001:db8:1::30")
293
294	mldv2include_prepare $h1
295
296	ip link set dev br0 type bridge mcast_last_member_interval 500
297	check_err $? "Could not change mcast_last_member_interval to 5s"
298
299	$MZ $h1 -c 1 $MZPKT_TO_EXC -q
300	sleep 1
301	bridge -j -d -s mdb show dev br0 \
302		| jq -e ".[].mdb[] | \
303			 select(.grp == \"$TEST_GROUP\" and \
304				.source_list != null and .filter_mode == \"exclude\")" &>/dev/null
305	check_err $? "Wrong *,G entry filter mode"
306
307	brmcast_check_sg_entries "to_exclude" "${X[@]}" "${Y[@]}"
308
309	brmcast_check_sg_state 0 "${X[@]}"
310	brmcast_check_sg_state 1 "${Y[@]}"
311
312	bridge -j -d -s mdb show dev br0 \
313		| jq -e ".[].mdb[] | \
314			 select(.grp == \"$TEST_GROUP\" and \
315				.source_list != null and
316				.source_list[].address == \"2001:db8:1::2\")" &>/dev/null
317	check_fail $? "Wrong *,G entry source list, 2001:db8:1::2 entry still exists"
318	bridge -j -d -s mdb show dev br0 \
319		| jq -e ".[].mdb[] | \
320			 select(.grp == \"$TEST_GROUP\" and \
321				.source_list != null and
322				.source_list[].address == \"2001:db8:1::21\")" &>/dev/null
323	check_fail $? "Wrong *,G entry source list, 2001:db8:1::21 entry still exists"
324
325	brmcast_check_sg_fwding 1 "${X[@]}" 2001:db8:1::100
326	brmcast_check_sg_fwding 0 "${Y[@]}"
327
328	log_test "MLDv2 report $TEST_GROUP include -> to_exclude"
329
330	ip link set dev br0 type bridge mcast_last_member_interval 100
331
332	mldv2cleanup $swp1
333}
334
335mldv2exc_allow_test()
336{
337	RET=0
338	local X=("2001:db8:1::1" "2001:db8:1::2" "2001:db8:1::20" "2001:db8:1::30")
339	local Y=("2001:db8:1::21")
340
341	mldv2exclude_prepare $h1
342
343	$MZ $h1 -c 1 $MZPKT_ALLOW2 -q
344	sleep 1
345	brmcast_check_sg_entries "allow" "${X[@]}" "${Y[@]}"
346
347	brmcast_check_sg_state 0 "${X[@]}"
348	brmcast_check_sg_state 1 "${Y[@]}"
349
350	brmcast_check_sg_fwding 1 "${X[@]}" 2001:db8:1::100
351	brmcast_check_sg_fwding 0 "${Y[@]}"
352
353	log_test "MLDv2 report $TEST_GROUP exclude -> allow"
354
355	mldv2cleanup $swp1
356}
357
358mldv2exc_is_include_test()
359{
360	RET=0
361	local X=("2001:db8:1::1" "2001:db8:1::2" "2001:db8:1::20" "2001:db8:1::30")
362	local Y=("2001:db8:1::21")
363
364	mldv2exclude_prepare $h1
365
366	$MZ $h1 -c 1 $MZPKT_IS_INC3 -q
367	sleep 1
368	brmcast_check_sg_entries "is_include" "${X[@]}" "${Y[@]}"
369
370	brmcast_check_sg_state 0 "${X[@]}"
371	brmcast_check_sg_state 1 "${Y[@]}"
372
373	brmcast_check_sg_fwding 1 "${X[@]}" 2001:db8:1::100
374	brmcast_check_sg_fwding 0 "${Y[@]}"
375
376	log_test "MLDv2 report $TEST_GROUP exclude -> is_include"
377
378	mldv2cleanup $swp1
379}
380
381mldv2exc_is_exclude_test()
382{
383	RET=0
384	local X=("2001:db8:1::30")
385	local Y=("2001:db8:1::20")
386
387	mldv2exclude_prepare $h1
388
389	$MZ $h1 -c 1 $MZPKT_IS_EXC2 -q
390	sleep 1
391	brmcast_check_sg_entries "is_exclude" "${X[@]}" "${Y[@]}"
392
393	brmcast_check_sg_state 0 "${X[@]}"
394	brmcast_check_sg_state 1 "${Y[@]}"
395
396	brmcast_check_sg_fwding 1 "${X[@]}" 2001:db8:1::100
397	brmcast_check_sg_fwding 0 "${Y[@]}"
398
399	log_test "MLDv2 report $TEST_GROUP exclude -> is_exclude"
400
401	mldv2cleanup $swp1
402}
403
404mldv2exc_to_exclude_test()
405{
406	RET=0
407	local X=("2001:db8:1::1" "2001:db8:1::30")
408	local Y=("2001:db8:1::20")
409
410	mldv2exclude_prepare $h1
411
412	ip link set dev br0 type bridge mcast_last_member_interval 500
413	check_err $? "Could not change mcast_last_member_interval to 5s"
414
415	$MZ $h1 -c 1 $MZPKT_TO_EXC -q
416	sleep 1
417	brmcast_check_sg_entries "to_exclude" "${X[@]}" "${Y[@]}"
418
419	brmcast_check_sg_state 0 "${X[@]}"
420	brmcast_check_sg_state 1 "${Y[@]}"
421
422	brmcast_check_sg_fwding 1 "${X[@]}" 2001:db8:1::100
423	brmcast_check_sg_fwding 0 "${Y[@]}"
424
425	log_test "MLDv2 report $TEST_GROUP exclude -> to_exclude"
426
427	ip link set dev br0 type bridge mcast_last_member_interval 100
428
429	mldv2cleanup $swp1
430}
431
432mldv2inc_block_test()
433{
434	RET=0
435	local X=("2001:db8:1::2" "2001:db8:1::3")
436
437	mldv2include_prepare $h1
438
439	$MZ $h1 -c 1 $MZPKT_BLOCK -q
440	# make sure the lowered timers have expired (by default 2 seconds)
441	sleep 3
442	brmcast_check_sg_entries "block" "${X[@]}"
443
444	brmcast_check_sg_state 0 "${X[@]}"
445
446	bridge -j -d -s mdb show dev br0 \
447		| jq -e ".[].mdb[] | \
448			 select(.grp == \"$TEST_GROUP\" and \
449				.source_list != null and
450				.source_list[].address == \"2001:db8:1::1\")" &>/dev/null
451	check_fail $? "Wrong *,G entry source list, 2001:db8:1::1 entry still exists"
452
453	brmcast_check_sg_fwding 1 "${X[@]}"
454	brmcast_check_sg_fwding 0 2001:db8:1::100
455
456	log_test "MLDv2 report $TEST_GROUP include -> block"
457
458	mldv2cleanup $swp1
459}
460
461mldv2exc_block_test()
462{
463	RET=0
464	local X=("2001:db8:1::1" "2001:db8:1::2" "2001:db8:1::30")
465	local Y=("2001:db8:1::20" "2001:db8:1::21")
466
467	mldv2exclude_prepare $h1
468
469	ip link set dev br0 type bridge mcast_last_member_interval 500
470	check_err $? "Could not change mcast_last_member_interval to 5s"
471
472	$MZ $h1 -c 1 $MZPKT_BLOCK -q
473	sleep 1
474	brmcast_check_sg_entries "block" "${X[@]}" "${Y[@]}"
475
476	brmcast_check_sg_state 0 "${X[@]}"
477	brmcast_check_sg_state 1 "${Y[@]}"
478
479	brmcast_check_sg_fwding 1 "${X[@]}" 2001:db8:1::100
480	brmcast_check_sg_fwding 0 "${Y[@]}"
481
482	log_test "MLDv2 report $TEST_GROUP exclude -> block"
483
484	ip link set dev br0 type bridge mcast_last_member_interval 100
485
486	mldv2cleanup $swp1
487}
488
489mldv2exc_timeout_test()
490{
491	RET=0
492	local X=("2001:db8:1::20" "2001:db8:1::30")
493
494	# GMI should be 5 seconds
495	ip link set dev br0 type bridge mcast_query_interval 100 \
496					mcast_query_response_interval 100 \
497					mcast_membership_interval 500
498
499	mldv2exclude_prepare $h1
500	ip link set dev br0 type bridge mcast_query_interval 500 \
501					mcast_query_response_interval 500 \
502					mcast_membership_interval 1500
503
504	$MZ $h1 -c 1 $MZPKT_ALLOW2 -q
505	sleep 5
506	bridge -j -d -s mdb show dev br0 \
507		| jq -e ".[].mdb[] | \
508			 select(.grp == \"$TEST_GROUP\" and \
509				.source_list != null and .filter_mode == \"include\")" &>/dev/null
510	check_err $? "Wrong *,G entry filter mode"
511
512	bridge -j -d -s mdb show dev br0 \
513		| jq -e ".[].mdb[] | \
514			 select(.grp == \"$TEST_GROUP\" and \
515				.source_list != null and
516				.source_list[].address == \"2001:db8:1::1\")" &>/dev/null
517	check_fail $? "Wrong *,G entry source list, 2001:db8:1::1 entry still exists"
518	bridge -j -d -s mdb show dev br0 \
519		| jq -e ".[].mdb[] | \
520			 select(.grp == \"$TEST_GROUP\" and \
521				.source_list != null and
522				.source_list[].address == \"2001:db8:1::2\")" &>/dev/null
523	check_fail $? "Wrong *,G entry source list, 2001:db8:1::2 entry still exists"
524
525	brmcast_check_sg_entries "allow" "${X[@]}"
526
527	brmcast_check_sg_state 0 "${X[@]}"
528
529	brmcast_check_sg_fwding 1 "${X[@]}"
530	brmcast_check_sg_fwding 0 2001:db8:1::100
531
532	log_test "MLDv2 group $TEST_GROUP exclude timeout"
533
534	ip link set dev br0 type bridge mcast_query_interval 12500 \
535					mcast_query_response_interval 1000 \
536					mcast_membership_interval 26000
537
538	mldv2cleanup $swp1
539}
540
541mldv2star_ex_auto_add_test()
542{
543	RET=0
544
545	mldv2exclude_prepare $h1
546
547	$MZ $h2 -c 1 $MZPKT_IS_INC -q
548	sleep 1
549	bridge -j -d -s mdb show dev br0 \
550		| jq -e ".[].mdb[] | \
551			 select(.grp == \"$TEST_GROUP\" and .src == \"2001:db8:1::3\" and \
552				.port == \"$swp1\")" &>/dev/null
553	check_err $? "S,G entry for *,G port doesn't exist"
554
555	bridge -j -d -s mdb show dev br0 \
556		| jq -e ".[].mdb[] | \
557			 select(.grp == \"$TEST_GROUP\" and .src == \"2001:db8:1::3\" and \
558				.port == \"$swp1\" and \
559				.flags[] == \"added_by_star_ex\")" &>/dev/null
560	check_err $? "Auto-added S,G entry doesn't have added_by_star_ex flag"
561
562	brmcast_check_sg_fwding 1 2001:db8:1::3
563
564	log_test "MLDv2 S,G port entry automatic add to a *,G port"
565
566	mldv2cleanup $swp1
567	mldv2cleanup $swp2
568}
569
570mldv2per_vlan_snooping_stp_test()
571{
572	local is_port=$1
573
574	local msg="port"
575	[[ $is_port -ne 1 ]] && msg="vlan"
576
577	ip link set br0 up type bridge vlan_filtering 1 \
578					mcast_mld_version 2 \
579					mcast_snooping 1 \
580					mcast_vlan_snooping 1 \
581					mcast_querier 1 \
582					mcast_stats_enabled 1
583	bridge vlan global set vid 1 dev br0 \
584					mcast_mld_version 2 \
585					mcast_snooping 1 \
586					mcast_querier 1 \
587					mcast_query_interval 100 \
588					mcast_startup_query_count 0
589
590	[[ $is_port -eq 1 ]] && bridge link set dev $swp1 state 0
591	[[ $is_port -ne 1 ]] && bridge vlan set vid 1 dev $swp1 state 4
592	sleep 5
593	local tx_s=$(ip -j -p stats show dev $swp1 \
594			group xstats_slave subgroup bridge suite mcast \
595			| jq '.[]["multicast"]["mld_queries"]["tx_v2"]')
596	[[ $is_port -eq 1 ]] && bridge link set dev $swp1 state 3
597	[[ $is_port -ne 1 ]] && bridge vlan set vid 1 dev $swp1 state 3
598	sleep 5
599	local tx_e=$(ip -j -p stats show dev $swp1 \
600			group xstats_slave subgroup bridge suite mcast \
601			| jq '.[]["multicast"]["mld_queries"]["tx_v2"]')
602
603	RET=0
604	local tx=$(expr $tx_e - $tx_s)
605	test $tx -gt 0
606	check_err $? "No MLD queries after STP state becomes forwarding"
607	log_test "per vlan snooping with $msg stp state change"
608
609	# restore settings
610	bridge vlan global set vid 1 dev br0 \
611					mcast_querier 0 \
612					mcast_query_interval 12500 \
613					mcast_startup_query_count 2 \
614					mcast_mld_version 1
615	ip link set br0 up type bridge vlan_filtering 0 \
616					mcast_vlan_snooping 0 \
617					mcast_stats_enabled 0
618}
619
620mldv2per_vlan_snooping_port_stp_test()
621{
622	mldv2per_vlan_snooping_stp_test 1
623}
624
625mldv2per_vlan_snooping_vlan_stp_test()
626{
627	mldv2per_vlan_snooping_stp_test 0
628}
629
630trap cleanup EXIT
631
632setup_prepare
633setup_wait
634
635tests_run
636
637exit $EXIT_STATUS
638