xref: /linux/tools/testing/selftests/net/forwarding/router_multicast.sh (revision 8be4d31cb8aaeea27bde4b7ddb26e28a89062ebf)
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4# +------------------+
5# | H1 (v$h1)        |
6# | 2001:db8:1::2/64 |
7# | 198.51.100.2/28  |
8# |         $h1 +    |
9# +-------------|----+
10#               |
11# +-------------|-------------------------------+
12# | SW1         |                               |
13# |        $rp1 +                               |
14# | 198.51.100.1/28                             |
15# | 2001:db8:1::1/64                            |
16# |                                             |
17# | 2001:db8:2::1/64           2001:db8:3::1/64 |
18# | 198.51.100.17/28           198.51.100.33/28 |
19# |         $rp2 +                     $rp3 +   |
20# +--------------|--------------------------|---+
21#                |                          |
22#                |                          |
23# +--------------|---+       +--------------|---+
24# | H2 (v$h2)    |   |       | H3 (v$h3)    |   |
25# |          $h2 +   |       |          $h3 +   |
26# | 198.51.100.18/28 |       | 198.51.100.34/28 |
27# | 2001:db8:2::2/64 |       | 2001:db8:3::2/64 |
28# +------------------+       +------------------+
29#
30
31ALL_TESTS="mcast_v4 mcast_v6 rpf_v4 rpf_v6 unres_v4 unres_v6"
32NUM_NETIFS=6
33source lib.sh
34source tc_common.sh
35
36h1_create()
37{
38	simple_if_init $h1 198.51.100.2/28 2001:db8:1::2/64
39
40	ip route add 198.51.100.16/28 vrf v$h1 nexthop via 198.51.100.1
41	ip route add 198.51.100.32/28 vrf v$h1 nexthop via 198.51.100.1
42
43	ip route add 2001:db8:2::/64 vrf v$h1 nexthop via 2001:db8:1::1
44	ip route add 2001:db8:3::/64 vrf v$h1 nexthop via 2001:db8:1::1
45
46	tc qdisc add dev $h1 ingress
47}
48
49h1_destroy()
50{
51	tc qdisc del dev $h1 ingress
52
53	ip route del 2001:db8:3::/64 vrf v$h1
54	ip route del 2001:db8:2::/64 vrf v$h1
55
56	ip route del 198.51.100.32/28 vrf v$h1
57	ip route del 198.51.100.16/28 vrf v$h1
58
59	simple_if_fini $h1 198.51.100.2/28 2001:db8:1::2/64
60}
61
62h2_create()
63{
64	simple_if_init $h2 198.51.100.18/28 2001:db8:2::2/64
65
66	ip route add 198.51.100.0/28 vrf v$h2 nexthop via 198.51.100.17
67	ip route add 198.51.100.32/28 vrf v$h2 nexthop via 198.51.100.17
68
69	ip route add 2001:db8:1::/64 vrf v$h2 nexthop via 2001:db8:2::1
70	ip route add 2001:db8:3::/64 vrf v$h2 nexthop via 2001:db8:2::1
71
72	tc qdisc add dev $h2 ingress
73}
74
75h2_destroy()
76{
77	tc qdisc del dev $h2 ingress
78
79	ip route del 2001:db8:3::/64 vrf v$h2
80	ip route del 2001:db8:1::/64 vrf v$h2
81
82	ip route del 198.51.100.32/28 vrf v$h2
83	ip route del 198.51.100.0/28 vrf v$h2
84
85	simple_if_fini $h2 198.51.100.18/28 2001:db8:2::2/64
86}
87
88h3_create()
89{
90	simple_if_init $h3 198.51.100.34/28 2001:db8:3::2/64
91
92	ip route add 198.51.100.0/28 vrf v$h3 nexthop via 198.51.100.33
93	ip route add 198.51.100.16/28 vrf v$h3 nexthop via 198.51.100.33
94
95	ip route add 2001:db8:1::/64 vrf v$h3 nexthop via 2001:db8:3::1
96	ip route add 2001:db8:2::/64 vrf v$h3 nexthop via 2001:db8:3::1
97
98	tc qdisc add dev $h3 ingress
99}
100
101h3_destroy()
102{
103	tc qdisc del dev $h3 ingress
104
105	ip route del 2001:db8:2::/64 vrf v$h3
106	ip route del 2001:db8:1::/64 vrf v$h3
107
108	ip route del 198.51.100.16/28 vrf v$h3
109	ip route del 198.51.100.0/28 vrf v$h3
110
111	simple_if_fini $h3 198.51.100.34/28 2001:db8:3::2/64
112}
113
114router_create()
115{
116	ip link set dev $rp1 up
117	ip link set dev $rp2 up
118	ip link set dev $rp3 up
119
120	ip address add 198.51.100.1/28 dev $rp1
121	ip address add 198.51.100.17/28 dev $rp2
122	ip address add 198.51.100.33/28 dev $rp3
123
124	ip address add 2001:db8:1::1/64 dev $rp1
125	ip address add 2001:db8:2::1/64 dev $rp2
126	ip address add 2001:db8:3::1/64 dev $rp3
127
128	tc qdisc add dev $rp3 ingress
129}
130
131router_destroy()
132{
133	tc qdisc del dev $rp3 ingress
134
135	ip address del 2001:db8:3::1/64 dev $rp3
136	ip address del 2001:db8:2::1/64 dev $rp2
137	ip address del 2001:db8:1::1/64 dev $rp1
138
139	ip address del 198.51.100.33/28 dev $rp3
140	ip address del 198.51.100.17/28 dev $rp2
141	ip address del 198.51.100.1/28 dev $rp1
142
143	ip link set dev $rp3 down
144	ip link set dev $rp2 down
145	ip link set dev $rp1 down
146}
147
148setup_prepare()
149{
150	h1=${NETIFS[p1]}
151	rp1=${NETIFS[p2]}
152
153	rp2=${NETIFS[p3]}
154	h2=${NETIFS[p4]}
155
156	rp3=${NETIFS[p5]}
157	h3=${NETIFS[p6]}
158
159	adf_mcd_start || exit "$EXIT_STATUS"
160
161	vrf_prepare
162
163	h1_create
164	h2_create
165	h3_create
166
167	router_create
168
169	forwarding_enable
170}
171
172cleanup()
173{
174	pre_cleanup
175
176	forwarding_restore
177
178	router_destroy
179
180	h3_destroy
181	h2_destroy
182	h1_destroy
183
184	vrf_cleanup
185
186	defer_scopes_cleanup
187}
188
189create_mcast_sg()
190{
191	local if_name=$1; shift
192	local s_addr=$1; shift
193	local mcast=$1; shift
194	local dest_ifs=("${@}")
195
196	mc_cli add "$if_name" "$s_addr" "$mcast" "${dest_ifs[@]}"
197}
198
199delete_mcast_sg()
200{
201	local if_name=$1; shift
202	local s_addr=$1; shift
203	local mcast=$1; shift
204	local dest_ifs=("${@}")
205
206        mc_cli remove "$if_name" "$s_addr" "$mcast" "${dest_ifs[@]}"
207}
208
209mcast_v4()
210{
211	# Add two interfaces to an MC group, send a packet to the MC group and
212	# verify packets are received on both. Then delete the route and verify
213	# packets are no longer received.
214
215	RET=0
216
217	tc filter add dev $h2 ingress protocol ip pref 1 handle 122 flower \
218		dst_ip 225.1.2.3 action drop
219	tc filter add dev $h3 ingress protocol ip pref 1 handle 133 flower \
220		dst_ip 225.1.2.3 action drop
221
222	create_mcast_sg $rp1 198.51.100.2 225.1.2.3 $rp2 $rp3
223
224	# Send frames with the corresponding L2 destination address.
225	$MZ $h1 -c 5 -p 128 -t udp -a 00:11:22:33:44:55 -b 01:00:5e:01:02:03 \
226		-A 198.51.100.2 -B 225.1.2.3 -q
227
228	tc_check_packets "dev $h2 ingress" 122 5
229	check_err $? "Multicast not received on first host"
230	tc_check_packets "dev $h3 ingress" 133 5
231	check_err $? "Multicast not received on second host"
232
233	delete_mcast_sg $rp1 198.51.100.2 225.1.2.3 $rp2 $rp3
234
235	$MZ $h1 -c 5 -p 128 -t udp -a 00:11:22:33:44:55 -b 01:00:5e:01:02:03 \
236		-A 198.51.100.2 -B 225.1.2.3 -q
237
238	tc_check_packets "dev $h2 ingress" 122 5
239	check_err $? "Multicast received on host although deleted"
240	tc_check_packets "dev $h3 ingress" 133 5
241	check_err $? "Multicast received on second host although deleted"
242
243	tc filter del dev $h3 ingress protocol ip pref 1 handle 133 flower
244	tc filter del dev $h2 ingress protocol ip pref 1 handle 122 flower
245
246	log_test "mcast IPv4"
247}
248
249mcast_v6()
250{
251	# Add two interfaces to an MC group, send a packet to the MC group and
252	# verify packets are received on both. Then delete the route and verify
253	# packets are no longer received.
254
255	RET=0
256
257	tc filter add dev $h2 ingress protocol ipv6 pref 1 handle 122 flower \
258		dst_ip ff0e::3 action drop
259	tc filter add dev $h3 ingress protocol ipv6 pref 1 handle 133 flower \
260		dst_ip ff0e::3 action drop
261
262	create_mcast_sg $rp1 2001:db8:1::2 ff0e::3 $rp2 $rp3
263
264	# Send frames with the corresponding L2 destination address.
265	$MZ $h1 -6 -c 5 -p 128 -t udp -a 00:11:22:33:44:55 \
266		-b 33:33:00:00:00:03 -A 2001:db8:1::2 -B ff0e::3 -q
267
268	tc_check_packets "dev $h2 ingress" 122 5
269	check_err $? "Multicast not received on first host"
270	tc_check_packets "dev $h3 ingress" 133 5
271	check_err $? "Multicast not received on second host"
272
273	delete_mcast_sg $rp1 2001:db8:1::2 ff0e::3 $rp2 $rp3
274
275	$MZ $h1 -6 -c 5 -p 128 -t udp -a 00:11:22:33:44:55 \
276		-b 33:33:00:00:00:03 -A 2001:db8:1::2 -B ff0e::3 -q
277
278	tc_check_packets "dev $h2 ingress" 122 5
279	check_err $? "Multicast received on first host although deleted"
280	tc_check_packets "dev $h3 ingress" 133 5
281	check_err $? "Multicast received on second host although deleted"
282
283	tc filter del dev $h3 ingress protocol ipv6 pref 1 handle 133 flower
284	tc filter del dev $h2 ingress protocol ipv6 pref 1 handle 122 flower
285
286	log_test "mcast IPv6"
287}
288
289rpf_v4()
290{
291	# Add a multicast route from first router port to the other two. Send
292	# matching packets and test that both hosts receive them. Then, send
293	# the same packets via the third router port and test that they do not
294	# reach any host due to RPF check. A filter with 'skip_hw' is added to
295	# test that devices capable of multicast routing offload trap those
296	# packets. The filter is essentialy a NOP in other scenarios.
297
298	RET=0
299
300	tc filter add dev $h1 ingress protocol ip pref 1 handle 1 flower \
301		dst_ip 225.1.2.3 ip_proto udp dst_port 12345 action drop
302	tc filter add dev $h2 ingress protocol ip pref 1 handle 1 flower \
303		dst_ip 225.1.2.3 ip_proto udp dst_port 12345 action drop
304	tc filter add dev $h3 ingress protocol ip pref 1 handle 1 flower \
305		dst_ip 225.1.2.3 ip_proto udp dst_port 12345 action drop
306	tc filter add dev $rp3 ingress protocol ip pref 1 handle 1 flower \
307		skip_hw dst_ip 225.1.2.3 ip_proto udp dst_port 12345 action pass
308
309	create_mcast_sg $rp1 198.51.100.2 225.1.2.3 $rp2 $rp3
310
311	$MZ $h1 -c 5 -p 128 -t udp "ttl=10,sp=54321,dp=12345" \
312		-a 00:11:22:33:44:55 -b 01:00:5e:01:02:03 \
313		-A 198.51.100.2 -B 225.1.2.3 -q
314
315	tc_check_packets "dev $h2 ingress" 1 5
316	check_err $? "Multicast not received on first host"
317	tc_check_packets "dev $h3 ingress" 1 5
318	check_err $? "Multicast not received on second host"
319
320	$MZ $h3 -c 5 -p 128 -t udp "ttl=10,sp=54321,dp=12345" \
321		-a 00:11:22:33:44:55 -b 01:00:5e:01:02:03 \
322		-A 198.51.100.2 -B 225.1.2.3 -q
323
324	tc_check_packets "dev $h1 ingress" 1 0
325	check_err $? "Multicast received on first host when should not"
326	tc_check_packets "dev $h2 ingress" 1 5
327	check_err $? "Multicast received on second host when should not"
328	tc_check_packets "dev $rp3 ingress" 1 5
329	check_err $? "Packets not trapped due to RPF check"
330
331	delete_mcast_sg $rp1 198.51.100.2 225.1.2.3 $rp2 $rp3
332
333	tc filter del dev $rp3 ingress protocol ip pref 1 handle 1 flower
334	tc filter del dev $h3 ingress protocol ip pref 1 handle 1 flower
335	tc filter del dev $h2 ingress protocol ip pref 1 handle 1 flower
336	tc filter del dev $h1 ingress protocol ip pref 1 handle 1 flower
337
338	log_test "RPF IPv4"
339}
340
341rpf_v6()
342{
343	RET=0
344
345	tc filter add dev $h1 ingress protocol ipv6 pref 1 handle 1 flower \
346		dst_ip ff0e::3 ip_proto udp dst_port 12345 action drop
347	tc filter add dev $h2 ingress protocol ipv6 pref 1 handle 1 flower \
348		dst_ip ff0e::3 ip_proto udp dst_port 12345 action drop
349	tc filter add dev $h3 ingress protocol ipv6 pref 1 handle 1 flower \
350		dst_ip ff0e::3 ip_proto udp dst_port 12345 action drop
351	tc filter add dev $rp3 ingress protocol ipv6 pref 1 handle 1 flower \
352		skip_hw dst_ip ff0e::3 ip_proto udp dst_port 12345 action pass
353
354	create_mcast_sg $rp1 2001:db8:1::2 ff0e::3 $rp2 $rp3
355
356	$MZ $h1 -6 -c 5 -p 128 -t udp "ttl=10,sp=54321,dp=12345" \
357		-a 00:11:22:33:44:55 -b 33:33:00:00:00:03 \
358		-A 2001:db8:1::2 -B ff0e::3 -q
359
360	tc_check_packets "dev $h2 ingress" 1 5
361	check_err $? "Multicast not received on first host"
362	tc_check_packets "dev $h3 ingress" 1 5
363	check_err $? "Multicast not received on second host"
364
365	$MZ $h3 -6 -c 5 -p 128 -t udp "ttl=10,sp=54321,dp=12345" \
366		-a 00:11:22:33:44:55 -b 33:33:00:00:00:03 \
367		-A 2001:db8:1::2 -B ff0e::3 -q
368
369	tc_check_packets "dev $h1 ingress" 1 0
370	check_err $? "Multicast received on first host when should not"
371	tc_check_packets "dev $h2 ingress" 1 5
372	check_err $? "Multicast received on second host when should not"
373	tc_check_packets "dev $rp3 ingress" 1 5
374	check_err $? "Packets not trapped due to RPF check"
375
376	delete_mcast_sg $rp1 2001:db8:1::2 ff0e::3 $rp2 $rp3
377
378	tc filter del dev $rp3 ingress protocol ipv6 pref 1 handle 1 flower
379	tc filter del dev $h3 ingress protocol ipv6 pref 1 handle 1 flower
380	tc filter del dev $h2 ingress protocol ipv6 pref 1 handle 1 flower
381	tc filter del dev $h1 ingress protocol ipv6 pref 1 handle 1 flower
382
383	log_test "RPF IPv6"
384}
385
386unres_v4()
387{
388	# Send a multicast packet not corresponding to an installed route,
389	# causing the kernel to queue the packet for resolution and emit an
390	# IGMPMSG_NOCACHE notification. smcrouted will react to this
391	# notification by consulting its (*, G) list and installing an (S, G)
392	# route, which will be used to forward the queued packet.
393
394	RET=0
395
396	tc filter add dev $h2 ingress protocol ip pref 1 handle 1 flower \
397		dst_ip 225.1.2.3 ip_proto udp dst_port 12345 action drop
398	tc filter add dev $h3 ingress protocol ip pref 1 handle 1 flower \
399		dst_ip 225.1.2.3 ip_proto udp dst_port 12345 action drop
400
401	# Forwarding should fail before installing a matching (*, G).
402	$MZ $h1 -c 1 -p 128 -t udp "ttl=10,sp=54321,dp=12345" \
403		-a 00:11:22:33:44:55 -b 01:00:5e:01:02:03 \
404		-A 198.51.100.2 -B 225.1.2.3 -q
405
406	tc_check_packets "dev $h2 ingress" 1 0
407	check_err $? "Multicast received on first host when should not"
408	tc_check_packets "dev $h3 ingress" 1 0
409	check_err $? "Multicast received on second host when should not"
410
411	# Create (*, G). Will not be installed in the kernel.
412	create_mcast_sg $rp1 0.0.0.0 225.1.2.3 $rp2 $rp3
413
414	$MZ $h1 -c 1 -p 128 -t udp "ttl=10,sp=54321,dp=12345" \
415		-a 00:11:22:33:44:55 -b 01:00:5e:01:02:03 \
416		-A 198.51.100.2 -B 225.1.2.3 -q
417
418	tc_check_packets "dev $h2 ingress" 1 1
419	check_err $? "Multicast not received on first host"
420	tc_check_packets "dev $h3 ingress" 1 1
421	check_err $? "Multicast not received on second host"
422
423	delete_mcast_sg $rp1 0.0.0.0 225.1.2.3 $rp2 $rp3
424
425	tc filter del dev $h3 ingress protocol ip pref 1 handle 1 flower
426	tc filter del dev $h2 ingress protocol ip pref 1 handle 1 flower
427
428	log_test "Unresolved queue IPv4"
429}
430
431unres_v6()
432{
433	# Send a multicast packet not corresponding to an installed route,
434	# causing the kernel to queue the packet for resolution and emit an
435	# MRT6MSG_NOCACHE notification. smcrouted will react to this
436	# notification by consulting its (*, G) list and installing an (S, G)
437	# route, which will be used to forward the queued packet.
438
439	RET=0
440
441	tc filter add dev $h2 ingress protocol ipv6 pref 1 handle 1 flower \
442		dst_ip ff0e::3 ip_proto udp dst_port 12345 action drop
443	tc filter add dev $h3 ingress protocol ipv6 pref 1 handle 1 flower \
444		dst_ip ff0e::3 ip_proto udp dst_port 12345 action drop
445
446	# Forwarding should fail before installing a matching (*, G).
447	$MZ $h1 -6 -c 1 -p 128 -t udp "ttl=10,sp=54321,dp=12345" \
448		-a 00:11:22:33:44:55 -b 33:33:00:00:00:03 \
449		-A 2001:db8:1::2 -B ff0e::3 -q
450
451	tc_check_packets "dev $h2 ingress" 1 0
452	check_err $? "Multicast received on first host when should not"
453	tc_check_packets "dev $h3 ingress" 1 0
454	check_err $? "Multicast received on second host when should not"
455
456	# Create (*, G). Will not be installed in the kernel.
457	create_mcast_sg $rp1 :: ff0e::3 $rp2 $rp3
458
459	$MZ $h1 -6 -c 1 -p 128 -t udp "ttl=10,sp=54321,dp=12345" \
460		-a 00:11:22:33:44:55 -b 33:33:00:00:00:03 \
461		-A 2001:db8:1::2 -B ff0e::3 -q
462
463	tc_check_packets "dev $h2 ingress" 1 1
464	check_err $? "Multicast not received on first host"
465	tc_check_packets "dev $h3 ingress" 1 1
466	check_err $? "Multicast not received on second host"
467
468	delete_mcast_sg $rp1 :: ff0e::3 $rp2 $rp3
469
470	tc filter del dev $h3 ingress protocol ipv6 pref 1 handle 1 flower
471	tc filter del dev $h2 ingress protocol ipv6 pref 1 handle 1 flower
472
473	log_test "Unresolved queue IPv6"
474}
475
476trap cleanup EXIT
477
478setup_prepare
479setup_wait
480
481tests_run
482
483exit $EXIT_STATUS
484