1 #!/bin/bash 2 # SPDX-License-Identifier: GPL-2.0 3 4 # This test is for checking IPv4 and IPv6 FIB rules API 5 6 source lib.sh 7 ret=0 8 PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no} 9 10 RTABLE=100 11 RTABLE_PEER=101 12 RTABLE_VRF=102 13 GW_IP4=192.51.100.2 14 SRC_IP=192.51.100.3 15 GW_IP6=2001:db8:1::2 16 SRC_IP6=2001:db8:1::3 17 18 DEV_ADDR=192.51.100.1 19 DEV_ADDR6=2001:db8:1::1 20 DEV=dummy0 21 TESTS=" 22 fib_rule6 23 fib_rule4 24 fib_rule6_connect 25 fib_rule4_connect 26 fib_rule6_vrf 27 fib_rule4_vrf 28 " 29 30 SELFTEST_PATH="" 31 32 log_test() 33 { 34 local rc=$1 35 local expected=$2 36 local msg="$3" 37 38 $IP rule show | grep -q l3mdev 39 if [ $? -eq 0 ]; then 40 msg="$msg (VRF)" 41 fi 42 43 if [ ${rc} -eq ${expected} ]; then 44 nsuccess=$((nsuccess+1)) 45 printf "\n TEST: %-60s [ OK ]\n" "${msg}" 46 else 47 ret=1 48 nfail=$((nfail+1)) 49 printf "\n TEST: %-60s [FAIL]\n" "${msg}" 50 if [ "${PAUSE_ON_FAIL}" = "yes" ]; then 51 echo 52 echo "hit enter to continue, 'q' to quit" 53 read a 54 [ "$a" = "q" ] && exit 1 55 fi 56 fi 57 } 58 59 log_section() 60 { 61 echo 62 echo "######################################################################" 63 echo "TEST SECTION: $*" 64 echo "######################################################################" 65 } 66 67 check_nettest() 68 { 69 if which nettest > /dev/null 2>&1; then 70 return 0 71 fi 72 73 # Add the selftest directory to PATH if not already done 74 if [ "${SELFTEST_PATH}" = "" ]; then 75 SELFTEST_PATH="$(dirname $0)" 76 PATH="${PATH}:${SELFTEST_PATH}" 77 78 # Now retry with the new path 79 if which nettest > /dev/null 2>&1; then 80 return 0 81 fi 82 83 if [ "${ret}" -eq 0 ]; then 84 ret="${ksft_skip}" 85 fi 86 echo "nettest not found (try 'make -C ${SELFTEST_PATH} nettest')" 87 fi 88 89 return 1 90 } 91 92 setup() 93 { 94 set -e 95 setup_ns testns 96 IP="ip -netns $testns" 97 98 $IP link add dummy0 type dummy 99 $IP link set dev dummy0 up 100 $IP address add $DEV_ADDR/24 dev dummy0 101 $IP -6 address add $DEV_ADDR6/64 dev dummy0 102 103 set +e 104 } 105 106 cleanup() 107 { 108 $IP link del dev dummy0 &> /dev/null 109 cleanup_ns $testns 110 } 111 112 setup_peer() 113 { 114 set -e 115 116 setup_ns peerns 117 IP_PEER="ip -netns $peerns" 118 $IP_PEER link set dev lo up 119 120 ip link add name veth0 netns $testns type veth \ 121 peer name veth1 netns $peerns 122 $IP link set dev veth0 up 123 $IP_PEER link set dev veth1 up 124 125 $IP address add 192.0.2.10 peer 192.0.2.11/32 dev veth0 126 $IP_PEER address add 192.0.2.11 peer 192.0.2.10/32 dev veth1 127 128 $IP address add 2001:db8::10 peer 2001:db8::11/128 dev veth0 nodad 129 $IP_PEER address add 2001:db8::11 peer 2001:db8::10/128 dev veth1 nodad 130 131 $IP_PEER address add 198.51.100.11/32 dev lo 132 $IP route add table $RTABLE_PEER 198.51.100.11/32 via 192.0.2.11 133 134 $IP_PEER address add 2001:db8::1:11/128 dev lo 135 $IP route add table $RTABLE_PEER 2001:db8::1:11/128 via 2001:db8::11 136 137 set +e 138 } 139 140 cleanup_peer() 141 { 142 $IP link del dev veth0 143 ip netns del $peerns 144 } 145 146 setup_vrf() 147 { 148 $IP link add name vrf0 up type vrf table $RTABLE_VRF 149 $IP link set dev $DEV master vrf0 150 } 151 152 cleanup_vrf() 153 { 154 $IP link del dev vrf0 155 } 156 157 fib_check_iproute_support() 158 { 159 ip rule help 2>&1 | grep -q $1 160 if [ $? -ne 0 ]; then 161 echo "SKIP: iproute2 iprule too old, missing $1 match" 162 return 1 163 fi 164 165 ip route get help 2>&1 | grep -q $2 166 if [ $? -ne 0 ]; then 167 echo "SKIP: iproute2 get route too old, missing $2 match" 168 return 1 169 fi 170 171 return 0 172 } 173 174 fib_rule6_del() 175 { 176 $IP -6 rule del $1 177 log_test $? 0 "rule6 del $1" 178 } 179 180 fib_rule6_del_by_pref() 181 { 182 pref=$($IP -6 rule show $1 table $RTABLE | cut -d ":" -f 1) 183 $IP -6 rule del pref $pref 184 } 185 186 fib_rule6_test_match_n_redirect() 187 { 188 local match="$1" 189 local getmatch="$2" 190 local description="$3" 191 192 $IP -6 rule add $match table $RTABLE 193 $IP -6 route get $GW_IP6 $getmatch | grep -q "table $RTABLE" 194 log_test $? 0 "rule6 check: $description" 195 196 fib_rule6_del_by_pref "$match" 197 log_test $? 0 "rule6 del by pref: $description" 198 } 199 200 fib_rule6_test_reject() 201 { 202 local match="$1" 203 local rc 204 205 $IP -6 rule add $match table $RTABLE 2>/dev/null 206 rc=$? 207 log_test $rc 2 "rule6 check: $match" 208 209 if [ $rc -eq 0 ]; then 210 $IP -6 rule del $match table $RTABLE 211 fi 212 } 213 214 fib_rule6_test() 215 { 216 local getmatch 217 local match 218 local cnt 219 220 # setup the fib rule redirect route 221 $IP -6 route add table $RTABLE default via $GW_IP6 dev $DEV onlink 222 223 match="oif $DEV" 224 fib_rule6_test_match_n_redirect "$match" "$match" "oif redirect to table" 225 226 match="from $SRC_IP6 iif $DEV" 227 fib_rule6_test_match_n_redirect "$match" "$match" "iif redirect to table" 228 229 # Reject dsfield (tos) options which have ECN bits set 230 for cnt in $(seq 1 3); do 231 match="dsfield $cnt" 232 fib_rule6_test_reject "$match" 233 done 234 235 # Don't take ECN bits into account when matching on dsfield 236 match="tos 0x10" 237 for cnt in "0x10" "0x11" "0x12" "0x13"; do 238 # Using option 'tos' instead of 'dsfield' as old iproute2 239 # versions don't support 'dsfield' in ip rule show. 240 getmatch="tos $cnt" 241 fib_rule6_test_match_n_redirect "$match" "$getmatch" \ 242 "$getmatch redirect to table" 243 done 244 245 match="fwmark 0x64" 246 getmatch="mark 0x64" 247 fib_rule6_test_match_n_redirect "$match" "$getmatch" "fwmark redirect to table" 248 249 fib_check_iproute_support "uidrange" "uid" 250 if [ $? -eq 0 ]; then 251 match="uidrange 100-100" 252 getmatch="uid 100" 253 fib_rule6_test_match_n_redirect "$match" "$getmatch" "uid redirect to table" 254 fi 255 256 fib_check_iproute_support "sport" "sport" 257 if [ $? -eq 0 ]; then 258 match="sport 666 dport 777" 259 fib_rule6_test_match_n_redirect "$match" "$match" "sport and dport redirect to table" 260 fi 261 262 fib_check_iproute_support "ipproto" "ipproto" 263 if [ $? -eq 0 ]; then 264 match="ipproto tcp" 265 fib_rule6_test_match_n_redirect "$match" "$match" "ipproto match" 266 fi 267 268 fib_check_iproute_support "ipproto" "ipproto" 269 if [ $? -eq 0 ]; then 270 match="ipproto ipv6-icmp" 271 fib_rule6_test_match_n_redirect "$match" "$match" "ipproto ipv6-icmp match" 272 fi 273 } 274 275 fib_rule6_vrf_test() 276 { 277 setup_vrf 278 fib_rule6_test 279 cleanup_vrf 280 } 281 282 # Verify that the IPV6_TCLASS option of UDPv6 and TCPv6 sockets is properly 283 # taken into account when connecting the socket and when sending packets. 284 fib_rule6_connect_test() 285 { 286 local dsfield 287 288 if ! check_nettest; then 289 echo "SKIP: Could not run test without nettest tool" 290 return 291 fi 292 293 setup_peer 294 $IP -6 rule add dsfield 0x04 table $RTABLE_PEER 295 296 # Combine the base DS Field value (0x04) with all possible ECN values 297 # (Not-ECT: 0, ECT(1): 1, ECT(0): 2, CE: 3). 298 # The ECN bits shouldn't influence the result of the test. 299 for dsfield in 0x04 0x05 0x06 0x07; do 300 nettest -q -6 -B -t 5 -N $testns -O $peerns -U -D \ 301 -Q "${dsfield}" -l 2001:db8::1:11 -r 2001:db8::1:11 302 log_test $? 0 "rule6 dsfield udp connect (dsfield ${dsfield})" 303 304 nettest -q -6 -B -t 5 -N $testns -O $peerns -Q "${dsfield}" \ 305 -l 2001:db8::1:11 -r 2001:db8::1:11 306 log_test $? 0 "rule6 dsfield tcp connect (dsfield ${dsfield})" 307 done 308 309 $IP -6 rule del dsfield 0x04 table $RTABLE_PEER 310 cleanup_peer 311 } 312 313 fib_rule4_del() 314 { 315 $IP rule del $1 316 log_test $? 0 "del $1" 317 } 318 319 fib_rule4_del_by_pref() 320 { 321 pref=$($IP rule show $1 table $RTABLE | cut -d ":" -f 1) 322 $IP rule del pref $pref 323 } 324 325 fib_rule4_test_match_n_redirect() 326 { 327 local match="$1" 328 local getmatch="$2" 329 local description="$3" 330 331 $IP rule add $match table $RTABLE 332 $IP route get $GW_IP4 $getmatch | grep -q "table $RTABLE" 333 log_test $? 0 "rule4 check: $description" 334 335 fib_rule4_del_by_pref "$match" 336 log_test $? 0 "rule4 del by pref: $description" 337 } 338 339 fib_rule4_test_reject() 340 { 341 local match="$1" 342 local rc 343 344 $IP rule add $match table $RTABLE 2>/dev/null 345 rc=$? 346 log_test $rc 2 "rule4 check: $match" 347 348 if [ $rc -eq 0 ]; then 349 $IP rule del $match table $RTABLE 350 fi 351 } 352 353 fib_rule4_test() 354 { 355 local getmatch 356 local match 357 local cnt 358 359 # setup the fib rule redirect route 360 $IP route add table $RTABLE default via $GW_IP4 dev $DEV onlink 361 362 match="oif $DEV" 363 fib_rule4_test_match_n_redirect "$match" "$match" "oif redirect to table" 364 365 # need enable forwarding and disable rp_filter temporarily as all the 366 # addresses are in the same subnet and egress device == ingress device. 367 ip netns exec $testns sysctl -qw net.ipv4.ip_forward=1 368 ip netns exec $testns sysctl -qw net.ipv4.conf.$DEV.rp_filter=0 369 match="from $SRC_IP iif $DEV" 370 fib_rule4_test_match_n_redirect "$match" "$match" "iif redirect to table" 371 ip netns exec $testns sysctl -qw net.ipv4.ip_forward=0 372 373 # Reject dsfield (tos) options which have ECN bits set 374 for cnt in $(seq 1 3); do 375 match="dsfield $cnt" 376 fib_rule4_test_reject "$match" 377 done 378 379 # Don't take ECN bits into account when matching on dsfield 380 match="tos 0x10" 381 for cnt in "0x10" "0x11" "0x12" "0x13"; do 382 # Using option 'tos' instead of 'dsfield' as old iproute2 383 # versions don't support 'dsfield' in ip rule show. 384 getmatch="tos $cnt" 385 fib_rule4_test_match_n_redirect "$match" "$getmatch" \ 386 "$getmatch redirect to table" 387 done 388 389 match="fwmark 0x64" 390 getmatch="mark 0x64" 391 fib_rule4_test_match_n_redirect "$match" "$getmatch" "fwmark redirect to table" 392 393 fib_check_iproute_support "uidrange" "uid" 394 if [ $? -eq 0 ]; then 395 match="uidrange 100-100" 396 getmatch="uid 100" 397 fib_rule4_test_match_n_redirect "$match" "$getmatch" "uid redirect to table" 398 fi 399 400 fib_check_iproute_support "sport" "sport" 401 if [ $? -eq 0 ]; then 402 match="sport 666 dport 777" 403 fib_rule4_test_match_n_redirect "$match" "$match" "sport and dport redirect to table" 404 fi 405 406 fib_check_iproute_support "ipproto" "ipproto" 407 if [ $? -eq 0 ]; then 408 match="ipproto tcp" 409 fib_rule4_test_match_n_redirect "$match" "$match" "ipproto tcp match" 410 fi 411 412 fib_check_iproute_support "ipproto" "ipproto" 413 if [ $? -eq 0 ]; then 414 match="ipproto icmp" 415 fib_rule4_test_match_n_redirect "$match" "$match" "ipproto icmp match" 416 fi 417 } 418 419 fib_rule4_vrf_test() 420 { 421 setup_vrf 422 fib_rule4_test 423 cleanup_vrf 424 } 425 426 # Verify that the IP_TOS option of UDPv4 and TCPv4 sockets is properly taken 427 # into account when connecting the socket and when sending packets. 428 fib_rule4_connect_test() 429 { 430 local dsfield 431 432 if ! check_nettest; then 433 echo "SKIP: Could not run test without nettest tool" 434 return 435 fi 436 437 setup_peer 438 $IP -4 rule add dsfield 0x04 table $RTABLE_PEER 439 440 # Combine the base DS Field value (0x04) with all possible ECN values 441 # (Not-ECT: 0, ECT(1): 1, ECT(0): 2, CE: 3). 442 # The ECN bits shouldn't influence the result of the test. 443 for dsfield in 0x04 0x05 0x06 0x07; do 444 nettest -q -B -t 5 -N $testns -O $peerns -D -U -Q "${dsfield}" \ 445 -l 198.51.100.11 -r 198.51.100.11 446 log_test $? 0 "rule4 dsfield udp connect (dsfield ${dsfield})" 447 448 nettest -q -B -t 5 -N $testns -O $peerns -Q "${dsfield}" \ 449 -l 198.51.100.11 -r 198.51.100.11 450 log_test $? 0 "rule4 dsfield tcp connect (dsfield ${dsfield})" 451 done 452 453 $IP -4 rule del dsfield 0x04 table $RTABLE_PEER 454 cleanup_peer 455 } 456 457 run_fibrule_tests() 458 { 459 log_section "IPv4 fib rule" 460 fib_rule4_test 461 log_section "IPv6 fib rule" 462 fib_rule6_test 463 } 464 ################################################################################ 465 # usage 466 467 usage() 468 { 469 cat <<EOF 470 usage: ${0##*/} OPTS 471 472 -t <test> Test(s) to run (default: all) 473 (options: $TESTS) 474 EOF 475 } 476 477 ################################################################################ 478 # main 479 480 while getopts ":t:h" opt; do 481 case $opt in 482 t) TESTS=$OPTARG;; 483 h) usage; exit 0;; 484 *) usage; exit 1;; 485 esac 486 done 487 488 if [ "$(id -u)" -ne 0 ];then 489 echo "SKIP: Need root privileges" 490 exit $ksft_skip 491 fi 492 493 if [ ! -x "$(command -v ip)" ]; then 494 echo "SKIP: Could not run test without ip tool" 495 exit $ksft_skip 496 fi 497 498 # start clean 499 cleanup &> /dev/null 500 setup 501 for t in $TESTS 502 do 503 case $t in 504 fib_rule6_test|fib_rule6) fib_rule6_test;; 505 fib_rule4_test|fib_rule4) fib_rule4_test;; 506 fib_rule6_connect_test|fib_rule6_connect) fib_rule6_connect_test;; 507 fib_rule4_connect_test|fib_rule4_connect) fib_rule4_connect_test;; 508 fib_rule6_vrf_test|fib_rule6_vrf) fib_rule6_vrf_test;; 509 fib_rule4_vrf_test|fib_rule4_vrf) fib_rule4_vrf_test;; 510 511 help) echo "Test names: $TESTS"; exit 0;; 512 513 esac 514 done 515 cleanup 516 517 if [ "$TESTS" != "none" ]; then 518 printf "\nTests passed: %3d\n" ${nsuccess} 519 printf "Tests failed: %3d\n" ${nfail} 520 fi 521 522 exit $ret
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.