Merge branch 'net-ipv4-ipv6-new-option-to-accept-garp-untracked-na-only-if-in-network'
Jaehee Park says: ==================== net: ipv4/ipv6: new option to accept garp/untracked na only if in-network The first patch adds an option to learn a neighbor from garp only if the source ip is in the same subnet as an address configured on the interface that received the garp message. The option has been added to arp_accept in ipv4. The same feature has been added to ndisc (patch 2). For ipv6, the subnet filtering knob is an extension of the accept_untracked_na option introduced in these patches: https://lore.kernel.org/all/642672cb-8b11-c78f-8975-f287ece9e89e@gmail.com/t/ https://lore.kernel.org/netdev/20220530101414.65439-1-aajith@arista.com/T/ The third patch contains selftests for testing the different options for accepting arp and neighbor advertisements. ==================== Link: https://lore.kernel.org/r/cover.1657755188.git.jhpark1013@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
2acd102254
@ -1633,12 +1633,15 @@ arp_notify - BOOLEAN
|
||||
or hardware address changes.
|
||||
== ==========================================================
|
||||
|
||||
arp_accept - BOOLEAN
|
||||
Define behavior for gratuitous ARP frames who's IP is not
|
||||
already present in the ARP table:
|
||||
arp_accept - INTEGER
|
||||
Define behavior for accepting gratuitous ARP (garp) frames from devices
|
||||
that are not already present in the ARP table:
|
||||
|
||||
- 0 - don't create new entries in the ARP table
|
||||
- 1 - create new entries in the ARP table
|
||||
- 2 - create new entries only if the source IP address is in the same
|
||||
subnet as an address configured on the interface that received the
|
||||
garp message.
|
||||
|
||||
Both replies and requests type gratuitous arp will trigger the
|
||||
ARP table to be updated, if this setting is on.
|
||||
@ -2480,27 +2483,36 @@ drop_unsolicited_na - BOOLEAN
|
||||
|
||||
By default this is turned off.
|
||||
|
||||
accept_untracked_na - BOOLEAN
|
||||
Add a new neighbour cache entry in STALE state for routers on receiving a
|
||||
neighbour advertisement (either solicited or unsolicited) with target
|
||||
link-layer address option specified if no neighbour entry is already
|
||||
present for the advertised IPv6 address. Without this knob, NAs received
|
||||
for untracked addresses (absent in neighbour cache) are silently ignored.
|
||||
accept_untracked_na - INTEGER
|
||||
Define behavior for accepting neighbor advertisements from devices that
|
||||
are absent in the neighbor cache:
|
||||
|
||||
This is as per router-side behaviour documented in RFC9131.
|
||||
- 0 - (default) Do not accept unsolicited and untracked neighbor
|
||||
advertisements.
|
||||
|
||||
- 1 - Add a new neighbor cache entry in STALE state for routers on
|
||||
receiving a neighbor advertisement (either solicited or unsolicited)
|
||||
with target link-layer address option specified if no neighbor entry
|
||||
is already present for the advertised IPv6 address. Without this knob,
|
||||
NAs received for untracked addresses (absent in neighbor cache) are
|
||||
silently ignored.
|
||||
|
||||
This is as per router-side behavior documented in RFC9131.
|
||||
|
||||
This has lower precedence than drop_unsolicited_na.
|
||||
|
||||
This will optimize the return path for the initial off-link communication
|
||||
that is initiated by a directly connected host, by ensuring that
|
||||
the first-hop router which turns on this setting doesn't have to
|
||||
buffer the initial return packets to do neighbour-solicitation.
|
||||
The prerequisite is that the host is configured to send
|
||||
unsolicited neighbour advertisements on interface bringup.
|
||||
This setting should be used in conjunction with the ndisc_notify setting
|
||||
on the host to satisfy this prerequisite.
|
||||
This will optimize the return path for the initial off-link
|
||||
communication that is initiated by a directly connected host, by
|
||||
ensuring that the first-hop router which turns on this setting doesn't
|
||||
have to buffer the initial return packets to do neighbor-solicitation.
|
||||
The prerequisite is that the host is configured to send unsolicited
|
||||
neighbor advertisements on interface bringup. This setting should be
|
||||
used in conjunction with the ndisc_notify setting on the host to
|
||||
satisfy this prerequisite.
|
||||
|
||||
By default this is turned off.
|
||||
- 2 - Extend option (1) to add a new neighbor cache entry only if the
|
||||
source IP address is in the same subnet as an address configured on
|
||||
the interface that received the neighbor advertisement.
|
||||
|
||||
enhanced_dad - BOOLEAN
|
||||
Include a nonce option in the IPv6 neighbor solicitation messages used for
|
||||
|
@ -131,7 +131,7 @@ static inline void ipv4_devconf_setall(struct in_device *in_dev)
|
||||
IN_DEV_ORCONF((in_dev), IGNORE_ROUTES_WITH_LINKDOWN)
|
||||
|
||||
#define IN_DEV_ARPFILTER(in_dev) IN_DEV_ORCONF((in_dev), ARPFILTER)
|
||||
#define IN_DEV_ARP_ACCEPT(in_dev) IN_DEV_ORCONF((in_dev), ARP_ACCEPT)
|
||||
#define IN_DEV_ARP_ACCEPT(in_dev) IN_DEV_MAXCONF((in_dev), ARP_ACCEPT)
|
||||
#define IN_DEV_ARP_ANNOUNCE(in_dev) IN_DEV_MAXCONF((in_dev), ARP_ANNOUNCE)
|
||||
#define IN_DEV_ARP_IGNORE(in_dev) IN_DEV_MAXCONF((in_dev), ARP_IGNORE)
|
||||
#define IN_DEV_ARP_NOTIFY(in_dev) IN_DEV_MAXCONF((in_dev), ARP_NOTIFY)
|
||||
|
@ -429,6 +429,26 @@ static int arp_ignore(struct in_device *in_dev, __be32 sip, __be32 tip)
|
||||
return !inet_confirm_addr(net, in_dev, sip, tip, scope);
|
||||
}
|
||||
|
||||
static int arp_accept(struct in_device *in_dev, __be32 sip)
|
||||
{
|
||||
struct net *net = dev_net(in_dev->dev);
|
||||
int scope = RT_SCOPE_LINK;
|
||||
|
||||
switch (IN_DEV_ARP_ACCEPT(in_dev)) {
|
||||
case 0: /* Don't create new entries from garp */
|
||||
return 0;
|
||||
case 1: /* Create new entries from garp */
|
||||
return 1;
|
||||
case 2: /* Create a neighbor in the arp table only if sip
|
||||
* is in the same subnet as an address configured
|
||||
* on the interface that received the garp message
|
||||
*/
|
||||
return !!inet_confirm_addr(net, in_dev, sip, 0, scope);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int arp_filter(__be32 sip, __be32 tip, struct net_device *dev)
|
||||
{
|
||||
struct rtable *rt;
|
||||
@ -868,12 +888,12 @@ static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
n = __neigh_lookup(&arp_tbl, &sip, dev, 0);
|
||||
|
||||
addr_type = -1;
|
||||
if (n || IN_DEV_ARP_ACCEPT(in_dev)) {
|
||||
if (n || arp_accept(in_dev, sip)) {
|
||||
is_garp = arp_is_garp(net, dev, &addr_type, arp->ar_op,
|
||||
sip, tip, sha, tha);
|
||||
}
|
||||
|
||||
if (IN_DEV_ARP_ACCEPT(in_dev)) {
|
||||
if (arp_accept(in_dev, sip)) {
|
||||
/* Unsolicited ARP is not accepted by default.
|
||||
It is possible, that this option should be enabled for some
|
||||
devices (strip is candidate)
|
||||
|
@ -7042,7 +7042,7 @@ static const struct ctl_table addrconf_sysctl[] = {
|
||||
.data = &ipv6_devconf.accept_untracked_na,
|
||||
.maxlen = sizeof(int),
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_dointvec_minmax,
|
||||
.proc_handler = proc_dointvec,
|
||||
.extra1 = (void *)SYSCTL_ZERO,
|
||||
.extra2 = (void *)SYSCTL_ONE,
|
||||
},
|
||||
|
@ -967,6 +967,25 @@ out:
|
||||
in6_dev_put(idev);
|
||||
}
|
||||
|
||||
static int accept_untracked_na(struct net_device *dev, struct in6_addr *saddr)
|
||||
{
|
||||
struct inet6_dev *idev = __in6_dev_get(dev);
|
||||
|
||||
switch (idev->cnf.accept_untracked_na) {
|
||||
case 0: /* Don't accept untracked na (absent in neighbor cache) */
|
||||
return 0;
|
||||
case 1: /* Create new entries from na if currently untracked */
|
||||
return 1;
|
||||
case 2: /* Create new entries from untracked na only if saddr is in the
|
||||
* same subnet as an address configured on the interface that
|
||||
* received the na
|
||||
*/
|
||||
return !!ipv6_chk_prefix(saddr, dev);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void ndisc_recv_na(struct sk_buff *skb)
|
||||
{
|
||||
struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb);
|
||||
@ -1061,12 +1080,12 @@ static void ndisc_recv_na(struct sk_buff *skb)
|
||||
* Note that we don't do a (daddr == all-routers-mcast) check.
|
||||
*/
|
||||
new_state = msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE;
|
||||
if (!neigh && lladdr &&
|
||||
idev && idev->cnf.forwarding &&
|
||||
idev->cnf.accept_untracked_na) {
|
||||
if (!neigh && lladdr && idev && idev->cnf.forwarding) {
|
||||
if (accept_untracked_na(dev, saddr)) {
|
||||
neigh = neigh_create(&nd_tbl, &msg->target, dev);
|
||||
new_state = NUD_STALE;
|
||||
}
|
||||
}
|
||||
|
||||
if (neigh && !IS_ERR(neigh)) {
|
||||
u8 old_flags = neigh->flags;
|
||||
|
@ -38,6 +38,7 @@ TEST_PROGS += srv6_end_dt6_l3vpn_test.sh
|
||||
TEST_PROGS += vrf_strict_mode_test.sh
|
||||
TEST_PROGS += arp_ndisc_evict_nocarrier.sh
|
||||
TEST_PROGS += ndisc_unsolicited_na_test.sh
|
||||
TEST_PROGS += arp_ndisc_untracked_subnets.sh
|
||||
TEST_PROGS += stress_reuseport_listen.sh
|
||||
TEST_PROGS_EXTENDED := in_netns.sh setup_loopback.sh setup_veth.sh
|
||||
TEST_PROGS_EXTENDED += toeplitz_client.sh toeplitz.sh
|
||||
|
308
tools/testing/selftests/net/arp_ndisc_untracked_subnets.sh
Executable file
308
tools/testing/selftests/net/arp_ndisc_untracked_subnets.sh
Executable file
@ -0,0 +1,308 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# 2 namespaces: one host and one router. Use arping from the host to send a
|
||||
# garp to the router. Router accepts or ignores based on its arp_accept
|
||||
# or accept_untracked_na configuration.
|
||||
|
||||
TESTS="arp ndisc"
|
||||
|
||||
ROUTER_NS="ns-router"
|
||||
ROUTER_NS_V6="ns-router-v6"
|
||||
ROUTER_INTF="veth-router"
|
||||
ROUTER_ADDR="10.0.10.1"
|
||||
ROUTER_ADDR_V6="2001:db8:abcd:0012::1"
|
||||
|
||||
HOST_NS="ns-host"
|
||||
HOST_NS_V6="ns-host-v6"
|
||||
HOST_INTF="veth-host"
|
||||
HOST_ADDR="10.0.10.2"
|
||||
HOST_ADDR_V6="2001:db8:abcd:0012::2"
|
||||
|
||||
SUBNET_WIDTH=24
|
||||
PREFIX_WIDTH_V6=64
|
||||
|
||||
cleanup() {
|
||||
ip netns del ${HOST_NS}
|
||||
ip netns del ${ROUTER_NS}
|
||||
}
|
||||
|
||||
cleanup_v6() {
|
||||
ip netns del ${HOST_NS_V6}
|
||||
ip netns del ${ROUTER_NS_V6}
|
||||
}
|
||||
|
||||
setup() {
|
||||
set -e
|
||||
local arp_accept=$1
|
||||
|
||||
# Set up two namespaces
|
||||
ip netns add ${ROUTER_NS}
|
||||
ip netns add ${HOST_NS}
|
||||
|
||||
# Set up interfaces veth0 and veth1, which are pairs in separate
|
||||
# namespaces. veth0 is veth-router, veth1 is veth-host.
|
||||
# first, set up the inteface's link to the namespace
|
||||
# then, set the interface "up"
|
||||
ip netns exec ${ROUTER_NS} ip link add name ${ROUTER_INTF} \
|
||||
type veth peer name ${HOST_INTF}
|
||||
|
||||
ip netns exec ${ROUTER_NS} ip link set dev ${ROUTER_INTF} up
|
||||
ip netns exec ${ROUTER_NS} ip link set dev ${HOST_INTF} netns ${HOST_NS}
|
||||
|
||||
ip netns exec ${HOST_NS} ip link set dev ${HOST_INTF} up
|
||||
ip netns exec ${ROUTER_NS} ip addr add ${ROUTER_ADDR}/${SUBNET_WIDTH} \
|
||||
dev ${ROUTER_INTF}
|
||||
|
||||
ip netns exec ${HOST_NS} ip addr add ${HOST_ADDR}/${SUBNET_WIDTH} \
|
||||
dev ${HOST_INTF}
|
||||
ip netns exec ${HOST_NS} ip route add default via ${HOST_ADDR} \
|
||||
dev ${HOST_INTF}
|
||||
ip netns exec ${ROUTER_NS} ip route add default via ${ROUTER_ADDR} \
|
||||
dev ${ROUTER_INTF}
|
||||
|
||||
ROUTER_CONF=net.ipv4.conf.${ROUTER_INTF}
|
||||
ip netns exec ${ROUTER_NS} sysctl -w \
|
||||
${ROUTER_CONF}.arp_accept=${arp_accept} >/dev/null 2>&1
|
||||
set +e
|
||||
}
|
||||
|
||||
setup_v6() {
|
||||
set -e
|
||||
local accept_untracked_na=$1
|
||||
|
||||
# Set up two namespaces
|
||||
ip netns add ${ROUTER_NS_V6}
|
||||
ip netns add ${HOST_NS_V6}
|
||||
|
||||
# Set up interfaces veth0 and veth1, which are pairs in separate
|
||||
# namespaces. veth0 is veth-router, veth1 is veth-host.
|
||||
# first, set up the inteface's link to the namespace
|
||||
# then, set the interface "up"
|
||||
ip -6 -netns ${ROUTER_NS_V6} link add name ${ROUTER_INTF} \
|
||||
type veth peer name ${HOST_INTF}
|
||||
|
||||
ip -6 -netns ${ROUTER_NS_V6} link set dev ${ROUTER_INTF} up
|
||||
ip -6 -netns ${ROUTER_NS_V6} link set dev ${HOST_INTF} netns \
|
||||
${HOST_NS_V6}
|
||||
|
||||
ip -6 -netns ${HOST_NS_V6} link set dev ${HOST_INTF} up
|
||||
ip -6 -netns ${ROUTER_NS_V6} addr add \
|
||||
${ROUTER_ADDR_V6}/${PREFIX_WIDTH_V6} dev ${ROUTER_INTF} nodad
|
||||
|
||||
HOST_CONF=net.ipv6.conf.${HOST_INTF}
|
||||
ip netns exec ${HOST_NS_V6} sysctl -qw ${HOST_CONF}.ndisc_notify=1
|
||||
ip netns exec ${HOST_NS_V6} sysctl -qw ${HOST_CONF}.disable_ipv6=0
|
||||
ip -6 -netns ${HOST_NS_V6} addr add ${HOST_ADDR_V6}/${PREFIX_WIDTH_V6} \
|
||||
dev ${HOST_INTF}
|
||||
|
||||
ROUTER_CONF=net.ipv6.conf.${ROUTER_INTF}
|
||||
|
||||
ip netns exec ${ROUTER_NS_V6} sysctl -w \
|
||||
${ROUTER_CONF}.forwarding=1 >/dev/null 2>&1
|
||||
ip netns exec ${ROUTER_NS_V6} sysctl -w \
|
||||
${ROUTER_CONF}.drop_unsolicited_na=0 >/dev/null 2>&1
|
||||
ip netns exec ${ROUTER_NS_V6} sysctl -w \
|
||||
${ROUTER_CONF}.accept_untracked_na=${accept_untracked_na} \
|
||||
>/dev/null 2>&1
|
||||
set +e
|
||||
}
|
||||
|
||||
verify_arp() {
|
||||
local arp_accept=$1
|
||||
local same_subnet=$2
|
||||
|
||||
neigh_show_output=$(ip netns exec ${ROUTER_NS} ip neigh get \
|
||||
${HOST_ADDR} dev ${ROUTER_INTF} 2>/dev/null)
|
||||
|
||||
if [ ${arp_accept} -eq 1 ]; then
|
||||
# Neighbor entries expected
|
||||
[[ ${neigh_show_output} ]]
|
||||
elif [ ${arp_accept} -eq 2 ]; then
|
||||
if [ ${same_subnet} -eq 1 ]; then
|
||||
# Neighbor entries expected
|
||||
[[ ${neigh_show_output} ]]
|
||||
else
|
||||
[[ -z "${neigh_show_output}" ]]
|
||||
fi
|
||||
else
|
||||
[[ -z "${neigh_show_output}" ]]
|
||||
fi
|
||||
}
|
||||
|
||||
arp_test_gratuitous() {
|
||||
set -e
|
||||
local arp_accept=$1
|
||||
local same_subnet=$2
|
||||
|
||||
if [ ${arp_accept} -eq 2 ]; then
|
||||
test_msg=("test_arp: "
|
||||
"accept_arp=$1 "
|
||||
"same_subnet=$2")
|
||||
if [ ${same_subnet} -eq 0 ]; then
|
||||
HOST_ADDR=10.0.11.3
|
||||
else
|
||||
HOST_ADDR=10.0.10.3
|
||||
fi
|
||||
else
|
||||
test_msg=("test_arp: "
|
||||
"accept_arp=$1")
|
||||
fi
|
||||
# Supply arp_accept option to set up which sets it in sysctl
|
||||
setup ${arp_accept}
|
||||
ip netns exec ${HOST_NS} arping -A -U ${HOST_ADDR} -c1 2>&1 >/dev/null
|
||||
|
||||
if verify_arp $1 $2; then
|
||||
printf " TEST: %-60s [ OK ]\n" "${test_msg[*]}"
|
||||
else
|
||||
printf " TEST: %-60s [FAIL]\n" "${test_msg[*]}"
|
||||
fi
|
||||
cleanup
|
||||
set +e
|
||||
}
|
||||
|
||||
arp_test_gratuitous_combinations() {
|
||||
arp_test_gratuitous 0
|
||||
arp_test_gratuitous 1
|
||||
arp_test_gratuitous 2 0 # Second entry indicates subnet or not
|
||||
arp_test_gratuitous 2 1
|
||||
}
|
||||
|
||||
cleanup_tcpdump() {
|
||||
set -e
|
||||
[[ ! -z ${tcpdump_stdout} ]] && rm -f ${tcpdump_stdout}
|
||||
[[ ! -z ${tcpdump_stderr} ]] && rm -f ${tcpdump_stderr}
|
||||
tcpdump_stdout=
|
||||
tcpdump_stderr=
|
||||
set +e
|
||||
}
|
||||
|
||||
start_tcpdump() {
|
||||
set -e
|
||||
tcpdump_stdout=`mktemp`
|
||||
tcpdump_stderr=`mktemp`
|
||||
ip netns exec ${ROUTER_NS_V6} timeout 15s \
|
||||
tcpdump --immediate-mode -tpni ${ROUTER_INTF} -c 1 \
|
||||
"icmp6 && icmp6[0] == 136 && src ${HOST_ADDR_V6}" \
|
||||
> ${tcpdump_stdout} 2> /dev/null
|
||||
set +e
|
||||
}
|
||||
|
||||
verify_ndisc() {
|
||||
local accept_untracked_na=$1
|
||||
local same_subnet=$2
|
||||
|
||||
neigh_show_output=$(ip -6 -netns ${ROUTER_NS_V6} neigh show \
|
||||
to ${HOST_ADDR_V6} dev ${ROUTER_INTF} nud stale)
|
||||
|
||||
if [ ${accept_untracked_na} -eq 1 ]; then
|
||||
# Neighbour entry expected to be present
|
||||
[[ ${neigh_show_output} ]]
|
||||
elif [ ${accept_untracked_na} -eq 2 ]; then
|
||||
if [ ${same_subnet} -eq 1 ]; then
|
||||
[[ ${neigh_show_output} ]]
|
||||
else
|
||||
[[ -z "${neigh_show_output}" ]]
|
||||
fi
|
||||
else
|
||||
# Neighbour entry expected to be absent for all other cases
|
||||
[[ -z "${neigh_show_output}" ]]
|
||||
fi
|
||||
}
|
||||
|
||||
ndisc_test_untracked_advertisements() {
|
||||
set -e
|
||||
test_msg=("test_ndisc: "
|
||||
"accept_untracked_na=$1")
|
||||
|
||||
local accept_untracked_na=$1
|
||||
local same_subnet=$2
|
||||
if [ ${accept_untracked_na} -eq 2 ]; then
|
||||
test_msg=("test_ndisc: "
|
||||
"accept_untracked_na=$1 "
|
||||
"same_subnet=$2")
|
||||
if [ ${same_subnet} -eq 0 ]; then
|
||||
# Not same subnet
|
||||
HOST_ADDR_V6=2000:db8:abcd:0013::4
|
||||
else
|
||||
HOST_ADDR_V6=2001:db8:abcd:0012::3
|
||||
fi
|
||||
fi
|
||||
setup_v6 $1 $2
|
||||
start_tcpdump
|
||||
|
||||
if verify_ndisc $1 $2; then
|
||||
printf " TEST: %-60s [ OK ]\n" "${test_msg[*]}"
|
||||
else
|
||||
printf " TEST: %-60s [FAIL]\n" "${test_msg[*]}"
|
||||
fi
|
||||
|
||||
cleanup_tcpdump
|
||||
cleanup_v6
|
||||
set +e
|
||||
}
|
||||
|
||||
ndisc_test_untracked_combinations() {
|
||||
ndisc_test_untracked_advertisements 0
|
||||
ndisc_test_untracked_advertisements 1
|
||||
ndisc_test_untracked_advertisements 2 0
|
||||
ndisc_test_untracked_advertisements 2 1
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# usage
|
||||
|
||||
usage()
|
||||
{
|
||||
cat <<EOF
|
||||
usage: ${0##*/} OPTS
|
||||
|
||||
-t <test> Test(s) to run (default: all)
|
||||
(options: $TESTS)
|
||||
EOF
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# main
|
||||
|
||||
while getopts ":t:h" opt; do
|
||||
case $opt in
|
||||
t) TESTS=$OPTARG;;
|
||||
h) usage; exit 0;;
|
||||
*) usage; exit 1;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ "$(id -u)" -ne 0 ];then
|
||||
echo "SKIP: Need root privileges"
|
||||
exit $ksft_skip;
|
||||
fi
|
||||
|
||||
if [ ! -x "$(command -v ip)" ]; then
|
||||
echo "SKIP: Could not run test without ip tool"
|
||||
exit $ksft_skip
|
||||
fi
|
||||
|
||||
if [ ! -x "$(command -v tcpdump)" ]; then
|
||||
echo "SKIP: Could not run test without tcpdump tool"
|
||||
exit $ksft_skip
|
||||
fi
|
||||
|
||||
if [ ! -x "$(command -v arping)" ]; then
|
||||
echo "SKIP: Could not run test without arping tool"
|
||||
exit $ksft_skip
|
||||
fi
|
||||
|
||||
# start clean
|
||||
cleanup &> /dev/null
|
||||
cleanup_v6 &> /dev/null
|
||||
|
||||
for t in $TESTS
|
||||
do
|
||||
case $t in
|
||||
arp_test_gratuitous_combinations|arp) arp_test_gratuitous_combinations;;
|
||||
ndisc_test_untracked_combinations|ndisc) \
|
||||
ndisc_test_untracked_combinations;;
|
||||
help) echo "Test names: $TESTS"; exit 0;;
|
||||
esac
|
||||
done
|
Loading…
Reference in New Issue
Block a user