1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3#
4# Tests sysctl options {arp,ndisc}_evict_nocarrier={0,1}
5#
6# Create a veth pair and set IPs/routes on both. Then ping to establish
7# an entry in the ARP/ND table. Depending on the test set sysctl option to
8# 1 or 0. Set remote veth down which will cause local veth to go into a no
9# carrier state. Depending on the test check the ARP/ND table:
10#
11# {arp,ndisc}_evict_nocarrier=1 should contain no ARP/ND after no carrier
12# {arp,ndisc}_evict_nocarrer=0 should still contain the single ARP/ND entry
13#
14
15readonly PEER_NS="ns-peer-$(mktemp -u XXXXXX)"
16readonly V4_ADDR0=10.0.10.1
17readonly V4_ADDR1=10.0.10.2
18readonly V6_ADDR0=2001:db8:91::1
19readonly V6_ADDR1=2001:db8:91::2
20nsid=100
21ret=0
22
23cleanup_v6()
24{
25    ip netns del me
26    ip netns del peer
27
28    sysctl -w net.ipv6.conf.veth1.ndisc_evict_nocarrier=1 >/dev/null 2>&1
29    sysctl -w net.ipv6.conf.all.ndisc_evict_nocarrier=1 >/dev/null 2>&1
30}
31
32create_ns()
33{
34    local n=${1}
35
36    ip netns del ${n} 2>/dev/null
37
38    ip netns add ${n}
39    ip netns set ${n} $((nsid++))
40    ip -netns ${n} link set lo up
41}
42
43
44setup_v6() {
45    create_ns me
46    create_ns peer
47
48    IP="ip -netns me"
49
50    $IP li add veth1 type veth peer name veth2
51    $IP li set veth1 up
52    $IP -6 addr add $V6_ADDR0/64 dev veth1 nodad
53    $IP li set veth2 netns peer up
54    ip -netns peer -6 addr add $V6_ADDR1/64 dev veth2 nodad
55
56    ip netns exec me sysctl -w $1 >/dev/null 2>&1
57
58    # Establish an ND cache entry
59    ip netns exec me ping -6 -c1 -Iveth1 $V6_ADDR1 >/dev/null 2>&1
60    # Should have the veth1 entry in ND table
61    ip netns exec me ip -6 neigh get $V6_ADDR1 dev veth1 >/dev/null 2>&1
62    if [ $? -ne 0 ]; then
63        cleanup_v6
64        echo "failed"
65        exit 1
66    fi
67
68    # Set veth2 down, which will put veth1 in NOCARRIER state
69    ip netns exec peer ip link set veth2 down
70}
71
72setup_v4() {
73    ip netns add "${PEER_NS}"
74    ip link add name veth0 type veth peer name veth1
75    ip link set dev veth0 up
76    ip link set dev veth1 netns "${PEER_NS}"
77    ip netns exec "${PEER_NS}" ip link set dev veth1 up
78    ip addr add $V4_ADDR0/24 dev veth0
79    ip netns exec "${PEER_NS}" ip addr add $V4_ADDR1/24 dev veth1
80    ip netns exec ${PEER_NS} ip route add default via $V4_ADDR1 dev veth1
81    ip route add default via $V4_ADDR0 dev veth0
82
83    sysctl -w "$1" >/dev/null 2>&1
84
85    # Establish an ARP cache entry
86    ping -c1 -I veth0 $V4_ADDR1 -q >/dev/null 2>&1
87    # Should have the veth1 entry in ARP table
88    ip neigh get $V4_ADDR1 dev veth0 >/dev/null 2>&1
89    if [ $? -ne 0 ]; then
90        cleanup_v4
91        echo "failed"
92        exit 1
93    fi
94
95    # Set veth1 down, which will put veth0 in NOCARRIER state
96    ip netns exec "${PEER_NS}" ip link set veth1 down
97}
98
99cleanup_v4() {
100    ip neigh flush dev veth0
101    ip link del veth0
102    local -r ns="$(ip netns list|grep $PEER_NS)"
103    [ -n "$ns" ] && ip netns del $ns 2>/dev/null
104
105    sysctl -w net.ipv4.conf.veth0.arp_evict_nocarrier=1 >/dev/null 2>&1
106    sysctl -w net.ipv4.conf.all.arp_evict_nocarrier=1 >/dev/null 2>&1
107}
108
109# Run test when arp_evict_nocarrier = 1 (default).
110run_arp_evict_nocarrier_enabled() {
111    echo "run arp_evict_nocarrier=1 test"
112    setup_v4 "net.ipv4.conf.veth0.arp_evict_nocarrier=1"
113
114    # ARP table should be empty
115    ip neigh get $V4_ADDR1 dev veth0 >/dev/null 2>&1
116
117    if [ $? -eq 0 ];then
118        echo "failed"
119        ret=1
120    else
121        echo "ok"
122    fi
123
124    cleanup_v4
125}
126
127# Run test when arp_evict_nocarrier = 0
128run_arp_evict_nocarrier_disabled() {
129    echo "run arp_evict_nocarrier=0 test"
130    setup_v4 "net.ipv4.conf.veth0.arp_evict_nocarrier=0"
131
132    # ARP table should still contain the entry
133    ip neigh get $V4_ADDR1 dev veth0 >/dev/null 2>&1
134
135    if [ $? -eq 0 ];then
136        echo "ok"
137    else
138        echo "failed"
139        ret=1
140    fi
141
142    cleanup_v4
143}
144
145run_arp_evict_nocarrier_disabled_all() {
146    echo "run all.arp_evict_nocarrier=0 test"
147    setup_v4 "net.ipv4.conf.all.arp_evict_nocarrier=0"
148
149    # ARP table should still contain the entry
150    ip neigh get $V4_ADDR1 dev veth0 >/dev/null 2>&1
151
152    if [ $? -eq 0 ];then
153        echo "ok"
154    else
155        echo "failed"
156    fi
157
158    cleanup_v4
159}
160
161run_ndisc_evict_nocarrier_enabled() {
162    echo "run ndisc_evict_nocarrier=1 test"
163
164    setup_v6 "net.ipv6.conf.veth1.ndisc_evict_nocarrier=1"
165
166    ip netns exec me ip -6 neigh get $V6_ADDR1 dev veth1 >/dev/null 2>&1
167
168    if [ $? -eq 0 ];then
169        echo "failed"
170        ret=1
171    else
172        echo "ok"
173    fi
174
175    cleanup_v6
176}
177
178run_ndisc_evict_nocarrier_disabled() {
179    echo "run ndisc_evict_nocarrier=0 test"
180
181    setup_v6 "net.ipv6.conf.veth1.ndisc_evict_nocarrier=0"
182
183    ip netns exec me ip -6 neigh get $V6_ADDR1 dev veth1 >/dev/null 2>&1
184
185    if [ $? -eq 0 ];then
186        echo "ok"
187    else
188        echo "failed"
189        ret=1
190    fi
191
192    cleanup_v6
193}
194
195run_ndisc_evict_nocarrier_disabled_all() {
196    echo "run all.ndisc_evict_nocarrier=0 test"
197
198    setup_v6 "net.ipv6.conf.all.ndisc_evict_nocarrier=0"
199
200    ip netns exec me ip -6 neigh get $V6_ADDR1 dev veth1 >/dev/null 2>&1
201
202    if [ $? -eq 0 ];then
203        echo "ok"
204    else
205        echo "failed"
206        ret=1
207    fi
208
209    cleanup_v6
210}
211
212run_all_tests() {
213    run_arp_evict_nocarrier_enabled
214    run_arp_evict_nocarrier_disabled
215    run_arp_evict_nocarrier_disabled_all
216    run_ndisc_evict_nocarrier_enabled
217    run_ndisc_evict_nocarrier_disabled
218    run_ndisc_evict_nocarrier_disabled_all
219}
220
221if [ "$(id -u)" -ne 0 ];then
222	echo "SKIP: Need root privileges"
223	exit $ksft_skip;
224fi
225
226run_all_tests
227exit $ret
228