1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4ALL_TESTS="mldv2include_test mldv2inc_allow_test mldv2inc_is_include_test mldv2inc_is_exclude_test \
5	   mldv2inc_to_exclude_test mldv2exc_allow_test mldv2exc_is_include_test \
6	   mldv2exc_is_exclude_test mldv2exc_to_exclude_test"
7NUM_NETIFS=4
8CHECK_TC="yes"
9TEST_GROUP="ff02::cc"
10TEST_GROUP_MAC="33:33:00:00:00:cc"
11
12# MLDv2 is_in report: grp ff02::cc is_include 2001:db8:1::1,2001:db8:1::2,2001:db8:1::3
13MZPKT_IS_INC="33:33:00:00:00:01:fe:54:00:04:5e:ba:86:dd:60:0a:2d:ae:00:54:00:01:fe:80:00:\
1400:00:00:00:00:fc:54:00:ff:fe:04:5e:ba:ff:02:00:00:00:00:00:00:00:00:00:00:00:00:00:01:3a:\
1500:05:02:00:00:00:00:8f:00:8e:d9:00:00:00:01:01:00:00:03:ff:02:00:00:00:00:00:00:00:00:00:\
1600:00:00:00:cc:20:01:0d:b8:00:01:00:00:00:00:00:00:00:00:00:01:20:01:0d:b8:00:01:00:00:00:\
1700:00:00:00:00:00:02:20:01:0d:b8:00:01:00:00:00:00:00:00:00:00:00:03"
18# MLDv2 is_in report: grp ff02::cc is_include 2001:db8:1::10,2001:db8:1::11,2001:db8:1::12
19MZPKT_IS_INC2="33:33:00:00:00:01:fe:54:00:04:5e:ba:86:dd:60:0a:2d:ae:00:54:00:01:fe:80:00:\
2000:00:00:00:00:fc:54:00:ff:fe:04:5e:ba:ff:02:00:00:00:00:00:00:00:00:00:00:00:00:00:01:3a:00:\
2105:02:00:00:00:00:8f:00:8e:ac:00:00:00:01:01:00:00:03:ff:02:00:00:00:00:00:00:00:00:00:00:00:\
2200:00:cc:20:01:0d:b8:00:01:00:00:00:00:00:00:00:00:00:10:20:01:0d:b8:00:01:00:00:00:00:00:00:\
2300:00:00:11:20:01:0d:b8:00:01:00:00:00:00:00:00:00:00:00:12"
24# MLDv2 is_in report: grp ff02::cc is_include 2001:db8:1::20,2001:db8:1::30
25MZPKT_IS_INC3="33:33:00:00:00:01:fe:54:00:04:5e:ba:86:dd:60:0a:2d:ae:00:44:00:01:fe:80:00:00:00:\
2600:00:00:fc:54:00:ff:fe:04:5e:ba:ff:02:00:00:00:00:00:00:00:00:00:00:00:00:00:01:3a:00:05:02:00:\
2700:00:00:8f:00:bc:5a:00:00:00:01:01:00:00:02:ff:02:00:00:00:00:00:00:00:00:00:00:00:00:00:cc:20:\
2801:0d:b8:00:01:00:00:00:00:00:00:00:00:00:20:20:01:0d:b8:00:01:00:00:00:00:00:00:00:00:00:30"
29# MLDv2 allow report: grp ff02::cc allow 2001:db8:1::10,2001:db8:1::11,2001:db8:1::12
30MZPKT_ALLOW="33:33:00:00:00:01:fe:54:00:04:5e:ba:86:dd:60:0a:2d:ae:00:54:00:01:fe:80:00:00:\
3100:00:00:00:fc:54:00:ff:fe:04:5e:ba:ff:02:00:00:00:00:00:00:00:00:00:00:00:00:00:01:3a:00:05:\
3202:00:00:00:00:8f:00:8a:ac:00:00:00:01:05:00:00:03:ff:02:00:00:00:00:00:00:00:00:00:00:00:00:\
3300:cc:20:01:0d:b8:00:01:00:00:00:00:00:00:00:00:00:10:20:01:0d:b8:00:01:00:00:00:00:00:00:00:\
3400:00:11:20:01:0d:b8:00:01:00:00:00:00:00:00:00:00:00:12"
35# MLDv2 allow report: grp ff02::cc allow 2001:db8:1::20,2001:db8:1::30
36MZPKT_ALLOW2="33:33:00:00:00:01:fe:54:00:04:5e:ba:86:dd:60:0a:2d:ae:00:44:00:01:fe:80:00:00:00:\
3700:00:00:fc:54:00:ff:fe:04:5e:ba:ff:02:00:00:00:00:00:00:00:00:00:00:00:00:00:01:3a:00:05:02:00:\
3800:00:00:8f:00:b8:5a:00:00:00:01:05:00:00:02:ff:02:00:00:00:00:00:00:00:00:00:00:00:00:00:cc:20:\
3901:0d:b8:00:01:00:00:00:00:00:00:00:00:00:20:20:01:0d:b8:00:01:00:00:00:00:00:00:00:00:00:30"
40# MLDv2 is_ex report: grp ff02::cc is_exclude 2001:db8:1::1,2001:db8:1::2,2001:db8:1::20,2001:db8:1::21
41MZPKT_IS_EXC="33:33:00:00:00:01:fe:54:00:04:5e:ba:86:dd:60:0a:2d:ae:00:64:00:01:fe:80:00:00:00:\
4200:00:00:fc:54:00:ff:fe:04:5e:ba:ff:02:00:00:00:00:00:00:00:00:00:00:00:00:00:01:3a:00:05:02:00:\
4300:00:00:8f:00:5f:d0:00:00:00:01:02:00:00:04:ff:02:00:00:00:00:00:00:00:00:00:00:00:00:00:cc:20:\
4401:0d:b8:00:01:00:00:00:00:00:00:00:00:00:01:20:01:0d:b8:00:01:00:00:00:00:00:00:00:00:00:02:20:\
4501:0d:b8:00:01:00:00:00:00:00:00:00:00:00:20:20:01:0d:b8:00:01:00:00:00:00:00:00:00:00:00:21"
46# MLDv2 is_ex report: grp ff02::cc is_exclude 2001:db8:1::20,2001:db8:1::30
47MZPKT_IS_EXC2="33:33:00:00:00:01:fe:54:00:04:5e:ba:86:dd:60:0a:2d:ae:00:44:00:01:fe:80:00:00:00:\
4800:00:00:fc:54:00:ff:fe:04:5e:ba:ff:02:00:00:00:00:00:00:00:00:00:00:00:00:00:01:3a:00:05:02:00:\
4900:00:00:8f:00:bb:5a:00:00:00:01:02:00:00:02:ff:02:00:00:00:00:00:00:00:00:00:00:00:00:00:cc:20:\
5001:0d:b8:00:01:00:00:00:00:00:00:00:00:00:20:20:01:0d:b8:00:01:00:00:00:00:00:00:00:00:00:30"
51# MLDv2 to_ex report: grp ff02::cc to_exclude 2001:db8:1::1,2001:db8:1::20,2001:db8:1::30
52MZPKT_TO_EXC="33:33:00:00:00:01:fe:54:00:04:5e:ba:86:dd:60:0a:2d:ae:00:54:00:01:fe:80:00:00:00:\
5300:00:00:fc:54:00:ff:fe:04:5e:ba:ff:02:00:00:00:00:00:00:00:00:00:00:00:00:00:01:3a:00:05:02:00:\
5400:00:00:8f:00:8b:8e:00:00:00:01:04:00:00:03:ff:02:00:00:00:00:00:00:00:00:00:00:00:00:00:cc:20:\
5501:0d:b8:00:01:00:00:00:00:00:00:00:00:00:01:20:01:0d:b8:00:01:00:00:00:00:00:00:00:00:00:20:20:\
5601:0d:b8:00:01:00:00:00:00:00:00:00:00:00:30"
57
58source lib.sh
59
60h1_create()
61{
62	simple_if_init $h1 2001:db8:1::1/64
63}
64
65h1_destroy()
66{
67	simple_if_fini $h1 2001:db8:1::1/64
68}
69
70h2_create()
71{
72	simple_if_init $h2 2001:db8:1::2/64
73}
74
75h2_destroy()
76{
77	simple_if_fini $h2 2001:db8:1::2/64
78}
79
80switch_create()
81{
82	ip link add dev br0 type bridge mcast_snooping 1 mcast_query_response_interval 100 \
83					mcast_mld_version 2 mcast_startup_query_interval 300 \
84					mcast_querier 1
85
86	ip link set dev $swp1 master br0
87	ip link set dev $swp2 master br0
88
89	ip link set dev br0 up
90	ip link set dev $swp1 up
91	ip link set dev $swp2 up
92
93	# make sure a query has been generated
94	sleep 5
95}
96
97switch_destroy()
98{
99	ip link set dev $swp2 down
100	ip link set dev $swp1 down
101
102	ip link del dev br0
103}
104
105setup_prepare()
106{
107	h1=${NETIFS[p1]}
108	swp1=${NETIFS[p2]}
109
110	swp2=${NETIFS[p3]}
111	h2=${NETIFS[p4]}
112
113	vrf_prepare
114
115	h1_create
116	h2_create
117
118	switch_create
119}
120
121cleanup()
122{
123	pre_cleanup
124
125	switch_destroy
126
127	h2_destroy
128	h1_destroy
129
130	vrf_cleanup
131}
132
133mldv2include_prepare()
134{
135	local host1_if=$1
136	local X=("2001:db8:1::1" "2001:db8:1::2" "2001:db8:1::3")
137
138	ip link set dev br0 type bridge mcast_mld_version 2
139	check_err $? "Could not change bridge MLD version to 2"
140
141	$MZ $host1_if $MZPKT_IS_INC -q
142	sleep 1
143	bridge -j -d -s mdb show dev br0 \
144		| jq -e ".[].mdb[] | \
145			 select(.grp == \"$TEST_GROUP\" and .source_list != null)" &>/dev/null
146	check_err $? "Missing *,G entry with source list"
147	bridge -j -d -s mdb show dev br0 \
148		| jq -e ".[].mdb[] | \
149			 select(.grp == \"$TEST_GROUP\" and \
150				.source_list != null and .filter_mode == \"include\")" &>/dev/null
151	check_err $? "Wrong *,G entry filter mode"
152	brmcast_check_sg_entries "is_include" "${X[@]}"
153}
154
155mldv2exclude_prepare()
156{
157	local host1_if=$1
158	local mac=$2
159	local group=$3
160	local pkt=$4
161	local X=("2001:db8:1::1" "2001:db8:1::2")
162	local Y=("2001:db8:1::20" "2001:db8:1::21")
163
164	mldv2include_prepare $h1
165
166	$MZ $host1_if -c 1 $MZPKT_IS_EXC -q
167	sleep 1
168	bridge -j -d -s mdb show dev br0 \
169		| jq -e ".[].mdb[] | \
170			 select(.grp == \"$TEST_GROUP\" and \
171			 .source_list != null and .filter_mode == \"exclude\")" &>/dev/null
172	check_err $? "Wrong *,G entry filter mode"
173
174	brmcast_check_sg_entries "is_exclude" "${X[@]}" "${Y[@]}"
175
176	brmcast_check_sg_state 0 "${X[@]}"
177	brmcast_check_sg_state 1 "${Y[@]}"
178
179	bridge -j -d -s mdb show dev br0 \
180		| jq -e ".[].mdb[] | \
181			 select(.grp == \"$TEST_GROUP\" and \
182				.source_list != null and
183				.source_list[].address == \"2001:db8:1::3\")" &>/dev/null
184	check_fail $? "Wrong *,G entry source list, 2001:db8:1::3 entry still exists"
185}
186
187mldv2cleanup()
188{
189	local port=$1
190
191	bridge mdb del dev br0 port $port grp $TEST_GROUP
192	ip link set dev br0 type bridge mcast_mld_version 1
193}
194
195mldv2include_test()
196{
197	RET=0
198	local X=("2001:db8:1::1" "2001:db8:1::2" "2001:db8:1::3")
199
200	mldv2include_prepare $h1
201
202	brmcast_check_sg_state 0 "${X[@]}"
203
204	brmcast_check_sg_fwding 1 "${X[@]}"
205	brmcast_check_sg_fwding 0 "2001:db8:1::100"
206
207	log_test "MLDv2 report $TEST_GROUP is_include"
208
209	mldv2cleanup $swp1
210}
211
212mldv2inc_allow_test()
213{
214	RET=0
215	local X=("2001:db8:1::10" "2001:db8:1::11" "2001:db8:1::12")
216
217	mldv2include_prepare $h1
218
219	$MZ $h1 -c 1 $MZPKT_ALLOW -q
220	sleep 1
221	brmcast_check_sg_entries "allow" "${X[@]}"
222
223	brmcast_check_sg_state 0 "${X[@]}"
224
225	brmcast_check_sg_fwding 1 "${X[@]}"
226	brmcast_check_sg_fwding 0 "2001:db8:1::100"
227
228	log_test "MLDv2 report $TEST_GROUP include -> allow"
229
230	mldv2cleanup $swp1
231}
232
233mldv2inc_is_include_test()
234{
235	RET=0
236	local X=("2001:db8:1::10" "2001:db8:1::11" "2001:db8:1::12")
237
238	mldv2include_prepare $h1
239
240	$MZ $h1 -c 1 $MZPKT_IS_INC2 -q
241	sleep 1
242	brmcast_check_sg_entries "is_include" "${X[@]}"
243
244	brmcast_check_sg_state 0 "${X[@]}"
245
246	brmcast_check_sg_fwding 1 "${X[@]}"
247	brmcast_check_sg_fwding 0 "2001:db8:1::100"
248
249	log_test "MLDv2 report $TEST_GROUP include -> is_include"
250
251	mldv2cleanup $swp1
252}
253
254mldv2inc_is_exclude_test()
255{
256	RET=0
257
258	mldv2exclude_prepare $h1
259
260	brmcast_check_sg_fwding 1 "${X[@]}" 2001:db8:1::100
261	brmcast_check_sg_fwding 0 "${Y[@]}"
262
263	log_test "MLDv2 report $TEST_GROUP include -> is_exclude"
264
265	mldv2cleanup $swp1
266}
267
268mldv2inc_to_exclude_test()
269{
270	RET=0
271	local X=("2001:db8:1::1")
272	local Y=("2001:db8:1::20" "2001:db8:1::30")
273
274	mldv2include_prepare $h1
275
276	ip link set dev br0 type bridge mcast_last_member_interval 500
277	check_err $? "Could not change mcast_last_member_interval to 5s"
278
279	$MZ $h1 -c 1 $MZPKT_TO_EXC -q
280	sleep 1
281	bridge -j -d -s mdb show dev br0 \
282		| jq -e ".[].mdb[] | \
283			 select(.grp == \"$TEST_GROUP\" and \
284				.source_list != null and .filter_mode == \"exclude\")" &>/dev/null
285	check_err $? "Wrong *,G entry filter mode"
286
287	brmcast_check_sg_entries "to_exclude" "${X[@]}" "${Y[@]}"
288
289	brmcast_check_sg_state 0 "${X[@]}"
290	brmcast_check_sg_state 1 "${Y[@]}"
291
292	bridge -j -d -s mdb show dev br0 \
293		| jq -e ".[].mdb[] | \
294			 select(.grp == \"$TEST_GROUP\" and \
295				.source_list != null and
296				.source_list[].address == \"2001:db8:1::2\")" &>/dev/null
297	check_fail $? "Wrong *,G entry source list, 2001:db8:1::2 entry still exists"
298	bridge -j -d -s mdb show dev br0 \
299		| jq -e ".[].mdb[] | \
300			 select(.grp == \"$TEST_GROUP\" and \
301				.source_list != null and
302				.source_list[].address == \"2001:db8:1::21\")" &>/dev/null
303	check_fail $? "Wrong *,G entry source list, 2001:db8:1::21 entry still exists"
304
305	brmcast_check_sg_fwding 1 "${X[@]}" 2001:db8:1::100
306	brmcast_check_sg_fwding 0 "${Y[@]}"
307
308	log_test "MLDv2 report $TEST_GROUP include -> to_exclude"
309
310	ip link set dev br0 type bridge mcast_last_member_interval 100
311
312	mldv2cleanup $swp1
313}
314
315mldv2exc_allow_test()
316{
317	RET=0
318	local X=("2001:db8:1::1" "2001:db8:1::2" "2001:db8:1::20" "2001:db8:1::30")
319	local Y=("2001:db8:1::21")
320
321	mldv2exclude_prepare $h1
322
323	$MZ $h1 -c 1 $MZPKT_ALLOW2 -q
324	sleep 1
325	brmcast_check_sg_entries "allow" "${X[@]}" "${Y[@]}"
326
327	brmcast_check_sg_state 0 "${X[@]}"
328	brmcast_check_sg_state 1 "${Y[@]}"
329
330	brmcast_check_sg_fwding 1 "${X[@]}" 2001:db8:1::100
331	brmcast_check_sg_fwding 0 "${Y[@]}"
332
333	log_test "MLDv2 report $TEST_GROUP exclude -> allow"
334
335	mldv2cleanup $swp1
336}
337
338mldv2exc_is_include_test()
339{
340	RET=0
341	local X=("2001:db8:1::1" "2001:db8:1::2" "2001:db8:1::20" "2001:db8:1::30")
342	local Y=("2001:db8:1::21")
343
344	mldv2exclude_prepare $h1
345
346	$MZ $h1 -c 1 $MZPKT_IS_INC3 -q
347	sleep 1
348	brmcast_check_sg_entries "is_include" "${X[@]}" "${Y[@]}"
349
350	brmcast_check_sg_state 0 "${X[@]}"
351	brmcast_check_sg_state 1 "${Y[@]}"
352
353	brmcast_check_sg_fwding 1 "${X[@]}" 2001:db8:1::100
354	brmcast_check_sg_fwding 0 "${Y[@]}"
355
356	log_test "MLDv2 report $TEST_GROUP exclude -> is_include"
357
358	mldv2cleanup $swp1
359}
360
361mldv2exc_is_exclude_test()
362{
363	RET=0
364	local X=("2001:db8:1::30")
365	local Y=("2001:db8:1::20")
366
367	mldv2exclude_prepare $h1
368
369	$MZ $h1 -c 1 $MZPKT_IS_EXC2 -q
370	sleep 1
371	brmcast_check_sg_entries "is_exclude" "${X[@]}" "${Y[@]}"
372
373	brmcast_check_sg_state 0 "${X[@]}"
374	brmcast_check_sg_state 1 "${Y[@]}"
375
376	brmcast_check_sg_fwding 1 "${X[@]}" 2001:db8:1::100
377	brmcast_check_sg_fwding 0 "${Y[@]}"
378
379	log_test "MLDv2 report $TEST_GROUP exclude -> is_exclude"
380
381	mldv2cleanup $swp1
382}
383
384mldv2exc_to_exclude_test()
385{
386	RET=0
387	local X=("2001:db8:1::1" "2001:db8:1::30")
388	local Y=("2001:db8:1::20")
389
390	mldv2exclude_prepare $h1
391
392	ip link set dev br0 type bridge mcast_last_member_interval 500
393	check_err $? "Could not change mcast_last_member_interval to 5s"
394
395	$MZ $h1 -c 1 $MZPKT_TO_EXC -q
396	sleep 1
397	brmcast_check_sg_entries "to_exclude" "${X[@]}" "${Y[@]}"
398
399	brmcast_check_sg_state 0 "${X[@]}"
400	brmcast_check_sg_state 1 "${Y[@]}"
401
402	brmcast_check_sg_fwding 1 "${X[@]}" 2001:db8:1::100
403	brmcast_check_sg_fwding 0 "${Y[@]}"
404
405	log_test "MLDv2 report $TEST_GROUP exclude -> to_exclude"
406
407	ip link set dev br0 type bridge mcast_last_member_interval 100
408
409	mldv2cleanup $swp1
410}
411
412trap cleanup EXIT
413
414setup_prepare
415setup_wait
416
417tests_run
418
419exit $EXIT_STATUS
420