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"
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
357 # Set template for all tests, types and rules are filled in depending on test
368 flags interval,timeout
372 type filter hook prerouting priority 0; policy accept;
373 ${chain_spec} @test counter name \"test\"
396 type ${type_spec%% *}
401 type filter hook ingress device veth_a priority 0;
409 # Append string to error buffer
411 err_buf="${err_buf}${1}
415 # Append string to information buffer
417 info_buf="${info_buf}${1}
421 # Flush error buffer to stdout
423 printf "%s" "${err_buf}"
427 # Flush information buffer to stdout
429 printf "%s" "${info_buf}"
433 # Setup veth pair: this namespace receives traffic, B generates it
436 ip link add veth_a type veth peer name veth_b || return 1
438 ip link set veth_a up
439 ip link set veth_b netns B
441 ip -n B link set veth_b up
443 ip addr add dev veth_a 10.0.0.1
444 ip route add default dev veth_a
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
450 ip -n B route add default dev veth_b
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
457 ip netns exec B "$@" >/dev/null 2>&1
463 # Fill in set template and initialise set
465 eval "echo \"${set_template}\"" | nft -f -
468 # Check that at least one of the needed tools is available
470 [ -z "${tools}" ] && return 0
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"
480 __tools="${__tools} ${tool}"
482 command -v "${tool}" >/dev/null && return 0
484 err "need one of:${__tools}, skipping" && return 1
487 # Set up function to send ICMP packets
490 B ping -c1 -W1 "${dst_addr4}" >/dev/null 2>&1
494 # Set up function to send ICMPv6 packets
496 if command -v ping6 >/dev/null; then
498 ip -6 addr add "${dst_addr6}" dev veth_a nodad \
500 B ping6 -q -c1 -W1 "${dst_addr6}"
504 ip -6 addr add "${dst_addr6}" dev veth_a nodad \
506 B ping -q -6 -c1 -W1 "${dst_addr6}"
511 # Set up function to send single UDP packets on IPv4
513 if command -v sendip >/dev/null; then
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}"
519 # shellcheck disable=SC2086 # sendip needs split options
520 B sendip -p ipv4 -p udp ${src_addr4} ${src_port} \
521 ${dst_port} "${dst_addr4}"
527 elif command -v nc >/dev/null; then
528 if nc -u -w0 1.1.1.1 1 2>/dev/null; then
537 if [ -n "${src_addr4}" ]; then
538 B ip addr add "${src_addr4}" dev veth_b
539 __src_addr4="-s ${src_addr4}"
541 ip addr add "${dst_addr4}" dev veth_a 2>/dev/null
542 [ -n "${src_port}" ] && src_port="-p ${src_port}"
544 echo "" | B nc -u "${nc_opt}" "${__src_addr4}" \
545 "${src_port}" "${dst_addr4}" "${dst_port}"
550 elif [ -z "$(bash -c 'type -p')" ]; then
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
558 B bash -c "echo > /dev/udp/${dst_addr4}/${dst_port}"
560 if [ -n "${src_addr4}" ]; then
561 B ip addr del "${src_addr4}/16" dev veth_b
570 # Set up function to send single UDP packets on IPv6
572 if command -v sendip >/dev/null; then
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}"
579 src_addr6="-6s 2001:db8::2"
581 ip -6 addr add "${dst_addr6}" dev veth_a nodad \
584 # shellcheck disable=SC2086 # this needs split options
585 B sendip -p ipv6 -p udp ${src_addr6} ${src_port} \
586 ${dst_port} "${dst_addr6}"
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
595 ip -6 addr add "${dst_addr6}" dev veth_a nodad \
597 if [ -n "${src_addr6}" ]; then
598 B ip addr add "${src_addr6}" dev veth_b nodad
600 src_addr6="2001:db8::2"
602 [ -n "${src_port}" ] && src_port="-p ${src_port}"
604 # shellcheck disable=SC2086 # this needs split options
605 echo "" | B nc -u w0 "-s${src_addr6}" ${src_port} \
606 ${dst_addr6} ${dst_port}
611 elif [ -z "$(bash -c 'type -p')" ]; then
613 ip -6 addr add "${dst_addr6}" dev veth_a nodad \
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
624 # Set up function to send TCP traffic on IPv4
626 if command -v iperf3 >/dev/null; then
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}"
633 B ip addr add dev veth_b 10.0.0.2
634 src_addr4="-B 10.0.0.2"
636 if [ -n "${src_port}" ]; then
637 src_port="--cport ${src_port}"
639 B ip route add default dev veth_b 2>/dev/null
640 ip addr add "${dst_addr4}" dev veth_a 2>/dev/null
642 # shellcheck disable=SC2086 # this needs split options
643 iperf3 -s -DB "${dst_addr4}" ${dst_port} >/dev/null 2>&1
646 # shellcheck disable=SC2086 # this needs split options
647 B iperf3 -c "${dst_addr4}" ${dst_port} ${src_port} \
648 ${src_addr4} -l16 -t 1000
654 elif command -v iperf >/dev/null; then
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}"
661 B ip addr add dev veth_b 10.0.0.2 2>/dev/null
662 src_addr4="-B 10.0.0.2"
664 if [ -n "${src_port}" ]; then
665 src_addr4="${src_addr4}:${src_port}"
667 B ip route add default dev veth_b
668 ip addr add "${dst_addr4}" dev veth_a 2>/dev/null
670 # shellcheck disable=SC2086 # this needs split options
671 iperf -s -DB "${dst_addr4}" ${dst_port} >/dev/null 2>&1
674 # shellcheck disable=SC2086 # this needs split options
675 B iperf -c "${dst_addr4}" ${dst_port} ${src_addr4} \
682 elif command -v netperf >/dev/null; then
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
688 B ip addr add dev veth_b 10.0.0.2
691 if [ -n "${src_port}" ]; then
692 dst_port="${dst_port},${src_port}"
694 B ip route add default dev veth_b
695 ip addr add "${dst_addr4}" dev veth_a 2>/dev/null
697 # shellcheck disable=SC2086 # this needs split options
698 netserver -4 ${dst_port} -L "${dst_addr4}" \
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
715 # Set up function to send TCP traffic on IPv6
717 if command -v iperf3 >/dev/null; then
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}"
724 src_addr6="-B 2001:db8::2"
726 if [ -n "${src_port}" ]; then
727 src_port="--cport ${src_port}"
729 B ip route add default dev veth_b
730 ip -6 addr add "${dst_addr6}" dev veth_a nodad \
733 # shellcheck disable=SC2086 # this needs split options
734 iperf3 -s -DB "${dst_addr6}" ${dst_port} >/dev/null 2>&1
737 # shellcheck disable=SC2086 # this needs split options
738 B iperf3 -c "${dst_addr6}" ${dst_port} \
739 ${src_port} ${src_addr6} -l16 -t 1000
745 elif command -v iperf >/dev/null; then
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}"
752 src_addr6="-B 2001:db8::2"
754 if [ -n "${src_port}" ]; then
755 src_addr6="${src_addr6}:${src_port}"
757 B ip route add default dev veth_b
758 ip -6 addr add "${dst_addr6}" dev veth_a nodad \
761 # shellcheck disable=SC2086 # this needs split options
762 iperf -s -VDB "${dst_addr6}" ${dst_port} >/dev/null 2>&1
765 # shellcheck disable=SC2086 # this needs split options
766 B iperf -c "${dst_addr6}" -V ${dst_port} \
767 ${src_addr6} -l1 -t 1000
773 elif command -v netperf >/dev/null; then
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
779 src_addr6="2001:db8::2"
781 if [ -n "${src_port}" ]; then
782 dst_port="${dst_port},${src_port}"
784 B ip route add default dev veth_b
785 ip -6 addr add "${dst_addr6}" dev veth_a nodad \
788 # shellcheck disable=SC2086 # this needs split options
789 netserver -6 ${dst_port} -L "${dst_addr6}" \
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
806 # Set up function to send UDP traffic on IPv4
808 if command -v iperf3 >/dev/null; then
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}"
815 B ip addr add dev veth_b 10.0.0.2 2>/dev/null
816 src_addr4="-B 10.0.0.2"
818 if [ -n "${src_port}" ]; then
819 src_port="--cport ${src_port}"
821 B ip route add default dev veth_b
822 ip addr add "${dst_addr4}" dev veth_a 2>/dev/null
824 # shellcheck disable=SC2086 # this needs split options
825 iperf3 -s -DB "${dst_addr4}" ${dst_port}
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}
836 elif command -v iperf >/dev/null; then
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}"
843 B ip addr add dev veth_b 10.0.0.2
844 src_addr4="-B 10.0.0.2"
846 if [ -n "${src_port}" ]; then
847 src_addr4="${src_addr4}:${src_port}"
849 B ip route add default dev veth_b
850 ip addr add "${dst_addr4}" dev veth_a 2>/dev/null
852 # shellcheck disable=SC2086 # this needs split options
853 iperf -u -sDB "${dst_addr4}" ${dst_port} >/dev/null 2>&1
856 # shellcheck disable=SC2086 # this needs split options
857 B iperf -u -c "${dst_addr4}" -b 100M -l1 -t1000 \
858 ${dst_port} ${src_addr4}
864 elif command -v netperf >/dev/null; then
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
870 B ip addr add dev veth_b 10.0.0.2
873 if [ -n "${src_port}" ]; then
874 dst_port="${dst_port},${src_port}"
876 B ip route add default dev veth_b
877 ip addr add "${dst_addr4}" dev veth_a 2>/dev/null
879 # shellcheck disable=SC2086 # this needs split options
880 netserver -4 ${dst_port} -L "${dst_addr4}" \
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
897 # Find pktgen script and set up function to start pktgen injection
899 for pktgen_script_path in ${PKTGEN_SCRIPT_PATHS} __notfound; do
900 command -v "${pktgen_script_path}" >/dev/null && break
902 [ "${pktgen_script_path}" = "__notfound" ] && return 1
905 ${pktgen_script_path} -s80 \
906 -i veth_a -d "${dst_addr4}" -p "${dst_port}" \
908 -t $(($(nproc) / 5 + 1)) -b10000 -n0 2>/dev/null &
912 IP6=6 ${pktgen_script_path} -s100 \
913 -i veth_a -d "${dst_addr6}" -p "${dst_port}" \
915 -t $(($(nproc) / 5 + 1)) -b10000 -n0 2>/dev/null &
920 # Clean up before each test
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
930 killall iperf3 2>/dev/null
931 killall iperf 2>/dev/null
932 killall netperf 2>/dev/null
933 killall netserver 2>/dev/null
938 # Entry point for setup functions
940 if [ "$(id -u)" -ne 0 ]; then
941 echo " need to run as root"
942 exit ${KSELFTEST_SKIP}
946 check_tools || return 1
948 if ! eval setup_"${arg}"; then
949 err " ${arg} not supported"
955 # Format integer into IPv4 address, summing 10.0.0.5 (arbitrary) to it
957 a=$((${1} + 16777216 * 10 + 5))
958 printf "%i.%i.%i.%i" \
959 "$((a / 16777216))" "$((a % 16777216 / 65536))" \
960 "$((a % 65536 / 256))" "$((a % 256))"
963 # Format integer into IPv6 address, summing 2001:db8:: to it
965 printf "2001:db8::%04x:%04x" "$((${1} / 65536))" "$((${1} % 65536))"
968 # Format integer into EUI-48 address, summing 00:01:00:00:00:00 to it
970 printf "00:01:%02x:%02x:%02x:%02x" \
971 "$((${1} / 16777216))" "$((${1} % 16777216 / 65536))" \
972 "$((${1} % 65536 / 256))" "$((${1} % 256))"
975 # Format integer into port, avoid 0 port
977 printf "%i" "$((${1} % 65534 + 1))"
980 # Drop suffixed '6' from L4 protocol, if any
982 printf "%s" "${proto}" | tr -d 6
985 # Format destination and source fields into nft concatenated type
992 [ "${__expr}" != "{ " ] && __expr="${__expr} . "
994 __start="$(eval format_"${f}" "${start}")"
995 __end="$(eval format_"${f}" "${end}")"
997 if [ "${f}" = "proto" ]; then
998 __expr="${__expr}${__start}"
1000 __expr="${__expr}${__start}-${__end}"
1004 [ "${__expr}" != "{ " ] && __expr="${__expr} . "
1006 __start="$(eval format_"${f}" "${srcstart}")"
1007 __end="$(eval format_"${f}" "${srcend}")"
1009 if [ "${f}" = "proto" ]; then
1010 __expr="${__expr}${__start}"
1012 __expr="${__expr}${__start}-${__end}"
1016 if [ -n "${timeout}" ]; then
1017 echo "${__expr} timeout ${timeout}s }"
1023 # Format destination and source fields into nft type, start element only
1028 [ "${__expr}" != "{ " ] && __expr="${__expr} . "
1030 __expr="${__expr}$(eval format_"${f}" "${start}")"
1033 __expr="${__expr} . $(eval format_"${f}" "${start}")"
1039 # Format first destination field into nft type
1042 __start="$(eval format_"${f}" "${start}")"
1043 __end="$(eval format_"${f}" "${end}")"
1045 if [ "${f}" = "proto" ]; then
1046 echo "{ ${__start} }"
1048 echo "{ ${__start}-${__end} }"
1054 # Add single entry to 'test' set in 'inet filter' table
1056 if ! nft add element inet filter test "${1}"; then
1057 err "Failed to add ${1} given ruleset:"
1058 err "$(nft -a list ruleset)"
1063 # Format and output entries for sets in 'netdev perf' table
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)"
1074 # Add single entry to 'norange' set in 'netdev perf' table
1075 add_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)"
1083 # Add single entry to 'noconcat' set in 'netdev perf' table
1084 add_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)"
1092 # Delete single entry from set
1094 if ! nft delete element inet filter test "${1}"; then
1095 err "Failed to delete ${1} given ruleset:"
1096 err "$(nft -a list ruleset)"
1101 # Return packet count from 'test' counter in 'inet filter' table
1104 for token in $(nft list counter inet filter test); do
1105 [ ${found} -eq 1 ] && echo "${token}" && return
1106 [ "${token}" = "packets" ] && found=1
1110 # Return packet count from 'test' counter in 'netdev perf' table
1111 count_perf_packets() {
1113 for token in $(nft list counter netdev perf test); do
1114 [ ${found} -eq 1 ] && echo "${token}" && return
1115 [ "${token}" = "packets" ] && found=1
1119 # Set MAC addresses, send traffic according to specifier
1121 ip link set veth_a address "$(format_mac "${1}")"
1122 ip -n B link set veth_b address "$(format_mac "${2}")"
1125 eval dst_"$f"=\$\(format_\$f "${1}"\)
1128 eval src_"$f"=\$\(format_\$f "${2}"\)
1133 # Set MAC addresses, start pktgen injection
1135 dst_mac="$(format_mac "${1}")"
1136 ip link set veth_a address "${dst_mac}"
1139 eval dst_"$f"=\$\(format_\$f "${1}"\)
1142 eval src_"$f"=\$\(format_\$f "${2}"\)
1144 eval perf_\$perf_proto
1147 # Set MAC addresses, send single packet, check that it matches, reset counter
1149 ip link set veth_a address "$(format_mac "${1}")"
1150 ip -n B link set veth_b address "$(format_mac "${2}")"
1153 eval dst_"$f"=\$\(format_\$f "${1}"\)
1156 eval src_"$f"=\$\(format_\$f "${2}"\)
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)"
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)"
1170 nft reset counter inet filter test >/dev/null
1173 # Set MAC addresses, send single packet, check that it doesn't match
1175 ip link set veth_a address "$(format_mac "${1}")"
1176 ip -n B link set veth_b address "$(format_mac "${2}")"
1179 eval dst_"$f"=\$\(format_\$f "${1}"\)
1182 eval src_"$f"=\$\(format_\$f "${2}"\)
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)"
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)"
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
1202 test_correctness() {
1203 setup veth send_"${proto}" set || return ${KSELFTEST_SKIP}
1206 for i in $(seq "${start}" $((start + count))); do
1207 end=$((start + range_size))
1209 # Avoid negative or zero-sized port ranges
1210 if [ $((end / 65534)) -gt $((start / 65534)) ]; then
1214 srcstart=$((start + src_delta))
1215 srcend=$((end + src_delta))
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
1221 send_nomatch $((end + 1)) $((end + 1 + src_delta)) || return 1
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)) \
1233 range_size=$((range_size + 1))
1234 start=$((end + range_size))
1238 # Concurrency test template:
1239 # - add all the elements
1240 # - start a thread for each physical thread that:
1241 # - adds all the elements
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
1248 test_concurrency() {
1249 proto=${flood_proto}
1250 tools=${flood_tools}
1251 chain_spec=${flood_spec}
1252 setup veth flood_"${proto}" set || return ${KSELFTEST_SKIP}
1257 for i in $(seq ${start} $((start + count))); do
1258 end=$((start + range_size))
1259 srcstart=$((start + src_delta))
1260 srcend=$((end + src_delta))
1262 add "$(format)" || return 1
1264 flood "${i}" $((i + src_delta)) & flood_pids="${flood_pids} $!"
1266 range_size=$((range_size + 1))
1267 start=$((end + range_size))
1273 for c in $(seq 1 "$(nproc)"); do (
1274 for r in $(seq 1 "${race_repeat}"); do
1277 # $start needs to be local to this subshell
1278 # shellcheck disable=SC2030
1280 for i in $(seq ${start} $((start + count))); do
1281 end=$((start + range_size))
1282 srcstart=$((start + src_delta))
1283 srcend=$((end + src_delta))
1285 add "$(format)" 2>/dev/null
1287 range_size=$((range_size + 1))
1288 start=$((end + range_size))
1291 nft flush inet filter test 2>/dev/null
1295 for i in $(seq ${start} $((start + count))); do
1296 end=$((start + range_size))
1297 srcstart=$((start + src_delta))
1298 srcend=$((end + src_delta))
1300 add "$(format)" 2>/dev/null
1302 range_size=$((range_size + 1))
1303 start=$((end + range_size))
1307 setup set 2>/dev/null
1311 for i in $(seq ${start} $((start + count))); do
1312 end=$((start + range_size))
1313 srcstart=$((start + src_delta))
1314 srcend=$((end + src_delta))
1316 add "$(format)" 2>/dev/null
1318 range_size=$((range_size + 1))
1319 start=$((end + range_size))
1324 for i in $(seq ${start} $((start + count))); do
1325 end=$((start + range_size))
1326 srcstart=$((start + src_delta))
1327 srcend=$((end + src_delta))
1329 del "$(format)" 2>/dev/null
1331 range_size=$((range_size + 1))
1332 start=$((end + range_size))
1335 ) & pids="${pids} $!"
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
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
1352 setup veth send_"${proto}" set || return ${KSELFTEST_SKIP}
1356 for i in $(seq "${start}" $((start + count))); do
1357 end=$((start + range_size))
1358 srcstart=$((start + src_delta))
1359 srcend=$((end + src_delta))
1361 add "$(format)" || return 1
1363 for j in $(seq ${start} $((range_size / 2 + 1)) ${end}); do
1364 send_match "${j}" $((j + src_delta)) || return 1
1367 range_size=$((range_size + 1))
1368 start=$((end + range_size))
1371 for i in $(seq ${start} $((start + count))); do
1372 end=$((start + range_size))
1373 srcstart=$((start + src_delta))
1374 srcend=$((end + src_delta))
1376 for j in $(seq ${start} $((range_size / 2 + 1)) ${end}); do
1377 send_nomatch "${j}" $((j + src_delta)) || return 1
1380 range_size=$((range_size + 1))
1381 start=$((end + range_size))
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
1391 test_performance() {
1392 chain_spec=${perf_spec}
1395 setup veth perf set || return ${KSELFTEST_SKIP}
1399 for set in test norange noconcat; do
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))
1406 if [ $((end / 65534)) -gt $((start / 65534)) ]; then
1409 elif [ ${start} -eq ${end} ]; then
1415 start=$((end + range_size))
1420 perf $((end - 1)) ${srcstart}
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}"
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}"
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}"
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"
1463 test_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
1476 test_reported_issues() {
1477 eval test_bug_"${subtest}"
1480 # Run everything in a separate network namespace
1481 [ "${1}" != "run" ] && { unshare -n "${0}" run; exit $?; }
1485 # Entry point for test runs
1487 for name in ${TESTS}; do
1488 printf "TEST: %s\n" "$(echo ${name} | tr '_' ' ')"
1489 if [ "${name}" = "reported_issues" ]; then
1495 for subtest in ${SUBTESTS}; do
1496 eval desc=\$TYPE_"${subtest}"
1499 for __line in ${desc}; do
1500 # shellcheck disable=SC2086
1501 eval ${__line%% *}=\"${__line##* }\";
1506 if [ "${name}" = "concurrency" ] && \
1507 [ "${race_repeat}" = "0" ]; then
1510 if [ "${name}" = "performance" ] && \
1511 [ "${perf_duration}" = "0" ]; then
1515 printf " %-60s " "${display}"
1519 if [ $ret -eq 0 ]; then
1522 passed=$((passed + 1))
1523 elif [ $ret -eq 1 ]; then
1527 elif [ $ret -eq ${KSELFTEST_SKIP} ]; then
1534 [ ${passed} -eq 0 ] && exit ${KSELFTEST_SKIP}