1#!/bin/bash 2# SPDX-License-Identifier: GPL-2.0 3# 4# Test devlink-trap L3 drops functionality over mlxsw. Each registered L3 drop 5# packet trap is tested to make sure it is triggered under the right 6# conditions. 7 8# +---------------------------------+ 9# | H1 (vrf) | 10# | + $h1 | 11# | | 192.0.2.1/24 | 12# | | 2001:db8:1::1/64 | 13# | | | 14# | | default via 192.0.2.2 | 15# | | default via 2001:db8:1::2 | 16# +----|----------------------------+ 17# | 18# +----|----------------------------------------------------------------------+ 19# | SW | | 20# | + $rp1 | 21# | 192.0.2.2/24 | 22# | 2001:db8:1::2/64 | 23# | | 24# | 2001:db8:2::2/64 | 25# | 198.51.100.2/24 | 26# | + $rp2 | 27# | | | 28# +----|----------------------------------------------------------------------+ 29# | 30# +----|----------------------------+ 31# | | default via 198.51.100.2 | 32# | | default via 2001:db8:2::2 | 33# | | | 34# | | 2001:db8:2::1/64 | 35# | | 198.51.100.1/24 | 36# | + $h2 | 37# | H2 (vrf) | 38# +---------------------------------+ 39 40lib_dir=$(dirname $0)/../../../net/forwarding 41 42ALL_TESTS=" 43 non_ip_test 44 uc_dip_over_mc_dmac_test 45 dip_is_loopback_test 46 sip_is_mc_test 47 sip_is_loopback_test 48 ip_header_corrupted_test 49 ipv4_sip_is_limited_bc_test 50 ipv6_mc_dip_reserved_scope_test 51 ipv6_mc_dip_interface_local_scope_test 52 blackhole_route_test 53 irif_disabled_test 54 erif_disabled_test 55 blackhole_nexthop_test 56" 57 58NUM_NETIFS=4 59source $lib_dir/lib.sh 60source $lib_dir/tc_common.sh 61source $lib_dir/devlink_lib.sh 62 63h1_create() 64{ 65 simple_if_init $h1 192.0.2.1/24 2001:db8:1::1/64 66 67 ip -4 route add default vrf v$h1 nexthop via 192.0.2.2 68 ip -6 route add default vrf v$h1 nexthop via 2001:db8:1::2 69} 70 71h1_destroy() 72{ 73 ip -6 route del default vrf v$h1 nexthop via 2001:db8:1::2 74 ip -4 route del default vrf v$h1 nexthop via 192.0.2.2 75 76 simple_if_fini $h1 192.0.2.1/24 2001:db8:1::1/64 77} 78 79h2_create() 80{ 81 simple_if_init $h2 $h2_ipv4/24 $h2_ipv6/64 82 83 ip -4 route add default vrf v$h2 nexthop via 198.51.100.2 84 ip -6 route add default vrf v$h2 nexthop via 2001:db8:2::2 85} 86 87h2_destroy() 88{ 89 ip -6 route del default vrf v$h2 nexthop via 2001:db8:2::2 90 ip -4 route del default vrf v$h2 nexthop via 198.51.100.2 91 92 simple_if_fini $h2 $h2_ipv4/24 $h2_ipv6/64 93} 94 95router_create() 96{ 97 ip link set dev $rp1 up 98 ip link set dev $rp2 up 99 100 tc qdisc add dev $rp2 clsact 101 102 __addr_add_del $rp1 add 192.0.2.2/24 2001:db8:1::2/64 103 __addr_add_del $rp2 add 198.51.100.2/24 2001:db8:2::2/64 104} 105 106router_destroy() 107{ 108 __addr_add_del $rp2 del 198.51.100.2/24 2001:db8:2::2/64 109 __addr_add_del $rp1 del 192.0.2.2/24 2001:db8:1::2/64 110 111 tc qdisc del dev $rp2 clsact 112} 113 114setup_prepare() 115{ 116 h1=${NETIFS[p1]} 117 rp1=${NETIFS[p2]} 118 119 rp2=${NETIFS[p3]} 120 h2=${NETIFS[p4]} 121 122 h1mac=$(mac_get $h1) 123 rp1mac=$(mac_get $rp1) 124 125 h1_ipv4=192.0.2.1 126 h2_ipv4=198.51.100.1 127 h1_ipv6=2001:db8:1::1 128 h2_ipv6=2001:db8:2::1 129 130 vrf_prepare 131 forwarding_enable 132 133 h1_create 134 h2_create 135 136 router_create 137} 138 139cleanup() 140{ 141 pre_cleanup 142 143 router_destroy 144 145 h2_destroy 146 h1_destroy 147 148 forwarding_restore 149 vrf_cleanup 150} 151 152ping_check() 153{ 154 trap_name=$1; shift 155 156 devlink_trap_action_set $trap_name "trap" 157 ping_do $h1 $h2_ipv4 158 check_err $? "Packets that should not be trapped were trapped" 159 devlink_trap_action_set $trap_name "drop" 160} 161 162non_ip_test() 163{ 164 local trap_name="non_ip" 165 local mz_pid 166 167 RET=0 168 169 ping_check $trap_name 170 171 tc filter add dev $rp2 egress protocol ip pref 1 handle 101 \ 172 flower dst_ip $h2_ipv4 action drop 173 174 # Generate non-IP packets to the router 175 $MZ $h1 -c 0 -p 100 -d 1msec -B $h2_ipv4 -q "$rp1mac $h1mac \ 176 00:00 de:ad:be:ef" & 177 mz_pid=$! 178 179 devlink_trap_drop_test $trap_name $rp2 101 180 181 log_test "Non IP" 182 183 devlink_trap_drop_cleanup $mz_pid $rp2 "ip" 1 101 184} 185 186__uc_dip_over_mc_dmac_test() 187{ 188 local desc=$1; shift 189 local proto=$1; shift 190 local dip=$1; shift 191 local flags=${1:-""}; shift 192 local trap_name="uc_dip_over_mc_dmac" 193 local dmac=01:02:03:04:05:06 194 local mz_pid 195 196 RET=0 197 198 ping_check $trap_name 199 200 tc filter add dev $rp2 egress protocol $proto pref 1 handle 101 \ 201 flower ip_proto udp src_port 54321 dst_port 12345 action drop 202 203 # Generate IP packets with a unicast IP and a multicast destination MAC 204 $MZ $h1 $flags -t udp "sp=54321,dp=12345" -c 0 -p 100 -b $dmac \ 205 -B $dip -d 1msec -q & 206 mz_pid=$! 207 208 devlink_trap_drop_test $trap_name $rp2 101 209 210 log_test "Unicast destination IP over multicast destination MAC: $desc" 211 212 devlink_trap_drop_cleanup $mz_pid $rp2 $proto 1 101 213} 214 215uc_dip_over_mc_dmac_test() 216{ 217 __uc_dip_over_mc_dmac_test "IPv4" "ip" $h2_ipv4 218 __uc_dip_over_mc_dmac_test "IPv6" "ipv6" $h2_ipv6 "-6" 219} 220 221__sip_is_loopback_test() 222{ 223 local desc=$1; shift 224 local proto=$1; shift 225 local sip=$1; shift 226 local dip=$1; shift 227 local flags=${1:-""}; shift 228 local trap_name="sip_is_loopback_address" 229 local mz_pid 230 231 RET=0 232 233 ping_check $trap_name 234 235 tc filter add dev $rp2 egress protocol $proto pref 1 handle 101 \ 236 flower src_ip $sip action drop 237 238 # Generate packets with loopback source IP 239 $MZ $h1 $flags -t udp "sp=54321,dp=12345" -c 0 -p 100 -A $sip \ 240 -b $rp1mac -B $dip -d 1msec -q & 241 mz_pid=$! 242 243 devlink_trap_drop_test $trap_name $rp2 101 244 245 log_test "Source IP is loopback address: $desc" 246 247 devlink_trap_drop_cleanup $mz_pid $rp2 $proto 1 101 248} 249 250sip_is_loopback_test() 251{ 252 __sip_is_loopback_test "IPv4" "ip" "127.0.0.0/8" $h2_ipv4 253 __sip_is_loopback_test "IPv6" "ipv6" "::1" $h2_ipv6 "-6" 254} 255 256__dip_is_loopback_test() 257{ 258 local desc=$1; shift 259 local proto=$1; shift 260 local dip=$1; shift 261 local flags=${1:-""}; shift 262 local trap_name="dip_is_loopback_address" 263 local mz_pid 264 265 RET=0 266 267 ping_check $trap_name 268 269 tc filter add dev $rp2 egress protocol $proto pref 1 handle 101 \ 270 flower dst_ip $dip action drop 271 272 # Generate packets with loopback destination IP 273 $MZ $h1 $flags -t udp "sp=54321,dp=12345" -c 0 -p 100 -b $rp1mac \ 274 -B $dip -d 1msec -q & 275 mz_pid=$! 276 277 devlink_trap_drop_test $trap_name $rp2 101 278 279 log_test "Destination IP is loopback address: $desc" 280 281 devlink_trap_drop_cleanup $mz_pid $rp2 $proto 1 101 282} 283 284dip_is_loopback_test() 285{ 286 __dip_is_loopback_test "IPv4" "ip" "127.0.0.0/8" 287 __dip_is_loopback_test "IPv6" "ipv6" "::1" "-6" 288} 289 290__sip_is_mc_test() 291{ 292 local desc=$1; shift 293 local proto=$1; shift 294 local sip=$1; shift 295 local dip=$1; shift 296 local flags=${1:-""}; shift 297 local trap_name="sip_is_mc" 298 local mz_pid 299 300 RET=0 301 302 ping_check $trap_name 303 304 tc filter add dev $rp2 egress protocol $proto pref 1 handle 101 \ 305 flower src_ip $sip action drop 306 307 # Generate packets with multicast source IP 308 $MZ $h1 $flags -t udp "sp=54321,dp=12345" -c 0 -p 100 -A $sip \ 309 -b $rp1mac -B $dip -d 1msec -q & 310 mz_pid=$! 311 312 devlink_trap_drop_test $trap_name $rp2 101 313 314 log_test "Source IP is multicast: $desc" 315 316 devlink_trap_drop_cleanup $mz_pid $rp2 $proto 1 101 317} 318 319sip_is_mc_test() 320{ 321 __sip_is_mc_test "IPv4" "ip" "239.1.1.1" $h2_ipv4 322 __sip_is_mc_test "IPv6" "ipv6" "FF02::2" $h2_ipv6 "-6" 323} 324 325ipv4_sip_is_limited_bc_test() 326{ 327 local trap_name="ipv4_sip_is_limited_bc" 328 local sip=255.255.255.255 329 local mz_pid 330 331 RET=0 332 333 ping_check $trap_name 334 335 tc filter add dev $rp2 egress protocol ip pref 1 handle 101 \ 336 flower src_ip $sip action drop 337 338 # Generate packets with limited broadcast source IP 339 $MZ $h1 -t udp "sp=54321,dp=12345" -c 0 -p 100 -A $sip -b $rp1mac \ 340 -B $h2_ipv4 -d 1msec -q & 341 mz_pid=$! 342 343 devlink_trap_drop_test $trap_name $rp2 101 344 345 log_test "IPv4 source IP is limited broadcast" 346 347 devlink_trap_drop_cleanup $mz_pid $rp2 "ip" 1 101 348} 349 350ipv4_payload_get() 351{ 352 local ipver=$1; shift 353 local ihl=$1; shift 354 local checksum=$1; shift 355 356 p=$(: 357 )"08:00:"$( : ETH type 358 )"$ipver"$( : IP version 359 )"$ihl:"$( : IHL 360 )"00:"$( : IP TOS 361 )"00:F4:"$( : IP total length 362 )"00:00:"$( : IP identification 363 )"20:00:"$( : IP flags + frag off 364 )"30:"$( : IP TTL 365 )"01:"$( : IP proto 366 )"$checksum:"$( : IP header csum 367 )"$h1_ipv4:"$( : IP saddr 368 )"$h2_ipv4:"$( : IP daddr 369 ) 370 echo $p 371} 372 373__ipv4_header_corrupted_test() 374{ 375 local desc=$1; shift 376 local ipver=$1; shift 377 local ihl=$1; shift 378 local checksum=$1; shift 379 local trap_name="ip_header_corrupted" 380 local payload 381 local mz_pid 382 383 RET=0 384 385 ping_check $trap_name 386 387 tc filter add dev $rp2 egress protocol ip pref 1 handle 101 \ 388 flower dst_ip $h2_ipv4 action drop 389 390 payload=$(ipv4_payload_get $ipver $ihl $checksum) 391 392 # Generate packets with corrupted IP header 393 $MZ $h1 -c 0 -d 1msec -a $h1mac -b $rp1mac -q p=$payload & 394 mz_pid=$! 395 396 devlink_trap_drop_test $trap_name $rp2 101 397 398 log_test "IP header corrupted: $desc: IPv4" 399 400 devlink_trap_drop_cleanup $mz_pid $rp2 "ip" 1 101 401} 402 403ipv6_payload_get() 404{ 405 local ipver=$1; shift 406 407 p=$(: 408 )"86:DD:"$( : ETH type 409 )"$ipver"$( : IP version 410 )"0:0:"$( : Traffic class 411 )"0:00:00:"$( : Flow label 412 )"00:00:"$( : Payload length 413 )"01:"$( : Next header 414 )"04:"$( : Hop limit 415 )"$h1_ipv6:"$( : IP saddr 416 )"$h2_ipv6:"$( : IP daddr 417 ) 418 echo $p 419} 420 421__ipv6_header_corrupted_test() 422{ 423 local desc=$1; shift 424 local ipver=$1; shift 425 local trap_name="ip_header_corrupted" 426 local payload 427 local mz_pid 428 429 RET=0 430 431 ping_check $trap_name 432 433 tc filter add dev $rp2 egress protocol ip pref 1 handle 101 \ 434 flower dst_ip $h2_ipv4 action drop 435 436 payload=$(ipv6_payload_get $ipver) 437 438 # Generate packets with corrupted IP header 439 $MZ $h1 -c 0 -d 1msec -a $h1mac -b $rp1mac -q p=$payload & 440 mz_pid=$! 441 442 devlink_trap_drop_test $trap_name $rp2 101 443 444 log_test "IP header corrupted: $desc: IPv6" 445 446 devlink_trap_drop_cleanup $mz_pid $rp2 "ip" 1 101 447} 448 449ip_header_corrupted_test() 450{ 451 # Each test uses one wrong value. The three values below are correct. 452 local ipv="4" 453 local ihl="5" 454 local checksum="00:F4" 455 456 __ipv4_header_corrupted_test "wrong IP version" 5 $ihl $checksum 457 __ipv4_header_corrupted_test "wrong IHL" $ipv 4 $checksum 458 __ipv4_header_corrupted_test "wrong checksum" $ipv $ihl "00:00" 459 __ipv6_header_corrupted_test "wrong IP version" 5 460} 461 462ipv6_mc_dip_reserved_scope_test() 463{ 464 local trap_name="ipv6_mc_dip_reserved_scope" 465 local dip=FF00:: 466 local mz_pid 467 468 RET=0 469 470 ping_check $trap_name 471 472 tc filter add dev $rp2 egress protocol ipv6 pref 1 handle 101 \ 473 flower dst_ip $dip action drop 474 475 # Generate packets with reserved scope destination IP 476 $MZ $h1 -6 -t udp "sp=54321,dp=12345" -c 0 -p 100 -b \ 477 "33:33:00:00:00:00" -B $dip -d 1msec -q & 478 mz_pid=$! 479 480 devlink_trap_drop_test $trap_name $rp2 101 481 482 log_test "IPv6 multicast destination IP reserved scope" 483 484 devlink_trap_drop_cleanup $mz_pid $rp2 "ipv6" 1 101 485} 486 487ipv6_mc_dip_interface_local_scope_test() 488{ 489 local trap_name="ipv6_mc_dip_interface_local_scope" 490 local dip=FF01:: 491 local mz_pid 492 493 RET=0 494 495 ping_check $trap_name 496 497 tc filter add dev $rp2 egress protocol ipv6 pref 1 handle 101 \ 498 flower dst_ip $dip action drop 499 500 # Generate packets with interface local scope destination IP 501 $MZ $h1 -6 -t udp "sp=54321,dp=12345" -c 0 -p 100 -b \ 502 "33:33:00:00:00:00" -B $dip -d 1msec -q & 503 mz_pid=$! 504 505 devlink_trap_drop_test $trap_name $rp2 101 506 507 log_test "IPv6 multicast destination IP interface-local scope" 508 509 devlink_trap_drop_cleanup $mz_pid $rp2 "ipv6" 1 101 510} 511 512__blackhole_route_test() 513{ 514 local flags=$1; shift 515 local subnet=$1; shift 516 local proto=$1; shift 517 local dip=$1; shift 518 local ip_proto=${1:-"icmp"}; shift 519 local trap_name="blackhole_route" 520 local mz_pid 521 522 RET=0 523 524 ping_check $trap_name 525 526 ip -$flags route add blackhole $subnet 527 tc filter add dev $rp2 egress protocol $proto pref 1 handle 101 \ 528 flower skip_hw dst_ip $dip ip_proto $ip_proto action drop 529 530 # Generate packets to the blackhole route 531 $MZ $h1 -$flags -t udp "sp=54321,dp=12345" -c 0 -p 100 -b $rp1mac \ 532 -B $dip -d 1msec -q & 533 mz_pid=$! 534 535 devlink_trap_drop_test $trap_name $rp2 101 536 log_test "Blackhole route: IPv$flags" 537 538 devlink_trap_drop_cleanup $mz_pid $rp2 $proto 1 101 539 ip -$flags route del blackhole $subnet 540} 541 542blackhole_route_test() 543{ 544 __blackhole_route_test "4" "198.51.100.0/30" "ip" $h2_ipv4 545 __blackhole_route_test "6" "2001:db8:2::/120" "ipv6" $h2_ipv6 "icmpv6" 546} 547 548irif_disabled_test() 549{ 550 local trap_name="irif_disabled" 551 local t0_packets t0_bytes 552 local t1_packets t1_bytes 553 local mz_pid 554 555 RET=0 556 557 ping_check $trap_name 558 559 devlink_trap_action_set $trap_name "trap" 560 561 # When RIF of a physical port ("Sub-port RIF") is destroyed, we first 562 # block the STP of the {Port, VLAN} so packets cannot get into the RIF. 563 # Using bridge enables us to see this trap because when bridge is 564 # destroyed, there is a small time window that packets can go into the 565 # RIF, while it is disabled. 566 ip link add dev br0 type bridge 567 ip link set dev $rp1 master br0 568 ip address flush dev $rp1 569 __addr_add_del br0 add 192.0.2.2/24 570 ip li set dev br0 up 571 572 t0_packets=$(devlink_trap_rx_packets_get $trap_name) 573 t0_bytes=$(devlink_trap_rx_bytes_get $trap_name) 574 575 # Generate packets to h2 through br0 RIF that will be removed later 576 $MZ $h1 -t udp "sp=54321,dp=12345" -c 0 -p 100 -a own -b $rp1mac \ 577 -B $h2_ipv4 -q & 578 mz_pid=$! 579 580 # Wait before removing br0 RIF to allow packets to go into the bridge. 581 sleep 1 582 583 # Flushing address will dismantle the RIF 584 ip address flush dev br0 585 586 t1_packets=$(devlink_trap_rx_packets_get $trap_name) 587 t1_bytes=$(devlink_trap_rx_bytes_get $trap_name) 588 589 if [[ $t0_packets -eq $t1_packets && $t0_bytes -eq $t1_bytes ]]; then 590 check_err 1 "Trap stats idle when packets should be trapped" 591 fi 592 593 log_test "Ingress RIF disabled" 594 595 kill $mz_pid && wait $mz_pid &> /dev/null 596 ip link set dev $rp1 nomaster 597 __addr_add_del $rp1 add 192.0.2.2/24 2001:db8:1::2/64 598 ip link del dev br0 type bridge 599 devlink_trap_action_set $trap_name "drop" 600} 601 602erif_disabled_test() 603{ 604 local trap_name="erif_disabled" 605 local t0_packets t0_bytes 606 local t1_packets t1_bytes 607 local mz_pid 608 609 RET=0 610 611 ping_check $trap_name 612 613 devlink_trap_action_set $trap_name "trap" 614 ip link add dev br0 type bridge 615 ip add flush dev $rp1 616 ip link set dev $rp1 master br0 617 __addr_add_del br0 add 192.0.2.2/24 618 ip link set dev br0 up 619 620 t0_packets=$(devlink_trap_rx_packets_get $trap_name) 621 t0_bytes=$(devlink_trap_rx_bytes_get $trap_name) 622 623 rp2mac=$(mac_get $rp2) 624 625 # Generate packets that should go out through br0 RIF that will be 626 # removed later 627 $MZ $h2 -t udp "sp=54321,dp=12345" -c 0 -p 100 -a own -b $rp2mac \ 628 -B 192.0.2.1 -q & 629 mz_pid=$! 630 631 sleep 5 632 # Unlinking the port from the bridge will disable the RIF associated 633 # with br0 as it is no longer an upper of any mlxsw port. 634 ip link set dev $rp1 nomaster 635 636 t1_packets=$(devlink_trap_rx_packets_get $trap_name) 637 t1_bytes=$(devlink_trap_rx_bytes_get $trap_name) 638 639 if [[ $t0_packets -eq $t1_packets && $t0_bytes -eq $t1_bytes ]]; then 640 check_err 1 "Trap stats idle when packets should be trapped" 641 fi 642 643 log_test "Egress RIF disabled" 644 645 kill $mz_pid && wait $mz_pid &> /dev/null 646 __addr_add_del $rp1 add 192.0.2.2/24 2001:db8:1::2/64 647 ip link del dev br0 type bridge 648 devlink_trap_action_set $trap_name "drop" 649} 650 651__blackhole_nexthop_test() 652{ 653 local flags=$1; shift 654 local subnet=$1; shift 655 local proto=$1; shift 656 local dip=$1; shift 657 local trap_name="blackhole_nexthop" 658 local mz_pid 659 660 RET=0 661 662 ip -$flags nexthop add id 1 blackhole 663 ip -$flags route add $subnet nhid 1 664 tc filter add dev $rp2 egress protocol $proto pref 1 handle 101 \ 665 flower skip_hw dst_ip $dip ip_proto udp action drop 666 667 # Generate packets to the blackhole nexthop 668 $MZ $h1 -$flags -t udp "sp=54321,dp=12345" -c 0 -p 100 -b $rp1mac \ 669 -B $dip -d 1msec -q & 670 mz_pid=$! 671 672 devlink_trap_drop_test $trap_name $rp2 101 673 log_test "Blackhole nexthop: IPv$flags" 674 675 devlink_trap_drop_cleanup $mz_pid $rp2 $proto 1 101 676 ip -$flags route del $subnet 677 ip -$flags nexthop del id 1 678} 679 680blackhole_nexthop_test() 681{ 682 __blackhole_nexthop_test "4" "198.51.100.0/30" "ip" $h2_ipv4 683 __blackhole_nexthop_test "6" "2001:db8:2::/120" "ipv6" $h2_ipv6 684} 685 686trap cleanup EXIT 687 688setup_prepare 689setup_wait 690 691tests_run 692 693exit $EXIT_STATUS 694