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