xref: /linux/tools/testing/selftests/net/amt.sh (revision 7e170da2edec9fb0717543571cc14b0aabee2b46)
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4# Author: Taehee Yoo <ap420073@gmail.com>
5#
6# This script evaluates the AMT driver.
7# There are four network-namespaces, LISTENER, SOURCE, GATEWAY, RELAY.
8# The role of LISTENER is to listen multicast traffic.
9# In order to do that, it send IGMP group join message.
10# The role of SOURCE is to send multicast traffic to listener.
11# The role of GATEWAY is to work Gateway role of AMT interface.
12# The role of RELAY is to work Relay role of AMT interface.
13#
14#
15#       +------------------------+
16#       |    LISTENER netns      |
17#       |                        |
18#       |  +------------------+  |
19#       |  |       l_gw       |  |
20#       |  |  192.168.0.2/24  |  |
21#       |  |  2001:db8::2/64  |  |
22#       |  +------------------+  |
23#       |            .           |
24#       +------------------------+
25#                    .
26#                    .
27#       +-----------------------------------------------------+
28#       |            .         GATEWAY netns                  |
29#       |            .                                        |
30#       |+---------------------------------------------------+|
31#       ||           .          br0                          ||
32#       || +------------------+       +------------------+   ||
33#       || |       gw_l       |       |       amtg       |   ||
34#       || |  192.168.0.1/24  |       +--------+---------+   ||
35#       || |  2001:db8::1/64  |                |             ||
36#       || +------------------+                |             ||
37#       |+-------------------------------------|-------------+|
38#       |                                      |              |
39#       |                             +--------+---------+    |
40#       |                             |     gw_relay     |    |
41#       |                             |    10.0.0.1/24   |    |
42#       |                             +------------------+    |
43#       |                                      .              |
44#       +-----------------------------------------------------+
45#                                              .
46#                                              .
47#       +-----------------------------------------------------+
48#       |                       RELAY netns    .              |
49#       |                             +------------------+    |
50#       |                             |     relay_gw     |    |
51#       |                             |    10.0.0.2/24   |    |
52#       |                             +--------+---------+    |
53#       |                                      |              |
54#       |                                      |              |
55#       |  +------------------+       +--------+---------+    |
56#       |  |     relay_src    |       |       amtr       |    |
57#       |  |   172.17.0.1/24  |       +------------------+    |
58#       |  | 2001:db8:3::1/64 |                               |
59#       |  +------------------+                               |
60#       |            .                                        |
61#       |            .                                        |
62#       +-----------------------------------------------------+
63#                    .
64#                    .
65#       +------------------------+
66#       |            .           |
67#       |  +------------------+  |
68#       |  |     src_relay    |  |
69#       |  |   172.17.0.2/24  |  |
70#       |  | 2001:db8:3::2/64 |  |
71#       |  +------------------+  |
72#       |      SOURCE netns      |
73#       +------------------------+
74#==============================================================================
75
76source lib.sh
77
78readonly LISTENER=$(mktemp -u listener-XXXXXXXX)
79readonly GATEWAY=$(mktemp -u gateway-XXXXXXXX)
80readonly RELAY=$(mktemp -u relay-XXXXXXXX)
81readonly SOURCE=$(mktemp -u source-XXXXXXXX)
82readonly SMCROUTEDIR="$(mktemp -d)"
83ERR=4
84err=0
85
86exit_cleanup()
87{
88	for ns in "$@"; do
89		ip netns delete "${ns}" 2>/dev/null || true
90	done
91	if [ -f "$SMCROUTEDIR/amt.pid" ]; then
92		smcpid=$(< $SMCROUTEDIR/amt.pid)
93		kill $smcpid
94	fi
95	rm -rf $SMCROUTEDIR
96
97	exit $ERR
98}
99
100create_namespaces()
101{
102	ip netns add "${LISTENER}" || exit_cleanup
103	ip netns add "${GATEWAY}" || exit_cleanup "${LISTENER}"
104	ip netns add "${RELAY}" || exit_cleanup "${LISTENER}" "${GATEWAY}"
105	ip netns add "${SOURCE}" || exit_cleanup "${LISTENER}" "${GATEWAY}" \
106		"${RELAY}"
107}
108
109# The trap function handler
110#
111exit_cleanup_all()
112{
113	exit_cleanup "${LISTENER}" "${GATEWAY}" "${RELAY}" "${SOURCE}"
114}
115
116setup_interface()
117{
118	for ns in "${LISTENER}" "${GATEWAY}" "${RELAY}" "${SOURCE}"; do
119		ip -netns "${ns}" link set dev lo up
120	done;
121
122	ip link add l_gw type veth peer name gw_l
123	ip link add gw_relay type veth peer name relay_gw
124	ip link add relay_src type veth peer name src_relay
125
126	ip link set l_gw netns "${LISTENER}" up
127	ip link set gw_l netns "${GATEWAY}" up
128	ip link set gw_relay netns "${GATEWAY}" up
129	ip link set relay_gw netns "${RELAY}" up
130	ip link set relay_src netns "${RELAY}" up
131	ip link set src_relay netns "${SOURCE}" up mtu 1400
132
133	ip netns exec "${LISTENER}" ip a a 192.168.0.2/24 dev l_gw
134	ip netns exec "${LISTENER}" ip r a default via 192.168.0.1 dev l_gw
135	ip netns exec "${LISTENER}" ip a a 2001:db8::2/64 dev l_gw
136	ip netns exec "${LISTENER}" ip r a default via 2001:db8::1 dev l_gw
137	ip netns exec "${LISTENER}" ip a a 239.0.0.1/32 dev l_gw autojoin
138	ip netns exec "${LISTENER}" ip a a ff0e::5:6/128 dev l_gw autojoin
139
140	ip netns exec "${GATEWAY}" ip a a 192.168.0.1/24 dev gw_l
141	ip netns exec "${GATEWAY}" ip a a 2001:db8::1/64 dev gw_l
142	ip netns exec "${GATEWAY}" ip a a 10.0.0.1/24 dev gw_relay
143	ip netns exec "${GATEWAY}" ip link add br0 type bridge
144	ip netns exec "${GATEWAY}" ip link set br0 up
145	ip netns exec "${GATEWAY}" ip link set gw_l master br0
146	ip netns exec "${GATEWAY}" ip link set gw_l up
147	ip netns exec "${GATEWAY}" ip link add amtg master br0 type amt \
148		mode gateway local 10.0.0.1 discovery 10.0.0.2 dev gw_relay \
149		gateway_port 2268 relay_port 2268
150	ip netns exec "${RELAY}" ip a a 10.0.0.2/24 dev relay_gw
151	ip netns exec "${RELAY}" ip link add amtr type amt mode relay \
152		local 10.0.0.2 dev relay_gw relay_port 2268 max_tunnels 4
153	# Count the IGMP and MLD queries that leave the relay through its own
154	# amt device; test_query_egress expects none.
155	ip netns exec "${RELAY}" tc qdisc add dev amtr clsact
156	ip netns exec "${RELAY}" tc filter add dev amtr egress pref 1 \
157		protocol ip flower ip_proto 0x2 action pass
158	ip netns exec "${RELAY}" tc filter add dev amtr egress pref 2 \
159		protocol ipv6 flower ip_proto icmpv6 type 130 action pass
160	ip netns exec "${RELAY}" ip a a 172.17.0.1/24 dev relay_src
161	ip netns exec "${RELAY}" ip a a 2001:db8:3::1/64 dev relay_src
162	ip netns exec "${SOURCE}" ip a a 172.17.0.2/24 dev src_relay
163	ip netns exec "${SOURCE}" ip a a 2001:db8:3::2/64 dev src_relay
164	ip netns exec "${SOURCE}" ip r a default via 172.17.0.1 dev src_relay
165	ip netns exec "${SOURCE}" ip r a default via 2001:db8:3::1 dev src_relay
166	ip netns exec "${RELAY}" ip link set amtr up
167	ip netns exec "${GATEWAY}" ip link set amtg up
168}
169
170setup_sysctl()
171{
172	ip netns exec "${RELAY}" sysctl net.ipv4.ip_forward=1 -w -q
173}
174
175setup_iptables()
176{
177	ip netns exec "${RELAY}" iptables -t mangle -I PREROUTING \
178		-d 239.0.0.1 -j TTL --ttl-set 2
179	ip netns exec "${RELAY}" ip6tables -t mangle -I PREROUTING \
180		-j HL --hl-set 2
181}
182
183setup_mcast_routing()
184{
185	ip netns exec "${RELAY}" smcrouted -P $SMCROUTEDIR/amt.pid
186	ip netns exec "${RELAY}" smcroutectl a relay_src \
187		172.17.0.2 239.0.0.1 amtr
188	ip netns exec "${RELAY}" smcroutectl a relay_src \
189		2001:db8:3::2 ff0e::5:6 amtr
190}
191
192test_remote_ip()
193{
194	REMOTE=$(ip netns exec "${GATEWAY}" \
195		ip -d -j link show amtg | jq .[0].linkinfo.info_data.remote)
196	if [ $REMOTE == "\"10.0.0.2\"" ]; then
197		printf "TEST: %-60s  [ OK ]\n" "amt discovery"
198	else
199		printf "TEST: %-60s  [FAIL]\n" "amt discovery"
200		ERR=1
201	fi
202}
203
204send_mcast_torture4()
205{
206	for i in `seq 10`; do
207		ip netns exec "${SOURCE}" bash -c \
208		   'cat /dev/urandom | head -c 100M | nc -w 1 -u 239.0.0.1 4001'
209		echo -n "."
210	done
211}
212
213
214send_mcast_torture6()
215{
216	for i in `seq 10`; do
217		ip netns exec "${SOURCE}" bash -c \
218		   'cat /dev/urandom | head -c 100M | nc -w 1 -u ff0e::5:6 6001'
219		echo -n "."
220	done
221}
222
223check_features()
224{
225        ip link help 2>&1 | grep -q amt
226        if [ $? -ne 0 ]; then
227                echo "Missing amt support in iproute2" >&2
228                exit_cleanup
229        fi
230}
231
232test_ipv4_forward()
233{
234	RESULT4=$(ip netns exec "${LISTENER}" timeout 15 socat - UDP4-LISTEN:4000,readbytes=128 || true)
235	if echo "$RESULT4" | grep -q "172.17.0.2"; then
236		printf "TEST: %-60s  [ OK ]\n" "IPv4 amt multicast forwarding"
237		exit 0
238	else
239		printf "TEST: %-60s  [FAIL]\n" "IPv4 amt multicast forwarding"
240		exit 1
241	fi
242}
243
244test_ipv6_forward()
245{
246	RESULT6=$(ip netns exec "${LISTENER}" timeout 15 socat - UDP6-LISTEN:6000,readbytes=128 || true)
247	if echo "$RESULT6" | grep -q "2001:db8:3::2"; then
248		printf "TEST: %-60s  [ OK ]\n" "IPv6 amt multicast forwarding"
249		exit 0
250	else
251		printf "TEST: %-60s  [FAIL]\n" "IPv6 amt multicast forwarding"
252		exit 1
253	fi
254}
255
256# The relay sends its General Queries straight from the receive path, in
257# the same context that found the tunnel. A query queued on the amt device
258# instead could outlive the tunnel it was built for. The forwarding tests
259# above show that the gateway got its queries.
260test_query_egress()
261{
262	local n4 n6
263
264	n4=$(ip netns exec "${RELAY}" tc -s -j filter show dev amtr egress \
265		pref 1 | jq '[.[].options.actions[0].stats.packets // empty] | add // 0')
266	n6=$(ip netns exec "${RELAY}" tc -s -j filter show dev amtr egress \
267		pref 2 | jq '[.[].options.actions[0].stats.packets // empty] | add // 0')
268	if [ "$n4" -eq 0 ] && [ "$n6" -eq 0 ]; then
269		printf "TEST: %-60s  [ OK ]\n" "amt relay queries bypass the amt device"
270	else
271		printf "TEST: %-60s  [FAIL]\n" "amt relay queries bypass the amt device"
272		echo "IGMP queries on amtr egress: $n4, MLD queries: $n6" >&2
273		ERR=1
274	fi
275}
276
277send_mcast4()
278{
279	sleep 5
280	wait_local_port_listen ${LISTENER} 4000 udp
281	ip netns exec "${SOURCE}" bash -c \
282		'printf "%s %128s" 172.17.0.2 | nc -w 1 -u 239.0.0.1 4000' &
283}
284
285send_mcast6()
286{
287	wait_local_port_listen ${LISTENER} 6000 udp
288	ip netns exec "${SOURCE}" bash -c \
289		'printf "%s %128s" 2001:db8:3::2 | nc -w 1 -u ff0e::5:6 6000' &
290}
291
292check_features
293
294create_namespaces
295
296set -e
297trap exit_cleanup_all EXIT
298
299setup_interface
300setup_sysctl
301setup_iptables
302setup_mcast_routing
303test_remote_ip
304test_ipv4_forward &
305pid=$!
306send_mcast4
307wait $pid || err=$?
308if [ $err -eq 1 ]; then
309	ERR=1
310fi
311test_ipv6_forward &
312pid=$!
313send_mcast6
314wait $pid || err=$?
315if [ $err -eq 1 ]; then
316	ERR=1
317fi
318test_query_egress
319printf "TEST: %-50s" "IPv4 amt traffic forwarding torture"
320send_mcast_torture4
321printf "  [ OK ]\n"
322printf "TEST: %-50s" "IPv6 amt traffic forwarding torture"
323send_mcast_torture6
324printf "  [ OK ]\n"
325sleep 5
326if [ "${ERR}" -eq 1 ]; then
327        echo "Some tests failed." >&2
328else
329        ERR=0
330fi
331