1#!/bin/bash 2# SPDX-License-Identifier: GPL-2.0 3 4# This test is for the accept_untracked_na feature to 5# enable RFC9131 behaviour. The following is the test-matrix. 6# drop accept fwding behaviour 7# ---- ------ ------ ---------------------------------------------- 8# 1 X X Don't update NC 9# 0 0 X Don't update NC 10# 0 1 0 Don't update NC 11# 0 1 1 Add a STALE NC entry 12 13ret=0 14# Kselftest framework requirement - SKIP code is 4. 15ksft_skip=4 16 17PAUSE_ON_FAIL=no 18PAUSE=no 19 20HOST_NS="ns-host" 21ROUTER_NS="ns-router" 22 23HOST_INTF="veth-host" 24ROUTER_INTF="veth-router" 25 26ROUTER_ADDR="2000:20::1" 27HOST_ADDR="2000:20::2" 28SUBNET_WIDTH=64 29ROUTER_ADDR_WITH_MASK="${ROUTER_ADDR}/${SUBNET_WIDTH}" 30HOST_ADDR_WITH_MASK="${HOST_ADDR}/${SUBNET_WIDTH}" 31 32IP_HOST="ip -6 -netns ${HOST_NS}" 33IP_HOST_EXEC="ip netns exec ${HOST_NS}" 34IP_ROUTER="ip -6 -netns ${ROUTER_NS}" 35IP_ROUTER_EXEC="ip netns exec ${ROUTER_NS}" 36 37tcpdump_stdout= 38tcpdump_stderr= 39 40log_test() 41{ 42 local rc=$1 43 local expected=$2 44 local msg="$3" 45 46 if [ ${rc} -eq ${expected} ]; then 47 printf " TEST: %-60s [ OK ]\n" "${msg}" 48 nsuccess=$((nsuccess+1)) 49 else 50 ret=1 51 nfail=$((nfail+1)) 52 printf " TEST: %-60s [FAIL]\n" "${msg}" 53 if [ "${PAUSE_ON_FAIL}" = "yes" ]; then 54 echo 55 echo "hit enter to continue, 'q' to quit" 56 read a 57 [ "$a" = "q" ] && exit 1 58 fi 59 fi 60 61 if [ "${PAUSE}" = "yes" ]; then 62 echo 63 echo "hit enter to continue, 'q' to quit" 64 read a 65 [ "$a" = "q" ] && exit 1 66 fi 67} 68 69setup() 70{ 71 set -e 72 73 local drop_unsolicited_na=$1 74 local accept_untracked_na=$2 75 local forwarding=$3 76 77 # Setup two namespaces and a veth tunnel across them. 78 # On end of the tunnel is a router and the other end is a host. 79 ip netns add ${HOST_NS} 80 ip netns add ${ROUTER_NS} 81 ${IP_ROUTER} link add ${ROUTER_INTF} type veth \ 82 peer name ${HOST_INTF} netns ${HOST_NS} 83 84 # Enable IPv6 on both router and host, and configure static addresses. 85 # The router here is the DUT 86 # Setup router configuration as specified by the arguments. 87 # forwarding=0 case is to check that a non-router 88 # doesn't add neighbour entries. 89 ROUTER_CONF=net.ipv6.conf.${ROUTER_INTF} 90 ${IP_ROUTER_EXEC} sysctl -qw \ 91 ${ROUTER_CONF}.forwarding=${forwarding} 92 ${IP_ROUTER_EXEC} sysctl -qw \ 93 ${ROUTER_CONF}.drop_unsolicited_na=${drop_unsolicited_na} 94 ${IP_ROUTER_EXEC} sysctl -qw \ 95 ${ROUTER_CONF}.accept_untracked_na=${accept_untracked_na} 96 ${IP_ROUTER_EXEC} sysctl -qw ${ROUTER_CONF}.disable_ipv6=0 97 ${IP_ROUTER} addr add ${ROUTER_ADDR_WITH_MASK} dev ${ROUTER_INTF} 98 99 # Turn on ndisc_notify on host interface so that 100 # the host sends unsolicited NAs. 101 HOST_CONF=net.ipv6.conf.${HOST_INTF} 102 ${IP_HOST_EXEC} sysctl -qw ${HOST_CONF}.ndisc_notify=1 103 ${IP_HOST_EXEC} sysctl -qw ${HOST_CONF}.disable_ipv6=0 104 ${IP_HOST} addr add ${HOST_ADDR_WITH_MASK} dev ${HOST_INTF} 105 106 set +e 107} 108 109start_tcpdump() { 110 set -e 111 tcpdump_stdout=`mktemp` 112 tcpdump_stderr=`mktemp` 113 ${IP_ROUTER_EXEC} timeout 15s \ 114 tcpdump --immediate-mode -tpni ${ROUTER_INTF} -c 1 \ 115 "icmp6 && icmp6[0] == 136 && src ${HOST_ADDR}" \ 116 > ${tcpdump_stdout} 2> /dev/null 117 set +e 118} 119 120cleanup_tcpdump() 121{ 122 set -e 123 [[ ! -z ${tcpdump_stdout} ]] && rm -f ${tcpdump_stdout} 124 [[ ! -z ${tcpdump_stderr} ]] && rm -f ${tcpdump_stderr} 125 tcpdump_stdout= 126 tcpdump_stderr= 127 set +e 128} 129 130cleanup() 131{ 132 cleanup_tcpdump 133 ip netns del ${HOST_NS} 134 ip netns del ${ROUTER_NS} 135} 136 137link_up() { 138 set -e 139 ${IP_ROUTER} link set dev ${ROUTER_INTF} up 140 ${IP_HOST} link set dev ${HOST_INTF} up 141 set +e 142} 143 144verify_ndisc() { 145 local drop_unsolicited_na=$1 146 local accept_untracked_na=$2 147 local forwarding=$3 148 149 neigh_show_output=$(${IP_ROUTER} neigh show \ 150 to ${HOST_ADDR} dev ${ROUTER_INTF} nud stale) 151 if [ ${drop_unsolicited_na} -eq 0 ] && \ 152 [ ${accept_untracked_na} -eq 1 ] && \ 153 [ ${forwarding} -eq 1 ]; then 154 # Neighbour entry expected to be present for 011 case 155 [[ ${neigh_show_output} ]] 156 else 157 # Neighbour entry expected to be absent for all other cases 158 [[ -z ${neigh_show_output} ]] 159 fi 160} 161 162test_unsolicited_na_common() 163{ 164 # Setup the test bed, but keep links down 165 setup $1 $2 $3 166 167 # Bring the link up, wait for the NA, 168 # and add a delay to ensure neighbour processing is done. 169 link_up 170 start_tcpdump 171 172 # Verify the neighbour table 173 verify_ndisc $1 $2 $3 174 175} 176 177test_unsolicited_na_combination() { 178 test_unsolicited_na_common $1 $2 $3 179 test_msg=("test_unsolicited_na: " 180 "drop_unsolicited_na=$1 " 181 "accept_untracked_na=$2 " 182 "forwarding=$3") 183 log_test $? 0 "${test_msg[*]}" 184 cleanup 185} 186 187test_unsolicited_na_combinations() { 188 # Args: drop_unsolicited_na accept_untracked_na forwarding 189 190 # Expect entry 191 test_unsolicited_na_combination 0 1 1 192 193 # Expect no entry 194 test_unsolicited_na_combination 0 0 0 195 test_unsolicited_na_combination 0 0 1 196 test_unsolicited_na_combination 0 1 0 197 test_unsolicited_na_combination 1 0 0 198 test_unsolicited_na_combination 1 0 1 199 test_unsolicited_na_combination 1 1 0 200 test_unsolicited_na_combination 1 1 1 201} 202 203############################################################################### 204# usage 205 206usage() 207{ 208 cat <<EOF 209usage: ${0##*/} OPTS 210 -p Pause on fail 211 -P Pause after each test before cleanup 212EOF 213} 214 215############################################################################### 216# main 217 218while getopts :pPh o 219do 220 case $o in 221 p) PAUSE_ON_FAIL=yes;; 222 P) PAUSE=yes;; 223 h) usage; exit 0;; 224 *) usage; exit 1;; 225 esac 226done 227 228# make sure we don't pause twice 229[ "${PAUSE}" = "yes" ] && PAUSE_ON_FAIL=no 230 231if [ "$(id -u)" -ne 0 ];then 232 echo "SKIP: Need root privileges" 233 exit $ksft_skip; 234fi 235 236if [ ! -x "$(command -v ip)" ]; then 237 echo "SKIP: Could not run test without ip tool" 238 exit $ksft_skip 239fi 240 241if [ ! -x "$(command -v tcpdump)" ]; then 242 echo "SKIP: Could not run test without tcpdump tool" 243 exit $ksft_skip 244fi 245 246# start clean 247cleanup &> /dev/null 248 249test_unsolicited_na_combinations 250 251printf "\nTests passed: %3d\n" ${nsuccess} 252printf "Tests failed: %3d\n" ${nfail} 253 254exit $ret 255