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