669 lines · bash
1#!/bin/bash2# SPDX-License-Identifier: GPL-2.03 4# This test is for checking IPv4 and IPv6 FIB rules API5 6source lib.sh7ret=08PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no}9 10RTABLE=10011RTABLE_PEER=10112RTABLE_VRF=10213GW_IP4=192.51.100.214SRC_IP=192.51.100.315GW_IP6=2001:db8:1::216SRC_IP6=2001:db8:1::317 18DEV_ADDR=192.51.100.119DEV_ADDR6=2001:db8:1::120DEV=dummy021TESTS="22 fib_rule623 fib_rule424 fib_rule6_connect25 fib_rule4_connect26 fib_rule6_vrf27 fib_rule4_vrf28"29 30SELFTEST_PATH=""31 32log_test()33{34 local rc=$135 local expected=$236 local msg="$3"37 38 if [ ${rc} -eq ${expected} ]; then39 nsuccess=$((nsuccess+1))40 printf " TEST: %-60s [ OK ]\n" "${msg}"41 else42 ret=143 nfail=$((nfail+1))44 printf " TEST: %-60s [FAIL]\n" "${msg}"45 if [ "${PAUSE_ON_FAIL}" = "yes" ]; then46 echo47 echo "hit enter to continue, 'q' to quit"48 read a49 [ "$a" = "q" ] && exit 150 fi51 fi52}53 54setup()55{56 set -e57 setup_ns testns58 IP="ip -netns $testns"59 60 $IP link add dummy0 type dummy61 $IP link set dev dummy0 up62 $IP address add $DEV_ADDR/24 dev dummy063 $IP -6 address add $DEV_ADDR6/64 dev dummy064 65 set +e66}67 68cleanup()69{70 $IP link del dev dummy0 &> /dev/null71 cleanup_ns $testns72}73 74setup_peer()75{76 set -e77 78 setup_ns peerns79 IP_PEER="ip -netns $peerns"80 $IP_PEER link set dev lo up81 82 ip link add name veth0 netns $testns type veth \83 peer name veth1 netns $peerns84 $IP link set dev veth0 up85 $IP_PEER link set dev veth1 up86 87 $IP address add 192.0.2.10 peer 192.0.2.11/32 dev veth088 $IP_PEER address add 192.0.2.11 peer 192.0.2.10/32 dev veth189 90 $IP address add 2001:db8::10 peer 2001:db8::11/128 dev veth0 nodad91 $IP_PEER address add 2001:db8::11 peer 2001:db8::10/128 dev veth1 nodad92 93 $IP_PEER address add 198.51.100.11/32 dev lo94 $IP route add table $RTABLE_PEER 198.51.100.11/32 via 192.0.2.1195 96 $IP_PEER address add 2001:db8::1:11/128 dev lo97 $IP route add table $RTABLE_PEER 2001:db8::1:11/128 via 2001:db8::1198 99 set +e100}101 102cleanup_peer()103{104 $IP link del dev veth0105 ip netns del $peerns106}107 108setup_vrf()109{110 $IP link add name vrf0 up type vrf table $RTABLE_VRF111 $IP link set dev $DEV master vrf0112}113 114cleanup_vrf()115{116 $IP link del dev vrf0117}118 119fib_check_iproute_support()120{121 ip rule help 2>&1 | grep -q $1122 if [ $? -ne 0 ]; then123 echo "SKIP: iproute2 iprule too old, missing $1 match"124 return 1125 fi126 127 ip route get help 2>&1 | grep -q $2128 if [ $? -ne 0 ]; then129 echo "SKIP: iproute2 get route too old, missing $2 match"130 return 1131 fi132 133 return 0134}135 136fib_rule6_del()137{138 $IP -6 rule del $1139 log_test $? 0 "rule6 del $1"140}141 142fib_rule6_del_by_pref()143{144 pref=$($IP -6 rule show $1 table $RTABLE | cut -d ":" -f 1)145 $IP -6 rule del pref $pref146}147 148fib_rule6_test_match_n_redirect()149{150 local match="$1"151 local getmatch="$2"152 local getnomatch="$3"153 local description="$4"154 local nomatch_description="$5"155 156 $IP -6 rule add $match table $RTABLE157 $IP -6 route get $GW_IP6 $getmatch | grep -q "table $RTABLE"158 log_test $? 0 "rule6 check: $description"159 160 $IP -6 route get $GW_IP6 $getnomatch 2>&1 | grep -q "table $RTABLE"161 log_test $? 1 "rule6 check: $nomatch_description"162 163 fib_rule6_del_by_pref "$match"164 log_test $? 0 "rule6 del by pref: $description"165}166 167fib_rule6_test_reject()168{169 local match="$1"170 local rc171 172 $IP -6 rule add $match table $RTABLE 2>/dev/null173 rc=$?174 log_test $rc 2 "rule6 check: $match"175 176 if [ $rc -eq 0 ]; then177 $IP -6 rule del $match table $RTABLE178 fi179}180 181fib_rule6_test()182{183 local ext_name=$1; shift184 local getnomatch185 local getmatch186 local match187 local cnt188 189 echo190 echo "IPv6 FIB rule tests $ext_name"191 192 # setup the fib rule redirect route193 $IP -6 route add table $RTABLE default via $GW_IP6 dev $DEV onlink194 195 match="oif $DEV"196 getnomatch="oif lo"197 fib_rule6_test_match_n_redirect "$match" "$match" "$getnomatch" \198 "oif redirect to table" "oif no redirect to table"199 200 match="from $SRC_IP6 iif $DEV"201 getnomatch="from $SRC_IP6 iif lo"202 fib_rule6_test_match_n_redirect "$match" "$match" "$getnomatch" \203 "iif redirect to table" "iif no redirect to table"204 205 # Reject dsfield (tos) options which have ECN bits set206 for cnt in $(seq 1 3); do207 match="dsfield $cnt"208 fib_rule6_test_reject "$match"209 done210 211 # Don't take ECN bits into account when matching on dsfield212 match="tos 0x10"213 for cnt in "0x10" "0x11" "0x12" "0x13"; do214 # Using option 'tos' instead of 'dsfield' as old iproute2215 # versions don't support 'dsfield' in ip rule show.216 getmatch="tos $cnt"217 getnomatch="tos 0x20"218 fib_rule6_test_match_n_redirect "$match" "$getmatch" \219 "$getnomatch" "$getmatch redirect to table" \220 "$getnomatch no redirect to table"221 done222 223 # Re-test TOS matching, but with input routes since they are handled224 # differently from output routes.225 match="tos 0x10"226 for cnt in "0x10" "0x11" "0x12" "0x13"; do227 getmatch="tos $cnt"228 getnomatch="tos 0x20"229 fib_rule6_test_match_n_redirect "$match" \230 "from $SRC_IP6 iif $DEV $getmatch" \231 "from $SRC_IP6 iif $DEV $getnomatch" \232 "iif $getmatch redirect to table" \233 "iif $getnomatch no redirect to table"234 done235 236 match="fwmark 0x64"237 getmatch="mark 0x64"238 getnomatch="mark 0x63"239 fib_rule6_test_match_n_redirect "$match" "$getmatch" "$getnomatch" \240 "fwmark redirect to table" "fwmark no redirect to table"241 242 fib_check_iproute_support "uidrange" "uid"243 if [ $? -eq 0 ]; then244 match="uidrange 100-100"245 getmatch="uid 100"246 getnomatch="uid 101"247 fib_rule6_test_match_n_redirect "$match" "$getmatch" \248 "$getnomatch" "uid redirect to table" \249 "uid no redirect to table"250 fi251 252 fib_check_iproute_support "sport" "sport"253 if [ $? -eq 0 ]; then254 match="sport 666 dport 777"255 getnomatch="sport 667 dport 778"256 fib_rule6_test_match_n_redirect "$match" "$match" \257 "$getnomatch" "sport and dport redirect to table" \258 "sport and dport no redirect to table"259 fi260 261 fib_check_iproute_support "ipproto" "ipproto"262 if [ $? -eq 0 ]; then263 match="ipproto tcp"264 getnomatch="ipproto udp"265 fib_rule6_test_match_n_redirect "$match" "$match" \266 "$getnomatch" "ipproto tcp match" "ipproto udp no match"267 fi268 269 fib_check_iproute_support "ipproto" "ipproto"270 if [ $? -eq 0 ]; then271 match="ipproto ipv6-icmp"272 getnomatch="ipproto tcp"273 fib_rule6_test_match_n_redirect "$match" "$match" \274 "$getnomatch" "ipproto ipv6-icmp match" \275 "ipproto ipv6-tcp no match"276 fi277 278 fib_check_iproute_support "dscp" "tos"279 if [ $? -eq 0 ]; then280 match="dscp 0x3f"281 getmatch="tos 0xfc"282 getnomatch="tos 0xf4"283 fib_rule6_test_match_n_redirect "$match" "$getmatch" \284 "$getnomatch" "dscp redirect to table" \285 "dscp no redirect to table"286 287 match="dscp 0x3f"288 getmatch="from $SRC_IP6 iif $DEV tos 0xfc"289 getnomatch="from $SRC_IP6 iif $DEV tos 0xf4"290 fib_rule6_test_match_n_redirect "$match" "$getmatch" \291 "$getnomatch" "iif dscp redirect to table" \292 "iif dscp no redirect to table"293 fi294}295 296fib_rule6_vrf_test()297{298 setup_vrf299 fib_rule6_test "- with VRF"300 cleanup_vrf301}302 303# Verify that the IPV6_TCLASS option of UDPv6 and TCPv6 sockets is properly304# taken into account when connecting the socket and when sending packets.305fib_rule6_connect_test()306{307 local dsfield308 309 echo310 echo "IPv6 FIB rule connect tests"311 312 setup_peer313 $IP -6 rule add dsfield 0x04 table $RTABLE_PEER314 315 # Combine the base DS Field value (0x04) with all possible ECN values316 # (Not-ECT: 0, ECT(1): 1, ECT(0): 2, CE: 3).317 # The ECN bits shouldn't influence the result of the test.318 for dsfield in 0x04 0x05 0x06 0x07; do319 nettest -q -6 -B -t 5 -N $testns -O $peerns -U -D \320 -Q "${dsfield}" -l 2001:db8::1:11 -r 2001:db8::1:11321 log_test $? 0 "rule6 dsfield udp connect (dsfield ${dsfield})"322 323 nettest -q -6 -B -t 5 -N $testns -O $peerns -Q "${dsfield}" \324 -l 2001:db8::1:11 -r 2001:db8::1:11325 log_test $? 0 "rule6 dsfield tcp connect (dsfield ${dsfield})"326 done327 328 # Check that UDP and TCP connections fail when using a DS Field that329 # does not match the previously configured FIB rule.330 nettest -q -6 -B -t 5 -N $testns -O $peerns -U -D \331 -Q 0x20 -l 2001:db8::1:11 -r 2001:db8::1:11332 log_test $? 1 "rule6 dsfield udp no connect (dsfield 0x20)"333 334 nettest -q -6 -B -t 5 -N $testns -O $peerns -Q 0x20 \335 -l 2001:db8::1:11 -r 2001:db8::1:11336 log_test $? 1 "rule6 dsfield tcp no connect (dsfield 0x20)"337 338 $IP -6 rule del dsfield 0x04 table $RTABLE_PEER339 340 ip rule help 2>&1 | grep -q dscp341 if [ $? -ne 0 ]; then342 echo "SKIP: iproute2 iprule too old, missing dscp match"343 cleanup_peer344 return345 fi346 347 $IP -6 rule add dscp 0x3f table $RTABLE_PEER348 349 nettest -q -6 -B -t 5 -N $testns -O $peerns -U -D -Q 0xfc \350 -l 2001:db8::1:11 -r 2001:db8::1:11351 log_test $? 0 "rule6 dscp udp connect"352 353 nettest -q -6 -B -t 5 -N $testns -O $peerns -Q 0xfc \354 -l 2001:db8::1:11 -r 2001:db8::1:11355 log_test $? 0 "rule6 dscp tcp connect"356 357 nettest -q -6 -B -t 5 -N $testns -O $peerns -U -D -Q 0xf4 \358 -l 2001:db8::1:11 -r 2001:db8::1:11359 log_test $? 1 "rule6 dscp udp no connect"360 361 nettest -q -6 -B -t 5 -N $testns -O $peerns -Q 0xf4 \362 -l 2001:db8::1:11 -r 2001:db8::1:11363 log_test $? 1 "rule6 dscp tcp no connect"364 365 $IP -6 rule del dscp 0x3f table $RTABLE_PEER366 367 cleanup_peer368}369 370fib_rule4_del()371{372 $IP rule del $1373 log_test $? 0 "del $1"374}375 376fib_rule4_del_by_pref()377{378 pref=$($IP rule show $1 table $RTABLE | cut -d ":" -f 1)379 $IP rule del pref $pref380}381 382fib_rule4_test_match_n_redirect()383{384 local match="$1"385 local getmatch="$2"386 local getnomatch="$3"387 local description="$4"388 local nomatch_description="$5"389 390 $IP rule add $match table $RTABLE391 $IP route get $GW_IP4 $getmatch | grep -q "table $RTABLE"392 log_test $? 0 "rule4 check: $description"393 394 $IP route get $GW_IP4 $getnomatch 2>&1 | grep -q "table $RTABLE"395 log_test $? 1 "rule4 check: $nomatch_description"396 397 fib_rule4_del_by_pref "$match"398 log_test $? 0 "rule4 del by pref: $description"399}400 401fib_rule4_test_reject()402{403 local match="$1"404 local rc405 406 $IP rule add $match table $RTABLE 2>/dev/null407 rc=$?408 log_test $rc 2 "rule4 check: $match"409 410 if [ $rc -eq 0 ]; then411 $IP rule del $match table $RTABLE412 fi413}414 415fib_rule4_test()416{417 local ext_name=$1; shift418 local getnomatch419 local getmatch420 local match421 local cnt422 423 echo424 echo "IPv4 FIB rule tests $ext_name"425 426 # setup the fib rule redirect route427 $IP route add table $RTABLE default via $GW_IP4 dev $DEV onlink428 429 match="oif $DEV"430 getnomatch="oif lo"431 fib_rule4_test_match_n_redirect "$match" "$match" "$getnomatch" \432 "oif redirect to table" "oif no redirect to table"433 434 # Enable forwarding and disable rp_filter as all the addresses are in435 # the same subnet and egress device == ingress device.436 ip netns exec $testns sysctl -qw net.ipv4.ip_forward=1437 ip netns exec $testns sysctl -qw net.ipv4.conf.$DEV.rp_filter=0438 match="from $SRC_IP iif $DEV"439 getnomatch="from $SRC_IP iif lo"440 fib_rule4_test_match_n_redirect "$match" "$match" "$getnomatch" \441 "iif redirect to table" "iif no redirect to table"442 443 # Reject dsfield (tos) options which have ECN bits set444 for cnt in $(seq 1 3); do445 match="dsfield $cnt"446 fib_rule4_test_reject "$match"447 done448 449 # Don't take ECN bits into account when matching on dsfield450 match="tos 0x10"451 for cnt in "0x10" "0x11" "0x12" "0x13"; do452 # Using option 'tos' instead of 'dsfield' as old iproute2453 # versions don't support 'dsfield' in ip rule show.454 getmatch="tos $cnt"455 getnomatch="tos 0x20"456 fib_rule4_test_match_n_redirect "$match" "$getmatch" \457 "$getnomatch" "$getmatch redirect to table" \458 "$getnomatch no redirect to table"459 done460 461 # Re-test TOS matching, but with input routes since they are handled462 # differently from output routes.463 match="tos 0x10"464 for cnt in "0x10" "0x11" "0x12" "0x13"; do465 getmatch="tos $cnt"466 getnomatch="tos 0x20"467 fib_rule4_test_match_n_redirect "$match" \468 "from $SRC_IP iif $DEV $getmatch" \469 "from $SRC_IP iif $DEV $getnomatch" \470 "iif $getmatch redirect to table" \471 "iif $getnomatch no redirect to table"472 done473 474 match="fwmark 0x64"475 getmatch="mark 0x64"476 getnomatch="mark 0x63"477 fib_rule4_test_match_n_redirect "$match" "$getmatch" "$getnomatch" \478 "fwmark redirect to table" "fwmark no redirect to table"479 480 fib_check_iproute_support "uidrange" "uid"481 if [ $? -eq 0 ]; then482 match="uidrange 100-100"483 getmatch="uid 100"484 getnomatch="uid 101"485 fib_rule4_test_match_n_redirect "$match" "$getmatch" \486 "$getnomatch" "uid redirect to table" \487 "uid no redirect to table"488 fi489 490 fib_check_iproute_support "sport" "sport"491 if [ $? -eq 0 ]; then492 match="sport 666 dport 777"493 getnomatch="sport 667 dport 778"494 fib_rule4_test_match_n_redirect "$match" "$match" \495 "$getnomatch" "sport and dport redirect to table" \496 "sport and dport no redirect to table"497 fi498 499 fib_check_iproute_support "ipproto" "ipproto"500 if [ $? -eq 0 ]; then501 match="ipproto tcp"502 getnomatch="ipproto udp"503 fib_rule4_test_match_n_redirect "$match" "$match" \504 "$getnomatch" "ipproto tcp match" \505 "ipproto udp no match"506 fi507 508 fib_check_iproute_support "ipproto" "ipproto"509 if [ $? -eq 0 ]; then510 match="ipproto icmp"511 getnomatch="ipproto tcp"512 fib_rule4_test_match_n_redirect "$match" "$match" \513 "$getnomatch" "ipproto icmp match" \514 "ipproto tcp no match"515 fi516 517 fib_check_iproute_support "dscp" "tos"518 if [ $? -eq 0 ]; then519 match="dscp 0x3f"520 getmatch="tos 0xfc"521 getnomatch="tos 0xf4"522 fib_rule4_test_match_n_redirect "$match" "$getmatch" \523 "$getnomatch" "dscp redirect to table" \524 "dscp no redirect to table"525 526 match="dscp 0x3f"527 getmatch="from $SRC_IP iif $DEV tos 0xfc"528 getnomatch="from $SRC_IP iif $DEV tos 0xf4"529 fib_rule4_test_match_n_redirect "$match" "$getmatch" \530 "$getnomatch" "iif dscp redirect to table" \531 "iif dscp no redirect to table"532 fi533}534 535fib_rule4_vrf_test()536{537 setup_vrf538 fib_rule4_test "- with VRF"539 cleanup_vrf540}541 542# Verify that the IP_TOS option of UDPv4 and TCPv4 sockets is properly taken543# into account when connecting the socket and when sending packets.544fib_rule4_connect_test()545{546 local dsfield547 548 echo549 echo "IPv4 FIB rule connect tests"550 551 setup_peer552 $IP -4 rule add dsfield 0x04 table $RTABLE_PEER553 554 # Combine the base DS Field value (0x04) with all possible ECN values555 # (Not-ECT: 0, ECT(1): 1, ECT(0): 2, CE: 3).556 # The ECN bits shouldn't influence the result of the test.557 for dsfield in 0x04 0x05 0x06 0x07; do558 nettest -q -B -t 5 -N $testns -O $peerns -D -U -Q "${dsfield}" \559 -l 198.51.100.11 -r 198.51.100.11560 log_test $? 0 "rule4 dsfield udp connect (dsfield ${dsfield})"561 562 nettest -q -B -t 5 -N $testns -O $peerns -Q "${dsfield}" \563 -l 198.51.100.11 -r 198.51.100.11564 log_test $? 0 "rule4 dsfield tcp connect (dsfield ${dsfield})"565 done566 567 # Check that UDP and TCP connections fail when using a DS Field that568 # does not match the previously configured FIB rule.569 nettest -q -B -t 5 -N $testns -O $peerns -D -U -Q 0x20 \570 -l 198.51.100.11 -r 198.51.100.11571 log_test $? 1 "rule4 dsfield udp no connect (dsfield 0x20)"572 573 nettest -q -B -t 5 -N $testns -O $peerns -Q 0x20 \574 -l 198.51.100.11 -r 198.51.100.11575 log_test $? 1 "rule4 dsfield tcp no connect (dsfield 0x20)"576 577 $IP -4 rule del dsfield 0x04 table $RTABLE_PEER578 579 ip rule help 2>&1 | grep -q dscp580 if [ $? -ne 0 ]; then581 echo "SKIP: iproute2 iprule too old, missing dscp match"582 cleanup_peer583 return584 fi585 586 $IP -4 rule add dscp 0x3f table $RTABLE_PEER587 588 nettest -q -B -t 5 -N $testns -O $peerns -D -U -Q 0xfc \589 -l 198.51.100.11 -r 198.51.100.11590 log_test $? 0 "rule4 dscp udp connect"591 592 nettest -q -B -t 5 -N $testns -O $peerns -Q 0xfc \593 -l 198.51.100.11 -r 198.51.100.11594 log_test $? 0 "rule4 dscp tcp connect"595 596 nettest -q -B -t 5 -N $testns -O $peerns -D -U -Q 0xf4 \597 -l 198.51.100.11 -r 198.51.100.11598 log_test $? 1 "rule4 dscp udp no connect"599 600 nettest -q -B -t 5 -N $testns -O $peerns -Q 0xf4 \601 -l 198.51.100.11 -r 198.51.100.11602 log_test $? 1 "rule4 dscp tcp no connect"603 604 $IP -4 rule del dscp 0x3f table $RTABLE_PEER605 606 cleanup_peer607}608################################################################################609# usage610 611usage()612{613 cat <<EOF614usage: ${0##*/} OPTS615 616 -t <test> Test(s) to run (default: all)617 (options: $TESTS)618EOF619}620 621################################################################################622# main623 624while getopts ":t:h" opt; do625 case $opt in626 t) TESTS=$OPTARG;;627 h) usage; exit 0;;628 *) usage; exit 1;;629 esac630done631 632if [ "$(id -u)" -ne 0 ];then633 echo "SKIP: Need root privileges"634 exit $ksft_skip635fi636 637if [ ! -x "$(command -v ip)" ]; then638 echo "SKIP: Could not run test without ip tool"639 exit $ksft_skip640fi641 642check_gen_prog "nettest"643 644# start clean645cleanup &> /dev/null646setup647for t in $TESTS648do649 case $t in650 fib_rule6_test|fib_rule6) fib_rule6_test;;651 fib_rule4_test|fib_rule4) fib_rule4_test;;652 fib_rule6_connect_test|fib_rule6_connect) fib_rule6_connect_test;;653 fib_rule4_connect_test|fib_rule4_connect) fib_rule4_connect_test;;654 fib_rule6_vrf_test|fib_rule6_vrf) fib_rule6_vrf_test;;655 fib_rule4_vrf_test|fib_rule4_vrf) fib_rule4_vrf_test;;656 657 help) echo "Test names: $TESTS"; exit 0;;658 659 esac660done661cleanup662 663if [ "$TESTS" != "none" ]; then664 printf "\nTests passed: %3d\n" ${nsuccess}665 printf "Tests failed: %3d\n" ${nfail}666fi667 668exit $ret669