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="$1" 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 namespaces 178 setup_ns ns1 179 IP="ip -netns $ns1" 180 setup_ns ns2 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 ${ns2} up 209 ip -netns $ns2 addr add ${V4ADDRS[p${n}]}/24 dev ${NETIFS[p${n}]} 210 ip -netns $ns2 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 219################################################################################ 220# IPv4 tests 221# 222 223run_ip() 224{ 225 local table="$1" 226 local prefix="$2" 227 local gw="$3" 228 local dev="$4" 229 local exp_rc="$5" 230 local desc="$6" 231 232 # dev arg may be empty 233 [ -n "${dev}" ] && dev="dev ${dev}" 234 235 run_cmd "${IP} ro add table ${table} ${prefix}/32 via ${gw} ${dev} onlink" 236 log_test $? ${exp_rc} "${desc}" 237} 238 239run_ip_mpath() 240{ 241 local table="$1" 242 local prefix="$2" 243 local nh1="$3" 244 local nh2="$4" 245 local exp_rc="$5" 246 local desc="$6" 247 248 # dev arg may be empty 249 [ -n "${dev}" ] && dev="dev ${dev}" 250 251 run_cmd "${IP} ro add table ${table} ${prefix}/32 \ 252 nexthop via ${nh1} nexthop via ${nh2}" 253 log_test $? ${exp_rc} "${desc}" 254} 255 256valid_onlink_ipv4() 257{ 258 # - unicast connected, unicast recursive 259 # 260 log_subsection "default VRF - main table" 261 262 run_ip 254 ${TEST_NET4[1]}.1 ${CONGW[1]} ${NETIFS[p1]} 0 "unicast connected" 263 run_ip 254 ${TEST_NET4[1]}.2 ${RECGW4[1]} ${NETIFS[p1]} 0 "unicast recursive" 264 run_ip 254 ${TEST_NET4[1]}.9 ${CONGW[1]} ${NETIFS[p3]} 0 \ 265 "nexthop device mismatch" 266 267 log_subsection "VRF ${VRF}" 268 269 run_ip ${VRF_TABLE} ${TEST_NET4[2]}.1 ${CONGW[3]} ${NETIFS[p5]} 0 "unicast connected" 270 run_ip ${VRF_TABLE} ${TEST_NET4[2]}.2 ${RECGW4[2]} ${NETIFS[p5]} 0 "unicast recursive" 271 run_ip ${VRF_TABLE} ${TEST_NET4[2]}.10 ${CONGW[3]} ${NETIFS[p7]} 0 \ 272 "nexthop device mismatch" 273 274 log_subsection "VRF device, PBR table" 275 276 run_ip ${PBR_TABLE} ${TEST_NET4[2]}.3 ${CONGW[3]} ${NETIFS[p5]} 0 "unicast connected" 277 run_ip ${PBR_TABLE} ${TEST_NET4[2]}.4 ${RECGW4[2]} ${NETIFS[p5]} 0 "unicast recursive" 278 279 # multipath version 280 # 281 log_subsection "default VRF - main table - multipath" 282 283 run_ip_mpath 254 ${TEST_NET4[1]}.5 \ 284 "${CONGW[1]} dev ${NETIFS[p1]} onlink" \ 285 "${CONGW[2]} dev ${NETIFS[p3]} onlink" \ 286 0 "unicast connected - multipath" 287 288 run_ip_mpath 254 ${TEST_NET4[1]}.6 \ 289 "${RECGW4[1]} dev ${NETIFS[p1]} onlink" \ 290 "${RECGW4[2]} dev ${NETIFS[p3]} onlink" \ 291 0 "unicast recursive - multipath" 292 293 run_ip_mpath 254 ${TEST_NET4[1]}.7 \ 294 "${CONGW[1]} dev ${NETIFS[p1]}" \ 295 "${CONGW[2]} dev ${NETIFS[p3]} onlink" \ 296 0 "unicast connected - multipath onlink first only" 297 298 run_ip_mpath 254 ${TEST_NET4[1]}.8 \ 299 "${CONGW[1]} dev ${NETIFS[p1]} onlink" \ 300 "${CONGW[2]} dev ${NETIFS[p3]}" \ 301 0 "unicast connected - multipath onlink second only" 302} 303 304invalid_onlink_ipv4() 305{ 306 run_ip 254 ${TEST_NET4[1]}.11 ${V4ADDRS[p1]} ${NETIFS[p1]} 2 \ 307 "Invalid gw - local unicast address" 308 run_ip 254 ${TEST_NET4[1]}.12 ${MCAST4} ${NETIFS[p1]} 2 \ 309 "Invalid gw - multicast address" 310 311 run_ip ${VRF_TABLE} ${TEST_NET4[2]}.11 ${V4ADDRS[p5]} ${NETIFS[p5]} 2 \ 312 "Invalid gw - local unicast address, VRF" 313 run_ip ${VRF_TABLE} ${TEST_NET4[2]}.12 ${MCAST4} ${NETIFS[p5]} 2 \ 314 "Invalid gw - multicast address, VRF" 315 316 run_ip 254 ${TEST_NET4[1]}.101 ${V4ADDRS[p1]} "" 2 "No nexthop device given" 317} 318 319################################################################################ 320# IPv6 tests 321# 322 323run_ip6() 324{ 325 local table="$1" 326 local prefix="$2" 327 local gw="$3" 328 local dev="$4" 329 local exp_rc="$5" 330 local desc="$6" 331 332 # dev arg may be empty 333 [ -n "${dev}" ] && dev="dev ${dev}" 334 335 run_cmd "${IP} -6 ro add table ${table} ${prefix}/128 via ${gw} ${dev} onlink" 336 log_test $? ${exp_rc} "${desc}" 337} 338 339run_ip6_mpath() 340{ 341 local table="$1" 342 local prefix="$2" 343 local opts="$3" 344 local nh1="$4" 345 local nh2="$5" 346 local exp_rc="$6" 347 local desc="$7" 348 349 run_cmd "${IP} -6 ro add table ${table} ${prefix}/128 ${opts} \ 350 nexthop via ${nh1} nexthop via ${nh2}" 351 log_test $? ${exp_rc} "${desc}" 352} 353 354valid_onlink_ipv6() 355{ 356 # - unicast connected, unicast recursive, v4-mapped 357 # 358 log_subsection "default VRF - main table" 359 360 run_ip6 254 ${TEST_NET6[1]}::1 ${V6ADDRS[p1]/::*}::64 ${NETIFS[p1]} 0 "unicast connected" 361 run_ip6 254 ${TEST_NET6[1]}::2 ${RECGW6[1]} ${NETIFS[p1]} 0 "unicast recursive" 362 run_ip6 254 ${TEST_NET6[1]}::3 ::ffff:${TEST_NET4IN6[1]} ${NETIFS[p1]} 0 "v4-mapped" 363 run_ip6 254 ${TEST_NET6[1]}::a ${V6ADDRS[p1]/::*}::64 ${NETIFS[p3]} 0 \ 364 "nexthop device mismatch" 365 366 log_subsection "VRF ${VRF}" 367 368 run_ip6 ${VRF_TABLE} ${TEST_NET6[2]}::1 ${V6ADDRS[p5]/::*}::64 ${NETIFS[p5]} 0 "unicast connected" 369 run_ip6 ${VRF_TABLE} ${TEST_NET6[2]}::2 ${RECGW6[2]} ${NETIFS[p5]} 0 "unicast recursive" 370 run_ip6 ${VRF_TABLE} ${TEST_NET6[2]}::3 ::ffff:${TEST_NET4IN6[2]} ${NETIFS[p5]} 0 "v4-mapped" 371 run_ip6 ${VRF_TABLE} ${TEST_NET6[2]}::b ${V6ADDRS[p5]/::*}::64 \ 372 ${NETIFS[p7]} 0 "nexthop device mismatch" 373 374 log_subsection "VRF device, PBR table" 375 376 run_ip6 ${PBR_TABLE} ${TEST_NET6[2]}::4 ${V6ADDRS[p5]/::*}::64 ${NETIFS[p5]} 0 "unicast connected" 377 run_ip6 ${PBR_TABLE} ${TEST_NET6[2]}::5 ${RECGW6[2]} ${NETIFS[p5]} 0 "unicast recursive" 378 run_ip6 ${PBR_TABLE} ${TEST_NET6[2]}::6 ::ffff:${TEST_NET4IN6[2]} ${NETIFS[p5]} 0 "v4-mapped" 379 380 # multipath version 381 # 382 log_subsection "default VRF - main table - multipath" 383 384 run_ip6_mpath 254 ${TEST_NET6[1]}::4 "onlink" \ 385 "${V6ADDRS[p1]/::*}::64 dev ${NETIFS[p1]}" \ 386 "${V6ADDRS[p3]/::*}::64 dev ${NETIFS[p3]}" \ 387 0 "unicast connected - multipath onlink" 388 389 run_ip6_mpath 254 ${TEST_NET6[1]}::5 "onlink" \ 390 "${RECGW6[1]} dev ${NETIFS[p1]}" \ 391 "${RECGW6[2]} dev ${NETIFS[p3]}" \ 392 0 "unicast recursive - multipath onlink" 393 394 run_ip6_mpath 254 ${TEST_NET6[1]}::6 "onlink" \ 395 "::ffff:${TEST_NET4IN6[1]} dev ${NETIFS[p1]}" \ 396 "::ffff:${TEST_NET4IN6[2]} dev ${NETIFS[p3]}" \ 397 0 "v4-mapped - multipath onlink" 398 399 run_ip6_mpath 254 ${TEST_NET6[1]}::7 "" \ 400 "${V6ADDRS[p1]/::*}::64 dev ${NETIFS[p1]} onlink" \ 401 "${V6ADDRS[p3]/::*}::64 dev ${NETIFS[p3]} onlink" \ 402 0 "unicast connected - multipath onlink both nexthops" 403 404 run_ip6_mpath 254 ${TEST_NET6[1]}::8 "" \ 405 "${V6ADDRS[p1]/::*}::64 dev ${NETIFS[p1]} onlink" \ 406 "${V6ADDRS[p3]/::*}::64 dev ${NETIFS[p3]}" \ 407 0 "unicast connected - multipath onlink first only" 408 409 run_ip6_mpath 254 ${TEST_NET6[1]}::9 "" \ 410 "${V6ADDRS[p1]/::*}::64 dev ${NETIFS[p1]}" \ 411 "${V6ADDRS[p3]/::*}::64 dev ${NETIFS[p3]} onlink" \ 412 0 "unicast connected - multipath onlink second only" 413} 414 415invalid_onlink_ipv6() 416{ 417 local lladdr 418 419 lladdr=$(get_linklocal ${NETIFS[p1]}) || return 1 420 421 run_ip6 254 ${TEST_NET6[1]}::11 ${V6ADDRS[p1]} ${NETIFS[p1]} 2 \ 422 "Invalid gw - local unicast address" 423 run_ip6 254 ${TEST_NET6[1]}::12 ${lladdr} ${NETIFS[p1]} 2 \ 424 "Invalid gw - local linklocal address" 425 run_ip6 254 ${TEST_NET6[1]}::12 ${MCAST6} ${NETIFS[p1]} 2 \ 426 "Invalid gw - multicast address" 427 428 lladdr=$(get_linklocal ${NETIFS[p5]}) || return 1 429 run_ip6 ${VRF_TABLE} ${TEST_NET6[2]}::11 ${V6ADDRS[p5]} ${NETIFS[p5]} 2 \ 430 "Invalid gw - local unicast address, VRF" 431 run_ip6 ${VRF_TABLE} ${TEST_NET6[2]}::12 ${lladdr} ${NETIFS[p5]} 2 \ 432 "Invalid gw - local linklocal address, VRF" 433 run_ip6 ${VRF_TABLE} ${TEST_NET6[2]}::12 ${MCAST6} ${NETIFS[p5]} 2 \ 434 "Invalid gw - multicast address, VRF" 435 436 run_ip6 254 ${TEST_NET6[1]}::101 ${V6ADDRS[p1]} "" 2 \ 437 "No nexthop device given" 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