summaryrefslogtreecommitdiff
path: root/tools/testing
diff options
context:
space:
mode:
Diffstat (limited to 'tools/testing')
-rw-r--r--tools/testing/selftests/drivers/net/team/Makefile1
-rw-r--r--tools/testing/selftests/drivers/net/team/config2
-rwxr-xr-xtools/testing/selftests/drivers/net/team/non_ether_header_ops.sh41
-rw-r--r--tools/testing/selftests/kvm/Makefile.kvm1
-rw-r--r--tools/testing/selftests/kvm/s390/irq_routing.c75
-rw-r--r--tools/testing/selftests/landlock/tsync_test.c91
-rwxr-xr-xtools/testing/selftests/net/fib_tests.sh61
-rwxr-xr-xtools/testing/selftests/net/netfilter/nft_concat_range.sh70
8 files changed, 337 insertions, 5 deletions
diff --git a/tools/testing/selftests/drivers/net/team/Makefile b/tools/testing/selftests/drivers/net/team/Makefile
index 45a3e7ad3dcb..02d6f51d5a06 100644
--- a/tools/testing/selftests/drivers/net/team/Makefile
+++ b/tools/testing/selftests/drivers/net/team/Makefile
@@ -3,6 +3,7 @@
TEST_PROGS := \
dev_addr_lists.sh \
+ non_ether_header_ops.sh \
options.sh \
propagation.sh \
refleak.sh \
diff --git a/tools/testing/selftests/drivers/net/team/config b/tools/testing/selftests/drivers/net/team/config
index 558e1d0cf565..5d36a22ef080 100644
--- a/tools/testing/selftests/drivers/net/team/config
+++ b/tools/testing/selftests/drivers/net/team/config
@@ -1,7 +1,9 @@
+CONFIG_BONDING=y
CONFIG_DUMMY=y
CONFIG_IPV6=y
CONFIG_MACVLAN=y
CONFIG_NETDEVSIM=m
+CONFIG_NET_IPGRE=y
CONFIG_NET_TEAM=y
CONFIG_NET_TEAM_MODE_ACTIVEBACKUP=y
CONFIG_NET_TEAM_MODE_LOADBALANCE=y
diff --git a/tools/testing/selftests/drivers/net/team/non_ether_header_ops.sh b/tools/testing/selftests/drivers/net/team/non_ether_header_ops.sh
new file mode 100755
index 000000000000..948a43576bdc
--- /dev/null
+++ b/tools/testing/selftests/drivers/net/team/non_ether_header_ops.sh
@@ -0,0 +1,41 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# shellcheck disable=SC2154
+#
+# Reproduce the non-Ethernet header_ops confusion scenario with:
+# g0 (gre) -> b0 (bond) -> t0 (team)
+#
+# Before the fix, direct header_ops inheritance in this stack could call
+# callbacks with the wrong net_device context and crash.
+
+lib_dir=$(dirname "$0")
+source "$lib_dir"/../../../net/lib.sh
+
+trap cleanup_all_ns EXIT
+
+setup_ns ns1
+
+ip -n "$ns1" link add d0 type dummy
+ip -n "$ns1" addr add 10.10.10.1/24 dev d0
+ip -n "$ns1" link set d0 up
+
+ip -n "$ns1" link add g0 type gre local 10.10.10.1
+ip -n "$ns1" link add b0 type bond mode active-backup
+ip -n "$ns1" link add t0 type team
+
+ip -n "$ns1" link set g0 master b0
+ip -n "$ns1" link set b0 master t0
+
+ip -n "$ns1" link set g0 up
+ip -n "$ns1" link set b0 up
+ip -n "$ns1" link set t0 up
+
+# IPv6 address assignment triggers MLD join reports that call
+# dev_hard_header() on t0, exercising the inherited header_ops path.
+ip -n "$ns1" -6 addr add 2001:db8:1::1/64 dev t0 nodad
+for i in $(seq 1 20); do
+ ip netns exec "$ns1" ping -6 -I t0 ff02::1 -c1 -W1 &>/dev/null || true
+done
+
+echo "PASS: non-Ethernet header_ops stacking did not crash"
+exit "$EXIT_STATUS"
diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
index dc68371f76a3..6471fa214a9f 100644
--- a/tools/testing/selftests/kvm/Makefile.kvm
+++ b/tools/testing/selftests/kvm/Makefile.kvm
@@ -206,6 +206,7 @@ TEST_GEN_PROGS_s390 += s390/ucontrol_test
TEST_GEN_PROGS_s390 += s390/user_operexec
TEST_GEN_PROGS_s390 += s390/keyop
TEST_GEN_PROGS_s390 += rseq_test
+TEST_GEN_PROGS_s390 += s390/irq_routing
TEST_GEN_PROGS_riscv = $(TEST_GEN_PROGS_COMMON)
TEST_GEN_PROGS_riscv += riscv/sbi_pmu_test
diff --git a/tools/testing/selftests/kvm/s390/irq_routing.c b/tools/testing/selftests/kvm/s390/irq_routing.c
new file mode 100644
index 000000000000..7819a0af19a8
--- /dev/null
+++ b/tools/testing/selftests/kvm/s390/irq_routing.c
@@ -0,0 +1,75 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * IRQ routing offset tests.
+ *
+ * Copyright IBM Corp. 2026
+ *
+ * Authors:
+ * Janosch Frank <frankja@linux.ibm.com>
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+
+#include "test_util.h"
+#include "kvm_util.h"
+#include "kselftest.h"
+#include "ucall_common.h"
+
+extern char guest_code[];
+asm("guest_code:\n"
+ "diag %r0,%r0,0\n"
+ "j .\n");
+
+static void test(void)
+{
+ struct kvm_irq_routing *routing;
+ struct kvm_vcpu *vcpu;
+ struct kvm_vm *vm;
+ vm_paddr_t mem;
+ int ret;
+
+ struct kvm_irq_routing_entry ue = {
+ .type = KVM_IRQ_ROUTING_S390_ADAPTER,
+ .gsi = 1,
+ };
+
+ vm = vm_create_with_one_vcpu(&vcpu, guest_code);
+ mem = vm_phy_pages_alloc(vm, 2, 4096 * 42, 0);
+
+ routing = kvm_gsi_routing_create();
+ routing->nr = 1;
+ routing->entries[0] = ue;
+ routing->entries[0].u.adapter.summary_addr = (uintptr_t)mem;
+ routing->entries[0].u.adapter.ind_addr = (uintptr_t)mem;
+
+ routing->entries[0].u.adapter.summary_offset = 4096 * 8;
+ ret = __vm_ioctl(vm, KVM_SET_GSI_ROUTING, routing);
+ ksft_test_result(ret == -1 && errno == EINVAL, "summary offset outside of page\n");
+
+ routing->entries[0].u.adapter.summary_offset -= 4;
+ ret = __vm_ioctl(vm, KVM_SET_GSI_ROUTING, routing);
+ ksft_test_result(ret == 0, "summary offset inside of page\n");
+
+ routing->entries[0].u.adapter.ind_offset = 4096 * 8;
+ ret = __vm_ioctl(vm, KVM_SET_GSI_ROUTING, routing);
+ ksft_test_result(ret == -1 && errno == EINVAL, "ind offset outside of page\n");
+
+ routing->entries[0].u.adapter.ind_offset -= 4;
+ ret = __vm_ioctl(vm, KVM_SET_GSI_ROUTING, routing);
+ ksft_test_result(ret == 0, "ind offset inside of page\n");
+
+ kvm_vm_free(vm);
+}
+
+int main(int argc, char *argv[])
+{
+ TEST_REQUIRE(kvm_has_cap(KVM_CAP_IRQ_ROUTING));
+
+ ksft_print_header();
+ ksft_set_plan(4);
+ test();
+
+ ksft_finished(); /* Print results and exit() accordingly */
+}
diff --git a/tools/testing/selftests/landlock/tsync_test.c b/tools/testing/selftests/landlock/tsync_test.c
index 37ef0d2270db..2b9ad4f154f4 100644
--- a/tools/testing/selftests/landlock/tsync_test.c
+++ b/tools/testing/selftests/landlock/tsync_test.c
@@ -6,9 +6,10 @@
*/
#define _GNU_SOURCE
+#include <linux/landlock.h>
#include <pthread.h>
+#include <signal.h>
#include <sys/prctl.h>
-#include <linux/landlock.h>
#include "common.h"
@@ -158,4 +159,92 @@ TEST(competing_enablement)
EXPECT_EQ(0, close(ruleset_fd));
}
+static void signal_nop_handler(int sig)
+{
+}
+
+struct signaler_data {
+ pthread_t target;
+ volatile bool stop;
+};
+
+static void *signaler_thread(void *data)
+{
+ struct signaler_data *sd = data;
+
+ while (!sd->stop)
+ pthread_kill(sd->target, SIGUSR1);
+
+ return NULL;
+}
+
+/*
+ * Number of idle sibling threads. This must be large enough that even on
+ * machines with many cores, the sibling threads cannot all complete their
+ * credential preparation in a single parallel wave, otherwise the signaler
+ * thread has no window to interrupt wait_for_completion_interruptible().
+ * 200 threads on a 64-core machine yields ~3 serialized waves, giving the
+ * tight signal loop enough time to land an interruption.
+ */
+#define NUM_IDLE_THREADS 200
+
+/*
+ * Exercises the tsync interruption and cancellation paths in tsync.c.
+ *
+ * When a signal interrupts the calling thread while it waits for sibling
+ * threads to finish their credential preparation
+ * (wait_for_completion_interruptible in landlock_restrict_sibling_threads),
+ * the kernel sets ERESTARTNOINTR, cancels queued task works that have not
+ * started yet (cancel_tsync_works), then waits for the remaining works to
+ * finish. On the error return, syscalls.c aborts the prepared credentials.
+ * The kernel automatically restarts the syscall, so userspace sees success.
+ */
+TEST(tsync_interrupt)
+{
+ size_t i;
+ pthread_t threads[NUM_IDLE_THREADS];
+ pthread_t signaler;
+ struct signaler_data sd;
+ struct sigaction sa = {};
+ const int ruleset_fd = create_ruleset(_metadata);
+
+ disable_caps(_metadata);
+
+ /* Install a no-op SIGUSR1 handler so the signal does not kill us. */
+ sa.sa_handler = signal_nop_handler;
+ sigemptyset(&sa.sa_mask);
+ ASSERT_EQ(0, sigaction(SIGUSR1, &sa, NULL));
+
+ ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
+
+ for (i = 0; i < NUM_IDLE_THREADS; i++)
+ ASSERT_EQ(0, pthread_create(&threads[i], NULL, idle, NULL));
+
+ /*
+ * Start a signaler thread that continuously sends SIGUSR1 to the
+ * calling thread. This maximizes the chance of interrupting
+ * wait_for_completion_interruptible() in the kernel's tsync path.
+ */
+ sd.target = pthread_self();
+ sd.stop = false;
+ ASSERT_EQ(0, pthread_create(&signaler, NULL, signaler_thread, &sd));
+
+ /*
+ * The syscall may be interrupted and transparently restarted by the
+ * kernel (ERESTARTNOINTR). From userspace, it should always succeed.
+ */
+ EXPECT_EQ(0, landlock_restrict_self(ruleset_fd,
+ LANDLOCK_RESTRICT_SELF_TSYNC));
+
+ sd.stop = true;
+ ASSERT_EQ(0, pthread_join(signaler, NULL));
+
+ for (i = 0; i < NUM_IDLE_THREADS; i++) {
+ ASSERT_EQ(0, pthread_cancel(threads[i]));
+ ASSERT_EQ(0, pthread_join(threads[i], NULL));
+ }
+
+ EXPECT_EQ(0, close(ruleset_fd));
+}
+
TEST_HARNESS_MAIN
diff --git a/tools/testing/selftests/net/fib_tests.sh b/tools/testing/selftests/net/fib_tests.sh
index c5694cc4ddd2..829f72c8ee07 100755
--- a/tools/testing/selftests/net/fib_tests.sh
+++ b/tools/testing/selftests/net/fib_tests.sh
@@ -868,6 +868,64 @@ fib6_gc_test()
check_rt_num 5 $($IP -6 route list |grep -v expires|grep 2001:20::|wc -l)
log_test $ret 0 "ipv6 route garbage collection (replace with permanent)"
+ # Delete dummy_10 and remove all routes
+ $IP link del dev dummy_10
+
+ # rd6 is required for the next test. (ipv6toolkit)
+ if [ ! -x "$(command -v rd6)" ]; then
+ echo "SKIP: rd6 not found."
+ set +e
+ cleanup &> /dev/null
+ return
+ fi
+
+ setup_ns ns2
+ $IP link add veth1 type veth peer veth2 netns $ns2
+ $IP link set veth1 up
+ ip -netns $ns2 link set veth2 up
+ $IP addr add fe80:dead::1/64 dev veth1
+ ip -netns $ns2 addr add fe80:dead::2/64 dev veth2
+
+ # Add NTF_ROUTER neighbour to prevent rt6_age_examine_exception()
+ # from removing not-yet-expired exceptions.
+ ip -netns $ns2 link set veth2 address 00:11:22:33:44:55
+ $IP neigh add fe80:dead::3 lladdr 00:11:22:33:44:55 dev veth1 router
+
+ $NS_EXEC sysctl -wq net.ipv6.conf.veth1.accept_redirects=1
+ $NS_EXEC sysctl -wq net.ipv6.conf.veth1.forwarding=0
+
+ # Temporary routes
+ for i in $(seq 1 5); do
+ # Expire route after $EXPIRE seconds
+ $IP -6 route add 2001:10::$i \
+ via fe80:dead::2 dev veth1 expires $EXPIRE
+
+ ip netns exec $ns2 rd6 -i veth2 \
+ -s fe80:dead::2 -d fe80:dead::1 \
+ -r 2001:10::$i -t fe80:dead::3 -p ICMP6
+ done
+
+ check_rt_num 5 $($IP -6 route list | grep expires | grep 2001:10:: | wc -l)
+
+ # Promote to permanent routes by "prepend" (w/o NLM_F_EXCL and NLM_F_REPLACE)
+ for i in $(seq 1 5); do
+ # -EEXIST, but the temporary route becomes the permanent route.
+ $IP -6 route append 2001:10::$i \
+ via fe80:dead::2 dev veth1 2>/dev/null || true
+ done
+
+ check_rt_num 5 $($IP -6 route list | grep -v expires | grep 2001:10:: | wc -l)
+ check_rt_num 5 $($IP -6 route list cache | grep 2001:10:: | wc -l)
+
+ # Trigger GC instead of waiting $GC_WAIT_TIME.
+ # rt6_nh_dump_exceptions() just skips expired exceptions.
+ $NS_EXEC sysctl -wq net.ipv6.route.flush=1
+ check_rt_num 0 $($IP -6 route list cache | grep 2001:10:: | wc -l)
+ log_test $ret 0 "ipv6 route garbage collection (promote to permanent routes)"
+
+ $IP neigh del fe80:dead::3 lladdr 00:11:22:33:44:55 dev veth1 router
+ $IP link del veth1
+
# ra6 is required for the next test. (ipv6toolkit)
if [ ! -x "$(command -v ra6)" ]; then
echo "SKIP: ra6 not found."
@@ -876,9 +934,6 @@ fib6_gc_test()
return
fi
- # Delete dummy_10 and remove all routes
- $IP link del dev dummy_10
-
# Create a pair of veth devices to send a RA message from one
# device to another.
$IP link add veth1 type veth peer name veth2
diff --git a/tools/testing/selftests/net/netfilter/nft_concat_range.sh b/tools/testing/selftests/net/netfilter/nft_concat_range.sh
index 394166f224a4..ffdc6ccc6511 100755
--- a/tools/testing/selftests/net/netfilter/nft_concat_range.sh
+++ b/tools/testing/selftests/net/netfilter/nft_concat_range.sh
@@ -29,7 +29,8 @@ TYPES="net_port port_net net6_port port_proto net6_port_mac net6_port_mac_proto
net6_port_net6_port net_port_mac_proto_net"
# Reported bugs, also described by TYPE_ variables below
-BUGS="flush_remove_add reload net_port_proto_match avx2_mismatch doublecreate insert_overlap"
+BUGS="flush_remove_add reload net_port_proto_match avx2_mismatch doublecreate
+ insert_overlap load_flush_load4 load_flush_load8"
# List of possible paths to pktgen script from kernel tree for performance tests
PKTGEN_SCRIPT_PATHS="
@@ -432,6 +433,30 @@ race_repeat 0
perf_duration 0
"
+TYPE_load_flush_load4="
+display reload with flush, 4bit groups
+type_spec ipv4_addr . ipv4_addr
+chain_spec ip saddr . ip daddr
+dst addr4
+proto icmp
+
+race_repeat 0
+
+perf_duration 0
+"
+
+TYPE_load_flush_load8="
+display reload with flush, 8bit groups
+type_spec ipv4_addr . ipv4_addr
+chain_spec ip saddr . ip daddr
+dst addr4
+proto icmp
+
+race_repeat 0
+
+perf_duration 0
+"
+
# Set template for all tests, types and rules are filled in depending on test
set_template='
flush ruleset
@@ -1997,6 +2022,49 @@ test_bug_insert_overlap()
return 0
}
+test_bug_load_flush_load4()
+{
+ local i
+
+ setup veth send_"${proto}" set || return ${ksft_skip}
+
+ for i in $(seq 0 255); do
+ local addelem="add element inet filter test"
+ local j
+
+ for j in $(seq 0 20); do
+ echo "$addelem { 10.$j.0.$i . 10.$j.1.$i }"
+ echo "$addelem { 10.$j.0.$i . 10.$j.2.$i }"
+ done
+ done > "$tmp"
+
+ nft -f "$tmp" || return 1
+
+ ( echo "flush set inet filter test";cat "$tmp") | nft -f -
+ [ $? -eq 0 ] || return 1
+
+ return 0
+}
+
+test_bug_load_flush_load8()
+{
+ local i
+
+ setup veth send_"${proto}" set || return ${ksft_skip}
+
+ for i in $(seq 1 100); do
+ echo "add element inet filter test { 10.0.0.$i . 10.0.1.$i }"
+ echo "add element inet filter test { 10.0.0.$i . 10.0.2.$i }"
+ done > "$tmp"
+
+ nft -f "$tmp" || return 1
+
+ ( echo "flush set inet filter test";cat "$tmp") | nft -f -
+ [ $? -eq 0 ] || return 1
+
+ return 0
+}
+
test_reported_issues() {
eval test_bug_"${subtest}"
}