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