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