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 test_ttl 72 test_tos 73 test_ecn_encap 74 reapply_config 75 ping_ipv4 76 test_flood 77 test_unicast 78 "} 79 80NUM_NETIFS=6 81source lib.sh 82 83h1_create() 84{ 85 simple_if_init $h1 192.0.2.1/28 86 tc qdisc add dev $h1 clsact 87} 88 89h1_destroy() 90{ 91 tc qdisc del dev $h1 clsact 92 simple_if_fini $h1 192.0.2.1/28 93} 94 95h2_create() 96{ 97 simple_if_init $h2 192.0.2.2/28 98 tc qdisc add dev $h2 clsact 99} 100 101h2_destroy() 102{ 103 tc qdisc del dev $h2 clsact 104 simple_if_fini $h2 192.0.2.2/28 105} 106 107rp1_set_addr() 108{ 109 ip address add dev $rp1 192.0.2.17/28 110 111 ip route add 192.0.2.32/28 nexthop via 192.0.2.18 112 ip route add 192.0.2.48/28 nexthop via 192.0.2.18 113} 114 115rp1_unset_addr() 116{ 117 ip route del 192.0.2.48/28 nexthop via 192.0.2.18 118 ip route del 192.0.2.32/28 nexthop via 192.0.2.18 119 120 ip address del dev $rp1 192.0.2.17/28 121} 122 123switch_create() 124{ 125 ip link add name br1 type bridge vlan_filtering 0 mcast_snooping 0 126 # Make sure the bridge uses the MAC address of the local port and not 127 # that of the VxLAN's device. 128 ip link set dev br1 address $(mac_get $swp1) 129 ip link set dev br1 up 130 131 ip link set dev $rp1 up 132 rp1_set_addr 133 134 ip link add name vx1 type vxlan id 1000 \ 135 local 192.0.2.17 dstport "$VXPORT" \ 136 nolearning noudpcsum tos inherit ttl 100 137 ip link set dev vx1 up 138 139 ip link set dev vx1 master br1 140 ip link set dev $swp1 master br1 141 ip link set dev $swp1 up 142 143 ip link set dev $swp2 master br1 144 ip link set dev $swp2 up 145 146 bridge fdb append dev vx1 00:00:00:00:00:00 dst 192.0.2.34 self 147 bridge fdb append dev vx1 00:00:00:00:00:00 dst 192.0.2.50 self 148} 149 150switch_destroy() 151{ 152 rp1_unset_addr 153 ip link set dev $rp1 down 154 155 bridge fdb del dev vx1 00:00:00:00:00:00 dst 192.0.2.50 self 156 bridge fdb del dev vx1 00:00:00:00:00:00 dst 192.0.2.34 self 157 158 ip link set dev vx1 nomaster 159 ip link set dev vx1 down 160 ip link del dev vx1 161 162 ip link set dev $swp2 down 163 ip link set dev $swp2 nomaster 164 165 ip link set dev $swp1 down 166 ip link set dev $swp1 nomaster 167 168 ip link set dev br1 down 169 ip link del dev br1 170} 171 172vrp2_create() 173{ 174 simple_if_init $rp2 192.0.2.18/28 175 __simple_if_init v1 v$rp2 192.0.2.33/28 176 __simple_if_init v3 v$rp2 192.0.2.49/28 177 tc qdisc add dev v1 clsact 178} 179 180vrp2_destroy() 181{ 182 tc qdisc del dev v1 clsact 183 __simple_if_fini v3 192.0.2.49/28 184 __simple_if_fini v1 192.0.2.33/28 185 simple_if_fini $rp2 192.0.2.18/28 186} 187 188ns_init_common() 189{ 190 local in_if=$1; shift 191 local in_addr=$1; shift 192 local other_in_addr=$1; shift 193 local nh_addr=$1; shift 194 local host_addr=$1; shift 195 196 ip link set dev $in_if up 197 ip address add dev $in_if $in_addr/28 198 tc qdisc add dev $in_if clsact 199 200 ip link add name br2 type bridge vlan_filtering 0 201 ip link set dev br2 up 202 203 ip link add name w1 type veth peer name w2 204 205 ip link set dev w1 master br2 206 ip link set dev w1 up 207 208 ip link add name vx2 type vxlan id 1000 local $in_addr dstport "$VXPORT" 209 ip link set dev vx2 up 210 bridge fdb append dev vx2 00:00:00:00:00:00 dst 192.0.2.17 self 211 bridge fdb append dev vx2 00:00:00:00:00:00 dst $other_in_addr self 212 213 ip link set dev vx2 master br2 214 tc qdisc add dev vx2 clsact 215 216 simple_if_init w2 $host_addr/28 217 218 ip route add 192.0.2.16/28 nexthop via $nh_addr 219 ip route add $other_in_addr/32 nexthop via $nh_addr 220} 221export -f ns_init_common 222 223ns1_create() 224{ 225 ip netns add ns1 226 ip link set dev v2 netns ns1 227 in_ns ns1 \ 228 ns_init_common v2 192.0.2.34 192.0.2.50 192.0.2.33 192.0.2.3 229} 230 231ns1_destroy() 232{ 233 ip netns exec ns1 ip link set dev v2 netns 1 234 ip netns del ns1 235} 236 237ns2_create() 238{ 239 ip netns add ns2 240 ip link set dev v4 netns ns2 241 in_ns ns2 \ 242 ns_init_common v4 192.0.2.50 192.0.2.34 192.0.2.49 192.0.2.4 243} 244 245ns2_destroy() 246{ 247 ip netns exec ns2 ip link set dev v4 netns 1 248 ip netns del ns2 249} 250 251setup_prepare() 252{ 253 h1=${NETIFS[p1]} 254 swp1=${NETIFS[p2]} 255 256 swp2=${NETIFS[p3]} 257 h2=${NETIFS[p4]} 258 259 rp1=${NETIFS[p5]} 260 rp2=${NETIFS[p6]} 261 262 vrf_prepare 263 forwarding_enable 264 265 h1_create 266 h2_create 267 switch_create 268 269 ip link add name v1 type veth peer name v2 270 ip link add name v3 type veth peer name v4 271 vrp2_create 272 ns1_create 273 ns2_create 274 275 r1_mac=$(in_ns ns1 mac_get w2) 276 r2_mac=$(in_ns ns2 mac_get w2) 277 h2_mac=$(mac_get $h2) 278} 279 280cleanup() 281{ 282 pre_cleanup 283 284 ns2_destroy 285 ns1_destroy 286 vrp2_destroy 287 ip link del dev v3 288 ip link del dev v1 289 290 switch_destroy 291 h2_destroy 292 h1_destroy 293 294 forwarding_restore 295 vrf_cleanup 296} 297 298# For the first round of tests, vx1 is the first device to get attached to the 299# bridge, and that at the point that the local IP is already configured. Try the 300# other scenario of attaching the device to an already-offloaded bridge, and 301# only then attach the local IP. 302reapply_config() 303{ 304 echo "Reapplying configuration" 305 306 bridge fdb del dev vx1 00:00:00:00:00:00 dst 192.0.2.50 self 307 bridge fdb del dev vx1 00:00:00:00:00:00 dst 192.0.2.34 self 308 rp1_unset_addr 309 ip link set dev vx1 nomaster 310 sleep 5 311 312 ip link set dev vx1 master br1 313 bridge fdb append dev vx1 00:00:00:00:00:00 dst 192.0.2.34 self 314 bridge fdb append dev vx1 00:00:00:00:00:00 dst 192.0.2.50 self 315 sleep 1 316 rp1_set_addr 317 sleep 5 318} 319 320ping_ipv4() 321{ 322 ping_test $h1 192.0.2.2 ": local->local" 323 ping_test $h1 192.0.2.3 ": local->remote 1" 324 ping_test $h1 192.0.2.4 ": local->remote 2" 325} 326 327maybe_in_ns() 328{ 329 echo ${1:+in_ns} $1 330} 331 332__flood_counter_add_del() 333{ 334 local add_del=$1; shift 335 local dev=$1; shift 336 local ns=$1; shift 337 338 # Putting the ICMP capture both to HW and to SW will end up 339 # double-counting the packets that are trapped to slow path, such as for 340 # the unicast test. Adding either skip_hw or skip_sw fixes this problem, 341 # but with skip_hw, the flooded packets are not counted at all, because 342 # those are dropped due to MAC address mismatch; and skip_sw is a no-go 343 # for veth-based topologies. 344 # 345 # So try to install with skip_sw and fall back to skip_sw if that fails. 346 347 $(maybe_in_ns $ns) __icmp_capture_add_del \ 348 $add_del 100 "" $dev skip_sw 2>/dev/null || \ 349 $(maybe_in_ns $ns) __icmp_capture_add_del \ 350 $add_del 100 "" $dev skip_hw 351} 352 353flood_counter_install() 354{ 355 __flood_counter_add_del add "$@" 356} 357 358flood_counter_uninstall() 359{ 360 __flood_counter_add_del del "$@" 361} 362 363flood_fetch_stat() 364{ 365 local dev=$1; shift 366 local ns=$1; shift 367 368 $(maybe_in_ns $ns) tc_rule_stats_get $dev 100 ingress 369} 370 371flood_fetch_stats() 372{ 373 local counters=("${@}") 374 local counter 375 376 for counter in "${counters[@]}"; do 377 flood_fetch_stat $counter 378 done 379} 380 381vxlan_flood_test() 382{ 383 local mac=$1; shift 384 local dst=$1; shift 385 local -a expects=("${@}") 386 387 local -a counters=($h2 "vx2 ns1" "vx2 ns2") 388 local counter 389 local key 390 391 for counter in "${counters[@]}"; do 392 flood_counter_install $counter 393 done 394 395 local -a t0s=($(flood_fetch_stats "${counters[@]}")) 396 $MZ $h1 -c 10 -d 100msec -p 64 -b $mac -B $dst -t icmp -q 397 sleep 1 398 local -a t1s=($(flood_fetch_stats "${counters[@]}")) 399 400 for key in ${!t0s[@]}; do 401 local delta=$((t1s[$key] - t0s[$key])) 402 local expect=${expects[$key]} 403 404 ((expect == delta)) 405 check_err $? "${counters[$key]}: Expected to capture $expect packets, got $delta." 406 done 407 408 for counter in "${counters[@]}"; do 409 flood_counter_uninstall $counter 410 done 411} 412 413__test_flood() 414{ 415 local mac=$1; shift 416 local dst=$1; shift 417 local what=$1; shift 418 419 RET=0 420 421 vxlan_flood_test $mac $dst 10 10 10 422 423 log_test "VXLAN: $what" 424} 425 426test_flood() 427{ 428 __test_flood de:ad:be:ef:13:37 192.0.2.100 "flood" 429} 430 431vxlan_fdb_add_del() 432{ 433 local add_del=$1; shift 434 local mac=$1; shift 435 local dev=$1; shift 436 local dst=$1; shift 437 438 bridge fdb $add_del dev $dev $mac self static permanent \ 439 ${dst:+dst} $dst 2>/dev/null 440 bridge fdb $add_del dev $dev $mac master static 2>/dev/null 441} 442 443__test_unicast() 444{ 445 local mac=$1; shift 446 local dst=$1; shift 447 local hit_idx=$1; shift 448 local what=$1; shift 449 450 RET=0 451 452 local -a expects=(0 0 0) 453 expects[$hit_idx]=10 454 455 vxlan_flood_test $mac $dst "${expects[@]}" 456 457 log_test "VXLAN: $what" 458} 459 460test_unicast() 461{ 462 local -a targets=("$h2_mac $h2" 463 "$r1_mac vx1 192.0.2.34" 464 "$r2_mac vx1 192.0.2.50") 465 local target 466 467 for target in "${targets[@]}"; do 468 vxlan_fdb_add_del add $target 469 done 470 471 __test_unicast $h2_mac 192.0.2.2 0 "local MAC unicast" 472 __test_unicast $r1_mac 192.0.2.3 1 "remote MAC 1 unicast" 473 __test_unicast $r2_mac 192.0.2.4 2 "remote MAC 2 unicast" 474 475 for target in "${targets[@]}"; do 476 vxlan_fdb_add_del del $target 477 done 478} 479 480vxlan_ping_test() 481{ 482 local ping_dev=$1; shift 483 local ping_dip=$1; shift 484 local ping_args=$1; shift 485 local capture_dev=$1; shift 486 local capture_dir=$1; shift 487 local capture_pref=$1; shift 488 local expect=$1; shift 489 490 local t0=$(tc_rule_stats_get $capture_dev $capture_pref $capture_dir) 491 ping_do $ping_dev $ping_dip "$ping_args" 492 local t1=$(tc_rule_stats_get $capture_dev $capture_pref $capture_dir) 493 local delta=$((t1 - t0)) 494 495 # Tolerate a couple stray extra packets. 496 ((expect <= delta && delta <= expect + 2)) 497 check_err $? "$capture_dev: Expected to capture $expect packets, got $delta." 498} 499 500test_ttl() 501{ 502 RET=0 503 504 tc filter add dev v1 egress pref 77 prot ip \ 505 flower ip_ttl 99 action pass 506 vxlan_ping_test $h1 192.0.2.3 "" v1 egress 77 10 507 tc filter del dev v1 egress pref 77 prot ip 508 509 log_test "VXLAN: envelope TTL" 510} 511 512test_tos() 513{ 514 RET=0 515 516 tc filter add dev v1 egress pref 77 prot ip \ 517 flower ip_tos 0x40 action pass 518 vxlan_ping_test $h1 192.0.2.3 "-Q 0x40" v1 egress 77 10 519 vxlan_ping_test $h1 192.0.2.3 "-Q 0x30" v1 egress 77 0 520 tc filter del dev v1 egress pref 77 prot ip 521 522 log_test "VXLAN: envelope TOS inheritance" 523} 524 525__test_ecn_encap() 526{ 527 local q=$1; shift 528 local tos=$1; shift 529 530 RET=0 531 532 tc filter add dev v1 egress pref 77 prot ip \ 533 flower ip_tos $tos action pass 534 sleep 1 535 vxlan_ping_test $h1 192.0.2.3 "-Q $q" v1 egress 77 10 536 tc filter del dev v1 egress pref 77 prot ip 537 538 log_test "VXLAN: ECN encap: $q->$tos" 539} 540 541test_ecn_encap() 542{ 543 # In accordance with INET_ECN_encapsulate() 544 __test_ecn_encap 0x00 0x00 545 __test_ecn_encap 0x01 0x01 546 __test_ecn_encap 0x02 0x02 547 __test_ecn_encap 0x03 0x02 548} 549 550test_all() 551{ 552 echo "Running tests with UDP port $VXPORT" 553 tests_run 554} 555 556trap cleanup EXIT 557 558setup_prepare 559setup_wait 560test_all 561 562exit $EXIT_STATUS 563