1#!/bin/sh 2# SPDX-License-Identifier: GPL-2.0 3 4# Test various bareudp tunnel configurations. 5# 6# The bareudp module allows to tunnel network protocols like IP or MPLS over 7# UDP, without adding any intermediate header. This scripts tests several 8# configurations of bareudp (using IPv4 or IPv6 as underlay and transporting 9# IPv4, IPv6 or MPLS packets on the overlay). 10# 11# Network topology: 12# 13# * A chain of 4 network namespaces, connected with veth pairs. Each veth 14# is assigned an IPv4 and an IPv6 address. A host-route allows a veth to 15# join its peer. 16# 17# * NS0 and NS3 are at the extremities of the chain. They have additional 18# IPv4 and IPv6 addresses on their loopback device. Routes are added in NS0 19# and NS3, so that they can communicate using these overlay IP addresses. 20# For IPv4 and IPv6 reachability tests, the route simply sets the peer's 21# veth address as gateway. For MPLS reachability tests, an MPLS header is 22# also pushed before the IP header. 23# 24# * NS1 and NS2 are the intermediate namespaces. They use a bareudp device to 25# encapsulate the traffic into UDP. 26# 27# +-----------------------------------------------------------------------+ 28# | NS0 | 29# | | 30# | lo: | 31# | * IPv4 address: 192.0.2.100/32 | 32# | * IPv6 address: 2001:db8::100/128 | 33# | * IPv6 address: 2001:db8::200/128 | 34# | * IPv4 route: 192.0.2.103/32 reachable via 192.0.2.11 | 35# | * IPv6 route: 2001:db8::103/128 reachable via 2001:db8::11 | 36# | * IPv6 route: 2001:db8::203/128 reachable via 2001:db8::11 | 37# | (encapsulated with MPLS label 203) | 38# | | 39# | veth01: | 40# | ^ * IPv4 address: 192.0.2.10, peer 192.0.2.11/32 | 41# | | * IPv6 address: 2001:db8::10, peer 2001:db8::11/128 | 42# | | | 43# +---+-------------------------------------------------------------------+ 44# | 45# | Traffic type: IP or MPLS (depending on test) 46# | 47# +---+-------------------------------------------------------------------+ 48# | | NS1 | 49# | | | 50# | v | 51# | veth10: | 52# | * IPv4 address: 192.0.2.11, peer 192.0.2.10/32 | 53# | * IPv6 address: 2001:db8::11, peer 2001:db8::10/128 | 54# | | 55# | bareudp_ns1: | 56# | * Encapsulate IP or MPLS packets received on veth10 into UDP | 57# | and send the resulting packets through veth12. | 58# | * Decapsulate bareudp packets (either IP or MPLS, over UDP) | 59# | received on veth12 and send the inner packets through veth10. | 60# | | 61# | veth12: | 62# | ^ * IPv4 address: 192.0.2.21, peer 192.0.2.22/32 | 63# | | * IPv6 address: 2001:db8::21, peer 2001:db8::22/128 | 64# | | | 65# +---+-------------------------------------------------------------------+ 66# | 67# | Traffic type: IP or MPLS (depending on test), over UDP 68# | 69# +---+-------------------------------------------------------------------+ 70# | | NS2 | 71# | | | 72# | v | 73# | veth21: | 74# | * IPv4 address: 192.0.2.22, peer 192.0.2.21/32 | 75# | * IPv6 address: 2001:db8::22, peer 2001:db8::21/128 | 76# | | 77# | bareudp_ns2: | 78# | * Decapsulate bareudp packets (either IP or MPLS, over UDP) | 79# | received on veth21 and send the inner packets through veth23. | 80# | * Encapsulate IP or MPLS packets received on veth23 into UDP | 81# | and send the resulting packets through veth21. | 82# | | 83# | veth23: | 84# | ^ * IPv4 address: 192.0.2.32, peer 192.0.2.33/32 | 85# | | * IPv6 address: 2001:db8::32, peer 2001:db8::33/128 | 86# | | | 87# +---+-------------------------------------------------------------------+ 88# | 89# | Traffic type: IP or MPLS (depending on test) 90# | 91# +---+-------------------------------------------------------------------+ 92# | | NS3 | 93# | v | 94# | veth32: | 95# | * IPv4 address: 192.0.2.33, peer 192.0.2.32/32 | 96# | * IPv6 address: 2001:db8::33, peer 2001:db8::32/128 | 97# | | 98# | lo: | 99# | * IPv4 address: 192.0.2.103/32 | 100# | * IPv6 address: 2001:db8::103/128 | 101# | * IPv6 address: 2001:db8::203/128 | 102# | * IPv4 route: 192.0.2.100/32 reachable via 192.0.2.32 | 103# | * IPv6 route: 2001:db8::100/128 reachable via 2001:db8::32 | 104# | * IPv6 route: 2001:db8::200/128 reachable via 2001:db8::32 | 105# | (encapsulated with MPLS label 200) | 106# | | 107# +-----------------------------------------------------------------------+ 108 109ERR=4 # Return 4 by default, which is the SKIP code for kselftest 110PING6="ping" 111PAUSE_ON_FAIL="no" 112 113readonly NS0=$(mktemp -u ns0-XXXXXXXX) 114readonly NS1=$(mktemp -u ns1-XXXXXXXX) 115readonly NS2=$(mktemp -u ns2-XXXXXXXX) 116readonly NS3=$(mktemp -u ns3-XXXXXXXX) 117 118# Exit the script after having removed the network namespaces it created 119# 120# Parameters: 121# 122# * The list of network namespaces to delete before exiting. 123# 124exit_cleanup() 125{ 126 for ns in "$@"; do 127 ip netns delete "${ns}" 2>/dev/null || true 128 done 129 130 if [ "${ERR}" -eq 4 ]; then 131 echo "Error: Setting up the testing environment failed." >&2 132 fi 133 134 exit "${ERR}" 135} 136 137# Create the four network namespaces used by the script (NS0, NS1, NS2 and NS3) 138# 139# New namespaces are cleaned up manually in case of error, to ensure that only 140# namespaces created by this script are deleted. 141create_namespaces() 142{ 143 ip netns add "${NS0}" || exit_cleanup 144 ip netns add "${NS1}" || exit_cleanup "${NS0}" 145 ip netns add "${NS2}" || exit_cleanup "${NS0}" "${NS1}" 146 ip netns add "${NS3}" || exit_cleanup "${NS0}" "${NS1}" "${NS2}" 147} 148 149# The trap function handler 150# 151exit_cleanup_all() 152{ 153 exit_cleanup "${NS0}" "${NS1}" "${NS2}" "${NS3}" 154} 155 156# Configure a network interface using a host route 157# 158# Parameters 159# 160# * $1: the netns the network interface resides in, 161# * $2: the network interface name, 162# * $3: the local IPv4 address to assign to this interface, 163# * $4: the IPv4 address of the remote network interface, 164# * $5: the local IPv6 address to assign to this interface, 165# * $6: the IPv6 address of the remote network interface. 166# 167iface_config() 168{ 169 local NS="${1}"; readonly NS 170 local DEV="${2}"; readonly DEV 171 local LOCAL_IP4="${3}"; readonly LOCAL_IP4 172 local PEER_IP4="${4}"; readonly PEER_IP4 173 local LOCAL_IP6="${5}"; readonly LOCAL_IP6 174 local PEER_IP6="${6}"; readonly PEER_IP6 175 176 ip -netns "${NS}" link set dev "${DEV}" up 177 ip -netns "${NS}" address add dev "${DEV}" "${LOCAL_IP4}" peer "${PEER_IP4}" 178 ip -netns "${NS}" address add dev "${DEV}" "${LOCAL_IP6}" peer "${PEER_IP6}" nodad 179} 180 181# Create base networking topology: 182# 183# * set up the loopback device in all network namespaces (NS0..NS3), 184# * set up a veth pair to connect each netns in sequence (NS0 with NS1, 185# NS1 with NS2, etc.), 186# * add and IPv4 and an IPv6 address on each veth interface, 187# * prepare the ingress qdiscs in the intermediate namespaces. 188# 189setup_underlay() 190{ 191 for ns in "${NS0}" "${NS1}" "${NS2}" "${NS3}"; do 192 ip -netns "${ns}" link set dev lo up 193 done; 194 195 ip link add name veth01 netns "${NS0}" type veth peer name veth10 netns "${NS1}" 196 ip link add name veth12 netns "${NS1}" type veth peer name veth21 netns "${NS2}" 197 ip link add name veth23 netns "${NS2}" type veth peer name veth32 netns "${NS3}" 198 iface_config "${NS0}" veth01 192.0.2.10 192.0.2.11/32 2001:db8::10 2001:db8::11/128 199 iface_config "${NS1}" veth10 192.0.2.11 192.0.2.10/32 2001:db8::11 2001:db8::10/128 200 iface_config "${NS1}" veth12 192.0.2.21 192.0.2.22/32 2001:db8::21 2001:db8::22/128 201 iface_config "${NS2}" veth21 192.0.2.22 192.0.2.21/32 2001:db8::22 2001:db8::21/128 202 iface_config "${NS2}" veth23 192.0.2.32 192.0.2.33/32 2001:db8::32 2001:db8::33/128 203 iface_config "${NS3}" veth32 192.0.2.33 192.0.2.32/32 2001:db8::33 2001:db8::32/128 204 205 tc -netns "${NS1}" qdisc add dev veth10 ingress 206 tc -netns "${NS2}" qdisc add dev veth23 ingress 207} 208 209# Set up the IPv4, IPv6 and MPLS overlays. 210# 211# Configuration is similar for all protocols: 212# 213# * add an overlay IP address on the loopback interface of each edge 214# namespace, 215# * route these IP addresses via the intermediate namespaces (for the MPLS 216# tests, this is also where MPLS encapsulation is done), 217# * add routes for these IP addresses (or MPLS labels) in the intermediate 218# namespaces. 219# 220# The bareudp encapsulation isn't configured in setup_overlay_*(). That will be 221# done just before running the reachability tests. 222 223setup_overlay_ipv4() 224{ 225 # Add the overlay IP addresses and route them through the veth devices 226 ip -netns "${NS0}" address add 192.0.2.100/32 dev lo 227 ip -netns "${NS3}" address add 192.0.2.103/32 dev lo 228 ip -netns "${NS0}" route add 192.0.2.103/32 src 192.0.2.100 via 192.0.2.11 229 ip -netns "${NS3}" route add 192.0.2.100/32 src 192.0.2.103 via 192.0.2.32 230 231 # Route the overlay addresses in the intermediate namespaces 232 # (used after bareudp decapsulation) 233 ip netns exec "${NS1}" sysctl -qw net.ipv4.ip_forward=1 234 ip netns exec "${NS2}" sysctl -qw net.ipv4.ip_forward=1 235 ip -netns "${NS1}" route add 192.0.2.100/32 via 192.0.2.10 236 ip -netns "${NS2}" route add 192.0.2.103/32 via 192.0.2.33 237 238 # The intermediate namespaces don't have routes for the reverse path, 239 # as it will be handled by tc. So we need to ensure that rp_filter is 240 # not going to block the traffic. 241 ip netns exec "${NS1}" sysctl -qw net.ipv4.conf.all.rp_filter=0 242 ip netns exec "${NS2}" sysctl -qw net.ipv4.conf.all.rp_filter=0 243 ip netns exec "${NS1}" sysctl -qw net.ipv4.conf.default.rp_filter=0 244 ip netns exec "${NS2}" sysctl -qw net.ipv4.conf.default.rp_filter=0 245} 246 247setup_overlay_ipv6() 248{ 249 # Add the overlay IP addresses and route them through the veth devices 250 ip -netns "${NS0}" address add 2001:db8::100/128 dev lo 251 ip -netns "${NS3}" address add 2001:db8::103/128 dev lo 252 ip -netns "${NS0}" route add 2001:db8::103/128 src 2001:db8::100 via 2001:db8::11 253 ip -netns "${NS3}" route add 2001:db8::100/128 src 2001:db8::103 via 2001:db8::32 254 255 # Route the overlay addresses in the intermediate namespaces 256 # (used after bareudp decapsulation) 257 ip netns exec "${NS1}" sysctl -qw net.ipv6.conf.all.forwarding=1 258 ip netns exec "${NS2}" sysctl -qw net.ipv6.conf.all.forwarding=1 259 ip -netns "${NS1}" route add 2001:db8::100/128 via 2001:db8::10 260 ip -netns "${NS2}" route add 2001:db8::103/128 via 2001:db8::33 261} 262 263setup_overlay_mpls() 264{ 265 # Add specific overlay IP addresses, routed over MPLS 266 ip -netns "${NS0}" address add 2001:db8::200/128 dev lo 267 ip -netns "${NS3}" address add 2001:db8::203/128 dev lo 268 ip -netns "${NS0}" route add 2001:db8::203/128 src 2001:db8::200 encap mpls 203 via 2001:db8::11 269 ip -netns "${NS3}" route add 2001:db8::200/128 src 2001:db8::203 encap mpls 200 via 2001:db8::32 270 271 # Route the MPLS packets in the intermediate namespaces 272 # (used after bareudp decapsulation) 273 ip netns exec "${NS1}" sysctl -qw net.mpls.platform_labels=256 274 ip netns exec "${NS2}" sysctl -qw net.mpls.platform_labels=256 275 ip -netns "${NS1}" -family mpls route add 200 via inet6 2001:db8::10 276 ip -netns "${NS2}" -family mpls route add 203 via inet6 2001:db8::33 277} 278 279# Run "ping" from NS0 and print the result 280# 281# Parameters: 282# 283# * $1: the variant of ping to use (normally either "ping" or "ping6"), 284# * $2: the IP address to ping, 285# * $3: a human readable description of the purpose of the test. 286# 287# If the test fails and PAUSE_ON_FAIL is active, the user is given the 288# possibility to continue with the next test or to quit immediately. 289# 290ping_test_one() 291{ 292 local PING="$1"; readonly PING 293 local IP="$2"; readonly IP 294 local MSG="$3"; readonly MSG 295 local RET 296 297 printf "TEST: %-60s " "${MSG}" 298 299 set +e 300 ip netns exec "${NS0}" "${PING}" -w 5 -c 1 "${IP}" > /dev/null 2>&1 301 RET=$? 302 set -e 303 304 if [ "${RET}" -eq 0 ]; then 305 printf "[ OK ]\n" 306 else 307 ERR=1 308 printf "[FAIL]\n" 309 if [ "${PAUSE_ON_FAIL}" = "yes" ]; then 310 printf "\nHit enter to continue, 'q' to quit\n" 311 read a 312 if [ "$a" = "q" ]; then 313 exit 1 314 fi 315 fi 316 fi 317} 318 319# Run reachability tests 320# 321# Parameters: 322# 323# * $1: human readable string describing the underlay protocol. 324# 325# $IPV4, $IPV6, $MPLS_UC and $MULTIPROTO are inherited from the calling 326# function. 327# 328ping_test() 329{ 330 local UNDERLAY="$1"; readonly UNDERLAY 331 local MODE 332 local MSG 333 334 if [ "${MULTIPROTO}" = "multiproto" ]; then 335 MODE=" (multiproto mode)" 336 else 337 MODE="" 338 fi 339 340 if [ $IPV4 ]; then 341 ping_test_one "ping" "192.0.2.103" "IPv4 packets over ${UNDERLAY}${MODE}" 342 fi 343 if [ $IPV6 ]; then 344 ping_test_one "${PING6}" "2001:db8::103" "IPv6 packets over ${UNDERLAY}${MODE}" 345 fi 346 if [ $MPLS_UC ]; then 347 ping_test_one "${PING6}" "2001:db8::203" "Unicast MPLS packets over ${UNDERLAY}${MODE}" 348 fi 349} 350 351# Set up a bareudp overlay and run reachability tests over IPv4 and IPv6 352# 353# Parameters: 354# 355# * $1: the packet type (protocol) to be handled by bareudp, 356# * $2: a flag to activate or deactivate bareudp's "multiproto" mode. 357# 358test_overlay() 359{ 360 local ETHERTYPE="$1"; readonly ETHERTYPE 361 local MULTIPROTO="$2"; readonly MULTIPROTO 362 local IPV4 363 local IPV6 364 local MPLS_UC 365 366 case "${ETHERTYPE}" in 367 "ipv4") 368 IPV4="ipv4" 369 if [ "${MULTIPROTO}" = "multiproto" ]; then 370 IPV6="ipv6" 371 else 372 IPV6="" 373 fi 374 MPLS_UC="" 375 ;; 376 "ipv6") 377 IPV6="ipv6" 378 IPV4="" 379 MPLS_UC="" 380 ;; 381 "mpls_uc") 382 MPLS_UC="mpls_uc" 383 IPV4="" 384 IPV6="" 385 ;; 386 *) 387 exit 1 388 ;; 389 esac 390 readonly IPV4 391 readonly IPV6 392 readonly MPLS_UC 393 394 # Create the bareudp devices in the intermediate namespaces 395 ip -netns "${NS1}" link add name bareudp_ns1 up type bareudp dstport 6635 ethertype "${ETHERTYPE}" "${MULTIPROTO}" 396 ip -netns "${NS2}" link add name bareudp_ns2 up type bareudp dstport 6635 ethertype "${ETHERTYPE}" "${MULTIPROTO}" 397 398 # IPv4 over UDPv4 399 if [ $IPV4 ]; then 400 # Encapsulation instructions for bareudp over IPv4 401 tc -netns "${NS1}" filter add dev veth10 ingress protocol ipv4 \ 402 flower dst_ip 192.0.2.103/32 \ 403 action tunnel_key set src_ip 192.0.2.21 dst_ip 192.0.2.22 id 0 \ 404 action mirred egress redirect dev bareudp_ns1 405 tc -netns "${NS2}" filter add dev veth23 ingress protocol ipv4 \ 406 flower dst_ip 192.0.2.100/32 \ 407 action tunnel_key set src_ip 192.0.2.22 dst_ip 192.0.2.21 id 0 \ 408 action mirred egress redirect dev bareudp_ns2 409 fi 410 411 # IPv6 over UDPv4 412 if [ $IPV6 ]; then 413 # Encapsulation instructions for bareudp over IPv4 414 tc -netns "${NS1}" filter add dev veth10 ingress protocol ipv6 \ 415 flower dst_ip 2001:db8::103/128 \ 416 action tunnel_key set src_ip 192.0.2.21 dst_ip 192.0.2.22 id 0 \ 417 action mirred egress redirect dev bareudp_ns1 418 tc -netns "${NS2}" filter add dev veth23 ingress protocol ipv6 \ 419 flower dst_ip 2001:db8::100/128 \ 420 action tunnel_key set src_ip 192.0.2.22 dst_ip 192.0.2.21 id 0 \ 421 action mirred egress redirect dev bareudp_ns2 422 fi 423 424 # MPLS (unicast) over UDPv4 425 if [ $MPLS_UC ]; then 426 ip netns exec "${NS1}" sysctl -qw net.mpls.conf.bareudp_ns1.input=1 427 ip netns exec "${NS2}" sysctl -qw net.mpls.conf.bareudp_ns2.input=1 428 429 # Encapsulation instructions for bareudp over IPv4 430 tc -netns "${NS1}" filter add dev veth10 ingress protocol mpls_uc \ 431 flower mpls_label 203 \ 432 action tunnel_key set src_ip 192.0.2.21 dst_ip 192.0.2.22 id 0 \ 433 action mirred egress redirect dev bareudp_ns1 434 tc -netns "${NS2}" filter add dev veth23 ingress protocol mpls_uc \ 435 flower mpls_label 200 \ 436 action tunnel_key set src_ip 192.0.2.22 dst_ip 192.0.2.21 id 0 \ 437 action mirred egress redirect dev bareudp_ns2 438 fi 439 440 # Test IPv4 underlay 441 ping_test "UDPv4" 442 443 # Cleanup bareudp encapsulation instructions, as they were specific to 444 # the IPv4 underlay, before setting up and testing the IPv6 underlay 445 tc -netns "${NS1}" filter delete dev veth10 ingress 446 tc -netns "${NS2}" filter delete dev veth23 ingress 447 448 # IPv4 over UDPv6 449 if [ $IPV4 ]; then 450 # New encapsulation instructions for bareudp over IPv6 451 tc -netns "${NS1}" filter add dev veth10 ingress protocol ipv4 \ 452 flower dst_ip 192.0.2.103/32 \ 453 action tunnel_key set src_ip 2001:db8::21 dst_ip 2001:db8::22 id 0 \ 454 action mirred egress redirect dev bareudp_ns1 455 tc -netns "${NS2}" filter add dev veth23 ingress protocol ipv4 \ 456 flower dst_ip 192.0.2.100/32 \ 457 action tunnel_key set src_ip 2001:db8::22 dst_ip 2001:db8::21 id 0 \ 458 action mirred egress redirect dev bareudp_ns2 459 fi 460 461 # IPv6 over UDPv6 462 if [ $IPV6 ]; then 463 # New encapsulation instructions for bareudp over IPv6 464 tc -netns "${NS1}" filter add dev veth10 ingress protocol ipv6 \ 465 flower dst_ip 2001:db8::103/128 \ 466 action tunnel_key set src_ip 2001:db8::21 dst_ip 2001:db8::22 id 0 \ 467 action mirred egress redirect dev bareudp_ns1 468 tc -netns "${NS2}" filter add dev veth23 ingress protocol ipv6 \ 469 flower dst_ip 2001:db8::100/128 \ 470 action tunnel_key set src_ip 2001:db8::22 dst_ip 2001:db8::21 id 0 \ 471 action mirred egress redirect dev bareudp_ns2 472 fi 473 474 # MPLS (unicast) over UDPv6 475 if [ $MPLS_UC ]; then 476 # New encapsulation instructions for bareudp over IPv6 477 tc -netns "${NS1}" filter add dev veth10 ingress protocol mpls_uc \ 478 flower mpls_label 203 \ 479 action tunnel_key set src_ip 2001:db8::21 dst_ip 2001:db8::22 id 0 \ 480 action mirred egress redirect dev bareudp_ns1 481 tc -netns "${NS2}" filter add dev veth23 ingress protocol mpls_uc \ 482 flower mpls_label 200 \ 483 action tunnel_key set src_ip 2001:db8::22 dst_ip 2001:db8::21 id 0 \ 484 action mirred egress redirect dev bareudp_ns2 485 fi 486 487 # Test IPv6 underlay 488 ping_test "UDPv6" 489 490 tc -netns "${NS1}" filter delete dev veth10 ingress 491 tc -netns "${NS2}" filter delete dev veth23 ingress 492 ip -netns "${NS1}" link delete bareudp_ns1 493 ip -netns "${NS2}" link delete bareudp_ns2 494} 495 496check_features() 497{ 498 ip link help 2>&1 | grep -q bareudp 499 if [ $? -ne 0 ]; then 500 echo "Missing bareudp support in iproute2" >&2 501 exit_cleanup 502 fi 503 504 # Use ping6 on systems where ping doesn't handle IPv6 505 ping -w 1 -c 1 ::1 > /dev/null 2>&1 || PING6="ping6" 506} 507 508usage() 509{ 510 echo "Usage: $0 [-p]" 511 exit 1 512} 513 514while getopts :p o 515do 516 case $o in 517 p) PAUSE_ON_FAIL="yes";; 518 *) usage;; 519 esac 520done 521 522check_features 523 524# Create namespaces before setting up the exit trap. 525# Otherwise, exit_cleanup_all() could delete namespaces that were not created 526# by this script. 527create_namespaces 528 529set -e 530trap exit_cleanup_all EXIT 531 532setup_underlay 533setup_overlay_ipv4 534setup_overlay_ipv6 535setup_overlay_mpls 536 537test_overlay ipv4 nomultiproto 538test_overlay ipv6 nomultiproto 539test_overlay ipv4 multiproto 540test_overlay mpls_uc nomultiproto 541 542if [ "${ERR}" -eq 1 ]; then 543 echo "Some tests failed." >&2 544else 545 ERR=0 546fi 547