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 doublecreate insert_overlap" 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 411TYPE_doublecreate=" 412display cannot create same element twice 413type_spec ipv4_addr . ipv4_addr 414chain_spec ip saddr . ip daddr 415dst addr4 416proto icmp 417 418race_repeat 0 419 420perf_duration 0 421" 422 423TYPE_insert_overlap=" 424display reject overlapping range on add 425type_spec ipv4_addr . ipv4_addr 426chain_spec ip saddr . ip daddr 427dst addr4 428proto icmp 429 430race_repeat 0 431 432perf_duration 0 433" 434 435# Set template for all tests, types and rules are filled in depending on test 436set_template=' 437flush ruleset 438 439table inet filter { 440 counter test { 441 packets 0 bytes 0 442 } 443 444 set test { 445 type ${type_spec} 446 counter 447 flags interval,timeout 448 } 449 450 chain input { 451 type filter hook prerouting priority 0; policy accept; 452 ${chain_spec} @test counter name \"test\" 453 } 454} 455 456table netdev perf { 457 counter test { 458 packets 0 bytes 0 459 } 460 461 counter match { 462 packets 0 bytes 0 463 } 464 465 set test { 466 type ${type_spec} 467 flags interval 468 } 469 470 set norange { 471 type ${type_spec} 472 } 473 474 set noconcat { 475 type ${type_spec%% *} 476 flags interval 477 } 478 479 chain test { 480 type filter hook ingress device veth_a priority 0; 481 } 482} 483' 484 485err_buf= 486info_buf= 487 488# Append string to error buffer 489err() { 490 err_buf="${err_buf}${1} 491" 492} 493 494# Append string to information buffer 495info() { 496 info_buf="${info_buf}${1} 497" 498} 499 500# Flush error buffer to stdout 501err_flush() { 502 printf "%s" "${err_buf}" 503 err_buf= 504} 505 506# Flush information buffer to stdout 507info_flush() { 508 printf "%s" "${info_buf}" 509 info_buf= 510} 511 512# Setup veth pair: this namespace receives traffic, B generates it 513setup_veth() { 514 ip netns add B 515 ip link add veth_a type veth peer name veth_b || return 1 516 517 ip link set veth_a up 518 ip link set veth_b netns B 519 520 ip -n B link set veth_b up 521 522 ip addr add dev veth_a 10.0.0.1 523 ip route add default dev veth_a 524 525 ip -6 addr add fe80::1/64 dev veth_a nodad 526 ip -6 addr add 2001:db8::1/64 dev veth_a nodad 527 ip -6 route add default dev veth_a 528 529 ip -n B route add default dev veth_b 530 531 ip -6 -n B addr add fe80::2/64 dev veth_b nodad 532 ip -6 -n B addr add 2001:db8::2/64 dev veth_b nodad 533 ip -6 -n B route add default dev veth_b 534 535 B() { 536 ip netns exec B "$@" >/dev/null 2>&1 537 } 538} 539 540# Fill in set template and initialise set 541setup_set() { 542 eval "echo \"${set_template}\"" | nft -f - 543} 544 545# Check that at least one of the needed tools is available 546check_tools() { 547 [ -z "${tools}" ] && return 0 548 549 __tools= 550 for tool in ${tools}; do 551 __tools="${__tools} ${tool}" 552 553 command -v "${tool}" >/dev/null && return 0 554 done 555 err "need one of:${__tools}, skipping" && return 1 556} 557 558# Set up function to send ICMP packets 559setup_send_icmp() { 560 send_icmp() { 561 B ping -c1 -W1 "${dst_addr4}" >/dev/null 2>&1 562 } 563} 564 565# Set up function to send ICMPv6 packets 566setup_send_icmp6() { 567 if command -v ping6 >/dev/null; then 568 send_icmp6() { 569 ip -6 addr add "${dst_addr6}" dev veth_a nodad \ 570 2>/dev/null 571 B ping6 -q -c1 -W1 "${dst_addr6}" 572 } 573 else 574 send_icmp6() { 575 ip -6 addr add "${dst_addr6}" dev veth_a nodad \ 576 2>/dev/null 577 B ping -q -6 -c1 -W1 "${dst_addr6}" 578 } 579 fi 580} 581 582# Set up function to send single UDP packets on IPv4 583setup_send_udp() { 584 if command -v sendip >/dev/null; then 585 send_udp() { 586 [ -n "${src_port}" ] && src_port="-us ${src_port}" 587 [ -n "${dst_port}" ] && dst_port="-ud ${dst_port}" 588 [ -n "${src_addr4}" ] && src_addr4="-is ${src_addr4}" 589 590 # shellcheck disable=SC2086 # sendip needs split options 591 B sendip -p ipv4 -p udp ${src_addr4} ${src_port} \ 592 ${dst_port} "${dst_addr4}" 593 594 src_port= 595 dst_port= 596 src_addr4= 597 } 598 elif command -v socat -v >/dev/null; then 599 send_udp() { 600 if [ -n "${src_addr4}" ]; then 601 B ip addr add "${src_addr4}" dev veth_b 602 __socatbind=",bind=${src_addr4}" 603 if [ -n "${src_port}" ];then 604 __socatbind="${__socatbind}:${src_port}" 605 fi 606 fi 607 608 ip addr add "${dst_addr4}" dev veth_a 2>/dev/null 609 [ -z "${dst_port}" ] && dst_port=12345 610 611 echo "test4" | B socat -t 0.01 STDIN UDP4-DATAGRAM:"$dst_addr4":"$dst_port""${__socatbind}" 612 613 src_addr4= 614 src_port= 615 } 616 elif [ -z "$(bash -c 'type -p')" ]; then 617 send_udp() { 618 ip addr add "${dst_addr4}" dev veth_a 2>/dev/null 619 if [ -n "${src_addr4}" ]; then 620 B ip addr add "${src_addr4}/16" dev veth_b 621 B ip route add default dev veth_b 622 fi 623 624 B bash -c "echo > /dev/udp/${dst_addr4}/${dst_port}" 625 626 if [ -n "${src_addr4}" ]; then 627 B ip addr del "${src_addr4}/16" dev veth_b 628 fi 629 src_addr4= 630 } 631 else 632 return 1 633 fi 634} 635 636# Set up function to send single UDP packets on IPv6 637setup_send_udp6() { 638 if command -v sendip >/dev/null; then 639 send_udp6() { 640 [ -n "${src_port}" ] && src_port="-us ${src_port}" 641 [ -n "${dst_port}" ] && dst_port="-ud ${dst_port}" 642 if [ -n "${src_addr6}" ]; then 643 src_addr6="-6s ${src_addr6}" 644 else 645 src_addr6="-6s 2001:db8::2" 646 fi 647 ip -6 addr add "${dst_addr6}" dev veth_a nodad \ 648 2>/dev/null 649 650 # shellcheck disable=SC2086 # this needs split options 651 B sendip -p ipv6 -p udp ${src_addr6} ${src_port} \ 652 ${dst_port} "${dst_addr6}" 653 654 src_port= 655 dst_port= 656 src_addr6= 657 } 658 elif command -v socat -v >/dev/null; then 659 send_udp6() { 660 ip -6 addr add "${dst_addr6}" dev veth_a nodad \ 661 2>/dev/null 662 663 __socatbind6= 664 665 if [ -n "${src_addr6}" ]; then 666 B ip addr add "${src_addr6}" dev veth_b nodad 667 668 __socatbind6=",bind=[${src_addr6}]" 669 670 if [ -n "${src_port}" ] ;then 671 __socatbind6="${__socatbind6}:${src_port}" 672 fi 673 fi 674 675 echo "test6" | B socat -t 0.01 STDIN UDP6-DATAGRAM:["$dst_addr6"]:"$dst_port""${__socatbind6}" 676 } 677 elif [ -z "$(bash -c 'type -p')" ]; then 678 send_udp6() { 679 ip -6 addr add "${dst_addr6}" dev veth_a nodad \ 680 2>/dev/null 681 B ip addr add "${src_addr6}" dev veth_b nodad 682 B bash -c "echo > /dev/udp/${dst_addr6}/${dst_port}" 683 ip -6 addr del "${dst_addr6}" dev veth_a 2>/dev/null 684 } 685 else 686 return 1 687 fi 688} 689 690listener_ready() 691{ 692 port="$1" 693 ss -lnt -o "sport = :$port" | grep -q "$port" 694} 695 696# Set up function to send TCP traffic on IPv4 697setup_flood_tcp() { 698 if command -v iperf3 >/dev/null; then 699 flood_tcp() { 700 local n_port="${dst_port}" 701 [ -n "${dst_port}" ] && dst_port="-p ${dst_port}" 702 if [ -n "${src_addr4}" ]; then 703 B ip addr add "${src_addr4}/16" dev veth_b 704 src_addr4="-B ${src_addr4}" 705 else 706 B ip addr add dev veth_b 10.0.0.2 707 src_addr4="-B 10.0.0.2" 708 fi 709 if [ -n "${src_port}" ]; then 710 src_port="--cport ${src_port}" 711 fi 712 B ip route add default dev veth_b 2>/dev/null 713 ip addr add "${dst_addr4}" dev veth_a 2>/dev/null 714 715 # shellcheck disable=SC2086 # this needs split options 716 iperf3 -s -DB "${dst_addr4}" ${dst_port} >/dev/null 2>&1 717 busywait "$BUSYWAIT_TIMEOUT" listener_ready "$n_port" 718 719 # shellcheck disable=SC2086 # this needs split options 720 B iperf3 -c "${dst_addr4}" ${dst_port} ${src_port} \ 721 ${src_addr4} -l16 -t 1000 722 723 src_addr4= 724 src_port= 725 dst_port= 726 } 727 elif command -v iperf >/dev/null; then 728 flood_tcp() { 729 local n_port="${dst_port}" 730 [ -n "${dst_port}" ] && dst_port="-p ${dst_port}" 731 if [ -n "${src_addr4}" ]; then 732 B ip addr add "${src_addr4}/16" dev veth_b 733 src_addr4="-B ${src_addr4}" 734 else 735 B ip addr add dev veth_b 10.0.0.2 2>/dev/null 736 src_addr4="-B 10.0.0.2" 737 fi 738 if [ -n "${src_port}" ]; then 739 src_addr4="${src_addr4}:${src_port}" 740 fi 741 B ip route add default dev veth_b 742 ip addr add "${dst_addr4}" dev veth_a 2>/dev/null 743 744 # shellcheck disable=SC2086 # this needs split options 745 iperf -s -DB "${dst_addr4}" ${dst_port} >/dev/null 2>&1 746 busywait "$BUSYWAIT_TIMEOUT" listener_ready "$n_port" 747 748 # shellcheck disable=SC2086 # this needs split options 749 B iperf -c "${dst_addr4}" ${dst_port} ${src_addr4} \ 750 -l20 -t 1000 751 752 src_addr4= 753 src_port= 754 dst_port= 755 } 756 elif command -v netperf >/dev/null; then 757 flood_tcp() { 758 local n_port="${dst_port}" 759 [ -n "${dst_port}" ] && dst_port="-p ${dst_port}" 760 if [ -n "${src_addr4}" ]; then 761 B ip addr add "${src_addr4}/16" dev veth_b 762 else 763 B ip addr add dev veth_b 10.0.0.2 764 src_addr4="10.0.0.2" 765 fi 766 if [ -n "${src_port}" ]; then 767 dst_port="${dst_port},${src_port}" 768 fi 769 B ip route add default dev veth_b 770 ip addr add "${dst_addr4}" dev veth_a 2>/dev/null 771 772 # shellcheck disable=SC2086 # this needs split options 773 netserver -4 ${dst_port} -L "${dst_addr4}" \ 774 >/dev/null 2>&1 775 busywait "$BUSYWAIT_TIMEOUT" listener_ready "${n_port}" 776 777 # shellcheck disable=SC2086 # this needs split options 778 B netperf -4 -H "${dst_addr4}" ${dst_port} \ 779 -L "${src_addr4}" -l 1000 -t TCP_STREAM 780 781 src_addr4= 782 src_port= 783 dst_port= 784 } 785 else 786 return 1 787 fi 788} 789 790# Set up function to send TCP traffic on IPv6 791setup_flood_tcp6() { 792 if command -v iperf3 >/dev/null; then 793 flood_tcp6() { 794 local n_port="${dst_port}" 795 [ -n "${dst_port}" ] && dst_port="-p ${dst_port}" 796 if [ -n "${src_addr6}" ]; then 797 B ip addr add "${src_addr6}" dev veth_b nodad 798 src_addr6="-B ${src_addr6}" 799 else 800 src_addr6="-B 2001:db8::2" 801 fi 802 if [ -n "${src_port}" ]; then 803 src_port="--cport ${src_port}" 804 fi 805 B ip route add default dev veth_b 806 ip -6 addr add "${dst_addr6}" dev veth_a nodad \ 807 2>/dev/null 808 809 # shellcheck disable=SC2086 # this needs split options 810 iperf3 -s -DB "${dst_addr6}" ${dst_port} >/dev/null 2>&1 811 busywait "$BUSYWAIT_TIMEOUT" listener_ready "${n_port}" 812 813 # shellcheck disable=SC2086 # this needs split options 814 B iperf3 -c "${dst_addr6}" ${dst_port} \ 815 ${src_port} ${src_addr6} -l16 -t 1000 816 817 src_addr6= 818 src_port= 819 dst_port= 820 } 821 elif command -v iperf >/dev/null; then 822 flood_tcp6() { 823 local n_port="${dst_port}" 824 [ -n "${dst_port}" ] && dst_port="-p ${dst_port}" 825 if [ -n "${src_addr6}" ]; then 826 B ip addr add "${src_addr6}" dev veth_b nodad 827 src_addr6="-B ${src_addr6}" 828 else 829 src_addr6="-B 2001:db8::2" 830 fi 831 if [ -n "${src_port}" ]; then 832 src_addr6="${src_addr6}:${src_port}" 833 fi 834 B ip route add default dev veth_b 835 ip -6 addr add "${dst_addr6}" dev veth_a nodad \ 836 2>/dev/null 837 838 # shellcheck disable=SC2086 # this needs split options 839 iperf -s -VDB "${dst_addr6}" ${dst_port} >/dev/null 2>&1 840 busywait "$BUSYWAIT_TIMEOUT" listener_ready "$n_port" 841 842 # shellcheck disable=SC2086 # this needs split options 843 B iperf -c "${dst_addr6}" -V ${dst_port} \ 844 ${src_addr6} -l1 -t 1000 845 846 src_addr6= 847 src_port= 848 dst_port= 849 } 850 elif command -v netperf >/dev/null; then 851 flood_tcp6() { 852 local n_port="${dst_port}" 853 [ -n "${dst_port}" ] && dst_port="-p ${dst_port}" 854 if [ -n "${src_addr6}" ]; then 855 B ip addr add "${src_addr6}" dev veth_b nodad 856 else 857 src_addr6="2001:db8::2" 858 fi 859 if [ -n "${src_port}" ]; then 860 dst_port="${dst_port},${src_port}" 861 fi 862 B ip route add default dev veth_b 863 ip -6 addr add "${dst_addr6}" dev veth_a nodad \ 864 2>/dev/null 865 866 # shellcheck disable=SC2086 # this needs split options 867 netserver -6 ${dst_port} -L "${dst_addr6}" \ 868 >/dev/null 2>&1 869 busywait "$BUSYWAIT_TIMEOUT" listener_ready "$n_port" 870 871 # shellcheck disable=SC2086 # this needs split options 872 B netperf -6 -H "${dst_addr6}" ${dst_port} \ 873 -L "${src_addr6}" -l 1000 -t TCP_STREAM 874 875 src_addr6= 876 src_port= 877 dst_port= 878 } 879 else 880 return 1 881 fi 882} 883 884# Set up function to send UDP traffic on IPv4 885setup_flood_udp() { 886 if command -v iperf3 >/dev/null; then 887 flood_udp() { 888 local n_port="${dst_port}" 889 [ -n "${dst_port}" ] && dst_port="-p ${dst_port}" 890 if [ -n "${src_addr4}" ]; then 891 B ip addr add "${src_addr4}/16" dev veth_b 892 src_addr4="-B ${src_addr4}" 893 else 894 B ip addr add dev veth_b 10.0.0.2 2>/dev/null 895 src_addr4="-B 10.0.0.2" 896 fi 897 if [ -n "${src_port}" ]; then 898 src_port="--cport ${src_port}" 899 fi 900 B ip route add default dev veth_b 901 ip addr add "${dst_addr4}" dev veth_a 2>/dev/null 902 903 # shellcheck disable=SC2086 # this needs split options 904 iperf3 -s -DB "${dst_addr4}" ${dst_port} 905 busywait "$BUSYWAIT_TIMEOUT" listener_ready "$n_port" 906 907 # shellcheck disable=SC2086 # this needs split options 908 B iperf3 -u -c "${dst_addr4}" -Z -b 100M -l16 -t1000 \ 909 ${dst_port} ${src_port} ${src_addr4} 910 911 src_addr4= 912 src_port= 913 dst_port= 914 } 915 elif command -v iperf >/dev/null; then 916 flood_udp() { 917 local n_port="${dst_port}" 918 [ -n "${dst_port}" ] && dst_port="-p ${dst_port}" 919 if [ -n "${src_addr4}" ]; then 920 B ip addr add "${src_addr4}/16" dev veth_b 921 src_addr4="-B ${src_addr4}" 922 else 923 B ip addr add dev veth_b 10.0.0.2 924 src_addr4="-B 10.0.0.2" 925 fi 926 if [ -n "${src_port}" ]; then 927 src_addr4="${src_addr4}:${src_port}" 928 fi 929 B ip route add default dev veth_b 930 ip addr add "${dst_addr4}" dev veth_a 2>/dev/null 931 932 # shellcheck disable=SC2086 # this needs split options 933 iperf -u -sDB "${dst_addr4}" ${dst_port} >/dev/null 2>&1 934 busywait "$BUSYWAIT_TIMEOUT" listener_ready "$n_port" 935 936 # shellcheck disable=SC2086 # this needs split options 937 B iperf -u -c "${dst_addr4}" -b 100M -l1 -t1000 \ 938 ${dst_port} ${src_addr4} 939 940 src_addr4= 941 src_port= 942 dst_port= 943 } 944 elif command -v netperf >/dev/null; then 945 flood_udp() { 946 local n_port="${dst_port}" 947 [ -n "${dst_port}" ] && dst_port="-p ${dst_port}" 948 if [ -n "${src_addr4}" ]; then 949 B ip addr add "${src_addr4}/16" dev veth_b 950 else 951 B ip addr add dev veth_b 10.0.0.2 952 src_addr4="10.0.0.2" 953 fi 954 if [ -n "${src_port}" ]; then 955 dst_port="${dst_port},${src_port}" 956 fi 957 B ip route add default dev veth_b 958 ip addr add "${dst_addr4}" dev veth_a 2>/dev/null 959 960 # shellcheck disable=SC2086 # this needs split options 961 netserver -4 ${dst_port} -L "${dst_addr4}" \ 962 >/dev/null 2>&1 963 busywait "$BUSYWAIT_TIMEOUT" listener_ready "$n_port" 964 965 # shellcheck disable=SC2086 # this needs split options 966 B netperf -4 -H "${dst_addr4}" ${dst_port} \ 967 -L "${src_addr4}" -l 1000 -t UDP_STREAM 968 969 src_addr4= 970 src_port= 971 dst_port= 972 } 973 else 974 return 1 975 fi 976} 977 978# Find pktgen script and set up function to start pktgen injection 979setup_perf() { 980 for pktgen_script_path in ${PKTGEN_SCRIPT_PATHS} __notfound; do 981 command -v "${pktgen_script_path}" >/dev/null && break 982 done 983 [ "${pktgen_script_path}" = "__notfound" ] && return 1 984 985 perf_ipv4() { 986 ${pktgen_script_path} -s80 \ 987 -i veth_a -d "${dst_addr4}" -p "${dst_port}" \ 988 -m "${dst_mac}" \ 989 -t $(($(nproc) / 5 + 1)) -b10000 -n0 2>/dev/null & 990 perf_pid=$! 991 } 992 perf_ipv6() { 993 IP6=6 ${pktgen_script_path} -s100 \ 994 -i veth_a -d "${dst_addr6}" -p "${dst_port}" \ 995 -m "${dst_mac}" \ 996 -t $(($(nproc) / 5 + 1)) -b10000 -n0 2>/dev/null & 997 perf_pid=$! 998 } 999} 1000 1001# Clean up before each test 1002cleanup() { 1003 nft reset counter inet filter test >/dev/null 2>&1 1004 nft flush ruleset >/dev/null 2>&1 1005 ip link del dummy0 2>/dev/null 1006 ip route del default 2>/dev/null 1007 ip -6 route del default 2>/dev/null 1008 ip netns pids B 2>/dev/null | xargs kill 2>/dev/null 1009 ip netns del B 2>/dev/null 1010 ip link del veth_a 2>/dev/null 1011 timeout= 1012 killall iperf3 2>/dev/null 1013 killall iperf 2>/dev/null 1014 killall netperf 2>/dev/null 1015 killall netserver 2>/dev/null 1016} 1017 1018cleanup_exit() { 1019 cleanup 1020 rm -f "$tmp" 1021} 1022 1023# Entry point for setup functions 1024setup() { 1025 if [ "$(id -u)" -ne 0 ]; then 1026 echo " need to run as root" 1027 exit ${ksft_skip} 1028 fi 1029 1030 cleanup 1031 check_tools || return 1 1032 for arg do 1033 if ! eval setup_"${arg}"; then 1034 err " ${arg} not supported" 1035 return 1 1036 fi 1037 done 1038} 1039 1040# Format integer into IPv4 address, summing 10.0.0.5 (arbitrary) to it 1041format_addr4() { 1042 a=$((${1} + 16777216 * 10 + 5)) 1043 printf "%i.%i.%i.%i" \ 1044 "$((a / 16777216))" "$((a % 16777216 / 65536))" \ 1045 "$((a % 65536 / 256))" "$((a % 256))" 1046} 1047 1048# Format integer into IPv6 address, summing 2001:db8:: to it 1049format_addr6() { 1050 printf "2001:db8::%04x:%04x" "$((${1} / 65536))" "$((${1} % 65536))" 1051} 1052 1053# Format integer into EUI-48 address, summing 00:01:00:00:00:00 to it 1054format_mac() { 1055 printf "00:01:%02x:%02x:%02x:%02x" \ 1056 "$((${1} / 16777216))" "$((${1} % 16777216 / 65536))" \ 1057 "$((${1} % 65536 / 256))" "$((${1} % 256))" 1058} 1059 1060# Format integer into port, avoid 0 port 1061format_port() { 1062 printf "%i" "$((${1} % 65534 + 1))" 1063} 1064 1065# Drop suffixed '6' from L4 protocol, if any 1066format_proto() { 1067 printf "%s" "${proto}" | tr -d 6 1068} 1069 1070# Format destination and source fields into nft concatenated type 1071format() { 1072 __start= 1073 __end= 1074 __expr="{ " 1075 1076 for f in ${dst}; do 1077 [ "${__expr}" != "{ " ] && __expr="${__expr} . " 1078 1079 __start="$(eval format_"${f}" "${start}")" 1080 __end="$(eval format_"${f}" "${end}")" 1081 1082 if [ "${f}" = "proto" ]; then 1083 __expr="${__expr}${__start}" 1084 else 1085 __expr="${__expr}${__start}-${__end}" 1086 fi 1087 done 1088 for f in ${src}; do 1089 [ "${__expr}" != "{ " ] && __expr="${__expr} . " 1090 1091 __start="$(eval format_"${f}" "${srcstart}")" 1092 __end="$(eval format_"${f}" "${srcend}")" 1093 1094 if [ "${f}" = "proto" ]; then 1095 __expr="${__expr}${__start}" 1096 else 1097 __expr="${__expr}${__start}-${__end}" 1098 fi 1099 done 1100 1101 if [ -n "${timeout}" ]; then 1102 echo "${__expr} timeout ${timeout}s }" 1103 else 1104 echo "${__expr} }" 1105 fi 1106} 1107 1108# Format destination and source fields into nft type, start element only 1109format_norange() { 1110 __expr="{ " 1111 1112 for f in ${dst}; do 1113 [ "${__expr}" != "{ " ] && __expr="${__expr} . " 1114 1115 __expr="${__expr}$(eval format_"${f}" "${start}")" 1116 done 1117 for f in ${src}; do 1118 __expr="${__expr} . $(eval format_"${f}" "${start}")" 1119 done 1120 1121 echo "${__expr} }" 1122} 1123 1124# Format first destination field into nft type 1125format_noconcat() { 1126 for f in ${dst}; do 1127 __start="$(eval format_"${f}" "${start}")" 1128 __end="$(eval format_"${f}" "${end}")" 1129 1130 if [ "${f}" = "proto" ]; then 1131 echo "{ ${__start} }" 1132 else 1133 echo "{ ${__start}-${__end} }" 1134 fi 1135 return 1136 done 1137} 1138 1139# Add single entry to 'test' set in 'inet filter' table 1140add() { 1141 if ! nft add element inet filter test "${1}"; then 1142 err "Failed to add ${1} given ruleset:" 1143 err "$(nft -a list ruleset)" 1144 return 1 1145 fi 1146} 1147 1148# Format and output entries for sets in 'netdev perf' table 1149add_perf() { 1150 if [ "${1}" = "test" ]; then 1151 echo "add element netdev perf test $(format)" 1152 elif [ "${1}" = "norange" ]; then 1153 echo "add element netdev perf norange $(format_norange)" 1154 elif [ "${1}" = "noconcat" ]; then 1155 echo "add element netdev perf noconcat $(format_noconcat)" 1156 fi 1157} 1158 1159# Add single entry to 'norange' set in 'netdev perf' table 1160add_perf_norange() { 1161 if ! nft add element netdev perf norange "${1}"; then 1162 err "Failed to add ${1} given ruleset:" 1163 err "$(nft -a list ruleset)" 1164 return 1 1165 fi 1166} 1167 1168# Add single entry to 'noconcat' set in 'netdev perf' table 1169add_perf_noconcat() { 1170 if ! nft add element netdev perf noconcat "${1}"; then 1171 err "Failed to add ${1} given ruleset:" 1172 err "$(nft -a list ruleset)" 1173 return 1 1174 fi 1175} 1176 1177# Delete single entry from set 1178del() { 1179 if ! nft delete element inet filter test "${1}"; then 1180 err "Failed to delete ${1} given ruleset:" 1181 err "$(nft -a list ruleset)" 1182 return 1 1183 fi 1184} 1185 1186# Return packet count for elem $1 from 'test' counter in 'inet filter' table 1187count_packets() { 1188 found=0 1189 for token in $(nft reset element inet filter test "${1}" ); do 1190 [ ${found} -eq 1 ] && echo "${token}" && return 1191 [ "${token}" = "packets" ] && found=1 1192 done 1193} 1194 1195# Return packet count from 'test' counter in 'inet filter' table 1196count_packets_nomatch() { 1197 found=0 1198 for token in $(nft list counter inet filter test); do 1199 [ ${found} -eq 1 ] && echo "${token}" && return 1200 [ "${token}" = "packets" ] && found=1 1201 done 1202} 1203 1204# Return packet count from 'test' counter in 'netdev perf' table 1205count_perf_packets() { 1206 found=0 1207 for token in $(nft list counter netdev perf test); do 1208 [ ${found} -eq 1 ] && echo "${token}" && return 1209 [ "${token}" = "packets" ] && found=1 1210 done 1211} 1212 1213# Set MAC addresses, send traffic according to specifier 1214flood() { 1215 ip link set veth_a address "$(format_mac "${1}")" 1216 ip -n B link set veth_b address "$(format_mac "${2}")" 1217 1218 for f in ${dst}; do 1219 eval dst_"$f"=\$\(format_\$f "${1}"\) 1220 done 1221 for f in ${src}; do 1222 eval src_"$f"=\$\(format_\$f "${2}"\) 1223 done 1224 eval flood_\$proto 1225} 1226 1227# Set MAC addresses, start pktgen injection 1228perf() { 1229 dst_mac="$(format_mac "${1}")" 1230 ip link set veth_a address "${dst_mac}" 1231 1232 for f in ${dst}; do 1233 eval dst_"$f"=\$\(format_\$f "${1}"\) 1234 done 1235 for f in ${src}; do 1236 eval src_"$f"=\$\(format_\$f "${2}"\) 1237 done 1238 eval perf_\$perf_proto 1239} 1240 1241# Set MAC addresses, send single packet, check that it matches, reset counter 1242send_match() { 1243 local elem="$1" 1244 1245 shift 1246 1247 ip link set veth_a address "$(format_mac "${1}")" 1248 ip -n B link set veth_b address "$(format_mac "${2}")" 1249 1250 for f in ${dst}; do 1251 eval dst_"$f"=\$\(format_\$f "${1}"\) 1252 done 1253 for f in ${src}; do 1254 eval src_"$f"=\$\(format_\$f "${2}"\) 1255 done 1256 eval send_\$proto 1257 if [ "$(count_packets "$elem")" != "1" ]; then 1258 err "${proto} packet to:" 1259 err " $(for f in ${dst}; do 1260 eval format_\$f "${1}"; printf ' '; done)" 1261 err "from:" 1262 err " $(for f in ${src}; do 1263 eval format_\$f "${2}"; printf ' '; done)" 1264 err "should have matched ruleset:" 1265 err "$(nft -a list ruleset)" 1266 return 1 1267 fi 1268 nft reset counter inet filter test >/dev/null 1269} 1270 1271# Set MAC addresses, send single packet, check that it doesn't match 1272send_nomatch() { 1273 ip link set veth_a address "$(format_mac "${1}")" 1274 ip -n B link set veth_b address "$(format_mac "${2}")" 1275 1276 for f in ${dst}; do 1277 eval dst_"$f"=\$\(format_\$f "${1}"\) 1278 done 1279 for f in ${src}; do 1280 eval src_"$f"=\$\(format_\$f "${2}"\) 1281 done 1282 eval send_\$proto 1283 if [ "$(count_packets_nomatch)" != "0" ]; then 1284 err "${proto} packet to:" 1285 err " $(for f in ${dst}; do 1286 eval format_\$f "${1}"; printf ' '; done)" 1287 err "from:" 1288 err " $(for f in ${src}; do 1289 eval format_\$f "${2}"; printf ' '; done)" 1290 err "should not have matched ruleset:" 1291 err "$(nft -a list ruleset)" 1292 return 1 1293 fi 1294} 1295 1296maybe_send_nomatch() { 1297 local elem="$1" 1298 local what="$4" 1299 1300 [ $((RANDOM%20)) -gt 0 ] && return 1301 1302 dst_addr4="$2" 1303 dst_port="$3" 1304 send_udp 1305 1306 if [ "$(count_packets_nomatch)" != "0" ]; then 1307 err "Packet to $dst_addr4:$dst_port did match $what" 1308 err "$(nft -a list ruleset)" 1309 return 1 1310 fi 1311} 1312 1313maybe_send_match() { 1314 local elem="$1" 1315 local what="$4" 1316 1317 [ $((RANDOM%20)) -gt 0 ] && return 1318 1319 dst_addr4="$2" 1320 dst_port="$3" 1321 send_udp 1322 1323 if [ "$(count_packets "{ $elem }")" != "1" ]; then 1324 err "Packet to $dst_addr4:$dst_port did not match $what" 1325 err "$(nft -a list ruleset)" 1326 return 1 1327 fi 1328 nft reset counter inet filter test >/dev/null 1329 nft reset element inet filter test "{ $elem }" >/dev/null 1330} 1331 1332# Correctness test template: 1333# - add ranged element, check that packets match it 1334# - check that packets outside range don't match it 1335# - remove some elements, check that packets don't match anymore 1336test_correctness_main() { 1337 range_size=1 1338 1339 send_nomatch $((end + 1)) $((end + 1 + src_delta)) || return 1 1340 1341 for i in $(seq "${start}" $((start + count))); do 1342 local elem="" 1343 1344 end=$((start + range_size)) 1345 1346 # Avoid negative or zero-sized port ranges 1347 if [ $((end / 65534)) -gt $((start / 65534)) ]; then 1348 start=${end} 1349 end=$((end + 1)) 1350 fi 1351 srcstart=$((start + src_delta)) 1352 srcend=$((end + src_delta)) 1353 1354 elem="$(format)" 1355 add "$elem" || return 1 1356 for j in $(seq "$start" $((range_size / 2 + 1)) ${end}); do 1357 send_match "$elem" "${j}" $((j + src_delta)) || return 1 1358 done 1359 send_nomatch $((end + 1)) $((end + 1 + src_delta)) || return 1 1360 1361 # Delete elements now and then 1362 if [ $((i % 3)) -eq 0 ]; then 1363 del "$elem" || return 1 1364 for j in $(seq "$start" \ 1365 $((range_size / 2 + 1)) ${end}); do 1366 send_nomatch "${j}" $((j + src_delta)) \ 1367 || return 1 1368 done 1369 fi 1370 1371 range_size=$((range_size + 1)) 1372 start=$((end + range_size)) 1373 done 1374} 1375 1376test_correctness() { 1377 setup veth send_"${proto}" set || return ${ksft_skip} 1378 1379 test_correctness_main 1380} 1381 1382# Repeat the correctness tests, but add extra non-matching entries. 1383# This exercises the more compact '4 bit group' representation that 1384# gets picked when the default 8-bit representation exceed 1385# NFT_PIPAPO_LT_SIZE_HIGH bytes of memory. 1386# See usage of NFT_PIPAPO_LT_SIZE_HIGH in pipapo_lt_bits_adjust(). 1387# 1388# The format() helper is way too slow when generating lots of 1389# entries so its not used here. 1390test_correctness_large() { 1391 setup veth send_"${proto}" set || return ${ksft_skip} 1392 # number of dummy (filler) entries to add. 1393 local dcount=16385 1394 1395 ( 1396 echo -n "add element inet filter test { " 1397 1398 case "$type_spec" in 1399 "ether_addr . ipv4_addr") 1400 for i in $(seq 1 $dcount); do 1401 [ $i -gt 1 ] && echo ", " 1402 format_mac $((1000000 + i)) 1403 printf ". 172.%i.%i.%i " $((RANDOM%256)) $((RANDOM%256)) $((i%256)) 1404 done 1405 ;; 1406 "inet_proto . ipv6_addr") 1407 for i in $(seq 1 $dcount); do 1408 [ $i -gt 1 ] && echo ", " 1409 printf "%i . " $((RANDOM%256)) 1410 format_addr6 $((1000000 + i)) 1411 done 1412 ;; 1413 "inet_service . inet_proto") 1414 # smaller key sizes, need more entries to hit the 1415 # 4-bit threshold. 1416 dcount=65536 1417 for i in $(seq 1 $dcount); do 1418 local proto=$((RANDOM%256)) 1419 1420 # Test uses UDP to match, as it also fails when matching 1421 # an entry that doesn't exist, so skip 'udp' entries 1422 # to not trigger a wrong failure. 1423 [ $proto -eq 17 ] && proto=18 1424 [ $i -gt 1 ] && echo ", " 1425 printf "%i . %i " $(((i%65534) + 1)) $((proto)) 1426 done 1427 ;; 1428 "inet_service . ipv4_addr") 1429 dcount=32768 1430 for i in $(seq 1 $dcount); do 1431 [ $i -gt 1 ] && echo ", " 1432 printf "%i . 172.%i.%i.%i " $(((RANDOM%65534) + 1)) $((RANDOM%256)) $((RANDOM%256)) $((i%256)) 1433 done 1434 ;; 1435 "ipv4_addr . ether_addr") 1436 for i in $(seq 1 $dcount); do 1437 [ $i -gt 1 ] && echo ", " 1438 printf "172.%i.%i.%i . " $((RANDOM%256)) $((RANDOM%256)) $((i%256)) 1439 format_mac $((1000000 + i)) 1440 done 1441 ;; 1442 "ipv4_addr . inet_service") 1443 dcount=32768 1444 for i in $(seq 1 $dcount); do 1445 [ $i -gt 1 ] && echo ", " 1446 printf "172.%i.%i.%i . %i" $((RANDOM%256)) $((RANDOM%256)) $((i%256)) $(((RANDOM%65534) + 1)) 1447 done 1448 ;; 1449 "ipv4_addr . inet_service . ether_addr . inet_proto . ipv4_addr") 1450 dcount=65536 1451 for i in $(seq 1 $dcount); do 1452 [ $i -gt 1 ] && echo ", " 1453 printf "172.%i.%i.%i . %i . " $((RANDOM%256)) $((RANDOM%256)) $((i%256)) $(((RANDOM%65534) + 1)) 1454 format_mac $((1000000 + i)) 1455 printf ". %i . 192.168.%i.%i" $((RANDOM%256)) $((RANDOM%256)) $((i%256)) 1456 done 1457 ;; 1458 "ipv4_addr . inet_service . inet_proto") 1459 for i in $(seq 1 $dcount); do 1460 [ $i -gt 1 ] && echo ", " 1461 printf "172.%i.%i.%i . %i . %i " $((RANDOM%256)) $((RANDOM%256)) $((i%256)) $(((RANDOM%65534) + 1)) $((RANDOM%256)) 1462 done 1463 ;; 1464 "ipv4_addr . inet_service . inet_proto . ipv4_addr") 1465 for i in $(seq 1 $dcount); do 1466 [ $i -gt 1 ] && echo ", " 1467 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)) 1468 done 1469 ;; 1470 "ipv4_addr . inet_service . ipv4_addr") 1471 dcount=32768 1472 for i in $(seq 1 $dcount); do 1473 [ $i -gt 1 ] && echo ", " 1474 printf "172.%i.%i.%i . %i . 192.168.%i.%i " $((RANDOM%256)) $((RANDOM%256)) $((i%256)) $(((RANDOM%65534) + 1)) $((RANDOM%256)) $((RANDOM%256)) 1475 done 1476 ;; 1477 "ipv6_addr . ether_addr") 1478 for i in $(seq 1 $dcount); do 1479 [ $i -gt 1 ] && echo ", " 1480 format_addr6 $((i + 1000000)) 1481 echo -n " . " 1482 format_mac $((1000000 + i)) 1483 done 1484 ;; 1485 "ipv6_addr . inet_service") 1486 dcount=32768 1487 for i in $(seq 1 $dcount); do 1488 [ $i -gt 1 ] && echo ", " 1489 format_addr6 $((i + 1000000)) 1490 echo -n " . $(((RANDOM%65534) + 1))" 1491 done 1492 ;; 1493 "ipv6_addr . inet_service . ether_addr") 1494 dcount=32768 1495 for i in $(seq 1 $dcount); do 1496 [ $i -gt 1 ] && echo ", " 1497 format_addr6 $((i + 1000000)) 1498 echo -n " . $(((RANDOM%65534) + 1)) . " 1499 format_mac $((i + 1000000)) 1500 done 1501 ;; 1502 "ipv6_addr . inet_service . ether_addr . inet_proto") 1503 dcount=65536 1504 for i in $(seq 1 $dcount); do 1505 [ $i -gt 1 ] && echo ", " 1506 format_addr6 $((i + 1000000)) 1507 echo -n " . $(((RANDOM%65534) + 1)) . " 1508 format_mac $((i + 1000000)) 1509 echo -n " . $((RANDOM%256))" 1510 done 1511 ;; 1512 "ipv6_addr . inet_service . ipv6_addr . inet_service") 1513 dcount=32768 1514 for i in $(seq 1 $dcount); do 1515 [ $i -gt 1 ] && echo ", " 1516 format_addr6 $((i + 1000000)) 1517 echo -n " . $(((RANDOM%65534) + 1)) . " 1518 format_addr6 $((i + 2123456)) 1519 echo -n " . $((RANDOM%256))" 1520 done 1521 ;; 1522 *) 1523 "Unhandled $type_spec" 1524 return 1 1525 esac 1526 echo -n "}" 1527 1528 ) | nft -f - || return 1 1529 1530 test_correctness_main 1531} 1532 1533# Concurrency test template: 1534# - add all the elements 1535# - start a thread for each physical thread that: 1536# - adds all the elements 1537# - flushes the set 1538# - adds all the elements 1539# - flushes the entire ruleset 1540# - adds the set back 1541# - adds all the elements 1542# - delete all the elements 1543test_concurrency() { 1544 proto=${flood_proto} 1545 tools=${flood_tools} 1546 chain_spec=${flood_spec} 1547 setup veth flood_"${proto}" set || return ${ksft_skip} 1548 1549 range_size=1 1550 cstart=${start} 1551 flood_pids= 1552 for i in $(seq "$start" $((start + count))); do 1553 end=$((start + range_size)) 1554 srcstart=$((start + src_delta)) 1555 srcend=$((end + src_delta)) 1556 1557 add "$(format)" || return 1 1558 1559 flood "${i}" $((i + src_delta)) & flood_pids="${flood_pids} $!" 1560 1561 range_size=$((range_size + 1)) 1562 start=$((end + range_size)) 1563 done 1564 1565 sleep $((RANDOM%10)) 1566 1567 pids= 1568 for c in $(seq 1 "$(nproc)"); do ( 1569 for r in $(seq 1 "${race_repeat}"); do 1570 range_size=1 1571 1572 # $start needs to be local to this subshell 1573 # shellcheck disable=SC2030 1574 start=${cstart} 1575 for i in $(seq "$start" $((start + count))); do 1576 end=$((start + range_size)) 1577 srcstart=$((start + src_delta)) 1578 srcend=$((end + src_delta)) 1579 1580 add "$(format)" 2>/dev/null 1581 1582 range_size=$((range_size + 1)) 1583 start=$((end + range_size)) 1584 done 1585 1586 nft flush inet filter test 2>/dev/null 1587 1588 range_size=1 1589 start=${cstart} 1590 for i in $(seq "$start" $((start + count))); do 1591 end=$((start + range_size)) 1592 srcstart=$((start + src_delta)) 1593 srcend=$((end + src_delta)) 1594 1595 add "$(format)" 2>/dev/null 1596 1597 range_size=$((range_size + 1)) 1598 start=$((end + range_size)) 1599 done 1600 1601 nft flush ruleset 1602 setup set 2>/dev/null 1603 1604 range_size=1 1605 start=${cstart} 1606 for i in $(seq "$start" $((start + count))); do 1607 end=$((start + range_size)) 1608 srcstart=$((start + src_delta)) 1609 srcend=$((end + src_delta)) 1610 1611 add "$(format)" 2>/dev/null 1612 1613 range_size=$((range_size + 1)) 1614 start=$((end + range_size)) 1615 done 1616 1617 range_size=1 1618 start=${cstart} 1619 for i in $(seq "$start" $((start + count))); do 1620 end=$((start + range_size)) 1621 srcstart=$((start + src_delta)) 1622 srcend=$((end + src_delta)) 1623 1624 del "$(format)" 2>/dev/null 1625 1626 range_size=$((range_size + 1)) 1627 start=$((end + range_size)) 1628 done 1629 done 1630 ) & pids="${pids} $!" 1631 done 1632 1633 # shellcheck disable=SC2046,SC2086 # word splitting wanted here 1634 wait $(for pid in ${pids}; do echo ${pid}; done) 1635 # shellcheck disable=SC2046,SC2086 1636 kill $(for pid in ${flood_pids}; do echo ${pid}; done) 2>/dev/null 1637 # shellcheck disable=SC2046,SC2086 1638 wait $(for pid in ${flood_pids}; do echo ${pid}; done) 2>/dev/null 1639 1640 return 0 1641} 1642 1643# Timeout test template: 1644# - add all the elements with 3s timeout while checking that packets match 1645# - wait 3s after the last insertion, check that packets don't match any entry 1646test_timeout() { 1647 setup veth send_"${proto}" set || return ${ksft_skip} 1648 1649 timeout=3 1650 1651 [ "$KSFT_MACHINE_SLOW" = "yes" ] && timeout=8 1652 1653 range_size=1 1654 for i in $(seq "$start" $((start + count))); do 1655 local elem="" 1656 1657 end=$((start + range_size)) 1658 srcstart=$((start + src_delta)) 1659 srcend=$((end + src_delta)) 1660 1661 elem="$(format)" 1662 add "$elem" || return 1 1663 1664 for j in $(seq "$start" $((range_size / 2 + 1)) ${end}); do 1665 send_match "$elem" "${j}" $((j + src_delta)) || return 1 1666 done 1667 1668 range_size=$((range_size + 1)) 1669 start=$((end + range_size)) 1670 done 1671 sleep $timeout 1672 for i in $(seq "$start" $((start + count))); do 1673 end=$((start + range_size)) 1674 srcstart=$((start + src_delta)) 1675 srcend=$((end + src_delta)) 1676 1677 for j in $(seq "$start" $((range_size / 2 + 1)) ${end}); do 1678 send_nomatch "${j}" $((j + src_delta)) || return 1 1679 done 1680 1681 range_size=$((range_size + 1)) 1682 start=$((end + range_size)) 1683 done 1684} 1685 1686# Performance test template: 1687# - add concatenated ranged entries 1688# - add non-ranged concatenated entries (for hash set matching rate baseline) 1689# - add ranged entries with first field only (for rbhash baseline) 1690# - start pktgen injection directly on device rx path of this namespace 1691# - measure drop only rate, hash and rbtree baselines, then matching rate 1692test_performance() { 1693 chain_spec=${perf_spec} 1694 dst="${perf_dst}" 1695 src="${perf_src}" 1696 setup veth perf set || return ${ksft_skip} 1697 1698 first=${start} 1699 range_size=1 1700 for set in test norange noconcat; do 1701 start=${first} 1702 for i in $(seq "$start" $((start + perf_entries))); do 1703 end=$((start + range_size)) 1704 srcstart=$((start + src_delta)) 1705 srcend=$((end + src_delta)) 1706 1707 if [ $((end / 65534)) -gt $((start / 65534)) ]; then 1708 start=${end} 1709 end=$((end + 1)) 1710 elif [ "$start" -eq "$end" ]; then 1711 end=$((start + 1)) 1712 fi 1713 1714 add_perf ${set} 1715 1716 start=$((end + range_size)) 1717 done > "${tmp}" 1718 nft -f "${tmp}" 1719 done 1720 1721 perf $((end - 1)) "$srcstart" 1722 1723 sleep 2 1724 1725 nft add rule netdev perf test counter name \"test\" drop 1726 nft reset counter netdev perf test >/dev/null 2>&1 1727 sleep "${perf_duration}" 1728 pps="$(printf %10s $(($(count_perf_packets) / perf_duration)))" 1729 info " baseline (drop from netdev hook): ${pps}pps" 1730 handle="$(nft -a list chain netdev perf test | grep counter)" 1731 handle="${handle##* }" 1732 nft delete rule netdev perf test handle "${handle}" 1733 1734 nft add rule "netdev perf test ${chain_spec} @norange \ 1735 counter name \"test\" drop" 1736 nft reset counter netdev perf test >/dev/null 2>&1 1737 sleep "${perf_duration}" 1738 pps="$(printf %10s $(($(count_perf_packets) / perf_duration)))" 1739 info " baseline hash (non-ranged entries): ${pps}pps" 1740 handle="$(nft -a list chain netdev perf test | grep counter)" 1741 handle="${handle##* }" 1742 nft delete rule netdev perf test handle "${handle}" 1743 1744 nft add rule "netdev perf test ${chain_spec%%. *} @noconcat \ 1745 counter name \"test\" drop" 1746 nft reset counter netdev perf test >/dev/null 2>&1 1747 sleep "${perf_duration}" 1748 pps="$(printf %10s $(($(count_perf_packets) / perf_duration)))" 1749 info " baseline rbtree (match on first field only): ${pps}pps" 1750 handle="$(nft -a list chain netdev perf test | grep counter)" 1751 handle="${handle##* }" 1752 nft delete rule netdev perf test handle "${handle}" 1753 1754 nft add rule "netdev perf test ${chain_spec} @test \ 1755 counter name \"test\" drop" 1756 nft reset counter netdev perf test >/dev/null 2>&1 1757 sleep "${perf_duration}" 1758 pps="$(printf %10s $(($(count_perf_packets) / perf_duration)))" 1759 p5="$(printf %5s "${perf_entries}")" 1760 info " set with ${p5} full, ranged entries: ${pps}pps" 1761 kill "${perf_pid}" 1762} 1763 1764test_bug_flush_remove_add() { 1765 rounds=100 1766 [ "$KSFT_MACHINE_SLOW" = "yes" ] && rounds=10 1767 1768 set_cmd='{ set s { type ipv4_addr . inet_service; flags interval; }; }' 1769 elem1='{ 10.0.0.1 . 22-25, 10.0.0.1 . 10-20 }' 1770 elem2='{ 10.0.0.1 . 10-20, 10.0.0.1 . 22-25 }' 1771 for i in $(seq 1 $rounds); do 1772 nft add table t "$set_cmd" || return ${ksft_skip} 1773 nft add element t s "$elem1" 2>/dev/null || return 1 1774 nft flush set t s 2>/dev/null || return 1 1775 nft add element t s "$elem2" 2>/dev/null || return 1 1776 done 1777 nft flush ruleset 1778} 1779 1780# - add ranged element, check that packets match it 1781# - reload the set, check packets still match 1782test_bug_reload() { 1783 setup veth send_"${proto}" set || return ${ksft_skip} 1784 rstart=${start} 1785 1786 range_size=1 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 add "$(format)" || return 1 1799 range_size=$((range_size + 1)) 1800 start=$((end + range_size)) 1801 done 1802 1803 # check kernel does allocate pcpu sctrach map 1804 # for reload with no elemet add/delete 1805 ( echo flush set inet filter test ; 1806 nft list set inet filter test ) | nft -f - 1807 1808 start=${rstart} 1809 range_size=1 1810 1811 for i in $(seq "${start}" $((start + count))); do 1812 end=$((start + range_size)) 1813 1814 # Avoid negative or zero-sized port ranges 1815 if [ $((end / 65534)) -gt $((start / 65534)) ]; then 1816 start=${end} 1817 end=$((end + 1)) 1818 fi 1819 srcstart=$((start + src_delta)) 1820 srcend=$((end + src_delta)) 1821 1822 for j in $(seq "$start" $((range_size / 2 + 1)) ${end}); do 1823 send_match "$(format)" "${j}" $((j + src_delta)) || return 1 1824 done 1825 1826 range_size=$((range_size + 1)) 1827 start=$((end + range_size)) 1828 done 1829 1830 nft flush ruleset 1831} 1832 1833# - add ranged element, check that packets match it 1834# - delete element again, check it is gone 1835test_bug_net_port_proto_match() { 1836 setup veth send_"${proto}" set || return ${ksft_skip} 1837 rstart=${start} 1838 1839 range_size=1 1840 for i in $(seq 1 10); do 1841 for j in $(seq 1 20) ; do 1842 local dport=$j 1843 1844 elem=$(printf "10.%d.%d.0/24 . %d-%d0 . 6-17 " ${i} ${j} ${dport} "$((dport+1))") 1845 1846 # too slow, do not test all addresses 1847 maybe_send_nomatch "$elem" $(printf "10.%d.%d.1" $i $j) $(printf "%d1" $((dport+1))) "before add" || return 1 1848 1849 nft "add element inet filter test { $elem }" || return 1 1850 1851 maybe_send_match "$elem" $(printf "10.%d.%d.1" $i $j) $(printf "%d" $dport) "after add" || return 1 1852 1853 nft "get element inet filter test { $elem }" | grep -q "$elem" 1854 if [ $? -ne 0 ];then 1855 local got=$(nft "get element inet filter test { $elem }") 1856 err "post-add: should have returned $elem but got $got" 1857 return 1 1858 fi 1859 1860 maybe_send_nomatch "$elem" $(printf "10.%d.%d.1" $i $j) $(printf "%d1" $((dport+1))) "out-of-range" || return 1 1861 done 1862 done 1863 1864 # recheck after set was filled 1865 for i in $(seq 1 10); do 1866 for j in $(seq 1 20) ; do 1867 local dport=$j 1868 1869 elem=$(printf "10.%d.%d.0/24 . %d-%d0 . 6-17 " ${i} ${j} ${dport} "$((dport+1))") 1870 1871 nft "get element inet filter test { $elem }" | grep -q "$elem" 1872 if [ $? -ne 0 ];then 1873 local got=$(nft "get element inet filter test { $elem }") 1874 err "post-fill: should have returned $elem but got $got" 1875 return 1 1876 fi 1877 1878 maybe_send_match "$elem" $(printf "10.%d.%d.1" $i $j) $(printf "%d" $dport) "recheck" || return 1 1879 maybe_send_nomatch "$elem" $(printf "10.%d.%d.1" $i $j) $(printf "%d1" $((dport+1))) "recheck out-of-range" || return 1 1880 done 1881 done 1882 1883 # random del and re-fetch 1884 for i in $(seq 1 10); do 1885 for j in $(seq 1 20) ; do 1886 local rnd=$((RANDOM%10)) 1887 local dport=$j 1888 local got="" 1889 1890 elem=$(printf "10.%d.%d.0/24 . %d-%d0 . 6-17 " ${i} ${j} ${dport} "$((dport+1))") 1891 if [ $rnd -gt 0 ];then 1892 continue 1893 fi 1894 1895 nft "delete element inet filter test { $elem }" 1896 got=$(nft "get element inet filter test { $elem }" 2>/dev/null) 1897 if [ $? -eq 0 ];then 1898 err "post-delete: query for $elem returned $got instead of error." 1899 return 1 1900 fi 1901 1902 maybe_send_nomatch "$elem" $(printf "10.%d.%d.1" $i $j) $(printf "%d" $dport) "match after deletion" || return 1 1903 done 1904 done 1905 1906 nft flush ruleset 1907} 1908 1909test_bug_avx2_mismatch() 1910{ 1911 setup veth send_"${proto}" set || return ${ksft_skip} 1912 1913 local a1="fe80:dead:01ff:0a02:0b03:6007:8009:a001" 1914 local a2="fe80:dead:01fe:0a02:0b03:6007:8009:a001" 1915 1916 nft "add element inet filter test { icmpv6 . $a1 }" 1917 1918 dst_addr6="$a2" 1919 send_icmp6 1920 1921 if [ "$(count_packets "{ icmpv6 . $a1 }")" -gt "0" ]; then 1922 err "False match for $a2" 1923 return 1 1924 fi 1925} 1926 1927test_bug_doublecreate() 1928{ 1929 local elements="1.2.3.4 . 1.2.4.1, 1.2.4.1 . 1.2.3.4" 1930 local ret=1 1931 local i 1932 1933 setup veth send_"${proto}" set || return ${ksft_skip} 1934 1935 add "{ $elements }" || return 1 1936 # expected to work: 'add' on existing should be no-op. 1937 add "{ $elements }" || return 1 1938 1939 # 'create' should return an error. 1940 if nft create element inet filter test "{ $elements }" 2>/dev/null; then 1941 err "Could create an existing element" 1942 return 1 1943 fi 1944nft -f - <<EOF 2>/dev/null 1945flush set inet filter test 1946create element inet filter test { $elements } 1947create element inet filter test { $elements } 1948EOF 1949 ret=$? 1950 if [ $ret -eq 0 ]; then 1951 err "Could create element twice in one transaction" 1952 err "$(nft -a list ruleset)" 1953 return 1 1954 fi 1955 1956nft -f - <<EOF 2>/dev/null 1957flush set inet filter test 1958create element inet filter test { $elements } 1959EOF 1960 ret=$? 1961 if [ $ret -ne 0 ]; then 1962 err "Could not flush and re-create element in one transaction" 1963 return 1 1964 fi 1965 1966 return 0 1967} 1968 1969add_fail() 1970{ 1971 if nft add element inet filter test "$1" 2>/dev/null ; then 1972 err "Returned success for add ${1} given set:" 1973 err "$(nft -a list set inet filter test )" 1974 return 1 1975 fi 1976 1977 return 0 1978} 1979 1980test_bug_insert_overlap() 1981{ 1982 local elements="1.2.3.4 . 1.2.4.1" 1983 1984 setup veth send_"${proto}" set || return ${ksft_skip} 1985 1986 add "{ $elements }" || return 1 1987 1988 elements="1.2.3.0-1.2.3.4 . 1.2.4.1" 1989 add_fail "{ $elements }" || return 1 1990 1991 elements="1.2.3.0-1.2.3.4 . 1.2.4.2" 1992 add "{ $elements }" || return 1 1993 1994 elements="1.2.3.4 . 1.2.4.1-1.2.4.2" 1995 add_fail "{ $elements }" || return 1 1996 1997 return 0 1998} 1999 2000test_reported_issues() { 2001 eval test_bug_"${subtest}" 2002} 2003 2004# Run everything in a separate network namespace 2005[ "${1}" != "run" ] && { unshare -n "${0}" run; exit $?; } 2006tmp="$(mktemp)" 2007trap cleanup_exit EXIT 2008 2009# Entry point for test runs 2010passed=0 2011for name in ${TESTS}; do 2012 printf "TEST: %s\n" "$(echo "$name" | tr '_' ' ')" 2013 if [ "${name}" = "reported_issues" ]; then 2014 SUBTESTS="${BUGS}" 2015 else 2016 SUBTESTS="${TYPES}" 2017 fi 2018 2019 for subtest in ${SUBTESTS}; do 2020 eval desc=\$TYPE_"${subtest}" 2021 IFS=' 2022' 2023 for __line in ${desc}; do 2024 # shellcheck disable=SC2086 2025 eval ${__line%% *}=\"${__line##* }\"; 2026 done 2027 IFS=' 2028' 2029 2030 if [ "${name}" = "concurrency" ] && \ 2031 [ "${race_repeat}" = "0" ]; then 2032 continue 2033 fi 2034 if [ "${name}" = "performance" ] && \ 2035 [ "${perf_duration}" = "0" ]; then 2036 continue 2037 fi 2038 2039 [ "$KSFT_MACHINE_SLOW" = "yes" ] && count=1 2040 2041 printf " %-32s " "${display}" 2042 tthen=$(date +%s) 2043 eval test_"${name}" 2044 ret=$? 2045 2046 tnow=$(date +%s) 2047 printf "%5ds%-30s" $((tnow-tthen)) 2048 2049 if [ $ret -eq 0 ]; then 2050 printf "[ OK ]\n" 2051 info_flush 2052 passed=$((passed + 1)) 2053 elif [ $ret -eq 1 ]; then 2054 printf "[FAIL]\n" 2055 err_flush 2056 exit 1 2057 elif [ $ret -eq ${ksft_skip} ]; then 2058 printf "[SKIP]\n" 2059 err_flush 2060 fi 2061 done 2062done 2063 2064[ ${passed} -eq 0 ] && exit ${ksft_skip} || exit 0 2065