1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4# +-----------------------+                          +------------------------+
5# | H1 (vrf)              |                          | H2 (vrf)               |
6# | + $h1.10              |                          | + $h2.10               |
7# | | 192.0.2.1/28        |                          | | 192.0.2.2/28         |
8# | | 2001:db8:1::1/64    |                          | | 2001:db8:1::2/64     |
9# | |                     |                          | |                      |
10# | |  + $h1.20           |                          | |  + $h2.20            |
11# | \  | 198.51.100.1/24  |                          | \  | 198.51.100.2/24   |
12# |  \ | 2001:db8:2::1/64 |                          |  \ | 2001:db8:2::2/64  |
13# |   \|                  |                          |   \|                   |
14# |    + $h1              |                          |    + $h2               |
15# +----|------------------+                          +----|-------------------+
16#      |                                                  |
17# +----|--------------------------------------------------|-------------------+
18# | SW |                                                  |                   |
19# | +--|--------------------------------------------------|-----------------+ |
20# | |  + $swp1                   BR0 (802.1q)             + $swp2           | |
21# | |     vid 10                                             vid 10         | |
22# | |     vid 20                                             vid 20         | |
23# | |                                                                       | |
24# | +-----------------------------------------------------------------------+ |
25# +---------------------------------------------------------------------------+
26
27ALL_TESTS="
28	cfg_test
29	fwd_test
30	ctrl_test
31"
32
33NUM_NETIFS=4
34source lib.sh
35source tc_common.sh
36
37h1_create()
38{
39	simple_if_init $h1
40	vlan_create $h1 10 v$h1 192.0.2.1/28 2001:db8:1::1/64
41	vlan_create $h1 20 v$h1 198.51.100.1/24 2001:db8:2::1/64
42}
43
44h1_destroy()
45{
46	vlan_destroy $h1 20
47	vlan_destroy $h1 10
48	simple_if_fini $h1
49}
50
51h2_create()
52{
53	simple_if_init $h2
54	vlan_create $h2 10 v$h2 192.0.2.2/28
55	vlan_create $h2 20 v$h2 198.51.100.2/24
56}
57
58h2_destroy()
59{
60	vlan_destroy $h2 20
61	vlan_destroy $h2 10
62	simple_if_fini $h2
63}
64
65switch_create()
66{
67	ip link add name br0 type bridge vlan_filtering 1 vlan_default_pvid 0 \
68		mcast_snooping 1 mcast_igmp_version 3 mcast_mld_version 2
69	bridge vlan add vid 10 dev br0 self
70	bridge vlan add vid 20 dev br0 self
71	ip link set dev br0 up
72
73	ip link set dev $swp1 master br0
74	ip link set dev $swp1 up
75	bridge vlan add vid 10 dev $swp1
76	bridge vlan add vid 20 dev $swp1
77
78	ip link set dev $swp2 master br0
79	ip link set dev $swp2 up
80	bridge vlan add vid 10 dev $swp2
81	bridge vlan add vid 20 dev $swp2
82
83	tc qdisc add dev br0 clsact
84	tc qdisc add dev $h2 clsact
85}
86
87switch_destroy()
88{
89	tc qdisc del dev $h2 clsact
90	tc qdisc del dev br0 clsact
91
92	bridge vlan del vid 20 dev $swp2
93	bridge vlan del vid 10 dev $swp2
94	ip link set dev $swp2 down
95	ip link set dev $swp2 nomaster
96
97	bridge vlan del vid 20 dev $swp1
98	bridge vlan del vid 10 dev $swp1
99	ip link set dev $swp1 down
100	ip link set dev $swp1 nomaster
101
102	ip link set dev br0 down
103	bridge vlan del vid 20 dev br0 self
104	bridge vlan del vid 10 dev br0 self
105	ip link del dev br0
106}
107
108setup_prepare()
109{
110	h1=${NETIFS[p1]}
111	swp1=${NETIFS[p2]}
112
113	swp2=${NETIFS[p3]}
114	h2=${NETIFS[p4]}
115
116	vrf_prepare
117	forwarding_enable
118
119	h1_create
120	h2_create
121	switch_create
122}
123
124cleanup()
125{
126	pre_cleanup
127
128	switch_destroy
129	h2_destroy
130	h1_destroy
131
132	forwarding_restore
133	vrf_cleanup
134}
135
136cfg_test_host_common()
137{
138	local name=$1; shift
139	local grp=$1; shift
140	local src=$1; shift
141	local state=$1; shift
142	local invalid_state=$1; shift
143
144	RET=0
145
146	# Check basic add, replace and delete behavior.
147	bridge mdb add dev br0 port br0 grp $grp $state vid 10
148	bridge mdb show dev br0 vid 10 | grep -q "$grp"
149	check_err $? "Failed to add $name host entry"
150
151	bridge mdb replace dev br0 port br0 grp $grp $state vid 10 &> /dev/null
152	check_fail $? "Managed to replace $name host entry"
153
154	bridge mdb del dev br0 port br0 grp $grp $state vid 10
155	bridge mdb show dev br0 vid 10 | grep -q "$grp"
156	check_fail $? "Failed to delete $name host entry"
157
158	# Check error cases.
159	bridge mdb add dev br0 port br0 grp $grp $invalid_state vid 10 \
160		&> /dev/null
161	check_fail $? "Managed to add $name host entry with a $invalid_state state"
162
163	bridge mdb add dev br0 port br0 grp $grp src $src $state vid 10 \
164		&> /dev/null
165	check_fail $? "Managed to add $name host entry with a source"
166
167	bridge mdb add dev br0 port br0 grp $grp $state vid 10 \
168		filter_mode exclude &> /dev/null
169	check_fail $? "Managed to add $name host entry with a filter mode"
170
171	bridge mdb add dev br0 port br0 grp $grp $state vid 10 \
172		source_list $src &> /dev/null
173	check_fail $? "Managed to add $name host entry with a source list"
174
175	bridge mdb add dev br0 port br0 grp $grp $state vid 10 \
176		proto 123 &> /dev/null
177	check_fail $? "Managed to add $name host entry with a protocol"
178
179	log_test "Common host entries configuration tests ($name)"
180}
181
182# Check configuration of host entries from all types.
183cfg_test_host()
184{
185	echo
186	log_info "# Host entries configuration tests"
187
188	cfg_test_host_common "IPv4" "239.1.1.1" "192.0.2.1" "temp" "permanent"
189	cfg_test_host_common "IPv6" "ff0e::1" "2001:db8:1::1" "temp" "permanent"
190	cfg_test_host_common "L2" "01:02:03:04:05:06" "00:00:00:00:00:01" \
191		"permanent" "temp"
192}
193
194cfg_test_port_common()
195{
196	local name=$1;shift
197	local grp_key=$1; shift
198
199	RET=0
200
201	# Check basic add, replace and delete behavior.
202	bridge mdb add dev br0 port $swp1 $grp_key permanent vid 10
203	bridge mdb show dev br0 vid 10 | grep -q "$grp_key"
204	check_err $? "Failed to add $name entry"
205
206	bridge mdb replace dev br0 port $swp1 $grp_key permanent vid 10 \
207		&> /dev/null
208	check_err $? "Failed to replace $name entry"
209
210	bridge mdb del dev br0 port $swp1 $grp_key permanent vid 10
211	bridge mdb show dev br0 vid 10 | grep -q "$grp_key"
212	check_fail $? "Failed to delete $name entry"
213
214	# Check default protocol and replacement.
215	bridge mdb add dev br0 port $swp1 $grp_key permanent vid 10
216	bridge -d mdb show dev br0 vid 10 | grep "$grp_key" | grep -q "static"
217	check_err $? "$name entry not added with default \"static\" protocol"
218
219	bridge mdb replace dev br0 port $swp1 $grp_key permanent vid 10 \
220		proto 123
221	bridge -d mdb show dev br0 vid 10 | grep "$grp_key" | grep -q "123"
222	check_err $? "Failed to replace protocol of $name entry"
223	bridge mdb del dev br0 port $swp1 $grp_key permanent vid 10
224
225	# Check behavior when VLAN is not specified.
226	bridge mdb add dev br0 port $swp1 $grp_key permanent
227	bridge mdb show dev br0 vid 10 | grep -q "$grp_key"
228	check_err $? "$name entry with VLAN 10 not added when VLAN was not specified"
229	bridge mdb show dev br0 vid 20 | grep -q "$grp_key"
230	check_err $? "$name entry with VLAN 20 not added when VLAN was not specified"
231
232	bridge mdb del dev br0 port $swp1 $grp_key permanent
233	bridge mdb show dev br0 vid 10 | grep -q "$grp_key"
234	check_fail $? "$name entry with VLAN 10 not deleted when VLAN was not specified"
235	bridge mdb show dev br0 vid 20 | grep -q "$grp_key"
236	check_fail $? "$name entry with VLAN 20 not deleted when VLAN was not specified"
237
238	# Check behavior when bridge port is down.
239	ip link set dev $swp1 down
240
241	bridge mdb add dev br0 port $swp1 $grp_key permanent vid 10
242	check_err $? "Failed to add $name permanent entry when bridge port is down"
243
244	bridge mdb del dev br0 port $swp1 $grp_key permanent vid 10
245
246	bridge mdb add dev br0 port $swp1 $grp_key temp vid 10 &> /dev/null
247	check_fail $? "Managed to add $name temporary entry when bridge port is down"
248
249	ip link set dev $swp1 up
250	setup_wait_dev $swp1
251
252	# Check error cases.
253	ip link set dev br0 down
254	bridge mdb add dev br0 port $swp1 $grp_key permanent vid 10 \
255		&> /dev/null
256	check_fail $? "Managed to add $name entry when bridge is down"
257	ip link set dev br0 up
258
259	ip link set dev br0 type bridge mcast_snooping 0
260	bridge mdb add dev br0 port $swp1 $grp_key permanent vid \
261		10 &> /dev/null
262	check_fail $? "Managed to add $name entry when multicast snooping is disabled"
263	ip link set dev br0 type bridge mcast_snooping 1
264
265	bridge mdb add dev br0 port $swp1 $grp_key permanent vid 5000 \
266		&> /dev/null
267	check_fail $? "Managed to add $name entry with an invalid VLAN"
268
269	log_test "Common port group entries configuration tests ($name)"
270}
271
272src_list_create()
273{
274	local src_prefix=$1; shift
275	local num_srcs=$1; shift
276	local src_list
277	local i
278
279	for i in $(seq 1 $num_srcs); do
280		src_list=${src_list},${src_prefix}${i}
281	done
282
283	echo $src_list | cut -c 2-
284}
285
286__cfg_test_port_ip_star_g()
287{
288	local name=$1; shift
289	local grp=$1; shift
290	local invalid_grp=$1; shift
291	local src_prefix=$1; shift
292	local src1=${src_prefix}1
293	local src2=${src_prefix}2
294	local src3=${src_prefix}3
295	local max_srcs=31
296	local num_srcs
297
298	RET=0
299
300	bridge mdb add dev br0 port $swp1 grp $grp vid 10
301	bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep -q "exclude"
302	check_err $? "Default filter mode is not \"exclude\""
303	bridge mdb del dev br0 port $swp1 grp $grp vid 10
304
305	# Check basic add and delete behavior.
306	bridge mdb add dev br0 port $swp1 grp $grp vid 10 filter_mode exclude \
307		source_list $src1
308	bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep -q -v "src"
309	check_err $? "(*, G) entry not created"
310	bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep -q "src $src1"
311	check_err $? "(S, G) entry not created"
312	bridge mdb del dev br0 port $swp1 grp $grp vid 10
313	bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep -q -v "src"
314	check_fail $? "(*, G) entry not deleted"
315	bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep -q "src $src1"
316	check_fail $? "(S, G) entry not deleted"
317
318	## State (permanent / temp) tests.
319
320	# Check that group and source timer are not set for permanent entries.
321	bridge mdb add dev br0 port $swp1 grp $grp permanent vid 10 \
322		filter_mode exclude source_list $src1
323
324	bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep -v "src" | \
325		grep -q "permanent"
326	check_err $? "(*, G) entry not added as \"permanent\" when should"
327	bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep "src" | \
328		grep -q "permanent"
329	check_err $? "(S, G) entry not added as \"permanent\" when should"
330
331	bridge -d -s mdb show dev br0 vid 10 | grep "$grp" | grep -v "src" | \
332		grep -q " 0.00"
333	check_err $? "(*, G) \"permanent\" entry has a pending group timer"
334	bridge -d -s mdb show dev br0 vid 10 | grep "$grp" | grep -v "src" | \
335		grep -q "\/0.00"
336	check_err $? "\"permanent\" source entry has a pending source timer"
337
338	bridge mdb del dev br0 port $swp1 grp $grp vid 10
339
340	# Check that group timer is set for temporary (*, G) EXCLUDE, but not
341	# the source timer.
342	bridge mdb add dev br0 port $swp1 grp $grp temp vid 10 \
343		filter_mode exclude source_list $src1
344
345	bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep -v "src" | \
346		grep -q "temp"
347	check_err $? "(*, G) EXCLUDE entry not added as \"temp\" when should"
348	bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep "src" | \
349		grep -q "temp"
350	check_err $? "(S, G) \"blocked\" entry not added as \"temp\" when should"
351
352	bridge -d -s mdb show dev br0 vid 10 | grep "$grp" | grep -v "src" | \
353		grep -q " 0.00"
354	check_fail $? "(*, G) EXCLUDE entry does not have a pending group timer"
355	bridge -d -s mdb show dev br0 vid 10 | grep "$grp" | grep -v "src" | \
356		grep -q "\/0.00"
357	check_err $? "\"blocked\" source entry has a pending source timer"
358
359	bridge mdb del dev br0 port $swp1 grp $grp vid 10
360
361	# Check that group timer is not set for temporary (*, G) INCLUDE, but
362	# that the source timer is set.
363	bridge mdb add dev br0 port $swp1 grp $grp temp vid 10 \
364		filter_mode include source_list $src1
365
366	bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep -v "src" | \
367		grep -q "temp"
368	check_err $? "(*, G) INCLUDE entry not added as \"temp\" when should"
369	bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep "src" | \
370		grep -q "temp"
371	check_err $? "(S, G) entry not added as \"temp\" when should"
372
373	bridge -d -s mdb show dev br0 vid 10 | grep "$grp" | grep -v "src" | \
374		grep -q " 0.00"
375	check_err $? "(*, G) INCLUDE entry has a pending group timer"
376	bridge -d -s mdb show dev br0 vid 10 | grep "$grp" | grep -v "src" | \
377		grep -q "\/0.00"
378	check_fail $? "Source entry does not have a pending source timer"
379
380	bridge mdb del dev br0 port $swp1 grp $grp vid 10
381
382	# Check that group timer is never set for (S, G) entries.
383	bridge mdb add dev br0 port $swp1 grp $grp temp vid 10 \
384		filter_mode include source_list $src1
385
386	bridge -d -s mdb show dev br0 vid 10 | grep "$grp" | grep "src" | \
387		grep -q " 0.00"
388	check_err $? "(S, G) entry has a pending group timer"
389
390	bridge mdb del dev br0 port $swp1 grp $grp vid 10
391
392	## Filter mode (include / exclude) tests.
393
394	# Check that (*, G) INCLUDE entries are added with correct filter mode
395	# and that (S, G) entries are not marked as "blocked".
396	bridge mdb add dev br0 port $swp1 grp $grp vid 10 \
397		filter_mode include source_list $src1
398
399	bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep -v "src" | \
400		grep -q "include"
401	check_err $? "(*, G) INCLUDE not added with \"include\" filter mode"
402	bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep "src" | \
403		grep -q "blocked"
404	check_fail $? "(S, G) entry marked as \"blocked\" when should not"
405
406	bridge mdb del dev br0 port $swp1 grp $grp vid 10
407
408	# Check that (*, G) EXCLUDE entries are added with correct filter mode
409	# and that (S, G) entries are marked as "blocked".
410	bridge mdb add dev br0 port $swp1 grp $grp vid 10 \
411		filter_mode exclude source_list $src1
412
413	bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep -v "src" | \
414		grep -q "exclude"
415	check_err $? "(*, G) EXCLUDE not added with \"exclude\" filter mode"
416	bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep "src" | \
417		grep -q "blocked"
418	check_err $? "(S, G) entry not marked as \"blocked\" when should"
419
420	bridge mdb del dev br0 port $swp1 grp $grp vid 10
421
422	## Protocol tests.
423
424	# Check that (*, G) and (S, G) entries are added with the specified
425	# protocol.
426	bridge mdb add dev br0 port $swp1 grp $grp vid 10 \
427		filter_mode exclude source_list $src1 proto zebra
428
429	bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep -v "src" | \
430		grep -q "zebra"
431	check_err $? "(*, G) entry not added with \"zebra\" protocol"
432	bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep "src" | \
433		grep -q "zebra"
434	check_err $? "(S, G) entry not marked added with \"zebra\" protocol"
435
436	bridge mdb del dev br0 port $swp1 grp $grp vid 10
437
438	## Replace tests.
439
440	# Check that state can be modified.
441	bridge mdb add dev br0 port $swp1 grp $grp temp vid 10 \
442		filter_mode exclude source_list $src1
443
444	bridge mdb replace dev br0 port $swp1 grp $grp permanent vid 10 \
445		filter_mode exclude source_list $src1
446	bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep -v "src" | \
447		grep -q "permanent"
448	check_err $? "(*, G) entry not marked as \"permanent\" after replace"
449	bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep "src" | \
450		grep -q "permanent"
451	check_err $? "(S, G) entry not marked as \"permanent\" after replace"
452
453	bridge mdb replace dev br0 port $swp1 grp $grp temp vid 10 \
454		filter_mode exclude source_list $src1
455	bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep -v "src" | \
456		grep -q "temp"
457	check_err $? "(*, G) entry not marked as \"temp\" after replace"
458	bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep "src" | \
459		grep -q "temp"
460	check_err $? "(S, G) entry not marked as \"temp\" after replace"
461
462	bridge mdb del dev br0 port $swp1 grp $grp vid 10
463
464	# Check that filter mode can be modified.
465	bridge mdb add dev br0 port $swp1 grp $grp temp vid 10 \
466		filter_mode exclude source_list $src1
467
468	bridge mdb replace dev br0 port $swp1 grp $grp temp vid 10 \
469		filter_mode include source_list $src1
470	bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep -v "src" | \
471		grep -q "include"
472	check_err $? "(*, G) not marked with \"include\" filter mode after replace"
473	bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep "src" | \
474		grep -q "blocked"
475	check_fail $? "(S, G) marked as \"blocked\" after replace"
476
477	bridge mdb replace dev br0 port $swp1 grp $grp temp vid 10 \
478		filter_mode exclude source_list $src1
479	bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep -v "src" | \
480		grep -q "exclude"
481	check_err $? "(*, G) not marked with \"exclude\" filter mode after replace"
482	bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep "src" | \
483		grep -q "blocked"
484	check_err $? "(S, G) not marked as \"blocked\" after replace"
485
486	bridge mdb del dev br0 port $swp1 grp $grp vid 10
487
488	# Check that sources can be added to and removed from the source list.
489	bridge mdb add dev br0 port $swp1 grp $grp temp vid 10 \
490		filter_mode exclude source_list $src1
491
492	bridge mdb replace dev br0 port $swp1 grp $grp temp vid 10 \
493		filter_mode exclude source_list $src1,$src2,$src3
494	bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep -q "src $src1"
495	check_err $? "(S, G) entry for source $src1 not created after replace"
496	bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep -q "src $src2"
497	check_err $? "(S, G) entry for source $src2 not created after replace"
498	bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep -q "src $src3"
499	check_err $? "(S, G) entry for source $src3 not created after replace"
500
501	bridge mdb replace dev br0 port $swp1 grp $grp temp vid 10 \
502		filter_mode exclude source_list $src1,$src3
503	bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep -q "src $src1"
504	check_err $? "(S, G) entry for source $src1 not created after second replace"
505	bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep -q "src $src2"
506	check_fail $? "(S, G) entry for source $src2 created after second replace"
507	bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep -q "src $src3"
508	check_err $? "(S, G) entry for source $src3 not created after second replace"
509
510	bridge mdb del dev br0 port $swp1 grp $grp vid 10
511
512	# Check that protocol can be modified.
513	bridge mdb add dev br0 port $swp1 grp $grp temp vid 10 \
514		filter_mode exclude source_list $src1 proto zebra
515
516	bridge mdb replace dev br0 port $swp1 grp $grp temp vid 10 \
517		filter_mode exclude source_list $src1 proto bgp
518	bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep -v "src" | \
519		grep -q "bgp"
520	check_err $? "(*, G) protocol not changed to \"bgp\" after replace"
521	bridge -d mdb show dev br0 vid 10 | grep "$grp" | grep "src" | \
522		grep -q "bgp"
523	check_err $? "(S, G) protocol not changed to \"bgp\" after replace"
524
525	bridge mdb del dev br0 port $swp1 grp $grp vid 10
526
527	## Star exclude tests.
528
529	# Check star exclude functionality. When adding a new EXCLUDE (*, G),
530	# it needs to be also added to all (S, G) entries for proper
531	# replication.
532	bridge mdb add dev br0 port $swp2 grp $grp vid 10 \
533		filter_mode include source_list $src1
534	bridge mdb add dev br0 port $swp1 grp $grp vid 10
535	bridge -d mdb show dev br0 vid 10 | grep "$swp1" | grep "$grp" | \
536		grep "$src1" | grep -q "added_by_star_ex"
537	check_err $? "\"added_by_star_ex\" entry not created after adding (*, G) entry"
538	bridge mdb del dev br0 port $swp1 grp $grp vid 10
539	bridge mdb del dev br0 port $swp2 grp $grp src $src1 vid 10
540
541	## Error cases tests.
542
543	bridge mdb add dev br0 port $swp1 grp $invalid_grp vid 10 &> /dev/null
544	check_fail $? "Managed to add an entry with an invalid group"
545
546	bridge mdb add dev br0 port $swp1 grp $grp vid 10 filter_mode include \
547		&> /dev/null
548	check_fail $? "Managed to add an INCLUDE entry with an empty source list"
549
550	bridge mdb add dev br0 port $swp1 grp $grp vid 10 filter_mode include \
551		source_list $grp &> /dev/null
552	check_fail $? "Managed to add an entry with an invalid source in source list"
553
554	bridge mdb add dev br0 port $swp1 grp $grp vid 10 \
555		source_list $src &> /dev/null
556	check_fail $? "Managed to add an entry with a source list and no filter mode"
557
558	bridge mdb add dev br0 port $swp1 grp $grp vid 10 filter_mode include \
559		source_list $src1
560	bridge mdb add dev br0 port $swp1 grp $grp vid 10 filter_mode exclude \
561		source_list $src1 &> /dev/null
562	check_fail $? "Managed to replace an entry without using replace"
563	bridge mdb del dev br0 port $swp1 grp $grp vid 10
564
565	bridge mdb add dev br0 port $swp1 grp $grp src $src2 vid 10
566	bridge mdb add dev br0 port $swp1 grp $grp vid 10 filter_mode include \
567		source_list $src1,$src2,$src3 &> /dev/null
568	check_fail $? "Managed to add a source that already has a forwarding entry"
569	bridge mdb del dev br0 port $swp1 grp $grp src $src2 vid 10
570
571	# Check maximum number of sources.
572	bridge mdb add dev br0 port $swp1 grp $grp vid 10 filter_mode exclude \
573		source_list $(src_list_create $src_prefix $max_srcs)
574	num_srcs=$(bridge -d mdb show dev br0 vid 10 | grep "$grp" | \
575		grep "src" | wc -l)
576	[[ $num_srcs -eq $max_srcs ]]
577	check_err $? "Failed to configure maximum number of sources ($max_srcs)"
578	bridge mdb del dev br0 port $swp1 grp $grp vid 10
579
580	bridge mdb add dev br0 port $swp1 grp $grp vid 10 filter_mode exclude \
581		source_list $(src_list_create $src_prefix $((max_srcs + 1))) \
582		&> /dev/null
583	check_fail $? "Managed to exceed maximum number of sources ($max_srcs)"
584
585	log_test "$name (*, G) port group entries configuration tests"
586}
587
588cfg_test_port_ip_star_g()
589{
590	echo
591	log_info "# Port group entries configuration tests - (*, G)"
592
593	cfg_test_port_common "IPv4 (*, G)" "grp 239.1.1.1"
594	cfg_test_port_common "IPv6 (*, G)" "grp ff0e::1"
595	__cfg_test_port_ip_star_g "IPv4" "239.1.1.1" "224.0.0.1" "192.0.2."
596	__cfg_test_port_ip_star_g "IPv6" "ff0e::1" "ff02::1" "2001:db8:1::"
597}
598
599__cfg_test_port_ip_sg()
600{
601	local name=$1; shift
602	local grp=$1; shift
603	local src=$1; shift
604	local grp_key="grp $grp src $src"
605
606	RET=0
607
608	bridge mdb add dev br0 port $swp1 $grp_key vid 10
609	bridge -d mdb show dev br0 vid 10 | grep "$grp_key" | grep -q "include"
610	check_err $? "Default filter mode is not \"include\""
611	bridge mdb del dev br0 port $swp1 $grp_key vid 10
612
613	# Check that entries can be added as both permanent and temp and that
614	# group timer is set correctly.
615	bridge mdb add dev br0 port $swp1 $grp_key permanent vid 10
616	bridge -d mdb show dev br0 vid 10 | grep "$grp_key" | \
617		grep -q "permanent"
618	check_err $? "Entry not added as \"permanent\" when should"
619	bridge -d -s mdb show dev br0 vid 10 | grep "$grp_key" | \
620		grep -q " 0.00"
621	check_err $? "\"permanent\" entry has a pending group timer"
622	bridge mdb del dev br0 port $swp1 $grp_key vid 10
623
624	bridge mdb add dev br0 port $swp1 $grp_key temp vid 10
625	bridge -d mdb show dev br0 vid 10 | grep "$grp_key" | \
626		grep -q "temp"
627	check_err $? "Entry not added as \"temp\" when should"
628	bridge -d -s mdb show dev br0 vid 10 | grep "$grp_key" | \
629		grep -q " 0.00"
630	check_fail $? "\"temp\" entry has an unpending group timer"
631	bridge mdb del dev br0 port $swp1 $grp_key vid 10
632
633	# Check error cases.
634	bridge mdb add dev br0 port $swp1 $grp_key vid 10 \
635		filter_mode include &> /dev/null
636	check_fail $? "Managed to add an entry with a filter mode"
637
638	bridge mdb add dev br0 port $swp1 $grp_key vid 10 \
639		filter_mode include source_list $src &> /dev/null
640	check_fail $? "Managed to add an entry with a source list"
641
642	bridge mdb add dev br0 port $swp1 grp $grp src $grp vid 10 &> /dev/null
643	check_fail $? "Managed to add an entry with an invalid source"
644
645	bridge mdb add dev br0 port $swp1 $grp_key vid 10 temp
646	bridge mdb add dev br0 port $swp1 $grp_key vid 10 permanent &> /dev/null
647	check_fail $? "Managed to replace an entry without using replace"
648	bridge mdb del dev br0 port $swp1 $grp_key vid 10
649
650	# Check that we can replace available attributes.
651	bridge mdb add dev br0 port $swp1 $grp_key vid 10 proto 123
652	bridge mdb replace dev br0 port $swp1 $grp_key vid 10 proto 111
653	bridge -d mdb show dev br0 vid 10 | grep "$grp_key" | \
654		grep -q "111"
655	check_err $? "Failed to replace protocol"
656
657	bridge mdb replace dev br0 port $swp1 $grp_key vid 10 permanent
658	bridge -d mdb show dev br0 vid 10 | grep "$grp_key" | \
659		grep -q "permanent"
660	check_err $? "Entry not marked as \"permanent\" after replace"
661	bridge -d -s mdb show dev br0 vid 10 | grep "$grp_key" | \
662		grep -q " 0.00"
663	check_err $? "Entry has a pending group timer after replace"
664
665	bridge mdb replace dev br0 port $swp1 $grp_key vid 10 temp
666	bridge -d mdb show dev br0 vid 10 | grep "$grp_key" | \
667		grep -q "temp"
668	check_err $? "Entry not marked as \"temp\" after replace"
669	bridge -d -s mdb show dev br0 vid 10 | grep "$grp_key" | \
670		grep -q " 0.00"
671	check_fail $? "Entry has an unpending group timer after replace"
672	bridge mdb del dev br0 port $swp1 $grp_key vid 10
673
674	# Check star exclude functionality. When adding a (S, G), all matching
675	# (*, G) ports need to be added to it.
676	bridge mdb add dev br0 port $swp2 grp $grp vid 10
677	bridge mdb add dev br0 port $swp1 $grp_key vid 10
678	bridge mdb show dev br0 vid 10 | grep "$grp_key" | grep $swp2 | \
679		grep -q "added_by_star_ex"
680	check_err $? "\"added_by_star_ex\" entry not created after adding (S, G) entry"
681	bridge mdb del dev br0 port $swp1 $grp_key vid 10
682	bridge mdb del dev br0 port $swp2 grp $grp vid 10
683
684	log_test "$name (S, G) port group entries configuration tests"
685}
686
687cfg_test_port_ip_sg()
688{
689	echo
690	log_info "# Port group entries configuration tests - (S, G)"
691
692	cfg_test_port_common "IPv4 (S, G)" "grp 239.1.1.1 src 192.0.2.1"
693	cfg_test_port_common "IPv6 (S, G)" "grp ff0e::1 src 2001:db8:1::1"
694	__cfg_test_port_ip_sg "IPv4" "239.1.1.1" "192.0.2.1"
695	__cfg_test_port_ip_sg "IPv6" "ff0e::1" "2001:db8:1::1"
696}
697
698cfg_test_port_ip()
699{
700	cfg_test_port_ip_star_g
701	cfg_test_port_ip_sg
702}
703
704__cfg_test_port_l2()
705{
706	local grp="01:02:03:04:05:06"
707
708	RET=0
709
710	bridge meb add dev br0 port $swp grp 00:01:02:03:04:05 \
711		permanent vid 10 &> /dev/null
712	check_fail $? "Managed to add an entry with unicast MAC"
713
714	bridge mdb add dev br0 port $swp grp $grp src 00:01:02:03:04:05 \
715		permanent vid 10 &> /dev/null
716	check_fail $? "Managed to add an entry with a source"
717
718	bridge mdb add dev br0 port $swp1 grp $grp permanent vid 10 \
719		filter_mode include &> /dev/null
720	check_fail $? "Managed to add an entry with a filter mode"
721
722	bridge mdb add dev br0 port $swp1 grp $grp permanent vid 10 \
723		source_list 00:01:02:03:04:05 &> /dev/null
724	check_fail $? "Managed to add an entry with a source list"
725
726	log_test "L2 (*, G) port group entries configuration tests"
727}
728
729cfg_test_port_l2()
730{
731	echo
732	log_info "# Port group entries configuration tests - L2"
733
734	cfg_test_port_common "L2 (*, G)" "grp 01:02:03:04:05:06"
735	__cfg_test_port_l2
736}
737
738# Check configuration of regular (port) entries of all types.
739cfg_test_port()
740{
741	cfg_test_port_ip
742	cfg_test_port_l2
743}
744
745ipv4_grps_get()
746{
747	local max_grps=$1; shift
748	local i
749
750	for i in $(seq 0 $((max_grps - 1))); do
751		echo "239.1.1.$i"
752	done
753}
754
755ipv6_grps_get()
756{
757	local max_grps=$1; shift
758	local i
759
760	for i in $(seq 0 $((max_grps - 1))); do
761		echo "ff0e::$(printf %x $i)"
762	done
763}
764
765l2_grps_get()
766{
767	local max_grps=$1; shift
768	local i
769
770	for i in $(seq 0 $((max_grps - 1))); do
771		echo "01:00:00:00:00:$(printf %02x $i)"
772	done
773}
774
775cfg_test_dump_common()
776{
777	local name=$1; shift
778	local fn=$1; shift
779	local max_bridges=2
780	local max_grps=256
781	local max_ports=32
782	local num_entries
783	local batch_file
784	local grp
785	local i j
786
787	RET=0
788
789	# Create net devices.
790	for i in $(seq 1 $max_bridges); do
791		ip link add name br-test${i} up type bridge vlan_filtering 1 \
792			mcast_snooping 1
793		for j in $(seq 1 $max_ports); do
794			ip link add name br-test${i}-du${j} up \
795				master br-test${i} type dummy
796		done
797	done
798
799	# Create batch file with MDB entries.
800	batch_file=$(mktemp)
801	for i in $(seq 1 $max_bridges); do
802		for j in $(seq 1 $max_ports); do
803			for grp in $($fn $max_grps); do
804				echo "mdb add dev br-test${i} \
805					port br-test${i}-du${j} grp $grp \
806					permanent vid 1" >> $batch_file
807			done
808		done
809	done
810
811	# Program the batch file and check for expected number of entries.
812	bridge -b $batch_file
813	for i in $(seq 1 $max_bridges); do
814		num_entries=$(bridge mdb show dev br-test${i} | \
815			grep "permanent" | wc -l)
816		[[ $num_entries -eq $((max_grps * max_ports)) ]]
817		check_err $? "Wrong number of entries in br-test${i}"
818	done
819
820	# Cleanup.
821	rm $batch_file
822	for i in $(seq 1 $max_bridges); do
823		ip link del dev br-test${i}
824		for j in $(seq $max_ports); do
825			ip link del dev br-test${i}-du${j}
826		done
827	done
828
829	log_test "$name large scale dump tests"
830}
831
832# Check large scale dump.
833cfg_test_dump()
834{
835	echo
836	log_info "# Large scale dump tests"
837
838	cfg_test_dump_common "IPv4" ipv4_grps_get
839	cfg_test_dump_common "IPv6" ipv6_grps_get
840	cfg_test_dump_common "L2" l2_grps_get
841}
842
843cfg_test()
844{
845	cfg_test_host
846	cfg_test_port
847	cfg_test_dump
848}
849
850__fwd_test_host_ip()
851{
852	local grp=$1; shift
853	local dmac=$1; shift
854	local src=$1; shift
855	local mode=$1; shift
856	local name
857	local eth_type
858
859	RET=0
860
861	if [[ $mode == "-4" ]]; then
862		name="IPv4"
863		eth_type="ipv4"
864	else
865		name="IPv6"
866		eth_type="ipv6"
867	fi
868
869	tc filter add dev br0 ingress protocol 802.1q pref 1 handle 1 flower \
870		vlan_ethtype $eth_type vlan_id 10 dst_ip $grp src_ip $src \
871		action drop
872
873	# Packet should only be flooded to multicast router ports when there is
874	# no matching MDB entry. The bridge is not configured as a multicast
875	# router port.
876	$MZ $mode $h1.10 -a own -b $dmac -c 1 -p 128 -A $src -B $grp -t udp -q
877	tc_check_packets "dev br0 ingress" 1 0
878	check_err $? "Packet locally received after flood"
879
880	# Install a regular port group entry and expect the packet to not be
881	# locally received.
882	bridge mdb add dev br0 port $swp2 grp $grp temp vid 10
883	$MZ $mode $h1.10 -a own -b $dmac -c 1 -p 128 -A $src -B $grp -t udp -q
884	tc_check_packets "dev br0 ingress" 1 0
885	check_err $? "Packet locally received after installing a regular entry"
886
887	# Add a host entry and expect the packet to be locally received.
888	bridge mdb add dev br0 port br0 grp $grp temp vid 10
889	$MZ $mode $h1.10 -a own -b $dmac -c 1 -p 128 -A $src -B $grp -t udp -q
890	tc_check_packets "dev br0 ingress" 1 1
891	check_err $? "Packet not locally received after adding a host entry"
892
893	# Remove the host entry and expect the packet to not be locally
894	# received.
895	bridge mdb del dev br0 port br0 grp $grp vid 10
896	$MZ $mode $h1.10 -a own -b $dmac -c 1 -p 128 -A $src -B $grp -t udp -q
897	tc_check_packets "dev br0 ingress" 1 1
898	check_err $? "Packet locally received after removing a host entry"
899
900	bridge mdb del dev br0 port $swp2 grp $grp vid 10
901
902	tc filter del dev br0 ingress protocol 802.1q pref 1 handle 1 flower
903
904	log_test "$name host entries forwarding tests"
905}
906
907fwd_test_host_ip()
908{
909	__fwd_test_host_ip "239.1.1.1" "01:00:5e:01:01:01" "192.0.2.1" "-4"
910	__fwd_test_host_ip "ff0e::1" "33:33:00:00:00:01" "2001:db8:1::1" "-6"
911}
912
913fwd_test_host_l2()
914{
915	local dmac=01:02:03:04:05:06
916
917	RET=0
918
919	tc filter add dev br0 ingress protocol all pref 1 handle 1 flower \
920		dst_mac $dmac action drop
921
922	# Packet should be flooded and locally received when there is no
923	# matching MDB entry.
924	$MZ $h1.10 -c 1 -p 128 -a own -b $dmac -q
925	tc_check_packets "dev br0 ingress" 1 1
926	check_err $? "Packet not locally received after flood"
927
928	# Install a regular port group entry and expect the packet to not be
929	# locally received.
930	bridge mdb add dev br0 port $swp2 grp $dmac permanent vid 10
931	$MZ $h1.10 -c 1 -p 128 -a own -b $dmac -q
932	tc_check_packets "dev br0 ingress" 1 1
933	check_err $? "Packet locally received after installing a regular entry"
934
935	# Add a host entry and expect the packet to be locally received.
936	bridge mdb add dev br0 port br0 grp $dmac permanent vid 10
937	$MZ $h1.10 -c 1 -p 128 -a own -b $dmac -q
938	tc_check_packets "dev br0 ingress" 1 2
939	check_err $? "Packet not locally received after adding a host entry"
940
941	# Remove the host entry and expect the packet to not be locally
942	# received.
943	bridge mdb del dev br0 port br0 grp $dmac permanent vid 10
944	$MZ $h1.10 -c 1 -p 128 -a own -b $dmac -q
945	tc_check_packets "dev br0 ingress" 1 2
946	check_err $? "Packet locally received after removing a host entry"
947
948	bridge mdb del dev br0 port $swp2 grp $dmac permanent vid 10
949
950	tc filter del dev br0 ingress protocol all pref 1 handle 1 flower
951
952	log_test "L2 host entries forwarding tests"
953}
954
955fwd_test_host()
956{
957	# Disable multicast router on the bridge to ensure that packets are
958	# only locally received when a matching host entry is present.
959	ip link set dev br0 type bridge mcast_router 0
960
961	fwd_test_host_ip
962	fwd_test_host_l2
963
964	ip link set dev br0 type bridge mcast_router 1
965}
966
967__fwd_test_port_ip()
968{
969	local grp=$1; shift
970	local dmac=$1; shift
971	local valid_src=$1; shift
972	local invalid_src=$1; shift
973	local mode=$1; shift
974	local filter_mode=$1; shift
975	local name
976	local eth_type
977	local src_list
978
979	RET=0
980
981	if [[ $mode == "-4" ]]; then
982		name="IPv4"
983		eth_type="ipv4"
984	else
985		name="IPv6"
986		eth_type="ipv6"
987	fi
988
989	# The valid source is the one we expect to get packets from after
990	# adding the entry.
991	if [[ $filter_mode == "include" ]]; then
992		src_list=$valid_src
993	else
994		src_list=$invalid_src
995	fi
996
997	tc filter add dev $h2 ingress protocol 802.1q pref 1 handle 1 flower \
998		vlan_ethtype $eth_type vlan_id 10 dst_ip $grp \
999		src_ip $valid_src action drop
1000	tc filter add dev $h2 ingress protocol 802.1q pref 1 handle 2 flower \
1001		vlan_ethtype $eth_type vlan_id 10 dst_ip $grp \
1002		src_ip $invalid_src action drop
1003
1004	$MZ $mode $h1.10 -a own -b $dmac -c 1 -p 128 -A $valid_src -B $grp -t udp -q
1005	tc_check_packets "dev $h2 ingress" 1 0
1006	check_err $? "Packet from valid source received on H2 before adding entry"
1007
1008	$MZ $mode $h1.10 -a own -b $dmac -c 1 -p 128 -A $invalid_src -B $grp -t udp -q
1009	tc_check_packets "dev $h2 ingress" 2 0
1010	check_err $? "Packet from invalid source received on H2 before adding entry"
1011
1012	bridge mdb add dev br0 port $swp2 grp $grp vid 10 \
1013		filter_mode $filter_mode source_list $src_list
1014
1015	$MZ $mode $h1.10 -a own -b $dmac -c 1 -p 128 -A $valid_src -B $grp -t udp -q
1016	tc_check_packets "dev $h2 ingress" 1 1
1017	check_err $? "Packet from valid source not received on H2 after adding entry"
1018
1019	$MZ $mode $h1.10 -a own -b $dmac -c 1 -p 128 -A $invalid_src -B $grp -t udp -q
1020	tc_check_packets "dev $h2 ingress" 2 0
1021	check_err $? "Packet from invalid source received on H2 after adding entry"
1022
1023	bridge mdb replace dev br0 port $swp2 grp $grp vid 10 \
1024		filter_mode exclude
1025
1026	$MZ $mode $h1.10 -a own -b $dmac -c 1 -p 128 -A $valid_src -B $grp -t udp -q
1027	tc_check_packets "dev $h2 ingress" 1 2
1028	check_err $? "Packet from valid source not received on H2 after allowing all sources"
1029
1030	$MZ $mode $h1.10 -a own -b $dmac -c 1 -p 128 -A $invalid_src -B $grp -t udp -q
1031	tc_check_packets "dev $h2 ingress" 2 1
1032	check_err $? "Packet from invalid source not received on H2 after allowing all sources"
1033
1034	bridge mdb del dev br0 port $swp2 grp $grp vid 10
1035
1036	$MZ $mode $h1.10 -a own -b $dmac -c 1 -p 128 -A $valid_src -B $grp -t udp -q
1037	tc_check_packets "dev $h2 ingress" 1 2
1038	check_err $? "Packet from valid source received on H2 after deleting entry"
1039
1040	$MZ $mode $h1.10 -a own -b $dmac -c 1 -p 128 -A $invalid_src -B $grp -t udp -q
1041	tc_check_packets "dev $h2 ingress" 2 1
1042	check_err $? "Packet from invalid source received on H2 after deleting entry"
1043
1044	tc filter del dev $h2 ingress protocol 802.1q pref 1 handle 2 flower
1045	tc filter del dev $h2 ingress protocol 802.1q pref 1 handle 1 flower
1046
1047	log_test "$name port group \"$filter_mode\" entries forwarding tests"
1048}
1049
1050fwd_test_port_ip()
1051{
1052	__fwd_test_port_ip "239.1.1.1" "01:00:5e:01:01:01" "192.0.2.1" "192.0.2.2" "-4" "exclude"
1053	__fwd_test_port_ip "ff0e::1" "33:33:00:00:00:01" "2001:db8:1::1" "2001:db8:1::2" "-6" \
1054		"exclude"
1055	__fwd_test_port_ip "239.1.1.1" "01:00:5e:01:01:01" "192.0.2.1" "192.0.2.2" "-4" "include"
1056	__fwd_test_port_ip "ff0e::1" "33:33:00:00:00:01" "2001:db8:1::1" "2001:db8:1::2" "-6" \
1057		"include"
1058}
1059
1060fwd_test_port_l2()
1061{
1062	local dmac=01:02:03:04:05:06
1063
1064	RET=0
1065
1066	tc filter add dev $h2 ingress protocol all pref 1 handle 1 flower \
1067		dst_mac $dmac action drop
1068
1069	$MZ $h1.10 -c 1 -p 128 -a own -b $dmac -q
1070	tc_check_packets "dev $h2 ingress" 1 0
1071	check_err $? "Packet received on H2 before adding entry"
1072
1073	bridge mdb add dev br0 port $swp2 grp $dmac permanent vid 10
1074	$MZ $h1.10 -c 1 -p 128 -a own -b $dmac -q
1075	tc_check_packets "dev $h2 ingress" 1 1
1076	check_err $? "Packet not received on H2 after adding entry"
1077
1078	bridge mdb del dev br0 port $swp2 grp $dmac permanent vid 10
1079	$MZ $h1.10 -c 1 -p 128 -a own -b $dmac -q
1080	tc_check_packets "dev $h2 ingress" 1 1
1081	check_err $? "Packet received on H2 after deleting entry"
1082
1083	tc filter del dev $h2 ingress protocol all pref 1 handle 1 flower
1084
1085	log_test "L2 port entries forwarding tests"
1086}
1087
1088fwd_test_port()
1089{
1090	# Disable multicast flooding to ensure that packets are only forwarded
1091	# out of a port when a matching port group entry is present.
1092	bridge link set dev $swp2 mcast_flood off
1093
1094	fwd_test_port_ip
1095	fwd_test_port_l2
1096
1097	bridge link set dev $swp2 mcast_flood on
1098}
1099
1100fwd_test()
1101{
1102	echo
1103	log_info "# Forwarding tests"
1104
1105	# Forwarding according to MDB entries only takes place when the bridge
1106	# detects that there is a valid querier in the network. Set the bridge
1107	# as the querier and assign it a valid IPv6 link-local address to be
1108	# used as the source address for MLD queries.
1109	ip -6 address add fe80::1/64 nodad dev br0
1110	ip link set dev br0 type bridge mcast_querier 1
1111	# Wait the default Query Response Interval (10 seconds) for the bridge
1112	# to determine that there are no other queriers in the network.
1113	sleep 10
1114
1115	fwd_test_host
1116	fwd_test_port
1117
1118	ip link set dev br0 type bridge mcast_querier 0
1119	ip -6 address del fe80::1/64 dev br0
1120}
1121
1122ctrl_igmpv3_is_in_test()
1123{
1124	RET=0
1125
1126	# Add a permanent entry and check that it is not affected by the
1127	# received IGMP packet.
1128	bridge mdb add dev br0 port $swp1 grp 239.1.1.1 permanent vid 10 \
1129		filter_mode include source_list 192.0.2.1
1130
1131	# IS_IN ( 192.0.2.2 )
1132	$MZ $h1.10 -c 1 -a own -b 01:00:5e:01:01:01 -A 192.0.2.1 -B 239.1.1.1 \
1133		-t ip proto=2,p=$(igmpv3_is_in_get 239.1.1.1 192.0.2.2) -q
1134
1135	bridge -d mdb show dev br0 vid 10 | grep 239.1.1.1 | grep -q 192.0.2.2
1136	check_fail $? "Permanent entry affected by IGMP packet"
1137
1138	# Replace the permanent entry with a temporary one and check that after
1139	# processing the IGMP packet, a new source is added to the list along
1140	# with a new forwarding entry.
1141	bridge mdb replace dev br0 port $swp1 grp 239.1.1.1 temp vid 10 \
1142		filter_mode include source_list 192.0.2.1
1143
1144	# IS_IN ( 192.0.2.2 )
1145	$MZ $h1.10 -a own -b 01:00:5e:01:01:01 -c 1 -A 192.0.2.1 -B 239.1.1.1 \
1146		-t ip proto=2,p=$(igmpv3_is_in_get 239.1.1.1 192.0.2.2) -q
1147
1148	bridge -d mdb show dev br0 vid 10 | grep 239.1.1.1 | grep -v "src" | \
1149		grep -q 192.0.2.2
1150	check_err $? "Source not add to source list"
1151
1152	bridge -d mdb show dev br0 vid 10 | grep 239.1.1.1 | \
1153		grep -q "src 192.0.2.2"
1154	check_err $? "(S, G) entry not created for new source"
1155
1156	bridge mdb del dev br0 port $swp1 grp 239.1.1.1 vid 10
1157
1158	log_test "IGMPv3 MODE_IS_INCLUDE tests"
1159}
1160
1161ctrl_mldv2_is_in_test()
1162{
1163	RET=0
1164
1165	# Add a permanent entry and check that it is not affected by the
1166	# received MLD packet.
1167	bridge mdb add dev br0 port $swp1 grp ff0e::1 permanent vid 10 \
1168		filter_mode include source_list 2001:db8:1::1
1169
1170	# IS_IN ( 2001:db8:1::2 )
1171	local p=$(mldv2_is_in_get fe80::1 ff0e::1 2001:db8:1::2)
1172	$MZ -6 $h1.10 -a own -b 33:33:00:00:00:01 -c 1 -A fe80::1 -B ff0e::1 \
1173		-t ip hop=1,next=0,p="$p" -q
1174
1175	bridge -d mdb show dev br0 vid 10 | grep ff0e::1 | \
1176		grep -q 2001:db8:1::2
1177	check_fail $? "Permanent entry affected by MLD packet"
1178
1179	# Replace the permanent entry with a temporary one and check that after
1180	# processing the MLD packet, a new source is added to the list along
1181	# with a new forwarding entry.
1182	bridge mdb replace dev br0 port $swp1 grp ff0e::1 temp vid 10 \
1183		filter_mode include source_list 2001:db8:1::1
1184
1185	# IS_IN ( 2001:db8:1::2 )
1186	$MZ -6 $h1.10 -a own -b 33:33:00:00:00:01 -c 1 -A fe80::1 -B ff0e::1 \
1187		-t ip hop=1,next=0,p="$p" -q
1188
1189	bridge -d mdb show dev br0 vid 10 | grep ff0e::1 | grep -v "src" | \
1190		grep -q 2001:db8:1::2
1191	check_err $? "Source not add to source list"
1192
1193	bridge -d mdb show dev br0 vid 10 | grep ff0e::1 | \
1194		grep -q "src 2001:db8:1::2"
1195	check_err $? "(S, G) entry not created for new source"
1196
1197	bridge mdb del dev br0 port $swp1 grp ff0e::1 vid 10
1198
1199	log_test "MLDv2 MODE_IS_INCLUDE tests"
1200}
1201
1202ctrl_test()
1203{
1204	echo
1205	log_info "# Control packets tests"
1206
1207	ctrl_igmpv3_is_in_test
1208	ctrl_mldv2_is_in_test
1209}
1210
1211if ! bridge mdb help 2>&1 | grep -q "replace"; then
1212	echo "SKIP: iproute2 too old, missing bridge mdb replace support"
1213	exit $ksft_skip
1214fi
1215
1216trap cleanup EXIT
1217
1218setup_prepare
1219setup_wait
1220tests_run
1221
1222exit $EXIT_STATUS
1223