selftests: Add FIB onlink tests
authorDavid Ahern <dsahern@gmail.com>
Tue, 13 Feb 2018 16:44:06 +0000 (08:44 -0800)
committerDavid S. Miller <davem@davemloft.net>
Tue, 13 Feb 2018 19:47:33 +0000 (14:47 -0500)
Add test cases verifying FIB onlink commands work as expected in
various conditions - IPv4, IPv6, main table, and VRF.

Signed-off-by: David Ahern <dsahern@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
tools/testing/selftests/net/fib-onlink-tests.sh [new file with mode: 0755]

diff --git a/tools/testing/selftests/net/fib-onlink-tests.sh b/tools/testing/selftests/net/fib-onlink-tests.sh
new file mode 100755 (executable)
index 0000000..06b1d7c
--- /dev/null
@@ -0,0 +1,375 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+
+# IPv4 and IPv6 onlink tests
+
+PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no}
+
+# 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.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 "\n    TEST: %-50s  [ OK ]\n" "${msg}"
+       else
+               nfail=$((nfail+1))
+               printf "\n    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()
+{
+       echo
+       echo "COMMAND: $*"
+       eval $*
+}
+
+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
+       ip -6 ro add table ${VRF_TABLE} unreachable default
+
+       # 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}]}
+       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}]}
+       done
+
+       set +e
+
+       # let DAD complete - assume default of 1 probe
+       sleep 1
+}
+
+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}"
+}
+
+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[2]} ${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[2]} ${NETIFS[p5]} 0 "unicast connected"
+       run_ip ${PBR_TABLE} ${TEST_NET4[2]}.4 ${RECGW4[2]} ${NETIFS[p5]} 0 "unicast recursive"
+}
+
+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}"
+}
+
+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"
+}
+
+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
+       invalid_onlink_ipv6
+}
+
+################################################################################
+# main
+
+nsuccess=0
+nfail=0
+
+cleanup
+setup
+run_onlink_tests
+cleanup
+
+if [ "$TESTS" != "none" ]; then
+       printf "\nTests passed: %3d\n" ${nsuccess}
+       printf "Tests failed: %3d\n"   ${nfail}
+fi