diff --git a/tools/testing/selftests/net/ndisc_unsolicited_na_test.sh b/tools/testing/selftests/net/ndisc_unsolicited_na_test.sh index 5db69dad0cfc..ba9e670b5149 100755 --- a/tools/testing/selftests/net/ndisc_unsolicited_na_test.sh +++ b/tools/testing/selftests/net/ndisc_unsolicited_na_test.sh @@ -3,12 +3,18 @@ # 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 +# state drop accept fwding behaviour +# ------ ---- ------ ------ ---------------------------------------------- +# absent 1 X X Don't update NC +# absent 0 0 X Don't update NC +# absent 0 1 0 Don't update NC +# absent 0 1 1 Add a STALE NC entry +# failed 1 X X Keep the NC entry in FAILED state +# failed 0 0 X Keep the NC entry in FAILED state +# failed 0 1 0 Keep the NC entry in FAILED state +# failed 0 1 1 Update the NC entry to STALE +# failed 0 2 1 Update the NC entry to STALE if in-network +# failed 0 2 1 Keep the NC entry FAILED if out-of-network source lib.sh ret=0 @@ -19,14 +25,18 @@ PAUSE=no HOST_INTF="veth-host" ROUTER_INTF="veth-router" -ROUTER_ADDR="2000:20::1" +ROUTER_ADDR_IN_NETWORK="2000:20::1" +ROUTER_ADDR_OUT_OF_NETWORK="2000:21::1" +ROUTER_ADDR="${ROUTER_ADDR_IN_NETWORK}" HOST_ADDR="2000:20::2" +HOST_LLADDR="02:00:00:00:00:02" SUBNET_WIDTH=64 ROUTER_ADDR_WITH_MASK="${ROUTER_ADDR}/${SUBNET_WIDTH}" HOST_ADDR_WITH_MASK="${HOST_ADDR}/${SUBNET_WIDTH}" tcpdump_stdout= tcpdump_stderr= +tcpdump_pid= log_test() { @@ -75,6 +85,7 @@ setup() ${IP_ROUTER} link add ${ROUTER_INTF} type veth \ peer name ${HOST_INTF} netns ${HOST_NS} + ${IP_HOST} link set dev "${HOST_INTF}" address "${HOST_LLADDR}" # Enable IPv6 on both router and host, and configure static addresses. # The router here is the DUT @@ -88,6 +99,8 @@ setup() ${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}.ndisc_evict_nocarrier=0 ${IP_ROUTER_EXEC} sysctl -qw ${ROUTER_CONF}.disable_ipv6=0 ${IP_ROUTER} addr add ${ROUTER_ADDR_WITH_MASK} dev ${ROUTER_INTF} @@ -102,24 +115,39 @@ setup() } start_tcpdump() { - set -e - tcpdump_stdout=`mktemp` - tcpdump_stderr=`mktemp` + tcpdump_stdout=$(mktemp) || return 1 + tcpdump_stderr=$(mktemp) || return 1 ${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 + > "${tcpdump_stdout}" 2> "${tcpdump_stderr}" & + tcpdump_pid=$! + + slowwait 5 grep -q "listening on ${ROUTER_INTF}" "${tcpdump_stderr}" +} + +wait_tcpdump() +{ + local rc + + wait "${tcpdump_pid}" + rc=$? + tcpdump_pid= + + return "${rc}" } cleanup_tcpdump() { - set -e - [[ ! -z ${tcpdump_stdout} ]] && rm -f ${tcpdump_stdout} - [[ ! -z ${tcpdump_stderr} ]] && rm -f ${tcpdump_stderr} + if [ -n "${tcpdump_pid}" ]; then + kill "${tcpdump_pid}" 2> /dev/null + wait "${tcpdump_pid}" 2> /dev/null + fi + [ -n "${tcpdump_stdout}" ] && rm -f "${tcpdump_stdout}" + [ -n "${tcpdump_stderr}" ] && rm -f "${tcpdump_stderr}" tcpdump_stdout= tcpdump_stderr= - set +e + tcpdump_pid= } cleanup() @@ -129,58 +157,145 @@ cleanup() ip netns del ${ROUTER_NS} } -link_up() { - set -e +router_link_up() +{ ${IP_ROUTER} link set dev ${ROUTER_INTF} up +} + +host_link_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 + local initial_state=${4:-absent} + local same_subnet=${5:-1} + local expected_lladdr + local neigh_show_output + local expected_state - 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} ]] + if [ "${drop_unsolicited_na}" -eq 0 ] && + [ "${forwarding}" -eq 1 ]; then + case "${accept_untracked_na}" in + 1) + expected_state=STALE + expected_lladdr="${HOST_LLADDR}" + ;; + 2) + if [ "${same_subnet}" -eq 1 ]; then + expected_state=STALE + expected_lladdr="${HOST_LLADDR}" + fi + ;; + esac + fi + if [ -z "${expected_state}" ] && + [ "${initial_state}" = "failed" ]; then + expected_state=FAILED + fi + + if [ -n "${expected_state}" ]; then + neigh_show_output=$(${IP_ROUTER} neigh show \ + to "${HOST_ADDR}" dev "${ROUTER_INTF}") + if [[ " ${neigh_show_output} " != \ + *" ${expected_state} "* ]]; then + return 1 + fi + if [ -n "${expected_lladdr}" ] && + [[ " ${neigh_show_output} " != \ + *" lladdr ${expected_lladdr} "* ]]; then + return 1 + fi + if [[ "${expected_state}" == "FAILED" && + "${neigh_show_output}" == *"lladdr"* ]]; then + return 1 + fi + if [ "${initial_state}" = "failed" ]; then + [[ "${neigh_show_output}" == *"extern_learn"* ]] + fi else - # Neighbour entry expected to be absent for all other cases + neigh_show_output=$(${IP_ROUTER} neigh show \ + to "${HOST_ADDR}" dev "${ROUTER_INTF}") [[ -z ${neigh_show_output} ]] fi } test_unsolicited_na_common() { - # Setup the test bed, but keep links down - setup $1 $2 $3 + local same_subnet=${5:-1} + local neigh_show_output - # Bring the link up, wait for the NA, - # and add a delay to ensure neighbour processing is done. - link_up - start_tcpdump + if [ "${same_subnet}" -eq 1 ]; then + ROUTER_ADDR="${ROUTER_ADDR_IN_NETWORK}" + else + ROUTER_ADDR="${ROUTER_ADDR_OUT_OF_NETWORK}" + fi + ROUTER_ADDR_WITH_MASK="${ROUTER_ADDR}/${SUBNET_WIDTH}" + + # Setup the test bed, but keep links down + setup "$1" "$2" "$3" + + if [ "${4:-absent}" = "failed" ]; then + if ! ${IP_ROUTER} neigh replace "${HOST_ADDR}" \ + dev "${ROUTER_INTF}" \ + nud failed extern_learn; then + echo "Unable to create NUD_FAILED neighbor entry" + return 1 + fi + neigh_show_output=$(${IP_ROUTER} neigh show \ + to "${HOST_ADDR}" dev "${ROUTER_INTF}") + if [[ " ${neigh_show_output} " != *" FAILED "* ]]; then + echo "Unable to verify NUD_FAILED neighbor entry" + return 1 + fi + if [[ "${neigh_show_output}" != *"extern_learn"* ]]; then + echo "Neighbor entry is not externally learned" + return 1 + fi + fi + + # Arm the capture before bringing up the host and starting DAD. + router_link_up || return 1 + start_tcpdump || return 1 + host_link_up || return 1 + + # Closing tcpdump's packet socket calls synchronize_net(), so waiting + # for it also waits for receive processing of the captured NA. + wait_tcpdump || return 1 # Verify the neighbour table - verify_ndisc $1 $2 $3 + verify_ndisc "$1" "$2" "$3" "$4" "${same_subnet}" } test_unsolicited_na_combination() { - test_unsolicited_na_common $1 $2 $3 + local initial_state=${4:-absent} + local same_subnet=${5:-1} + local rc + + test_unsolicited_na_common "$1" "$2" "$3" "${initial_state}" \ + "${same_subnet}" + rc=$? test_msg=("test_unsolicited_na: " "drop_unsolicited_na=$1 " "accept_untracked_na=$2 " "forwarding=$3") - log_test $? 0 "${test_msg[*]}" + if [ "${initial_state}" = "failed" ]; then + test_msg+=("initial_state=failed") + fi + if [ "$2" -eq 2 ]; then + test_msg+=("same_subnet=${same_subnet}") + fi + log_test "${rc}" 0 "${test_msg[*]}" cleanup } test_unsolicited_na_combinations() { # Args: drop_unsolicited_na accept_untracked_na forwarding + # [initial_state] [same_subnet] # Expect entry test_unsolicited_na_combination 0 1 1 @@ -193,6 +308,16 @@ test_unsolicited_na_combinations() { test_unsolicited_na_combination 1 0 1 test_unsolicited_na_combination 1 1 0 test_unsolicited_na_combination 1 1 1 + + # Expect FAILED entry to become STALE + test_unsolicited_na_combination 0 1 1 failed + test_unsolicited_na_combination 0 2 1 failed 1 + + # Expect FAILED entry to remain FAILED + test_unsolicited_na_combination 0 0 1 failed + test_unsolicited_na_combination 0 1 0 failed + test_unsolicited_na_combination 1 1 1 failed + test_unsolicited_na_combination 0 2 1 failed 0 } ###############################################################################