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