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 for i in $(seq "${start}" $((start + count))); do 1315 local elem="" 1316 1317 end=$((start + range_size)) 1318 1319 # Avoid negative or zero-sized port ranges 1320 if [ $((end / 65534)) -gt $((start / 65534)) ]; then 1321 start=${end} 1322 end=$((end + 1)) 1323 fi 1324 srcstart=$((start + src_delta)) 1325 srcend=$((end + src_delta)) 1326 1327 elem="$(format)" 1328 add "$elem" || return 1 1329 for j in $(seq "$start" $((range_size / 2 + 1)) ${end}); do 1330 send_match "$elem" "${j}" $((j + src_delta)) || return 1 1331 done 1332 send_nomatch $((end + 1)) $((end + 1 + src_delta)) || return 1 1333 1334 # Delete elements now and then 1335 if [ $((i % 3)) -eq 0 ]; then 1336 del "$elem" || return 1 1337 for j in $(seq "$start" \ 1338 $((range_size / 2 + 1)) ${end}); do 1339 send_nomatch "${j}" $((j + src_delta)) \ 1340 || return 1 1341 done 1342 fi 1343 1344 range_size=$((range_size + 1)) 1345 start=$((end + range_size)) 1346 done 1347} 1348 1349test_correctness() { 1350 setup veth send_"${proto}" set || return ${ksft_skip} 1351 1352 test_correctness_main 1353} 1354 1355# Repeat the correctness tests, but add extra non-matching entries. 1356# This exercises the more compact '4 bit group' representation that 1357# gets picked when the default 8-bit representation exceed 1358# NFT_PIPAPO_LT_SIZE_HIGH bytes of memory. 1359# See usage of NFT_PIPAPO_LT_SIZE_HIGH in pipapo_lt_bits_adjust(). 1360# 1361# The format() helper is way too slow when generating lots of 1362# entries so its not used here. 1363test_correctness_large() { 1364 setup veth send_"${proto}" set || return ${ksft_skip} 1365 # number of dummy (filler) entries to add. 1366 local dcount=16385 1367 1368 ( 1369 echo -n "add element inet filter test { " 1370 1371 case "$type_spec" in 1372 "ether_addr . ipv4_addr") 1373 for i in $(seq 1 $dcount); do 1374 [ $i -gt 1 ] && echo ", " 1375 format_mac $((1000000 + i)) 1376 printf ". 172.%i.%i.%i " $((RANDOM%256)) $((RANDOM%256)) $((i%256)) 1377 done 1378 ;; 1379 "inet_proto . ipv6_addr") 1380 for i in $(seq 1 $dcount); do 1381 [ $i -gt 1 ] && echo ", " 1382 printf "%i . " $((RANDOM%256)) 1383 format_addr6 $((1000000 + i)) 1384 done 1385 ;; 1386 "inet_service . inet_proto") 1387 # smaller key sizes, need more entries to hit the 1388 # 4-bit threshold. 1389 dcount=65536 1390 for i in $(seq 1 $dcount); do 1391 local proto=$((RANDOM%256)) 1392 1393 # Test uses UDP to match, as it also fails when matching 1394 # an entry that doesn't exist, so skip 'udp' entries 1395 # to not trigger a wrong failure. 1396 [ $proto -eq 17 ] && proto=18 1397 [ $i -gt 1 ] && echo ", " 1398 printf "%i . %i " $(((i%65534) + 1)) $((proto)) 1399 done 1400 ;; 1401 "inet_service . ipv4_addr") 1402 dcount=32768 1403 for i in $(seq 1 $dcount); do 1404 [ $i -gt 1 ] && echo ", " 1405 printf "%i . 172.%i.%i.%i " $(((RANDOM%65534) + 1)) $((RANDOM%256)) $((RANDOM%256)) $((i%256)) 1406 done 1407 ;; 1408 "ipv4_addr . ether_addr") 1409 for i in $(seq 1 $dcount); do 1410 [ $i -gt 1 ] && echo ", " 1411 printf "172.%i.%i.%i . " $((RANDOM%256)) $((RANDOM%256)) $((i%256)) 1412 format_mac $((1000000 + i)) 1413 done 1414 ;; 1415 "ipv4_addr . inet_service") 1416 dcount=32768 1417 for i in $(seq 1 $dcount); do 1418 [ $i -gt 1 ] && echo ", " 1419 printf "172.%i.%i.%i . %i" $((RANDOM%256)) $((RANDOM%256)) $((i%256)) $(((RANDOM%65534) + 1)) 1420 done 1421 ;; 1422 "ipv4_addr . inet_service . ether_addr . inet_proto . ipv4_addr") 1423 dcount=65536 1424 for i in $(seq 1 $dcount); do 1425 [ $i -gt 1 ] && echo ", " 1426 printf "172.%i.%i.%i . %i . " $((RANDOM%256)) $((RANDOM%256)) $((i%256)) $(((RANDOM%65534) + 1)) 1427 format_mac $((1000000 + i)) 1428 printf ". %i . 192.168.%i.%i" $((RANDOM%256)) $((RANDOM%256)) $((i%256)) 1429 done 1430 ;; 1431 "ipv4_addr . inet_service . inet_proto") 1432 for i in $(seq 1 $dcount); do 1433 [ $i -gt 1 ] && echo ", " 1434 printf "172.%i.%i.%i . %i . %i " $((RANDOM%256)) $((RANDOM%256)) $((i%256)) $(((RANDOM%65534) + 1)) $((RANDOM%256)) 1435 done 1436 ;; 1437 "ipv4_addr . inet_service . inet_proto . ipv4_addr") 1438 for i in $(seq 1 $dcount); do 1439 [ $i -gt 1 ] && echo ", " 1440 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)) 1441 done 1442 ;; 1443 "ipv4_addr . inet_service . ipv4_addr") 1444 dcount=32768 1445 for i in $(seq 1 $dcount); do 1446 [ $i -gt 1 ] && echo ", " 1447 printf "172.%i.%i.%i . %i . 192.168.%i.%i " $((RANDOM%256)) $((RANDOM%256)) $((i%256)) $(((RANDOM%65534) + 1)) $((RANDOM%256)) $((RANDOM%256)) 1448 done 1449 ;; 1450 "ipv6_addr . ether_addr") 1451 for i in $(seq 1 $dcount); do 1452 [ $i -gt 1 ] && echo ", " 1453 format_addr6 $((i + 1000000)) 1454 echo -n " . " 1455 format_mac $((1000000 + i)) 1456 done 1457 ;; 1458 "ipv6_addr . inet_service") 1459 dcount=32768 1460 for i in $(seq 1 $dcount); do 1461 [ $i -gt 1 ] && echo ", " 1462 format_addr6 $((i + 1000000)) 1463 echo -n " . $(((RANDOM%65534) + 1))" 1464 done 1465 ;; 1466 "ipv6_addr . inet_service . ether_addr") 1467 dcount=32768 1468 for i in $(seq 1 $dcount); do 1469 [ $i -gt 1 ] && echo ", " 1470 format_addr6 $((i + 1000000)) 1471 echo -n " . $(((RANDOM%65534) + 1)) . " 1472 format_mac $((i + 1000000)) 1473 done 1474 ;; 1475 "ipv6_addr . inet_service . ether_addr . inet_proto") 1476 dcount=65536 1477 for i in $(seq 1 $dcount); do 1478 [ $i -gt 1 ] && echo ", " 1479 format_addr6 $((i + 1000000)) 1480 echo -n " . $(((RANDOM%65534) + 1)) . " 1481 format_mac $((i + 1000000)) 1482 echo -n " . $((RANDOM%256))" 1483 done 1484 ;; 1485 "ipv6_addr . inet_service . 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 format_addr6 $((i + 2123456)) 1492 echo -n " . $((RANDOM%256))" 1493 done 1494 ;; 1495 *) 1496 "Unhandled $type_spec" 1497 return 1 1498 esac 1499 echo -n "}" 1500 1501 ) | nft -f - || return 1 1502 1503 test_correctness_main 1504} 1505 1506# Concurrency test template: 1507# - add all the elements 1508# - start a thread for each physical thread that: 1509# - adds all the elements 1510# - flushes the set 1511# - adds all the elements 1512# - flushes the entire ruleset 1513# - adds the set back 1514# - adds all the elements 1515# - delete all the elements 1516test_concurrency() { 1517 proto=${flood_proto} 1518 tools=${flood_tools} 1519 chain_spec=${flood_spec} 1520 setup veth flood_"${proto}" set || return ${ksft_skip} 1521 1522 range_size=1 1523 cstart=${start} 1524 flood_pids= 1525 for i in $(seq "$start" $((start + count))); do 1526 end=$((start + range_size)) 1527 srcstart=$((start + src_delta)) 1528 srcend=$((end + src_delta)) 1529 1530 add "$(format)" || return 1 1531 1532 flood "${i}" $((i + src_delta)) & flood_pids="${flood_pids} $!" 1533 1534 range_size=$((range_size + 1)) 1535 start=$((end + range_size)) 1536 done 1537 1538 sleep $((RANDOM%10)) 1539 1540 pids= 1541 for c in $(seq 1 "$(nproc)"); do ( 1542 for r in $(seq 1 "${race_repeat}"); do 1543 range_size=1 1544 1545 # $start needs to be local to this subshell 1546 # shellcheck disable=SC2030 1547 start=${cstart} 1548 for i in $(seq "$start" $((start + count))); do 1549 end=$((start + range_size)) 1550 srcstart=$((start + src_delta)) 1551 srcend=$((end + src_delta)) 1552 1553 add "$(format)" 2>/dev/null 1554 1555 range_size=$((range_size + 1)) 1556 start=$((end + range_size)) 1557 done 1558 1559 nft flush inet filter test 2>/dev/null 1560 1561 range_size=1 1562 start=${cstart} 1563 for i in $(seq "$start" $((start + count))); do 1564 end=$((start + range_size)) 1565 srcstart=$((start + src_delta)) 1566 srcend=$((end + src_delta)) 1567 1568 add "$(format)" 2>/dev/null 1569 1570 range_size=$((range_size + 1)) 1571 start=$((end + range_size)) 1572 done 1573 1574 nft flush ruleset 1575 setup set 2>/dev/null 1576 1577 range_size=1 1578 start=${cstart} 1579 for i in $(seq "$start" $((start + count))); do 1580 end=$((start + range_size)) 1581 srcstart=$((start + src_delta)) 1582 srcend=$((end + src_delta)) 1583 1584 add "$(format)" 2>/dev/null 1585 1586 range_size=$((range_size + 1)) 1587 start=$((end + range_size)) 1588 done 1589 1590 range_size=1 1591 start=${cstart} 1592 for i in $(seq "$start" $((start + count))); do 1593 end=$((start + range_size)) 1594 srcstart=$((start + src_delta)) 1595 srcend=$((end + src_delta)) 1596 1597 del "$(format)" 2>/dev/null 1598 1599 range_size=$((range_size + 1)) 1600 start=$((end + range_size)) 1601 done 1602 done 1603 ) & pids="${pids} $!" 1604 done 1605 1606 # shellcheck disable=SC2046,SC2086 # word splitting wanted here 1607 wait $(for pid in ${pids}; do echo ${pid}; done) 1608 # shellcheck disable=SC2046,SC2086 1609 kill $(for pid in ${flood_pids}; do echo ${pid}; done) 2>/dev/null 1610 # shellcheck disable=SC2046,SC2086 1611 wait $(for pid in ${flood_pids}; do echo ${pid}; done) 2>/dev/null 1612 1613 return 0 1614} 1615 1616# Timeout test template: 1617# - add all the elements with 3s timeout while checking that packets match 1618# - wait 3s after the last insertion, check that packets don't match any entry 1619test_timeout() { 1620 setup veth send_"${proto}" set || return ${ksft_skip} 1621 1622 timeout=3 1623 1624 [ "$KSFT_MACHINE_SLOW" = "yes" ] && timeout=8 1625 1626 range_size=1 1627 for i in $(seq "$start" $((start + count))); do 1628 local elem="" 1629 1630 end=$((start + range_size)) 1631 srcstart=$((start + src_delta)) 1632 srcend=$((end + src_delta)) 1633 1634 elem="$(format)" 1635 add "$elem" || return 1 1636 1637 for j in $(seq "$start" $((range_size / 2 + 1)) ${end}); do 1638 send_match "$elem" "${j}" $((j + src_delta)) || return 1 1639 done 1640 1641 range_size=$((range_size + 1)) 1642 start=$((end + range_size)) 1643 done 1644 sleep $timeout 1645 for i in $(seq "$start" $((start + count))); do 1646 end=$((start + range_size)) 1647 srcstart=$((start + src_delta)) 1648 srcend=$((end + src_delta)) 1649 1650 for j in $(seq "$start" $((range_size / 2 + 1)) ${end}); do 1651 send_nomatch "${j}" $((j + src_delta)) || return 1 1652 done 1653 1654 range_size=$((range_size + 1)) 1655 start=$((end + range_size)) 1656 done 1657} 1658 1659# Performance test template: 1660# - add concatenated ranged entries 1661# - add non-ranged concatenated entries (for hash set matching rate baseline) 1662# - add ranged entries with first field only (for rbhash baseline) 1663# - start pktgen injection directly on device rx path of this namespace 1664# - measure drop only rate, hash and rbtree baselines, then matching rate 1665test_performance() { 1666 chain_spec=${perf_spec} 1667 dst="${perf_dst}" 1668 src="${perf_src}" 1669 setup veth perf set || return ${ksft_skip} 1670 1671 first=${start} 1672 range_size=1 1673 for set in test norange noconcat; do 1674 start=${first} 1675 for i in $(seq "$start" $((start + perf_entries))); do 1676 end=$((start + range_size)) 1677 srcstart=$((start + src_delta)) 1678 srcend=$((end + src_delta)) 1679 1680 if [ $((end / 65534)) -gt $((start / 65534)) ]; then 1681 start=${end} 1682 end=$((end + 1)) 1683 elif [ "$start" -eq "$end" ]; then 1684 end=$((start + 1)) 1685 fi 1686 1687 add_perf ${set} 1688 1689 start=$((end + range_size)) 1690 done > "${tmp}" 1691 nft -f "${tmp}" 1692 done 1693 1694 perf $((end - 1)) "$srcstart" 1695 1696 sleep 2 1697 1698 nft add rule netdev perf test counter name \"test\" drop 1699 nft reset counter netdev perf test >/dev/null 2>&1 1700 sleep "${perf_duration}" 1701 pps="$(printf %10s $(($(count_perf_packets) / perf_duration)))" 1702 info " baseline (drop from netdev hook): ${pps}pps" 1703 handle="$(nft -a list chain netdev perf test | grep counter)" 1704 handle="${handle##* }" 1705 nft delete rule netdev perf test handle "${handle}" 1706 1707 nft add rule "netdev perf test ${chain_spec} @norange \ 1708 counter name \"test\" drop" 1709 nft reset counter netdev perf test >/dev/null 2>&1 1710 sleep "${perf_duration}" 1711 pps="$(printf %10s $(($(count_perf_packets) / perf_duration)))" 1712 info " baseline hash (non-ranged entries): ${pps}pps" 1713 handle="$(nft -a list chain netdev perf test | grep counter)" 1714 handle="${handle##* }" 1715 nft delete rule netdev perf test handle "${handle}" 1716 1717 nft add rule "netdev perf test ${chain_spec%%. *} @noconcat \ 1718 counter name \"test\" drop" 1719 nft reset counter netdev perf test >/dev/null 2>&1 1720 sleep "${perf_duration}" 1721 pps="$(printf %10s $(($(count_perf_packets) / perf_duration)))" 1722 info " baseline rbtree (match on first field only): ${pps}pps" 1723 handle="$(nft -a list chain netdev perf test | grep counter)" 1724 handle="${handle##* }" 1725 nft delete rule netdev perf test handle "${handle}" 1726 1727 nft add rule "netdev perf test ${chain_spec} @test \ 1728 counter name \"test\" drop" 1729 nft reset counter netdev perf test >/dev/null 2>&1 1730 sleep "${perf_duration}" 1731 pps="$(printf %10s $(($(count_perf_packets) / perf_duration)))" 1732 p5="$(printf %5s "${perf_entries}")" 1733 info " set with ${p5} full, ranged entries: ${pps}pps" 1734 kill "${perf_pid}" 1735} 1736 1737test_bug_flush_remove_add() { 1738 rounds=100 1739 [ "$KSFT_MACHINE_SLOW" = "yes" ] && rounds=10 1740 1741 set_cmd='{ set s { type ipv4_addr . inet_service; flags interval; }; }' 1742 elem1='{ 10.0.0.1 . 22-25, 10.0.0.1 . 10-20 }' 1743 elem2='{ 10.0.0.1 . 10-20, 10.0.0.1 . 22-25 }' 1744 for i in $(seq 1 $rounds); do 1745 nft add table t "$set_cmd" || return ${ksft_skip} 1746 nft add element t s "$elem1" 2>/dev/null || return 1 1747 nft flush set t s 2>/dev/null || return 1 1748 nft add element t s "$elem2" 2>/dev/null || return 1 1749 done 1750 nft flush ruleset 1751} 1752 1753# - add ranged element, check that packets match it 1754# - reload the set, check packets still match 1755test_bug_reload() { 1756 setup veth send_"${proto}" set || return ${ksft_skip} 1757 rstart=${start} 1758 1759 range_size=1 1760 for i in $(seq "${start}" $((start + count))); do 1761 end=$((start + range_size)) 1762 1763 # Avoid negative or zero-sized port ranges 1764 if [ $((end / 65534)) -gt $((start / 65534)) ]; then 1765 start=${end} 1766 end=$((end + 1)) 1767 fi 1768 srcstart=$((start + src_delta)) 1769 srcend=$((end + src_delta)) 1770 1771 add "$(format)" || return 1 1772 range_size=$((range_size + 1)) 1773 start=$((end + range_size)) 1774 done 1775 1776 # check kernel does allocate pcpu sctrach map 1777 # for reload with no elemet add/delete 1778 ( echo flush set inet filter test ; 1779 nft list set inet filter test ) | nft -f - 1780 1781 start=${rstart} 1782 range_size=1 1783 1784 for i in $(seq "${start}" $((start + count))); do 1785 end=$((start + range_size)) 1786 1787 # Avoid negative or zero-sized port ranges 1788 if [ $((end / 65534)) -gt $((start / 65534)) ]; then 1789 start=${end} 1790 end=$((end + 1)) 1791 fi 1792 srcstart=$((start + src_delta)) 1793 srcend=$((end + src_delta)) 1794 1795 for j in $(seq "$start" $((range_size / 2 + 1)) ${end}); do 1796 send_match "$(format)" "${j}" $((j + src_delta)) || return 1 1797 done 1798 1799 range_size=$((range_size + 1)) 1800 start=$((end + range_size)) 1801 done 1802 1803 nft flush ruleset 1804} 1805 1806# - add ranged element, check that packets match it 1807# - delete element again, check it is gone 1808test_bug_net_port_proto_match() { 1809 setup veth send_"${proto}" set || return ${ksft_skip} 1810 rstart=${start} 1811 1812 range_size=1 1813 for i in $(seq 1 10); do 1814 for j in $(seq 1 20) ; do 1815 local dport=$j 1816 1817 elem=$(printf "10.%d.%d.0/24 . %d-%d0 . 6-17 " ${i} ${j} ${dport} "$((dport+1))") 1818 1819 # too slow, do not test all addresses 1820 maybe_send_nomatch "$elem" $(printf "10.%d.%d.1" $i $j) $(printf "%d1" $((dport+1))) "before add" || return 1 1821 1822 nft "add element inet filter test { $elem }" || return 1 1823 1824 maybe_send_match "$elem" $(printf "10.%d.%d.1" $i $j) $(printf "%d" $dport) "after add" || return 1 1825 1826 nft "get element inet filter test { $elem }" | grep -q "$elem" 1827 if [ $? -ne 0 ];then 1828 local got=$(nft "get element inet filter test { $elem }") 1829 err "post-add: should have returned $elem but got $got" 1830 return 1 1831 fi 1832 1833 maybe_send_nomatch "$elem" $(printf "10.%d.%d.1" $i $j) $(printf "%d1" $((dport+1))) "out-of-range" || return 1 1834 done 1835 done 1836 1837 # recheck after set was filled 1838 for i in $(seq 1 10); do 1839 for j in $(seq 1 20) ; do 1840 local dport=$j 1841 1842 elem=$(printf "10.%d.%d.0/24 . %d-%d0 . 6-17 " ${i} ${j} ${dport} "$((dport+1))") 1843 1844 nft "get element inet filter test { $elem }" | grep -q "$elem" 1845 if [ $? -ne 0 ];then 1846 local got=$(nft "get element inet filter test { $elem }") 1847 err "post-fill: should have returned $elem but got $got" 1848 return 1 1849 fi 1850 1851 maybe_send_match "$elem" $(printf "10.%d.%d.1" $i $j) $(printf "%d" $dport) "recheck" || return 1 1852 maybe_send_nomatch "$elem" $(printf "10.%d.%d.1" $i $j) $(printf "%d1" $((dport+1))) "recheck out-of-range" || return 1 1853 done 1854 done 1855 1856 # random del and re-fetch 1857 for i in $(seq 1 10); do 1858 for j in $(seq 1 20) ; do 1859 local rnd=$((RANDOM%10)) 1860 local dport=$j 1861 local got="" 1862 1863 elem=$(printf "10.%d.%d.0/24 . %d-%d0 . 6-17 " ${i} ${j} ${dport} "$((dport+1))") 1864 if [ $rnd -gt 0 ];then 1865 continue 1866 fi 1867 1868 nft "delete element inet filter test { $elem }" 1869 got=$(nft "get element inet filter test { $elem }" 2>/dev/null) 1870 if [ $? -eq 0 ];then 1871 err "post-delete: query for $elem returned $got instead of error." 1872 return 1 1873 fi 1874 1875 maybe_send_nomatch "$elem" $(printf "10.%d.%d.1" $i $j) $(printf "%d" $dport) "match after deletion" || return 1 1876 done 1877 done 1878 1879 nft flush ruleset 1880} 1881 1882test_bug_avx2_mismatch() 1883{ 1884 setup veth send_"${proto}" set || return ${ksft_skip} 1885 1886 local a1="fe80:dead:01ff:0a02:0b03:6007:8009:a001" 1887 local a2="fe80:dead:01fe:0a02:0b03:6007:8009:a001" 1888 1889 nft "add element inet filter test { icmpv6 . $a1 }" 1890 1891 dst_addr6="$a2" 1892 send_icmp6 1893 1894 if [ "$(count_packets "{ icmpv6 . $a1 }")" -gt "0" ]; then 1895 err "False match for $a2" 1896 return 1 1897 fi 1898} 1899 1900test_reported_issues() { 1901 eval test_bug_"${subtest}" 1902} 1903 1904# Run everything in a separate network namespace 1905[ "${1}" != "run" ] && { unshare -n "${0}" run; exit $?; } 1906tmp="$(mktemp)" 1907trap cleanup_exit EXIT 1908 1909# Entry point for test runs 1910passed=0 1911for name in ${TESTS}; do 1912 printf "TEST: %s\n" "$(echo "$name" | tr '_' ' ')" 1913 if [ "${name}" = "reported_issues" ]; then 1914 SUBTESTS="${BUGS}" 1915 else 1916 SUBTESTS="${TYPES}" 1917 fi 1918 1919 for subtest in ${SUBTESTS}; do 1920 eval desc=\$TYPE_"${subtest}" 1921 IFS=' 1922' 1923 for __line in ${desc}; do 1924 # shellcheck disable=SC2086 1925 eval ${__line%% *}=\"${__line##* }\"; 1926 done 1927 IFS=' 1928' 1929 1930 if [ "${name}" = "concurrency" ] && \ 1931 [ "${race_repeat}" = "0" ]; then 1932 continue 1933 fi 1934 if [ "${name}" = "performance" ] && \ 1935 [ "${perf_duration}" = "0" ]; then 1936 continue 1937 fi 1938 1939 [ "$KSFT_MACHINE_SLOW" = "yes" ] && count=1 1940 1941 printf " %-32s " "${display}" 1942 tthen=$(date +%s) 1943 eval test_"${name}" 1944 ret=$? 1945 1946 tnow=$(date +%s) 1947 printf "%5ds%-30s" $((tnow-tthen)) 1948 1949 if [ $ret -eq 0 ]; then 1950 printf "[ OK ]\n" 1951 info_flush 1952 passed=$((passed + 1)) 1953 elif [ $ret -eq 1 ]; then 1954 printf "[FAIL]\n" 1955 err_flush 1956 exit 1 1957 elif [ $ret -eq ${ksft_skip} ]; then 1958 printf "[SKIP]\n" 1959 err_flush 1960 fi 1961 done 1962done 1963 1964[ ${passed} -eq 0 ] && exit ${ksft_skip} || exit 0 1965