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