2 # SPDX-License-Identifier: GPL-2.0
4 # nft_concat_range.sh - Tests for sets with concatenation of ranged fields
6 # Copyright (c) 2019 Red Hat GmbH
8 # Author: Stefano Brivio <sbrivio@redhat.com>
10 # shellcheck disable=SC2154,SC2034,SC2016,SC2030,SC2031
11 # ^ Configuration and templates sourced with eval, counters reused in subshells
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
21 TESTS="reported_issues correctness concurrency timeout"
22 [ "${quicktest}" != "1" ] && TESTS="${TESTS} performance"
24 # Set types, defined by TYPE_ variables below
25 TYPES="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"
29 # Reported bugs, also described by TYPE_ variables below
30 BUGS="flush_remove_add reload"
32 # List of possible paths to pktgen script from kernel tree for performance tests
34 ../../../../samples/pktgen/pktgen_bench_xmit_mode_netif_receive.sh
35 pktgen/pktgen_bench_xmit_mode_netif_receive.sh"
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
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
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
62 type_spec ipv4_addr . inet_service
63 chain_spec ip daddr . udp dport
73 flood_tools iperf3 iperf netperf
75 flood_spec ip daddr . udp dport
78 perf_spec ip daddr . udp dport
87 type_spec inet_service . ipv4_addr
88 chain_spec udp dport . ip daddr
98 flood_tools iperf3 iperf netperf
100 flood_spec udp dport . ip daddr
103 perf_spec udp dport . ip daddr
112 type_spec ipv6_addr . inet_service
113 chain_spec ip6 daddr . udp dport
123 flood_tools iperf3 iperf netperf
125 flood_spec ip6 daddr . udp dport
128 perf_spec ip6 daddr . udp dport
137 type_spec inet_service . inet_proto
138 chain_spec udp dport . meta l4proto
150 perf_spec udp dport . meta l4proto
158 display net6,port,mac
159 type_spec ipv6_addr . inet_service . ether_addr
160 chain_spec ip6 daddr . udp dport . ether saddr
172 perf_spec ip6 daddr . udp dport . ether daddr
173 perf_dst addr6 port mac
179 TYPE_net6_port_mac_proto="
180 display net6,port,mac,proto
181 type_spec ipv6_addr . inet_service . ether_addr . inet_proto
182 chain_spec ip6 daddr . udp dport . ether saddr . meta l4proto
194 perf_spec ip6 daddr . udp dport . ether daddr . meta l4proto
195 perf_dst addr6 port mac proto
203 type_spec ipv4_addr . inet_service . ipv4_addr
204 chain_spec ip daddr . udp dport . ip saddr
214 flood_tools iperf3 iperf netperf
216 flood_spec ip daddr . udp dport . ip saddr
221 TYPE_net6_port_net6_port="
222 display net6,port,net6,port
223 type_spec ipv6_addr . inet_service . ipv6_addr . inet_service
224 chain_spec ip6 daddr . udp dport . ip6 saddr . udp sport
234 flood_tools iperf3 iperf netperf
236 flood_spec ip6 daddr . tcp dport . ip6 saddr . tcp sport
241 TYPE_net_port_mac_proto_net="
242 display net,port,mac,proto,net
243 type_spec ipv4_addr . inet_service . ether_addr . inet_proto . ipv4_addr
244 chain_spec ip daddr . udp dport . ether saddr . meta l4proto . ip saddr
260 type_spec ipv4_addr . ether_addr
261 chain_spec ip daddr . ether saddr
273 perf_spec ip daddr . ether daddr
282 type_spec ether_addr . ipv4_addr
283 chain_spec ether saddr . ip saddr
298 display net,mac - ICMP
299 type_spec ipv4_addr . ether_addr
300 chain_spec ip daddr . ether saddr
315 display net6,mac - ICMPv6
316 type_spec ipv6_addr . ether_addr
317 chain_spec ip6 daddr . ether saddr
331 TYPE_net_port_proto_net="
332 display net,port,proto,net
333 type_spec ipv4_addr . inet_service . inet_proto . ipv4_addr
334 chain_spec ip daddr . udp dport . meta l4proto . ip saddr
344 flood_tools iperf3 iperf netperf
346 flood_spec ip daddr . tcp dport . meta l4proto . ip saddr
351 # Definition of tests for bugs reported in the past:
352 # display display text for test report
353 TYPE_flush_remove_add="
354 display Add two elements, flush, re-add
358 display net,mac with reload
359 type_spec ipv4_addr . ether_addr
360 chain_spec ip daddr . ether saddr
374 # Set template for all tests, types and rules are filled in depending on test
385 flags interval,timeout
389 type filter hook prerouting priority 0; policy accept;
390 ${chain_spec} @test counter name \"test\"
413 type ${type_spec%% *}
418 type filter hook ingress device veth_a priority 0;
426 # Append string to error buffer
428 err_buf="${err_buf}${1}
432 # Append string to information buffer
434 info_buf="${info_buf}${1}
438 # Flush error buffer to stdout
440 printf "%s" "${err_buf}"
444 # Flush information buffer to stdout
446 printf "%s" "${info_buf}"
450 # Setup veth pair: this namespace receives traffic, B generates it
453 ip link add veth_a type veth peer name veth_b || return 1
455 ip link set veth_a up
456 ip link set veth_b netns B
458 ip -n B link set veth_b up
460 ip addr add dev veth_a 10.0.0.1
461 ip route add default dev veth_a
463 ip -6 addr add fe80::1/64 dev veth_a nodad
464 ip -6 addr add 2001:db8::1/64 dev veth_a nodad
465 ip -6 route add default dev veth_a
467 ip -n B route add default dev veth_b
469 ip -6 -n B addr add fe80::2/64 dev veth_b nodad
470 ip -6 -n B addr add 2001:db8::2/64 dev veth_b nodad
471 ip -6 -n B route add default dev veth_b
474 ip netns exec B "$@" >/dev/null 2>&1
480 # Fill in set template and initialise set
482 eval "echo \"${set_template}\"" | nft -f -
485 # Check that at least one of the needed tools is available
487 [ -z "${tools}" ] && return 0
490 for tool in ${tools}; do
491 if [ "${tool}" = "nc" ] && [ "${proto}" = "udp6" ] && \
492 ! nc -u -w0 1.1.1.1 1 2>/dev/null; then
493 # Some GNU netcat builds might not support IPv6
494 __tools="${__tools} netcat-openbsd"
497 __tools="${__tools} ${tool}"
499 command -v "${tool}" >/dev/null && return 0
501 err "need one of:${__tools}, skipping" && return 1
504 # Set up function to send ICMP packets
507 B ping -c1 -W1 "${dst_addr4}" >/dev/null 2>&1
511 # Set up function to send ICMPv6 packets
513 if command -v ping6 >/dev/null; then
515 ip -6 addr add "${dst_addr6}" dev veth_a nodad \
517 B ping6 -q -c1 -W1 "${dst_addr6}"
521 ip -6 addr add "${dst_addr6}" dev veth_a nodad \
523 B ping -q -6 -c1 -W1 "${dst_addr6}"
528 # Set up function to send single UDP packets on IPv4
530 if command -v sendip >/dev/null; then
532 [ -n "${src_port}" ] && src_port="-us ${src_port}"
533 [ -n "${dst_port}" ] && dst_port="-ud ${dst_port}"
534 [ -n "${src_addr4}" ] && src_addr4="-is ${src_addr4}"
536 # shellcheck disable=SC2086 # sendip needs split options
537 B sendip -p ipv4 -p udp ${src_addr4} ${src_port} \
538 ${dst_port} "${dst_addr4}"
544 elif command -v nc >/dev/null; then
545 if nc -u -w0 1.1.1.1 1 2>/dev/null; then
554 if [ -n "${src_addr4}" ]; then
555 B ip addr add "${src_addr4}" dev veth_b
556 __src_addr4="-s ${src_addr4}"
558 ip addr add "${dst_addr4}" dev veth_a 2>/dev/null
559 [ -n "${src_port}" ] && src_port="-p ${src_port}"
561 echo "" | B nc -u "${nc_opt}" "${__src_addr4}" \
562 "${src_port}" "${dst_addr4}" "${dst_port}"
567 elif [ -z "$(bash -c 'type -p')" ]; then
569 ip addr add "${dst_addr4}" dev veth_a 2>/dev/null
570 if [ -n "${src_addr4}" ]; then
571 B ip addr add "${src_addr4}/16" dev veth_b
572 B ip route add default dev veth_b
575 B bash -c "echo > /dev/udp/${dst_addr4}/${dst_port}"
577 if [ -n "${src_addr4}" ]; then
578 B ip addr del "${src_addr4}/16" dev veth_b
587 # Set up function to send single UDP packets on IPv6
589 if command -v sendip >/dev/null; then
591 [ -n "${src_port}" ] && src_port="-us ${src_port}"
592 [ -n "${dst_port}" ] && dst_port="-ud ${dst_port}"
593 if [ -n "${src_addr6}" ]; then
594 src_addr6="-6s ${src_addr6}"
596 src_addr6="-6s 2001:db8::2"
598 ip -6 addr add "${dst_addr6}" dev veth_a nodad \
601 # shellcheck disable=SC2086 # this needs split options
602 B sendip -p ipv6 -p udp ${src_addr6} ${src_port} \
603 ${dst_port} "${dst_addr6}"
609 elif command -v nc >/dev/null && nc -u -w0 1.1.1.1 1 2>/dev/null; then
610 # GNU netcat might not work with IPv6, try next tool
612 ip -6 addr add "${dst_addr6}" dev veth_a nodad \
614 if [ -n "${src_addr6}" ]; then
615 B ip addr add "${src_addr6}" dev veth_b nodad
617 src_addr6="2001:db8::2"
619 [ -n "${src_port}" ] && src_port="-p ${src_port}"
621 # shellcheck disable=SC2086 # this needs split options
622 echo "" | B nc -u w0 "-s${src_addr6}" ${src_port} \
623 ${dst_addr6} ${dst_port}
628 elif [ -z "$(bash -c 'type -p')" ]; then
630 ip -6 addr add "${dst_addr6}" dev veth_a nodad \
632 B ip addr add "${src_addr6}" dev veth_b nodad
633 B bash -c "echo > /dev/udp/${dst_addr6}/${dst_port}"
634 ip -6 addr del "${dst_addr6}" dev veth_a 2>/dev/null
641 # Set up function to send TCP traffic on IPv4
643 if command -v iperf3 >/dev/null; then
645 [ -n "${dst_port}" ] && dst_port="-p ${dst_port}"
646 if [ -n "${src_addr4}" ]; then
647 B ip addr add "${src_addr4}/16" dev veth_b
648 src_addr4="-B ${src_addr4}"
650 B ip addr add dev veth_b 10.0.0.2
651 src_addr4="-B 10.0.0.2"
653 if [ -n "${src_port}" ]; then
654 src_port="--cport ${src_port}"
656 B ip route add default dev veth_b 2>/dev/null
657 ip addr add "${dst_addr4}" dev veth_a 2>/dev/null
659 # shellcheck disable=SC2086 # this needs split options
660 iperf3 -s -DB "${dst_addr4}" ${dst_port} >/dev/null 2>&1
663 # shellcheck disable=SC2086 # this needs split options
664 B iperf3 -c "${dst_addr4}" ${dst_port} ${src_port} \
665 ${src_addr4} -l16 -t 1000
671 elif command -v iperf >/dev/null; then
673 [ -n "${dst_port}" ] && dst_port="-p ${dst_port}"
674 if [ -n "${src_addr4}" ]; then
675 B ip addr add "${src_addr4}/16" dev veth_b
676 src_addr4="-B ${src_addr4}"
678 B ip addr add dev veth_b 10.0.0.2 2>/dev/null
679 src_addr4="-B 10.0.0.2"
681 if [ -n "${src_port}" ]; then
682 src_addr4="${src_addr4}:${src_port}"
684 B ip route add default dev veth_b
685 ip addr add "${dst_addr4}" dev veth_a 2>/dev/null
687 # shellcheck disable=SC2086 # this needs split options
688 iperf -s -DB "${dst_addr4}" ${dst_port} >/dev/null 2>&1
691 # shellcheck disable=SC2086 # this needs split options
692 B iperf -c "${dst_addr4}" ${dst_port} ${src_addr4} \
699 elif command -v netperf >/dev/null; then
701 [ -n "${dst_port}" ] && dst_port="-p ${dst_port}"
702 if [ -n "${src_addr4}" ]; then
703 B ip addr add "${src_addr4}/16" dev veth_b
705 B ip addr add dev veth_b 10.0.0.2
708 if [ -n "${src_port}" ]; then
709 dst_port="${dst_port},${src_port}"
711 B ip route add default dev veth_b
712 ip addr add "${dst_addr4}" dev veth_a 2>/dev/null
714 # shellcheck disable=SC2086 # this needs split options
715 netserver -4 ${dst_port} -L "${dst_addr4}" \
719 # shellcheck disable=SC2086 # this needs split options
720 B netperf -4 -H "${dst_addr4}" ${dst_port} \
721 -L "${src_addr4}" -l 1000 -t TCP_STREAM
732 # Set up function to send TCP traffic on IPv6
734 if command -v iperf3 >/dev/null; then
736 [ -n "${dst_port}" ] && dst_port="-p ${dst_port}"
737 if [ -n "${src_addr6}" ]; then
738 B ip addr add "${src_addr6}" dev veth_b nodad
739 src_addr6="-B ${src_addr6}"
741 src_addr6="-B 2001:db8::2"
743 if [ -n "${src_port}" ]; then
744 src_port="--cport ${src_port}"
746 B ip route add default dev veth_b
747 ip -6 addr add "${dst_addr6}" dev veth_a nodad \
750 # shellcheck disable=SC2086 # this needs split options
751 iperf3 -s -DB "${dst_addr6}" ${dst_port} >/dev/null 2>&1
754 # shellcheck disable=SC2086 # this needs split options
755 B iperf3 -c "${dst_addr6}" ${dst_port} \
756 ${src_port} ${src_addr6} -l16 -t 1000
762 elif command -v iperf >/dev/null; then
764 [ -n "${dst_port}" ] && dst_port="-p ${dst_port}"
765 if [ -n "${src_addr6}" ]; then
766 B ip addr add "${src_addr6}" dev veth_b nodad
767 src_addr6="-B ${src_addr6}"
769 src_addr6="-B 2001:db8::2"
771 if [ -n "${src_port}" ]; then
772 src_addr6="${src_addr6}:${src_port}"
774 B ip route add default dev veth_b
775 ip -6 addr add "${dst_addr6}" dev veth_a nodad \
778 # shellcheck disable=SC2086 # this needs split options
779 iperf -s -VDB "${dst_addr6}" ${dst_port} >/dev/null 2>&1
782 # shellcheck disable=SC2086 # this needs split options
783 B iperf -c "${dst_addr6}" -V ${dst_port} \
784 ${src_addr6} -l1 -t 1000
790 elif command -v netperf >/dev/null; then
792 [ -n "${dst_port}" ] && dst_port="-p ${dst_port}"
793 if [ -n "${src_addr6}" ]; then
794 B ip addr add "${src_addr6}" dev veth_b nodad
796 src_addr6="2001:db8::2"
798 if [ -n "${src_port}" ]; then
799 dst_port="${dst_port},${src_port}"
801 B ip route add default dev veth_b
802 ip -6 addr add "${dst_addr6}" dev veth_a nodad \
805 # shellcheck disable=SC2086 # this needs split options
806 netserver -6 ${dst_port} -L "${dst_addr6}" \
810 # shellcheck disable=SC2086 # this needs split options
811 B netperf -6 -H "${dst_addr6}" ${dst_port} \
812 -L "${src_addr6}" -l 1000 -t TCP_STREAM
823 # Set up function to send UDP traffic on IPv4
825 if command -v iperf3 >/dev/null; then
827 [ -n "${dst_port}" ] && dst_port="-p ${dst_port}"
828 if [ -n "${src_addr4}" ]; then
829 B ip addr add "${src_addr4}/16" dev veth_b
830 src_addr4="-B ${src_addr4}"
832 B ip addr add dev veth_b 10.0.0.2 2>/dev/null
833 src_addr4="-B 10.0.0.2"
835 if [ -n "${src_port}" ]; then
836 src_port="--cport ${src_port}"
838 B ip route add default dev veth_b
839 ip addr add "${dst_addr4}" dev veth_a 2>/dev/null
841 # shellcheck disable=SC2086 # this needs split options
842 iperf3 -s -DB "${dst_addr4}" ${dst_port}
845 # shellcheck disable=SC2086 # this needs split options
846 B iperf3 -u -c "${dst_addr4}" -Z -b 100M -l16 -t1000 \
847 ${dst_port} ${src_port} ${src_addr4}
853 elif command -v iperf >/dev/null; then
855 [ -n "${dst_port}" ] && dst_port="-p ${dst_port}"
856 if [ -n "${src_addr4}" ]; then
857 B ip addr add "${src_addr4}/16" dev veth_b
858 src_addr4="-B ${src_addr4}"
860 B ip addr add dev veth_b 10.0.0.2
861 src_addr4="-B 10.0.0.2"
863 if [ -n "${src_port}" ]; then
864 src_addr4="${src_addr4}:${src_port}"
866 B ip route add default dev veth_b
867 ip addr add "${dst_addr4}" dev veth_a 2>/dev/null
869 # shellcheck disable=SC2086 # this needs split options
870 iperf -u -sDB "${dst_addr4}" ${dst_port} >/dev/null 2>&1
873 # shellcheck disable=SC2086 # this needs split options
874 B iperf -u -c "${dst_addr4}" -b 100M -l1 -t1000 \
875 ${dst_port} ${src_addr4}
881 elif command -v netperf >/dev/null; then
883 [ -n "${dst_port}" ] && dst_port="-p ${dst_port}"
884 if [ -n "${src_addr4}" ]; then
885 B ip addr add "${src_addr4}/16" dev veth_b
887 B ip addr add dev veth_b 10.0.0.2
890 if [ -n "${src_port}" ]; then
891 dst_port="${dst_port},${src_port}"
893 B ip route add default dev veth_b
894 ip addr add "${dst_addr4}" dev veth_a 2>/dev/null
896 # shellcheck disable=SC2086 # this needs split options
897 netserver -4 ${dst_port} -L "${dst_addr4}" \
901 # shellcheck disable=SC2086 # this needs split options
902 B netperf -4 -H "${dst_addr4}" ${dst_port} \
903 -L "${src_addr4}" -l 1000 -t UDP_STREAM
914 # Find pktgen script and set up function to start pktgen injection
916 for pktgen_script_path in ${PKTGEN_SCRIPT_PATHS} __notfound; do
917 command -v "${pktgen_script_path}" >/dev/null && break
919 [ "${pktgen_script_path}" = "__notfound" ] && return 1
922 ${pktgen_script_path} -s80 \
923 -i veth_a -d "${dst_addr4}" -p "${dst_port}" \
925 -t $(($(nproc) / 5 + 1)) -b10000 -n0 2>/dev/null &
929 IP6=6 ${pktgen_script_path} -s100 \
930 -i veth_a -d "${dst_addr6}" -p "${dst_port}" \
932 -t $(($(nproc) / 5 + 1)) -b10000 -n0 2>/dev/null &
937 # Clean up before each test
939 nft reset counter inet filter test >/dev/null 2>&1
940 nft flush ruleset >/dev/null 2>&1
941 ip link del dummy0 2>/dev/null
942 ip route del default 2>/dev/null
943 ip -6 route del default 2>/dev/null
944 ip netns del B 2>/dev/null
945 ip link del veth_a 2>/dev/null
947 killall iperf3 2>/dev/null
948 killall iperf 2>/dev/null
949 killall netperf 2>/dev/null
950 killall netserver 2>/dev/null
955 # Entry point for setup functions
957 if [ "$(id -u)" -ne 0 ]; then
958 echo " need to run as root"
959 exit ${KSELFTEST_SKIP}
963 check_tools || return 1
965 if ! eval setup_"${arg}"; then
966 err " ${arg} not supported"
972 # Format integer into IPv4 address, summing 10.0.0.5 (arbitrary) to it
974 a=$((${1} + 16777216 * 10 + 5))
975 printf "%i.%i.%i.%i" \
976 "$((a / 16777216))" "$((a % 16777216 / 65536))" \
977 "$((a % 65536 / 256))" "$((a % 256))"
980 # Format integer into IPv6 address, summing 2001:db8:: to it
982 printf "2001:db8::%04x:%04x" "$((${1} / 65536))" "$((${1} % 65536))"
985 # Format integer into EUI-48 address, summing 00:01:00:00:00:00 to it
987 printf "00:01:%02x:%02x:%02x:%02x" \
988 "$((${1} / 16777216))" "$((${1} % 16777216 / 65536))" \
989 "$((${1} % 65536 / 256))" "$((${1} % 256))"
992 # Format integer into port, avoid 0 port
994 printf "%i" "$((${1} % 65534 + 1))"
997 # Drop suffixed '6' from L4 protocol, if any
999 printf "%s" "${proto}" | tr -d 6
1002 # Format destination and source fields into nft concatenated type
1009 [ "${__expr}" != "{ " ] && __expr="${__expr} . "
1011 __start="$(eval format_"${f}" "${start}")"
1012 __end="$(eval format_"${f}" "${end}")"
1014 if [ "${f}" = "proto" ]; then
1015 __expr="${__expr}${__start}"
1017 __expr="${__expr}${__start}-${__end}"
1021 [ "${__expr}" != "{ " ] && __expr="${__expr} . "
1023 __start="$(eval format_"${f}" "${srcstart}")"
1024 __end="$(eval format_"${f}" "${srcend}")"
1026 if [ "${f}" = "proto" ]; then
1027 __expr="${__expr}${__start}"
1029 __expr="${__expr}${__start}-${__end}"
1033 if [ -n "${timeout}" ]; then
1034 echo "${__expr} timeout ${timeout}s }"
1040 # Format destination and source fields into nft type, start element only
1045 [ "${__expr}" != "{ " ] && __expr="${__expr} . "
1047 __expr="${__expr}$(eval format_"${f}" "${start}")"
1050 __expr="${__expr} . $(eval format_"${f}" "${start}")"
1056 # Format first destination field into nft type
1059 __start="$(eval format_"${f}" "${start}")"
1060 __end="$(eval format_"${f}" "${end}")"
1062 if [ "${f}" = "proto" ]; then
1063 echo "{ ${__start} }"
1065 echo "{ ${__start}-${__end} }"
1071 # Add single entry to 'test' set in 'inet filter' table
1073 if ! nft add element inet filter test "${1}"; then
1074 err "Failed to add ${1} given ruleset:"
1075 err "$(nft -a list ruleset)"
1080 # Format and output entries for sets in 'netdev perf' table
1082 if [ "${1}" = "test" ]; then
1083 echo "add element netdev perf test $(format)"
1084 elif [ "${1}" = "norange" ]; then
1085 echo "add element netdev perf norange $(format_norange)"
1086 elif [ "${1}" = "noconcat" ]; then
1087 echo "add element netdev perf noconcat $(format_noconcat)"
1091 # Add single entry to 'norange' set in 'netdev perf' table
1092 add_perf_norange() {
1093 if ! nft add element netdev perf norange "${1}"; then
1094 err "Failed to add ${1} given ruleset:"
1095 err "$(nft -a list ruleset)"
1100 # Add single entry to 'noconcat' set in 'netdev perf' table
1101 add_perf_noconcat() {
1102 if ! nft add element netdev perf noconcat "${1}"; then
1103 err "Failed to add ${1} given ruleset:"
1104 err "$(nft -a list ruleset)"
1109 # Delete single entry from set
1111 if ! nft delete element inet filter test "${1}"; then
1112 err "Failed to delete ${1} given ruleset:"
1113 err "$(nft -a list ruleset)"
1118 # Return packet count from 'test' counter in 'inet filter' table
1121 for token in $(nft list counter inet filter test); do
1122 [ ${found} -eq 1 ] && echo "${token}" && return
1123 [ "${token}" = "packets" ] && found=1
1127 # Return packet count from 'test' counter in 'netdev perf' table
1128 count_perf_packets() {
1130 for token in $(nft list counter netdev perf test); do
1131 [ ${found} -eq 1 ] && echo "${token}" && return
1132 [ "${token}" = "packets" ] && found=1
1136 # Set MAC addresses, send traffic according to specifier
1138 ip link set veth_a address "$(format_mac "${1}")"
1139 ip -n B link set veth_b address "$(format_mac "${2}")"
1142 eval dst_"$f"=\$\(format_\$f "${1}"\)
1145 eval src_"$f"=\$\(format_\$f "${2}"\)
1150 # Set MAC addresses, start pktgen injection
1152 dst_mac="$(format_mac "${1}")"
1153 ip link set veth_a address "${dst_mac}"
1156 eval dst_"$f"=\$\(format_\$f "${1}"\)
1159 eval src_"$f"=\$\(format_\$f "${2}"\)
1161 eval perf_\$perf_proto
1164 # Set MAC addresses, send single packet, check that it matches, reset counter
1166 ip link set veth_a address "$(format_mac "${1}")"
1167 ip -n B link set veth_b address "$(format_mac "${2}")"
1170 eval dst_"$f"=\$\(format_\$f "${1}"\)
1173 eval src_"$f"=\$\(format_\$f "${2}"\)
1176 if [ "$(count_packets)" != "1" ]; then
1177 err "${proto} packet to:"
1178 err " $(for f in ${dst}; do
1179 eval format_\$f "${1}"; printf ' '; done)"
1181 err " $(for f in ${src}; do
1182 eval format_\$f "${2}"; printf ' '; done)"
1183 err "should have matched ruleset:"
1184 err "$(nft -a list ruleset)"
1187 nft reset counter inet filter test >/dev/null
1190 # Set MAC addresses, send single packet, check that it doesn't match
1192 ip link set veth_a address "$(format_mac "${1}")"
1193 ip -n B link set veth_b address "$(format_mac "${2}")"
1196 eval dst_"$f"=\$\(format_\$f "${1}"\)
1199 eval src_"$f"=\$\(format_\$f "${2}"\)
1202 if [ "$(count_packets)" != "0" ]; then
1203 err "${proto} packet to:"
1204 err " $(for f in ${dst}; do
1205 eval format_\$f "${1}"; printf ' '; done)"
1207 err " $(for f in ${src}; do
1208 eval format_\$f "${2}"; printf ' '; done)"
1209 err "should not have matched ruleset:"
1210 err "$(nft -a list ruleset)"
1215 # Correctness test template:
1216 # - add ranged element, check that packets match it
1217 # - check that packets outside range don't match it
1218 # - remove some elements, check that packets don't match anymore
1219 test_correctness() {
1220 setup veth send_"${proto}" set || return ${KSELFTEST_SKIP}
1223 for i in $(seq "${start}" $((start + count))); do
1224 end=$((start + range_size))
1226 # Avoid negative or zero-sized port ranges
1227 if [ $((end / 65534)) -gt $((start / 65534)) ]; then
1231 srcstart=$((start + src_delta))
1232 srcend=$((end + src_delta))
1234 add "$(format)" || return 1
1235 for j in $(seq ${start} $((range_size / 2 + 1)) ${end}); do
1236 send_match "${j}" $((j + src_delta)) || return 1
1238 send_nomatch $((end + 1)) $((end + 1 + src_delta)) || return 1
1240 # Delete elements now and then
1241 if [ $((i % 3)) -eq 0 ]; then
1242 del "$(format)" || return 1
1243 for j in $(seq ${start} \
1244 $((range_size / 2 + 1)) ${end}); do
1245 send_nomatch "${j}" $((j + src_delta)) \
1250 range_size=$((range_size + 1))
1251 start=$((end + range_size))
1255 # Concurrency test template:
1256 # - add all the elements
1257 # - start a thread for each physical thread that:
1258 # - adds all the elements
1260 # - adds all the elements
1261 # - flushes the entire ruleset
1262 # - adds the set back
1263 # - adds all the elements
1264 # - delete all the elements
1265 test_concurrency() {
1266 proto=${flood_proto}
1267 tools=${flood_tools}
1268 chain_spec=${flood_spec}
1269 setup veth flood_"${proto}" set || return ${KSELFTEST_SKIP}
1274 for i in $(seq ${start} $((start + count))); do
1275 end=$((start + range_size))
1276 srcstart=$((start + src_delta))
1277 srcend=$((end + src_delta))
1279 add "$(format)" || return 1
1281 flood "${i}" $((i + src_delta)) & flood_pids="${flood_pids} $!"
1283 range_size=$((range_size + 1))
1284 start=$((end + range_size))
1290 for c in $(seq 1 "$(nproc)"); do (
1291 for r in $(seq 1 "${race_repeat}"); do
1294 # $start needs to be local to this subshell
1295 # shellcheck disable=SC2030
1297 for i in $(seq ${start} $((start + count))); do
1298 end=$((start + range_size))
1299 srcstart=$((start + src_delta))
1300 srcend=$((end + src_delta))
1302 add "$(format)" 2>/dev/null
1304 range_size=$((range_size + 1))
1305 start=$((end + range_size))
1308 nft flush inet filter test 2>/dev/null
1312 for i in $(seq ${start} $((start + count))); do
1313 end=$((start + range_size))
1314 srcstart=$((start + src_delta))
1315 srcend=$((end + src_delta))
1317 add "$(format)" 2>/dev/null
1319 range_size=$((range_size + 1))
1320 start=$((end + range_size))
1324 setup set 2>/dev/null
1328 for i in $(seq ${start} $((start + count))); do
1329 end=$((start + range_size))
1330 srcstart=$((start + src_delta))
1331 srcend=$((end + src_delta))
1333 add "$(format)" 2>/dev/null
1335 range_size=$((range_size + 1))
1336 start=$((end + range_size))
1341 for i in $(seq ${start} $((start + count))); do
1342 end=$((start + range_size))
1343 srcstart=$((start + src_delta))
1344 srcend=$((end + src_delta))
1346 del "$(format)" 2>/dev/null
1348 range_size=$((range_size + 1))
1349 start=$((end + range_size))
1352 ) & pids="${pids} $!"
1355 # shellcheck disable=SC2046,SC2086 # word splitting wanted here
1356 wait $(for pid in ${pids}; do echo ${pid}; done)
1357 # shellcheck disable=SC2046,SC2086
1358 kill $(for pid in ${flood_pids}; do echo ${pid}; done) 2>/dev/null
1359 # shellcheck disable=SC2046,SC2086
1360 wait $(for pid in ${flood_pids}; do echo ${pid}; done) 2>/dev/null
1365 # Timeout test template:
1366 # - add all the elements with 3s timeout while checking that packets match
1367 # - wait 3s after the last insertion, check that packets don't match any entry
1369 setup veth send_"${proto}" set || return ${KSELFTEST_SKIP}
1373 for i in $(seq "${start}" $((start + count))); do
1374 end=$((start + range_size))
1375 srcstart=$((start + src_delta))
1376 srcend=$((end + src_delta))
1378 add "$(format)" || return 1
1380 for j in $(seq ${start} $((range_size / 2 + 1)) ${end}); do
1381 send_match "${j}" $((j + src_delta)) || return 1
1384 range_size=$((range_size + 1))
1385 start=$((end + range_size))
1388 for i in $(seq ${start} $((start + count))); do
1389 end=$((start + range_size))
1390 srcstart=$((start + src_delta))
1391 srcend=$((end + src_delta))
1393 for j in $(seq ${start} $((range_size / 2 + 1)) ${end}); do
1394 send_nomatch "${j}" $((j + src_delta)) || return 1
1397 range_size=$((range_size + 1))
1398 start=$((end + range_size))
1402 # Performance test template:
1403 # - add concatenated ranged entries
1404 # - add non-ranged concatenated entries (for hash set matching rate baseline)
1405 # - add ranged entries with first field only (for rbhash baseline)
1406 # - start pktgen injection directly on device rx path of this namespace
1407 # - measure drop only rate, hash and rbtree baselines, then matching rate
1408 test_performance() {
1409 chain_spec=${perf_spec}
1412 setup veth perf set || return ${KSELFTEST_SKIP}
1416 for set in test norange noconcat; do
1418 for i in $(seq ${start} $((start + perf_entries))); do
1419 end=$((start + range_size))
1420 srcstart=$((start + src_delta))
1421 srcend=$((end + src_delta))
1423 if [ $((end / 65534)) -gt $((start / 65534)) ]; then
1426 elif [ ${start} -eq ${end} ]; then
1432 start=$((end + range_size))
1437 perf $((end - 1)) ${srcstart}
1441 nft add rule netdev perf test counter name \"test\" drop
1442 nft reset counter netdev perf test >/dev/null 2>&1
1443 sleep "${perf_duration}"
1444 pps="$(printf %10s $(($(count_perf_packets) / perf_duration)))"
1445 info " baseline (drop from netdev hook): ${pps}pps"
1446 handle="$(nft -a list chain netdev perf test | grep counter)"
1447 handle="${handle##* }"
1448 nft delete rule netdev perf test handle "${handle}"
1450 nft add rule "netdev perf test ${chain_spec} @norange \
1451 counter name \"test\" drop"
1452 nft reset counter netdev perf test >/dev/null 2>&1
1453 sleep "${perf_duration}"
1454 pps="$(printf %10s $(($(count_perf_packets) / perf_duration)))"
1455 info " baseline hash (non-ranged entries): ${pps}pps"
1456 handle="$(nft -a list chain netdev perf test | grep counter)"
1457 handle="${handle##* }"
1458 nft delete rule netdev perf test handle "${handle}"
1460 nft add rule "netdev perf test ${chain_spec%%. *} @noconcat \
1461 counter name \"test\" drop"
1462 nft reset counter netdev perf test >/dev/null 2>&1
1463 sleep "${perf_duration}"
1464 pps="$(printf %10s $(($(count_perf_packets) / perf_duration)))"
1465 info " baseline rbtree (match on first field only): ${pps}pps"
1466 handle="$(nft -a list chain netdev perf test | grep counter)"
1467 handle="${handle##* }"
1468 nft delete rule netdev perf test handle "${handle}"
1470 nft add rule "netdev perf test ${chain_spec} @test \
1471 counter name \"test\" drop"
1472 nft reset counter netdev perf test >/dev/null 2>&1
1473 sleep "${perf_duration}"
1474 pps="$(printf %10s $(($(count_perf_packets) / perf_duration)))"
1475 p5="$(printf %5s "${perf_entries}")"
1476 info " set with ${p5} full, ranged entries: ${pps}pps"
1480 test_bug_flush_remove_add() {
1481 set_cmd='{ set s { type ipv4_addr . inet_service; flags interval; }; }'
1482 elem1='{ 10.0.0.1 . 22-25, 10.0.0.1 . 10-20 }'
1483 elem2='{ 10.0.0.1 . 10-20, 10.0.0.1 . 22-25 }'
1484 for i in `seq 1 100`; do
1485 nft add table t ${set_cmd} || return ${KSELFTEST_SKIP}
1486 nft add element t s ${elem1} 2>/dev/null || return 1
1487 nft flush set t s 2>/dev/null || return 1
1488 nft add element t s ${elem2} 2>/dev/null || return 1
1493 # - add ranged element, check that packets match it
1494 # - reload the set, check packets still match
1496 setup veth send_"${proto}" set || return ${KSELFTEST_SKIP}
1500 for i in $(seq "${start}" $((start + count))); do
1501 end=$((start + range_size))
1503 # Avoid negative or zero-sized port ranges
1504 if [ $((end / 65534)) -gt $((start / 65534)) ]; then
1508 srcstart=$((start + src_delta))
1509 srcend=$((end + src_delta))
1511 add "$(format)" || return 1
1512 range_size=$((range_size + 1))
1513 start=$((end + range_size))
1516 # check kernel does allocate pcpu sctrach map
1517 # for reload with no elemet add/delete
1518 ( echo flush set inet filter test ;
1519 nft list set inet filter test ) | nft -f -
1524 for i in $(seq "${start}" $((start + count))); do
1525 end=$((start + range_size))
1527 # Avoid negative or zero-sized port ranges
1528 if [ $((end / 65534)) -gt $((start / 65534)) ]; then
1532 srcstart=$((start + src_delta))
1533 srcend=$((end + src_delta))
1535 for j in $(seq ${start} $((range_size / 2 + 1)) ${end}); do
1536 send_match "${j}" $((j + src_delta)) || return 1
1539 range_size=$((range_size + 1))
1540 start=$((end + range_size))
1546 test_reported_issues() {
1547 eval test_bug_"${subtest}"
1550 # Run everything in a separate network namespace
1551 [ "${1}" != "run" ] && { unshare -n "${0}" run; exit $?; }
1555 # Entry point for test runs
1557 for name in ${TESTS}; do
1558 printf "TEST: %s\n" "$(echo ${name} | tr '_' ' ')"
1559 if [ "${name}" = "reported_issues" ]; then
1565 for subtest in ${SUBTESTS}; do
1566 eval desc=\$TYPE_"${subtest}"
1569 for __line in ${desc}; do
1570 # shellcheck disable=SC2086
1571 eval ${__line%% *}=\"${__line##* }\";
1576 if [ "${name}" = "concurrency" ] && \
1577 [ "${race_repeat}" = "0" ]; then
1580 if [ "${name}" = "performance" ] && \
1581 [ "${perf_duration}" = "0" ]; then
1585 printf " %-60s " "${display}"
1589 if [ $ret -eq 0 ]; then
1592 passed=$((passed + 1))
1593 elif [ $ret -eq 1 ]; then
1597 elif [ $ret -eq ${KSELFTEST_SKIP} ]; then
1604 [ ${passed} -eq 0 ] && exit ${KSELFTEST_SKIP} || exit 0