284 lines · bash
1#!/bin/bash2# SPDX-License-Identifier: GPL-2.03#4# 2 namespaces: one host and one router. Use arping from the host to send a5# garp to the router. Router accepts or ignores based on its arp_accept6# or accept_untracked_na configuration.7 8source lib.sh9 10TESTS="arp ndisc"11 12ROUTER_INTF="veth-router"13ROUTER_ADDR="10.0.10.1"14ROUTER_ADDR_V6="2001:db8:abcd:0012::1"15 16HOST_INTF="veth-host"17HOST_ADDR="10.0.10.2"18HOST_ADDR_V6="2001:db8:abcd:0012::2"19 20SUBNET_WIDTH=2421PREFIX_WIDTH_V6=6422 23cleanup() {24 cleanup_ns ${HOST_NS} ${ROUTER_NS}25}26 27cleanup_v6() {28 cleanup_ns ${HOST_NS_V6} ${ROUTER_NS_V6}29}30 31setup() {32 set -e33 local arp_accept=$134 35 # Set up two namespaces36 setup_ns HOST_NS ROUTER_NS37 38 # Set up interfaces veth0 and veth1, which are pairs in separate39 # namespaces. veth0 is veth-router, veth1 is veth-host.40 # first, set up the inteface's link to the namespace41 # then, set the interface "up"42 ip netns exec ${ROUTER_NS} ip link add name ${ROUTER_INTF} \43 type veth peer name ${HOST_INTF}44 45 ip netns exec ${ROUTER_NS} ip link set dev ${ROUTER_INTF} up46 ip netns exec ${ROUTER_NS} ip link set dev ${HOST_INTF} netns ${HOST_NS}47 48 ip netns exec ${HOST_NS} ip link set dev ${HOST_INTF} up49 ip netns exec ${ROUTER_NS} ip addr add ${ROUTER_ADDR}/${SUBNET_WIDTH} \50 dev ${ROUTER_INTF}51 52 ip netns exec ${HOST_NS} ip addr add ${HOST_ADDR}/${SUBNET_WIDTH} \53 dev ${HOST_INTF}54 ip netns exec ${HOST_NS} ip route add default via ${HOST_ADDR} \55 dev ${HOST_INTF}56 ip netns exec ${ROUTER_NS} ip route add default via ${ROUTER_ADDR} \57 dev ${ROUTER_INTF}58 59 ROUTER_CONF=net.ipv4.conf.${ROUTER_INTF}60 ip netns exec ${ROUTER_NS} sysctl -w \61 ${ROUTER_CONF}.arp_accept=${arp_accept} >/dev/null 2>&162 set +e63}64 65setup_v6() {66 set -e67 local accept_untracked_na=$168 69 # Set up two namespaces70 setup_ns HOST_NS_V6 ROUTER_NS_V671 72 # Set up interfaces veth0 and veth1, which are pairs in separate73 # namespaces. veth0 is veth-router, veth1 is veth-host.74 # first, set up the inteface's link to the namespace75 # then, set the interface "up"76 ip -n ${ROUTER_NS_V6} link add name ${ROUTER_INTF} \77 type veth peer name ${HOST_INTF} netns ${HOST_NS_V6}78 79 # Add tc rule to filter out host na message80 tc -n ${ROUTER_NS_V6} qdisc add dev ${ROUTER_INTF} clsact81 tc -n ${ROUTER_NS_V6} filter add dev ${ROUTER_INTF} \82 ingress protocol ipv6 pref 1 handle 101 \83 flower src_ip ${HOST_ADDR_V6} ip_proto icmpv6 type 136 skip_hw action pass84 85 HOST_CONF=net.ipv6.conf.${HOST_INTF}86 ip netns exec ${HOST_NS_V6} sysctl -qw ${HOST_CONF}.ndisc_notify=187 ip netns exec ${HOST_NS_V6} sysctl -qw ${HOST_CONF}.disable_ipv6=088 ROUTER_CONF=net.ipv6.conf.${ROUTER_INTF}89 ip netns exec ${ROUTER_NS_V6} sysctl -w \90 ${ROUTER_CONF}.forwarding=1 >/dev/null 2>&191 ip netns exec ${ROUTER_NS_V6} sysctl -w \92 ${ROUTER_CONF}.drop_unsolicited_na=0 >/dev/null 2>&193 ip netns exec ${ROUTER_NS_V6} sysctl -w \94 ${ROUTER_CONF}.accept_untracked_na=${accept_untracked_na} \95 >/dev/null 2>&196 97 ip -n ${ROUTER_NS_V6} link set dev ${ROUTER_INTF} up98 ip -n ${HOST_NS_V6} link set dev ${HOST_INTF} up99 ip -n ${ROUTER_NS_V6} addr add ${ROUTER_ADDR_V6}/${PREFIX_WIDTH_V6} \100 dev ${ROUTER_INTF} nodad101 ip -n ${HOST_NS_V6} addr add ${HOST_ADDR_V6}/${PREFIX_WIDTH_V6} \102 dev ${HOST_INTF}103 set +e104}105 106verify_arp() {107 local arp_accept=$1108 local same_subnet=$2109 110 neigh_show_output=$(ip netns exec ${ROUTER_NS} ip neigh get \111 ${HOST_ADDR} dev ${ROUTER_INTF} 2>/dev/null)112 113 if [ ${arp_accept} -eq 1 ]; then114 # Neighbor entries expected115 [[ ${neigh_show_output} ]]116 elif [ ${arp_accept} -eq 2 ]; then117 if [ ${same_subnet} -eq 1 ]; then118 # Neighbor entries expected119 [[ ${neigh_show_output} ]]120 else121 [[ -z "${neigh_show_output}" ]]122 fi123 else124 [[ -z "${neigh_show_output}" ]]125 fi126 }127 128arp_test_gratuitous() {129 set -e130 local arp_accept=$1131 local same_subnet=$2132 133 if [ ${arp_accept} -eq 2 ]; then134 test_msg=("test_arp: "135 "accept_arp=$1 "136 "same_subnet=$2")137 if [ ${same_subnet} -eq 0 ]; then138 HOST_ADDR=10.0.11.3139 else140 HOST_ADDR=10.0.10.3141 fi142 else143 test_msg=("test_arp: "144 "accept_arp=$1")145 fi146 # Supply arp_accept option to set up which sets it in sysctl147 setup ${arp_accept}148 ip netns exec ${HOST_NS} arping -A -I ${HOST_INTF} -U ${HOST_ADDR} -c1 2>&1 >/dev/null149 150 if verify_arp $1 $2; then151 printf " TEST: %-60s [ OK ]\n" "${test_msg[*]}"152 else153 printf " TEST: %-60s [FAIL]\n" "${test_msg[*]}"154 fi155 cleanup156 set +e157}158 159arp_test_gratuitous_combinations() {160 arp_test_gratuitous 0161 arp_test_gratuitous 1162 arp_test_gratuitous 2 0 # Second entry indicates subnet or not163 arp_test_gratuitous 2 1164}165 166verify_ndisc() {167 local accept_untracked_na=$1168 local same_subnet=$2169 170 neigh_show_output=$(ip -6 -netns ${ROUTER_NS_V6} neigh show \171 to ${HOST_ADDR_V6} dev ${ROUTER_INTF} nud stale)172 173 if [ ${accept_untracked_na} -eq 1 ]; then174 # Neighbour entry expected to be present175 [[ ${neigh_show_output} ]]176 elif [ ${accept_untracked_na} -eq 2 ]; then177 if [ ${same_subnet} -eq 1 ]; then178 [[ ${neigh_show_output} ]]179 else180 [[ -z "${neigh_show_output}" ]]181 fi182 else183 # Neighbour entry expected to be absent for all other cases184 [[ -z "${neigh_show_output}" ]]185 fi186}187 188ndisc_test_untracked_advertisements() {189 set -e190 test_msg=("test_ndisc: "191 "accept_untracked_na=$1")192 193 local accept_untracked_na=$1194 local same_subnet=$2195 if [ ${accept_untracked_na} -eq 2 ]; then196 test_msg=("test_ndisc: "197 "accept_untracked_na=$1 "198 "same_subnet=$2")199 if [ ${same_subnet} -eq 0 ]; then200 # Not same subnet201 HOST_ADDR_V6=2000:db8:abcd:0013::4202 else203 HOST_ADDR_V6=2001:db8:abcd:0012::3204 fi205 fi206 setup_v6 $1207 slowwait_for_counter 15 1 \208 tc_rule_handle_stats_get "dev ${ROUTER_INTF} ingress" 101 ".packets" "-n ${ROUTER_NS_V6}"209 210 if verify_ndisc $1 $2; then211 printf " TEST: %-60s [ OK ]\n" "${test_msg[*]}"212 else213 printf " TEST: %-60s [FAIL]\n" "${test_msg[*]}"214 fi215 216 cleanup_v6217 set +e218}219 220ndisc_test_untracked_combinations() {221 ndisc_test_untracked_advertisements 0222 ndisc_test_untracked_advertisements 1223 ndisc_test_untracked_advertisements 2 0224 ndisc_test_untracked_advertisements 2 1225}226 227################################################################################228# usage229 230usage()231{232 cat <<EOF233usage: ${0##*/} OPTS234 235 -t <test> Test(s) to run (default: all)236 (options: $TESTS)237EOF238}239 240################################################################################241# main242 243while getopts ":t:h" opt; do244 case $opt in245 t) TESTS=$OPTARG;;246 h) usage; exit 0;;247 *) usage; exit 1;;248 esac249done250 251if [ "$(id -u)" -ne 0 ];then252 echo "SKIP: Need root privileges"253 exit $ksft_skip;254fi255 256if [ ! -x "$(command -v ip)" ]; then257 echo "SKIP: Could not run test without ip tool"258 exit $ksft_skip259fi260 261if [ ! -x "$(command -v tcpdump)" ]; then262 echo "SKIP: Could not run test without tcpdump tool"263 exit $ksft_skip264fi265 266if [ ! -x "$(command -v arping)" ]; then267 echo "SKIP: Could not run test without arping tool"268 exit $ksft_skip269fi270 271# start clean272cleanup &> /dev/null273cleanup_v6 &> /dev/null274 275for t in $TESTS276do277 case $t in278 arp_test_gratuitous_combinations|arp) arp_test_gratuitous_combinations;;279 ndisc_test_untracked_combinations|ndisc) \280 ndisc_test_untracked_combinations;;281 help) echo "Test names: $TESTS"; exit 0;;282esac283done284