1#!/bin/bash 2# SPDX-License-Identifier: GPL-2.0 3# 4# 2 namespaces: one host and one router. Use arping from the host to send a 5# garp to the router. Router accepts or ignores based on its arp_accept 6# or accept_untracked_na configuration. 7 8source lib.sh 9 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=24 21PREFIX_WIDTH_V6=64 22 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 -e 33 local arp_accept=$1 34 35 # Set up two namespaces 36 setup_ns HOST_NS ROUTER_NS 37 38 # Set up interfaces veth0 and veth1, which are pairs in separate 39 # namespaces. veth0 is veth-router, veth1 is veth-host. 40 # first, set up the inteface's link to the namespace 41 # 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} up 46 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} up 49 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>&1 62 set +e 63} 64 65setup_v6() { 66 set -e 67 local accept_untracked_na=$1 68 69 # Set up two namespaces 70 setup_ns HOST_NS_V6 ROUTER_NS_V6 71 72 # Set up interfaces veth0 and veth1, which are pairs in separate 73 # namespaces. veth0 is veth-router, veth1 is veth-host. 74 # first, set up the inteface's link to the namespace 75 # 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 message 80 tc -n ${ROUTER_NS_V6} qdisc add dev ${ROUTER_INTF} clsact 81 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 pass 84 85 HOST_CONF=net.ipv6.conf.${HOST_INTF} 86 ip netns exec ${HOST_NS_V6} sysctl -qw ${HOST_CONF}.ndisc_notify=1 87 ip netns exec ${HOST_NS_V6} sysctl -qw ${HOST_CONF}.disable_ipv6=0 88 ROUTER_CONF=net.ipv6.conf.${ROUTER_INTF} 89 ip netns exec ${ROUTER_NS_V6} sysctl -w \ 90 ${ROUTER_CONF}.forwarding=1 >/dev/null 2>&1 91 ip netns exec ${ROUTER_NS_V6} sysctl -w \ 92 ${ROUTER_CONF}.drop_unsolicited_na=0 >/dev/null 2>&1 93 ip netns exec ${ROUTER_NS_V6} sysctl -w \ 94 ${ROUTER_CONF}.accept_untracked_na=${accept_untracked_na} \ 95 >/dev/null 2>&1 96 97 ip -n ${ROUTER_NS_V6} link set dev ${ROUTER_INTF} up 98 ip -n ${HOST_NS_V6} link set dev ${HOST_INTF} up 99 ip -n ${ROUTER_NS_V6} addr add ${ROUTER_ADDR_V6}/${PREFIX_WIDTH_V6} \ 100 dev ${ROUTER_INTF} nodad 101 ip -n ${HOST_NS_V6} addr add ${HOST_ADDR_V6}/${PREFIX_WIDTH_V6} \ 102 dev ${HOST_INTF} 103 set +e 104} 105 106verify_arp() { 107 local arp_accept=$1 108 local same_subnet=$2 109 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 ]; then 114 # Neighbor entries expected 115 [[ ${neigh_show_output} ]] 116 elif [ ${arp_accept} -eq 2 ]; then 117 if [ ${same_subnet} -eq 1 ]; then 118 # Neighbor entries expected 119 [[ ${neigh_show_output} ]] 120 else 121 [[ -z "${neigh_show_output}" ]] 122 fi 123 else 124 [[ -z "${neigh_show_output}" ]] 125 fi 126 } 127 128arp_test_gratuitous() { 129 set -e 130 local arp_accept=$1 131 local same_subnet=$2 132 133 if [ ${arp_accept} -eq 2 ]; then 134 test_msg=("test_arp: " 135 "accept_arp=$1 " 136 "same_subnet=$2") 137 if [ ${same_subnet} -eq 0 ]; then 138 HOST_ADDR=10.0.11.3 139 else 140 HOST_ADDR=10.0.10.3 141 fi 142 else 143 test_msg=("test_arp: " 144 "accept_arp=$1") 145 fi 146 # Supply arp_accept option to set up which sets it in sysctl 147 setup ${arp_accept} 148 ip netns exec ${HOST_NS} arping -A -I ${HOST_INTF} -U ${HOST_ADDR} -c1 2>&1 >/dev/null 149 150 if verify_arp $1 $2; then 151 printf " TEST: %-60s [ OK ]\n" "${test_msg[*]}" 152 else 153 printf " TEST: %-60s [FAIL]\n" "${test_msg[*]}" 154 fi 155 cleanup 156 set +e 157} 158 159arp_test_gratuitous_combinations() { 160 arp_test_gratuitous 0 161 arp_test_gratuitous 1 162 arp_test_gratuitous 2 0 # Second entry indicates subnet or not 163 arp_test_gratuitous 2 1 164} 165 166verify_ndisc() { 167 local accept_untracked_na=$1 168 local same_subnet=$2 169 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 ]; then 174 # Neighbour entry expected to be present 175 [[ ${neigh_show_output} ]] 176 elif [ ${accept_untracked_na} -eq 2 ]; then 177 if [ ${same_subnet} -eq 1 ]; then 178 [[ ${neigh_show_output} ]] 179 else 180 [[ -z "${neigh_show_output}" ]] 181 fi 182 else 183 # Neighbour entry expected to be absent for all other cases 184 [[ -z "${neigh_show_output}" ]] 185 fi 186} 187 188ndisc_test_untracked_advertisements() { 189 set -e 190 test_msg=("test_ndisc: " 191 "accept_untracked_na=$1") 192 193 local accept_untracked_na=$1 194 local same_subnet=$2 195 if [ ${accept_untracked_na} -eq 2 ]; then 196 test_msg=("test_ndisc: " 197 "accept_untracked_na=$1 " 198 "same_subnet=$2") 199 if [ ${same_subnet} -eq 0 ]; then 200 # Not same subnet 201 HOST_ADDR_V6=2000:db8:abcd:0013::4 202 else 203 HOST_ADDR_V6=2001:db8:abcd:0012::3 204 fi 205 fi 206 setup_v6 $1 207 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; then 211 printf " TEST: %-60s [ OK ]\n" "${test_msg[*]}" 212 else 213 printf " TEST: %-60s [FAIL]\n" "${test_msg[*]}" 214 fi 215 216 cleanup_v6 217 set +e 218} 219 220ndisc_test_untracked_combinations() { 221 ndisc_test_untracked_advertisements 0 222 ndisc_test_untracked_advertisements 1 223 ndisc_test_untracked_advertisements 2 0 224 ndisc_test_untracked_advertisements 2 1 225} 226 227################################################################################ 228# usage 229 230usage() 231{ 232 cat <<EOF 233usage: ${0##*/} OPTS 234 235 -t <test> Test(s) to run (default: all) 236 (options: $TESTS) 237EOF 238} 239 240################################################################################ 241# main 242 243while getopts ":t:h" opt; do 244 case $opt in 245 t) TESTS=$OPTARG;; 246 h) usage; exit 0;; 247 *) usage; exit 1;; 248 esac 249done 250 251if [ "$(id -u)" -ne 0 ];then 252 echo "SKIP: Need root privileges" 253 exit $ksft_skip; 254fi 255 256if [ ! -x "$(command -v ip)" ]; then 257 echo "SKIP: Could not run test without ip tool" 258 exit $ksft_skip 259fi 260 261if [ ! -x "$(command -v tcpdump)" ]; then 262 echo "SKIP: Could not run test without tcpdump tool" 263 exit $ksft_skip 264fi 265 266if [ ! -x "$(command -v arping)" ]; then 267 echo "SKIP: Could not run test without arping tool" 268 exit $ksft_skip 269fi 270 271# start clean 272cleanup &> /dev/null 273cleanup_v6 &> /dev/null 274 275for t in $TESTS 276do 277 case $t in 278 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;; 282esac 283done 284