123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505 |
- #!/bin/bash
- # SPDX-License-Identifier: GPL-2.0
- # IPv4 and IPv6 onlink tests
- PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no}
- VERBOSE=0
- # Network interfaces
- # - odd in current namespace; even in peer ns
- declare -A NETIFS
- # default VRF
- NETIFS[p1]=veth1
- NETIFS[p2]=veth2
- NETIFS[p3]=veth3
- NETIFS[p4]=veth4
- # VRF
- NETIFS[p5]=veth5
- NETIFS[p6]=veth6
- NETIFS[p7]=veth7
- NETIFS[p8]=veth8
- # /24 network
- declare -A V4ADDRS
- V4ADDRS[p1]=169.254.1.1
- V4ADDRS[p2]=169.254.1.2
- V4ADDRS[p3]=169.254.3.1
- V4ADDRS[p4]=169.254.3.2
- V4ADDRS[p5]=169.254.5.1
- V4ADDRS[p6]=169.254.5.2
- V4ADDRS[p7]=169.254.7.1
- V4ADDRS[p8]=169.254.7.2
- # /64 network
- declare -A V6ADDRS
- V6ADDRS[p1]=2001:db8:101::1
- V6ADDRS[p2]=2001:db8:101::2
- V6ADDRS[p3]=2001:db8:301::1
- V6ADDRS[p4]=2001:db8:301::2
- V6ADDRS[p5]=2001:db8:501::1
- V6ADDRS[p6]=2001:db8:501::2
- V6ADDRS[p7]=2001:db8:701::1
- V6ADDRS[p8]=2001:db8:701::2
- # Test networks:
- # [1] = default table
- # [2] = VRF
- #
- # /32 host routes
- declare -A TEST_NET4
- TEST_NET4[1]=169.254.101
- TEST_NET4[2]=169.254.102
- # /128 host routes
- declare -A TEST_NET6
- TEST_NET6[1]=2001:db8:101
- TEST_NET6[2]=2001:db8:102
- # connected gateway
- CONGW[1]=169.254.1.254
- CONGW[2]=169.254.3.254
- CONGW[3]=169.254.5.254
- # recursive gateway
- RECGW4[1]=169.254.11.254
- RECGW4[2]=169.254.12.254
- RECGW6[1]=2001:db8:11::64
- RECGW6[2]=2001:db8:12::64
- # for v4 mapped to v6
- declare -A TEST_NET4IN6IN6
- TEST_NET4IN6[1]=10.1.1.254
- TEST_NET4IN6[2]=10.2.1.254
- # mcast address
- MCAST6=ff02::1
- PEER_NS=bart
- PEER_CMD="ip netns exec ${PEER_NS}"
- VRF=lisa
- VRF_TABLE=1101
- PBR_TABLE=101
- ################################################################################
- # utilities
- log_test()
- {
- local rc=$1
- local expected=$2
- local msg="$3"
- if [ ${rc} -eq ${expected} ]; then
- nsuccess=$((nsuccess+1))
- printf " TEST: %-50s [ OK ]\n" "${msg}"
- else
- nfail=$((nfail+1))
- printf " TEST: %-50s [FAIL]\n" "${msg}"
- if [ "${PAUSE_ON_FAIL}" = "yes" ]; then
- echo
- echo "hit enter to continue, 'q' to quit"
- read a
- [ "$a" = "q" ] && exit 1
- fi
- fi
- }
- log_section()
- {
- echo
- echo "######################################################################"
- echo "TEST SECTION: $*"
- echo "######################################################################"
- }
- log_subsection()
- {
- echo
- echo "#########################################"
- echo "TEST SUBSECTION: $*"
- }
- run_cmd()
- {
- local cmd="$*"
- local out
- local rc
- if [ "$VERBOSE" = "1" ]; then
- printf " COMMAND: $cmd\n"
- fi
- out=$(eval $cmd 2>&1)
- rc=$?
- if [ "$VERBOSE" = "1" -a -n "$out" ]; then
- echo " $out"
- fi
- [ "$VERBOSE" = "1" ] && echo
- return $rc
- }
- get_linklocal()
- {
- local dev=$1
- local pfx
- local addr
- addr=$(${pfx} ip -6 -br addr show dev ${dev} | \
- awk '{
- for (i = 3; i <= NF; ++i) {
- if ($i ~ /^fe80/)
- print $i
- }
- }'
- )
- addr=${addr/\/*}
- [ -z "$addr" ] && return 1
- echo $addr
- return 0
- }
- ################################################################################
- #
- setup()
- {
- echo
- echo "########################################"
- echo "Configuring interfaces"
- set -e
- # create namespace
- ip netns add ${PEER_NS}
- ip -netns ${PEER_NS} li set lo up
- # add vrf table
- ip li add ${VRF} type vrf table ${VRF_TABLE}
- ip li set ${VRF} up
- ip ro add table ${VRF_TABLE} unreachable default metric 8192
- ip -6 ro add table ${VRF_TABLE} unreachable default metric 8192
- # create test interfaces
- ip li add ${NETIFS[p1]} type veth peer name ${NETIFS[p2]}
- ip li add ${NETIFS[p3]} type veth peer name ${NETIFS[p4]}
- ip li add ${NETIFS[p5]} type veth peer name ${NETIFS[p6]}
- ip li add ${NETIFS[p7]} type veth peer name ${NETIFS[p8]}
- # enslave vrf interfaces
- for n in 5 7; do
- ip li set ${NETIFS[p${n}]} vrf ${VRF}
- done
- # add addresses
- for n in 1 3 5 7; do
- ip li set ${NETIFS[p${n}]} up
- ip addr add ${V4ADDRS[p${n}]}/24 dev ${NETIFS[p${n}]}
- ip addr add ${V6ADDRS[p${n}]}/64 dev ${NETIFS[p${n}]} nodad
- done
- # move peer interfaces to namespace and add addresses
- for n in 2 4 6 8; do
- ip li set ${NETIFS[p${n}]} netns ${PEER_NS} up
- ip -netns ${PEER_NS} addr add ${V4ADDRS[p${n}]}/24 dev ${NETIFS[p${n}]}
- ip -netns ${PEER_NS} addr add ${V6ADDRS[p${n}]}/64 dev ${NETIFS[p${n}]} nodad
- done
- ip -6 ro add default via ${V6ADDRS[p3]/::[0-9]/::64}
- ip -6 ro add table ${VRF_TABLE} default via ${V6ADDRS[p7]/::[0-9]/::64}
- set +e
- }
- cleanup()
- {
- # make sure we start from a clean slate
- ip netns del ${PEER_NS} 2>/dev/null
- for n in 1 3 5 7; do
- ip link del ${NETIFS[p${n}]} 2>/dev/null
- done
- ip link del ${VRF} 2>/dev/null
- ip ro flush table ${VRF_TABLE}
- ip -6 ro flush table ${VRF_TABLE}
- }
- ################################################################################
- # IPv4 tests
- #
- run_ip()
- {
- local table="$1"
- local prefix="$2"
- local gw="$3"
- local dev="$4"
- local exp_rc="$5"
- local desc="$6"
- # dev arg may be empty
- [ -n "${dev}" ] && dev="dev ${dev}"
- run_cmd ip ro add table "${table}" "${prefix}"/32 via "${gw}" "${dev}" onlink
- log_test $? ${exp_rc} "${desc}"
- }
- run_ip_mpath()
- {
- local table="$1"
- local prefix="$2"
- local nh1="$3"
- local nh2="$4"
- local exp_rc="$5"
- local desc="$6"
- # dev arg may be empty
- [ -n "${dev}" ] && dev="dev ${dev}"
- run_cmd ip ro add table "${table}" "${prefix}"/32 \
- nexthop via ${nh1} nexthop via ${nh2}
- log_test $? ${exp_rc} "${desc}"
- }
- valid_onlink_ipv4()
- {
- # - unicast connected, unicast recursive
- #
- log_subsection "default VRF - main table"
- run_ip 254 ${TEST_NET4[1]}.1 ${CONGW[1]} ${NETIFS[p1]} 0 "unicast connected"
- run_ip 254 ${TEST_NET4[1]}.2 ${RECGW4[1]} ${NETIFS[p1]} 0 "unicast recursive"
- log_subsection "VRF ${VRF}"
- run_ip ${VRF_TABLE} ${TEST_NET4[2]}.1 ${CONGW[3]} ${NETIFS[p5]} 0 "unicast connected"
- run_ip ${VRF_TABLE} ${TEST_NET4[2]}.2 ${RECGW4[2]} ${NETIFS[p5]} 0 "unicast recursive"
- log_subsection "VRF device, PBR table"
- run_ip ${PBR_TABLE} ${TEST_NET4[2]}.3 ${CONGW[3]} ${NETIFS[p5]} 0 "unicast connected"
- run_ip ${PBR_TABLE} ${TEST_NET4[2]}.4 ${RECGW4[2]} ${NETIFS[p5]} 0 "unicast recursive"
- # multipath version
- #
- log_subsection "default VRF - main table - multipath"
- run_ip_mpath 254 ${TEST_NET4[1]}.5 \
- "${CONGW[1]} dev ${NETIFS[p1]} onlink" \
- "${CONGW[2]} dev ${NETIFS[p3]} onlink" \
- 0 "unicast connected - multipath"
- run_ip_mpath 254 ${TEST_NET4[1]}.6 \
- "${RECGW4[1]} dev ${NETIFS[p1]} onlink" \
- "${RECGW4[2]} dev ${NETIFS[p3]} onlink" \
- 0 "unicast recursive - multipath"
- run_ip_mpath 254 ${TEST_NET4[1]}.7 \
- "${CONGW[1]} dev ${NETIFS[p1]}" \
- "${CONGW[2]} dev ${NETIFS[p3]} onlink" \
- 0 "unicast connected - multipath onlink first only"
- run_ip_mpath 254 ${TEST_NET4[1]}.8 \
- "${CONGW[1]} dev ${NETIFS[p1]} onlink" \
- "${CONGW[2]} dev ${NETIFS[p3]}" \
- 0 "unicast connected - multipath onlink second only"
- }
- invalid_onlink_ipv4()
- {
- run_ip 254 ${TEST_NET4[1]}.11 ${V4ADDRS[p1]} ${NETIFS[p1]} 2 \
- "Invalid gw - local unicast address"
- run_ip ${VRF_TABLE} ${TEST_NET4[2]}.11 ${V4ADDRS[p5]} ${NETIFS[p5]} 2 \
- "Invalid gw - local unicast address, VRF"
- run_ip 254 ${TEST_NET4[1]}.101 ${V4ADDRS[p1]} "" 2 "No nexthop device given"
- run_ip 254 ${TEST_NET4[1]}.102 ${V4ADDRS[p3]} ${NETIFS[p1]} 2 \
- "Gateway resolves to wrong nexthop device"
- run_ip ${VRF_TABLE} ${TEST_NET4[2]}.103 ${V4ADDRS[p7]} ${NETIFS[p5]} 2 \
- "Gateway resolves to wrong nexthop device - VRF"
- }
- ################################################################################
- # IPv6 tests
- #
- run_ip6()
- {
- local table="$1"
- local prefix="$2"
- local gw="$3"
- local dev="$4"
- local exp_rc="$5"
- local desc="$6"
- # dev arg may be empty
- [ -n "${dev}" ] && dev="dev ${dev}"
- run_cmd ip -6 ro add table "${table}" "${prefix}"/128 via "${gw}" "${dev}" onlink
- log_test $? ${exp_rc} "${desc}"
- }
- run_ip6_mpath()
- {
- local table="$1"
- local prefix="$2"
- local opts="$3"
- local nh1="$4"
- local nh2="$5"
- local exp_rc="$6"
- local desc="$7"
- run_cmd ip -6 ro add table "${table}" "${prefix}"/128 "${opts}" \
- nexthop via ${nh1} nexthop via ${nh2}
- log_test $? ${exp_rc} "${desc}"
- }
- valid_onlink_ipv6()
- {
- # - unicast connected, unicast recursive, v4-mapped
- #
- log_subsection "default VRF - main table"
- run_ip6 254 ${TEST_NET6[1]}::1 ${V6ADDRS[p1]/::*}::64 ${NETIFS[p1]} 0 "unicast connected"
- run_ip6 254 ${TEST_NET6[1]}::2 ${RECGW6[1]} ${NETIFS[p1]} 0 "unicast recursive"
- run_ip6 254 ${TEST_NET6[1]}::3 ::ffff:${TEST_NET4IN6[1]} ${NETIFS[p1]} 0 "v4-mapped"
- log_subsection "VRF ${VRF}"
- run_ip6 ${VRF_TABLE} ${TEST_NET6[2]}::1 ${V6ADDRS[p5]/::*}::64 ${NETIFS[p5]} 0 "unicast connected"
- run_ip6 ${VRF_TABLE} ${TEST_NET6[2]}::2 ${RECGW6[2]} ${NETIFS[p5]} 0 "unicast recursive"
- run_ip6 ${VRF_TABLE} ${TEST_NET6[2]}::3 ::ffff:${TEST_NET4IN6[2]} ${NETIFS[p5]} 0 "v4-mapped"
- log_subsection "VRF device, PBR table"
- run_ip6 ${PBR_TABLE} ${TEST_NET6[2]}::4 ${V6ADDRS[p5]/::*}::64 ${NETIFS[p5]} 0 "unicast connected"
- run_ip6 ${PBR_TABLE} ${TEST_NET6[2]}::5 ${RECGW6[2]} ${NETIFS[p5]} 0 "unicast recursive"
- run_ip6 ${PBR_TABLE} ${TEST_NET6[2]}::6 ::ffff:${TEST_NET4IN6[2]} ${NETIFS[p5]} 0 "v4-mapped"
- # multipath version
- #
- log_subsection "default VRF - main table - multipath"
- run_ip6_mpath 254 ${TEST_NET6[1]}::4 "onlink" \
- "${V6ADDRS[p1]/::*}::64 dev ${NETIFS[p1]}" \
- "${V6ADDRS[p3]/::*}::64 dev ${NETIFS[p3]}" \
- 0 "unicast connected - multipath onlink"
- run_ip6_mpath 254 ${TEST_NET6[1]}::5 "onlink" \
- "${RECGW6[1]} dev ${NETIFS[p1]}" \
- "${RECGW6[2]} dev ${NETIFS[p3]}" \
- 0 "unicast recursive - multipath onlink"
- run_ip6_mpath 254 ${TEST_NET6[1]}::6 "onlink" \
- "::ffff:${TEST_NET4IN6[1]} dev ${NETIFS[p1]}" \
- "::ffff:${TEST_NET4IN6[2]} dev ${NETIFS[p3]}" \
- 0 "v4-mapped - multipath onlink"
- run_ip6_mpath 254 ${TEST_NET6[1]}::7 "" \
- "${V6ADDRS[p1]/::*}::64 dev ${NETIFS[p1]} onlink" \
- "${V6ADDRS[p3]/::*}::64 dev ${NETIFS[p3]} onlink" \
- 0 "unicast connected - multipath onlink both nexthops"
- run_ip6_mpath 254 ${TEST_NET6[1]}::8 "" \
- "${V6ADDRS[p1]/::*}::64 dev ${NETIFS[p1]} onlink" \
- "${V6ADDRS[p3]/::*}::64 dev ${NETIFS[p3]}" \
- 0 "unicast connected - multipath onlink first only"
- run_ip6_mpath 254 ${TEST_NET6[1]}::9 "" \
- "${V6ADDRS[p1]/::*}::64 dev ${NETIFS[p1]}" \
- "${V6ADDRS[p3]/::*}::64 dev ${NETIFS[p3]} onlink" \
- 0 "unicast connected - multipath onlink second only"
- }
- invalid_onlink_ipv6()
- {
- local lladdr
- lladdr=$(get_linklocal ${NETIFS[p1]}) || return 1
- run_ip6 254 ${TEST_NET6[1]}::11 ${V6ADDRS[p1]} ${NETIFS[p1]} 2 \
- "Invalid gw - local unicast address"
- run_ip6 254 ${TEST_NET6[1]}::12 ${lladdr} ${NETIFS[p1]} 2 \
- "Invalid gw - local linklocal address"
- run_ip6 254 ${TEST_NET6[1]}::12 ${MCAST6} ${NETIFS[p1]} 2 \
- "Invalid gw - multicast address"
- lladdr=$(get_linklocal ${NETIFS[p5]}) || return 1
- run_ip6 ${VRF_TABLE} ${TEST_NET6[2]}::11 ${V6ADDRS[p5]} ${NETIFS[p5]} 2 \
- "Invalid gw - local unicast address, VRF"
- run_ip6 ${VRF_TABLE} ${TEST_NET6[2]}::12 ${lladdr} ${NETIFS[p5]} 2 \
- "Invalid gw - local linklocal address, VRF"
- run_ip6 ${VRF_TABLE} ${TEST_NET6[2]}::12 ${MCAST6} ${NETIFS[p5]} 2 \
- "Invalid gw - multicast address, VRF"
- run_ip6 254 ${TEST_NET6[1]}::101 ${V6ADDRS[p1]} "" 2 \
- "No nexthop device given"
- # default VRF validation is done against LOCAL table
- # run_ip6 254 ${TEST_NET6[1]}::102 ${V6ADDRS[p3]/::[0-9]/::64} ${NETIFS[p1]} 2 \
- # "Gateway resolves to wrong nexthop device"
- run_ip6 ${VRF_TABLE} ${TEST_NET6[2]}::103 ${V6ADDRS[p7]/::[0-9]/::64} ${NETIFS[p5]} 2 \
- "Gateway resolves to wrong nexthop device - VRF"
- }
- run_onlink_tests()
- {
- log_section "IPv4 onlink"
- log_subsection "Valid onlink commands"
- valid_onlink_ipv4
- log_subsection "Invalid onlink commands"
- invalid_onlink_ipv4
- log_section "IPv6 onlink"
- log_subsection "Valid onlink commands"
- valid_onlink_ipv6
- log_subsection "Invalid onlink commands"
- invalid_onlink_ipv6
- }
- ################################################################################
- # usage
- usage()
- {
- cat <<EOF
- usage: ${0##*/} OPTS
- -p Pause on fail
- -v verbose mode (show commands and output)
- EOF
- }
- ################################################################################
- # main
- nsuccess=0
- nfail=0
- while getopts :t:pPhv o
- do
- case $o in
- p) PAUSE_ON_FAIL=yes;;
- v) VERBOSE=$(($VERBOSE + 1));;
- h) usage; exit 0;;
- *) usage; exit 1;;
- esac
- done
- cleanup
- setup
- run_onlink_tests
- cleanup
- if [ "$TESTS" != "none" ]; then
- printf "\nTests passed: %3d\n" ${nsuccess}
- printf "Tests failed: %3d\n" ${nfail}
- fi
|