255 lines
6.0 KiB
Bash
255 lines
6.0 KiB
Bash
|
#!/bin/bash
|
||
|
# SPDX-License-Identifier: GPL-2.0
|
||
|
|
||
|
# This test is for the accept_untracked_na feature to
|
||
|
# enable RFC9131 behaviour. The following is the test-matrix.
|
||
|
# drop accept fwding behaviour
|
||
|
# ---- ------ ------ ----------------------------------------------
|
||
|
# 1 X X Don't update NC
|
||
|
# 0 0 X Don't update NC
|
||
|
# 0 1 0 Don't update NC
|
||
|
# 0 1 1 Add a STALE NC entry
|
||
|
|
||
|
ret=0
|
||
|
# Kselftest framework requirement - SKIP code is 4.
|
||
|
ksft_skip=4
|
||
|
|
||
|
PAUSE_ON_FAIL=no
|
||
|
PAUSE=no
|
||
|
|
||
|
HOST_NS="ns-host"
|
||
|
ROUTER_NS="ns-router"
|
||
|
|
||
|
HOST_INTF="veth-host"
|
||
|
ROUTER_INTF="veth-router"
|
||
|
|
||
|
ROUTER_ADDR="2000:20::1"
|
||
|
HOST_ADDR="2000:20::2"
|
||
|
SUBNET_WIDTH=64
|
||
|
ROUTER_ADDR_WITH_MASK="${ROUTER_ADDR}/${SUBNET_WIDTH}"
|
||
|
HOST_ADDR_WITH_MASK="${HOST_ADDR}/${SUBNET_WIDTH}"
|
||
|
|
||
|
IP_HOST="ip -6 -netns ${HOST_NS}"
|
||
|
IP_HOST_EXEC="ip netns exec ${HOST_NS}"
|
||
|
IP_ROUTER="ip -6 -netns ${ROUTER_NS}"
|
||
|
IP_ROUTER_EXEC="ip netns exec ${ROUTER_NS}"
|
||
|
|
||
|
tcpdump_stdout=
|
||
|
tcpdump_stderr=
|
||
|
|
||
|
log_test()
|
||
|
{
|
||
|
local rc=$1
|
||
|
local expected=$2
|
||
|
local msg="$3"
|
||
|
|
||
|
if [ ${rc} -eq ${expected} ]; then
|
||
|
printf " TEST: %-60s [ OK ]\n" "${msg}"
|
||
|
nsuccess=$((nsuccess+1))
|
||
|
else
|
||
|
ret=1
|
||
|
nfail=$((nfail+1))
|
||
|
printf " TEST: %-60s [FAIL]\n" "${msg}"
|
||
|
if [ "${PAUSE_ON_FAIL}" = "yes" ]; then
|
||
|
echo
|
||
|
echo "hit enter to continue, 'q' to quit"
|
||
|
read a
|
||
|
[ "$a" = "q" ] && exit 1
|
||
|
fi
|
||
|
fi
|
||
|
|
||
|
if [ "${PAUSE}" = "yes" ]; then
|
||
|
echo
|
||
|
echo "hit enter to continue, 'q' to quit"
|
||
|
read a
|
||
|
[ "$a" = "q" ] && exit 1
|
||
|
fi
|
||
|
}
|
||
|
|
||
|
setup()
|
||
|
{
|
||
|
set -e
|
||
|
|
||
|
local drop_unsolicited_na=$1
|
||
|
local accept_untracked_na=$2
|
||
|
local forwarding=$3
|
||
|
|
||
|
# Setup two namespaces and a veth tunnel across them.
|
||
|
# On end of the tunnel is a router and the other end is a host.
|
||
|
ip netns add ${HOST_NS}
|
||
|
ip netns add ${ROUTER_NS}
|
||
|
${IP_ROUTER} link add ${ROUTER_INTF} type veth \
|
||
|
peer name ${HOST_INTF} netns ${HOST_NS}
|
||
|
|
||
|
# Enable IPv6 on both router and host, and configure static addresses.
|
||
|
# The router here is the DUT
|
||
|
# Setup router configuration as specified by the arguments.
|
||
|
# forwarding=0 case is to check that a non-router
|
||
|
# doesn't add neighbour entries.
|
||
|
ROUTER_CONF=net.ipv6.conf.${ROUTER_INTF}
|
||
|
${IP_ROUTER_EXEC} sysctl -qw \
|
||
|
${ROUTER_CONF}.forwarding=${forwarding}
|
||
|
${IP_ROUTER_EXEC} sysctl -qw \
|
||
|
${ROUTER_CONF}.drop_unsolicited_na=${drop_unsolicited_na}
|
||
|
${IP_ROUTER_EXEC} sysctl -qw \
|
||
|
${ROUTER_CONF}.accept_untracked_na=${accept_untracked_na}
|
||
|
${IP_ROUTER_EXEC} sysctl -qw ${ROUTER_CONF}.disable_ipv6=0
|
||
|
${IP_ROUTER} addr add ${ROUTER_ADDR_WITH_MASK} dev ${ROUTER_INTF}
|
||
|
|
||
|
# Turn on ndisc_notify on host interface so that
|
||
|
# the host sends unsolicited NAs.
|
||
|
HOST_CONF=net.ipv6.conf.${HOST_INTF}
|
||
|
${IP_HOST_EXEC} sysctl -qw ${HOST_CONF}.ndisc_notify=1
|
||
|
${IP_HOST_EXEC} sysctl -qw ${HOST_CONF}.disable_ipv6=0
|
||
|
${IP_HOST} addr add ${HOST_ADDR_WITH_MASK} dev ${HOST_INTF}
|
||
|
|
||
|
set +e
|
||
|
}
|
||
|
|
||
|
start_tcpdump() {
|
||
|
set -e
|
||
|
tcpdump_stdout=`mktemp`
|
||
|
tcpdump_stderr=`mktemp`
|
||
|
${IP_ROUTER_EXEC} timeout 15s \
|
||
|
tcpdump --immediate-mode -tpni ${ROUTER_INTF} -c 1 \
|
||
|
"icmp6 && icmp6[0] == 136 && src ${HOST_ADDR}" \
|
||
|
> ${tcpdump_stdout} 2> /dev/null
|
||
|
set +e
|
||
|
}
|
||
|
|
||
|
cleanup_tcpdump()
|
||
|
{
|
||
|
set -e
|
||
|
[[ ! -z ${tcpdump_stdout} ]] && rm -f ${tcpdump_stdout}
|
||
|
[[ ! -z ${tcpdump_stderr} ]] && rm -f ${tcpdump_stderr}
|
||
|
tcpdump_stdout=
|
||
|
tcpdump_stderr=
|
||
|
set +e
|
||
|
}
|
||
|
|
||
|
cleanup()
|
||
|
{
|
||
|
cleanup_tcpdump
|
||
|
ip netns del ${HOST_NS}
|
||
|
ip netns del ${ROUTER_NS}
|
||
|
}
|
||
|
|
||
|
link_up() {
|
||
|
set -e
|
||
|
${IP_ROUTER} link set dev ${ROUTER_INTF} up
|
||
|
${IP_HOST} link set dev ${HOST_INTF} up
|
||
|
set +e
|
||
|
}
|
||
|
|
||
|
verify_ndisc() {
|
||
|
local drop_unsolicited_na=$1
|
||
|
local accept_untracked_na=$2
|
||
|
local forwarding=$3
|
||
|
|
||
|
neigh_show_output=$(${IP_ROUTER} neigh show \
|
||
|
to ${HOST_ADDR} dev ${ROUTER_INTF} nud stale)
|
||
|
if [ ${drop_unsolicited_na} -eq 0 ] && \
|
||
|
[ ${accept_untracked_na} -eq 1 ] && \
|
||
|
[ ${forwarding} -eq 1 ]; then
|
||
|
# Neighbour entry expected to be present for 011 case
|
||
|
[[ ${neigh_show_output} ]]
|
||
|
else
|
||
|
# Neighbour entry expected to be absent for all other cases
|
||
|
[[ -z ${neigh_show_output} ]]
|
||
|
fi
|
||
|
}
|
||
|
|
||
|
test_unsolicited_na_common()
|
||
|
{
|
||
|
# Setup the test bed, but keep links down
|
||
|
setup $1 $2 $3
|
||
|
|
||
|
# Bring the link up, wait for the NA,
|
||
|
# and add a delay to ensure neighbour processing is done.
|
||
|
link_up
|
||
|
start_tcpdump
|
||
|
|
||
|
# Verify the neighbour table
|
||
|
verify_ndisc $1 $2 $3
|
||
|
|
||
|
}
|
||
|
|
||
|
test_unsolicited_na_combination() {
|
||
|
test_unsolicited_na_common $1 $2 $3
|
||
|
test_msg=("test_unsolicited_na: "
|
||
|
"drop_unsolicited_na=$1 "
|
||
|
"accept_untracked_na=$2 "
|
||
|
"forwarding=$3")
|
||
|
log_test $? 0 "${test_msg[*]}"
|
||
|
cleanup
|
||
|
}
|
||
|
|
||
|
test_unsolicited_na_combinations() {
|
||
|
# Args: drop_unsolicited_na accept_untracked_na forwarding
|
||
|
|
||
|
# Expect entry
|
||
|
test_unsolicited_na_combination 0 1 1
|
||
|
|
||
|
# Expect no entry
|
||
|
test_unsolicited_na_combination 0 0 0
|
||
|
test_unsolicited_na_combination 0 0 1
|
||
|
test_unsolicited_na_combination 0 1 0
|
||
|
test_unsolicited_na_combination 1 0 0
|
||
|
test_unsolicited_na_combination 1 0 1
|
||
|
test_unsolicited_na_combination 1 1 0
|
||
|
test_unsolicited_na_combination 1 1 1
|
||
|
}
|
||
|
|
||
|
###############################################################################
|
||
|
# usage
|
||
|
|
||
|
usage()
|
||
|
{
|
||
|
cat <<EOF
|
||
|
usage: ${0##*/} OPTS
|
||
|
-p Pause on fail
|
||
|
-P Pause after each test before cleanup
|
||
|
EOF
|
||
|
}
|
||
|
|
||
|
###############################################################################
|
||
|
# main
|
||
|
|
||
|
while getopts :pPh o
|
||
|
do
|
||
|
case $o in
|
||
|
p) PAUSE_ON_FAIL=yes;;
|
||
|
P) PAUSE=yes;;
|
||
|
h) usage; exit 0;;
|
||
|
*) usage; exit 1;;
|
||
|
esac
|
||
|
done
|
||
|
|
||
|
# make sure we don't pause twice
|
||
|
[ "${PAUSE}" = "yes" ] && PAUSE_ON_FAIL=no
|
||
|
|
||
|
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
|
||
|
|
||
|
# start clean
|
||
|
cleanup &> /dev/null
|
||
|
|
||
|
test_unsolicited_na_combinations
|
||
|
|
||
|
printf "\nTests passed: %3d\n" ${nsuccess}
|
||
|
printf "Tests failed: %3d\n" ${nfail}
|
||
|
|
||
|
exit $ret
|