1#!/bin/bash 2# SPDX-License-Identifier: GPL-2.0 3 4# +--------------------+ +----------------------+ 5# | H1 (vrf) | | H2 (vrf) | 6# | + $h1 | | + $h2 | 7# | | 192.0.2.1/28 | | | 192.0.2.2/28 | 8# +----|---------------+ +--|-------------------+ 9# | | 10# +----|--------------------------------------------------|-------------------+ 11# | SW | | | 12# | +--|--------------------------------------------------|-----------------+ | 13# | | + $swp1 BR1 (802.1d) + $swp2 | | 14# | | | | 15# | | + vx1 (vxlan) | | 16# | | local 192.0.2.17 | | 17# | | remote 192.0.2.34 192.0.2.50 | | 18# | | id 1000 dstport $VXPORT | | 19# | +-----------------------------------------------------------------------+ | 20# | | 21# | 192.0.2.32/28 via 192.0.2.18 | 22# | 192.0.2.48/28 via 192.0.2.18 | 23# | | 24# | + $rp1 | 25# | | 192.0.2.17/28 | 26# +----|----------------------------------------------------------------------+ 27# | 28# +----|--------------------------------------------------------+ 29# | | VRP2 (vrf) | 30# | + $rp2 | 31# | 192.0.2.18/28 | 32# | | (maybe) HW 33# ============================================================================= 34# | | (likely) SW 35# | + v1 (veth) + v3 (veth) | 36# | | 192.0.2.33/28 | 192.0.2.49/28 | 37# +----|---------------------------------------|----------------+ 38# | | 39# +----|------------------------------+ +----|------------------------------+ 40# | + v2 (veth) NS1 (netns) | | + v4 (veth) NS2 (netns) | 41# | 192.0.2.34/28 | | 192.0.2.50/28 | 42# | | | | 43# | 192.0.2.16/28 via 192.0.2.33 | | 192.0.2.16/28 via 192.0.2.49 | 44# | 192.0.2.50/32 via 192.0.2.33 | | 192.0.2.34/32 via 192.0.2.49 | 45# | | | | 46# | +-------------------------------+ | | +-------------------------------+ | 47# | | BR2 (802.1d) | | | | BR2 (802.1d) | | 48# | | + vx2 (vxlan) | | | | + vx2 (vxlan) | | 49# | | local 192.0.2.34 | | | | local 192.0.2.50 | | 50# | | remote 192.0.2.17 | | | | remote 192.0.2.17 | | 51# | | remote 192.0.2.50 | | | | remote 192.0.2.34 | | 52# | | id 1000 dstport $VXPORT | | | | id 1000 dstport $VXPORT | | 53# | | | | | | | | 54# | | + w1 (veth) | | | | + w1 (veth) | | 55# | +--|----------------------------+ | | +--|----------------------------+ | 56# | | | | | | 57# | +--|----------------------------+ | | +--|----------------------------+ | 58# | | | VW2 (vrf) | | | | | VW2 (vrf) | | 59# | | + w2 (veth) | | | | + w2 (veth) | | 60# | | 192.0.2.3/28 | | | | 192.0.2.4/28 | | 61# | +-------------------------------+ | | +-------------------------------+ | 62# +-----------------------------------+ +-----------------------------------+ 63 64: ${VXPORT:=4789} 65export VXPORT 66 67: ${ALL_TESTS:=" 68 ping_ipv4 69 test_flood 70 test_unicast 71 reapply_config 72 ping_ipv4 73 test_flood 74 test_unicast 75 "} 76 77NUM_NETIFS=6 78source lib.sh 79 80h1_create() 81{ 82 simple_if_init $h1 192.0.2.1/28 83 tc qdisc add dev $h1 clsact 84} 85 86h1_destroy() 87{ 88 tc qdisc del dev $h1 clsact 89 simple_if_fini $h1 192.0.2.1/28 90} 91 92h2_create() 93{ 94 simple_if_init $h2 192.0.2.2/28 95 tc qdisc add dev $h2 clsact 96} 97 98h2_destroy() 99{ 100 tc qdisc del dev $h2 clsact 101 simple_if_fini $h2 192.0.2.2/28 102} 103 104rp1_set_addr() 105{ 106 ip address add dev $rp1 192.0.2.17/28 107 108 ip route add 192.0.2.32/28 nexthop via 192.0.2.18 109 ip route add 192.0.2.48/28 nexthop via 192.0.2.18 110} 111 112rp1_unset_addr() 113{ 114 ip route del 192.0.2.48/28 nexthop via 192.0.2.18 115 ip route del 192.0.2.32/28 nexthop via 192.0.2.18 116 117 ip address del dev $rp1 192.0.2.17/28 118} 119 120switch_create() 121{ 122 ip link add name br1 type bridge vlan_filtering 0 mcast_snooping 0 123 # Make sure the bridge uses the MAC address of the local port and not 124 # that of the VxLAN's device. 125 ip link set dev br1 address $(mac_get $swp1) 126 ip link set dev br1 up 127 128 ip link set dev $rp1 up 129 rp1_set_addr 130 131 ip link add name vx1 type vxlan id 1000 \ 132 local 192.0.2.17 dstport "$VXPORT" \ 133 nolearning noudpcsum tos inherit ttl 100 134 ip link set dev vx1 up 135 136 ip link set dev vx1 master br1 137 ip link set dev $swp1 master br1 138 ip link set dev $swp1 up 139 140 ip link set dev $swp2 master br1 141 ip link set dev $swp2 up 142 143 bridge fdb append dev vx1 00:00:00:00:00:00 dst 192.0.2.34 self 144 bridge fdb append dev vx1 00:00:00:00:00:00 dst 192.0.2.50 self 145} 146 147switch_destroy() 148{ 149 rp1_unset_addr 150 ip link set dev $rp1 down 151 152 bridge fdb del dev vx1 00:00:00:00:00:00 dst 192.0.2.50 self 153 bridge fdb del dev vx1 00:00:00:00:00:00 dst 192.0.2.34 self 154 155 ip link set dev vx1 nomaster 156 ip link set dev vx1 down 157 ip link del dev vx1 158 159 ip link set dev $swp2 down 160 ip link set dev $swp2 nomaster 161 162 ip link set dev $swp1 down 163 ip link set dev $swp1 nomaster 164 165 ip link set dev br1 down 166 ip link del dev br1 167} 168 169vrp2_create() 170{ 171 simple_if_init $rp2 192.0.2.18/28 172 __simple_if_init v1 v$rp2 192.0.2.33/28 173 __simple_if_init v3 v$rp2 192.0.2.49/28 174 tc qdisc add dev v1 clsact 175} 176 177vrp2_destroy() 178{ 179 tc qdisc del dev v1 clsact 180 __simple_if_fini v3 192.0.2.49/28 181 __simple_if_fini v1 192.0.2.33/28 182 simple_if_fini $rp2 192.0.2.18/28 183} 184 185ns_init_common() 186{ 187 local in_if=$1; shift 188 local in_addr=$1; shift 189 local other_in_addr=$1; shift 190 local nh_addr=$1; shift 191 local host_addr=$1; shift 192 193 ip link set dev $in_if up 194 ip address add dev $in_if $in_addr/28 195 tc qdisc add dev $in_if clsact 196 197 ip link add name br2 type bridge vlan_filtering 0 198 ip link set dev br2 up 199 200 ip link add name w1 type veth peer name w2 201 202 ip link set dev w1 master br2 203 ip link set dev w1 up 204 205 ip link add name vx2 type vxlan id 1000 local $in_addr dstport "$VXPORT" 206 ip link set dev vx2 up 207 bridge fdb append dev vx2 00:00:00:00:00:00 dst 192.0.2.17 self 208 bridge fdb append dev vx2 00:00:00:00:00:00 dst $other_in_addr self 209 210 ip link set dev vx2 master br2 211 tc qdisc add dev vx2 clsact 212 213 simple_if_init w2 $host_addr/28 214 215 ip route add 192.0.2.16/28 nexthop via $nh_addr 216 ip route add $other_in_addr/32 nexthop via $nh_addr 217} 218export -f ns_init_common 219 220ns1_create() 221{ 222 ip netns add ns1 223 ip link set dev v2 netns ns1 224 in_ns ns1 \ 225 ns_init_common v2 192.0.2.34 192.0.2.50 192.0.2.33 192.0.2.3 226} 227 228ns1_destroy() 229{ 230 ip netns exec ns1 ip link set dev v2 netns 1 231 ip netns del ns1 232} 233 234ns2_create() 235{ 236 ip netns add ns2 237 ip link set dev v4 netns ns2 238 in_ns ns2 \ 239 ns_init_common v4 192.0.2.50 192.0.2.34 192.0.2.49 192.0.2.4 240} 241 242ns2_destroy() 243{ 244 ip netns exec ns2 ip link set dev v4 netns 1 245 ip netns del ns2 246} 247 248setup_prepare() 249{ 250 h1=${NETIFS[p1]} 251 swp1=${NETIFS[p2]} 252 253 swp2=${NETIFS[p3]} 254 h2=${NETIFS[p4]} 255 256 rp1=${NETIFS[p5]} 257 rp2=${NETIFS[p6]} 258 259 vrf_prepare 260 forwarding_enable 261 262 h1_create 263 h2_create 264 switch_create 265 266 ip link add name v1 type veth peer name v2 267 ip link add name v3 type veth peer name v4 268 vrp2_create 269 ns1_create 270 ns2_create 271 272 r1_mac=$(in_ns ns1 mac_get w2) 273 r2_mac=$(in_ns ns2 mac_get w2) 274 h2_mac=$(mac_get $h2) 275} 276 277cleanup() 278{ 279 pre_cleanup 280 281 ns2_destroy 282 ns1_destroy 283 vrp2_destroy 284 ip link del dev v3 285 ip link del dev v1 286 287 switch_destroy 288 h2_destroy 289 h1_destroy 290 291 forwarding_restore 292 vrf_cleanup 293} 294 295# For the first round of tests, vx1 is the first device to get attached to the 296# bridge, and that at the point that the local IP is already configured. Try the 297# other scenario of attaching the device to an already-offloaded bridge, and 298# only then attach the local IP. 299reapply_config() 300{ 301 echo "Reapplying configuration" 302 303 bridge fdb del dev vx1 00:00:00:00:00:00 dst 192.0.2.50 self 304 bridge fdb del dev vx1 00:00:00:00:00:00 dst 192.0.2.34 self 305 rp1_unset_addr 306 ip link set dev vx1 nomaster 307 sleep 5 308 309 ip link set dev vx1 master br1 310 bridge fdb append dev vx1 00:00:00:00:00:00 dst 192.0.2.34 self 311 bridge fdb append dev vx1 00:00:00:00:00:00 dst 192.0.2.50 self 312 sleep 1 313 rp1_set_addr 314 sleep 5 315} 316 317ping_ipv4() 318{ 319 ping_test $h1 192.0.2.2 ": local->local" 320 ping_test $h1 192.0.2.3 ": local->remote 1" 321 ping_test $h1 192.0.2.4 ": local->remote 2" 322} 323 324maybe_in_ns() 325{ 326 echo ${1:+in_ns} $1 327} 328 329__flood_counter_add_del() 330{ 331 local add_del=$1; shift 332 local dev=$1; shift 333 local ns=$1; shift 334 335 # Putting the ICMP capture both to HW and to SW will end up 336 # double-counting the packets that are trapped to slow path, such as for 337 # the unicast test. Adding either skip_hw or skip_sw fixes this problem, 338 # but with skip_hw, the flooded packets are not counted at all, because 339 # those are dropped due to MAC address mismatch; and skip_sw is a no-go 340 # for veth-based topologies. 341 # 342 # So try to install with skip_sw and fall back to skip_sw if that fails. 343 344 $(maybe_in_ns $ns) __icmp_capture_add_del \ 345 $add_del 100 "" $dev skip_sw 2>/dev/null || \ 346 $(maybe_in_ns $ns) __icmp_capture_add_del \ 347 $add_del 100 "" $dev skip_hw 348} 349 350flood_counter_install() 351{ 352 __flood_counter_add_del add "$@" 353} 354 355flood_counter_uninstall() 356{ 357 __flood_counter_add_del del "$@" 358} 359 360flood_fetch_stat() 361{ 362 local dev=$1; shift 363 local ns=$1; shift 364 365 $(maybe_in_ns $ns) tc_rule_stats_get $dev 100 ingress 366} 367 368flood_fetch_stats() 369{ 370 local counters=("${@}") 371 local counter 372 373 for counter in "${counters[@]}"; do 374 flood_fetch_stat $counter 375 done 376} 377 378vxlan_flood_test() 379{ 380 local mac=$1; shift 381 local dst=$1; shift 382 local -a expects=("${@}") 383 384 local -a counters=($h2 "vx2 ns1" "vx2 ns2") 385 local counter 386 local key 387 388 for counter in "${counters[@]}"; do 389 flood_counter_install $counter 390 done 391 392 local -a t0s=($(flood_fetch_stats "${counters[@]}")) 393 $MZ $h1 -c 10 -d 100msec -p 64 -b $mac -B $dst -t icmp -q 394 sleep 1 395 local -a t1s=($(flood_fetch_stats "${counters[@]}")) 396 397 for key in ${!t0s[@]}; do 398 local delta=$((t1s[$key] - t0s[$key])) 399 local expect=${expects[$key]} 400 401 ((expect == delta)) 402 check_err $? "${counters[$key]}: Expected to capture $expect packets, got $delta." 403 done 404 405 for counter in "${counters[@]}"; do 406 flood_counter_uninstall $counter 407 done 408} 409 410__test_flood() 411{ 412 local mac=$1; shift 413 local dst=$1; shift 414 local what=$1; shift 415 416 RET=0 417 418 vxlan_flood_test $mac $dst 10 10 10 419 420 log_test "VXLAN: $what" 421} 422 423test_flood() 424{ 425 __test_flood de:ad:be:ef:13:37 192.0.2.100 "flood" 426} 427 428vxlan_fdb_add_del() 429{ 430 local add_del=$1; shift 431 local mac=$1; shift 432 local dev=$1; shift 433 local dst=$1; shift 434 435 bridge fdb $add_del dev $dev $mac self static permanent \ 436 ${dst:+dst} $dst 2>/dev/null 437 bridge fdb $add_del dev $dev $mac master static 2>/dev/null 438} 439 440__test_unicast() 441{ 442 local mac=$1; shift 443 local dst=$1; shift 444 local hit_idx=$1; shift 445 local what=$1; shift 446 447 RET=0 448 449 local -a expects=(0 0 0) 450 expects[$hit_idx]=10 451 452 vxlan_flood_test $mac $dst "${expects[@]}" 453 454 log_test "VXLAN: $what" 455} 456 457test_unicast() 458{ 459 local -a targets=("$h2_mac $h2" 460 "$r1_mac vx1 192.0.2.34" 461 "$r2_mac vx1 192.0.2.50") 462 local target 463 464 for target in "${targets[@]}"; do 465 vxlan_fdb_add_del add $target 466 done 467 468 __test_unicast $h2_mac 192.0.2.2 0 "local MAC unicast" 469 __test_unicast $r1_mac 192.0.2.3 1 "remote MAC 1 unicast" 470 __test_unicast $r2_mac 192.0.2.4 2 "remote MAC 2 unicast" 471 472 for target in "${targets[@]}"; do 473 vxlan_fdb_add_del del $target 474 done 475} 476 477test_all() 478{ 479 echo "Running tests with UDP port $VXPORT" 480 tests_run 481} 482 483trap cleanup EXIT 484 485setup_prepare 486setup_wait 487test_all 488 489exit $EXIT_STATUS 490