1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4ALL_TESTS="v2reportleave_test v3include_test v3inc_allow_test v3inc_is_include_test \
5	   v3inc_is_exclude_test v3inc_to_exclude_test v3exc_allow_test v3exc_is_include_test \
6	   v3exc_is_exclude_test v3exc_to_exclude_test v3inc_block_test v3exc_block_test \
7	   v3exc_timeout_test v3star_ex_auto_add_test"
8NUM_NETIFS=4
9CHECK_TC="yes"
10TEST_GROUP="239.10.10.10"
11TEST_GROUP_MAC="01:00:5e:0a:0a:0a"
12
13ALL_GROUP="224.0.0.1"
14ALL_MAC="01:00:5e:00:00:01"
15
16# IGMPv3 is_in report: grp 239.10.10.10 is_include 192.0.2.1,192.0.2.2,192.0.2.3
17MZPKT_IS_INC="22:00:9d:de:00:00:00:01:01:00:00:03:ef:0a:0a:0a:c0:00:02:01:c0:00:02:02:c0:00:02:03"
18# IGMPv3 is_in report: grp 239.10.10.10 is_include 192.0.2.10,192.0.2.11,192.0.2.12
19MZPKT_IS_INC2="22:00:9d:c3:00:00:00:01:01:00:00:03:ef:0a:0a:0a:c0:00:02:0a:c0:00:02:0b:c0:00:02:0c"
20# IGMPv3 is_in report: grp 239.10.10.10 is_include 192.0.2.20,192.0.2.30
21MZPKT_IS_INC3="22:00:5f:b4:00:00:00:01:01:00:00:02:ef:0a:0a:0a:c0:00:02:14:c0:00:02:1e"
22# IGMPv3 allow report: grp 239.10.10.10 allow 192.0.2.10,192.0.2.11,192.0.2.12
23MZPKT_ALLOW="22:00:99:c3:00:00:00:01:05:00:00:03:ef:0a:0a:0a:c0:00:02:0a:c0:00:02:0b:c0:00:02:0c"
24# IGMPv3 allow report: grp 239.10.10.10 allow 192.0.2.20,192.0.2.30
25MZPKT_ALLOW2="22:00:5b:b4:00:00:00:01:05:00:00:02:ef:0a:0a:0a:c0:00:02:14:c0:00:02:1e"
26# IGMPv3 is_ex report: grp 239.10.10.10 is_exclude 192.0.2.1,192.0.2.2,192.0.2.20,192.0.2.21
27MZPKT_IS_EXC="22:00:da:b6:00:00:00:01:02:00:00:04:ef:0a:0a:0a:c0:00:02:01:c0:00:02:02:c0:00:02:14:c0:00:02:15"
28# IGMPv3 is_ex report: grp 239.10.10.10 is_exclude 192.0.2.20,192.0.2.30
29MZPKT_IS_EXC2="22:00:5e:b4:00:00:00:01:02:00:00:02:ef:0a:0a:0a:c0:00:02:14:c0:00:02:1e"
30# IGMPv3 to_ex report: grp 239.10.10.10 to_exclude 192.0.2.1,192.0.2.20,192.0.2.30
31MZPKT_TO_EXC="22:00:9a:b1:00:00:00:01:04:00:00:03:ef:0a:0a:0a:c0:00:02:01:c0:00:02:14:c0:00:02:1e"
32# IGMPv3 block report: grp 239.10.10.10 block 192.0.2.1,192.0.2.20,192.0.2.30
33MZPKT_BLOCK="22:00:98:b1:00:00:00:01:06:00:00:03:ef:0a:0a:0a:c0:00:02:01:c0:00:02:14:c0:00:02:1e"
34
35source lib.sh
36
37h1_create()
38{
39	simple_if_init $h1 192.0.2.1/24 2001:db8:1::1/64
40}
41
42h1_destroy()
43{
44	simple_if_fini $h1 192.0.2.1/24 2001:db8:1::1/64
45}
46
47h2_create()
48{
49	simple_if_init $h2 192.0.2.2/24 2001:db8:1::2/64
50}
51
52h2_destroy()
53{
54	simple_if_fini $h2 192.0.2.2/24 2001:db8:1::2/64
55}
56
57switch_create()
58{
59	ip link add dev br0 type bridge mcast_snooping 1 mcast_querier 1
60
61	ip link set dev $swp1 master br0
62	ip link set dev $swp2 master br0
63
64	ip link set dev br0 up
65	ip link set dev $swp1 up
66	ip link set dev $swp2 up
67}
68
69switch_destroy()
70{
71	ip link set dev $swp2 down
72	ip link set dev $swp1 down
73
74	ip link del dev br0
75}
76
77setup_prepare()
78{
79	h1=${NETIFS[p1]}
80	swp1=${NETIFS[p2]}
81
82	swp2=${NETIFS[p3]}
83	h2=${NETIFS[p4]}
84
85	vrf_prepare
86
87	h1_create
88	h2_create
89
90	switch_create
91}
92
93cleanup()
94{
95	pre_cleanup
96
97	switch_destroy
98
99	# Always cleanup the mcast group
100	ip address del dev $h2 $TEST_GROUP/32 2>&1 1>/dev/null
101
102	h2_destroy
103	h1_destroy
104
105	vrf_cleanup
106}
107
108# return 0 if the packet wasn't seen on host2_if or 1 if it was
109mcast_packet_test()
110{
111	local mac=$1
112	local src_ip=$2
113	local ip=$3
114	local host1_if=$4
115	local host2_if=$5
116	local seen=0
117
118	# Add an ACL on `host2_if` which will tell us whether the packet
119	# was received by it or not.
120	tc qdisc add dev $host2_if ingress
121	tc filter add dev $host2_if ingress protocol ip pref 1 handle 101 \
122		flower ip_proto udp dst_mac $mac action drop
123
124	$MZ $host1_if -c 1 -p 64 -b $mac -A $src_ip -B $ip -t udp "dp=4096,sp=2048" -q
125	sleep 1
126
127	tc -j -s filter show dev $host2_if ingress \
128		| jq -e ".[] | select(.options.handle == 101) \
129		| select(.options.actions[0].stats.packets == 1)" &> /dev/null
130	if [[ $? -eq 0 ]]; then
131		seen=1
132	fi
133
134	tc filter del dev $host2_if ingress protocol ip pref 1 handle 101 flower
135	tc qdisc del dev $host2_if ingress
136
137	return $seen
138}
139
140v2reportleave_test()
141{
142	RET=0
143	ip address add dev $h2 $TEST_GROUP/32 autojoin
144	check_err $? "Could not join $TEST_GROUP"
145
146	sleep 5
147	bridge mdb show dev br0 | grep $TEST_GROUP 1>/dev/null
148	check_err $? "IGMPv2 report didn't create mdb entry for $TEST_GROUP"
149
150	mcast_packet_test $TEST_GROUP_MAC 192.0.2.1 $TEST_GROUP $h1 $h2
151	check_fail $? "Traffic to $TEST_GROUP wasn't forwarded"
152
153	log_test "IGMPv2 report $TEST_GROUP"
154
155	RET=0
156	bridge mdb show dev br0 | grep $TEST_GROUP 1>/dev/null
157	check_err $? "mdb entry for $TEST_GROUP is missing"
158
159	ip address del dev $h2 $TEST_GROUP/32
160	check_err $? "Could not leave $TEST_GROUP"
161
162	sleep 5
163	bridge mdb show dev br0 | grep $TEST_GROUP 1>/dev/null
164	check_fail $? "Leave didn't delete mdb entry for $TEST_GROUP"
165
166	mcast_packet_test $TEST_GROUP_MAC 192.0.2.1 $TEST_GROUP $h1 $h2
167	check_err $? "Traffic to $TEST_GROUP was forwarded without mdb entry"
168
169	log_test "IGMPv2 leave $TEST_GROUP"
170}
171
172check_sg_entries()
173{
174	local report=$1; shift
175	local slist=("$@")
176	local sarg=""
177
178	for src in "${slist[@]}"; do
179		sarg="${sarg} and .source_list[].address == \"$src\""
180	done
181	bridge -j -d -s mdb show dev br0 \
182		| jq -e ".[].mdb[] | \
183			 select(.grp == \"$TEST_GROUP\" and .source_list != null $sarg)" &>/dev/null
184	check_err $? "Wrong *,G entry source list after $report report"
185
186	for sgent in "${slist[@]}"; do
187		bridge -j -d -s mdb show dev br0 \
188			| jq -e ".[].mdb[] | \
189				 select(.grp == \"$TEST_GROUP\" and .src == \"$sgent\")" &>/dev/null
190		check_err $? "Missing S,G entry ($sgent, $TEST_GROUP)"
191	done
192}
193
194check_sg_fwding()
195{
196	local should_fwd=$1; shift
197	local sources=("$@")
198
199	for src in "${sources[@]}"; do
200		local retval=0
201
202		mcast_packet_test $TEST_GROUP_MAC $src $TEST_GROUP $h2 $h1
203		retval=$?
204		if [ $should_fwd -eq 1 ]; then
205			check_fail $retval "Didn't forward traffic from S,G ($src, $TEST_GROUP)"
206		else
207			check_err $retval "Forwarded traffic for blocked S,G ($src, $TEST_GROUP)"
208		fi
209	done
210}
211
212check_sg_state()
213{
214	local is_blocked=$1; shift
215	local sources=("$@")
216	local should_fail=1
217
218	if [ $is_blocked -eq 1 ]; then
219		should_fail=0
220	fi
221
222	for src in "${sources[@]}"; do
223		bridge -j -d -s mdb show dev br0 \
224			| jq -e ".[].mdb[] | \
225				 select(.grp == \"$TEST_GROUP\" and .source_list != null) |
226				 .source_list[] |
227				 select(.address == \"$src\") |
228				 select(.timer == \"0.00\")" &>/dev/null
229		check_err_fail $should_fail $? "Entry $src has zero timer"
230
231		bridge -j -d -s mdb show dev br0 \
232			| jq -e ".[].mdb[] | \
233				 select(.grp == \"$TEST_GROUP\" and .src == \"$src\" and \
234				 .flags[] == \"blocked\")" &>/dev/null
235		check_err_fail $should_fail $? "Entry $src has blocked flag"
236	done
237}
238
239v3include_prepare()
240{
241	local host1_if=$1
242	local mac=$2
243	local group=$3
244	local X=("192.0.2.1" "192.0.2.2" "192.0.2.3")
245
246	ip link set dev br0 type bridge mcast_igmp_version 3
247	check_err $? "Could not change bridge IGMP version to 3"
248
249	$MZ $host1_if -b $mac -c 1 -B $group -t ip "proto=2,p=$MZPKT_IS_INC" -q
250	sleep 1
251	bridge -j -d -s mdb show dev br0 \
252		| jq -e ".[].mdb[] | \
253			 select(.grp == \"$TEST_GROUP\" and .source_list != null)" &>/dev/null
254	check_err $? "Missing *,G entry with source list"
255	bridge -j -d -s mdb show dev br0 \
256		| jq -e ".[].mdb[] | \
257			 select(.grp == \"$TEST_GROUP\" and \
258				.source_list != null and .filter_mode == \"include\")" &>/dev/null
259	check_err $? "Wrong *,G entry filter mode"
260	check_sg_entries "is_include" "${X[@]}"
261}
262
263v3exclude_prepare()
264{
265	local host1_if=$1
266	local mac=$2
267	local group=$3
268	local pkt=$4
269	local X=("192.0.2.1" "192.0.2.2")
270	local Y=("192.0.2.20" "192.0.2.21")
271
272	v3include_prepare $host1_if $mac $group
273
274	$MZ $host1_if -c 1 -b $mac -B $group -t ip "proto=2,p=$MZPKT_IS_EXC" -q
275	sleep 1
276	bridge -j -d -s mdb show dev br0 \
277		| jq -e ".[].mdb[] | \
278			 select(.grp == \"$TEST_GROUP\" and \
279				.source_list != null and .filter_mode == \"exclude\")" &>/dev/null
280	check_err $? "Wrong *,G entry filter mode"
281
282	check_sg_entries "is_exclude" "${X[@]}" "${Y[@]}"
283
284	check_sg_state 0 "${X[@]}"
285	check_sg_state 1 "${Y[@]}"
286
287	bridge -j -d -s mdb show dev br0 \
288		| jq -e ".[].mdb[] | \
289			 select(.grp == \"$TEST_GROUP\" and \
290				.source_list != null and
291				.source_list[].address == \"192.0.2.3\")" &>/dev/null
292	check_fail $? "Wrong *,G entry source list, 192.0.2.3 entry still exists"
293}
294
295v3cleanup()
296{
297	local port=$1
298	local group=$2
299
300	bridge mdb del dev br0 port $port grp $group
301	ip link set dev br0 type bridge mcast_igmp_version 2
302}
303
304v3include_test()
305{
306	RET=0
307	local X=("192.0.2.1" "192.0.2.2" "192.0.2.3")
308
309	v3include_prepare $h1 $ALL_MAC $ALL_GROUP
310
311	check_sg_state 0 "${X[@]}"
312
313	check_sg_fwding 1 "${X[@]}"
314	check_sg_fwding 0 "192.0.2.100"
315
316	log_test "IGMPv3 report $TEST_GROUP is_include"
317
318	v3cleanup $swp1 $TEST_GROUP
319}
320
321v3inc_allow_test()
322{
323	RET=0
324	local X=("192.0.2.10" "192.0.2.11" "192.0.2.12")
325
326	v3include_prepare $h1 $ALL_MAC $ALL_GROUP
327
328	$MZ $h1 -c 1 -b $ALL_MAC -B $ALL_GROUP -t ip "proto=2,p=$MZPKT_ALLOW" -q
329	sleep 1
330	check_sg_entries "allow" "${X[@]}"
331
332	check_sg_state 0 "${X[@]}"
333
334	check_sg_fwding 1 "${X[@]}"
335	check_sg_fwding 0 "192.0.2.100"
336
337	log_test "IGMPv3 report $TEST_GROUP include -> allow"
338
339	v3cleanup $swp1 $TEST_GROUP
340}
341
342v3inc_is_include_test()
343{
344	RET=0
345	local X=("192.0.2.10" "192.0.2.11" "192.0.2.12")
346
347	v3include_prepare $h1 $ALL_MAC $ALL_GROUP
348
349	$MZ $h1 -c 1 -b $ALL_MAC -B $ALL_GROUP -t ip "proto=2,p=$MZPKT_IS_INC2" -q
350	sleep 1
351	check_sg_entries "is_include" "${X[@]}"
352
353	check_sg_state 0 "${X[@]}"
354
355	check_sg_fwding 1 "${X[@]}"
356	check_sg_fwding 0 "192.0.2.100"
357
358	log_test "IGMPv3 report $TEST_GROUP include -> is_include"
359
360	v3cleanup $swp1 $TEST_GROUP
361}
362
363v3inc_is_exclude_test()
364{
365	RET=0
366
367	v3exclude_prepare $h1 $ALL_MAC $ALL_GROUP
368
369	check_sg_fwding 1 "${X[@]}" 192.0.2.100
370	check_sg_fwding 0 "${Y[@]}"
371
372	log_test "IGMPv3 report $TEST_GROUP include -> is_exclude"
373
374	v3cleanup $swp1 $TEST_GROUP
375}
376
377v3inc_to_exclude_test()
378{
379	RET=0
380	local X=("192.0.2.1")
381	local Y=("192.0.2.20" "192.0.2.30")
382
383	v3include_prepare $h1 $ALL_MAC $ALL_GROUP
384
385	ip link set dev br0 type bridge mcast_last_member_interval 500
386	check_err $? "Could not change mcast_last_member_interval to 5s"
387
388	$MZ $h1 -c 1 -b $ALL_MAC -B $ALL_GROUP -t ip "proto=2,p=$MZPKT_TO_EXC" -q
389	sleep 1
390	bridge -j -d -s mdb show dev br0 \
391		| jq -e ".[].mdb[] | \
392			 select(.grp == \"$TEST_GROUP\" and \
393				.source_list != null and .filter_mode == \"exclude\")" &>/dev/null
394	check_err $? "Wrong *,G entry filter mode"
395
396	check_sg_entries "to_exclude" "${X[@]}" "${Y[@]}"
397
398	check_sg_state 0 "${X[@]}"
399	check_sg_state 1 "${Y[@]}"
400
401	bridge -j -d -s mdb show dev br0 \
402		| jq -e ".[].mdb[] | \
403			 select(.grp == \"$TEST_GROUP\" and \
404				.source_list != null and
405				.source_list[].address == \"192.0.2.2\")" &>/dev/null
406	check_fail $? "Wrong *,G entry source list, 192.0.2.2 entry still exists"
407	bridge -j -d -s mdb show dev br0 \
408		| jq -e ".[].mdb[] | \
409			 select(.grp == \"$TEST_GROUP\" and \
410				.source_list != null and
411				.source_list[].address == \"192.0.2.21\")" &>/dev/null
412	check_fail $? "Wrong *,G entry source list, 192.0.2.21 entry still exists"
413
414	check_sg_fwding 1 "${X[@]}" 192.0.2.100
415	check_sg_fwding 0 "${Y[@]}"
416
417	log_test "IGMPv3 report $TEST_GROUP include -> to_exclude"
418
419	ip link set dev br0 type bridge mcast_last_member_interval 100
420
421	v3cleanup $swp1 $TEST_GROUP
422}
423
424v3exc_allow_test()
425{
426	RET=0
427	local X=("192.0.2.1" "192.0.2.2" "192.0.2.20" "192.0.2.30")
428	local Y=("192.0.2.21")
429
430	v3exclude_prepare $h1 $ALL_MAC $ALL_GROUP
431
432	$MZ $h1 -c 1 -b $ALL_MAC -B $ALL_GROUP -t ip "proto=2,p=$MZPKT_ALLOW2" -q
433	sleep 1
434	check_sg_entries "allow" "${X[@]}" "${Y[@]}"
435
436	check_sg_state 0 "${X[@]}"
437	check_sg_state 1 "${Y[@]}"
438
439	check_sg_fwding 1 "${X[@]}" 192.0.2.100
440	check_sg_fwding 0 "${Y[@]}"
441
442	log_test "IGMPv3 report $TEST_GROUP exclude -> allow"
443
444	v3cleanup $swp1 $TEST_GROUP
445}
446
447v3exc_is_include_test()
448{
449	RET=0
450	local X=("192.0.2.1" "192.0.2.2" "192.0.2.20" "192.0.2.30")
451	local Y=("192.0.2.21")
452
453	v3exclude_prepare $h1 $ALL_MAC $ALL_GROUP
454
455	$MZ $h1 -c 1 -b $ALL_MAC -B $ALL_GROUP -t ip "proto=2,p=$MZPKT_IS_INC3" -q
456	sleep 1
457	check_sg_entries "is_include" "${X[@]}" "${Y[@]}"
458
459	check_sg_state 0 "${X[@]}"
460	check_sg_state 1 "${Y[@]}"
461
462	check_sg_fwding 1 "${X[@]}" 192.0.2.100
463	check_sg_fwding 0 "${Y[@]}"
464
465	log_test "IGMPv3 report $TEST_GROUP exclude -> is_include"
466
467	v3cleanup $swp1 $TEST_GROUP
468}
469
470v3exc_is_exclude_test()
471{
472	RET=0
473	local X=("192.0.2.30")
474	local Y=("192.0.2.20")
475
476	v3exclude_prepare $h1 $ALL_MAC $ALL_GROUP
477
478	$MZ $h1 -c 1 -b $ALL_MAC -B $ALL_GROUP -t ip "proto=2,p=$MZPKT_IS_EXC2" -q
479	sleep 1
480	check_sg_entries "is_exclude" "${X[@]}" "${Y[@]}"
481
482	check_sg_state 0 "${X[@]}"
483	check_sg_state 1 "${Y[@]}"
484
485	check_sg_fwding 1 "${X[@]}" 192.0.2.100
486	check_sg_fwding 0 "${Y[@]}"
487
488	log_test "IGMPv3 report $TEST_GROUP exclude -> is_exclude"
489
490	v3cleanup $swp1 $TEST_GROUP
491}
492
493v3exc_to_exclude_test()
494{
495	RET=0
496	local X=("192.0.2.1" "192.0.2.30")
497	local Y=("192.0.2.20")
498
499	v3exclude_prepare $h1 $ALL_MAC $ALL_GROUP
500
501	ip link set dev br0 type bridge mcast_last_member_interval 500
502	check_err $? "Could not change mcast_last_member_interval to 5s"
503
504	$MZ $h1 -c 1 -b $ALL_MAC -B $ALL_GROUP -t ip "proto=2,p=$MZPKT_TO_EXC" -q
505	sleep 1
506	check_sg_entries "to_exclude" "${X[@]}" "${Y[@]}"
507
508	check_sg_state 0 "${X[@]}"
509	check_sg_state 1 "${Y[@]}"
510
511	check_sg_fwding 1 "${X[@]}" 192.0.2.100
512	check_sg_fwding 0 "${Y[@]}"
513
514	log_test "IGMPv3 report $TEST_GROUP exclude -> to_exclude"
515
516	ip link set dev br0 type bridge mcast_last_member_interval 100
517
518	v3cleanup $swp1 $TEST_GROUP
519}
520
521v3inc_block_test()
522{
523	RET=0
524	local X=("192.0.2.2" "192.0.2.3")
525
526	v3include_prepare $h1 $ALL_MAC $ALL_GROUP
527
528	$MZ $h1 -c 1 -b $ALL_MAC -B $ALL_GROUP -t ip "proto=2,p=$MZPKT_BLOCK" -q
529	# make sure the lowered timers have expired (by default 2 seconds)
530	sleep 3
531	check_sg_entries "block" "${X[@]}"
532
533	check_sg_state 0 "${X[@]}"
534
535	bridge -j -d -s mdb show dev br0 \
536		| jq -e ".[].mdb[] | \
537			 select(.grp == \"$TEST_GROUP\" and \
538				.source_list != null and
539				.source_list[].address == \"192.0.2.1\")" &>/dev/null
540	check_fail $? "Wrong *,G entry source list, 192.0.2.1 entry still exists"
541
542	check_sg_fwding 1 "${X[@]}"
543	check_sg_fwding 0 "192.0.2.100"
544
545	log_test "IGMPv3 report $TEST_GROUP include -> block"
546
547	v3cleanup $swp1 $TEST_GROUP
548}
549
550v3exc_block_test()
551{
552	RET=0
553	local X=("192.0.2.1" "192.0.2.2" "192.0.2.30")
554	local Y=("192.0.2.20" "192.0.2.21")
555
556	v3exclude_prepare $h1 $ALL_MAC $ALL_GROUP
557
558	ip link set dev br0 type bridge mcast_last_member_interval 500
559	check_err $? "Could not change mcast_last_member_interval to 5s"
560
561	$MZ $h1 -c 1 -b $ALL_MAC -B $ALL_GROUP -t ip "proto=2,p=$MZPKT_BLOCK" -q
562	sleep 1
563	check_sg_entries "block" "${X[@]}" "${Y[@]}"
564
565	check_sg_state 0 "${X[@]}"
566	check_sg_state 1 "${Y[@]}"
567
568	check_sg_fwding 1 "${X[@]}" 192.0.2.100
569	check_sg_fwding 0 "${Y[@]}"
570
571	log_test "IGMPv3 report $TEST_GROUP exclude -> block"
572
573	ip link set dev br0 type bridge mcast_last_member_interval 100
574
575	v3cleanup $swp1 $TEST_GROUP
576}
577
578v3exc_timeout_test()
579{
580	RET=0
581	local X=("192.0.2.20" "192.0.2.30")
582
583	# GMI should be 3 seconds
584	ip link set dev br0 type bridge mcast_query_interval 100 mcast_query_response_interval 100
585
586	v3exclude_prepare $h1 $ALL_MAC $ALL_GROUP
587	ip link set dev br0 type bridge mcast_query_interval 500 mcast_query_response_interval 500
588	$MZ $h1 -c 1 -b $ALL_MAC -B $ALL_GROUP -t ip "proto=2,p=$MZPKT_ALLOW2" -q
589	sleep 3
590	bridge -j -d -s mdb show dev br0 \
591		| jq -e ".[].mdb[] | \
592			 select(.grp == \"$TEST_GROUP\" and \
593				.source_list != null and .filter_mode == \"include\")" &>/dev/null
594	check_err $? "Wrong *,G entry filter mode"
595
596	bridge -j -d -s mdb show dev br0 \
597		| jq -e ".[].mdb[] | \
598			 select(.grp == \"$TEST_GROUP\" and \
599				.source_list != null and
600				.source_list[].address == \"192.0.2.1\")" &>/dev/null
601	check_fail $? "Wrong *,G entry source list, 192.0.2.1 entry still exists"
602	bridge -j -d -s mdb show dev br0 \
603		| jq -e ".[].mdb[] | \
604			 select(.grp == \"$TEST_GROUP\" and \
605				.source_list != null and
606				.source_list[].address == \"192.0.2.2\")" &>/dev/null
607	check_fail $? "Wrong *,G entry source list, 192.0.2.2 entry still exists"
608
609	check_sg_entries "allow" "${X[@]}"
610
611	check_sg_state 0 "${X[@]}"
612
613	check_sg_fwding 1 "${X[@]}"
614	check_sg_fwding 0 192.0.2.100
615
616	log_test "IGMPv3 group $TEST_GROUP exclude timeout"
617
618	ip link set dev br0 type bridge mcast_query_interval 12500 \
619					mcast_query_response_interval 1000
620
621	v3cleanup $swp1 $TEST_GROUP
622}
623
624v3star_ex_auto_add_test()
625{
626	RET=0
627
628	v3exclude_prepare $h1 $ALL_MAC $ALL_GROUP
629
630	$MZ $h2 -c 1 -b $ALL_MAC -B $ALL_GROUP -t ip "proto=2,p=$MZPKT_IS_INC" -q
631	sleep 1
632	bridge -j -d -s mdb show dev br0 \
633		| jq -e ".[].mdb[] | \
634			 select(.grp == \"$TEST_GROUP\" and .src == \"192.0.2.3\" and \
635				.port == \"$swp1\")" &>/dev/null
636	check_err $? "S,G entry for *,G port doesn't exist"
637
638	bridge -j -d -s mdb show dev br0 \
639		| jq -e ".[].mdb[] | \
640			 select(.grp == \"$TEST_GROUP\" and .src == \"192.0.2.3\" and \
641				.port == \"$swp1\" and \
642				.flags[] == \"added_by_star_ex\")" &>/dev/null
643	check_err $? "Auto-added S,G entry doesn't have added_by_star_ex flag"
644
645	check_sg_fwding 1 192.0.2.3
646
647	log_test "IGMPv3 S,G port entry automatic add to a *,G port"
648
649	v3cleanup $swp1 $TEST_GROUP
650	v3cleanup $swp2 $TEST_GROUP
651}
652
653trap cleanup EXIT
654
655setup_prepare
656setup_wait
657
658tests_run
659
660exit $EXIT_STATUS
661