| #!/bin/sh |
| # SPDX-License-Identifier: GPL-2.0 |
| # |
| # nft_concat_range.sh - Tests for sets with concatenation of ranged fields |
| # |
| # Copyright (c) 2019 Red Hat GmbH |
| # |
| # Author: Stefano Brivio <sbrivio@redhat.com> |
| # |
| # shellcheck disable=SC2154,SC2034,SC2016,SC2030,SC2031 |
| # ^ Configuration and templates sourced with eval, counters reused in subshells |
| |
| KSELFTEST_SKIP=4 |
| |
| # Available test groups: |
| # - reported_issues: check for issues that were reported in the past |
| # - correctness: check that packets match given entries, and only those |
| # - concurrency: attempt races between insertion, deletion and lookup |
| # - timeout: check that packets match entries until they expire |
| # - performance: estimate matching rate, compare with rbtree and hash baselines |
| TESTS="reported_issues correctness concurrency timeout" |
| [ "${quicktest}" != "1" ] && TESTS="${TESTS} performance" |
| |
| # Set types, defined by TYPE_ variables below |
| TYPES="net_port port_net net6_port port_proto net6_port_mac net6_port_mac_proto |
| net_port_net net_mac net_mac_icmp net6_mac_icmp net6_port_net6_port |
| net_port_mac_proto_net" |
| |
| # Reported bugs, also described by TYPE_ variables below |
| BUGS="flush_remove_add" |
| |
| # List of possible paths to pktgen script from kernel tree for performance tests |
| PKTGEN_SCRIPT_PATHS=" |
| ../../../samples/pktgen/pktgen_bench_xmit_mode_netif_receive.sh |
| pktgen/pktgen_bench_xmit_mode_netif_receive.sh" |
| |
| # Definition of set types: |
| # display display text for test report |
| # type_spec nftables set type specifier |
| # chain_spec nftables type specifier for rules mapping to set |
| # dst call sequence of format_*() functions for destination fields |
| # src call sequence of format_*() functions for source fields |
| # start initial integer used to generate addresses and ports |
| # count count of entries to generate and match |
| # src_delta number summed to destination generator for source fields |
| # tools list of tools for correctness and timeout tests, any can be used |
| # proto L4 protocol of test packets |
| # |
| # race_repeat race attempts per thread, 0 disables concurrency test for type |
| # flood_tools list of tools for concurrency tests, any can be used |
| # flood_proto L4 protocol of test packets for concurrency tests |
| # flood_spec nftables type specifier for concurrency tests |
| # |
| # perf_duration duration of single pktgen injection test |
| # perf_spec nftables type specifier for performance tests |
| # perf_dst format_*() functions for destination fields in performance test |
| # perf_src format_*() functions for source fields in performance test |
| # perf_entries number of set entries for performance test |
| # perf_proto L3 protocol of test packets |
| TYPE_net_port=" |
| display net,port |
| type_spec ipv4_addr . inet_service |
| chain_spec ip daddr . udp dport |
| dst addr4 port |
| src |
| start 1 |
| count 5 |
| src_delta 2000 |
| tools sendip nc bash |
| proto udp |
| |
| race_repeat 3 |
| flood_tools iperf3 iperf netperf |
| flood_proto udp |
| flood_spec ip daddr . udp dport |
| |
| perf_duration 5 |
| perf_spec ip daddr . udp dport |
| perf_dst addr4 port |
| perf_src |
| perf_entries 1000 |
| perf_proto ipv4 |
| " |
| |
| TYPE_port_net=" |
| display port,net |
| type_spec inet_service . ipv4_addr |
| chain_spec udp dport . ip daddr |
| dst port addr4 |
| src |
| start 1 |
| count 5 |
| src_delta 2000 |
| tools sendip nc bash |
| proto udp |
| |
| race_repeat 3 |
| flood_tools iperf3 iperf netperf |
| flood_proto udp |
| flood_spec udp dport . ip daddr |
| |
| perf_duration 5 |
| perf_spec udp dport . ip daddr |
| perf_dst port addr4 |
| perf_src |
| perf_entries 100 |
| perf_proto ipv4 |
| " |
| |
| TYPE_net6_port=" |
| display net6,port |
| type_spec ipv6_addr . inet_service |
| chain_spec ip6 daddr . udp dport |
| dst addr6 port |
| src |
| start 10 |
| count 5 |
| src_delta 2000 |
| tools sendip nc bash |
| proto udp6 |
| |
| race_repeat 3 |
| flood_tools iperf3 iperf netperf |
| flood_proto tcp6 |
| flood_spec ip6 daddr . udp dport |
| |
| perf_duration 5 |
| perf_spec ip6 daddr . udp dport |
| perf_dst addr6 port |
| perf_src |
| perf_entries 1000 |
| perf_proto ipv6 |
| " |
| |
| TYPE_port_proto=" |
| display port,proto |
| type_spec inet_service . inet_proto |
| chain_spec udp dport . meta l4proto |
| dst port proto |
| src |
| start 1 |
| count 5 |
| src_delta 2000 |
| tools sendip nc bash |
| proto udp |
| |
| race_repeat 0 |
| |
| perf_duration 5 |
| perf_spec udp dport . meta l4proto |
| perf_dst port proto |
| perf_src |
| perf_entries 30000 |
| perf_proto ipv4 |
| " |
| |
| TYPE_net6_port_mac=" |
| display net6,port,mac |
| type_spec ipv6_addr . inet_service . ether_addr |
| chain_spec ip6 daddr . udp dport . ether saddr |
| dst addr6 port |
| src mac |
| start 10 |
| count 5 |
| src_delta 2000 |
| tools sendip nc bash |
| proto udp6 |
| |
| race_repeat 0 |
| |
| perf_duration 5 |
| perf_spec ip6 daddr . udp dport . ether daddr |
| perf_dst addr6 port mac |
| perf_src |
| perf_entries 10 |
| perf_proto ipv6 |
| " |
| |
| TYPE_net6_port_mac_proto=" |
| display net6,port,mac,proto |
| type_spec ipv6_addr . inet_service . ether_addr . inet_proto |
| chain_spec ip6 daddr . udp dport . ether saddr . meta l4proto |
| dst addr6 port |
| src mac proto |
| start 10 |
| count 5 |
| src_delta 2000 |
| tools sendip nc bash |
| proto udp6 |
| |
| race_repeat 0 |
| |
| perf_duration 5 |
| perf_spec ip6 daddr . udp dport . ether daddr . meta l4proto |
| perf_dst addr6 port mac proto |
| perf_src |
| perf_entries 1000 |
| perf_proto ipv6 |
| " |
| |
| TYPE_net_port_net=" |
| display net,port,net |
| type_spec ipv4_addr . inet_service . ipv4_addr |
| chain_spec ip daddr . udp dport . ip saddr |
| dst addr4 port |
| src addr4 |
| start 1 |
| count 5 |
| src_delta 2000 |
| tools sendip nc bash |
| proto udp |
| |
| race_repeat 3 |
| flood_tools iperf3 iperf netperf |
| flood_proto tcp |
| flood_spec ip daddr . udp dport . ip saddr |
| |
| perf_duration 0 |
| " |
| |
| TYPE_net6_port_net6_port=" |
| display net6,port,net6,port |
| type_spec ipv6_addr . inet_service . ipv6_addr . inet_service |
| chain_spec ip6 daddr . udp dport . ip6 saddr . udp sport |
| dst addr6 port |
| src addr6 port |
| start 10 |
| count 5 |
| src_delta 2000 |
| tools sendip nc |
| proto udp6 |
| |
| race_repeat 3 |
| flood_tools iperf3 iperf netperf |
| flood_proto tcp6 |
| flood_spec ip6 daddr . tcp dport . ip6 saddr . tcp sport |
| |
| perf_duration 0 |
| " |
| |
| TYPE_net_port_mac_proto_net=" |
| display net,port,mac,proto,net |
| type_spec ipv4_addr . inet_service . ether_addr . inet_proto . ipv4_addr |
| chain_spec ip daddr . udp dport . ether saddr . meta l4proto . ip saddr |
| dst addr4 port |
| src mac proto addr4 |
| start 1 |
| count 5 |
| src_delta 2000 |
| tools sendip nc bash |
| proto udp |
| |
| race_repeat 0 |
| |
| perf_duration 0 |
| " |
| |
| TYPE_net_mac=" |
| display net,mac |
| type_spec ipv4_addr . ether_addr |
| chain_spec ip daddr . ether saddr |
| dst addr4 |
| src mac |
| start 1 |
| count 5 |
| src_delta 2000 |
| tools sendip nc bash |
| proto udp |
| |
| race_repeat 0 |
| |
| perf_duration 5 |
| perf_spec ip daddr . ether daddr |
| perf_dst addr4 mac |
| perf_src |
| perf_entries 1000 |
| perf_proto ipv4 |
| " |
| |
| TYPE_net_mac_icmp=" |
| display net,mac - ICMP |
| type_spec ipv4_addr . ether_addr |
| chain_spec ip daddr . ether saddr |
| dst addr4 |
| src mac |
| start 1 |
| count 5 |
| src_delta 2000 |
| tools ping |
| proto icmp |
| |
| race_repeat 0 |
| |
| perf_duration 0 |
| " |
| |
| TYPE_net6_mac_icmp=" |
| display net6,mac - ICMPv6 |
| type_spec ipv6_addr . ether_addr |
| chain_spec ip6 daddr . ether saddr |
| dst addr6 |
| src mac |
| start 10 |
| count 50 |
| src_delta 2000 |
| tools ping |
| proto icmp6 |
| |
| race_repeat 0 |
| |
| perf_duration 0 |
| " |
| |
| TYPE_net_port_proto_net=" |
| display net,port,proto,net |
| type_spec ipv4_addr . inet_service . inet_proto . ipv4_addr |
| chain_spec ip daddr . udp dport . meta l4proto . ip saddr |
| dst addr4 port proto |
| src addr4 |
| start 1 |
| count 5 |
| src_delta 2000 |
| tools sendip nc |
| proto udp |
| |
| race_repeat 3 |
| flood_tools iperf3 iperf netperf |
| flood_proto tcp |
| flood_spec ip daddr . tcp dport . meta l4proto . ip saddr |
| |
| perf_duration 0 |
| " |
| |
| # Definition of tests for bugs reported in the past: |
| # display display text for test report |
| TYPE_flush_remove_add=" |
| display Add two elements, flush, re-add |
| " |
| |
| # Set template for all tests, types and rules are filled in depending on test |
| set_template=' |
| flush ruleset |
| |
| table inet filter { |
| counter test { |
| packets 0 bytes 0 |
| } |
| |
| set test { |
| type ${type_spec} |
| flags interval,timeout |
| } |
| |
| chain input { |
| type filter hook prerouting priority 0; policy accept; |
| ${chain_spec} @test counter name \"test\" |
| } |
| } |
| |
| table netdev perf { |
| counter test { |
| packets 0 bytes 0 |
| } |
| |
| counter match { |
| packets 0 bytes 0 |
| } |
| |
| set test { |
| type ${type_spec} |
| flags interval |
| } |
| |
| set norange { |
| type ${type_spec} |
| } |
| |
| set noconcat { |
| type ${type_spec%% *} |
| flags interval |
| } |
| |
| chain test { |
| type filter hook ingress device veth_a priority 0; |
| } |
| } |
| ' |
| |
| err_buf= |
| info_buf= |
| |
| # Append string to error buffer |
| err() { |
| err_buf="${err_buf}${1} |
| " |
| } |
| |
| # Append string to information buffer |
| info() { |
| info_buf="${info_buf}${1} |
| " |
| } |
| |
| # Flush error buffer to stdout |
| err_flush() { |
| printf "%s" "${err_buf}" |
| err_buf= |
| } |
| |
| # Flush information buffer to stdout |
| info_flush() { |
| printf "%s" "${info_buf}" |
| info_buf= |
| } |
| |
| # Setup veth pair: this namespace receives traffic, B generates it |
| setup_veth() { |
| ip netns add B |
| ip link add veth_a type veth peer name veth_b || return 1 |
| |
| ip link set veth_a up |
| ip link set veth_b netns B |
| |
| ip -n B link set veth_b up |
| |
| ip addr add dev veth_a 10.0.0.1 |
| ip route add default dev veth_a |
| |
| ip -6 addr add fe80::1/64 dev veth_a nodad |
| ip -6 addr add 2001:db8::1/64 dev veth_a nodad |
| ip -6 route add default dev veth_a |
| |
| ip -n B route add default dev veth_b |
| |
| ip -6 -n B addr add fe80::2/64 dev veth_b nodad |
| ip -6 -n B addr add 2001:db8::2/64 dev veth_b nodad |
| ip -6 -n B route add default dev veth_b |
| |
| B() { |
| ip netns exec B "$@" >/dev/null 2>&1 |
| } |
| |
| sleep 2 |
| } |
| |
| # Fill in set template and initialise set |
| setup_set() { |
| eval "echo \"${set_template}\"" | nft -f - |
| } |
| |
| # Check that at least one of the needed tools is available |
| check_tools() { |
| [ -z "${tools}" ] && return 0 |
| |
| __tools= |
| for tool in ${tools}; do |
| if [ "${tool}" = "nc" ] && [ "${proto}" = "udp6" ] && \ |
| ! nc -u -w0 1.1.1.1 1 2>/dev/null; then |
| # Some GNU netcat builds might not support IPv6 |
| __tools="${__tools} netcat-openbsd" |
| continue |
| fi |
| __tools="${__tools} ${tool}" |
| |
| command -v "${tool}" >/dev/null && return 0 |
| done |
| err "need one of:${__tools}, skipping" && return 1 |
| } |
| |
| # Set up function to send ICMP packets |
| setup_send_icmp() { |
| send_icmp() { |
| B ping -c1 -W1 "${dst_addr4}" >/dev/null 2>&1 |
| } |
| } |
| |
| # Set up function to send ICMPv6 packets |
| setup_send_icmp6() { |
| if command -v ping6 >/dev/null; then |
| send_icmp6() { |
| ip -6 addr add "${dst_addr6}" dev veth_a nodad \ |
| 2>/dev/null |
| B ping6 -q -c1 -W1 "${dst_addr6}" |
| } |
| else |
| send_icmp6() { |
| ip -6 addr add "${dst_addr6}" dev veth_a nodad \ |
| 2>/dev/null |
| B ping -q -6 -c1 -W1 "${dst_addr6}" |
| } |
| fi |
| } |
| |
| # Set up function to send single UDP packets on IPv4 |
| setup_send_udp() { |
| if command -v sendip >/dev/null; then |
| send_udp() { |
| [ -n "${src_port}" ] && src_port="-us ${src_port}" |
| [ -n "${dst_port}" ] && dst_port="-ud ${dst_port}" |
| [ -n "${src_addr4}" ] && src_addr4="-is ${src_addr4}" |
| |
| # shellcheck disable=SC2086 # sendip needs split options |
| B sendip -p ipv4 -p udp ${src_addr4} ${src_port} \ |
| ${dst_port} "${dst_addr4}" |
| |
| src_port= |
| dst_port= |
| src_addr4= |
| } |
| elif command -v nc >/dev/null; then |
| if nc -u -w0 1.1.1.1 1 2>/dev/null; then |
| # OpenBSD netcat |
| nc_opt="-w0" |
| else |
| # GNU netcat |
| nc_opt="-q0" |
| fi |
| |
| send_udp() { |
| if [ -n "${src_addr4}" ]; then |
| B ip addr add "${src_addr4}" dev veth_b |
| __src_addr4="-s ${src_addr4}" |
| fi |
| ip addr add "${dst_addr4}" dev veth_a 2>/dev/null |
| [ -n "${src_port}" ] && src_port="-p ${src_port}" |
| |
| echo "" | B nc -u "${nc_opt}" "${__src_addr4}" \ |
| "${src_port}" "${dst_addr4}" "${dst_port}" |
| |
| src_addr4= |
| src_port= |
| } |
| elif [ -z "$(bash -c 'type -p')" ]; then |
| send_udp() { |
| ip addr add "${dst_addr4}" dev veth_a 2>/dev/null |
| if [ -n "${src_addr4}" ]; then |
| B ip addr add "${src_addr4}/16" dev veth_b |
| B ip route add default dev veth_b |
| fi |
| |
| B bash -c "echo > /dev/udp/${dst_addr4}/${dst_port}" |
| |
| if [ -n "${src_addr4}" ]; then |
| B ip addr del "${src_addr4}/16" dev veth_b |
| fi |
| src_addr4= |
| } |
| else |
| return 1 |
| fi |
| } |
| |
| # Set up function to send single UDP packets on IPv6 |
| setup_send_udp6() { |
| if command -v sendip >/dev/null; then |
| send_udp6() { |
| [ -n "${src_port}" ] && src_port="-us ${src_port}" |
| [ -n "${dst_port}" ] && dst_port="-ud ${dst_port}" |
| if [ -n "${src_addr6}" ]; then |
| src_addr6="-6s ${src_addr6}" |
| else |
| src_addr6="-6s 2001:db8::2" |
| fi |
| ip -6 addr add "${dst_addr6}" dev veth_a nodad \ |
| 2>/dev/null |
| |
| # shellcheck disable=SC2086 # this needs split options |
| B sendip -p ipv6 -p udp ${src_addr6} ${src_port} \ |
| ${dst_port} "${dst_addr6}" |
| |
| src_port= |
| dst_port= |
| src_addr6= |
| } |
| elif command -v nc >/dev/null && nc -u -w0 1.1.1.1 1 2>/dev/null; then |
| # GNU netcat might not work with IPv6, try next tool |
| send_udp6() { |
| ip -6 addr add "${dst_addr6}" dev veth_a nodad \ |
| 2>/dev/null |
| if [ -n "${src_addr6}" ]; then |
| B ip addr add "${src_addr6}" dev veth_b nodad |
| else |
| src_addr6="2001:db8::2" |
| fi |
| [ -n "${src_port}" ] && src_port="-p ${src_port}" |
| |
| # shellcheck disable=SC2086 # this needs split options |
| echo "" | B nc -u w0 "-s${src_addr6}" ${src_port} \ |
| ${dst_addr6} ${dst_port} |
| |
| src_addr6= |
| src_port= |
| } |
| elif [ -z "$(bash -c 'type -p')" ]; then |
| send_udp6() { |
| ip -6 addr add "${dst_addr6}" dev veth_a nodad \ |
| 2>/dev/null |
| B ip addr add "${src_addr6}" dev veth_b nodad |
| B bash -c "echo > /dev/udp/${dst_addr6}/${dst_port}" |
| ip -6 addr del "${dst_addr6}" dev veth_a 2>/dev/null |
| } |
| else |
| return 1 |
| fi |
| } |
| |
| # Set up function to send TCP traffic on IPv4 |
| setup_flood_tcp() { |
| if command -v iperf3 >/dev/null; then |
| flood_tcp() { |
| [ -n "${dst_port}" ] && dst_port="-p ${dst_port}" |
| if [ -n "${src_addr4}" ]; then |
| B ip addr add "${src_addr4}/16" dev veth_b |
| src_addr4="-B ${src_addr4}" |
| else |
| B ip addr add dev veth_b 10.0.0.2 |
| src_addr4="-B 10.0.0.2" |
| fi |
| if [ -n "${src_port}" ]; then |
| src_port="--cport ${src_port}" |
| fi |
| B ip route add default dev veth_b 2>/dev/null |
| ip addr add "${dst_addr4}" dev veth_a 2>/dev/null |
| |
| # shellcheck disable=SC2086 # this needs split options |
| iperf3 -s -DB "${dst_addr4}" ${dst_port} >/dev/null 2>&1 |
| sleep 2 |
| |
| # shellcheck disable=SC2086 # this needs split options |
| B iperf3 -c "${dst_addr4}" ${dst_port} ${src_port} \ |
| ${src_addr4} -l16 -t 1000 |
| |
| src_addr4= |
| src_port= |
| dst_port= |
| } |
| elif command -v iperf >/dev/null; then |
| flood_tcp() { |
| [ -n "${dst_port}" ] && dst_port="-p ${dst_port}" |
| if [ -n "${src_addr4}" ]; then |
| B ip addr add "${src_addr4}/16" dev veth_b |
| src_addr4="-B ${src_addr4}" |
| else |
| B ip addr add dev veth_b 10.0.0.2 2>/dev/null |
| src_addr4="-B 10.0.0.2" |
| fi |
| if [ -n "${src_port}" ]; then |
| src_addr4="${src_addr4}:${src_port}" |
| fi |
| B ip route add default dev veth_b |
| ip addr add "${dst_addr4}" dev veth_a 2>/dev/null |
| |
| # shellcheck disable=SC2086 # this needs split options |
| iperf -s -DB "${dst_addr4}" ${dst_port} >/dev/null 2>&1 |
| sleep 2 |
| |
| # shellcheck disable=SC2086 # this needs split options |
| B iperf -c "${dst_addr4}" ${dst_port} ${src_addr4} \ |
| -l20 -t 1000 |
| |
| src_addr4= |
| src_port= |
| dst_port= |
| } |
| elif command -v netperf >/dev/null; then |
| flood_tcp() { |
| [ -n "${dst_port}" ] && dst_port="-p ${dst_port}" |
| if [ -n "${src_addr4}" ]; then |
| B ip addr add "${src_addr4}/16" dev veth_b |
| else |
| B ip addr add dev veth_b 10.0.0.2 |
| src_addr4="10.0.0.2" |
| fi |
| if [ -n "${src_port}" ]; then |
| dst_port="${dst_port},${src_port}" |
| fi |
| B ip route add default dev veth_b |
| ip addr add "${dst_addr4}" dev veth_a 2>/dev/null |
| |
| # shellcheck disable=SC2086 # this needs split options |
| netserver -4 ${dst_port} -L "${dst_addr4}" \ |
| >/dev/null 2>&1 |
| sleep 2 |
| |
| # shellcheck disable=SC2086 # this needs split options |
| B netperf -4 -H "${dst_addr4}" ${dst_port} \ |
| -L "${src_addr4}" -l 1000 -t TCP_STREAM |
| |
| src_addr4= |
| src_port= |
| dst_port= |
| } |
| else |
| return 1 |
| fi |
| } |
| |
| # Set up function to send TCP traffic on IPv6 |
| setup_flood_tcp6() { |
| if command -v iperf3 >/dev/null; then |
| flood_tcp6() { |
| [ -n "${dst_port}" ] && dst_port="-p ${dst_port}" |
| if [ -n "${src_addr6}" ]; then |
| B ip addr add "${src_addr6}" dev veth_b nodad |
| src_addr6="-B ${src_addr6}" |
| else |
| src_addr6="-B 2001:db8::2" |
| fi |
| if [ -n "${src_port}" ]; then |
| src_port="--cport ${src_port}" |
| fi |
| B ip route add default dev veth_b |
| ip -6 addr add "${dst_addr6}" dev veth_a nodad \ |
| 2>/dev/null |
| |
| # shellcheck disable=SC2086 # this needs split options |
| iperf3 -s -DB "${dst_addr6}" ${dst_port} >/dev/null 2>&1 |
| sleep 2 |
| |
| # shellcheck disable=SC2086 # this needs split options |
| B iperf3 -c "${dst_addr6}" ${dst_port} \ |
| ${src_port} ${src_addr6} -l16 -t 1000 |
| |
| src_addr6= |
| src_port= |
| dst_port= |
| } |
| elif command -v iperf >/dev/null; then |
| flood_tcp6() { |
| [ -n "${dst_port}" ] && dst_port="-p ${dst_port}" |
| if [ -n "${src_addr6}" ]; then |
| B ip addr add "${src_addr6}" dev veth_b nodad |
| src_addr6="-B ${src_addr6}" |
| else |
| src_addr6="-B 2001:db8::2" |
| fi |
| if [ -n "${src_port}" ]; then |
| src_addr6="${src_addr6}:${src_port}" |
| fi |
| B ip route add default dev veth_b |
| ip -6 addr add "${dst_addr6}" dev veth_a nodad \ |
| 2>/dev/null |
| |
| # shellcheck disable=SC2086 # this needs split options |
| iperf -s -VDB "${dst_addr6}" ${dst_port} >/dev/null 2>&1 |
| sleep 2 |
| |
| # shellcheck disable=SC2086 # this needs split options |
| B iperf -c "${dst_addr6}" -V ${dst_port} \ |
| ${src_addr6} -l1 -t 1000 |
| |
| src_addr6= |
| src_port= |
| dst_port= |
| } |
| elif command -v netperf >/dev/null; then |
| flood_tcp6() { |
| [ -n "${dst_port}" ] && dst_port="-p ${dst_port}" |
| if [ -n "${src_addr6}" ]; then |
| B ip addr add "${src_addr6}" dev veth_b nodad |
| else |
| src_addr6="2001:db8::2" |
| fi |
| if [ -n "${src_port}" ]; then |
| dst_port="${dst_port},${src_port}" |
| fi |
| B ip route add default dev veth_b |
| ip -6 addr add "${dst_addr6}" dev veth_a nodad \ |
| 2>/dev/null |
| |
| # shellcheck disable=SC2086 # this needs split options |
| netserver -6 ${dst_port} -L "${dst_addr6}" \ |
| >/dev/null 2>&1 |
| sleep 2 |
| |
| # shellcheck disable=SC2086 # this needs split options |
| B netperf -6 -H "${dst_addr6}" ${dst_port} \ |
| -L "${src_addr6}" -l 1000 -t TCP_STREAM |
| |
| src_addr6= |
| src_port= |
| dst_port= |
| } |
| else |
| return 1 |
| fi |
| } |
| |
| # Set up function to send UDP traffic on IPv4 |
| setup_flood_udp() { |
| if command -v iperf3 >/dev/null; then |
| flood_udp() { |
| [ -n "${dst_port}" ] && dst_port="-p ${dst_port}" |
| if [ -n "${src_addr4}" ]; then |
| B ip addr add "${src_addr4}/16" dev veth_b |
| src_addr4="-B ${src_addr4}" |
| else |
| B ip addr add dev veth_b 10.0.0.2 2>/dev/null |
| src_addr4="-B 10.0.0.2" |
| fi |
| if [ -n "${src_port}" ]; then |
| src_port="--cport ${src_port}" |
| fi |
| B ip route add default dev veth_b |
| ip addr add "${dst_addr4}" dev veth_a 2>/dev/null |
| |
| # shellcheck disable=SC2086 # this needs split options |
| iperf3 -s -DB "${dst_addr4}" ${dst_port} |
| sleep 2 |
| |
| # shellcheck disable=SC2086 # this needs split options |
| B iperf3 -u -c "${dst_addr4}" -Z -b 100M -l16 -t1000 \ |
| ${dst_port} ${src_port} ${src_addr4} |
| |
| src_addr4= |
| src_port= |
| dst_port= |
| } |
| elif command -v iperf >/dev/null; then |
| flood_udp() { |
| [ -n "${dst_port}" ] && dst_port="-p ${dst_port}" |
| if [ -n "${src_addr4}" ]; then |
| B ip addr add "${src_addr4}/16" dev veth_b |
| src_addr4="-B ${src_addr4}" |
| else |
| B ip addr add dev veth_b 10.0.0.2 |
| src_addr4="-B 10.0.0.2" |
| fi |
| if [ -n "${src_port}" ]; then |
| src_addr4="${src_addr4}:${src_port}" |
| fi |
| B ip route add default dev veth_b |
| ip addr add "${dst_addr4}" dev veth_a 2>/dev/null |
| |
| # shellcheck disable=SC2086 # this needs split options |
| iperf -u -sDB "${dst_addr4}" ${dst_port} >/dev/null 2>&1 |
| sleep 2 |
| |
| # shellcheck disable=SC2086 # this needs split options |
| B iperf -u -c "${dst_addr4}" -b 100M -l1 -t1000 \ |
| ${dst_port} ${src_addr4} |
| |
| src_addr4= |
| src_port= |
| dst_port= |
| } |
| elif command -v netperf >/dev/null; then |
| flood_udp() { |
| [ -n "${dst_port}" ] && dst_port="-p ${dst_port}" |
| if [ -n "${src_addr4}" ]; then |
| B ip addr add "${src_addr4}/16" dev veth_b |
| else |
| B ip addr add dev veth_b 10.0.0.2 |
| src_addr4="10.0.0.2" |
| fi |
| if [ -n "${src_port}" ]; then |
| dst_port="${dst_port},${src_port}" |
| fi |
| B ip route add default dev veth_b |
| ip addr add "${dst_addr4}" dev veth_a 2>/dev/null |
| |
| # shellcheck disable=SC2086 # this needs split options |
| netserver -4 ${dst_port} -L "${dst_addr4}" \ |
| >/dev/null 2>&1 |
| sleep 2 |
| |
| # shellcheck disable=SC2086 # this needs split options |
| B netperf -4 -H "${dst_addr4}" ${dst_port} \ |
| -L "${src_addr4}" -l 1000 -t UDP_STREAM |
| |
| src_addr4= |
| src_port= |
| dst_port= |
| } |
| else |
| return 1 |
| fi |
| } |
| |
| # Find pktgen script and set up function to start pktgen injection |
| setup_perf() { |
| for pktgen_script_path in ${PKTGEN_SCRIPT_PATHS} __notfound; do |
| command -v "${pktgen_script_path}" >/dev/null && break |
| done |
| [ "${pktgen_script_path}" = "__notfound" ] && return 1 |
| |
| perf_ipv4() { |
| ${pktgen_script_path} -s80 \ |
| -i veth_a -d "${dst_addr4}" -p "${dst_port}" \ |
| -m "${dst_mac}" \ |
| -t $(($(nproc) / 5 + 1)) -b10000 -n0 2>/dev/null & |
| perf_pid=$! |
| } |
| perf_ipv6() { |
| IP6=6 ${pktgen_script_path} -s100 \ |
| -i veth_a -d "${dst_addr6}" -p "${dst_port}" \ |
| -m "${dst_mac}" \ |
| -t $(($(nproc) / 5 + 1)) -b10000 -n0 2>/dev/null & |
| perf_pid=$! |
| } |
| } |
| |
| # Clean up before each test |
| cleanup() { |
| nft reset counter inet filter test >/dev/null 2>&1 |
| nft flush ruleset >/dev/null 2>&1 |
| ip link del dummy0 2>/dev/null |
| ip route del default 2>/dev/null |
| ip -6 route del default 2>/dev/null |
| ip netns del B 2>/dev/null |
| ip link del veth_a 2>/dev/null |
| timeout= |
| killall iperf3 2>/dev/null |
| killall iperf 2>/dev/null |
| killall netperf 2>/dev/null |
| killall netserver 2>/dev/null |
| rm -f ${tmp} |
| sleep 2 |
| } |
| |
| # Entry point for setup functions |
| setup() { |
| if [ "$(id -u)" -ne 0 ]; then |
| echo " need to run as root" |
| exit ${KSELFTEST_SKIP} |
| fi |
| |
| cleanup |
| check_tools || return 1 |
| for arg do |
| if ! eval setup_"${arg}"; then |
| err " ${arg} not supported" |
| return 1 |
| fi |
| done |
| } |
| |
| # Format integer into IPv4 address, summing 10.0.0.5 (arbitrary) to it |
| format_addr4() { |
| a=$((${1} + 16777216 * 10 + 5)) |
| printf "%i.%i.%i.%i" \ |
| "$((a / 16777216))" "$((a % 16777216 / 65536))" \ |
| "$((a % 65536 / 256))" "$((a % 256))" |
| } |
| |
| # Format integer into IPv6 address, summing 2001:db8:: to it |
| format_addr6() { |
| printf "2001:db8::%04x:%04x" "$((${1} / 65536))" "$((${1} % 65536))" |
| } |
| |
| # Format integer into EUI-48 address, summing 00:01:00:00:00:00 to it |
| format_mac() { |
| printf "00:01:%02x:%02x:%02x:%02x" \ |
| "$((${1} / 16777216))" "$((${1} % 16777216 / 65536))" \ |
| "$((${1} % 65536 / 256))" "$((${1} % 256))" |
| } |
| |
| # Format integer into port, avoid 0 port |
| format_port() { |
| printf "%i" "$((${1} % 65534 + 1))" |
| } |
| |
| # Drop suffixed '6' from L4 protocol, if any |
| format_proto() { |
| printf "%s" "${proto}" | tr -d 6 |
| } |
| |
| # Format destination and source fields into nft concatenated type |
| format() { |
| __start= |
| __end= |
| __expr="{ " |
| |
| for f in ${dst}; do |
| [ "${__expr}" != "{ " ] && __expr="${__expr} . " |
| |
| __start="$(eval format_"${f}" "${start}")" |
| __end="$(eval format_"${f}" "${end}")" |
| |
| if [ "${f}" = "proto" ]; then |
| __expr="${__expr}${__start}" |
| else |
| __expr="${__expr}${__start}-${__end}" |
| fi |
| done |
| for f in ${src}; do |
| __expr="${__expr} . " |
| __start="$(eval format_"${f}" "${srcstart}")" |
| __end="$(eval format_"${f}" "${srcend}")" |
| |
| if [ "${f}" = "proto" ]; then |
| __expr="${__expr}${__start}" |
| else |
| __expr="${__expr}${__start}-${__end}" |
| fi |
| done |
| |
| if [ -n "${timeout}" ]; then |
| echo "${__expr} timeout ${timeout}s }" |
| else |
| echo "${__expr} }" |
| fi |
| } |
| |
| # Format destination and source fields into nft type, start element only |
| format_norange() { |
| __expr="{ " |
| |
| for f in ${dst}; do |
| [ "${__expr}" != "{ " ] && __expr="${__expr} . " |
| |
| __expr="${__expr}$(eval format_"${f}" "${start}")" |
| done |
| for f in ${src}; do |
| __expr="${__expr} . $(eval format_"${f}" "${start}")" |
| done |
| |
| echo "${__expr} }" |
| } |
| |
| # Format first destination field into nft type |
| format_noconcat() { |
| for f in ${dst}; do |
| __start="$(eval format_"${f}" "${start}")" |
| __end="$(eval format_"${f}" "${end}")" |
| |
| if [ "${f}" = "proto" ]; then |
| echo "{ ${__start} }" |
| else |
| echo "{ ${__start}-${__end} }" |
| fi |
| return |
| done |
| } |
| |
| # Add single entry to 'test' set in 'inet filter' table |
| add() { |
| if ! nft add element inet filter test "${1}"; then |
| err "Failed to add ${1} given ruleset:" |
| err "$(nft -a list ruleset)" |
| return 1 |
| fi |
| } |
| |
| # Format and output entries for sets in 'netdev perf' table |
| add_perf() { |
| if [ "${1}" = "test" ]; then |
| echo "add element netdev perf test $(format)" |
| elif [ "${1}" = "norange" ]; then |
| echo "add element netdev perf norange $(format_norange)" |
| elif [ "${1}" = "noconcat" ]; then |
| echo "add element netdev perf noconcat $(format_noconcat)" |
| fi |
| } |
| |
| # Add single entry to 'norange' set in 'netdev perf' table |
| add_perf_norange() { |
| if ! nft add element netdev perf norange "${1}"; then |
| err "Failed to add ${1} given ruleset:" |
| err "$(nft -a list ruleset)" |
| return 1 |
| fi |
| } |
| |
| # Add single entry to 'noconcat' set in 'netdev perf' table |
| add_perf_noconcat() { |
| if ! nft add element netdev perf noconcat "${1}"; then |
| err "Failed to add ${1} given ruleset:" |
| err "$(nft -a list ruleset)" |
| return 1 |
| fi |
| } |
| |
| # Delete single entry from set |
| del() { |
| if ! nft delete element inet filter test "${1}"; then |
| err "Failed to delete ${1} given ruleset:" |
| err "$(nft -a list ruleset)" |
| return 1 |
| fi |
| } |
| |
| # Return packet count from 'test' counter in 'inet filter' table |
| count_packets() { |
| found=0 |
| for token in $(nft list counter inet filter test); do |
| [ ${found} -eq 1 ] && echo "${token}" && return |
| [ "${token}" = "packets" ] && found=1 |
| done |
| } |
| |
| # Return packet count from 'test' counter in 'netdev perf' table |
| count_perf_packets() { |
| found=0 |
| for token in $(nft list counter netdev perf test); do |
| [ ${found} -eq 1 ] && echo "${token}" && return |
| [ "${token}" = "packets" ] && found=1 |
| done |
| } |
| |
| # Set MAC addresses, send traffic according to specifier |
| flood() { |
| ip link set veth_a address "$(format_mac "${1}")" |
| ip -n B link set veth_b address "$(format_mac "${2}")" |
| |
| for f in ${dst}; do |
| eval dst_"$f"=\$\(format_\$f "${1}"\) |
| done |
| for f in ${src}; do |
| eval src_"$f"=\$\(format_\$f "${2}"\) |
| done |
| eval flood_\$proto |
| } |
| |
| # Set MAC addresses, start pktgen injection |
| perf() { |
| dst_mac="$(format_mac "${1}")" |
| ip link set veth_a address "${dst_mac}" |
| |
| for f in ${dst}; do |
| eval dst_"$f"=\$\(format_\$f "${1}"\) |
| done |
| for f in ${src}; do |
| eval src_"$f"=\$\(format_\$f "${2}"\) |
| done |
| eval perf_\$perf_proto |
| } |
| |
| # Set MAC addresses, send single packet, check that it matches, reset counter |
| send_match() { |
| ip link set veth_a address "$(format_mac "${1}")" |
| ip -n B link set veth_b address "$(format_mac "${2}")" |
| |
| for f in ${dst}; do |
| eval dst_"$f"=\$\(format_\$f "${1}"\) |
| done |
| for f in ${src}; do |
| eval src_"$f"=\$\(format_\$f "${2}"\) |
| done |
| eval send_\$proto |
| if [ "$(count_packets)" != "1" ]; then |
| err "${proto} packet to:" |
| err " $(for f in ${dst}; do |
| eval format_\$f "${1}"; printf ' '; done)" |
| err "from:" |
| err " $(for f in ${src}; do |
| eval format_\$f "${2}"; printf ' '; done)" |
| err "should have matched ruleset:" |
| err "$(nft -a list ruleset)" |
| return 1 |
| fi |
| nft reset counter inet filter test >/dev/null |
| } |
| |
| # Set MAC addresses, send single packet, check that it doesn't match |
| send_nomatch() { |
| ip link set veth_a address "$(format_mac "${1}")" |
| ip -n B link set veth_b address "$(format_mac "${2}")" |
| |
| for f in ${dst}; do |
| eval dst_"$f"=\$\(format_\$f "${1}"\) |
| done |
| for f in ${src}; do |
| eval src_"$f"=\$\(format_\$f "${2}"\) |
| done |
| eval send_\$proto |
| if [ "$(count_packets)" != "0" ]; then |
| err "${proto} packet to:" |
| err " $(for f in ${dst}; do |
| eval format_\$f "${1}"; printf ' '; done)" |
| err "from:" |
| err " $(for f in ${src}; do |
| eval format_\$f "${2}"; printf ' '; done)" |
| err "should not have matched ruleset:" |
| err "$(nft -a list ruleset)" |
| return 1 |
| fi |
| } |
| |
| # Correctness test template: |
| # - add ranged element, check that packets match it |
| # - check that packets outside range don't match it |
| # - remove some elements, check that packets don't match anymore |
| test_correctness() { |
| setup veth send_"${proto}" set || return ${KSELFTEST_SKIP} |
| |
| range_size=1 |
| for i in $(seq "${start}" $((start + count))); do |
| end=$((start + range_size)) |
| |
| # Avoid negative or zero-sized port ranges |
| if [ $((end / 65534)) -gt $((start / 65534)) ]; then |
| start=${end} |
| end=$((end + 1)) |
| fi |
| srcstart=$((start + src_delta)) |
| srcend=$((end + src_delta)) |
| |
| add "$(format)" || return 1 |
| for j in $(seq ${start} $((range_size / 2 + 1)) ${end}); do |
| send_match "${j}" $((j + src_delta)) || return 1 |
| done |
| send_nomatch $((end + 1)) $((end + 1 + src_delta)) || return 1 |
| |
| # Delete elements now and then |
| if [ $((i % 3)) -eq 0 ]; then |
| del "$(format)" || return 1 |
| for j in $(seq ${start} \ |
| $((range_size / 2 + 1)) ${end}); do |
| send_nomatch "${j}" $((j + src_delta)) \ |
| || return 1 |
| done |
| fi |
| |
| range_size=$((range_size + 1)) |
| start=$((end + range_size)) |
| done |
| } |
| |
| # Concurrency test template: |
| # - add all the elements |
| # - start a thread for each physical thread that: |
| # - adds all the elements |
| # - flushes the set |
| # - adds all the elements |
| # - flushes the entire ruleset |
| # - adds the set back |
| # - adds all the elements |
| # - delete all the elements |
| test_concurrency() { |
| proto=${flood_proto} |
| tools=${flood_tools} |
| chain_spec=${flood_spec} |
| setup veth flood_"${proto}" set || return ${KSELFTEST_SKIP} |
| |
| range_size=1 |
| cstart=${start} |
| flood_pids= |
| for i in $(seq ${start} $((start + count))); do |
| end=$((start + range_size)) |
| srcstart=$((start + src_delta)) |
| srcend=$((end + src_delta)) |
| |
| add "$(format)" || return 1 |
| |
| flood "${i}" $((i + src_delta)) & flood_pids="${flood_pids} $!" |
| |
| range_size=$((range_size + 1)) |
| start=$((end + range_size)) |
| done |
| |
| sleep 10 |
| |
| pids= |
| for c in $(seq 1 "$(nproc)"); do ( |
| for r in $(seq 1 "${race_repeat}"); do |
| range_size=1 |
| |
| # $start needs to be local to this subshell |
| # shellcheck disable=SC2030 |
| start=${cstart} |
| for i in $(seq ${start} $((start + count))); do |
| end=$((start + range_size)) |
| srcstart=$((start + src_delta)) |
| srcend=$((end + src_delta)) |
| |
| add "$(format)" 2>/dev/null |
| |
| range_size=$((range_size + 1)) |
| start=$((end + range_size)) |
| done |
| |
| nft flush inet filter test 2>/dev/null |
| |
| range_size=1 |
| start=${cstart} |
| for i in $(seq ${start} $((start + count))); do |
| end=$((start + range_size)) |
| srcstart=$((start + src_delta)) |
| srcend=$((end + src_delta)) |
| |
| add "$(format)" 2>/dev/null |
| |
| range_size=$((range_size + 1)) |
| start=$((end + range_size)) |
| done |
| |
| nft flush ruleset |
| setup set 2>/dev/null |
| |
| range_size=1 |
| start=${cstart} |
| for i in $(seq ${start} $((start + count))); do |
| end=$((start + range_size)) |
| srcstart=$((start + src_delta)) |
| srcend=$((end + src_delta)) |
| |
| add "$(format)" 2>/dev/null |
| |
| range_size=$((range_size + 1)) |
| start=$((end + range_size)) |
| done |
| |
| range_size=1 |
| start=${cstart} |
| for i in $(seq ${start} $((start + count))); do |
| end=$((start + range_size)) |
| srcstart=$((start + src_delta)) |
| srcend=$((end + src_delta)) |
| |
| del "$(format)" 2>/dev/null |
| |
| range_size=$((range_size + 1)) |
| start=$((end + range_size)) |
| done |
| done |
| ) & pids="${pids} $!" |
| done |
| |
| # shellcheck disable=SC2046,SC2086 # word splitting wanted here |
| wait $(for pid in ${pids}; do echo ${pid}; done) |
| # shellcheck disable=SC2046,SC2086 |
| kill $(for pid in ${flood_pids}; do echo ${pid}; done) 2>/dev/null |
| # shellcheck disable=SC2046,SC2086 |
| wait $(for pid in ${flood_pids}; do echo ${pid}; done) 2>/dev/null |
| |
| return 0 |
| } |
| |
| # Timeout test template: |
| # - add all the elements with 3s timeout while checking that packets match |
| # - wait 3s after the last insertion, check that packets don't match any entry |
| test_timeout() { |
| setup veth send_"${proto}" set || return ${KSELFTEST_SKIP} |
| |
| timeout=3 |
| range_size=1 |
| for i in $(seq "${start}" $((start + count))); do |
| end=$((start + range_size)) |
| srcstart=$((start + src_delta)) |
| srcend=$((end + src_delta)) |
| |
| add "$(format)" || return 1 |
| |
| for j in $(seq ${start} $((range_size / 2 + 1)) ${end}); do |
| send_match "${j}" $((j + src_delta)) || return 1 |
| done |
| |
| range_size=$((range_size + 1)) |
| start=$((end + range_size)) |
| done |
| sleep 3 |
| for i in $(seq ${start} $((start + count))); do |
| end=$((start + range_size)) |
| srcstart=$((start + src_delta)) |
| srcend=$((end + src_delta)) |
| |
| for j in $(seq ${start} $((range_size / 2 + 1)) ${end}); do |
| send_nomatch "${j}" $((j + src_delta)) || return 1 |
| done |
| |
| range_size=$((range_size + 1)) |
| start=$((end + range_size)) |
| done |
| } |
| |
| # Performance test template: |
| # - add concatenated ranged entries |
| # - add non-ranged concatenated entries (for hash set matching rate baseline) |
| # - add ranged entries with first field only (for rbhash baseline) |
| # - start pktgen injection directly on device rx path of this namespace |
| # - measure drop only rate, hash and rbtree baselines, then matching rate |
| test_performance() { |
| chain_spec=${perf_spec} |
| dst="${perf_dst}" |
| src="${perf_src}" |
| setup veth perf set || return ${KSELFTEST_SKIP} |
| |
| first=${start} |
| range_size=1 |
| for set in test norange noconcat; do |
| start=${first} |
| for i in $(seq ${start} $((start + perf_entries))); do |
| end=$((start + range_size)) |
| srcstart=$((start + src_delta)) |
| srcend=$((end + src_delta)) |
| |
| if [ $((end / 65534)) -gt $((start / 65534)) ]; then |
| start=${end} |
| end=$((end + 1)) |
| elif [ ${start} -eq ${end} ]; then |
| end=$((start + 1)) |
| fi |
| |
| add_perf ${set} |
| |
| start=$((end + range_size)) |
| done > "${tmp}" |
| nft -f "${tmp}" |
| done |
| |
| perf $((end - 1)) ${srcstart} |
| |
| sleep 2 |
| |
| nft add rule netdev perf test counter name \"test\" drop |
| nft reset counter netdev perf test >/dev/null 2>&1 |
| sleep "${perf_duration}" |
| pps="$(printf %10s $(($(count_perf_packets) / perf_duration)))" |
| info " baseline (drop from netdev hook): ${pps}pps" |
| handle="$(nft -a list chain netdev perf test | grep counter)" |
| handle="${handle##* }" |
| nft delete rule netdev perf test handle "${handle}" |
| |
| nft add rule "netdev perf test ${chain_spec} @norange \ |
| counter name \"test\" drop" |
| nft reset counter netdev perf test >/dev/null 2>&1 |
| sleep "${perf_duration}" |
| pps="$(printf %10s $(($(count_perf_packets) / perf_duration)))" |
| info " baseline hash (non-ranged entries): ${pps}pps" |
| handle="$(nft -a list chain netdev perf test | grep counter)" |
| handle="${handle##* }" |
| nft delete rule netdev perf test handle "${handle}" |
| |
| nft add rule "netdev perf test ${chain_spec%%. *} @noconcat \ |
| counter name \"test\" drop" |
| nft reset counter netdev perf test >/dev/null 2>&1 |
| sleep "${perf_duration}" |
| pps="$(printf %10s $(($(count_perf_packets) / perf_duration)))" |
| info " baseline rbtree (match on first field only): ${pps}pps" |
| handle="$(nft -a list chain netdev perf test | grep counter)" |
| handle="${handle##* }" |
| nft delete rule netdev perf test handle "${handle}" |
| |
| nft add rule "netdev perf test ${chain_spec} @test \ |
| counter name \"test\" drop" |
| nft reset counter netdev perf test >/dev/null 2>&1 |
| sleep "${perf_duration}" |
| pps="$(printf %10s $(($(count_perf_packets) / perf_duration)))" |
| p5="$(printf %5s "${perf_entries}")" |
| info " set with ${p5} full, ranged entries: ${pps}pps" |
| kill "${perf_pid}" |
| } |
| |
| test_bug_flush_remove_add() { |
| set_cmd='{ set s { type ipv4_addr . inet_service; flags interval; }; }' |
| elem1='{ 10.0.0.1 . 22-25, 10.0.0.1 . 10-20 }' |
| elem2='{ 10.0.0.1 . 10-20, 10.0.0.1 . 22-25 }' |
| for i in `seq 1 100`; do |
| nft add table t ${set_cmd} || return ${KSELFTEST_SKIP} |
| nft add element t s ${elem1} 2>/dev/null || return 1 |
| nft flush set t s 2>/dev/null || return 1 |
| nft add element t s ${elem2} 2>/dev/null || return 1 |
| done |
| nft flush ruleset |
| } |
| |
| test_reported_issues() { |
| eval test_bug_"${subtest}" |
| } |
| |
| # Run everything in a separate network namespace |
| [ "${1}" != "run" ] && { unshare -n "${0}" run; exit $?; } |
| tmp="$(mktemp)" |
| trap cleanup EXIT |
| |
| # Entry point for test runs |
| passed=0 |
| for name in ${TESTS}; do |
| printf "TEST: %s\n" "$(echo ${name} | tr '_' ' ')" |
| if [ "${name}" = "reported_issues" ]; then |
| SUBTESTS="${BUGS}" |
| else |
| SUBTESTS="${TYPES}" |
| fi |
| |
| for subtest in ${SUBTESTS}; do |
| eval desc=\$TYPE_"${subtest}" |
| IFS=' |
| ' |
| for __line in ${desc}; do |
| # shellcheck disable=SC2086 |
| eval ${__line%% *}=\"${__line##* }\"; |
| done |
| IFS=' |
| ' |
| |
| if [ "${name}" = "concurrency" ] && \ |
| [ "${race_repeat}" = "0" ]; then |
| continue |
| fi |
| if [ "${name}" = "performance" ] && \ |
| [ "${perf_duration}" = "0" ]; then |
| continue |
| fi |
| |
| printf " %-60s " "${display}" |
| eval test_"${name}" |
| ret=$? |
| |
| if [ $ret -eq 0 ]; then |
| printf "[ OK ]\n" |
| info_flush |
| passed=$((passed + 1)) |
| elif [ $ret -eq 1 ]; then |
| printf "[FAIL]\n" |
| err_flush |
| exit 1 |
| elif [ $ret -eq ${KSELFTEST_SKIP} ]; then |
| printf "[SKIP]\n" |
| err_flush |
| fi |
| done |
| done |
| |
| [ ${passed} -eq 0 ] && exit ${KSELFTEST_SKIP} |