xref: /linux/tools/testing/selftests/net/forwarding/bridge_mdb.sh (revision 6d9b262afe0ec1d6e0ef99321ca9d6b921310471)
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 get dev br0 grp $grp vid 10 &> /dev/null
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 get dev br0 grp $grp vid 10 &> /dev/null
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 get dev br0 $grp_key vid 10 &> /dev/null
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 get dev br0 $grp_key vid 10 &> /dev/null
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 get dev br0 $grp_key vid 10 | 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 get dev br0 $grp_key vid 10 | 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 get dev br0 $grp_key vid 10 &> /dev/null
228	check_err $? "$name entry with VLAN 10 not added when VLAN was not specified"
229	bridge mdb get dev br0 $grp_key vid 20 &> /dev/null
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 get dev br0 $grp_key vid 10 &> /dev/null
234	check_fail $? "$name entry with VLAN 10 not deleted when VLAN was not specified"
235	bridge mdb get dev br0 $grp_key vid 20 &> /dev/null
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 get dev br0 grp $grp vid 10 | 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 get dev br0 grp $grp vid 10 &> /dev/null
309	check_err $? "(*, G) entry not created"
310	bridge -d mdb get dev br0 grp $grp src $src1 vid 10 &> /dev/null
311	check_err $? "(S, G) entry not created"
312	bridge mdb del dev br0 port $swp1 grp $grp vid 10
313	bridge -d mdb get dev br0 grp $grp vid 10 &> /dev/null
314	check_fail $? "(*, G) entry not deleted"
315	bridge -d mdb get dev br0 grp $grp src $src1 vid 10 &> /dev/null
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 get dev br0 grp $grp vid 10 | grep -q "permanent"
325	check_err $? "(*, G) entry not added as \"permanent\" when should"
326	bridge -d mdb get dev br0 grp $grp src $src1 vid 10 | \
327		grep -q "permanent"
328	check_err $? "(S, G) entry not added as \"permanent\" when should"
329
330	bridge -d -s mdb get dev br0 grp $grp vid 10 | grep -q " 0.00"
331	check_err $? "(*, G) \"permanent\" entry has a pending group timer"
332	bridge -d -s mdb get dev br0 grp $grp vid 10 | grep -q "/0.00"
333	check_err $? "\"permanent\" source entry has a pending source timer"
334
335	bridge mdb del dev br0 port $swp1 grp $grp vid 10
336
337	# Check that group timer is set for temporary (*, G) EXCLUDE, but not
338	# the source timer.
339	bridge mdb add dev br0 port $swp1 grp $grp temp vid 10 \
340		filter_mode exclude source_list $src1
341
342	bridge -d mdb get dev br0 grp $grp vid 10 | grep -q "temp"
343	check_err $? "(*, G) EXCLUDE entry not added as \"temp\" when should"
344	bridge -d mdb get dev br0 grp $grp src $src1 vid 10 | grep -q "temp"
345	check_err $? "(S, G) \"blocked\" entry not added as \"temp\" when should"
346
347	bridge -d -s mdb get dev br0 grp $grp vid 10 | grep -q " 0.00"
348	check_fail $? "(*, G) EXCLUDE entry does not have a pending group timer"
349	bridge -d -s mdb get dev br0 grp $grp vid 10 | grep -q "/0.00"
350	check_err $? "\"blocked\" source entry has a pending source timer"
351
352	bridge mdb del dev br0 port $swp1 grp $grp vid 10
353
354	# Check that group timer is not set for temporary (*, G) INCLUDE, but
355	# that the source timer is set.
356	bridge mdb add dev br0 port $swp1 grp $grp temp vid 10 \
357		filter_mode include source_list $src1
358
359	bridge -d mdb get dev br0 grp $grp vid 10 | grep -q "temp"
360	check_err $? "(*, G) INCLUDE entry not added as \"temp\" when should"
361	bridge -d mdb get dev br0 grp $grp src $src1 vid 10 | grep -q "temp"
362	check_err $? "(S, G) entry not added as \"temp\" when should"
363
364	bridge -d -s mdb get dev br0 grp $grp vid 10 | grep -q " 0.00"
365	check_err $? "(*, G) INCLUDE entry has a pending group timer"
366	bridge -d -s mdb get dev br0 grp $grp vid 10 | grep -q "/0.00"
367	check_fail $? "Source entry does not have a pending source timer"
368
369	bridge mdb del dev br0 port $swp1 grp $grp vid 10
370
371	# Check that group timer is never set for (S, G) entries.
372	bridge mdb add dev br0 port $swp1 grp $grp temp vid 10 \
373		filter_mode include source_list $src1
374
375	bridge -d -s mdb get dev br0 grp $grp src $src1 vid 10 | grep -q " 0.00"
376	check_err $? "(S, G) entry has a pending group timer"
377
378	bridge mdb del dev br0 port $swp1 grp $grp vid 10
379
380	## Filter mode (include / exclude) tests.
381
382	# Check that (*, G) INCLUDE entries are added with correct filter mode
383	# and that (S, G) entries are not marked as "blocked".
384	bridge mdb add dev br0 port $swp1 grp $grp vid 10 \
385		filter_mode include source_list $src1
386
387	bridge -d mdb get dev br0 grp $grp vid 10 | grep -q "include"
388	check_err $? "(*, G) INCLUDE not added with \"include\" filter mode"
389	bridge -d mdb get dev br0 grp $grp src $src1 vid 10 | grep -q "blocked"
390	check_fail $? "(S, G) entry marked as \"blocked\" when should not"
391
392	bridge mdb del dev br0 port $swp1 grp $grp vid 10
393
394	# Check that (*, G) EXCLUDE entries are added with correct filter mode
395	# and that (S, G) entries are marked as "blocked".
396	bridge mdb add dev br0 port $swp1 grp $grp vid 10 \
397		filter_mode exclude source_list $src1
398
399	bridge -d mdb get dev br0 grp $grp vid 10 | grep -q "exclude"
400	check_err $? "(*, G) EXCLUDE not added with \"exclude\" filter mode"
401	bridge -d mdb get dev br0 grp $grp src $src1 vid 10 | grep -q "blocked"
402	check_err $? "(S, G) entry not marked as \"blocked\" when should"
403
404	bridge mdb del dev br0 port $swp1 grp $grp vid 10
405
406	## Protocol tests.
407
408	# Check that (*, G) and (S, G) entries are added with the specified
409	# protocol.
410	bridge mdb add dev br0 port $swp1 grp $grp vid 10 \
411		filter_mode exclude source_list $src1 proto zebra
412
413	bridge -d mdb get dev br0 grp $grp vid 10 | grep -q "zebra"
414	check_err $? "(*, G) entry not added with \"zebra\" protocol"
415	bridge -d mdb get dev br0 grp $grp src $src1 vid 10 | grep -q "zebra"
416	check_err $? "(S, G) entry not marked added with \"zebra\" protocol"
417
418	bridge mdb del dev br0 port $swp1 grp $grp vid 10
419
420	## Replace tests.
421
422	# Check that state can be modified.
423	bridge mdb add dev br0 port $swp1 grp $grp temp vid 10 \
424		filter_mode exclude source_list $src1
425
426	bridge mdb replace dev br0 port $swp1 grp $grp permanent vid 10 \
427		filter_mode exclude source_list $src1
428	bridge -d mdb get dev br0 grp $grp vid 10 | grep -q "permanent"
429	check_err $? "(*, G) entry not marked as \"permanent\" after replace"
430	bridge -d mdb get dev br0 grp $grp src $src1 vid 10 | grep -q "permanent"
431	check_err $? "(S, G) entry not marked as \"permanent\" after replace"
432
433	bridge mdb replace dev br0 port $swp1 grp $grp temp vid 10 \
434		filter_mode exclude source_list $src1
435	bridge -d mdb get dev br0 grp $grp vid 10 | grep -q "temp"
436	check_err $? "(*, G) entry not marked as \"temp\" after replace"
437	bridge -d mdb get dev br0 grp $grp src $src1 vid 10 | grep -q "temp"
438	check_err $? "(S, G) entry not marked as \"temp\" after replace"
439
440	bridge mdb del dev br0 port $swp1 grp $grp vid 10
441
442	# Check that filter mode can be modified.
443	bridge mdb add dev br0 port $swp1 grp $grp temp vid 10 \
444		filter_mode exclude source_list $src1
445
446	bridge mdb replace dev br0 port $swp1 grp $grp temp vid 10 \
447		filter_mode include source_list $src1
448	bridge -d mdb get dev br0 grp $grp vid 10 | grep -q "include"
449	check_err $? "(*, G) not marked with \"include\" filter mode after replace"
450	bridge -d mdb get dev br0 grp $grp src $src1 vid 10 | grep -q "blocked"
451	check_fail $? "(S, G) marked as \"blocked\" 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 get dev br0 grp $grp vid 10 | grep -q "exclude"
456	check_err $? "(*, G) not marked with \"exclude\" filter mode after replace"
457	bridge -d mdb get dev br0 grp $grp src $src1 vid 10 | grep -q "blocked"
458	check_err $? "(S, G) not marked as \"blocked\" after replace"
459
460	bridge mdb del dev br0 port $swp1 grp $grp vid 10
461
462	# Check that sources can be added to and removed from the source list.
463	bridge mdb add dev br0 port $swp1 grp $grp temp vid 10 \
464		filter_mode exclude source_list $src1
465
466	bridge mdb replace dev br0 port $swp1 grp $grp temp vid 10 \
467		filter_mode exclude source_list $src1,$src2,$src3
468	bridge -d mdb get dev br0 grp $grp src $src1 vid 10 &> /dev/null
469	check_err $? "(S, G) entry for source $src1 not created after replace"
470	bridge -d mdb get dev br0 grp $grp src $src2 vid 10 &> /dev/null
471	check_err $? "(S, G) entry for source $src2 not created after replace"
472	bridge -d mdb get dev br0 grp $grp src $src3 vid 10 &> /dev/null
473	check_err $? "(S, G) entry for source $src3 not created after replace"
474
475	bridge mdb replace dev br0 port $swp1 grp $grp temp vid 10 \
476		filter_mode exclude source_list $src1,$src3
477	bridge -d mdb get dev br0 grp $grp src $src1 vid 10 &> /dev/null
478	check_err $? "(S, G) entry for source $src1 not created after second replace"
479	bridge -d mdb get dev br0 grp $grp src $src2 vid 10 &> /dev/null
480	check_fail $? "(S, G) entry for source $src2 created after second replace"
481	bridge -d mdb get dev br0 grp $grp src $src3 vid 10 &> /dev/null
482	check_err $? "(S, G) entry for source $src3 not created after second replace"
483
484	bridge mdb del dev br0 port $swp1 grp $grp vid 10
485
486	# Check that protocol can be modified.
487	bridge mdb add dev br0 port $swp1 grp $grp temp vid 10 \
488		filter_mode exclude source_list $src1 proto zebra
489
490	bridge mdb replace dev br0 port $swp1 grp $grp temp vid 10 \
491		filter_mode exclude source_list $src1 proto bgp
492	bridge -d mdb get dev br0 grp $grp vid 10 | grep -q "bgp"
493	check_err $? "(*, G) protocol not changed to \"bgp\" after replace"
494	bridge -d mdb get dev br0 grp $grp src $src1 vid 10 | grep -q "bgp"
495	check_err $? "(S, G) protocol not changed to \"bgp\" after replace"
496
497	bridge mdb del dev br0 port $swp1 grp $grp vid 10
498
499	## Star exclude tests.
500
501	# Check star exclude functionality. When adding a new EXCLUDE (*, G),
502	# it needs to be also added to all (S, G) entries for proper
503	# replication.
504	bridge mdb add dev br0 port $swp2 grp $grp vid 10 \
505		filter_mode include source_list $src1
506	bridge mdb add dev br0 port $swp1 grp $grp vid 10
507	bridge -d mdb get dev br0 grp $grp src $src1 vid 10 | grep "$swp1" | \
508		grep -q "added_by_star_ex"
509	check_err $? "\"added_by_star_ex\" entry not created after adding (*, G) entry"
510	bridge mdb del dev br0 port $swp1 grp $grp vid 10
511	bridge mdb del dev br0 port $swp2 grp $grp src $src1 vid 10
512
513	## Error cases tests.
514
515	bridge mdb add dev br0 port $swp1 grp $invalid_grp vid 10 &> /dev/null
516	check_fail $? "Managed to add an entry with an invalid group"
517
518	bridge mdb add dev br0 port $swp1 grp $grp vid 10 filter_mode include \
519		&> /dev/null
520	check_fail $? "Managed to add an INCLUDE entry with an empty source list"
521
522	bridge mdb add dev br0 port $swp1 grp $grp vid 10 filter_mode include \
523		source_list $grp &> /dev/null
524	check_fail $? "Managed to add an entry with an invalid source in source list"
525
526	bridge mdb add dev br0 port $swp1 grp $grp vid 10 \
527		source_list $src &> /dev/null
528	check_fail $? "Managed to add an entry with a source list and no filter mode"
529
530	bridge mdb add dev br0 port $swp1 grp $grp vid 10 filter_mode include \
531		source_list $src1
532	bridge mdb add dev br0 port $swp1 grp $grp vid 10 filter_mode exclude \
533		source_list $src1 &> /dev/null
534	check_fail $? "Managed to replace an entry without using replace"
535	bridge mdb del dev br0 port $swp1 grp $grp vid 10
536
537	bridge mdb add dev br0 port $swp1 grp $grp src $src2 vid 10
538	bridge mdb add dev br0 port $swp1 grp $grp vid 10 filter_mode include \
539		source_list $src1,$src2,$src3 &> /dev/null
540	check_fail $? "Managed to add a source that already has a forwarding entry"
541	bridge mdb del dev br0 port $swp1 grp $grp src $src2 vid 10
542
543	# Check maximum number of sources.
544	bridge mdb add dev br0 port $swp1 grp $grp vid 10 filter_mode exclude \
545		source_list $(src_list_create $src_prefix $max_srcs)
546	num_srcs=$(bridge -d mdb show dev br0 vid 10 | grep "$grp" | \
547		grep "src" | wc -l)
548	[[ $num_srcs -eq $max_srcs ]]
549	check_err $? "Failed to configure maximum number of sources ($max_srcs)"
550	bridge mdb del dev br0 port $swp1 grp $grp vid 10
551
552	bridge mdb add dev br0 port $swp1 grp $grp vid 10 filter_mode exclude \
553		source_list $(src_list_create $src_prefix $((max_srcs + 1))) \
554		&> /dev/null
555	check_fail $? "Managed to exceed maximum number of sources ($max_srcs)"
556
557	log_test "$name (*, G) port group entries configuration tests"
558}
559
560cfg_test_port_ip_star_g()
561{
562	echo
563	log_info "# Port group entries configuration tests - (*, G)"
564
565	cfg_test_port_common "IPv4 (*, G)" "grp 239.1.1.1"
566	cfg_test_port_common "IPv6 (*, G)" "grp ff0e::1"
567	__cfg_test_port_ip_star_g "IPv4" "239.1.1.1" "224.0.0.1" "192.0.2."
568	__cfg_test_port_ip_star_g "IPv6" "ff0e::1" "ff02::1" "2001:db8:1::"
569}
570
571__cfg_test_port_ip_sg()
572{
573	local name=$1; shift
574	local grp=$1; shift
575	local src=$1; shift
576	local grp_key="grp $grp src $src"
577
578	RET=0
579
580	bridge mdb add dev br0 port $swp1 $grp_key vid 10
581	bridge -d mdb get dev br0 $grp_key vid 10 | grep -q "include"
582	check_err $? "Default filter mode is not \"include\""
583	bridge mdb del dev br0 port $swp1 $grp_key vid 10
584
585	# Check that entries can be added as both permanent and temp and that
586	# group timer is set correctly.
587	bridge mdb add dev br0 port $swp1 $grp_key permanent vid 10
588	bridge -d mdb get dev br0 $grp_key vid 10 | grep -q "permanent"
589	check_err $? "Entry not added as \"permanent\" when should"
590	bridge -d -s mdb get dev br0 $grp_key vid 10 | grep -q " 0.00"
591	check_err $? "\"permanent\" entry has a pending group timer"
592	bridge mdb del dev br0 port $swp1 $grp_key vid 10
593
594	bridge mdb add dev br0 port $swp1 $grp_key temp vid 10
595	bridge -d mdb get dev br0 $grp_key vid 10 | grep -q "temp"
596	check_err $? "Entry not added as \"temp\" when should"
597	bridge -d -s mdb get dev br0 $grp_key vid 10 | grep -q " 0.00"
598	check_fail $? "\"temp\" entry has an unpending group timer"
599	bridge mdb del dev br0 port $swp1 $grp_key vid 10
600
601	# Check error cases.
602	bridge mdb add dev br0 port $swp1 $grp_key vid 10 \
603		filter_mode include &> /dev/null
604	check_fail $? "Managed to add an entry with a filter mode"
605
606	bridge mdb add dev br0 port $swp1 $grp_key vid 10 \
607		filter_mode include source_list $src &> /dev/null
608	check_fail $? "Managed to add an entry with a source list"
609
610	bridge mdb add dev br0 port $swp1 grp $grp src $grp vid 10 &> /dev/null
611	check_fail $? "Managed to add an entry with an invalid source"
612
613	bridge mdb add dev br0 port $swp1 $grp_key vid 10 temp
614	bridge mdb add dev br0 port $swp1 $grp_key vid 10 permanent &> /dev/null
615	check_fail $? "Managed to replace an entry without using replace"
616	bridge mdb del dev br0 port $swp1 $grp_key vid 10
617
618	# Check that we can replace available attributes.
619	bridge mdb add dev br0 port $swp1 $grp_key vid 10 proto 123
620	bridge mdb replace dev br0 port $swp1 $grp_key vid 10 proto 111
621	bridge -d mdb get dev br0 $grp_key vid 10 | grep -q "111"
622	check_err $? "Failed to replace protocol"
623
624	bridge mdb replace dev br0 port $swp1 $grp_key vid 10 permanent
625	bridge -d mdb get dev br0 $grp_key vid 10 | grep -q "permanent"
626	check_err $? "Entry not marked as \"permanent\" after replace"
627	bridge -d -s mdb get dev br0 $grp_key vid 10 | grep -q " 0.00"
628	check_err $? "Entry has a pending group timer after replace"
629
630	bridge mdb replace dev br0 port $swp1 $grp_key vid 10 temp
631	bridge -d mdb get dev br0 $grp_key vid 10 | grep -q "temp"
632	check_err $? "Entry not marked as \"temp\" after replace"
633	bridge -d -s mdb get dev br0 $grp_key vid 10 | grep -q " 0.00"
634	check_fail $? "Entry has an unpending group timer after replace"
635	bridge mdb del dev br0 port $swp1 $grp_key vid 10
636
637	# Check star exclude functionality. When adding a (S, G), all matching
638	# (*, G) ports need to be added to it.
639	bridge mdb add dev br0 port $swp2 grp $grp vid 10
640	bridge mdb add dev br0 port $swp1 $grp_key vid 10
641	bridge mdb get dev br0 $grp_key vid 10 | grep $swp2 | \
642		grep -q "added_by_star_ex"
643	check_err $? "\"added_by_star_ex\" entry not created after adding (S, G) entry"
644	bridge mdb del dev br0 port $swp1 $grp_key vid 10
645	bridge mdb del dev br0 port $swp2 grp $grp vid 10
646
647	log_test "$name (S, G) port group entries configuration tests"
648}
649
650cfg_test_port_ip_sg()
651{
652	echo
653	log_info "# Port group entries configuration tests - (S, G)"
654
655	cfg_test_port_common "IPv4 (S, G)" "grp 239.1.1.1 src 192.0.2.1"
656	cfg_test_port_common "IPv6 (S, G)" "grp ff0e::1 src 2001:db8:1::1"
657	__cfg_test_port_ip_sg "IPv4" "239.1.1.1" "192.0.2.1"
658	__cfg_test_port_ip_sg "IPv6" "ff0e::1" "2001:db8:1::1"
659}
660
661cfg_test_port_ip()
662{
663	cfg_test_port_ip_star_g
664	cfg_test_port_ip_sg
665}
666
667__cfg_test_port_l2()
668{
669	local grp="01:02:03:04:05:06"
670
671	RET=0
672
673	bridge meb add dev br0 port $swp grp 00:01:02:03:04:05 \
674		permanent vid 10 &> /dev/null
675	check_fail $? "Managed to add an entry with unicast MAC"
676
677	bridge mdb add dev br0 port $swp grp $grp src 00:01:02:03:04:05 \
678		permanent vid 10 &> /dev/null
679	check_fail $? "Managed to add an entry with a source"
680
681	bridge mdb add dev br0 port $swp1 grp $grp permanent vid 10 \
682		filter_mode include &> /dev/null
683	check_fail $? "Managed to add an entry with a filter mode"
684
685	bridge mdb add dev br0 port $swp1 grp $grp permanent vid 10 \
686		source_list 00:01:02:03:04:05 &> /dev/null
687	check_fail $? "Managed to add an entry with a source list"
688
689	log_test "L2 (*, G) port group entries configuration tests"
690}
691
692cfg_test_port_l2()
693{
694	echo
695	log_info "# Port group entries configuration tests - L2"
696
697	cfg_test_port_common "L2 (*, G)" "grp 01:02:03:04:05:06"
698	__cfg_test_port_l2
699}
700
701# Check configuration of regular (port) entries of all types.
702cfg_test_port()
703{
704	cfg_test_port_ip
705	cfg_test_port_l2
706}
707
708ipv4_grps_get()
709{
710	local max_grps=$1; shift
711	local i
712
713	for i in $(seq 0 $((max_grps - 1))); do
714		echo "239.1.1.$i"
715	done
716}
717
718ipv6_grps_get()
719{
720	local max_grps=$1; shift
721	local i
722
723	for i in $(seq 0 $((max_grps - 1))); do
724		echo "ff0e::$(printf %x $i)"
725	done
726}
727
728l2_grps_get()
729{
730	local max_grps=$1; shift
731	local i
732
733	for i in $(seq 0 $((max_grps - 1))); do
734		echo "01:00:00:00:00:$(printf %02x $i)"
735	done
736}
737
738cfg_test_dump_common()
739{
740	local name=$1; shift
741	local fn=$1; shift
742	local max_bridges=2
743	local max_grps=256
744	local max_ports=32
745	local num_entries
746	local batch_file
747	local grp
748	local i j
749
750	RET=0
751
752	# Create net devices.
753	for i in $(seq 1 $max_bridges); do
754		ip link add name br-test${i} up type bridge vlan_filtering 1 \
755			mcast_snooping 1
756		for j in $(seq 1 $max_ports); do
757			ip link add name br-test${i}-du${j} up \
758				master br-test${i} type dummy
759		done
760	done
761
762	# Create batch file with MDB entries.
763	batch_file=$(mktemp)
764	for i in $(seq 1 $max_bridges); do
765		for j in $(seq 1 $max_ports); do
766			for grp in $($fn $max_grps); do
767				echo "mdb add dev br-test${i} \
768					port br-test${i}-du${j} grp $grp \
769					permanent vid 1" >> $batch_file
770			done
771		done
772	done
773
774	# Program the batch file and check for expected number of entries.
775	bridge -b $batch_file
776	for i in $(seq 1 $max_bridges); do
777		num_entries=$(bridge mdb show dev br-test${i} | \
778			grep "permanent" | wc -l)
779		[[ $num_entries -eq $((max_grps * max_ports)) ]]
780		check_err $? "Wrong number of entries in br-test${i}"
781	done
782
783	# Cleanup.
784	rm $batch_file
785	for i in $(seq 1 $max_bridges); do
786		ip link del dev br-test${i}
787		for j in $(seq $max_ports); do
788			ip link del dev br-test${i}-du${j}
789		done
790	done
791
792	log_test "$name large scale dump tests"
793}
794
795# Check large scale dump.
796cfg_test_dump()
797{
798	echo
799	log_info "# Large scale dump tests"
800
801	cfg_test_dump_common "IPv4" ipv4_grps_get
802	cfg_test_dump_common "IPv6" ipv6_grps_get
803	cfg_test_dump_common "L2" l2_grps_get
804}
805
806# Check flush functionality with different parameters.
807cfg_test_flush()
808{
809	local num_entries
810
811	# Add entries with different attributes and check that they are all
812	# flushed when the flush command is given with no parameters.
813
814	# Different port.
815	bridge mdb add dev br0 port $swp1 grp 239.1.1.1 vid 10
816	bridge mdb add dev br0 port $swp2 grp 239.1.1.2 vid 10
817
818	# Different VLAN ID.
819	bridge mdb add dev br0 port $swp1 grp 239.1.1.3 vid 10
820	bridge mdb add dev br0 port $swp1 grp 239.1.1.4 vid 20
821
822	# Different routing protocol.
823	bridge mdb add dev br0 port $swp1 grp 239.1.1.5 vid 10 proto bgp
824	bridge mdb add dev br0 port $swp1 grp 239.1.1.6 vid 10 proto zebra
825
826	# Different state.
827	bridge mdb add dev br0 port $swp1 grp 239.1.1.7 vid 10 permanent
828	bridge mdb add dev br0 port $swp1 grp 239.1.1.8 vid 10 temp
829
830	bridge mdb flush dev br0
831	num_entries=$(bridge mdb show dev br0 | wc -l)
832	[[ $num_entries -eq 0 ]]
833	check_err $? 0 "Not all entries flushed after flush all"
834
835	# Check that when flushing by port only entries programmed with the
836	# specified port are flushed and the rest are not.
837
838	bridge mdb add dev br0 port $swp1 grp 239.1.1.1 vid 10
839	bridge mdb add dev br0 port $swp2 grp 239.1.1.1 vid 10
840	bridge mdb add dev br0 port br0 grp 239.1.1.1 vid 10
841
842	bridge mdb flush dev br0 port $swp1
843
844	bridge mdb get dev br0 grp 239.1.1.1 vid 10 | grep -q "port $swp1"
845	check_fail $? "Entry not flushed by specified port"
846	bridge mdb get dev br0 grp 239.1.1.1 vid 10 | grep -q "port $swp2"
847	check_err $? "Entry flushed by wrong port"
848	bridge mdb get dev br0 grp 239.1.1.1 vid 10 | grep -q "port br0"
849	check_err $? "Host entry flushed by wrong port"
850
851	bridge mdb flush dev br0 port br0
852
853	bridge mdb get dev br0 grp 239.1.1.1 vid 10 | grep -q "port br0"
854	check_fail $? "Host entry not flushed by specified port"
855
856	bridge mdb flush dev br0
857
858	# Check that when flushing by VLAN ID only entries programmed with the
859	# specified VLAN ID are flushed and the rest are not.
860
861	bridge mdb add dev br0 port $swp1 grp 239.1.1.1 vid 10
862	bridge mdb add dev br0 port $swp2 grp 239.1.1.1 vid 10
863	bridge mdb add dev br0 port $swp1 grp 239.1.1.1 vid 20
864	bridge mdb add dev br0 port $swp2 grp 239.1.1.1 vid 20
865
866	bridge mdb flush dev br0 vid 10
867
868	bridge mdb get dev br0 grp 239.1.1.1 vid 10 &> /dev/null
869	check_fail $? "Entry not flushed by specified VLAN ID"
870	bridge mdb get dev br0 grp 239.1.1.1 vid 20 &> /dev/null
871	check_err $? "Entry flushed by wrong VLAN ID"
872
873	bridge mdb flush dev br0
874
875	# Check that all permanent entries are flushed when "permanent" is
876	# specified and that temporary entries are not.
877
878	bridge mdb add dev br0 port $swp1 grp 239.1.1.1 permanent vid 10
879	bridge mdb add dev br0 port $swp2 grp 239.1.1.1 temp vid 10
880
881	bridge mdb flush dev br0 permanent
882
883	bridge mdb get dev br0 grp 239.1.1.1 vid 10 | grep -q "port $swp1"
884	check_fail $? "Entry not flushed by \"permanent\" state"
885	bridge mdb get dev br0 grp 239.1.1.1 vid 10 | grep -q "port $swp2"
886	check_err $? "Entry flushed by wrong state (\"permanent\")"
887
888	bridge mdb flush dev br0
889
890	# Check that all temporary entries are flushed when "nopermanent" is
891	# specified and that permanent entries are not.
892
893	bridge mdb add dev br0 port $swp1 grp 239.1.1.1 permanent vid 10
894	bridge mdb add dev br0 port $swp2 grp 239.1.1.1 temp vid 10
895
896	bridge mdb flush dev br0 nopermanent
897
898	bridge mdb get dev br0 grp 239.1.1.1 vid 10 | grep -q "port $swp1"
899	check_err $? "Entry flushed by wrong state (\"nopermanent\")"
900	bridge mdb get dev br0 grp 239.1.1.1 vid 10 | grep -q "port $swp2"
901	check_fail $? "Entry not flushed by \"nopermanent\" state"
902
903	bridge mdb flush dev br0
904
905	# Check that L2 host entries are not flushed when "nopermanent" is
906	# specified, but flushed when "permanent" is specified.
907
908	bridge mdb add dev br0 port br0 grp 01:02:03:04:05:06 permanent vid 10
909
910	bridge mdb flush dev br0 nopermanent
911
912	bridge mdb get dev br0 grp 01:02:03:04:05:06 vid 10 &> /dev/null
913	check_err $? "L2 host entry flushed by wrong state (\"nopermanent\")"
914
915	bridge mdb flush dev br0 permanent
916
917	bridge mdb get dev br0 grp 01:02:03:04:05:06 vid 10 &> /dev/null
918	check_fail $? "L2 host entry not flushed by \"permanent\" state"
919
920	bridge mdb flush dev br0
921
922	# Check that IPv4 host entries are not flushed when "permanent" is
923	# specified, but flushed when "nopermanent" is specified.
924
925	bridge mdb add dev br0 port br0 grp 239.1.1.1 temp vid 10
926
927	bridge mdb flush dev br0 permanent
928
929	bridge mdb get dev br0 grp 239.1.1.1 vid 10 &> /dev/null
930	check_err $? "IPv4 host entry flushed by wrong state (\"permanent\")"
931
932	bridge mdb flush dev br0 nopermanent
933
934	bridge mdb get dev br0 grp 239.1.1.1 vid 10 &> /dev/null
935	check_fail $? "IPv4 host entry not flushed by \"nopermanent\" state"
936
937	bridge mdb flush dev br0
938
939	# Check that IPv6 host entries are not flushed when "permanent" is
940	# specified, but flushed when "nopermanent" is specified.
941
942	bridge mdb add dev br0 port br0 grp ff0e::1 temp vid 10
943
944	bridge mdb flush dev br0 permanent
945
946	bridge mdb get dev br0 grp ff0e::1 vid 10 &> /dev/null
947	check_err $? "IPv6 host entry flushed by wrong state (\"permanent\")"
948
949	bridge mdb flush dev br0 nopermanent
950
951	bridge mdb get dev br0 grp ff0e::1 vid 10 &> /dev/null
952	check_fail $? "IPv6 host entry not flushed by \"nopermanent\" state"
953
954	bridge mdb flush dev br0
955
956	# Check that when flushing by routing protocol only entries programmed
957	# with the specified routing protocol are flushed and the rest are not.
958
959	bridge mdb add dev br0 port $swp1 grp 239.1.1.1 vid 10 proto bgp
960	bridge mdb add dev br0 port $swp2 grp 239.1.1.1 vid 10 proto zebra
961	bridge mdb add dev br0 port br0 grp 239.1.1.1 vid 10
962
963	bridge mdb flush dev br0 proto bgp
964
965	bridge mdb get dev br0 grp 239.1.1.1 vid 10 | grep -q "port $swp1"
966	check_fail $? "Entry not flushed by specified routing protocol"
967	bridge mdb get dev br0 grp 239.1.1.1 vid 10 | grep -q "port $swp2"
968	check_err $? "Entry flushed by wrong routing protocol"
969	bridge mdb get dev br0 grp 239.1.1.1 vid 10 | grep -q "port br0"
970	check_err $? "Host entry flushed by wrong routing protocol"
971
972	bridge mdb flush dev br0
973
974	# Test that an error is returned when trying to flush using unsupported
975	# parameters.
976
977	bridge mdb flush dev br0 src_vni 10 &> /dev/null
978	check_fail $? "Managed to flush by source VNI"
979
980	bridge mdb flush dev br0 dst 198.51.100.1 &> /dev/null
981	check_fail $? "Managed to flush by destination IP"
982
983	bridge mdb flush dev br0 dst_port 4789 &> /dev/null
984	check_fail $? "Managed to flush by UDP destination port"
985
986	bridge mdb flush dev br0 vni 10 &> /dev/null
987	check_fail $? "Managed to flush by destination VNI"
988
989	log_test "Flush tests"
990}
991
992cfg_test()
993{
994	cfg_test_host
995	cfg_test_port
996	cfg_test_dump
997	cfg_test_flush
998}
999
1000__fwd_test_host_ip()
1001{
1002	local grp=$1; shift
1003	local dmac=$1; shift
1004	local src=$1; shift
1005	local mode=$1; shift
1006	local name
1007	local eth_type
1008
1009	RET=0
1010
1011	if [[ $mode == "-4" ]]; then
1012		name="IPv4"
1013		eth_type="ipv4"
1014	else
1015		name="IPv6"
1016		eth_type="ipv6"
1017	fi
1018
1019	tc filter add dev br0 ingress protocol 802.1q pref 1 handle 1 flower \
1020		vlan_ethtype $eth_type vlan_id 10 dst_ip $grp src_ip $src \
1021		action drop
1022
1023	# Packet should only be flooded to multicast router ports when there is
1024	# no matching MDB entry. The bridge is not configured as a multicast
1025	# router port.
1026	$MZ $mode $h1.10 -a own -b $dmac -c 1 -p 128 -A $src -B $grp -t udp -q
1027	tc_check_packets "dev br0 ingress" 1 0
1028	check_err $? "Packet locally received after flood"
1029
1030	# Install a regular port group entry and expect the packet to not be
1031	# locally received.
1032	bridge mdb add dev br0 port $swp2 grp $grp temp vid 10
1033	$MZ $mode $h1.10 -a own -b $dmac -c 1 -p 128 -A $src -B $grp -t udp -q
1034	tc_check_packets "dev br0 ingress" 1 0
1035	check_err $? "Packet locally received after installing a regular entry"
1036
1037	# Add a host entry and expect the packet to be locally received.
1038	bridge mdb add dev br0 port br0 grp $grp temp vid 10
1039	$MZ $mode $h1.10 -a own -b $dmac -c 1 -p 128 -A $src -B $grp -t udp -q
1040	tc_check_packets "dev br0 ingress" 1 1
1041	check_err $? "Packet not locally received after adding a host entry"
1042
1043	# Remove the host entry and expect the packet to not be locally
1044	# received.
1045	bridge mdb del dev br0 port br0 grp $grp vid 10
1046	$MZ $mode $h1.10 -a own -b $dmac -c 1 -p 128 -A $src -B $grp -t udp -q
1047	tc_check_packets "dev br0 ingress" 1 1
1048	check_err $? "Packet locally received after removing a host entry"
1049
1050	bridge mdb del dev br0 port $swp2 grp $grp vid 10
1051
1052	tc filter del dev br0 ingress protocol 802.1q pref 1 handle 1 flower
1053
1054	log_test "$name host entries forwarding tests"
1055}
1056
1057fwd_test_host_ip()
1058{
1059	__fwd_test_host_ip "239.1.1.1" "01:00:5e:01:01:01" "192.0.2.1" "-4"
1060	__fwd_test_host_ip "ff0e::1" "33:33:00:00:00:01" "2001:db8:1::1" "-6"
1061}
1062
1063fwd_test_host_l2()
1064{
1065	local dmac=01:02:03:04:05:06
1066
1067	RET=0
1068
1069	tc filter add dev br0 ingress protocol all pref 1 handle 1 flower \
1070		dst_mac $dmac action drop
1071
1072	# Packet should be flooded and locally received when there is no
1073	# matching MDB entry.
1074	$MZ $h1.10 -c 1 -p 128 -a own -b $dmac -q
1075	tc_check_packets "dev br0 ingress" 1 1
1076	check_err $? "Packet not locally received after flood"
1077
1078	# Install a regular port group entry and expect the packet to not be
1079	# locally received.
1080	bridge mdb add dev br0 port $swp2 grp $dmac permanent vid 10
1081	$MZ $h1.10 -c 1 -p 128 -a own -b $dmac -q
1082	tc_check_packets "dev br0 ingress" 1 1
1083	check_err $? "Packet locally received after installing a regular entry"
1084
1085	# Add a host entry and expect the packet to be locally received.
1086	bridge mdb add dev br0 port br0 grp $dmac permanent vid 10
1087	$MZ $h1.10 -c 1 -p 128 -a own -b $dmac -q
1088	tc_check_packets "dev br0 ingress" 1 2
1089	check_err $? "Packet not locally received after adding a host entry"
1090
1091	# Remove the host entry and expect the packet to not be locally
1092	# received.
1093	bridge mdb del dev br0 port br0 grp $dmac permanent vid 10
1094	$MZ $h1.10 -c 1 -p 128 -a own -b $dmac -q
1095	tc_check_packets "dev br0 ingress" 1 2
1096	check_err $? "Packet locally received after removing a host entry"
1097
1098	bridge mdb del dev br0 port $swp2 grp $dmac permanent vid 10
1099
1100	tc filter del dev br0 ingress protocol all pref 1 handle 1 flower
1101
1102	log_test "L2 host entries forwarding tests"
1103}
1104
1105fwd_test_host()
1106{
1107	# Disable multicast router on the bridge to ensure that packets are
1108	# only locally received when a matching host entry is present.
1109	ip link set dev br0 type bridge mcast_router 0
1110
1111	fwd_test_host_ip
1112	fwd_test_host_l2
1113
1114	ip link set dev br0 type bridge mcast_router 1
1115}
1116
1117__fwd_test_port_ip()
1118{
1119	local grp=$1; shift
1120	local dmac=$1; shift
1121	local valid_src=$1; shift
1122	local invalid_src=$1; shift
1123	local mode=$1; shift
1124	local filter_mode=$1; shift
1125	local name
1126	local eth_type
1127	local src_list
1128
1129	RET=0
1130
1131	if [[ $mode == "-4" ]]; then
1132		name="IPv4"
1133		eth_type="ipv4"
1134	else
1135		name="IPv6"
1136		eth_type="ipv6"
1137	fi
1138
1139	# The valid source is the one we expect to get packets from after
1140	# adding the entry.
1141	if [[ $filter_mode == "include" ]]; then
1142		src_list=$valid_src
1143	else
1144		src_list=$invalid_src
1145	fi
1146
1147	tc filter add dev $h2 ingress protocol 802.1q pref 1 handle 1 flower \
1148		vlan_ethtype $eth_type vlan_id 10 dst_ip $grp \
1149		src_ip $valid_src action drop
1150	tc filter add dev $h2 ingress protocol 802.1q pref 1 handle 2 flower \
1151		vlan_ethtype $eth_type vlan_id 10 dst_ip $grp \
1152		src_ip $invalid_src action drop
1153
1154	$MZ $mode $h1.10 -a own -b $dmac -c 1 -p 128 -A $valid_src -B $grp -t udp -q
1155	tc_check_packets "dev $h2 ingress" 1 0
1156	check_err $? "Packet from valid source received on H2 before adding entry"
1157
1158	$MZ $mode $h1.10 -a own -b $dmac -c 1 -p 128 -A $invalid_src -B $grp -t udp -q
1159	tc_check_packets "dev $h2 ingress" 2 0
1160	check_err $? "Packet from invalid source received on H2 before adding entry"
1161
1162	bridge mdb add dev br0 port $swp2 grp $grp vid 10 \
1163		filter_mode $filter_mode source_list $src_list
1164
1165	$MZ $mode $h1.10 -a own -b $dmac -c 1 -p 128 -A $valid_src -B $grp -t udp -q
1166	tc_check_packets "dev $h2 ingress" 1 1
1167	check_err $? "Packet from valid source not received on H2 after adding entry"
1168
1169	$MZ $mode $h1.10 -a own -b $dmac -c 1 -p 128 -A $invalid_src -B $grp -t udp -q
1170	tc_check_packets "dev $h2 ingress" 2 0
1171	check_err $? "Packet from invalid source received on H2 after adding entry"
1172
1173	bridge mdb replace dev br0 port $swp2 grp $grp vid 10 \
1174		filter_mode exclude
1175
1176	$MZ $mode $h1.10 -a own -b $dmac -c 1 -p 128 -A $valid_src -B $grp -t udp -q
1177	tc_check_packets "dev $h2 ingress" 1 2
1178	check_err $? "Packet from valid source not received on H2 after allowing all sources"
1179
1180	$MZ $mode $h1.10 -a own -b $dmac -c 1 -p 128 -A $invalid_src -B $grp -t udp -q
1181	tc_check_packets "dev $h2 ingress" 2 1
1182	check_err $? "Packet from invalid source not received on H2 after allowing all sources"
1183
1184	bridge mdb del dev br0 port $swp2 grp $grp vid 10
1185
1186	$MZ $mode $h1.10 -a own -b $dmac -c 1 -p 128 -A $valid_src -B $grp -t udp -q
1187	tc_check_packets "dev $h2 ingress" 1 2
1188	check_err $? "Packet from valid source received on H2 after deleting entry"
1189
1190	$MZ $mode $h1.10 -a own -b $dmac -c 1 -p 128 -A $invalid_src -B $grp -t udp -q
1191	tc_check_packets "dev $h2 ingress" 2 1
1192	check_err $? "Packet from invalid source received on H2 after deleting entry"
1193
1194	tc filter del dev $h2 ingress protocol 802.1q pref 1 handle 2 flower
1195	tc filter del dev $h2 ingress protocol 802.1q pref 1 handle 1 flower
1196
1197	log_test "$name port group \"$filter_mode\" entries forwarding tests"
1198}
1199
1200fwd_test_port_ip()
1201{
1202	__fwd_test_port_ip "239.1.1.1" "01:00:5e:01:01:01" "192.0.2.1" "192.0.2.2" "-4" "exclude"
1203	__fwd_test_port_ip "ff0e::1" "33:33:00:00:00:01" "2001:db8:1::1" "2001:db8:1::2" "-6" \
1204		"exclude"
1205	__fwd_test_port_ip "239.1.1.1" "01:00:5e:01:01:01" "192.0.2.1" "192.0.2.2" "-4" "include"
1206	__fwd_test_port_ip "ff0e::1" "33:33:00:00:00:01" "2001:db8:1::1" "2001:db8:1::2" "-6" \
1207		"include"
1208}
1209
1210fwd_test_port_l2()
1211{
1212	local dmac=01:02:03:04:05:06
1213
1214	RET=0
1215
1216	tc filter add dev $h2 ingress protocol all pref 1 handle 1 flower \
1217		dst_mac $dmac action drop
1218
1219	$MZ $h1.10 -c 1 -p 128 -a own -b $dmac -q
1220	tc_check_packets "dev $h2 ingress" 1 0
1221	check_err $? "Packet received on H2 before adding entry"
1222
1223	bridge mdb add dev br0 port $swp2 grp $dmac permanent vid 10
1224	$MZ $h1.10 -c 1 -p 128 -a own -b $dmac -q
1225	tc_check_packets "dev $h2 ingress" 1 1
1226	check_err $? "Packet not received on H2 after adding entry"
1227
1228	bridge mdb del dev br0 port $swp2 grp $dmac permanent vid 10
1229	$MZ $h1.10 -c 1 -p 128 -a own -b $dmac -q
1230	tc_check_packets "dev $h2 ingress" 1 1
1231	check_err $? "Packet received on H2 after deleting entry"
1232
1233	tc filter del dev $h2 ingress protocol all pref 1 handle 1 flower
1234
1235	log_test "L2 port entries forwarding tests"
1236}
1237
1238fwd_test_port()
1239{
1240	# Disable multicast flooding to ensure that packets are only forwarded
1241	# out of a port when a matching port group entry is present.
1242	bridge link set dev $swp2 mcast_flood off
1243
1244	fwd_test_port_ip
1245	fwd_test_port_l2
1246
1247	bridge link set dev $swp2 mcast_flood on
1248}
1249
1250fwd_test()
1251{
1252	echo
1253	log_info "# Forwarding tests"
1254
1255	# Set the Max Response Delay to 100 centiseconds (1 second) so that the
1256	# bridge will start forwarding according to its MDB soon after a
1257	# multicast querier is enabled.
1258	ip link set dev br0 type bridge mcast_query_response_interval 100
1259
1260	# Forwarding according to MDB entries only takes place when the bridge
1261	# detects that there is a valid querier in the network. Set the bridge
1262	# as the querier and assign it a valid IPv6 link-local address to be
1263	# used as the source address for MLD queries.
1264	ip -6 address add fe80::1/64 nodad dev br0
1265	ip link set dev br0 type bridge mcast_querier 1
1266	sleep 10
1267
1268	fwd_test_host
1269	fwd_test_port
1270
1271	ip link set dev br0 type bridge mcast_querier 0
1272	ip -6 address del fe80::1/64 dev br0
1273	ip link set dev br0 type bridge mcast_query_response_interval 1000
1274}
1275
1276ctrl_igmpv3_is_in_test()
1277{
1278	RET=0
1279
1280	# Add a permanent entry and check that it is not affected by the
1281	# received IGMP packet.
1282	bridge mdb add dev br0 port $swp1 grp 239.1.1.1 permanent vid 10 \
1283		filter_mode include source_list 192.0.2.1
1284
1285	# IS_IN ( 192.0.2.2 )
1286	$MZ $h1.10 -c 1 -a own -b 01:00:5e:01:01:01 -A 192.0.2.1 -B 239.1.1.1 \
1287		-t ip proto=2,p=$(igmpv3_is_in_get 239.1.1.1 192.0.2.2) -q
1288
1289	bridge mdb get dev br0 grp 239.1.1.1 src 192.0.2.2 vid 10 &> /dev/null
1290	check_fail $? "Permanent entry affected by IGMP packet"
1291
1292	# Replace the permanent entry with a temporary one and check that after
1293	# processing the IGMP packet, a new source is added to the list along
1294	# with a new forwarding entry.
1295	bridge mdb replace dev br0 port $swp1 grp 239.1.1.1 temp vid 10 \
1296		filter_mode include source_list 192.0.2.1
1297
1298	# IS_IN ( 192.0.2.2 )
1299	$MZ $h1.10 -a own -b 01:00:5e:01:01:01 -c 1 -A 192.0.2.1 -B 239.1.1.1 \
1300		-t ip proto=2,p=$(igmpv3_is_in_get 239.1.1.1 192.0.2.2) -q
1301
1302	bridge -d mdb get dev br0 grp 239.1.1.1 vid 10 | grep -q 192.0.2.2
1303	check_err $? "Source not add to source list"
1304
1305	bridge mdb get dev br0 grp 239.1.1.1 src 192.0.2.2 vid 10 &> /dev/null
1306	check_err $? "(S, G) entry not created for new source"
1307
1308	bridge mdb del dev br0 port $swp1 grp 239.1.1.1 vid 10
1309
1310	log_test "IGMPv3 MODE_IS_INCLUDE tests"
1311}
1312
1313ctrl_mldv2_is_in_test()
1314{
1315	RET=0
1316
1317	# Add a permanent entry and check that it is not affected by the
1318	# received MLD packet.
1319	bridge mdb add dev br0 port $swp1 grp ff0e::1 permanent vid 10 \
1320		filter_mode include source_list 2001:db8:1::1
1321
1322	# IS_IN ( 2001:db8:1::2 )
1323	local p=$(mldv2_is_in_get fe80::1 ff0e::1 2001:db8:1::2)
1324	$MZ -6 $h1.10 -a own -b 33:33:00:00:00:01 -c 1 -A fe80::1 -B ff0e::1 \
1325		-t ip hop=1,next=0,p="$p" -q
1326
1327	bridge mdb get dev br0 grp ff0e::1 src 2001:db8:1::2 vid 10 &> /dev/null
1328	check_fail $? "Permanent entry affected by MLD packet"
1329
1330	# Replace the permanent entry with a temporary one and check that after
1331	# processing the MLD packet, a new source is added to the list along
1332	# with a new forwarding entry.
1333	bridge mdb replace dev br0 port $swp1 grp ff0e::1 temp vid 10 \
1334		filter_mode include source_list 2001:db8:1::1
1335
1336	# IS_IN ( 2001:db8:1::2 )
1337	$MZ -6 $h1.10 -a own -b 33:33:00:00:00:01 -c 1 -A fe80::1 -B ff0e::1 \
1338		-t ip hop=1,next=0,p="$p" -q
1339
1340	bridge -d mdb get dev br0 grp ff0e::1 vid 10 | grep -q 2001:db8:1::2
1341	check_err $? "Source not add to source list"
1342
1343	bridge mdb get dev br0 grp ff0e::1 src 2001:db8:1::2 vid 10 &> /dev/null
1344	check_err $? "(S, G) entry not created for new source"
1345
1346	bridge mdb del dev br0 port $swp1 grp ff0e::1 vid 10
1347
1348	log_test "MLDv2 MODE_IS_INCLUDE tests"
1349}
1350
1351ctrl_test()
1352{
1353	echo
1354	log_info "# Control packets tests"
1355
1356	ctrl_igmpv3_is_in_test
1357	ctrl_mldv2_is_in_test
1358}
1359
1360if ! bridge mdb help 2>&1 | grep -q "flush"; then
1361	echo "SKIP: iproute2 too old, missing bridge mdb flush support"
1362	exit $ksft_skip
1363fi
1364
1365trap cleanup EXIT
1366
1367setup_prepare
1368setup_wait
1369tests_run
1370
1371exit $EXIT_STATUS
1372