1#!/bin/sh 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 11# ^ Configuration and templates sourced with eval, counters reused in subshells 12 13KSELFTEST_SKIP=4 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# - concurrency: attempt races between insertion, deletion and lookup 19# - timeout: check that packets match entries until they expire 20# - performance: estimate matching rate, compare with rbtree and hash baselines 21TESTS="reported_issues correctness concurrency timeout" 22[ "${quicktest}" != "1" ] && TESTS="${TESTS} performance" 23 24# Set types, defined by TYPE_ variables below 25TYPES="net_port port_net net6_port port_proto net6_port_mac net6_port_mac_proto 26 net_port_net net_mac mac_net net_mac_icmp net6_mac_icmp 27 net6_port_net6_port net_port_mac_proto_net" 28 29# Reported bugs, also described by TYPE_ variables below 30BUGS="flush_remove_add" 31 32# List of possible paths to pktgen script from kernel tree for performance tests 33PKTGEN_SCRIPT_PATHS=" 34 ../../../samples/pktgen/pktgen_bench_xmit_mode_netif_receive.sh 35 pktgen/pktgen_bench_xmit_mode_netif_receive.sh" 36 37# Definition of set types: 38# display display text for test report 39# type_spec nftables set type specifier 40# chain_spec nftables type specifier for rules mapping to set 41# dst call sequence of format_*() functions for destination fields 42# src call sequence of format_*() functions for source fields 43# start initial integer used to generate addresses and ports 44# count count of entries to generate and match 45# src_delta number summed to destination generator for source fields 46# tools list of tools for correctness and timeout tests, any can be used 47# proto L4 protocol of test packets 48# 49# race_repeat race attempts per thread, 0 disables concurrency test for type 50# flood_tools list of tools for concurrency tests, any can be used 51# flood_proto L4 protocol of test packets for concurrency tests 52# flood_spec nftables type specifier for concurrency tests 53# 54# perf_duration duration of single pktgen injection test 55# perf_spec nftables type specifier for performance tests 56# perf_dst format_*() functions for destination fields in performance test 57# perf_src format_*() functions for source fields in performance test 58# perf_entries number of set entries for performance test 59# perf_proto L3 protocol of test packets 60TYPE_net_port=" 61display net,port 62type_spec ipv4_addr . inet_service 63chain_spec ip daddr . udp dport 64dst addr4 port 65src 66start 1 67count 5 68src_delta 2000 69tools sendip nc bash 70proto udp 71 72race_repeat 3 73flood_tools iperf3 iperf netperf 74flood_proto udp 75flood_spec ip daddr . udp dport 76 77perf_duration 5 78perf_spec ip daddr . udp dport 79perf_dst addr4 port 80perf_src 81perf_entries 1000 82perf_proto ipv4 83" 84 85TYPE_port_net=" 86display port,net 87type_spec inet_service . ipv4_addr 88chain_spec udp dport . ip daddr 89dst port addr4 90src 91start 1 92count 5 93src_delta 2000 94tools sendip nc bash 95proto udp 96 97race_repeat 3 98flood_tools iperf3 iperf netperf 99flood_proto udp 100flood_spec udp dport . ip daddr 101 102perf_duration 5 103perf_spec udp dport . ip daddr 104perf_dst port addr4 105perf_src 106perf_entries 100 107perf_proto ipv4 108" 109 110TYPE_net6_port=" 111display net6,port 112type_spec ipv6_addr . inet_service 113chain_spec ip6 daddr . udp dport 114dst addr6 port 115src 116start 10 117count 5 118src_delta 2000 119tools sendip nc bash 120proto udp6 121 122race_repeat 3 123flood_tools iperf3 iperf netperf 124flood_proto tcp6 125flood_spec ip6 daddr . udp dport 126 127perf_duration 5 128perf_spec ip6 daddr . udp dport 129perf_dst addr6 port 130perf_src 131perf_entries 1000 132perf_proto ipv6 133" 134 135TYPE_port_proto=" 136display port,proto 137type_spec inet_service . inet_proto 138chain_spec udp dport . meta l4proto 139dst port proto 140src 141start 1 142count 5 143src_delta 2000 144tools sendip nc bash 145proto udp 146 147race_repeat 0 148 149perf_duration 5 150perf_spec udp dport . meta l4proto 151perf_dst port proto 152perf_src 153perf_entries 30000 154perf_proto ipv4 155" 156 157TYPE_net6_port_mac=" 158display net6,port,mac 159type_spec ipv6_addr . inet_service . ether_addr 160chain_spec ip6 daddr . udp dport . ether saddr 161dst addr6 port 162src mac 163start 10 164count 5 165src_delta 2000 166tools sendip nc bash 167proto udp6 168 169race_repeat 0 170 171perf_duration 5 172perf_spec ip6 daddr . udp dport . ether daddr 173perf_dst addr6 port mac 174perf_src 175perf_entries 10 176perf_proto ipv6 177" 178 179TYPE_net6_port_mac_proto=" 180display net6,port,mac,proto 181type_spec ipv6_addr . inet_service . ether_addr . inet_proto 182chain_spec ip6 daddr . udp dport . ether saddr . meta l4proto 183dst addr6 port 184src mac proto 185start 10 186count 5 187src_delta 2000 188tools sendip nc bash 189proto udp6 190 191race_repeat 0 192 193perf_duration 5 194perf_spec ip6 daddr . udp dport . ether daddr . meta l4proto 195perf_dst addr6 port mac proto 196perf_src 197perf_entries 1000 198perf_proto ipv6 199" 200 201TYPE_net_port_net=" 202display net,port,net 203type_spec ipv4_addr . inet_service . ipv4_addr 204chain_spec ip daddr . udp dport . ip saddr 205dst addr4 port 206src addr4 207start 1 208count 5 209src_delta 2000 210tools sendip nc bash 211proto udp 212 213race_repeat 3 214flood_tools iperf3 iperf netperf 215flood_proto tcp 216flood_spec ip daddr . udp dport . ip saddr 217 218perf_duration 0 219" 220 221TYPE_net6_port_net6_port=" 222display net6,port,net6,port 223type_spec ipv6_addr . inet_service . ipv6_addr . inet_service 224chain_spec ip6 daddr . udp dport . ip6 saddr . udp sport 225dst addr6 port 226src addr6 port 227start 10 228count 5 229src_delta 2000 230tools sendip nc 231proto udp6 232 233race_repeat 3 234flood_tools iperf3 iperf netperf 235flood_proto tcp6 236flood_spec ip6 daddr . tcp dport . ip6 saddr . tcp sport 237 238perf_duration 0 239" 240 241TYPE_net_port_mac_proto_net=" 242display net,port,mac,proto,net 243type_spec ipv4_addr . inet_service . ether_addr . inet_proto . ipv4_addr 244chain_spec ip daddr . udp dport . ether saddr . meta l4proto . ip saddr 245dst addr4 port 246src mac proto addr4 247start 1 248count 5 249src_delta 2000 250tools sendip nc bash 251proto udp 252 253race_repeat 0 254 255perf_duration 0 256" 257 258TYPE_net_mac=" 259display net,mac 260type_spec ipv4_addr . ether_addr 261chain_spec ip daddr . ether saddr 262dst addr4 263src mac 264start 1 265count 5 266src_delta 2000 267tools sendip nc bash 268proto udp 269 270race_repeat 0 271 272perf_duration 5 273perf_spec ip daddr . ether daddr 274perf_dst addr4 mac 275perf_src 276perf_entries 1000 277perf_proto ipv4 278" 279 280TYPE_mac_net=" 281display mac,net 282type_spec ether_addr . ipv4_addr 283chain_spec ether saddr . ip saddr 284dst 285src mac addr4 286start 1 287count 5 288src_delta 2000 289tools sendip nc bash 290proto udp 291 292race_repeat 0 293 294perf_duration 0 295" 296 297TYPE_net_mac_icmp=" 298display net,mac - ICMP 299type_spec ipv4_addr . ether_addr 300chain_spec ip daddr . ether saddr 301dst addr4 302src mac 303start 1 304count 5 305src_delta 2000 306tools ping 307proto icmp 308 309race_repeat 0 310 311perf_duration 0 312" 313 314TYPE_net6_mac_icmp=" 315display net6,mac - ICMPv6 316type_spec ipv6_addr . ether_addr 317chain_spec ip6 daddr . ether saddr 318dst addr6 319src mac 320start 10 321count 50 322src_delta 2000 323tools ping 324proto icmp6 325 326race_repeat 0 327 328perf_duration 0 329" 330 331TYPE_net_port_proto_net=" 332display net,port,proto,net 333type_spec ipv4_addr . inet_service . inet_proto . ipv4_addr 334chain_spec ip daddr . udp dport . meta l4proto . ip saddr 335dst addr4 port proto 336src addr4 337start 1 338count 5 339src_delta 2000 340tools sendip nc 341proto udp 342 343race_repeat 3 344flood_tools iperf3 iperf netperf 345flood_proto tcp 346flood_spec ip daddr . tcp dport . meta l4proto . ip saddr 347 348perf_duration 0 349" 350 351# Definition of tests for bugs reported in the past: 352# display display text for test report 353TYPE_flush_remove_add=" 354display Add two elements, flush, re-add 355" 356 357# Set template for all tests, types and rules are filled in depending on test 358set_template=' 359flush ruleset 360 361table inet filter { 362 counter test { 363 packets 0 bytes 0 364 } 365 366 set test { 367 type ${type_spec} 368 flags interval,timeout 369 } 370 371 chain input { 372 type filter hook prerouting priority 0; policy accept; 373 ${chain_spec} @test counter name \"test\" 374 } 375} 376 377table netdev perf { 378 counter test { 379 packets 0 bytes 0 380 } 381 382 counter match { 383 packets 0 bytes 0 384 } 385 386 set test { 387 type ${type_spec} 388 flags interval 389 } 390 391 set norange { 392 type ${type_spec} 393 } 394 395 set noconcat { 396 type ${type_spec%% *} 397 flags interval 398 } 399 400 chain test { 401 type filter hook ingress device veth_a priority 0; 402 } 403} 404' 405 406err_buf= 407info_buf= 408 409# Append string to error buffer 410err() { 411 err_buf="${err_buf}${1} 412" 413} 414 415# Append string to information buffer 416info() { 417 info_buf="${info_buf}${1} 418" 419} 420 421# Flush error buffer to stdout 422err_flush() { 423 printf "%s" "${err_buf}" 424 err_buf= 425} 426 427# Flush information buffer to stdout 428info_flush() { 429 printf "%s" "${info_buf}" 430 info_buf= 431} 432 433# Setup veth pair: this namespace receives traffic, B generates it 434setup_veth() { 435 ip netns add B 436 ip link add veth_a type veth peer name veth_b || return 1 437 438 ip link set veth_a up 439 ip link set veth_b netns B 440 441 ip -n B link set veth_b up 442 443 ip addr add dev veth_a 10.0.0.1 444 ip route add default dev veth_a 445 446 ip -6 addr add fe80::1/64 dev veth_a nodad 447 ip -6 addr add 2001:db8::1/64 dev veth_a nodad 448 ip -6 route add default dev veth_a 449 450 ip -n B route add default dev veth_b 451 452 ip -6 -n B addr add fe80::2/64 dev veth_b nodad 453 ip -6 -n B addr add 2001:db8::2/64 dev veth_b nodad 454 ip -6 -n B route add default dev veth_b 455 456 B() { 457 ip netns exec B "$@" >/dev/null 2>&1 458 } 459 460 sleep 2 461} 462 463# Fill in set template and initialise set 464setup_set() { 465 eval "echo \"${set_template}\"" | nft -f - 466} 467 468# Check that at least one of the needed tools is available 469check_tools() { 470 [ -z "${tools}" ] && return 0 471 472 __tools= 473 for tool in ${tools}; do 474 if [ "${tool}" = "nc" ] && [ "${proto}" = "udp6" ] && \ 475 ! nc -u -w0 1.1.1.1 1 2>/dev/null; then 476 # Some GNU netcat builds might not support IPv6 477 __tools="${__tools} netcat-openbsd" 478 continue 479 fi 480 __tools="${__tools} ${tool}" 481 482 command -v "${tool}" >/dev/null && return 0 483 done 484 err "need one of:${__tools}, skipping" && return 1 485} 486 487# Set up function to send ICMP packets 488setup_send_icmp() { 489 send_icmp() { 490 B ping -c1 -W1 "${dst_addr4}" >/dev/null 2>&1 491 } 492} 493 494# Set up function to send ICMPv6 packets 495setup_send_icmp6() { 496 if command -v ping6 >/dev/null; then 497 send_icmp6() { 498 ip -6 addr add "${dst_addr6}" dev veth_a nodad \ 499 2>/dev/null 500 B ping6 -q -c1 -W1 "${dst_addr6}" 501 } 502 else 503 send_icmp6() { 504 ip -6 addr add "${dst_addr6}" dev veth_a nodad \ 505 2>/dev/null 506 B ping -q -6 -c1 -W1 "${dst_addr6}" 507 } 508 fi 509} 510 511# Set up function to send single UDP packets on IPv4 512setup_send_udp() { 513 if command -v sendip >/dev/null; then 514 send_udp() { 515 [ -n "${src_port}" ] && src_port="-us ${src_port}" 516 [ -n "${dst_port}" ] && dst_port="-ud ${dst_port}" 517 [ -n "${src_addr4}" ] && src_addr4="-is ${src_addr4}" 518 519 # shellcheck disable=SC2086 # sendip needs split options 520 B sendip -p ipv4 -p udp ${src_addr4} ${src_port} \ 521 ${dst_port} "${dst_addr4}" 522 523 src_port= 524 dst_port= 525 src_addr4= 526 } 527 elif command -v nc >/dev/null; then 528 if nc -u -w0 1.1.1.1 1 2>/dev/null; then 529 # OpenBSD netcat 530 nc_opt="-w0" 531 else 532 # GNU netcat 533 nc_opt="-q0" 534 fi 535 536 send_udp() { 537 if [ -n "${src_addr4}" ]; then 538 B ip addr add "${src_addr4}" dev veth_b 539 __src_addr4="-s ${src_addr4}" 540 fi 541 ip addr add "${dst_addr4}" dev veth_a 2>/dev/null 542 [ -n "${src_port}" ] && src_port="-p ${src_port}" 543 544 echo "" | B nc -u "${nc_opt}" "${__src_addr4}" \ 545 "${src_port}" "${dst_addr4}" "${dst_port}" 546 547 src_addr4= 548 src_port= 549 } 550 elif [ -z "$(bash -c 'type -p')" ]; then 551 send_udp() { 552 ip addr add "${dst_addr4}" dev veth_a 2>/dev/null 553 if [ -n "${src_addr4}" ]; then 554 B ip addr add "${src_addr4}/16" dev veth_b 555 B ip route add default dev veth_b 556 fi 557 558 B bash -c "echo > /dev/udp/${dst_addr4}/${dst_port}" 559 560 if [ -n "${src_addr4}" ]; then 561 B ip addr del "${src_addr4}/16" dev veth_b 562 fi 563 src_addr4= 564 } 565 else 566 return 1 567 fi 568} 569 570# Set up function to send single UDP packets on IPv6 571setup_send_udp6() { 572 if command -v sendip >/dev/null; then 573 send_udp6() { 574 [ -n "${src_port}" ] && src_port="-us ${src_port}" 575 [ -n "${dst_port}" ] && dst_port="-ud ${dst_port}" 576 if [ -n "${src_addr6}" ]; then 577 src_addr6="-6s ${src_addr6}" 578 else 579 src_addr6="-6s 2001:db8::2" 580 fi 581 ip -6 addr add "${dst_addr6}" dev veth_a nodad \ 582 2>/dev/null 583 584 # shellcheck disable=SC2086 # this needs split options 585 B sendip -p ipv6 -p udp ${src_addr6} ${src_port} \ 586 ${dst_port} "${dst_addr6}" 587 588 src_port= 589 dst_port= 590 src_addr6= 591 } 592 elif command -v nc >/dev/null && nc -u -w0 1.1.1.1 1 2>/dev/null; then 593 # GNU netcat might not work with IPv6, try next tool 594 send_udp6() { 595 ip -6 addr add "${dst_addr6}" dev veth_a nodad \ 596 2>/dev/null 597 if [ -n "${src_addr6}" ]; then 598 B ip addr add "${src_addr6}" dev veth_b nodad 599 else 600 src_addr6="2001:db8::2" 601 fi 602 [ -n "${src_port}" ] && src_port="-p ${src_port}" 603 604 # shellcheck disable=SC2086 # this needs split options 605 echo "" | B nc -u w0 "-s${src_addr6}" ${src_port} \ 606 ${dst_addr6} ${dst_port} 607 608 src_addr6= 609 src_port= 610 } 611 elif [ -z "$(bash -c 'type -p')" ]; then 612 send_udp6() { 613 ip -6 addr add "${dst_addr6}" dev veth_a nodad \ 614 2>/dev/null 615 B ip addr add "${src_addr6}" dev veth_b nodad 616 B bash -c "echo > /dev/udp/${dst_addr6}/${dst_port}" 617 ip -6 addr del "${dst_addr6}" dev veth_a 2>/dev/null 618 } 619 else 620 return 1 621 fi 622} 623 624# Set up function to send TCP traffic on IPv4 625setup_flood_tcp() { 626 if command -v iperf3 >/dev/null; then 627 flood_tcp() { 628 [ -n "${dst_port}" ] && dst_port="-p ${dst_port}" 629 if [ -n "${src_addr4}" ]; then 630 B ip addr add "${src_addr4}/16" dev veth_b 631 src_addr4="-B ${src_addr4}" 632 else 633 B ip addr add dev veth_b 10.0.0.2 634 src_addr4="-B 10.0.0.2" 635 fi 636 if [ -n "${src_port}" ]; then 637 src_port="--cport ${src_port}" 638 fi 639 B ip route add default dev veth_b 2>/dev/null 640 ip addr add "${dst_addr4}" dev veth_a 2>/dev/null 641 642 # shellcheck disable=SC2086 # this needs split options 643 iperf3 -s -DB "${dst_addr4}" ${dst_port} >/dev/null 2>&1 644 sleep 2 645 646 # shellcheck disable=SC2086 # this needs split options 647 B iperf3 -c "${dst_addr4}" ${dst_port} ${src_port} \ 648 ${src_addr4} -l16 -t 1000 649 650 src_addr4= 651 src_port= 652 dst_port= 653 } 654 elif command -v iperf >/dev/null; then 655 flood_tcp() { 656 [ -n "${dst_port}" ] && dst_port="-p ${dst_port}" 657 if [ -n "${src_addr4}" ]; then 658 B ip addr add "${src_addr4}/16" dev veth_b 659 src_addr4="-B ${src_addr4}" 660 else 661 B ip addr add dev veth_b 10.0.0.2 2>/dev/null 662 src_addr4="-B 10.0.0.2" 663 fi 664 if [ -n "${src_port}" ]; then 665 src_addr4="${src_addr4}:${src_port}" 666 fi 667 B ip route add default dev veth_b 668 ip addr add "${dst_addr4}" dev veth_a 2>/dev/null 669 670 # shellcheck disable=SC2086 # this needs split options 671 iperf -s -DB "${dst_addr4}" ${dst_port} >/dev/null 2>&1 672 sleep 2 673 674 # shellcheck disable=SC2086 # this needs split options 675 B iperf -c "${dst_addr4}" ${dst_port} ${src_addr4} \ 676 -l20 -t 1000 677 678 src_addr4= 679 src_port= 680 dst_port= 681 } 682 elif command -v netperf >/dev/null; then 683 flood_tcp() { 684 [ -n "${dst_port}" ] && dst_port="-p ${dst_port}" 685 if [ -n "${src_addr4}" ]; then 686 B ip addr add "${src_addr4}/16" dev veth_b 687 else 688 B ip addr add dev veth_b 10.0.0.2 689 src_addr4="10.0.0.2" 690 fi 691 if [ -n "${src_port}" ]; then 692 dst_port="${dst_port},${src_port}" 693 fi 694 B ip route add default dev veth_b 695 ip addr add "${dst_addr4}" dev veth_a 2>/dev/null 696 697 # shellcheck disable=SC2086 # this needs split options 698 netserver -4 ${dst_port} -L "${dst_addr4}" \ 699 >/dev/null 2>&1 700 sleep 2 701 702 # shellcheck disable=SC2086 # this needs split options 703 B netperf -4 -H "${dst_addr4}" ${dst_port} \ 704 -L "${src_addr4}" -l 1000 -t TCP_STREAM 705 706 src_addr4= 707 src_port= 708 dst_port= 709 } 710 else 711 return 1 712 fi 713} 714 715# Set up function to send TCP traffic on IPv6 716setup_flood_tcp6() { 717 if command -v iperf3 >/dev/null; then 718 flood_tcp6() { 719 [ -n "${dst_port}" ] && dst_port="-p ${dst_port}" 720 if [ -n "${src_addr6}" ]; then 721 B ip addr add "${src_addr6}" dev veth_b nodad 722 src_addr6="-B ${src_addr6}" 723 else 724 src_addr6="-B 2001:db8::2" 725 fi 726 if [ -n "${src_port}" ]; then 727 src_port="--cport ${src_port}" 728 fi 729 B ip route add default dev veth_b 730 ip -6 addr add "${dst_addr6}" dev veth_a nodad \ 731 2>/dev/null 732 733 # shellcheck disable=SC2086 # this needs split options 734 iperf3 -s -DB "${dst_addr6}" ${dst_port} >/dev/null 2>&1 735 sleep 2 736 737 # shellcheck disable=SC2086 # this needs split options 738 B iperf3 -c "${dst_addr6}" ${dst_port} \ 739 ${src_port} ${src_addr6} -l16 -t 1000 740 741 src_addr6= 742 src_port= 743 dst_port= 744 } 745 elif command -v iperf >/dev/null; then 746 flood_tcp6() { 747 [ -n "${dst_port}" ] && dst_port="-p ${dst_port}" 748 if [ -n "${src_addr6}" ]; then 749 B ip addr add "${src_addr6}" dev veth_b nodad 750 src_addr6="-B ${src_addr6}" 751 else 752 src_addr6="-B 2001:db8::2" 753 fi 754 if [ -n "${src_port}" ]; then 755 src_addr6="${src_addr6}:${src_port}" 756 fi 757 B ip route add default dev veth_b 758 ip -6 addr add "${dst_addr6}" dev veth_a nodad \ 759 2>/dev/null 760 761 # shellcheck disable=SC2086 # this needs split options 762 iperf -s -VDB "${dst_addr6}" ${dst_port} >/dev/null 2>&1 763 sleep 2 764 765 # shellcheck disable=SC2086 # this needs split options 766 B iperf -c "${dst_addr6}" -V ${dst_port} \ 767 ${src_addr6} -l1 -t 1000 768 769 src_addr6= 770 src_port= 771 dst_port= 772 } 773 elif command -v netperf >/dev/null; then 774 flood_tcp6() { 775 [ -n "${dst_port}" ] && dst_port="-p ${dst_port}" 776 if [ -n "${src_addr6}" ]; then 777 B ip addr add "${src_addr6}" dev veth_b nodad 778 else 779 src_addr6="2001:db8::2" 780 fi 781 if [ -n "${src_port}" ]; then 782 dst_port="${dst_port},${src_port}" 783 fi 784 B ip route add default dev veth_b 785 ip -6 addr add "${dst_addr6}" dev veth_a nodad \ 786 2>/dev/null 787 788 # shellcheck disable=SC2086 # this needs split options 789 netserver -6 ${dst_port} -L "${dst_addr6}" \ 790 >/dev/null 2>&1 791 sleep 2 792 793 # shellcheck disable=SC2086 # this needs split options 794 B netperf -6 -H "${dst_addr6}" ${dst_port} \ 795 -L "${src_addr6}" -l 1000 -t TCP_STREAM 796 797 src_addr6= 798 src_port= 799 dst_port= 800 } 801 else 802 return 1 803 fi 804} 805 806# Set up function to send UDP traffic on IPv4 807setup_flood_udp() { 808 if command -v iperf3 >/dev/null; then 809 flood_udp() { 810 [ -n "${dst_port}" ] && dst_port="-p ${dst_port}" 811 if [ -n "${src_addr4}" ]; then 812 B ip addr add "${src_addr4}/16" dev veth_b 813 src_addr4="-B ${src_addr4}" 814 else 815 B ip addr add dev veth_b 10.0.0.2 2>/dev/null 816 src_addr4="-B 10.0.0.2" 817 fi 818 if [ -n "${src_port}" ]; then 819 src_port="--cport ${src_port}" 820 fi 821 B ip route add default dev veth_b 822 ip addr add "${dst_addr4}" dev veth_a 2>/dev/null 823 824 # shellcheck disable=SC2086 # this needs split options 825 iperf3 -s -DB "${dst_addr4}" ${dst_port} 826 sleep 2 827 828 # shellcheck disable=SC2086 # this needs split options 829 B iperf3 -u -c "${dst_addr4}" -Z -b 100M -l16 -t1000 \ 830 ${dst_port} ${src_port} ${src_addr4} 831 832 src_addr4= 833 src_port= 834 dst_port= 835 } 836 elif command -v iperf >/dev/null; then 837 flood_udp() { 838 [ -n "${dst_port}" ] && dst_port="-p ${dst_port}" 839 if [ -n "${src_addr4}" ]; then 840 B ip addr add "${src_addr4}/16" dev veth_b 841 src_addr4="-B ${src_addr4}" 842 else 843 B ip addr add dev veth_b 10.0.0.2 844 src_addr4="-B 10.0.0.2" 845 fi 846 if [ -n "${src_port}" ]; then 847 src_addr4="${src_addr4}:${src_port}" 848 fi 849 B ip route add default dev veth_b 850 ip addr add "${dst_addr4}" dev veth_a 2>/dev/null 851 852 # shellcheck disable=SC2086 # this needs split options 853 iperf -u -sDB "${dst_addr4}" ${dst_port} >/dev/null 2>&1 854 sleep 2 855 856 # shellcheck disable=SC2086 # this needs split options 857 B iperf -u -c "${dst_addr4}" -b 100M -l1 -t1000 \ 858 ${dst_port} ${src_addr4} 859 860 src_addr4= 861 src_port= 862 dst_port= 863 } 864 elif command -v netperf >/dev/null; then 865 flood_udp() { 866 [ -n "${dst_port}" ] && dst_port="-p ${dst_port}" 867 if [ -n "${src_addr4}" ]; then 868 B ip addr add "${src_addr4}/16" dev veth_b 869 else 870 B ip addr add dev veth_b 10.0.0.2 871 src_addr4="10.0.0.2" 872 fi 873 if [ -n "${src_port}" ]; then 874 dst_port="${dst_port},${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 netserver -4 ${dst_port} -L "${dst_addr4}" \ 881 >/dev/null 2>&1 882 sleep 2 883 884 # shellcheck disable=SC2086 # this needs split options 885 B netperf -4 -H "${dst_addr4}" ${dst_port} \ 886 -L "${src_addr4}" -l 1000 -t UDP_STREAM 887 888 src_addr4= 889 src_port= 890 dst_port= 891 } 892 else 893 return 1 894 fi 895} 896 897# Find pktgen script and set up function to start pktgen injection 898setup_perf() { 899 for pktgen_script_path in ${PKTGEN_SCRIPT_PATHS} __notfound; do 900 command -v "${pktgen_script_path}" >/dev/null && break 901 done 902 [ "${pktgen_script_path}" = "__notfound" ] && return 1 903 904 perf_ipv4() { 905 ${pktgen_script_path} -s80 \ 906 -i veth_a -d "${dst_addr4}" -p "${dst_port}" \ 907 -m "${dst_mac}" \ 908 -t $(($(nproc) / 5 + 1)) -b10000 -n0 2>/dev/null & 909 perf_pid=$! 910 } 911 perf_ipv6() { 912 IP6=6 ${pktgen_script_path} -s100 \ 913 -i veth_a -d "${dst_addr6}" -p "${dst_port}" \ 914 -m "${dst_mac}" \ 915 -t $(($(nproc) / 5 + 1)) -b10000 -n0 2>/dev/null & 916 perf_pid=$! 917 } 918} 919 920# Clean up before each test 921cleanup() { 922 nft reset counter inet filter test >/dev/null 2>&1 923 nft flush ruleset >/dev/null 2>&1 924 ip link del dummy0 2>/dev/null 925 ip route del default 2>/dev/null 926 ip -6 route del default 2>/dev/null 927 ip netns del B 2>/dev/null 928 ip link del veth_a 2>/dev/null 929 timeout= 930 killall iperf3 2>/dev/null 931 killall iperf 2>/dev/null 932 killall netperf 2>/dev/null 933 killall netserver 2>/dev/null 934 rm -f ${tmp} 935 sleep 2 936} 937 938# Entry point for setup functions 939setup() { 940 if [ "$(id -u)" -ne 0 ]; then 941 echo " need to run as root" 942 exit ${KSELFTEST_SKIP} 943 fi 944 945 cleanup 946 check_tools || return 1 947 for arg do 948 if ! eval setup_"${arg}"; then 949 err " ${arg} not supported" 950 return 1 951 fi 952 done 953} 954 955# Format integer into IPv4 address, summing 10.0.0.5 (arbitrary) to it 956format_addr4() { 957 a=$((${1} + 16777216 * 10 + 5)) 958 printf "%i.%i.%i.%i" \ 959 "$((a / 16777216))" "$((a % 16777216 / 65536))" \ 960 "$((a % 65536 / 256))" "$((a % 256))" 961} 962 963# Format integer into IPv6 address, summing 2001:db8:: to it 964format_addr6() { 965 printf "2001:db8::%04x:%04x" "$((${1} / 65536))" "$((${1} % 65536))" 966} 967 968# Format integer into EUI-48 address, summing 00:01:00:00:00:00 to it 969format_mac() { 970 printf "00:01:%02x:%02x:%02x:%02x" \ 971 "$((${1} / 16777216))" "$((${1} % 16777216 / 65536))" \ 972 "$((${1} % 65536 / 256))" "$((${1} % 256))" 973} 974 975# Format integer into port, avoid 0 port 976format_port() { 977 printf "%i" "$((${1} % 65534 + 1))" 978} 979 980# Drop suffixed '6' from L4 protocol, if any 981format_proto() { 982 printf "%s" "${proto}" | tr -d 6 983} 984 985# Format destination and source fields into nft concatenated type 986format() { 987 __start= 988 __end= 989 __expr="{ " 990 991 for f in ${dst}; do 992 [ "${__expr}" != "{ " ] && __expr="${__expr} . " 993 994 __start="$(eval format_"${f}" "${start}")" 995 __end="$(eval format_"${f}" "${end}")" 996 997 if [ "${f}" = "proto" ]; then 998 __expr="${__expr}${__start}" 999 else 1000 __expr="${__expr}${__start}-${__end}" 1001 fi 1002 done 1003 for f in ${src}; do 1004 [ "${__expr}" != "{ " ] && __expr="${__expr} . " 1005 1006 __start="$(eval format_"${f}" "${srcstart}")" 1007 __end="$(eval format_"${f}" "${srcend}")" 1008 1009 if [ "${f}" = "proto" ]; then 1010 __expr="${__expr}${__start}" 1011 else 1012 __expr="${__expr}${__start}-${__end}" 1013 fi 1014 done 1015 1016 if [ -n "${timeout}" ]; then 1017 echo "${__expr} timeout ${timeout}s }" 1018 else 1019 echo "${__expr} }" 1020 fi 1021} 1022 1023# Format destination and source fields into nft type, start element only 1024format_norange() { 1025 __expr="{ " 1026 1027 for f in ${dst}; do 1028 [ "${__expr}" != "{ " ] && __expr="${__expr} . " 1029 1030 __expr="${__expr}$(eval format_"${f}" "${start}")" 1031 done 1032 for f in ${src}; do 1033 __expr="${__expr} . $(eval format_"${f}" "${start}")" 1034 done 1035 1036 echo "${__expr} }" 1037} 1038 1039# Format first destination field into nft type 1040format_noconcat() { 1041 for f in ${dst}; do 1042 __start="$(eval format_"${f}" "${start}")" 1043 __end="$(eval format_"${f}" "${end}")" 1044 1045 if [ "${f}" = "proto" ]; then 1046 echo "{ ${__start} }" 1047 else 1048 echo "{ ${__start}-${__end} }" 1049 fi 1050 return 1051 done 1052} 1053 1054# Add single entry to 'test' set in 'inet filter' table 1055add() { 1056 if ! nft add element inet filter test "${1}"; then 1057 err "Failed to add ${1} given ruleset:" 1058 err "$(nft -a list ruleset)" 1059 return 1 1060 fi 1061} 1062 1063# Format and output entries for sets in 'netdev perf' table 1064add_perf() { 1065 if [ "${1}" = "test" ]; then 1066 echo "add element netdev perf test $(format)" 1067 elif [ "${1}" = "norange" ]; then 1068 echo "add element netdev perf norange $(format_norange)" 1069 elif [ "${1}" = "noconcat" ]; then 1070 echo "add element netdev perf noconcat $(format_noconcat)" 1071 fi 1072} 1073 1074# Add single entry to 'norange' set in 'netdev perf' table 1075add_perf_norange() { 1076 if ! nft add element netdev perf norange "${1}"; then 1077 err "Failed to add ${1} given ruleset:" 1078 err "$(nft -a list ruleset)" 1079 return 1 1080 fi 1081} 1082 1083# Add single entry to 'noconcat' set in 'netdev perf' table 1084add_perf_noconcat() { 1085 if ! nft add element netdev perf noconcat "${1}"; then 1086 err "Failed to add ${1} given ruleset:" 1087 err "$(nft -a list ruleset)" 1088 return 1 1089 fi 1090} 1091 1092# Delete single entry from set 1093del() { 1094 if ! nft delete element inet filter test "${1}"; then 1095 err "Failed to delete ${1} given ruleset:" 1096 err "$(nft -a list ruleset)" 1097 return 1 1098 fi 1099} 1100 1101# Return packet count from 'test' counter in 'inet filter' table 1102count_packets() { 1103 found=0 1104 for token in $(nft list counter inet filter test); do 1105 [ ${found} -eq 1 ] && echo "${token}" && return 1106 [ "${token}" = "packets" ] && found=1 1107 done 1108} 1109 1110# Return packet count from 'test' counter in 'netdev perf' table 1111count_perf_packets() { 1112 found=0 1113 for token in $(nft list counter netdev perf test); do 1114 [ ${found} -eq 1 ] && echo "${token}" && return 1115 [ "${token}" = "packets" ] && found=1 1116 done 1117} 1118 1119# Set MAC addresses, send traffic according to specifier 1120flood() { 1121 ip link set veth_a address "$(format_mac "${1}")" 1122 ip -n B link set veth_b address "$(format_mac "${2}")" 1123 1124 for f in ${dst}; do 1125 eval dst_"$f"=\$\(format_\$f "${1}"\) 1126 done 1127 for f in ${src}; do 1128 eval src_"$f"=\$\(format_\$f "${2}"\) 1129 done 1130 eval flood_\$proto 1131} 1132 1133# Set MAC addresses, start pktgen injection 1134perf() { 1135 dst_mac="$(format_mac "${1}")" 1136 ip link set veth_a address "${dst_mac}" 1137 1138 for f in ${dst}; do 1139 eval dst_"$f"=\$\(format_\$f "${1}"\) 1140 done 1141 for f in ${src}; do 1142 eval src_"$f"=\$\(format_\$f "${2}"\) 1143 done 1144 eval perf_\$perf_proto 1145} 1146 1147# Set MAC addresses, send single packet, check that it matches, reset counter 1148send_match() { 1149 ip link set veth_a address "$(format_mac "${1}")" 1150 ip -n B link set veth_b address "$(format_mac "${2}")" 1151 1152 for f in ${dst}; do 1153 eval dst_"$f"=\$\(format_\$f "${1}"\) 1154 done 1155 for f in ${src}; do 1156 eval src_"$f"=\$\(format_\$f "${2}"\) 1157 done 1158 eval send_\$proto 1159 if [ "$(count_packets)" != "1" ]; then 1160 err "${proto} packet to:" 1161 err " $(for f in ${dst}; do 1162 eval format_\$f "${1}"; printf ' '; done)" 1163 err "from:" 1164 err " $(for f in ${src}; do 1165 eval format_\$f "${2}"; printf ' '; done)" 1166 err "should have matched ruleset:" 1167 err "$(nft -a list ruleset)" 1168 return 1 1169 fi 1170 nft reset counter inet filter test >/dev/null 1171} 1172 1173# Set MAC addresses, send single packet, check that it doesn't match 1174send_nomatch() { 1175 ip link set veth_a address "$(format_mac "${1}")" 1176 ip -n B link set veth_b address "$(format_mac "${2}")" 1177 1178 for f in ${dst}; do 1179 eval dst_"$f"=\$\(format_\$f "${1}"\) 1180 done 1181 for f in ${src}; do 1182 eval src_"$f"=\$\(format_\$f "${2}"\) 1183 done 1184 eval send_\$proto 1185 if [ "$(count_packets)" != "0" ]; then 1186 err "${proto} packet to:" 1187 err " $(for f in ${dst}; do 1188 eval format_\$f "${1}"; printf ' '; done)" 1189 err "from:" 1190 err " $(for f in ${src}; do 1191 eval format_\$f "${2}"; printf ' '; done)" 1192 err "should not have matched ruleset:" 1193 err "$(nft -a list ruleset)" 1194 return 1 1195 fi 1196} 1197 1198# Correctness test template: 1199# - add ranged element, check that packets match it 1200# - check that packets outside range don't match it 1201# - remove some elements, check that packets don't match anymore 1202test_correctness() { 1203 setup veth send_"${proto}" set || return ${KSELFTEST_SKIP} 1204 1205 range_size=1 1206 for i in $(seq "${start}" $((start + count))); do 1207 end=$((start + range_size)) 1208 1209 # Avoid negative or zero-sized port ranges 1210 if [ $((end / 65534)) -gt $((start / 65534)) ]; then 1211 start=${end} 1212 end=$((end + 1)) 1213 fi 1214 srcstart=$((start + src_delta)) 1215 srcend=$((end + src_delta)) 1216 1217 add "$(format)" || return 1 1218 for j in $(seq ${start} $((range_size / 2 + 1)) ${end}); do 1219 send_match "${j}" $((j + src_delta)) || return 1 1220 done 1221 send_nomatch $((end + 1)) $((end + 1 + src_delta)) || return 1 1222 1223 # Delete elements now and then 1224 if [ $((i % 3)) -eq 0 ]; then 1225 del "$(format)" || return 1 1226 for j in $(seq ${start} \ 1227 $((range_size / 2 + 1)) ${end}); do 1228 send_nomatch "${j}" $((j + src_delta)) \ 1229 || return 1 1230 done 1231 fi 1232 1233 range_size=$((range_size + 1)) 1234 start=$((end + range_size)) 1235 done 1236} 1237 1238# Concurrency test template: 1239# - add all the elements 1240# - start a thread for each physical thread that: 1241# - adds all the elements 1242# - flushes the set 1243# - adds all the elements 1244# - flushes the entire ruleset 1245# - adds the set back 1246# - adds all the elements 1247# - delete all the elements 1248test_concurrency() { 1249 proto=${flood_proto} 1250 tools=${flood_tools} 1251 chain_spec=${flood_spec} 1252 setup veth flood_"${proto}" set || return ${KSELFTEST_SKIP} 1253 1254 range_size=1 1255 cstart=${start} 1256 flood_pids= 1257 for i in $(seq ${start} $((start + count))); do 1258 end=$((start + range_size)) 1259 srcstart=$((start + src_delta)) 1260 srcend=$((end + src_delta)) 1261 1262 add "$(format)" || return 1 1263 1264 flood "${i}" $((i + src_delta)) & flood_pids="${flood_pids} $!" 1265 1266 range_size=$((range_size + 1)) 1267 start=$((end + range_size)) 1268 done 1269 1270 sleep 10 1271 1272 pids= 1273 for c in $(seq 1 "$(nproc)"); do ( 1274 for r in $(seq 1 "${race_repeat}"); do 1275 range_size=1 1276 1277 # $start needs to be local to this subshell 1278 # shellcheck disable=SC2030 1279 start=${cstart} 1280 for i in $(seq ${start} $((start + count))); do 1281 end=$((start + range_size)) 1282 srcstart=$((start + src_delta)) 1283 srcend=$((end + src_delta)) 1284 1285 add "$(format)" 2>/dev/null 1286 1287 range_size=$((range_size + 1)) 1288 start=$((end + range_size)) 1289 done 1290 1291 nft flush inet filter test 2>/dev/null 1292 1293 range_size=1 1294 start=${cstart} 1295 for i in $(seq ${start} $((start + count))); do 1296 end=$((start + range_size)) 1297 srcstart=$((start + src_delta)) 1298 srcend=$((end + src_delta)) 1299 1300 add "$(format)" 2>/dev/null 1301 1302 range_size=$((range_size + 1)) 1303 start=$((end + range_size)) 1304 done 1305 1306 nft flush ruleset 1307 setup set 2>/dev/null 1308 1309 range_size=1 1310 start=${cstart} 1311 for i in $(seq ${start} $((start + count))); do 1312 end=$((start + range_size)) 1313 srcstart=$((start + src_delta)) 1314 srcend=$((end + src_delta)) 1315 1316 add "$(format)" 2>/dev/null 1317 1318 range_size=$((range_size + 1)) 1319 start=$((end + range_size)) 1320 done 1321 1322 range_size=1 1323 start=${cstart} 1324 for i in $(seq ${start} $((start + count))); do 1325 end=$((start + range_size)) 1326 srcstart=$((start + src_delta)) 1327 srcend=$((end + src_delta)) 1328 1329 del "$(format)" 2>/dev/null 1330 1331 range_size=$((range_size + 1)) 1332 start=$((end + range_size)) 1333 done 1334 done 1335 ) & pids="${pids} $!" 1336 done 1337 1338 # shellcheck disable=SC2046,SC2086 # word splitting wanted here 1339 wait $(for pid in ${pids}; do echo ${pid}; done) 1340 # shellcheck disable=SC2046,SC2086 1341 kill $(for pid in ${flood_pids}; do echo ${pid}; done) 2>/dev/null 1342 # shellcheck disable=SC2046,SC2086 1343 wait $(for pid in ${flood_pids}; do echo ${pid}; done) 2>/dev/null 1344 1345 return 0 1346} 1347 1348# Timeout test template: 1349# - add all the elements with 3s timeout while checking that packets match 1350# - wait 3s after the last insertion, check that packets don't match any entry 1351test_timeout() { 1352 setup veth send_"${proto}" set || return ${KSELFTEST_SKIP} 1353 1354 timeout=3 1355 range_size=1 1356 for i in $(seq "${start}" $((start + count))); do 1357 end=$((start + range_size)) 1358 srcstart=$((start + src_delta)) 1359 srcend=$((end + src_delta)) 1360 1361 add "$(format)" || return 1 1362 1363 for j in $(seq ${start} $((range_size / 2 + 1)) ${end}); do 1364 send_match "${j}" $((j + src_delta)) || return 1 1365 done 1366 1367 range_size=$((range_size + 1)) 1368 start=$((end + range_size)) 1369 done 1370 sleep 3 1371 for i in $(seq ${start} $((start + count))); do 1372 end=$((start + range_size)) 1373 srcstart=$((start + src_delta)) 1374 srcend=$((end + src_delta)) 1375 1376 for j in $(seq ${start} $((range_size / 2 + 1)) ${end}); do 1377 send_nomatch "${j}" $((j + src_delta)) || return 1 1378 done 1379 1380 range_size=$((range_size + 1)) 1381 start=$((end + range_size)) 1382 done 1383} 1384 1385# Performance test template: 1386# - add concatenated ranged entries 1387# - add non-ranged concatenated entries (for hash set matching rate baseline) 1388# - add ranged entries with first field only (for rbhash baseline) 1389# - start pktgen injection directly on device rx path of this namespace 1390# - measure drop only rate, hash and rbtree baselines, then matching rate 1391test_performance() { 1392 chain_spec=${perf_spec} 1393 dst="${perf_dst}" 1394 src="${perf_src}" 1395 setup veth perf set || return ${KSELFTEST_SKIP} 1396 1397 first=${start} 1398 range_size=1 1399 for set in test norange noconcat; do 1400 start=${first} 1401 for i in $(seq ${start} $((start + perf_entries))); do 1402 end=$((start + range_size)) 1403 srcstart=$((start + src_delta)) 1404 srcend=$((end + src_delta)) 1405 1406 if [ $((end / 65534)) -gt $((start / 65534)) ]; then 1407 start=${end} 1408 end=$((end + 1)) 1409 elif [ ${start} -eq ${end} ]; then 1410 end=$((start + 1)) 1411 fi 1412 1413 add_perf ${set} 1414 1415 start=$((end + range_size)) 1416 done > "${tmp}" 1417 nft -f "${tmp}" 1418 done 1419 1420 perf $((end - 1)) ${srcstart} 1421 1422 sleep 2 1423 1424 nft add rule netdev perf test counter name \"test\" drop 1425 nft reset counter netdev perf test >/dev/null 2>&1 1426 sleep "${perf_duration}" 1427 pps="$(printf %10s $(($(count_perf_packets) / perf_duration)))" 1428 info " baseline (drop from netdev hook): ${pps}pps" 1429 handle="$(nft -a list chain netdev perf test | grep counter)" 1430 handle="${handle##* }" 1431 nft delete rule netdev perf test handle "${handle}" 1432 1433 nft add rule "netdev perf test ${chain_spec} @norange \ 1434 counter name \"test\" drop" 1435 nft reset counter netdev perf test >/dev/null 2>&1 1436 sleep "${perf_duration}" 1437 pps="$(printf %10s $(($(count_perf_packets) / perf_duration)))" 1438 info " baseline hash (non-ranged entries): ${pps}pps" 1439 handle="$(nft -a list chain netdev perf test | grep counter)" 1440 handle="${handle##* }" 1441 nft delete rule netdev perf test handle "${handle}" 1442 1443 nft add rule "netdev perf test ${chain_spec%%. *} @noconcat \ 1444 counter name \"test\" drop" 1445 nft reset counter netdev perf test >/dev/null 2>&1 1446 sleep "${perf_duration}" 1447 pps="$(printf %10s $(($(count_perf_packets) / perf_duration)))" 1448 info " baseline rbtree (match on first field only): ${pps}pps" 1449 handle="$(nft -a list chain netdev perf test | grep counter)" 1450 handle="${handle##* }" 1451 nft delete rule netdev perf test handle "${handle}" 1452 1453 nft add rule "netdev perf test ${chain_spec} @test \ 1454 counter name \"test\" drop" 1455 nft reset counter netdev perf test >/dev/null 2>&1 1456 sleep "${perf_duration}" 1457 pps="$(printf %10s $(($(count_perf_packets) / perf_duration)))" 1458 p5="$(printf %5s "${perf_entries}")" 1459 info " set with ${p5} full, ranged entries: ${pps}pps" 1460 kill "${perf_pid}" 1461} 1462 1463test_bug_flush_remove_add() { 1464 set_cmd='{ set s { type ipv4_addr . inet_service; flags interval; }; }' 1465 elem1='{ 10.0.0.1 . 22-25, 10.0.0.1 . 10-20 }' 1466 elem2='{ 10.0.0.1 . 10-20, 10.0.0.1 . 22-25 }' 1467 for i in `seq 1 100`; do 1468 nft add table t ${set_cmd} || return ${KSELFTEST_SKIP} 1469 nft add element t s ${elem1} 2>/dev/null || return 1 1470 nft flush set t s 2>/dev/null || return 1 1471 nft add element t s ${elem2} 2>/dev/null || return 1 1472 done 1473 nft flush ruleset 1474} 1475 1476test_reported_issues() { 1477 eval test_bug_"${subtest}" 1478} 1479 1480# Run everything in a separate network namespace 1481[ "${1}" != "run" ] && { unshare -n "${0}" run; exit $?; } 1482tmp="$(mktemp)" 1483trap cleanup EXIT 1484 1485# Entry point for test runs 1486passed=0 1487for name in ${TESTS}; do 1488 printf "TEST: %s\n" "$(echo ${name} | tr '_' ' ')" 1489 if [ "${name}" = "reported_issues" ]; then 1490 SUBTESTS="${BUGS}" 1491 else 1492 SUBTESTS="${TYPES}" 1493 fi 1494 1495 for subtest in ${SUBTESTS}; do 1496 eval desc=\$TYPE_"${subtest}" 1497 IFS=' 1498' 1499 for __line in ${desc}; do 1500 # shellcheck disable=SC2086 1501 eval ${__line%% *}=\"${__line##* }\"; 1502 done 1503 IFS=' 1504' 1505 1506 if [ "${name}" = "concurrency" ] && \ 1507 [ "${race_repeat}" = "0" ]; then 1508 continue 1509 fi 1510 if [ "${name}" = "performance" ] && \ 1511 [ "${perf_duration}" = "0" ]; then 1512 continue 1513 fi 1514 1515 printf " %-60s " "${display}" 1516 eval test_"${name}" 1517 ret=$? 1518 1519 if [ $ret -eq 0 ]; then 1520 printf "[ OK ]\n" 1521 info_flush 1522 passed=$((passed + 1)) 1523 elif [ $ret -eq 1 ]; then 1524 printf "[FAIL]\n" 1525 err_flush 1526 exit 1 1527 elif [ $ret -eq ${KSELFTEST_SKIP} ]; then 1528 printf "[SKIP]\n" 1529 err_flush 1530 fi 1531 done 1532done 1533 1534[ ${passed} -eq 0 ] && exit ${KSELFTEST_SKIP} 1535