1#!/bin/bash 2# SPDX-License-Identifier: GPL-2.0 3 4# IPv4 and IPv6 onlink tests 5 6PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no} 7VERBOSE=0 8 9# Network interfaces 10# - odd in current namespace; even in peer ns 11declare -A NETIFS 12# default VRF 13NETIFS[p1]=veth1 14NETIFS[p2]=veth2 15NETIFS[p3]=veth3 16NETIFS[p4]=veth4 17# VRF 18NETIFS[p5]=veth5 19NETIFS[p6]=veth6 20NETIFS[p7]=veth7 21NETIFS[p8]=veth8 22 23# /24 network 24declare -A V4ADDRS 25V4ADDRS[p1]=169.254.1.1 26V4ADDRS[p2]=169.254.1.2 27V4ADDRS[p3]=169.254.3.1 28V4ADDRS[p4]=169.254.3.2 29V4ADDRS[p5]=169.254.5.1 30V4ADDRS[p6]=169.254.5.2 31V4ADDRS[p7]=169.254.7.1 32V4ADDRS[p8]=169.254.7.2 33 34# /64 network 35declare -A V6ADDRS 36V6ADDRS[p1]=2001:db8:101::1 37V6ADDRS[p2]=2001:db8:101::2 38V6ADDRS[p3]=2001:db8:301::1 39V6ADDRS[p4]=2001:db8:301::2 40V6ADDRS[p5]=2001:db8:501::1 41V6ADDRS[p6]=2001:db8:501::2 42V6ADDRS[p7]=2001:db8:701::1 43V6ADDRS[p8]=2001:db8:701::2 44 45# Test networks: 46# [1] = default table 47# [2] = VRF 48# 49# /32 host routes 50declare -A TEST_NET4 51TEST_NET4[1]=169.254.101 52TEST_NET4[2]=169.254.102 53# /128 host routes 54declare -A TEST_NET6 55TEST_NET6[1]=2001:db8:101 56TEST_NET6[2]=2001:db8:102 57 58# connected gateway 59CONGW[1]=169.254.1.254 60CONGW[2]=169.254.3.254 61CONGW[3]=169.254.5.254 62 63# recursive gateway 64RECGW4[1]=169.254.11.254 65RECGW4[2]=169.254.12.254 66RECGW6[1]=2001:db8:11::64 67RECGW6[2]=2001:db8:12::64 68 69# for v4 mapped to v6 70declare -A TEST_NET4IN6IN6 71TEST_NET4IN6[1]=10.1.1.254 72TEST_NET4IN6[2]=10.2.1.254 73 74# mcast address 75MCAST6=ff02::1 76 77 78PEER_NS=bart 79PEER_CMD="ip netns exec ${PEER_NS}" 80VRF=lisa 81VRF_TABLE=1101 82PBR_TABLE=101 83 84################################################################################ 85# utilities 86 87log_test() 88{ 89 local rc=$1 90 local expected=$2 91 local msg="$3" 92 93 if [ ${rc} -eq ${expected} ]; then 94 nsuccess=$((nsuccess+1)) 95 printf " TEST: %-50s [ OK ]\n" "${msg}" 96 else 97 nfail=$((nfail+1)) 98 printf " TEST: %-50s [FAIL]\n" "${msg}" 99 if [ "${PAUSE_ON_FAIL}" = "yes" ]; then 100 echo 101 echo "hit enter to continue, 'q' to quit" 102 read a 103 [ "$a" = "q" ] && exit 1 104 fi 105 fi 106} 107 108log_section() 109{ 110 echo 111 echo "######################################################################" 112 echo "TEST SECTION: $*" 113 echo "######################################################################" 114} 115 116log_subsection() 117{ 118 echo 119 echo "#########################################" 120 echo "TEST SUBSECTION: $*" 121} 122 123run_cmd() 124{ 125 local cmd="$*" 126 local out 127 local rc 128 129 if [ "$VERBOSE" = "1" ]; then 130 printf " COMMAND: $cmd\n" 131 fi 132 133 out=$(eval $cmd 2>&1) 134 rc=$? 135 if [ "$VERBOSE" = "1" -a -n "$out" ]; then 136 echo " $out" 137 fi 138 139 [ "$VERBOSE" = "1" ] && echo 140 141 return $rc 142} 143 144get_linklocal() 145{ 146 local dev=$1 147 local pfx 148 local addr 149 150 addr=$(${pfx} ip -6 -br addr show dev ${dev} | \ 151 awk '{ 152 for (i = 3; i <= NF; ++i) { 153 if ($i ~ /^fe80/) 154 print $i 155 } 156 }' 157 ) 158 addr=${addr/\/*} 159 160 [ -z "$addr" ] && return 1 161 162 echo $addr 163 164 return 0 165} 166 167################################################################################ 168# 169 170setup() 171{ 172 echo 173 echo "########################################" 174 echo "Configuring interfaces" 175 176 set -e 177 178 # create namespace 179 ip netns add ${PEER_NS} 180 ip -netns ${PEER_NS} li set lo up 181 182 # add vrf table 183 ip li add ${VRF} type vrf table ${VRF_TABLE} 184 ip li set ${VRF} up 185 ip ro add table ${VRF_TABLE} unreachable default metric 8192 186 ip -6 ro add table ${VRF_TABLE} unreachable default metric 8192 187 188 # create test interfaces 189 ip li add ${NETIFS[p1]} type veth peer name ${NETIFS[p2]} 190 ip li add ${NETIFS[p3]} type veth peer name ${NETIFS[p4]} 191 ip li add ${NETIFS[p5]} type veth peer name ${NETIFS[p6]} 192 ip li add ${NETIFS[p7]} type veth peer name ${NETIFS[p8]} 193 194 # enslave vrf interfaces 195 for n in 5 7; do 196 ip li set ${NETIFS[p${n}]} vrf ${VRF} 197 done 198 199 # add addresses 200 for n in 1 3 5 7; do 201 ip li set ${NETIFS[p${n}]} up 202 ip addr add ${V4ADDRS[p${n}]}/24 dev ${NETIFS[p${n}]} 203 ip addr add ${V6ADDRS[p${n}]}/64 dev ${NETIFS[p${n}]} nodad 204 done 205 206 # move peer interfaces to namespace and add addresses 207 for n in 2 4 6 8; do 208 ip li set ${NETIFS[p${n}]} netns ${PEER_NS} up 209 ip -netns ${PEER_NS} addr add ${V4ADDRS[p${n}]}/24 dev ${NETIFS[p${n}]} 210 ip -netns ${PEER_NS} addr add ${V6ADDRS[p${n}]}/64 dev ${NETIFS[p${n}]} nodad 211 done 212 213 ip -6 ro add default via ${V6ADDRS[p3]/::[0-9]/::64} 214 ip -6 ro add table ${VRF_TABLE} default via ${V6ADDRS[p7]/::[0-9]/::64} 215 216 set +e 217} 218 219cleanup() 220{ 221 # make sure we start from a clean slate 222 ip netns del ${PEER_NS} 2>/dev/null 223 for n in 1 3 5 7; do 224 ip link del ${NETIFS[p${n}]} 2>/dev/null 225 done 226 ip link del ${VRF} 2>/dev/null 227 ip ro flush table ${VRF_TABLE} 228 ip -6 ro flush table ${VRF_TABLE} 229} 230 231################################################################################ 232# IPv4 tests 233# 234 235run_ip() 236{ 237 local table="$1" 238 local prefix="$2" 239 local gw="$3" 240 local dev="$4" 241 local exp_rc="$5" 242 local desc="$6" 243 244 # dev arg may be empty 245 [ -n "${dev}" ] && dev="dev ${dev}" 246 247 run_cmd ip ro add table "${table}" "${prefix}"/32 via "${gw}" "${dev}" onlink 248 log_test $? ${exp_rc} "${desc}" 249} 250 251run_ip_mpath() 252{ 253 local table="$1" 254 local prefix="$2" 255 local nh1="$3" 256 local nh2="$4" 257 local exp_rc="$5" 258 local desc="$6" 259 260 # dev arg may be empty 261 [ -n "${dev}" ] && dev="dev ${dev}" 262 263 run_cmd ip ro add table "${table}" "${prefix}"/32 \ 264 nexthop via ${nh1} nexthop via ${nh2} 265 log_test $? ${exp_rc} "${desc}" 266} 267 268valid_onlink_ipv4() 269{ 270 # - unicast connected, unicast recursive 271 # 272 log_subsection "default VRF - main table" 273 274 run_ip 254 ${TEST_NET4[1]}.1 ${CONGW[1]} ${NETIFS[p1]} 0 "unicast connected" 275 run_ip 254 ${TEST_NET4[1]}.2 ${RECGW4[1]} ${NETIFS[p1]} 0 "unicast recursive" 276 277 log_subsection "VRF ${VRF}" 278 279 run_ip ${VRF_TABLE} ${TEST_NET4[2]}.1 ${CONGW[3]} ${NETIFS[p5]} 0 "unicast connected" 280 run_ip ${VRF_TABLE} ${TEST_NET4[2]}.2 ${RECGW4[2]} ${NETIFS[p5]} 0 "unicast recursive" 281 282 log_subsection "VRF device, PBR table" 283 284 run_ip ${PBR_TABLE} ${TEST_NET4[2]}.3 ${CONGW[3]} ${NETIFS[p5]} 0 "unicast connected" 285 run_ip ${PBR_TABLE} ${TEST_NET4[2]}.4 ${RECGW4[2]} ${NETIFS[p5]} 0 "unicast recursive" 286 287 # multipath version 288 # 289 log_subsection "default VRF - main table - multipath" 290 291 run_ip_mpath 254 ${TEST_NET4[1]}.5 \ 292 "${CONGW[1]} dev ${NETIFS[p1]} onlink" \ 293 "${CONGW[2]} dev ${NETIFS[p3]} onlink" \ 294 0 "unicast connected - multipath" 295 296 run_ip_mpath 254 ${TEST_NET4[1]}.6 \ 297 "${RECGW4[1]} dev ${NETIFS[p1]} onlink" \ 298 "${RECGW4[2]} dev ${NETIFS[p3]} onlink" \ 299 0 "unicast recursive - multipath" 300 301 run_ip_mpath 254 ${TEST_NET4[1]}.7 \ 302 "${CONGW[1]} dev ${NETIFS[p1]}" \ 303 "${CONGW[2]} dev ${NETIFS[p3]} onlink" \ 304 0 "unicast connected - multipath onlink first only" 305 306 run_ip_mpath 254 ${TEST_NET4[1]}.8 \ 307 "${CONGW[1]} dev ${NETIFS[p1]} onlink" \ 308 "${CONGW[2]} dev ${NETIFS[p3]}" \ 309 0 "unicast connected - multipath onlink second only" 310} 311 312invalid_onlink_ipv4() 313{ 314 run_ip 254 ${TEST_NET4[1]}.11 ${V4ADDRS[p1]} ${NETIFS[p1]} 2 \ 315 "Invalid gw - local unicast address" 316 317 run_ip ${VRF_TABLE} ${TEST_NET4[2]}.11 ${V4ADDRS[p5]} ${NETIFS[p5]} 2 \ 318 "Invalid gw - local unicast address, VRF" 319 320 run_ip 254 ${TEST_NET4[1]}.101 ${V4ADDRS[p1]} "" 2 "No nexthop device given" 321 322 run_ip 254 ${TEST_NET4[1]}.102 ${V4ADDRS[p3]} ${NETIFS[p1]} 2 \ 323 "Gateway resolves to wrong nexthop device" 324 325 run_ip ${VRF_TABLE} ${TEST_NET4[2]}.103 ${V4ADDRS[p7]} ${NETIFS[p5]} 2 \ 326 "Gateway resolves to wrong nexthop device - VRF" 327} 328 329################################################################################ 330# IPv6 tests 331# 332 333run_ip6() 334{ 335 local table="$1" 336 local prefix="$2" 337 local gw="$3" 338 local dev="$4" 339 local exp_rc="$5" 340 local desc="$6" 341 342 # dev arg may be empty 343 [ -n "${dev}" ] && dev="dev ${dev}" 344 345 run_cmd ip -6 ro add table "${table}" "${prefix}"/128 via "${gw}" "${dev}" onlink 346 log_test $? ${exp_rc} "${desc}" 347} 348 349run_ip6_mpath() 350{ 351 local table="$1" 352 local prefix="$2" 353 local opts="$3" 354 local nh1="$4" 355 local nh2="$5" 356 local exp_rc="$6" 357 local desc="$7" 358 359 run_cmd ip -6 ro add table "${table}" "${prefix}"/128 "${opts}" \ 360 nexthop via ${nh1} nexthop via ${nh2} 361 log_test $? ${exp_rc} "${desc}" 362} 363 364valid_onlink_ipv6() 365{ 366 # - unicast connected, unicast recursive, v4-mapped 367 # 368 log_subsection "default VRF - main table" 369 370 run_ip6 254 ${TEST_NET6[1]}::1 ${V6ADDRS[p1]/::*}::64 ${NETIFS[p1]} 0 "unicast connected" 371 run_ip6 254 ${TEST_NET6[1]}::2 ${RECGW6[1]} ${NETIFS[p1]} 0 "unicast recursive" 372 run_ip6 254 ${TEST_NET6[1]}::3 ::ffff:${TEST_NET4IN6[1]} ${NETIFS[p1]} 0 "v4-mapped" 373 374 log_subsection "VRF ${VRF}" 375 376 run_ip6 ${VRF_TABLE} ${TEST_NET6[2]}::1 ${V6ADDRS[p5]/::*}::64 ${NETIFS[p5]} 0 "unicast connected" 377 run_ip6 ${VRF_TABLE} ${TEST_NET6[2]}::2 ${RECGW6[2]} ${NETIFS[p5]} 0 "unicast recursive" 378 run_ip6 ${VRF_TABLE} ${TEST_NET6[2]}::3 ::ffff:${TEST_NET4IN6[2]} ${NETIFS[p5]} 0 "v4-mapped" 379 380 log_subsection "VRF device, PBR table" 381 382 run_ip6 ${PBR_TABLE} ${TEST_NET6[2]}::4 ${V6ADDRS[p5]/::*}::64 ${NETIFS[p5]} 0 "unicast connected" 383 run_ip6 ${PBR_TABLE} ${TEST_NET6[2]}::5 ${RECGW6[2]} ${NETIFS[p5]} 0 "unicast recursive" 384 run_ip6 ${PBR_TABLE} ${TEST_NET6[2]}::6 ::ffff:${TEST_NET4IN6[2]} ${NETIFS[p5]} 0 "v4-mapped" 385 386 # multipath version 387 # 388 log_subsection "default VRF - main table - multipath" 389 390 run_ip6_mpath 254 ${TEST_NET6[1]}::4 "onlink" \ 391 "${V6ADDRS[p1]/::*}::64 dev ${NETIFS[p1]}" \ 392 "${V6ADDRS[p3]/::*}::64 dev ${NETIFS[p3]}" \ 393 0 "unicast connected - multipath onlink" 394 395 run_ip6_mpath 254 ${TEST_NET6[1]}::5 "onlink" \ 396 "${RECGW6[1]} dev ${NETIFS[p1]}" \ 397 "${RECGW6[2]} dev ${NETIFS[p3]}" \ 398 0 "unicast recursive - multipath onlink" 399 400 run_ip6_mpath 254 ${TEST_NET6[1]}::6 "onlink" \ 401 "::ffff:${TEST_NET4IN6[1]} dev ${NETIFS[p1]}" \ 402 "::ffff:${TEST_NET4IN6[2]} dev ${NETIFS[p3]}" \ 403 0 "v4-mapped - multipath onlink" 404 405 run_ip6_mpath 254 ${TEST_NET6[1]}::7 "" \ 406 "${V6ADDRS[p1]/::*}::64 dev ${NETIFS[p1]} onlink" \ 407 "${V6ADDRS[p3]/::*}::64 dev ${NETIFS[p3]} onlink" \ 408 0 "unicast connected - multipath onlink both nexthops" 409 410 run_ip6_mpath 254 ${TEST_NET6[1]}::8 "" \ 411 "${V6ADDRS[p1]/::*}::64 dev ${NETIFS[p1]} onlink" \ 412 "${V6ADDRS[p3]/::*}::64 dev ${NETIFS[p3]}" \ 413 0 "unicast connected - multipath onlink first only" 414 415 run_ip6_mpath 254 ${TEST_NET6[1]}::9 "" \ 416 "${V6ADDRS[p1]/::*}::64 dev ${NETIFS[p1]}" \ 417 "${V6ADDRS[p3]/::*}::64 dev ${NETIFS[p3]} onlink" \ 418 0 "unicast connected - multipath onlink second only" 419} 420 421invalid_onlink_ipv6() 422{ 423 local lladdr 424 425 lladdr=$(get_linklocal ${NETIFS[p1]}) || return 1 426 427 run_ip6 254 ${TEST_NET6[1]}::11 ${V6ADDRS[p1]} ${NETIFS[p1]} 2 \ 428 "Invalid gw - local unicast address" 429 run_ip6 254 ${TEST_NET6[1]}::12 ${lladdr} ${NETIFS[p1]} 2 \ 430 "Invalid gw - local linklocal address" 431 run_ip6 254 ${TEST_NET6[1]}::12 ${MCAST6} ${NETIFS[p1]} 2 \ 432 "Invalid gw - multicast address" 433 434 lladdr=$(get_linklocal ${NETIFS[p5]}) || return 1 435 run_ip6 ${VRF_TABLE} ${TEST_NET6[2]}::11 ${V6ADDRS[p5]} ${NETIFS[p5]} 2 \ 436 "Invalid gw - local unicast address, VRF" 437 run_ip6 ${VRF_TABLE} ${TEST_NET6[2]}::12 ${lladdr} ${NETIFS[p5]} 2 \ 438 "Invalid gw - local linklocal address, VRF" 439 run_ip6 ${VRF_TABLE} ${TEST_NET6[2]}::12 ${MCAST6} ${NETIFS[p5]} 2 \ 440 "Invalid gw - multicast address, VRF" 441 442 run_ip6 254 ${TEST_NET6[1]}::101 ${V6ADDRS[p1]} "" 2 \ 443 "No nexthop device given" 444 445 # default VRF validation is done against LOCAL table 446 # run_ip6 254 ${TEST_NET6[1]}::102 ${V6ADDRS[p3]/::[0-9]/::64} ${NETIFS[p1]} 2 \ 447 # "Gateway resolves to wrong nexthop device" 448 449 run_ip6 ${VRF_TABLE} ${TEST_NET6[2]}::103 ${V6ADDRS[p7]/::[0-9]/::64} ${NETIFS[p5]} 2 \ 450 "Gateway resolves to wrong nexthop device - VRF" 451} 452 453run_onlink_tests() 454{ 455 log_section "IPv4 onlink" 456 log_subsection "Valid onlink commands" 457 valid_onlink_ipv4 458 log_subsection "Invalid onlink commands" 459 invalid_onlink_ipv4 460 461 log_section "IPv6 onlink" 462 log_subsection "Valid onlink commands" 463 valid_onlink_ipv6 464 log_subsection "Invalid onlink commands" 465 invalid_onlink_ipv6 466} 467 468################################################################################ 469# usage 470 471usage() 472{ 473 cat <<EOF 474usage: ${0##*/} OPTS 475 476 -p Pause on fail 477 -v verbose mode (show commands and output) 478EOF 479} 480 481################################################################################ 482# main 483 484nsuccess=0 485nfail=0 486 487while getopts :t:pPhv o 488do 489 case $o in 490 p) PAUSE_ON_FAIL=yes;; 491 v) VERBOSE=$(($VERBOSE + 1));; 492 h) usage; exit 0;; 493 *) usage; exit 1;; 494 esac 495done 496 497cleanup 498setup 499run_onlink_tests 500cleanup 501 502if [ "$TESTS" != "none" ]; then 503 printf "\nTests passed: %3d\n" ${nsuccess} 504 printf "Tests failed: %3d\n" ${nfail} 505fi 506