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