ndisc_unsolicited_na_test.sh 5.8 KB

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