selftests/net: change shebang to bash to support "source"
[platform/kernel/linux-starfive.git] / tools / testing / selftests / net / ndisc_unsolicited_na_test.sh
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
13 ret=0
14 # Kselftest framework requirement - SKIP code is 4.
15 ksft_skip=4
16
17 PAUSE_ON_FAIL=no
18 PAUSE=no
19
20 HOST_NS="ns-host"
21 ROUTER_NS="ns-router"
22
23 HOST_INTF="veth-host"
24 ROUTER_INTF="veth-router"
25
26 ROUTER_ADDR="2000:20::1"
27 HOST_ADDR="2000:20::2"
28 SUBNET_WIDTH=64
29 ROUTER_ADDR_WITH_MASK="${ROUTER_ADDR}/${SUBNET_WIDTH}"
30 HOST_ADDR_WITH_MASK="${HOST_ADDR}/${SUBNET_WIDTH}"
31
32 IP_HOST="ip -6 -netns ${HOST_NS}"
33 IP_HOST_EXEC="ip netns exec ${HOST_NS}"
34 IP_ROUTER="ip -6 -netns ${ROUTER_NS}"
35 IP_ROUTER_EXEC="ip netns exec ${ROUTER_NS}"
36
37 tcpdump_stdout=
38 tcpdump_stderr=
39
40 log_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
69 setup()
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
109 start_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
120 cleanup_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
130 cleanup()
131 {
132         cleanup_tcpdump
133         ip netns del ${HOST_NS}
134         ip netns del ${ROUTER_NS}
135 }
136
137 link_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
144 verify_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
162 test_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
177 test_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
187 test_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
206 usage()
207 {
208         cat <<EOF
209 usage: ${0##*/} OPTS
210         -p          Pause on fail
211         -P          Pause after each test before cleanup
212 EOF
213 }
214
215 ###############################################################################
216 # main
217
218 while getopts :pPh o
219 do
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
226 done
227
228 # make sure we don't pause twice
229 [ "${PAUSE}" = "yes" ] && PAUSE_ON_FAIL=no
230
231 if [ "$(id -u)" -ne 0 ];then
232         echo "SKIP: Need root privileges"
233         exit $ksft_skip;
234 fi
235
236 if [ ! -x "$(command -v ip)" ]; then
237         echo "SKIP: Could not run test without ip tool"
238         exit $ksft_skip
239 fi
240
241 if [ ! -x "$(command -v tcpdump)" ]; then
242         echo "SKIP: Could not run test without tcpdump tool"
243         exit $ksft_skip
244 fi
245
246 # start clean
247 cleanup &> /dev/null
248
249 test_unsolicited_na_combinations
250
251 printf "\nTests passed: %3d\n" ${nsuccess}
252 printf "Tests failed: %3d\n"   ${nfail}
253
254 exit $ret