1#!/bin/bash 2# SPDX-License-Identifier: GPL-2.0 3# 4# nft_concat_range.sh - Tests for sets with concatenation of ranged fields 5# 6# Copyright (c) 2019 Red Hat GmbH 7# 8# Author: Stefano Brivio <sbrivio@redhat.com> 9# 10# shellcheck disable=SC2154,SC2034,SC2016,SC2030,SC2031,SC2317 11# ^ Configuration and templates sourced with eval, counters reused in subshells 12 13source lib.sh 14 15# Available test groups: 16# - reported_issues: check for issues that were reported in the past 17# - correctness: check that packets match given entries, and only those 18# - correctness_large: same but with additional non-matching entries 19# - concurrency: attempt races between insertion, deletion and lookup 20# - timeout: check that packets match entries until they expire 21# - performance: estimate matching rate, compare with rbtree and hash baselines 22TESTS="reported_issues correctness correctness_large concurrency timeout" 23 24[ -n "$NFT_CONCAT_RANGE_TESTS" ] && TESTS="${NFT_CONCAT_RANGE_TESTS}" 25 26# Set types, defined by TYPE_ variables below 27TYPES="net_port port_net net6_port port_proto net6_port_mac net6_port_mac_proto 28 net_port_net net_mac mac_net net_mac_icmp net6_mac_icmp 29 net6_port_net6_port net_port_mac_proto_net" 30 31# Reported bugs, also described by TYPE_ variables below 32BUGS="flush_remove_add reload net_port_proto_match avx2_mismatch" 33 34# List of possible paths to pktgen script from kernel tree for performance tests 35PKTGEN_SCRIPT_PATHS=" 36 ../../../../../samples/pktgen/pktgen_bench_xmit_mode_netif_receive.sh 37 pktgen/pktgen_bench_xmit_mode_netif_receive.sh" 38 39# Definition of set types: 40# display display text for test report 41# type_spec nftables set type specifier 42# chain_spec nftables type specifier for rules mapping to set 43# dst call sequence of format_*() functions for destination fields 44# src call sequence of format_*() functions for source fields 45# start initial integer used to generate addresses and ports 46# count count of entries to generate and match 47# src_delta number summed to destination generator for source fields 48# tools list of tools for correctness and timeout tests, any can be used 49# proto L4 protocol of test packets 50# 51# race_repeat race attempts per thread, 0 disables concurrency test for type 52# flood_tools list of tools for concurrency tests, any can be used 53# flood_proto L4 protocol of test packets for concurrency tests 54# flood_spec nftables type specifier for concurrency tests 55# 56# perf_duration duration of single pktgen injection test 57# perf_spec nftables type specifier for performance tests 58# perf_dst format_*() functions for destination fields in performance test 59# perf_src format_*() functions for source fields in performance test 60# perf_entries number of set entries for performance test 61# perf_proto L3 protocol of test packets 62TYPE_net_port=" 63display net,port 64type_spec ipv4_addr . inet_service 65chain_spec ip daddr . udp dport 66dst addr4 port 67src 68start 1 69count 5 70src_delta 2000 71tools sendip bash 72proto udp 73 74race_repeat 3 75flood_tools iperf3 iperf netperf 76flood_proto udp 77flood_spec ip daddr . udp dport 78 79perf_duration 5 80perf_spec ip daddr . udp dport 81perf_dst addr4 port 82perf_src 83perf_entries 1000 84perf_proto ipv4 85" 86 87TYPE_port_net=" 88display port,net 89type_spec inet_service . ipv4_addr 90chain_spec udp dport . ip daddr 91dst port addr4 92src 93start 1 94count 5 95src_delta 2000 96tools sendip socat bash 97proto udp 98 99race_repeat 3 100flood_tools iperf3 iperf netperf 101flood_proto udp 102flood_spec udp dport . ip daddr 103 104perf_duration 5 105perf_spec udp dport . ip daddr 106perf_dst port addr4 107perf_src 108perf_entries 100 109perf_proto ipv4 110" 111 112TYPE_net6_port=" 113display net6,port 114type_spec ipv6_addr . inet_service 115chain_spec ip6 daddr . udp dport 116dst addr6 port 117src 118start 10 119count 5 120src_delta 2000 121tools sendip socat bash 122proto udp6 123 124race_repeat 3 125flood_tools iperf3 iperf netperf 126flood_proto tcp6 127flood_spec ip6 daddr . udp dport 128 129perf_duration 5 130perf_spec ip6 daddr . udp dport 131perf_dst addr6 port 132perf_src 133perf_entries 1000 134perf_proto ipv6 135" 136 137TYPE_port_proto=" 138display port,proto 139type_spec inet_service . inet_proto 140chain_spec udp dport . meta l4proto 141dst port proto 142src 143start 1 144count 5 145src_delta 2000 146tools sendip socat bash 147proto udp 148 149race_repeat 0 150 151perf_duration 5 152perf_spec udp dport . meta l4proto 153perf_dst port proto 154perf_src 155perf_entries 30000 156perf_proto ipv4 157" 158 159TYPE_net6_port_mac=" 160display net6,port,mac 161type_spec ipv6_addr . inet_service . ether_addr 162chain_spec ip6 daddr . udp dport . ether saddr 163dst addr6 port 164src mac 165start 10 166count 5 167src_delta 2000 168tools sendip socat bash 169proto udp6 170 171race_repeat 0 172 173perf_duration 5 174perf_spec ip6 daddr . udp dport . ether daddr 175perf_dst addr6 port mac 176perf_src 177perf_entries 10 178perf_proto ipv6 179" 180 181TYPE_net6_port_mac_proto=" 182display net6,port,mac,proto 183type_spec ipv6_addr . inet_service . ether_addr . inet_proto 184chain_spec ip6 daddr . udp dport . ether saddr . meta l4proto 185dst addr6 port 186src mac proto 187start 10 188count 5 189src_delta 2000 190tools sendip socat bash 191proto udp6 192 193race_repeat 0 194 195perf_duration 5 196perf_spec ip6 daddr . udp dport . ether daddr . meta l4proto 197perf_dst addr6 port mac proto 198perf_src 199perf_entries 1000 200perf_proto ipv6 201" 202 203TYPE_net_port_net=" 204display net,port,net 205type_spec ipv4_addr . inet_service . ipv4_addr 206chain_spec ip daddr . udp dport . ip saddr 207dst addr4 port 208src addr4 209start 1 210count 5 211src_delta 2000 212tools sendip socat bash 213proto udp 214 215race_repeat 3 216flood_tools iperf3 iperf netperf 217flood_proto tcp 218flood_spec ip daddr . udp dport . ip saddr 219 220perf_duration 0 221" 222 223TYPE_net6_port_net6_port=" 224display net6,port,net6,port 225type_spec ipv6_addr . inet_service . ipv6_addr . inet_service 226chain_spec ip6 daddr . udp dport . ip6 saddr . udp sport 227dst addr6 port 228src addr6 port 229start 10 230count 5 231src_delta 2000 232tools sendip socat 233proto udp6 234 235race_repeat 3 236flood_tools iperf3 iperf netperf 237flood_proto tcp6 238flood_spec ip6 daddr . tcp dport . ip6 saddr . tcp sport 239 240perf_duration 0 241" 242 243TYPE_net_port_mac_proto_net=" 244display net,port,mac,proto,net 245type_spec ipv4_addr . inet_service . ether_addr . inet_proto . ipv4_addr 246chain_spec ip daddr . udp dport . ether saddr . meta l4proto . ip saddr 247dst addr4 port 248src mac proto addr4 249start 1 250count 5 251src_delta 2000 252tools sendip socat bash 253proto udp 254 255race_repeat 0 256 257perf_duration 0 258" 259 260TYPE_net_mac=" 261display net,mac 262type_spec ipv4_addr . ether_addr 263chain_spec ip daddr . ether saddr 264dst addr4 265src mac 266start 1 267count 5 268src_delta 2000 269tools sendip socat bash 270proto udp 271 272race_repeat 0 273 274perf_duration 5 275perf_spec ip daddr . ether daddr 276perf_dst addr4 mac 277perf_src 278perf_entries 1000 279perf_proto ipv4 280" 281 282TYPE_mac_net=" 283display mac,net 284type_spec ether_addr . ipv4_addr 285chain_spec ether saddr . ip saddr 286dst 287src mac addr4 288start 1 289count 5 290src_delta 2000 291tools sendip socat bash 292proto udp 293 294race_repeat 0 295 296perf_duration 0 297" 298 299TYPE_net_mac_icmp=" 300display net,mac - ICMP 301type_spec ipv4_addr . ether_addr 302chain_spec ip daddr . ether saddr 303dst addr4 304src mac 305start 1 306count 5 307src_delta 2000 308tools ping 309proto icmp 310 311race_repeat 0 312 313perf_duration 0 314" 315 316TYPE_net6_mac_icmp=" 317display net6,mac - ICMPv6 318type_spec ipv6_addr . ether_addr 319chain_spec ip6 daddr . ether saddr 320dst addr6 321src mac 322start 10 323count 50 324src_delta 2000 325tools ping 326proto icmp6 327 328race_repeat 0 329 330perf_duration 0 331" 332 333TYPE_net_port_proto_net=" 334display net,port,proto,net 335type_spec ipv4_addr . inet_service . inet_proto . ipv4_addr 336chain_spec ip daddr . udp dport . meta l4proto . ip saddr 337dst addr4 port proto 338src addr4 339start 1 340count 5 341src_delta 2000 342tools sendip socat 343proto udp 344 345race_repeat 3 346flood_tools iperf3 iperf netperf 347flood_proto tcp 348flood_spec ip daddr . tcp dport . meta l4proto . ip saddr 349 350perf_duration 0 351" 352 353# Definition of tests for bugs reported in the past: 354# display display text for test report 355TYPE_flush_remove_add=" 356display Add two elements, flush, re-add 357" 358 359TYPE_reload=" 360display net,mac with reload 361type_spec ipv4_addr . ether_addr 362chain_spec ip daddr . ether saddr 363dst addr4 364src mac 365start 1 366count 1 367src_delta 2000 368tools sendip socat bash 369proto udp 370 371race_repeat 0 372 373perf_duration 0 374" 375 376TYPE_net_port_proto_match=" 377display net,port,proto 378type_spec ipv4_addr . inet_service . inet_proto 379chain_spec ip daddr . udp dport . meta l4proto 380dst addr4 port proto 381src 382start 1 383count 9 384src_delta 9 385tools sendip bash 386proto udp 387 388race_repeat 0 389 390perf_duration 0 391" 392 393TYPE_avx2_mismatch=" 394display avx2 false match 395type_spec inet_proto . ipv6_addr 396chain_spec meta l4proto . ip6 daddr 397dst proto addr6 398src 399start 1 400count 1 401src_delta 1 402tools ping 403proto icmp6 404 405race_repeat 0 406 407perf_duration 0 408" 409 410 411# Set template for all tests, types and rules are filled in depending on test 412set_template=' 413flush ruleset 414 415table inet filter { 416 counter test { 417 packets 0 bytes 0 418 } 419 420 set test { 421 type ${type_spec} 422 counter 423 flags interval,timeout 424 } 425 426 chain input { 427 type filter hook prerouting priority 0; policy accept; 428 ${chain_spec} @test counter name \"test\" 429 } 430} 431 432table netdev perf { 433 counter test { 434 packets 0 bytes 0 435 } 436 437 counter match { 438 packets 0 bytes 0 439 } 440 441 set test { 442 type ${type_spec} 443 flags interval 444 } 445 446 set norange { 447 type ${type_spec} 448 } 449 450 set noconcat { 451 type ${type_spec%% *} 452 flags interval 453 } 454 455 chain test { 456 type filter hook ingress device veth_a priority 0; 457 } 458} 459' 460 461err_buf= 462info_buf= 463 464# Append string to error buffer 465err() { 466 err_buf="${err_buf}${1} 467" 468} 469 470# Append string to information buffer 471info() { 472 info_buf="${info_buf}${1} 473" 474} 475 476# Flush error buffer to stdout 477err_flush() { 478 printf "%s" "${err_buf}" 479 err_buf= 480} 481 482# Flush information buffer to stdout 483info_flush() { 484 printf "%s" "${info_buf}" 485 info_buf= 486} 487 488# Setup veth pair: this namespace receives traffic, B generates it 489setup_veth() { 490 ip netns add B 491 ip link add veth_a type veth peer name veth_b || return 1 492 493 ip link set veth_a up 494 ip link set veth_b netns B 495 496 ip -n B link set veth_b up 497 498 ip addr add dev veth_a 10.0.0.1 499 ip route add default dev veth_a 500 501 ip -6 addr add fe80::1/64 dev veth_a nodad 502 ip -6 addr add 2001:db8::1/64 dev veth_a nodad 503 ip -6 route add default dev veth_a 504 505 ip -n B route add default dev veth_b 506 507 ip -6 -n B addr add fe80::2/64 dev veth_b nodad 508 ip -6 -n B addr add 2001:db8::2/64 dev veth_b nodad 509 ip -6 -n B route add default dev veth_b 510 511 B() { 512 ip netns exec B "$@" >/dev/null 2>&1 513 } 514} 515 516# Fill in set template and initialise set 517setup_set() { 518 eval "echo \"${set_template}\"" | nft -f - 519} 520 521# Check that at least one of the needed tools is available 522check_tools() { 523 [ -z "${tools}" ] && return 0 524 525 __tools= 526 for tool in ${tools}; do 527 __tools="${__tools} ${tool}" 528 529 command -v "${tool}" >/dev/null && return 0 530 done 531 err "need one of:${__tools}, skipping" && return 1 532} 533 534# Set up function to send ICMP packets 535setup_send_icmp() { 536 send_icmp() { 537 B ping -c1 -W1 "${dst_addr4}" >/dev/null 2>&1 538 } 539} 540 541# Set up function to send ICMPv6 packets 542setup_send_icmp6() { 543 if command -v ping6 >/dev/null; then 544 send_icmp6() { 545 ip -6 addr add "${dst_addr6}" dev veth_a nodad \ 546 2>/dev/null 547 B ping6 -q -c1 -W1 "${dst_addr6}" 548 } 549 else 550 send_icmp6() { 551 ip -6 addr add "${dst_addr6}" dev veth_a nodad \ 552 2>/dev/null 553 B ping -q -6 -c1 -W1 "${dst_addr6}" 554 } 555 fi 556} 557 558# Set up function to send single UDP packets on IPv4 559setup_send_udp() { 560 if command -v sendip >/dev/null; then 561 send_udp() { 562 [ -n "${src_port}" ] && src_port="-us ${src_port}" 563 [ -n "${dst_port}" ] && dst_port="-ud ${dst_port}" 564 [ -n "${src_addr4}" ] && src_addr4="-is ${src_addr4}" 565 566 # shellcheck disable=SC2086 # sendip needs split options 567 B sendip -p ipv4 -p udp ${src_addr4} ${src_port} \ 568 ${dst_port} "${dst_addr4}" 569 570 src_port= 571 dst_port= 572 src_addr4= 573 } 574 elif command -v socat -v >/dev/null; then 575 send_udp() { 576 if [ -n "${src_addr4}" ]; then 577 B ip addr add "${src_addr4}" dev veth_b 578 __socatbind=",bind=${src_addr4}" 579 if [ -n "${src_port}" ];then 580 __socatbind="${__socatbind}:${src_port}" 581 fi 582 fi 583 584 ip addr add "${dst_addr4}" dev veth_a 2>/dev/null 585 [ -z "${dst_port}" ] && dst_port=12345 586 587 echo "test4" | B socat -t 0.01 STDIN UDP4-DATAGRAM:"$dst_addr4":"$dst_port""${__socatbind}" 588 589 src_addr4= 590 src_port= 591 } 592 elif [ -z "$(bash -c 'type -p')" ]; then 593 send_udp() { 594 ip addr add "${dst_addr4}" dev veth_a 2>/dev/null 595 if [ -n "${src_addr4}" ]; then 596 B ip addr add "${src_addr4}/16" dev veth_b 597 B ip route add default dev veth_b 598 fi 599 600 B bash -c "echo > /dev/udp/${dst_addr4}/${dst_port}" 601 602 if [ -n "${src_addr4}" ]; then 603 B ip addr del "${src_addr4}/16" dev veth_b 604 fi 605 src_addr4= 606 } 607 else 608 return 1 609 fi 610} 611 612# Set up function to send single UDP packets on IPv6 613setup_send_udp6() { 614 if command -v sendip >/dev/null; then 615 send_udp6() { 616 [ -n "${src_port}" ] && src_port="-us ${src_port}" 617 [ -n "${dst_port}" ] && dst_port="-ud ${dst_port}" 618 if [ -n "${src_addr6}" ]; then 619 src_addr6="-6s ${src_addr6}" 620 else 621 src_addr6="-6s 2001:db8::2" 622 fi 623 ip -6 addr add "${dst_addr6}" dev veth_a nodad \ 624 2>/dev/null 625 626 # shellcheck disable=SC2086 # this needs split options 627 B sendip -p ipv6 -p udp ${src_addr6} ${src_port} \ 628 ${dst_port} "${dst_addr6}" 629 630 src_port= 631 dst_port= 632 src_addr6= 633 } 634 elif command -v socat -v >/dev/null; then 635 send_udp6() { 636 ip -6 addr add "${dst_addr6}" dev veth_a nodad \ 637 2>/dev/null 638 639 __socatbind6= 640 641 if [ -n "${src_addr6}" ]; then 642 B ip addr add "${src_addr6}" dev veth_b nodad 643 644 __socatbind6=",bind=[${src_addr6}]" 645 646 if [ -n "${src_port}" ] ;then 647 __socatbind6="${__socatbind6}:${src_port}" 648 fi 649 fi 650 651 echo "test6" | B socat -t 0.01 STDIN UDP6-DATAGRAM:["$dst_addr6"]:"$dst_port""${__socatbind6}" 652 } 653 elif [ -z "$(bash -c 'type -p')" ]; then 654 send_udp6() { 655 ip -6 addr add "${dst_addr6}" dev veth_a nodad \ 656 2>/dev/null 657 B ip addr add "${src_addr6}" dev veth_b nodad 658 B bash -c "echo > /dev/udp/${dst_addr6}/${dst_port}" 659 ip -6 addr del "${dst_addr6}" dev veth_a 2>/dev/null 660 } 661 else 662 return 1 663 fi 664} 665 666listener_ready() 667{ 668 port="$1" 669 ss -lnt -o "sport = :$port" | grep -q "$port" 670} 671 672# Set up function to send TCP traffic on IPv4 673setup_flood_tcp() { 674 if command -v iperf3 >/dev/null; then 675 flood_tcp() { 676 local n_port="${dst_port}" 677 [ -n "${dst_port}" ] && dst_port="-p ${dst_port}" 678 if [ -n "${src_addr4}" ]; then 679 B ip addr add "${src_addr4}/16" dev veth_b 680 src_addr4="-B ${src_addr4}" 681 else 682 B ip addr add dev veth_b 10.0.0.2 683 src_addr4="-B 10.0.0.2" 684 fi 685 if [ -n "${src_port}" ]; then 686 src_port="--cport ${src_port}" 687 fi 688 B ip route add default dev veth_b 2>/dev/null 689 ip addr add "${dst_addr4}" dev veth_a 2>/dev/null 690 691 # shellcheck disable=SC2086 # this needs split options 692 iperf3 -s -DB "${dst_addr4}" ${dst_port} >/dev/null 2>&1 693 busywait "$BUSYWAIT_TIMEOUT" listener_ready "$n_port" 694 695 # shellcheck disable=SC2086 # this needs split options 696 B iperf3 -c "${dst_addr4}" ${dst_port} ${src_port} \ 697 ${src_addr4} -l16 -t 1000 698 699 src_addr4= 700 src_port= 701 dst_port= 702 } 703 elif command -v iperf >/dev/null; then 704 flood_tcp() { 705 local n_port="${dst_port}" 706 [ -n "${dst_port}" ] && dst_port="-p ${dst_port}" 707 if [ -n "${src_addr4}" ]; then 708 B ip addr add "${src_addr4}/16" dev veth_b 709 src_addr4="-B ${src_addr4}" 710 else 711 B ip addr add dev veth_b 10.0.0.2 2>/dev/null 712 src_addr4="-B 10.0.0.2" 713 fi 714 if [ -n "${src_port}" ]; then 715 src_addr4="${src_addr4}:${src_port}" 716 fi 717 B ip route add default dev veth_b 718 ip addr add "${dst_addr4}" dev veth_a 2>/dev/null 719 720 # shellcheck disable=SC2086 # this needs split options 721 iperf -s -DB "${dst_addr4}" ${dst_port} >/dev/null 2>&1 722 busywait "$BUSYWAIT_TIMEOUT" listener_ready "$n_port" 723 724 # shellcheck disable=SC2086 # this needs split options 725 B iperf -c "${dst_addr4}" ${dst_port} ${src_addr4} \ 726 -l20 -t 1000 727 728 src_addr4= 729 src_port= 730 dst_port= 731 } 732 elif command -v netperf >/dev/null; then 733 flood_tcp() { 734 local n_port="${dst_port}" 735 [ -n "${dst_port}" ] && dst_port="-p ${dst_port}" 736 if [ -n "${src_addr4}" ]; then 737 B ip addr add "${src_addr4}/16" dev veth_b 738 else 739 B ip addr add dev veth_b 10.0.0.2 740 src_addr4="10.0.0.2" 741 fi 742 if [ -n "${src_port}" ]; then 743 dst_port="${dst_port},${src_port}" 744 fi 745 B ip route add default dev veth_b 746 ip addr add "${dst_addr4}" dev veth_a 2>/dev/null 747 748 # shellcheck disable=SC2086 # this needs split options 749 netserver -4 ${dst_port} -L "${dst_addr4}" \ 750 >/dev/null 2>&1 751 busywait "$BUSYWAIT_TIMEOUT" listener_ready "${n_port}" 752 753 # shellcheck disable=SC2086 # this needs split options 754 B netperf -4 -H "${dst_addr4}" ${dst_port} \ 755 -L "${src_addr4}" -l 1000 -t TCP_STREAM 756 757 src_addr4= 758 src_port= 759 dst_port= 760 } 761 else 762 return 1 763 fi 764} 765 766# Set up function to send TCP traffic on IPv6 767setup_flood_tcp6() { 768 if command -v iperf3 >/dev/null; then 769 flood_tcp6() { 770 local n_port="${dst_port}" 771 [ -n "${dst_port}" ] && dst_port="-p ${dst_port}" 772 if [ -n "${src_addr6}" ]; then 773 B ip addr add "${src_addr6}" dev veth_b nodad 774 src_addr6="-B ${src_addr6}" 775 else 776 src_addr6="-B 2001:db8::2" 777 fi 778 if [ -n "${src_port}" ]; then 779 src_port="--cport ${src_port}" 780 fi 781 B ip route add default dev veth_b 782 ip -6 addr add "${dst_addr6}" dev veth_a nodad \ 783 2>/dev/null 784 785 # shellcheck disable=SC2086 # this needs split options 786 iperf3 -s -DB "${dst_addr6}" ${dst_port} >/dev/null 2>&1 787 busywait "$BUSYWAIT_TIMEOUT" listener_ready "${n_port}" 788 789 # shellcheck disable=SC2086 # this needs split options 790 B iperf3 -c "${dst_addr6}" ${dst_port} \ 791 ${src_port} ${src_addr6} -l16 -t 1000 792 793 src_addr6= 794 src_port= 795 dst_port= 796 } 797 elif command -v iperf >/dev/null; then 798 flood_tcp6() { 799 local n_port="${dst_port}" 800 [ -n "${dst_port}" ] && dst_port="-p ${dst_port}" 801 if [ -n "${src_addr6}" ]; then 802 B ip addr add "${src_addr6}" dev veth_b nodad 803 src_addr6="-B ${src_addr6}" 804 else 805 src_addr6="-B 2001:db8::2" 806 fi 807 if [ -n "${src_port}" ]; then 808 src_addr6="${src_addr6}:${src_port}" 809 fi 810 B ip route add default dev veth_b 811 ip -6 addr add "${dst_addr6}" dev veth_a nodad \ 812 2>/dev/null 813 814 # shellcheck disable=SC2086 # this needs split options 815 iperf -s -VDB "${dst_addr6}" ${dst_port} >/dev/null 2>&1 816 busywait "$BUSYWAIT_TIMEOUT" listener_ready "$n_port" 817 818 # shellcheck disable=SC2086 # this needs split options 819 B iperf -c "${dst_addr6}" -V ${dst_port} \ 820 ${src_addr6} -l1 -t 1000 821 822 src_addr6= 823 src_port= 824 dst_port= 825 } 826 elif command -v netperf >/dev/null; then 827 flood_tcp6() { 828 local n_port="${dst_port}" 829 [ -n "${dst_port}" ] && dst_port="-p ${dst_port}" 830 if [ -n "${src_addr6}" ]; then 831 B ip addr add "${src_addr6}" dev veth_b nodad 832 else 833 src_addr6="2001:db8::2" 834 fi 835 if [ -n "${src_port}" ]; then 836 dst_port="${dst_port},${src_port}" 837 fi 838 B ip route add default dev veth_b 839 ip -6 addr add "${dst_addr6}" dev veth_a nodad \ 840 2>/dev/null 841 842 # shellcheck disable=SC2086 # this needs split options 843 netserver -6 ${dst_port} -L "${dst_addr6}" \ 844 >/dev/null 2>&1 845 busywait "$BUSYWAIT_TIMEOUT" listener_ready "$n_port" 846 847 # shellcheck disable=SC2086 # this needs split options 848 B netperf -6 -H "${dst_addr6}" ${dst_port} \ 849 -L "${src_addr6}" -l 1000 -t TCP_STREAM 850 851 src_addr6= 852 src_port= 853 dst_port= 854 } 855 else 856 return 1 857 fi 858} 859 860# Set up function to send UDP traffic on IPv4 861setup_flood_udp() { 862 if command -v iperf3 >/dev/null; then 863 flood_udp() { 864 local n_port="${dst_port}" 865 [ -n "${dst_port}" ] && dst_port="-p ${dst_port}" 866 if [ -n "${src_addr4}" ]; then 867 B ip addr add "${src_addr4}/16" dev veth_b 868 src_addr4="-B ${src_addr4}" 869 else 870 B ip addr add dev veth_b 10.0.0.2 2>/dev/null 871 src_addr4="-B 10.0.0.2" 872 fi 873 if [ -n "${src_port}" ]; then 874 src_port="--cport ${src_port}" 875 fi 876 B ip route add default dev veth_b 877 ip addr add "${dst_addr4}" dev veth_a 2>/dev/null 878 879 # shellcheck disable=SC2086 # this needs split options 880 iperf3 -s -DB "${dst_addr4}" ${dst_port} 881 busywait "$BUSYWAIT_TIMEOUT" listener_ready "$n_port" 882 883 # shellcheck disable=SC2086 # this needs split options 884 B iperf3 -u -c "${dst_addr4}" -Z -b 100M -l16 -t1000 \ 885 ${dst_port} ${src_port} ${src_addr4} 886 887 src_addr4= 888 src_port= 889 dst_port= 890 } 891 elif command -v iperf >/dev/null; then 892 flood_udp() { 893 local n_port="${dst_port}" 894 [ -n "${dst_port}" ] && dst_port="-p ${dst_port}" 895 if [ -n "${src_addr4}" ]; then 896 B ip addr add "${src_addr4}/16" dev veth_b 897 src_addr4="-B ${src_addr4}" 898 else 899 B ip addr add dev veth_b 10.0.0.2 900 src_addr4="-B 10.0.0.2" 901 fi 902 if [ -n "${src_port}" ]; then 903 src_addr4="${src_addr4}:${src_port}" 904 fi 905 B ip route add default dev veth_b 906 ip addr add "${dst_addr4}" dev veth_a 2>/dev/null 907 908 # shellcheck disable=SC2086 # this needs split options 909 iperf -u -sDB "${dst_addr4}" ${dst_port} >/dev/null 2>&1 910 busywait "$BUSYWAIT_TIMEOUT" listener_ready "$n_port" 911 912 # shellcheck disable=SC2086 # this needs split options 913 B iperf -u -c "${dst_addr4}" -b 100M -l1 -t1000 \ 914 ${dst_port} ${src_addr4} 915 916 src_addr4= 917 src_port= 918 dst_port= 919 } 920 elif command -v netperf >/dev/null; then 921 flood_udp() { 922 local n_port="${dst_port}" 923 [ -n "${dst_port}" ] && dst_port="-p ${dst_port}" 924 if [ -n "${src_addr4}" ]; then 925 B ip addr add "${src_addr4}/16" dev veth_b 926 else 927 B ip addr add dev veth_b 10.0.0.2 928 src_addr4="10.0.0.2" 929 fi 930 if [ -n "${src_port}" ]; then 931 dst_port="${dst_port},${src_port}" 932 fi 933 B ip route add default dev veth_b 934 ip addr add "${dst_addr4}" dev veth_a 2>/dev/null 935 936 # shellcheck disable=SC2086 # this needs split options 937 netserver -4 ${dst_port} -L "${dst_addr4}" \ 938 >/dev/null 2>&1 939 busywait "$BUSYWAIT_TIMEOUT" listener_ready "$n_port" 940 941 # shellcheck disable=SC2086 # this needs split options 942 B netperf -4 -H "${dst_addr4}" ${dst_port} \ 943 -L "${src_addr4}" -l 1000 -t UDP_STREAM 944 945 src_addr4= 946 src_port= 947 dst_port= 948 } 949 else 950 return 1 951 fi 952} 953 954# Find pktgen script and set up function to start pktgen injection 955setup_perf() { 956 for pktgen_script_path in ${PKTGEN_SCRIPT_PATHS} __notfound; do 957 command -v "${pktgen_script_path}" >/dev/null && break 958 done 959 [ "${pktgen_script_path}" = "__notfound" ] && return 1 960 961 perf_ipv4() { 962 ${pktgen_script_path} -s80 \ 963 -i veth_a -d "${dst_addr4}" -p "${dst_port}" \ 964 -m "${dst_mac}" \ 965 -t $(($(nproc) / 5 + 1)) -b10000 -n0 2>/dev/null & 966 perf_pid=$! 967 } 968 perf_ipv6() { 969 IP6=6 ${pktgen_script_path} -s100 \ 970 -i veth_a -d "${dst_addr6}" -p "${dst_port}" \ 971 -m "${dst_mac}" \ 972 -t $(($(nproc) / 5 + 1)) -b10000 -n0 2>/dev/null & 973 perf_pid=$! 974 } 975} 976 977# Clean up before each test 978cleanup() { 979 nft reset counter inet filter test >/dev/null 2>&1 980 nft flush ruleset >/dev/null 2>&1 981 ip link del dummy0 2>/dev/null 982 ip route del default 2>/dev/null 983 ip -6 route del default 2>/dev/null 984 ip netns pids B 2>/dev/null | xargs kill 2>/dev/null 985 ip netns del B 2>/dev/null 986 ip link del veth_a 2>/dev/null 987 timeout= 988 killall iperf3 2>/dev/null 989 killall iperf 2>/dev/null 990 killall netperf 2>/dev/null 991 killall netserver 2>/dev/null 992} 993 994cleanup_exit() { 995 cleanup 996 rm -f "$tmp" 997} 998 999# Entry point for setup functions 1000setup() { 1001 if [ "$(id -u)" -ne 0 ]; then 1002 echo " need to run as root" 1003 exit ${ksft_skip} 1004 fi 1005 1006 cleanup 1007 check_tools || return 1 1008 for arg do 1009 if ! eval setup_"${arg}"; then 1010 err " ${arg} not supported" 1011 return 1 1012 fi 1013 done 1014} 1015 1016# Format integer into IPv4 address, summing 10.0.0.5 (arbitrary) to it 1017format_addr4() { 1018 a=$((${1} + 16777216 * 10 + 5)) 1019 printf "%i.%i.%i.%i" \ 1020 "$((a / 16777216))" "$((a % 16777216 / 65536))" \ 1021 "$((a % 65536 / 256))" "$((a % 256))" 1022} 1023 1024# Format integer into IPv6 address, summing 2001:db8:: to it 1025format_addr6() { 1026 printf "2001:db8::%04x:%04x" "$((${1} / 65536))" "$((${1} % 65536))" 1027} 1028 1029# Format integer into EUI-48 address, summing 00:01:00:00:00:00 to it 1030format_mac() { 1031 printf "00:01:%02x:%02x:%02x:%02x" \ 1032 "$((${1} / 16777216))" "$((${1} % 16777216 / 65536))" \ 1033 "$((${1} % 65536 / 256))" "$((${1} % 256))" 1034} 1035 1036# Format integer into port, avoid 0 port 1037format_port() { 1038 printf "%i" "$((${1} % 65534 + 1))" 1039} 1040 1041# Drop suffixed '6' from L4 protocol, if any 1042format_proto() { 1043 printf "%s" "${proto}" | tr -d 6 1044} 1045 1046# Format destination and source fields into nft concatenated type 1047format() { 1048 __start= 1049 __end= 1050 __expr="{ " 1051 1052 for f in ${dst}; do 1053 [ "${__expr}" != "{ " ] && __expr="${__expr} . " 1054 1055 __start="$(eval format_"${f}" "${start}")" 1056 __end="$(eval format_"${f}" "${end}")" 1057 1058 if [ "${f}" = "proto" ]; then 1059 __expr="${__expr}${__start}" 1060 else 1061 __expr="${__expr}${__start}-${__end}" 1062 fi 1063 done 1064 for f in ${src}; do 1065 [ "${__expr}" != "{ " ] && __expr="${__expr} . " 1066 1067 __start="$(eval format_"${f}" "${srcstart}")" 1068 __end="$(eval format_"${f}" "${srcend}")" 1069 1070 if [ "${f}" = "proto" ]; then 1071 __expr="${__expr}${__start}" 1072 else 1073 __expr="${__expr}${__start}-${__end}" 1074 fi 1075 done 1076 1077 if [ -n "${timeout}" ]; then 1078 echo "${__expr} timeout ${timeout}s }" 1079 else 1080 echo "${__expr} }" 1081 fi 1082} 1083 1084# Format destination and source fields into nft type, start element only 1085format_norange() { 1086 __expr="{ " 1087 1088 for f in ${dst}; do 1089 [ "${__expr}" != "{ " ] && __expr="${__expr} . " 1090 1091 __expr="${__expr}$(eval format_"${f}" "${start}")" 1092 done 1093 for f in ${src}; do 1094 __expr="${__expr} . $(eval format_"${f}" "${start}")" 1095 done 1096 1097 echo "${__expr} }" 1098} 1099 1100# Format first destination field into nft type 1101format_noconcat() { 1102 for f in ${dst}; do 1103 __start="$(eval format_"${f}" "${start}")" 1104 __end="$(eval format_"${f}" "${end}")" 1105 1106 if [ "${f}" = "proto" ]; then 1107 echo "{ ${__start} }" 1108 else 1109 echo "{ ${__start}-${__end} }" 1110 fi 1111 return 1112 done 1113} 1114 1115# Add single entry to 'test' set in 'inet filter' table 1116add() { 1117 if ! nft add element inet filter test "${1}"; then 1118 err "Failed to add ${1} given ruleset:" 1119 err "$(nft -a list ruleset)" 1120 return 1 1121 fi 1122} 1123 1124# Format and output entries for sets in 'netdev perf' table 1125add_perf() { 1126 if [ "${1}" = "test" ]; then 1127 echo "add element netdev perf test $(format)" 1128 elif [ "${1}" = "norange" ]; then 1129 echo "add element netdev perf norange $(format_norange)" 1130 elif [ "${1}" = "noconcat" ]; then 1131 echo "add element netdev perf noconcat $(format_noconcat)" 1132 fi 1133} 1134 1135# Add single entry to 'norange' set in 'netdev perf' table 1136add_perf_norange() { 1137 if ! nft add element netdev perf norange "${1}"; then 1138 err "Failed to add ${1} given ruleset:" 1139 err "$(nft -a list ruleset)" 1140 return 1 1141 fi 1142} 1143 1144# Add single entry to 'noconcat' set in 'netdev perf' table 1145add_perf_noconcat() { 1146 if ! nft add element netdev perf noconcat "${1}"; then 1147 err "Failed to add ${1} given ruleset:" 1148 err "$(nft -a list ruleset)" 1149 return 1 1150 fi 1151} 1152 1153# Delete single entry from set 1154del() { 1155 if ! nft delete element inet filter test "${1}"; then 1156 err "Failed to delete ${1} given ruleset:" 1157 err "$(nft -a list ruleset)" 1158 return 1 1159 fi 1160} 1161 1162# Return packet count for elem $1 from 'test' counter in 'inet filter' table 1163count_packets() { 1164 found=0 1165 for token in $(nft reset element inet filter test "${1}" ); do 1166 [ ${found} -eq 1 ] && echo "${token}" && return 1167 [ "${token}" = "packets" ] && found=1 1168 done 1169} 1170 1171# Return packet count from 'test' counter in 'inet filter' table 1172count_packets_nomatch() { 1173 found=0 1174 for token in $(nft list counter inet filter test); do 1175 [ ${found} -eq 1 ] && echo "${token}" && return 1176 [ "${token}" = "packets" ] && found=1 1177 done 1178} 1179 1180# Return packet count from 'test' counter in 'netdev perf' table 1181count_perf_packets() { 1182 found=0 1183 for token in $(nft list counter netdev perf test); do 1184 [ ${found} -eq 1 ] && echo "${token}" && return 1185 [ "${token}" = "packets" ] && found=1 1186 done 1187} 1188 1189# Set MAC addresses, send traffic according to specifier 1190flood() { 1191 ip link set veth_a address "$(format_mac "${1}")" 1192 ip -n B link set veth_b address "$(format_mac "${2}")" 1193 1194 for f in ${dst}; do 1195 eval dst_"$f"=\$\(format_\$f "${1}"\) 1196 done 1197 for f in ${src}; do 1198 eval src_"$f"=\$\(format_\$f "${2}"\) 1199 done 1200 eval flood_\$proto 1201} 1202 1203# Set MAC addresses, start pktgen injection 1204perf() { 1205 dst_mac="$(format_mac "${1}")" 1206 ip link set veth_a address "${dst_mac}" 1207 1208 for f in ${dst}; do 1209 eval dst_"$f"=\$\(format_\$f "${1}"\) 1210 done 1211 for f in ${src}; do 1212 eval src_"$f"=\$\(format_\$f "${2}"\) 1213 done 1214 eval perf_\$perf_proto 1215} 1216 1217# Set MAC addresses, send single packet, check that it matches, reset counter 1218send_match() { 1219 local elem="$1" 1220 1221 shift 1222 1223 ip link set veth_a address "$(format_mac "${1}")" 1224 ip -n B link set veth_b address "$(format_mac "${2}")" 1225 1226 for f in ${dst}; do 1227 eval dst_"$f"=\$\(format_\$f "${1}"\) 1228 done 1229 for f in ${src}; do 1230 eval src_"$f"=\$\(format_\$f "${2}"\) 1231 done 1232 eval send_\$proto 1233 if [ "$(count_packets "$elem")" != "1" ]; then 1234 err "${proto} packet to:" 1235 err " $(for f in ${dst}; do 1236 eval format_\$f "${1}"; printf ' '; done)" 1237 err "from:" 1238 err " $(for f in ${src}; do 1239 eval format_\$f "${2}"; printf ' '; done)" 1240 err "should have matched ruleset:" 1241 err "$(nft -a list ruleset)" 1242 return 1 1243 fi 1244 nft reset counter inet filter test >/dev/null 1245} 1246 1247# Set MAC addresses, send single packet, check that it doesn't match 1248send_nomatch() { 1249 ip link set veth_a address "$(format_mac "${1}")" 1250 ip -n B link set veth_b address "$(format_mac "${2}")" 1251 1252 for f in ${dst}; do 1253 eval dst_"$f"=\$\(format_\$f "${1}"\) 1254 done 1255 for f in ${src}; do 1256 eval src_"$f"=\$\(format_\$f "${2}"\) 1257 done 1258 eval send_\$proto 1259 if [ "$(count_packets_nomatch)" != "0" ]; then 1260 err "${proto} packet to:" 1261 err " $(for f in ${dst}; do 1262 eval format_\$f "${1}"; printf ' '; done)" 1263 err "from:" 1264 err " $(for f in ${src}; do 1265 eval format_\$f "${2}"; printf ' '; done)" 1266 err "should not have matched ruleset:" 1267 err "$(nft -a list ruleset)" 1268 return 1 1269 fi 1270} 1271 1272maybe_send_nomatch() { 1273 local elem="$1" 1274 local what="$4" 1275 1276 [ $((RANDOM%20)) -gt 0 ] && return 1277 1278 dst_addr4="$2" 1279 dst_port="$3" 1280 send_udp 1281 1282 if [ "$(count_packets_nomatch)" != "0" ]; then 1283 err "Packet to $dst_addr4:$dst_port did match $what" 1284 err "$(nft -a list ruleset)" 1285 return 1 1286 fi 1287} 1288 1289maybe_send_match() { 1290 local elem="$1" 1291 local what="$4" 1292 1293 [ $((RANDOM%20)) -gt 0 ] && return 1294 1295 dst_addr4="$2" 1296 dst_port="$3" 1297 send_udp 1298 1299 if [ "$(count_packets "{ $elem }")" != "1" ]; then 1300 err "Packet to $dst_addr4:$dst_port did not match $what" 1301 err "$(nft -a list ruleset)" 1302 return 1 1303 fi 1304 nft reset counter inet filter test >/dev/null 1305 nft reset element inet filter test "{ $elem }" >/dev/null 1306} 1307 1308# Correctness test template: 1309# - add ranged element, check that packets match it 1310# - check that packets outside range don't match it 1311# - remove some elements, check that packets don't match anymore 1312test_correctness_main() { 1313 range_size=1 1314 1315 send_nomatch $((end + 1)) $((end + 1 + src_delta)) || return 1 1316 1317 for i in $(seq "${start}" $((start + count))); do 1318 local elem="" 1319 1320 end=$((start + range_size)) 1321 1322 # Avoid negative or zero-sized port ranges 1323 if [ $((end / 65534)) -gt $((start / 65534)) ]; then 1324 start=${end} 1325 end=$((end + 1)) 1326 fi 1327 srcstart=$((start + src_delta)) 1328 srcend=$((end + src_delta)) 1329 1330 elem="$(format)" 1331 add "$elem" || return 1 1332 for j in $(seq "$start" $((range_size / 2 + 1)) ${end}); do 1333 send_match "$elem" "${j}" $((j + src_delta)) || return 1 1334 done 1335 send_nomatch $((end + 1)) $((end + 1 + src_delta)) || return 1 1336 1337 # Delete elements now and then 1338 if [ $((i % 3)) -eq 0 ]; then 1339 del "$elem" || return 1 1340 for j in $(seq "$start" \ 1341 $((range_size / 2 + 1)) ${end}); do 1342 send_nomatch "${j}" $((j + src_delta)) \ 1343 || return 1 1344 done 1345 fi 1346 1347 range_size=$((range_size + 1)) 1348 start=$((end + range_size)) 1349 done 1350} 1351 1352test_correctness() { 1353 setup veth send_"${proto}" set || return ${ksft_skip} 1354 1355 test_correctness_main 1356} 1357 1358# Repeat the correctness tests, but add extra non-matching entries. 1359# This exercises the more compact '4 bit group' representation that 1360# gets picked when the default 8-bit representation exceed 1361# NFT_PIPAPO_LT_SIZE_HIGH bytes of memory. 1362# See usage of NFT_PIPAPO_LT_SIZE_HIGH in pipapo_lt_bits_adjust(). 1363# 1364# The format() helper is way too slow when generating lots of 1365# entries so its not used here. 1366test_correctness_large() { 1367 setup veth send_"${proto}" set || return ${ksft_skip} 1368 # number of dummy (filler) entries to add. 1369 local dcount=16385 1370 1371 ( 1372 echo -n "add element inet filter test { " 1373 1374 case "$type_spec" in 1375 "ether_addr . ipv4_addr") 1376 for i in $(seq 1 $dcount); do 1377 [ $i -gt 1 ] && echo ", " 1378 format_mac $((1000000 + i)) 1379 printf ". 172.%i.%i.%i " $((RANDOM%256)) $((RANDOM%256)) $((i%256)) 1380 done 1381 ;; 1382 "inet_proto . ipv6_addr") 1383 for i in $(seq 1 $dcount); do 1384 [ $i -gt 1 ] && echo ", " 1385 printf "%i . " $((RANDOM%256)) 1386 format_addr6 $((1000000 + i)) 1387 done 1388 ;; 1389 "inet_service . inet_proto") 1390 # smaller key sizes, need more entries to hit the 1391 # 4-bit threshold. 1392 dcount=65536 1393 for i in $(seq 1 $dcount); do 1394 local proto=$((RANDOM%256)) 1395 1396 # Test uses UDP to match, as it also fails when matching 1397 # an entry that doesn't exist, so skip 'udp' entries 1398 # to not trigger a wrong failure. 1399 [ $proto -eq 17 ] && proto=18 1400 [ $i -gt 1 ] && echo ", " 1401 printf "%i . %i " $(((i%65534) + 1)) $((proto)) 1402 done 1403 ;; 1404 "inet_service . ipv4_addr") 1405 dcount=32768 1406 for i in $(seq 1 $dcount); do 1407 [ $i -gt 1 ] && echo ", " 1408 printf "%i . 172.%i.%i.%i " $(((RANDOM%65534) + 1)) $((RANDOM%256)) $((RANDOM%256)) $((i%256)) 1409 done 1410 ;; 1411 "ipv4_addr . ether_addr") 1412 for i in $(seq 1 $dcount); do 1413 [ $i -gt 1 ] && echo ", " 1414 printf "172.%i.%i.%i . " $((RANDOM%256)) $((RANDOM%256)) $((i%256)) 1415 format_mac $((1000000 + i)) 1416 done 1417 ;; 1418 "ipv4_addr . inet_service") 1419 dcount=32768 1420 for i in $(seq 1 $dcount); do 1421 [ $i -gt 1 ] && echo ", " 1422 printf "172.%i.%i.%i . %i" $((RANDOM%256)) $((RANDOM%256)) $((i%256)) $(((RANDOM%65534) + 1)) 1423 done 1424 ;; 1425 "ipv4_addr . inet_service . ether_addr . inet_proto . ipv4_addr") 1426 dcount=65536 1427 for i in $(seq 1 $dcount); do 1428 [ $i -gt 1 ] && echo ", " 1429 printf "172.%i.%i.%i . %i . " $((RANDOM%256)) $((RANDOM%256)) $((i%256)) $(((RANDOM%65534) + 1)) 1430 format_mac $((1000000 + i)) 1431 printf ". %i . 192.168.%i.%i" $((RANDOM%256)) $((RANDOM%256)) $((i%256)) 1432 done 1433 ;; 1434 "ipv4_addr . inet_service . inet_proto") 1435 for i in $(seq 1 $dcount); do 1436 [ $i -gt 1 ] && echo ", " 1437 printf "172.%i.%i.%i . %i . %i " $((RANDOM%256)) $((RANDOM%256)) $((i%256)) $(((RANDOM%65534) + 1)) $((RANDOM%256)) 1438 done 1439 ;; 1440 "ipv4_addr . inet_service . inet_proto . ipv4_addr") 1441 for i in $(seq 1 $dcount); do 1442 [ $i -gt 1 ] && echo ", " 1443 printf "172.%i.%i.%i . %i . %i . 192.168.%i.%i " $((RANDOM%256)) $((RANDOM%256)) $((i%256)) $(((RANDOM%65534) + 1)) $((RANDOM%256)) $((RANDOM%256)) $((RANDOM%256)) 1444 done 1445 ;; 1446 "ipv4_addr . inet_service . ipv4_addr") 1447 dcount=32768 1448 for i in $(seq 1 $dcount); do 1449 [ $i -gt 1 ] && echo ", " 1450 printf "172.%i.%i.%i . %i . 192.168.%i.%i " $((RANDOM%256)) $((RANDOM%256)) $((i%256)) $(((RANDOM%65534) + 1)) $((RANDOM%256)) $((RANDOM%256)) 1451 done 1452 ;; 1453 "ipv6_addr . ether_addr") 1454 for i in $(seq 1 $dcount); do 1455 [ $i -gt 1 ] && echo ", " 1456 format_addr6 $((i + 1000000)) 1457 echo -n " . " 1458 format_mac $((1000000 + i)) 1459 done 1460 ;; 1461 "ipv6_addr . inet_service") 1462 dcount=32768 1463 for i in $(seq 1 $dcount); do 1464 [ $i -gt 1 ] && echo ", " 1465 format_addr6 $((i + 1000000)) 1466 echo -n " . $(((RANDOM%65534) + 1))" 1467 done 1468 ;; 1469 "ipv6_addr . inet_service . ether_addr") 1470 dcount=32768 1471 for i in $(seq 1 $dcount); do 1472 [ $i -gt 1 ] && echo ", " 1473 format_addr6 $((i + 1000000)) 1474 echo -n " . $(((RANDOM%65534) + 1)) . " 1475 format_mac $((i + 1000000)) 1476 done 1477 ;; 1478 "ipv6_addr . inet_service . ether_addr . inet_proto") 1479 dcount=65536 1480 for i in $(seq 1 $dcount); do 1481 [ $i -gt 1 ] && echo ", " 1482 format_addr6 $((i + 1000000)) 1483 echo -n " . $(((RANDOM%65534) + 1)) . " 1484 format_mac $((i + 1000000)) 1485 echo -n " . $((RANDOM%256))" 1486 done 1487 ;; 1488 "ipv6_addr . inet_service . ipv6_addr . inet_service") 1489 dcount=32768 1490 for i in $(seq 1 $dcount); do 1491 [ $i -gt 1 ] && echo ", " 1492 format_addr6 $((i + 1000000)) 1493 echo -n " . $(((RANDOM%65534) + 1)) . " 1494 format_addr6 $((i + 2123456)) 1495 echo -n " . $((RANDOM%256))" 1496 done 1497 ;; 1498 *) 1499 "Unhandled $type_spec" 1500 return 1 1501 esac 1502 echo -n "}" 1503 1504 ) | nft -f - || return 1 1505 1506 test_correctness_main 1507} 1508 1509# Concurrency test template: 1510# - add all the elements 1511# - start a thread for each physical thread that: 1512# - adds all the elements 1513# - flushes the set 1514# - adds all the elements 1515# - flushes the entire ruleset 1516# - adds the set back 1517# - adds all the elements 1518# - delete all the elements 1519test_concurrency() { 1520 proto=${flood_proto} 1521 tools=${flood_tools} 1522 chain_spec=${flood_spec} 1523 setup veth flood_"${proto}" set || return ${ksft_skip} 1524 1525 range_size=1 1526 cstart=${start} 1527 flood_pids= 1528 for i in $(seq "$start" $((start + count))); do 1529 end=$((start + range_size)) 1530 srcstart=$((start + src_delta)) 1531 srcend=$((end + src_delta)) 1532 1533 add "$(format)" || return 1 1534 1535 flood "${i}" $((i + src_delta)) & flood_pids="${flood_pids} $!" 1536 1537 range_size=$((range_size + 1)) 1538 start=$((end + range_size)) 1539 done 1540 1541 sleep $((RANDOM%10)) 1542 1543 pids= 1544 for c in $(seq 1 "$(nproc)"); do ( 1545 for r in $(seq 1 "${race_repeat}"); do 1546 range_size=1 1547 1548 # $start needs to be local to this subshell 1549 # shellcheck disable=SC2030 1550 start=${cstart} 1551 for i in $(seq "$start" $((start + count))); do 1552 end=$((start + range_size)) 1553 srcstart=$((start + src_delta)) 1554 srcend=$((end + src_delta)) 1555 1556 add "$(format)" 2>/dev/null 1557 1558 range_size=$((range_size + 1)) 1559 start=$((end + range_size)) 1560 done 1561 1562 nft flush inet filter test 2>/dev/null 1563 1564 range_size=1 1565 start=${cstart} 1566 for i in $(seq "$start" $((start + count))); do 1567 end=$((start + range_size)) 1568 srcstart=$((start + src_delta)) 1569 srcend=$((end + src_delta)) 1570 1571 add "$(format)" 2>/dev/null 1572 1573 range_size=$((range_size + 1)) 1574 start=$((end + range_size)) 1575 done 1576 1577 nft flush ruleset 1578 setup set 2>/dev/null 1579 1580 range_size=1 1581 start=${cstart} 1582 for i in $(seq "$start" $((start + count))); do 1583 end=$((start + range_size)) 1584 srcstart=$((start + src_delta)) 1585 srcend=$((end + src_delta)) 1586 1587 add "$(format)" 2>/dev/null 1588 1589 range_size=$((range_size + 1)) 1590 start=$((end + range_size)) 1591 done 1592 1593 range_size=1 1594 start=${cstart} 1595 for i in $(seq "$start" $((start + count))); do 1596 end=$((start + range_size)) 1597 srcstart=$((start + src_delta)) 1598 srcend=$((end + src_delta)) 1599 1600 del "$(format)" 2>/dev/null 1601 1602 range_size=$((range_size + 1)) 1603 start=$((end + range_size)) 1604 done 1605 done 1606 ) & pids="${pids} $!" 1607 done 1608 1609 # shellcheck disable=SC2046,SC2086 # word splitting wanted here 1610 wait $(for pid in ${pids}; do echo ${pid}; done) 1611 # shellcheck disable=SC2046,SC2086 1612 kill $(for pid in ${flood_pids}; do echo ${pid}; done) 2>/dev/null 1613 # shellcheck disable=SC2046,SC2086 1614 wait $(for pid in ${flood_pids}; do echo ${pid}; done) 2>/dev/null 1615 1616 return 0 1617} 1618 1619# Timeout test template: 1620# - add all the elements with 3s timeout while checking that packets match 1621# - wait 3s after the last insertion, check that packets don't match any entry 1622test_timeout() { 1623 setup veth send_"${proto}" set || return ${ksft_skip} 1624 1625 timeout=3 1626 1627 [ "$KSFT_MACHINE_SLOW" = "yes" ] && timeout=8 1628 1629 range_size=1 1630 for i in $(seq "$start" $((start + count))); do 1631 local elem="" 1632 1633 end=$((start + range_size)) 1634 srcstart=$((start + src_delta)) 1635 srcend=$((end + src_delta)) 1636 1637 elem="$(format)" 1638 add "$elem" || return 1 1639 1640 for j in $(seq "$start" $((range_size / 2 + 1)) ${end}); do 1641 send_match "$elem" "${j}" $((j + src_delta)) || return 1 1642 done 1643 1644 range_size=$((range_size + 1)) 1645 start=$((end + range_size)) 1646 done 1647 sleep $timeout 1648 for i in $(seq "$start" $((start + count))); do 1649 end=$((start + range_size)) 1650 srcstart=$((start + src_delta)) 1651 srcend=$((end + src_delta)) 1652 1653 for j in $(seq "$start" $((range_size / 2 + 1)) ${end}); do 1654 send_nomatch "${j}" $((j + src_delta)) || return 1 1655 done 1656 1657 range_size=$((range_size + 1)) 1658 start=$((end + range_size)) 1659 done 1660} 1661 1662# Performance test template: 1663# - add concatenated ranged entries 1664# - add non-ranged concatenated entries (for hash set matching rate baseline) 1665# - add ranged entries with first field only (for rbhash baseline) 1666# - start pktgen injection directly on device rx path of this namespace 1667# - measure drop only rate, hash and rbtree baselines, then matching rate 1668test_performance() { 1669 chain_spec=${perf_spec} 1670 dst="${perf_dst}" 1671 src="${perf_src}" 1672 setup veth perf set || return ${ksft_skip} 1673 1674 first=${start} 1675 range_size=1 1676 for set in test norange noconcat; do 1677 start=${first} 1678 for i in $(seq "$start" $((start + perf_entries))); do 1679 end=$((start + range_size)) 1680 srcstart=$((start + src_delta)) 1681 srcend=$((end + src_delta)) 1682 1683 if [ $((end / 65534)) -gt $((start / 65534)) ]; then 1684 start=${end} 1685 end=$((end + 1)) 1686 elif [ "$start" -eq "$end" ]; then 1687 end=$((start + 1)) 1688 fi 1689 1690 add_perf ${set} 1691 1692 start=$((end + range_size)) 1693 done > "${tmp}" 1694 nft -f "${tmp}" 1695 done 1696 1697 perf $((end - 1)) "$srcstart" 1698 1699 sleep 2 1700 1701 nft add rule netdev perf test counter name \"test\" drop 1702 nft reset counter netdev perf test >/dev/null 2>&1 1703 sleep "${perf_duration}" 1704 pps="$(printf %10s $(($(count_perf_packets) / perf_duration)))" 1705 info " baseline (drop from netdev hook): ${pps}pps" 1706 handle="$(nft -a list chain netdev perf test | grep counter)" 1707 handle="${handle##* }" 1708 nft delete rule netdev perf test handle "${handle}" 1709 1710 nft add rule "netdev perf test ${chain_spec} @norange \ 1711 counter name \"test\" drop" 1712 nft reset counter netdev perf test >/dev/null 2>&1 1713 sleep "${perf_duration}" 1714 pps="$(printf %10s $(($(count_perf_packets) / perf_duration)))" 1715 info " baseline hash (non-ranged entries): ${pps}pps" 1716 handle="$(nft -a list chain netdev perf test | grep counter)" 1717 handle="${handle##* }" 1718 nft delete rule netdev perf test handle "${handle}" 1719 1720 nft add rule "netdev perf test ${chain_spec%%. *} @noconcat \ 1721 counter name \"test\" drop" 1722 nft reset counter netdev perf test >/dev/null 2>&1 1723 sleep "${perf_duration}" 1724 pps="$(printf %10s $(($(count_perf_packets) / perf_duration)))" 1725 info " baseline rbtree (match on first field only): ${pps}pps" 1726 handle="$(nft -a list chain netdev perf test | grep counter)" 1727 handle="${handle##* }" 1728 nft delete rule netdev perf test handle "${handle}" 1729 1730 nft add rule "netdev perf test ${chain_spec} @test \ 1731 counter name \"test\" drop" 1732 nft reset counter netdev perf test >/dev/null 2>&1 1733 sleep "${perf_duration}" 1734 pps="$(printf %10s $(($(count_perf_packets) / perf_duration)))" 1735 p5="$(printf %5s "${perf_entries}")" 1736 info " set with ${p5} full, ranged entries: ${pps}pps" 1737 kill "${perf_pid}" 1738} 1739 1740test_bug_flush_remove_add() { 1741 rounds=100 1742 [ "$KSFT_MACHINE_SLOW" = "yes" ] && rounds=10 1743 1744 set_cmd='{ set s { type ipv4_addr . inet_service; flags interval; }; }' 1745 elem1='{ 10.0.0.1 . 22-25, 10.0.0.1 . 10-20 }' 1746 elem2='{ 10.0.0.1 . 10-20, 10.0.0.1 . 22-25 }' 1747 for i in $(seq 1 $rounds); do 1748 nft add table t "$set_cmd" || return ${ksft_skip} 1749 nft add element t s "$elem1" 2>/dev/null || return 1 1750 nft flush set t s 2>/dev/null || return 1 1751 nft add element t s "$elem2" 2>/dev/null || return 1 1752 done 1753 nft flush ruleset 1754} 1755 1756# - add ranged element, check that packets match it 1757# - reload the set, check packets still match 1758test_bug_reload() { 1759 setup veth send_"${proto}" set || return ${ksft_skip} 1760 rstart=${start} 1761 1762 range_size=1 1763 for i in $(seq "${start}" $((start + count))); do 1764 end=$((start + range_size)) 1765 1766 # Avoid negative or zero-sized port ranges 1767 if [ $((end / 65534)) -gt $((start / 65534)) ]; then 1768 start=${end} 1769 end=$((end + 1)) 1770 fi 1771 srcstart=$((start + src_delta)) 1772 srcend=$((end + src_delta)) 1773 1774 add "$(format)" || return 1 1775 range_size=$((range_size + 1)) 1776 start=$((end + range_size)) 1777 done 1778 1779 # check kernel does allocate pcpu sctrach map 1780 # for reload with no elemet add/delete 1781 ( echo flush set inet filter test ; 1782 nft list set inet filter test ) | nft -f - 1783 1784 start=${rstart} 1785 range_size=1 1786 1787 for i in $(seq "${start}" $((start + count))); do 1788 end=$((start + range_size)) 1789 1790 # Avoid negative or zero-sized port ranges 1791 if [ $((end / 65534)) -gt $((start / 65534)) ]; then 1792 start=${end} 1793 end=$((end + 1)) 1794 fi 1795 srcstart=$((start + src_delta)) 1796 srcend=$((end + src_delta)) 1797 1798 for j in $(seq "$start" $((range_size / 2 + 1)) ${end}); do 1799 send_match "$(format)" "${j}" $((j + src_delta)) || return 1 1800 done 1801 1802 range_size=$((range_size + 1)) 1803 start=$((end + range_size)) 1804 done 1805 1806 nft flush ruleset 1807} 1808 1809# - add ranged element, check that packets match it 1810# - delete element again, check it is gone 1811test_bug_net_port_proto_match() { 1812 setup veth send_"${proto}" set || return ${ksft_skip} 1813 rstart=${start} 1814 1815 range_size=1 1816 for i in $(seq 1 10); do 1817 for j in $(seq 1 20) ; do 1818 local dport=$j 1819 1820 elem=$(printf "10.%d.%d.0/24 . %d-%d0 . 6-17 " ${i} ${j} ${dport} "$((dport+1))") 1821 1822 # too slow, do not test all addresses 1823 maybe_send_nomatch "$elem" $(printf "10.%d.%d.1" $i $j) $(printf "%d1" $((dport+1))) "before add" || return 1 1824 1825 nft "add element inet filter test { $elem }" || return 1 1826 1827 maybe_send_match "$elem" $(printf "10.%d.%d.1" $i $j) $(printf "%d" $dport) "after add" || return 1 1828 1829 nft "get element inet filter test { $elem }" | grep -q "$elem" 1830 if [ $? -ne 0 ];then 1831 local got=$(nft "get element inet filter test { $elem }") 1832 err "post-add: should have returned $elem but got $got" 1833 return 1 1834 fi 1835 1836 maybe_send_nomatch "$elem" $(printf "10.%d.%d.1" $i $j) $(printf "%d1" $((dport+1))) "out-of-range" || return 1 1837 done 1838 done 1839 1840 # recheck after set was filled 1841 for i in $(seq 1 10); do 1842 for j in $(seq 1 20) ; do 1843 local dport=$j 1844 1845 elem=$(printf "10.%d.%d.0/24 . %d-%d0 . 6-17 " ${i} ${j} ${dport} "$((dport+1))") 1846 1847 nft "get element inet filter test { $elem }" | grep -q "$elem" 1848 if [ $? -ne 0 ];then 1849 local got=$(nft "get element inet filter test { $elem }") 1850 err "post-fill: should have returned $elem but got $got" 1851 return 1 1852 fi 1853 1854 maybe_send_match "$elem" $(printf "10.%d.%d.1" $i $j) $(printf "%d" $dport) "recheck" || return 1 1855 maybe_send_nomatch "$elem" $(printf "10.%d.%d.1" $i $j) $(printf "%d1" $((dport+1))) "recheck out-of-range" || return 1 1856 done 1857 done 1858 1859 # random del and re-fetch 1860 for i in $(seq 1 10); do 1861 for j in $(seq 1 20) ; do 1862 local rnd=$((RANDOM%10)) 1863 local dport=$j 1864 local got="" 1865 1866 elem=$(printf "10.%d.%d.0/24 . %d-%d0 . 6-17 " ${i} ${j} ${dport} "$((dport+1))") 1867 if [ $rnd -gt 0 ];then 1868 continue 1869 fi 1870 1871 nft "delete element inet filter test { $elem }" 1872 got=$(nft "get element inet filter test { $elem }" 2>/dev/null) 1873 if [ $? -eq 0 ];then 1874 err "post-delete: query for $elem returned $got instead of error." 1875 return 1 1876 fi 1877 1878 maybe_send_nomatch "$elem" $(printf "10.%d.%d.1" $i $j) $(printf "%d" $dport) "match after deletion" || return 1 1879 done 1880 done 1881 1882 nft flush ruleset 1883} 1884 1885test_bug_avx2_mismatch() 1886{ 1887 setup veth send_"${proto}" set || return ${ksft_skip} 1888 1889 local a1="fe80:dead:01ff:0a02:0b03:6007:8009:a001" 1890 local a2="fe80:dead:01fe:0a02:0b03:6007:8009:a001" 1891 1892 nft "add element inet filter test { icmpv6 . $a1 }" 1893 1894 dst_addr6="$a2" 1895 send_icmp6 1896 1897 if [ "$(count_packets "{ icmpv6 . $a1 }")" -gt "0" ]; then 1898 err "False match for $a2" 1899 return 1 1900 fi 1901} 1902 1903test_reported_issues() { 1904 eval test_bug_"${subtest}" 1905} 1906 1907# Run everything in a separate network namespace 1908[ "${1}" != "run" ] && { unshare -n "${0}" run; exit $?; } 1909tmp="$(mktemp)" 1910trap cleanup_exit EXIT 1911 1912# Entry point for test runs 1913passed=0 1914for name in ${TESTS}; do 1915 printf "TEST: %s\n" "$(echo "$name" | tr '_' ' ')" 1916 if [ "${name}" = "reported_issues" ]; then 1917 SUBTESTS="${BUGS}" 1918 else 1919 SUBTESTS="${TYPES}" 1920 fi 1921 1922 for subtest in ${SUBTESTS}; do 1923 eval desc=\$TYPE_"${subtest}" 1924 IFS=' 1925' 1926 for __line in ${desc}; do 1927 # shellcheck disable=SC2086 1928 eval ${__line%% *}=\"${__line##* }\"; 1929 done 1930 IFS=' 1931' 1932 1933 if [ "${name}" = "concurrency" ] && \ 1934 [ "${race_repeat}" = "0" ]; then 1935 continue 1936 fi 1937 if [ "${name}" = "performance" ] && \ 1938 [ "${perf_duration}" = "0" ]; then 1939 continue 1940 fi 1941 1942 [ "$KSFT_MACHINE_SLOW" = "yes" ] && count=1 1943 1944 printf " %-32s " "${display}" 1945 tthen=$(date +%s) 1946 eval test_"${name}" 1947 ret=$? 1948 1949 tnow=$(date +%s) 1950 printf "%5ds%-30s" $((tnow-tthen)) 1951 1952 if [ $ret -eq 0 ]; then 1953 printf "[ OK ]\n" 1954 info_flush 1955 passed=$((passed + 1)) 1956 elif [ $ret -eq 1 ]; then 1957 printf "[FAIL]\n" 1958 err_flush 1959 exit 1 1960 elif [ $ret -eq ${ksft_skip} ]; then 1961 printf "[SKIP]\n" 1962 err_flush 1963 fi 1964 done 1965done 1966 1967[ ${passed} -eq 0 ] && exit ${ksft_skip} || exit 0 1968