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