srv6_iptunnel_cache.sh 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. #!/bin/bash
  2. # SPDX-License-Identifier: GPL-2.0
  3. #
  4. # author: Andrea Mayer <andrea.mayer@uniroma2.it>
  5. # This test verifies that the seg6 lwtunnel does not share the dst_cache
  6. # between the input (forwarding) and output (locally generated) paths.
  7. #
  8. # A shared dst_cache allows a forwarded packet to populate the cache and a
  9. # subsequent locally generated packet to silently reuse that entry, bypassing
  10. # its own route lookup. To expose this, the SID is made reachable only for
  11. # forwarded traffic (via an ip rule matching iif) and blackholed for everything
  12. # else. A local ping on ns_router must always hit the blackhole;
  13. # if it succeeds after a forwarded packet has populated the
  14. # cache, the bug is confirmed.
  15. #
  16. # Both forwarded and local packets are pinned to the same CPU with taskset,
  17. # since dst_cache is per-cpu.
  18. #
  19. #
  20. # +--------------------+ +--------------------+
  21. # | ns_src | | ns_dst |
  22. # | | | |
  23. # | veth-s0 | | veth-d0 |
  24. # | fd00::1/64 | | fd01::2/64 |
  25. # +-------+------------+ +----------+---------+
  26. # | |
  27. # | +--------------------+ |
  28. # | | ns_router | |
  29. # | | | |
  30. # +------------+ veth-r0 veth-r1 +--------------+
  31. # | fd00::2 fd01::1 |
  32. # +--------------------+
  33. #
  34. #
  35. # ns_router: encap (main table)
  36. # +---------+---------------------------------------+
  37. # | dst | action |
  38. # +---------+---------------------------------------+
  39. # | cafe::1 | encap seg6 mode encap segs fc00::100 |
  40. # +---------+---------------------------------------+
  41. #
  42. # ns_router: post-encap SID resolution
  43. # +-------+------------+----------------------------+
  44. # | table | dst | action |
  45. # +-------+------------+----------------------------+
  46. # | 100 | fc00::100 | via fd01::2 dev veth-r1 |
  47. # +-------+------------+----------------------------+
  48. # | main | fc00::100 | blackhole |
  49. # +-------+------------+----------------------------+
  50. #
  51. # ns_router: ip rule
  52. # +------------------+------------------------------+
  53. # | match | action |
  54. # +------------------+------------------------------+
  55. # | iif veth-r0 | lookup 100 |
  56. # +------------------+------------------------------+
  57. #
  58. # ns_dst: SRv6 decap (main table)
  59. # +--------------+----------------------------------+
  60. # | SID | action |
  61. # +--------------+----------------------------------+
  62. # | fc00::100 | End.DT6 table 255 (local) |
  63. # +--------------+----------------------------------+
  64. source lib.sh
  65. readonly SID="fc00::100"
  66. readonly DEST="cafe::1"
  67. readonly SRC_MAC="02:00:00:00:00:01"
  68. readonly RTR_R0_MAC="02:00:00:00:00:02"
  69. readonly RTR_R1_MAC="02:00:00:00:00:03"
  70. readonly DST_MAC="02:00:00:00:00:04"
  71. cleanup()
  72. {
  73. cleanup_ns "${NS_SRC}" "${NS_RTR}" "${NS_DST}"
  74. }
  75. check_prerequisites()
  76. {
  77. if ! command -v ip &>/dev/null; then
  78. echo "SKIP: ip tool not found"
  79. exit "${ksft_skip}"
  80. fi
  81. if ! command -v ping &>/dev/null; then
  82. echo "SKIP: ping not found"
  83. exit "${ksft_skip}"
  84. fi
  85. if ! command -v sysctl &>/dev/null; then
  86. echo "SKIP: sysctl not found"
  87. exit "${ksft_skip}"
  88. fi
  89. if ! command -v taskset &>/dev/null; then
  90. echo "SKIP: taskset not found"
  91. exit "${ksft_skip}"
  92. fi
  93. }
  94. setup()
  95. {
  96. setup_ns NS_SRC NS_RTR NS_DST
  97. ip link add veth-s0 netns "${NS_SRC}" type veth \
  98. peer name veth-r0 netns "${NS_RTR}"
  99. ip link add veth-r1 netns "${NS_RTR}" type veth \
  100. peer name veth-d0 netns "${NS_DST}"
  101. ip -n "${NS_SRC}" link set veth-s0 address "${SRC_MAC}"
  102. ip -n "${NS_RTR}" link set veth-r0 address "${RTR_R0_MAC}"
  103. ip -n "${NS_RTR}" link set veth-r1 address "${RTR_R1_MAC}"
  104. ip -n "${NS_DST}" link set veth-d0 address "${DST_MAC}"
  105. # ns_src
  106. ip -n "${NS_SRC}" link set veth-s0 up
  107. ip -n "${NS_SRC}" addr add fd00::1/64 dev veth-s0 nodad
  108. ip -n "${NS_SRC}" -6 route add "${DEST}"/128 via fd00::2
  109. # ns_router
  110. ip -n "${NS_RTR}" link set veth-r0 up
  111. ip -n "${NS_RTR}" addr add fd00::2/64 dev veth-r0 nodad
  112. ip -n "${NS_RTR}" link set veth-r1 up
  113. ip -n "${NS_RTR}" addr add fd01::1/64 dev veth-r1 nodad
  114. ip netns exec "${NS_RTR}" sysctl -qw net.ipv6.conf.all.forwarding=1
  115. ip -n "${NS_RTR}" -6 route add "${DEST}"/128 \
  116. encap seg6 mode encap segs "${SID}" dev veth-r0
  117. ip -n "${NS_RTR}" -6 route add "${SID}"/128 table 100 \
  118. via fd01::2 dev veth-r1
  119. ip -n "${NS_RTR}" -6 route add blackhole "${SID}"/128
  120. ip -n "${NS_RTR}" -6 rule add iif veth-r0 lookup 100
  121. # ns_dst
  122. ip -n "${NS_DST}" link set veth-d0 up
  123. ip -n "${NS_DST}" addr add fd01::2/64 dev veth-d0 nodad
  124. ip -n "${NS_DST}" addr add "${DEST}"/128 dev lo nodad
  125. ip -n "${NS_DST}" -6 route add "${SID}"/128 \
  126. encap seg6local action End.DT6 table 255 dev veth-d0
  127. ip -n "${NS_DST}" -6 route add fd00::/64 via fd01::1
  128. # static neighbors
  129. ip -n "${NS_SRC}" -6 neigh add fd00::2 dev veth-s0 \
  130. lladdr "${RTR_R0_MAC}" nud permanent
  131. ip -n "${NS_RTR}" -6 neigh add fd00::1 dev veth-r0 \
  132. lladdr "${SRC_MAC}" nud permanent
  133. ip -n "${NS_RTR}" -6 neigh add fd01::2 dev veth-r1 \
  134. lladdr "${DST_MAC}" nud permanent
  135. ip -n "${NS_DST}" -6 neigh add fd01::1 dev veth-d0 \
  136. lladdr "${RTR_R1_MAC}" nud permanent
  137. }
  138. test_cache_isolation()
  139. {
  140. RET=0
  141. # local ping with empty cache: must fail (SID is blackholed)
  142. if ip netns exec "${NS_RTR}" taskset -c 0 \
  143. ping -c 1 -W 2 "${DEST}" &>/dev/null; then
  144. echo "SKIP: local ping succeeded, topology broken"
  145. exit "${ksft_skip}"
  146. fi
  147. # forward from ns_src to populate the input cache
  148. if ! ip netns exec "${NS_SRC}" taskset -c 0 \
  149. ping -c 1 -W 2 "${DEST}" &>/dev/null; then
  150. echo "SKIP: forwarded ping failed, topology broken"
  151. exit "${ksft_skip}"
  152. fi
  153. # local ping again: must still fail; if the output path reuses
  154. # the input cache, it bypasses the blackhole and the ping succeeds
  155. if ip netns exec "${NS_RTR}" taskset -c 0 \
  156. ping -c 1 -W 2 "${DEST}" &>/dev/null; then
  157. echo "FAIL: output path used dst cached by input path"
  158. RET="${ksft_fail}"
  159. else
  160. echo "PASS: output path dst_cache is independent"
  161. fi
  162. return "${RET}"
  163. }
  164. if [ "$(id -u)" -ne 0 ]; then
  165. echo "SKIP: Need root privileges"
  166. exit "${ksft_skip}"
  167. fi
  168. trap cleanup EXIT
  169. check_prerequisites
  170. setup
  171. test_cache_isolation
  172. exit "${RET}"