fib_offload.sh 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. #!/bin/bash
  2. # SPDX-License-Identifier: GPL-2.0
  3. #
  4. # Test unicast FIB offload indication.
  5. lib_dir=$(dirname $0)/../../../net/forwarding
  6. ALL_TESTS="
  7. ipv6_route_add
  8. ipv6_route_replace
  9. ipv6_route_nexthop_group_share
  10. ipv6_route_rate
  11. "
  12. NUM_NETIFS=4
  13. source $lib_dir/lib.sh
  14. source $lib_dir/devlink_lib.sh
  15. tor1_create()
  16. {
  17. simple_if_init $tor1_p1 2001:db8:1::2/128 2001:db8:1::3/128
  18. }
  19. tor1_destroy()
  20. {
  21. simple_if_fini $tor1_p1 2001:db8:1::2/128 2001:db8:1::3/128
  22. }
  23. tor2_create()
  24. {
  25. simple_if_init $tor2_p1 2001:db8:2::2/128 2001:db8:2::3/128
  26. }
  27. tor2_destroy()
  28. {
  29. simple_if_fini $tor2_p1 2001:db8:2::2/128 2001:db8:2::3/128
  30. }
  31. spine_create()
  32. {
  33. ip link set dev $spine_p1 up
  34. ip link set dev $spine_p2 up
  35. __addr_add_del $spine_p1 add 2001:db8:1::1/64
  36. __addr_add_del $spine_p2 add 2001:db8:2::1/64
  37. }
  38. spine_destroy()
  39. {
  40. __addr_add_del $spine_p2 del 2001:db8:2::1/64
  41. __addr_add_del $spine_p1 del 2001:db8:1::1/64
  42. ip link set dev $spine_p2 down
  43. ip link set dev $spine_p1 down
  44. }
  45. ipv6_offload_check()
  46. {
  47. local pfx="$1"; shift
  48. local expected_num=$1; shift
  49. local num
  50. # Try to avoid races with route offload
  51. sleep .1
  52. num=$(ip -6 route show match ${pfx} | grep "offload" | wc -l)
  53. if [ $num -eq $expected_num ]; then
  54. return 0
  55. fi
  56. return 1
  57. }
  58. ipv6_route_add_prefix()
  59. {
  60. RET=0
  61. # Add a prefix route and check that it is offloaded.
  62. ip -6 route add 2001:db8:3::/64 dev $spine_p1 metric 100
  63. ipv6_offload_check "2001:db8:3::/64 dev $spine_p1 metric 100" 1
  64. check_err $? "prefix route not offloaded"
  65. # Append an identical prefix route with an higher metric and check that
  66. # offload indication did not change.
  67. ip -6 route append 2001:db8:3::/64 dev $spine_p1 metric 200
  68. ipv6_offload_check "2001:db8:3::/64 dev $spine_p1 metric 100" 1
  69. check_err $? "lowest metric not offloaded after append"
  70. ipv6_offload_check "2001:db8:3::/64 dev $spine_p1 metric 200" 0
  71. check_err $? "highest metric offloaded when should not"
  72. # Prepend an identical prefix route with lower metric and check that
  73. # it is offloaded and the others are not.
  74. ip -6 route append 2001:db8:3::/64 dev $spine_p1 metric 10
  75. ipv6_offload_check "2001:db8:3::/64 dev $spine_p1 metric 10" 1
  76. check_err $? "lowest metric not offloaded after prepend"
  77. ipv6_offload_check "2001:db8:3::/64 dev $spine_p1 metric 100" 0
  78. check_err $? "mid metric offloaded when should not"
  79. ipv6_offload_check "2001:db8:3::/64 dev $spine_p1 metric 200" 0
  80. check_err $? "highest metric offloaded when should not"
  81. # Delete the routes and add the same route with a different nexthop
  82. # device. Check that it is offloaded.
  83. ip -6 route flush 2001:db8:3::/64 dev $spine_p1
  84. ip -6 route add 2001:db8:3::/64 dev $spine_p2
  85. ipv6_offload_check "2001:db8:3::/64 dev $spine_p2" 1
  86. log_test "IPv6 prefix route add"
  87. ip -6 route flush 2001:db8:3::/64
  88. }
  89. ipv6_route_add_mpath()
  90. {
  91. RET=0
  92. # Add a multipath route and check that it is offloaded.
  93. ip -6 route add 2001:db8:3::/64 metric 100 \
  94. nexthop via 2001:db8:1::2 dev $spine_p1 \
  95. nexthop via 2001:db8:2::2 dev $spine_p2
  96. ipv6_offload_check "2001:db8:3::/64 metric 100" 2
  97. check_err $? "multipath route not offloaded when should"
  98. # Append another nexthop and check that it is offloaded as well.
  99. ip -6 route append 2001:db8:3::/64 metric 100 \
  100. nexthop via 2001:db8:1::3 dev $spine_p1
  101. ipv6_offload_check "2001:db8:3::/64 metric 100" 3
  102. check_err $? "appended nexthop not offloaded when should"
  103. # Mimic route replace by removing the route and adding it back with
  104. # only two nexthops.
  105. ip -6 route del 2001:db8:3::/64
  106. ip -6 route add 2001:db8:3::/64 metric 100 \
  107. nexthop via 2001:db8:1::2 dev $spine_p1 \
  108. nexthop via 2001:db8:2::2 dev $spine_p2
  109. ipv6_offload_check "2001:db8:3::/64 metric 100" 2
  110. check_err $? "multipath route not offloaded after delete & add"
  111. # Append a nexthop with an higher metric and check that the offload
  112. # indication did not change.
  113. ip -6 route append 2001:db8:3::/64 metric 200 \
  114. nexthop via 2001:db8:1::3 dev $spine_p1
  115. ipv6_offload_check "2001:db8:3::/64 metric 100" 2
  116. check_err $? "lowest metric not offloaded after append"
  117. ipv6_offload_check "2001:db8:3::/64 metric 200" 0
  118. check_err $? "highest metric offloaded when should not"
  119. # Prepend a nexthop with a lower metric and check that it is offloaded
  120. # and the others are not.
  121. ip -6 route append 2001:db8:3::/64 metric 10 \
  122. nexthop via 2001:db8:1::3 dev $spine_p1
  123. ipv6_offload_check "2001:db8:3::/64 metric 10" 1
  124. check_err $? "lowest metric not offloaded after prepend"
  125. ipv6_offload_check "2001:db8:3::/64 metric 100" 0
  126. check_err $? "mid metric offloaded when should not"
  127. ipv6_offload_check "2001:db8:3::/64 metric 200" 0
  128. check_err $? "highest metric offloaded when should not"
  129. log_test "IPv6 multipath route add"
  130. ip -6 route flush 2001:db8:3::/64
  131. }
  132. ipv6_route_add()
  133. {
  134. ipv6_route_add_prefix
  135. ipv6_route_add_mpath
  136. }
  137. ipv6_route_replace()
  138. {
  139. RET=0
  140. # Replace prefix route with prefix route.
  141. ip -6 route add 2001:db8:3::/64 metric 100 dev $spine_p1
  142. ipv6_offload_check "2001:db8:3::/64 metric 100" 1
  143. check_err $? "prefix route not offloaded when should"
  144. ip -6 route replace 2001:db8:3::/64 metric 100 dev $spine_p2
  145. ipv6_offload_check "2001:db8:3::/64 metric 100" 1
  146. check_err $? "prefix route not offloaded after replace"
  147. # Replace prefix route with multipath route.
  148. ip -6 route replace 2001:db8:3::/64 metric 100 \
  149. nexthop via 2001:db8:1::2 dev $spine_p1 \
  150. nexthop via 2001:db8:2::2 dev $spine_p2
  151. ipv6_offload_check "2001:db8:3::/64 metric 100" 2
  152. check_err $? "multipath route not offloaded after replace"
  153. # Replace multipath route with prefix route. A prefix route cannot
  154. # replace a multipath route, so it is appended.
  155. ip -6 route replace 2001:db8:3::/64 metric 100 dev $spine_p1
  156. ipv6_offload_check "2001:db8:3::/64 metric 100 dev $spine_p1" 0
  157. check_err $? "prefix route offloaded after 'replacing' multipath route"
  158. ipv6_offload_check "2001:db8:3::/64 metric 100" 2
  159. check_err $? "multipath route not offloaded after being 'replaced' by prefix route"
  160. # Replace multipath route with multipath route.
  161. ip -6 route replace 2001:db8:3::/64 metric 100 \
  162. nexthop via 2001:db8:1::3 dev $spine_p1 \
  163. nexthop via 2001:db8:2::3 dev $spine_p2
  164. ipv6_offload_check "2001:db8:3::/64 metric 100" 2
  165. check_err $? "multipath route not offloaded after replacing multipath route"
  166. # Replace a non-existing multipath route with a multipath route and
  167. # check that it is appended and not offloaded.
  168. ip -6 route replace 2001:db8:3::/64 metric 200 \
  169. nexthop via 2001:db8:1::3 dev $spine_p1 \
  170. nexthop via 2001:db8:2::3 dev $spine_p2
  171. ipv6_offload_check "2001:db8:3::/64 metric 100" 2
  172. check_err $? "multipath route not offloaded after non-existing route was 'replaced'"
  173. ipv6_offload_check "2001:db8:3::/64 metric 200" 0
  174. check_err $? "multipath route offloaded after 'replacing' non-existing route"
  175. log_test "IPv6 route replace"
  176. ip -6 route flush 2001:db8:3::/64
  177. }
  178. ipv6_route_nexthop_group_share()
  179. {
  180. RET=0
  181. # The driver consolidates identical nexthop groups in order to reduce
  182. # the resource usage in its adjacency table. Check that the deletion
  183. # of one multipath route using the group does not affect the other.
  184. ip -6 route add 2001:db8:3::/64 \
  185. nexthop via 2001:db8:1::2 dev $spine_p1 \
  186. nexthop via 2001:db8:2::2 dev $spine_p2
  187. ip -6 route add 2001:db8:4::/64 \
  188. nexthop via 2001:db8:1::2 dev $spine_p1 \
  189. nexthop via 2001:db8:2::2 dev $spine_p2
  190. ipv6_offload_check "2001:db8:3::/64" 2
  191. check_err $? "multipath route not offloaded when should"
  192. ipv6_offload_check "2001:db8:4::/64" 2
  193. check_err $? "multipath route not offloaded when should"
  194. ip -6 route del 2001:db8:3::/64
  195. ipv6_offload_check "2001:db8:4::/64" 2
  196. check_err $? "multipath route not offloaded after deletion of route sharing the nexthop group"
  197. # Check that after unsharing a nexthop group the routes are still
  198. # marked as offloaded.
  199. ip -6 route add 2001:db8:3::/64 \
  200. nexthop via 2001:db8:1::2 dev $spine_p1 \
  201. nexthop via 2001:db8:2::2 dev $spine_p2
  202. ip -6 route del 2001:db8:4::/64 \
  203. nexthop via 2001:db8:1::2 dev $spine_p1
  204. ipv6_offload_check "2001:db8:4::/64" 1
  205. check_err $? "singlepath route not offloaded after unsharing the nexthop group"
  206. ipv6_offload_check "2001:db8:3::/64" 2
  207. check_err $? "multipath route not offloaded after unsharing the nexthop group"
  208. log_test "IPv6 nexthop group sharing"
  209. ip -6 route flush 2001:db8:3::/64
  210. ip -6 route flush 2001:db8:4::/64
  211. }
  212. ipv6_route_rate()
  213. {
  214. local batch_dir=$(mktemp -d)
  215. local num_rts=$((40 * 1024))
  216. local num_nhs=16
  217. local total
  218. local start
  219. local diff
  220. local end
  221. local nhs
  222. local i
  223. RET=0
  224. # Prepare 40K /64 multipath routes with 16 nexthops each and check how
  225. # long it takes to add them. A limit of 60 seconds is set. It is much
  226. # higher than insertion should take and meant to flag a serious
  227. # regression.
  228. total=$((nums_nhs * num_rts))
  229. for i in $(seq 1 $num_nhs); do
  230. ip -6 address add 2001:db8:1::10:$i/128 dev $tor1_p1
  231. nexthops+=" nexthop via 2001:db8:1::10:$i dev $spine_p1"
  232. done
  233. for i in $(seq 1 $num_rts); do
  234. echo "route add 2001:db8:8:$(printf "%x" $i)::/64$nexthops" \
  235. >> $batch_dir/add.batch
  236. echo "route del 2001:db8:8:$(printf "%x" $i)::/64$nexthops" \
  237. >> $batch_dir/del.batch
  238. done
  239. start=$(date +%s.%N)
  240. ip -batch $batch_dir/add.batch
  241. count=$(ip -6 route show | grep offload | wc -l)
  242. while [ $count -lt $total ]; do
  243. sleep .01
  244. count=$(ip -6 route show | grep offload | wc -l)
  245. done
  246. end=$(date +%s.%N)
  247. diff=$(echo "$end - $start" | bc -l)
  248. test "$(echo "$diff > 60" | bc -l)" -eq 0
  249. check_err $? "route insertion took too long"
  250. log_info "inserted $num_rts routes in $diff seconds"
  251. log_test "IPv6 routes insertion rate"
  252. ip -batch $batch_dir/del.batch
  253. for i in $(seq 1 $num_nhs); do
  254. ip -6 address del 2001:db8:1::10:$i/128 dev $tor1_p1
  255. done
  256. rm -rf $batch_dir
  257. }
  258. setup_prepare()
  259. {
  260. spine_p1=${NETIFS[p1]}
  261. tor1_p1=${NETIFS[p2]}
  262. spine_p2=${NETIFS[p3]}
  263. tor2_p1=${NETIFS[p4]}
  264. vrf_prepare
  265. forwarding_enable
  266. tor1_create
  267. tor2_create
  268. spine_create
  269. }
  270. cleanup()
  271. {
  272. pre_cleanup
  273. spine_destroy
  274. tor2_destroy
  275. tor1_destroy
  276. forwarding_restore
  277. vrf_cleanup
  278. }
  279. trap cleanup EXIT
  280. setup_prepare
  281. setup_wait
  282. tests_run
  283. exit $EXIT_STATUS