aboutsummaryrefslogtreecommitdiff
path: root/tools/testing
diff options
context:
space:
mode:
Diffstat (limited to 'tools/testing')
-rw-r--r--tools/testing/nvdimm/test/ndtest.c2
-rw-r--r--tools/testing/selftests/Makefile1
-rw-r--r--tools/testing/selftests/arm64/fp/za-fork.c2
-rw-r--r--tools/testing/selftests/bpf/Makefile14
-rw-r--r--tools/testing/selftests/bpf/README.rst2
-rw-r--r--tools/testing/selftests/bpf/network_helpers.h43
-rw-r--r--tools/testing/selftests/bpf/prog_tests/fill_link_info.c242
-rw-r--r--tools/testing/selftests/bpf/prog_tests/sockmap_listen.c51
-rw-r--r--tools/testing/selftests/bpf/prog_tests/tailcalls.c84
-rw-r--r--tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c2
-rw-r--r--tools/testing/selftests/bpf/prog_tests/verifier.c2
-rw-r--r--tools/testing/selftests/bpf/prog_tests/xdp_metadata.c33
-rw-r--r--tools/testing/selftests/bpf/progs/tailcall_poke.c32
-rw-r--r--tools/testing/selftests/bpf/progs/test_fill_link_info.c6
-rw-r--r--tools/testing/selftests/bpf/progs/test_global_func12.c4
-rw-r--r--tools/testing/selftests/bpf/progs/test_global_func17.c1
-rw-r--r--tools/testing/selftests/bpf/progs/test_sockmap_listen.c7
-rw-r--r--tools/testing/selftests/bpf/progs/verifier_global_subprogs.c92
-rw-r--r--tools/testing/selftests/bpf/progs/verifier_subprog_precision.c4
-rwxr-xr-xtools/testing/selftests/bpf/test_offload.py15
-rw-r--r--tools/testing/selftests/bpf/xdp_hw_metadata.c235
-rw-r--r--tools/testing/selftests/bpf/xsk.c3
-rw-r--r--tools/testing/selftests/bpf/xsk.h1
-rw-r--r--tools/testing/selftests/iommu/iommufd_utils.h13
-rw-r--r--tools/testing/selftests/kvm/Makefile7
-rw-r--r--tools/testing/selftests/kvm/x86_64/nx_huge_pages_test.c2
-rw-r--r--tools/testing/selftests/mm/Makefile4
-rw-r--r--tools/testing/selftests/mm/pagemap_ioctl.c9
-rw-r--r--tools/testing/selftests/net/Makefile2
-rw-r--r--tools/testing/selftests/net/af_unix/diag_uid.c1
-rwxr-xr-xtools/testing/selftests/net/arp_ndisc_evict_nocarrier.sh46
-rwxr-xr-xtools/testing/selftests/net/arp_ndisc_untracked_subnets.sh20
-rwxr-xr-xtools/testing/selftests/net/cmsg_ipv6.sh10
-rw-r--r--tools/testing/selftests/net/cmsg_sender.c2
-rwxr-xr-xtools/testing/selftests/net/cmsg_so_mark.sh7
-rwxr-xr-xtools/testing/selftests/net/cmsg_time.sh7
-rwxr-xr-xtools/testing/selftests/net/drop_monitor_tests.sh21
-rwxr-xr-xtools/testing/selftests/net/fcnal-test.sh30
-rwxr-xr-xtools/testing/selftests/net/fdb_flush.sh11
-rwxr-xr-xtools/testing/selftests/net/fib-onlink-tests.sh9
-rwxr-xr-xtools/testing/selftests/net/fib_nexthop_multiprefix.sh98
-rwxr-xr-xtools/testing/selftests/net/fib_nexthop_nongw.sh34
-rwxr-xr-xtools/testing/selftests/net/fib_nexthops.sh142
-rwxr-xr-xtools/testing/selftests/net/fib_rule_tests.sh36
-rwxr-xr-xtools/testing/selftests/net/fib_tests.sh184
-rw-r--r--tools/testing/selftests/net/forwarding/Makefile1
-rwxr-xr-xtools/testing/selftests/net/forwarding/ethtool_rmon.sh143
-rwxr-xr-xtools/testing/selftests/net/forwarding/lib.sh36
-rwxr-xr-xtools/testing/selftests/net/icmp.sh10
-rwxr-xr-xtools/testing/selftests/net/icmp_redirect.sh182
-rwxr-xr-xtools/testing/selftests/net/io_uring_zerocopy_tx.sh9
-rwxr-xr-xtools/testing/selftests/net/ioam6.sh247
-rw-r--r--tools/testing/selftests/net/ipsec.c4
-rwxr-xr-xtools/testing/selftests/net/l2tp.sh130
-rw-r--r--tools/testing/selftests/net/lib.sh93
-rw-r--r--tools/testing/selftests/net/mptcp/mptcp_connect.c11
-rw-r--r--tools/testing/selftests/net/mptcp/mptcp_inq.c11
-rwxr-xr-xtools/testing/selftests/net/msg_zerocopy.sh9
-rwxr-xr-xtools/testing/selftests/net/ndisc_unsolicited_na_test.sh19
-rwxr-xr-xtools/testing/selftests/net/sctp_vrf.sh12
-rw-r--r--tools/testing/selftests/net/settings2
-rwxr-xr-xtools/testing/selftests/net/srv6_end_dt46_l3vpn_test.sh51
-rwxr-xr-xtools/testing/selftests/net/srv6_end_dt4_l3vpn_test.sh48
-rwxr-xr-xtools/testing/selftests/net/srv6_end_dt6_l3vpn_test.sh46
-rw-r--r--tools/testing/selftests/net/tcp_ao/.gitignore2
-rw-r--r--tools/testing/selftests/net/tcp_ao/Makefile59
-rw-r--r--tools/testing/selftests/net/tcp_ao/bench-lookups.c358
-rw-r--r--tools/testing/selftests/net/tcp_ao/connect-deny.c264
-rw-r--r--tools/testing/selftests/net/tcp_ao/connect.c90
l---------tools/testing/selftests/net/tcp_ao/icmps-accept.c1
-rw-r--r--tools/testing/selftests/net/tcp_ao/icmps-discard.c449
-rw-r--r--tools/testing/selftests/net/tcp_ao/key-management.c1180
-rw-r--r--tools/testing/selftests/net/tcp_ao/lib/aolib.h605
-rw-r--r--tools/testing/selftests/net/tcp_ao/lib/kconfig.c148
-rw-r--r--tools/testing/selftests/net/tcp_ao/lib/netlink.c415
-rw-r--r--tools/testing/selftests/net/tcp_ao/lib/proc.c273
-rw-r--r--tools/testing/selftests/net/tcp_ao/lib/repair.c254
-rw-r--r--tools/testing/selftests/net/tcp_ao/lib/setup.c342
-rw-r--r--tools/testing/selftests/net/tcp_ao/lib/sock.c592
-rw-r--r--tools/testing/selftests/net/tcp_ao/lib/utils.c30
-rw-r--r--tools/testing/selftests/net/tcp_ao/restore.c236
-rw-r--r--tools/testing/selftests/net/tcp_ao/rst.c415
-rw-r--r--tools/testing/selftests/net/tcp_ao/self-connect.c197
-rw-r--r--tools/testing/selftests/net/tcp_ao/seq-ext.c245
-rw-r--r--tools/testing/selftests/net/tcp_ao/setsockopt-closed.c835
-rw-r--r--tools/testing/selftests/net/tcp_ao/unsigned-md5.c742
-rwxr-xr-xtools/testing/selftests/net/test_bridge_backup_port.sh371
-rwxr-xr-xtools/testing/selftests/net/test_bridge_neigh_suppress.sh331
-rwxr-xr-xtools/testing/selftests/net/test_vxlan_mdb.sh202
-rwxr-xr-xtools/testing/selftests/net/test_vxlan_nolocalbypass.sh48
-rwxr-xr-xtools/testing/selftests/net/test_vxlan_under_vrf.sh70
-rwxr-xr-xtools/testing/selftests/net/test_vxlan_vnifiltering.sh154
-rwxr-xr-xtools/testing/selftests/net/traceroute.sh82
-rwxr-xr-xtools/testing/selftests/net/unicast_extensions.sh99
-rwxr-xr-xtools/testing/selftests/net/vrf-xfrm-tests.sh77
-rwxr-xr-xtools/testing/selftests/net/vrf_route_leaking.sh201
-rwxr-xr-xtools/testing/selftests/net/vrf_strict_mode_test.sh47
-rw-r--r--tools/testing/selftests/tc-testing/Makefile2
-rw-r--r--tools/testing/selftests/tc-testing/tc-tests/filters/flower.json (renamed from tools/testing/selftests/tc-testing/tc-tests/filters/concurrency.json)98
-rw-r--r--tools/testing/selftests/tc-testing/tc-tests/filters/matchall.json23
-rw-r--r--tools/testing/selftests/tc-testing/tc-tests/filters/tests.json129
-rw-r--r--tools/testing/vsock/vsock_test.c175
102 files changed, 10596 insertions, 1882 deletions
diff --git a/tools/testing/nvdimm/test/ndtest.c b/tools/testing/nvdimm/test/ndtest.c
index fd26189d53be..b8419f460368 100644
--- a/tools/testing/nvdimm/test/ndtest.c
+++ b/tools/testing/nvdimm/test/ndtest.c
@@ -924,7 +924,7 @@ static __init int ndtest_init(void)
nfit_test_setup(ndtest_resource_lookup, NULL);
- rc = class_regster(&ndtest_dimm_class);
+ rc = class_register(&ndtest_dimm_class);
if (rc)
goto err_register;
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index 3b2061d1c1a5..f0c854d6511c 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -58,6 +58,7 @@ TARGETS += net/forwarding
TARGETS += net/hsr
TARGETS += net/mptcp
TARGETS += net/openvswitch
+TARGETS += net/tcp_ao
TARGETS += netfilter
TARGETS += nsfs
TARGETS += perf_events
diff --git a/tools/testing/selftests/arm64/fp/za-fork.c b/tools/testing/selftests/arm64/fp/za-fork.c
index b86cb1049497..587b94648222 100644
--- a/tools/testing/selftests/arm64/fp/za-fork.c
+++ b/tools/testing/selftests/arm64/fp/za-fork.c
@@ -85,7 +85,7 @@ int main(int argc, char **argv)
*/
ret = open("/proc/sys/abi/sme_default_vector_length", O_RDONLY, 0);
if (ret >= 0) {
- ksft_test_result(fork_test(), "fork_test");
+ ksft_test_result(fork_test(), "fork_test\n");
} else {
ksft_print_msg("SME not supported\n");
diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index 9c27b67bc7b1..617ae55c3bb5 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -18,7 +18,7 @@ else
GENDIR := $(abspath ../../../../include/generated)
endif
GENHDR := $(GENDIR)/autoconf.h
-HOSTPKG_CONFIG := pkg-config
+PKG_CONFIG ?= $(CROSS_COMPILE)pkg-config
ifneq ($(wildcard $(GENHDR)),)
GENFLAGS := -DHAVE_GENHDR
@@ -29,13 +29,17 @@ SAN_CFLAGS ?=
SAN_LDFLAGS ?= $(SAN_CFLAGS)
RELEASE ?=
OPT_FLAGS ?= $(if $(RELEASE),-O2,-O0)
+
+LIBELF_CFLAGS := $(shell $(PKG_CONFIG) libelf --cflags 2>/dev/null)
+LIBELF_LIBS := $(shell $(PKG_CONFIG) libelf --libs 2>/dev/null || echo -lelf)
+
CFLAGS += -g $(OPT_FLAGS) -rdynamic \
-Wall -Werror \
- $(GENFLAGS) $(SAN_CFLAGS) \
+ $(GENFLAGS) $(SAN_CFLAGS) $(LIBELF_CFLAGS) \
-I$(CURDIR) -I$(INCLUDE_DIR) -I$(GENDIR) -I$(LIBDIR) \
-I$(TOOLSINCDIR) -I$(APIDIR) -I$(OUTPUT)
LDFLAGS += $(SAN_LDFLAGS)
-LDLIBS += -lelf -lz -lrt -lpthread
+LDLIBS += $(LIBELF_LIBS) -lz -lrt -lpthread
ifneq ($(LLVM),)
# Silence some warnings when compiled with clang
@@ -219,9 +223,9 @@ $(OUTPUT)/urandom_read: urandom_read.c urandom_read_aux.c $(OUTPUT)/liburandom_r
$(OUTPUT)/sign-file: ../../../../scripts/sign-file.c
$(call msg,SIGN-FILE,,$@)
- $(Q)$(CC) $(shell $(HOSTPKG_CONFIG) --cflags libcrypto 2> /dev/null) \
+ $(Q)$(CC) $(shell $(PKG_CONFIG) --cflags libcrypto 2> /dev/null) \
$< -o $@ \
- $(shell $(HOSTPKG_CONFIG) --libs libcrypto 2> /dev/null || echo -lcrypto)
+ $(shell $(PKG_CONFIG) --libs libcrypto 2> /dev/null || echo -lcrypto)
$(OUTPUT)/bpf_testmod.ko: $(VMLINUX_BTF) $(RESOLVE_BTFIDS) $(wildcard bpf_testmod/Makefile bpf_testmod/*.[ch])
$(call msg,MOD,,$@)
diff --git a/tools/testing/selftests/bpf/README.rst b/tools/testing/selftests/bpf/README.rst
index cb9b95702ac6..9af79c7a9b58 100644
--- a/tools/testing/selftests/bpf/README.rst
+++ b/tools/testing/selftests/bpf/README.rst
@@ -77,7 +77,7 @@ In case of linker errors when running selftests, try using static linking:
.. code-block:: console
- $ LDLIBS=-static vmtest.sh
+ $ LDLIBS=-static PKG_CONFIG='pkg-config --static' vmtest.sh
.. note:: Some distros may not support static linking.
diff --git a/tools/testing/selftests/bpf/network_helpers.h b/tools/testing/selftests/bpf/network_helpers.h
index 34f1200a781b..94b9be24e39b 100644
--- a/tools/testing/selftests/bpf/network_helpers.h
+++ b/tools/testing/selftests/bpf/network_helpers.h
@@ -71,4 +71,47 @@ struct nstoken;
*/
struct nstoken *open_netns(const char *name);
void close_netns(struct nstoken *token);
+
+static __u16 csum_fold(__u32 csum)
+{
+ csum = (csum & 0xffff) + (csum >> 16);
+ csum = (csum & 0xffff) + (csum >> 16);
+
+ return (__u16)~csum;
+}
+
+static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr,
+ __u32 len, __u8 proto,
+ __wsum csum)
+{
+ __u64 s = csum;
+
+ s += (__u32)saddr;
+ s += (__u32)daddr;
+ s += htons(proto + len);
+ s = (s & 0xffffffff) + (s >> 32);
+ s = (s & 0xffffffff) + (s >> 32);
+
+ return csum_fold((__u32)s);
+}
+
+static inline __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
+ const struct in6_addr *daddr,
+ __u32 len, __u8 proto,
+ __wsum csum)
+{
+ __u64 s = csum;
+ int i;
+
+ for (i = 0; i < 4; i++)
+ s += (__u32)saddr->s6_addr32[i];
+ for (i = 0; i < 4; i++)
+ s += (__u32)daddr->s6_addr32[i];
+ s += htons(proto + len);
+ s = (s & 0xffffffff) + (s >> 32);
+ s = (s & 0xffffffff) + (s >> 32);
+
+ return csum_fold((__u32)s);
+}
+
#endif
diff --git a/tools/testing/selftests/bpf/prog_tests/fill_link_info.c b/tools/testing/selftests/bpf/prog_tests/fill_link_info.c
index 97142a4db374..d4b1901f7879 100644
--- a/tools/testing/selftests/bpf/prog_tests/fill_link_info.c
+++ b/tools/testing/selftests/bpf/prog_tests/fill_link_info.c
@@ -7,6 +7,7 @@
#include <test_progs.h>
#include "trace_helpers.h"
#include "test_fill_link_info.skel.h"
+#include "bpf/libbpf_internal.h"
#define TP_CAT "sched"
#define TP_NAME "sched_switch"
@@ -140,14 +141,14 @@ static void test_kprobe_fill_link_info(struct test_fill_link_info *skel,
.retprobe = type == BPF_PERF_EVENT_KRETPROBE,
);
ssize_t entry_offset = 0;
+ struct bpf_link *link;
int link_fd, err;
- skel->links.kprobe_run = bpf_program__attach_kprobe_opts(skel->progs.kprobe_run,
- KPROBE_FUNC, &opts);
- if (!ASSERT_OK_PTR(skel->links.kprobe_run, "attach_kprobe"))
+ link = bpf_program__attach_kprobe_opts(skel->progs.kprobe_run, KPROBE_FUNC, &opts);
+ if (!ASSERT_OK_PTR(link, "attach_kprobe"))
return;
- link_fd = bpf_link__fd(skel->links.kprobe_run);
+ link_fd = bpf_link__fd(link);
if (!invalid) {
/* See also arch_adjust_kprobe_addr(). */
if (skel->kconfig->CONFIG_X86_KERNEL_IBT)
@@ -157,39 +158,41 @@ static void test_kprobe_fill_link_info(struct test_fill_link_info *skel,
} else {
kprobe_fill_invalid_user_buffer(link_fd);
}
- bpf_link__detach(skel->links.kprobe_run);
+ bpf_link__destroy(link);
}
static void test_tp_fill_link_info(struct test_fill_link_info *skel)
{
+ struct bpf_link *link;
int link_fd, err;
- skel->links.tp_run = bpf_program__attach_tracepoint(skel->progs.tp_run, TP_CAT, TP_NAME);
- if (!ASSERT_OK_PTR(skel->links.tp_run, "attach_tp"))
+ link = bpf_program__attach_tracepoint(skel->progs.tp_run, TP_CAT, TP_NAME);
+ if (!ASSERT_OK_PTR(link, "attach_tp"))
return;
- link_fd = bpf_link__fd(skel->links.tp_run);
+ link_fd = bpf_link__fd(link);
err = verify_perf_link_info(link_fd, BPF_PERF_EVENT_TRACEPOINT, 0, 0, 0);
ASSERT_OK(err, "verify_perf_link_info");
- bpf_link__detach(skel->links.tp_run);
+ bpf_link__destroy(link);
}
static void test_uprobe_fill_link_info(struct test_fill_link_info *skel,
enum bpf_perf_event_type type)
{
+ struct bpf_link *link;
int link_fd, err;
- skel->links.uprobe_run = bpf_program__attach_uprobe(skel->progs.uprobe_run,
- type == BPF_PERF_EVENT_URETPROBE,
- 0, /* self pid */
- UPROBE_FILE, uprobe_offset);
- if (!ASSERT_OK_PTR(skel->links.uprobe_run, "attach_uprobe"))
+ link = bpf_program__attach_uprobe(skel->progs.uprobe_run,
+ type == BPF_PERF_EVENT_URETPROBE,
+ 0, /* self pid */
+ UPROBE_FILE, uprobe_offset);
+ if (!ASSERT_OK_PTR(link, "attach_uprobe"))
return;
- link_fd = bpf_link__fd(skel->links.uprobe_run);
+ link_fd = bpf_link__fd(link);
err = verify_perf_link_info(link_fd, type, 0, uprobe_offset, 0);
ASSERT_OK(err, "verify_perf_link_info");
- bpf_link__detach(skel->links.uprobe_run);
+ bpf_link__destroy(link);
}
static int verify_kmulti_link_info(int fd, bool retprobe)
@@ -278,24 +281,214 @@ static void test_kprobe_multi_fill_link_info(struct test_fill_link_info *skel,
bool retprobe, bool invalid)
{
LIBBPF_OPTS(bpf_kprobe_multi_opts, opts);
+ struct bpf_link *link;
int link_fd, err;
opts.syms = kmulti_syms;
opts.cnt = KMULTI_CNT;
opts.retprobe = retprobe;
- skel->links.kmulti_run = bpf_program__attach_kprobe_multi_opts(skel->progs.kmulti_run,
- NULL, &opts);
- if (!ASSERT_OK_PTR(skel->links.kmulti_run, "attach_kprobe_multi"))
+ link = bpf_program__attach_kprobe_multi_opts(skel->progs.kmulti_run, NULL, &opts);
+ if (!ASSERT_OK_PTR(link, "attach_kprobe_multi"))
return;
- link_fd = bpf_link__fd(skel->links.kmulti_run);
+ link_fd = bpf_link__fd(link);
if (!invalid) {
err = verify_kmulti_link_info(link_fd, retprobe);
ASSERT_OK(err, "verify_kmulti_link_info");
} else {
verify_kmulti_invalid_user_buffer(link_fd);
}
- bpf_link__detach(skel->links.kmulti_run);
+ bpf_link__destroy(link);
+}
+
+#define SEC(name) __attribute__((section(name), used))
+
+static short uprobe_link_info_sema_1 SEC(".probes");
+static short uprobe_link_info_sema_2 SEC(".probes");
+static short uprobe_link_info_sema_3 SEC(".probes");
+
+noinline void uprobe_link_info_func_1(void)
+{
+ asm volatile ("");
+ uprobe_link_info_sema_1++;
+}
+
+noinline void uprobe_link_info_func_2(void)
+{
+ asm volatile ("");
+ uprobe_link_info_sema_2++;
+}
+
+noinline void uprobe_link_info_func_3(void)
+{
+ asm volatile ("");
+ uprobe_link_info_sema_3++;
+}
+
+static int
+verify_umulti_link_info(int fd, bool retprobe, __u64 *offsets,
+ __u64 *cookies, __u64 *ref_ctr_offsets)
+{
+ char path[PATH_MAX], path_buf[PATH_MAX];
+ struct bpf_link_info info;
+ __u32 len = sizeof(info);
+ __u64 ref_ctr_offsets_buf[3];
+ __u64 offsets_buf[3];
+ __u64 cookies_buf[3];
+ int i, err, bit;
+ __u32 count = 0;
+
+ memset(path, 0, sizeof(path));
+ err = readlink("/proc/self/exe", path, sizeof(path));
+ if (!ASSERT_NEQ(err, -1, "readlink"))
+ return -1;
+
+ for (bit = 0; bit < 8; bit++) {
+ memset(&info, 0, sizeof(info));
+ info.uprobe_multi.path = ptr_to_u64(path_buf);
+ info.uprobe_multi.path_size = sizeof(path_buf);
+ info.uprobe_multi.count = count;
+
+ if (bit & 0x1)
+ info.uprobe_multi.offsets = ptr_to_u64(offsets_buf);
+ if (bit & 0x2)
+ info.uprobe_multi.cookies = ptr_to_u64(cookies_buf);
+ if (bit & 0x4)
+ info.uprobe_multi.ref_ctr_offsets = ptr_to_u64(ref_ctr_offsets_buf);
+
+ err = bpf_link_get_info_by_fd(fd, &info, &len);
+ if (!ASSERT_OK(err, "bpf_link_get_info_by_fd"))
+ return -1;
+
+ if (!ASSERT_EQ(info.type, BPF_LINK_TYPE_UPROBE_MULTI, "info.type"))
+ return -1;
+
+ ASSERT_EQ(info.uprobe_multi.pid, getpid(), "info.uprobe_multi.pid");
+ ASSERT_EQ(info.uprobe_multi.count, 3, "info.uprobe_multi.count");
+ ASSERT_EQ(info.uprobe_multi.flags & BPF_F_KPROBE_MULTI_RETURN,
+ retprobe, "info.uprobe_multi.flags.retprobe");
+ ASSERT_EQ(info.uprobe_multi.path_size, strlen(path) + 1, "info.uprobe_multi.path_size");
+ ASSERT_STREQ(path_buf, path, "info.uprobe_multi.path");
+
+ for (i = 0; i < info.uprobe_multi.count; i++) {
+ if (info.uprobe_multi.offsets)
+ ASSERT_EQ(offsets_buf[i], offsets[i], "info.uprobe_multi.offsets");
+ if (info.uprobe_multi.cookies)
+ ASSERT_EQ(cookies_buf[i], cookies[i], "info.uprobe_multi.cookies");
+ if (info.uprobe_multi.ref_ctr_offsets) {
+ ASSERT_EQ(ref_ctr_offsets_buf[i], ref_ctr_offsets[i],
+ "info.uprobe_multi.ref_ctr_offsets");
+ }
+ }
+ count = count ?: info.uprobe_multi.count;
+ }
+
+ return 0;
+}
+
+static void verify_umulti_invalid_user_buffer(int fd)
+{
+ struct bpf_link_info info;
+ __u32 len = sizeof(info);
+ __u64 buf[3];
+ int err;
+
+ /* upath_size defined, not path */
+ memset(&info, 0, sizeof(info));
+ info.uprobe_multi.path_size = 3;
+ err = bpf_link_get_info_by_fd(fd, &info, &len);
+ ASSERT_EQ(err, -EINVAL, "failed_upath_size");
+
+ /* path defined, but small */
+ memset(&info, 0, sizeof(info));
+ info.uprobe_multi.path = ptr_to_u64(buf);
+ info.uprobe_multi.path_size = 3;
+ err = bpf_link_get_info_by_fd(fd, &info, &len);
+ ASSERT_LT(err, 0, "failed_upath_small");
+
+ /* path has wrong pointer */
+ memset(&info, 0, sizeof(info));
+ info.uprobe_multi.path_size = PATH_MAX;
+ info.uprobe_multi.path = 123;
+ err = bpf_link_get_info_by_fd(fd, &info, &len);
+ ASSERT_EQ(err, -EFAULT, "failed_bad_path_ptr");
+
+ /* count zero, with offsets */
+ memset(&info, 0, sizeof(info));
+ info.uprobe_multi.offsets = ptr_to_u64(buf);
+ err = bpf_link_get_info_by_fd(fd, &info, &len);
+ ASSERT_EQ(err, -EINVAL, "failed_count");
+
+ /* offsets not big enough */
+ memset(&info, 0, sizeof(info));
+ info.uprobe_multi.offsets = ptr_to_u64(buf);
+ info.uprobe_multi.count = 2;
+ err = bpf_link_get_info_by_fd(fd, &info, &len);
+ ASSERT_EQ(err, -ENOSPC, "failed_small_count");
+
+ /* offsets has wrong pointer */
+ memset(&info, 0, sizeof(info));
+ info.uprobe_multi.offsets = 123;
+ info.uprobe_multi.count = 3;
+ err = bpf_link_get_info_by_fd(fd, &info, &len);
+ ASSERT_EQ(err, -EFAULT, "failed_wrong_offsets");
+}
+
+static void test_uprobe_multi_fill_link_info(struct test_fill_link_info *skel,
+ bool retprobe, bool invalid)
+{
+ LIBBPF_OPTS(bpf_uprobe_multi_opts, opts,
+ .retprobe = retprobe,
+ );
+ const char *syms[3] = {
+ "uprobe_link_info_func_1",
+ "uprobe_link_info_func_2",
+ "uprobe_link_info_func_3",
+ };
+ __u64 cookies[3] = {
+ 0xdead,
+ 0xbeef,
+ 0xcafe,
+ };
+ const char *sema[3] = {
+ "uprobe_link_info_sema_1",
+ "uprobe_link_info_sema_2",
+ "uprobe_link_info_sema_3",
+ };
+ __u64 *offsets = NULL, *ref_ctr_offsets;
+ struct bpf_link *link;
+ int link_fd, err;
+
+ err = elf_resolve_syms_offsets("/proc/self/exe", 3, sema,
+ (unsigned long **) &ref_ctr_offsets, STT_OBJECT);
+ if (!ASSERT_OK(err, "elf_resolve_syms_offsets_object"))
+ return;
+
+ err = elf_resolve_syms_offsets("/proc/self/exe", 3, syms,
+ (unsigned long **) &offsets, STT_FUNC);
+ if (!ASSERT_OK(err, "elf_resolve_syms_offsets_func"))
+ goto out;
+
+ opts.syms = syms;
+ opts.cookies = &cookies[0];
+ opts.ref_ctr_offsets = (unsigned long *) &ref_ctr_offsets[0];
+ opts.cnt = ARRAY_SIZE(syms);
+
+ link = bpf_program__attach_uprobe_multi(skel->progs.umulti_run, 0,
+ "/proc/self/exe", NULL, &opts);
+ if (!ASSERT_OK_PTR(link, "bpf_program__attach_uprobe_multi"))
+ goto out;
+
+ link_fd = bpf_link__fd(link);
+ if (invalid)
+ verify_umulti_invalid_user_buffer(link_fd);
+ else
+ verify_umulti_link_info(link_fd, retprobe, offsets, cookies, ref_ctr_offsets);
+
+ bpf_link__destroy(link);
+out:
+ free(ref_ctr_offsets);
+ free(offsets);
}
void test_fill_link_info(void)
@@ -337,6 +530,13 @@ void test_fill_link_info(void)
if (test__start_subtest("kprobe_multi_invalid_ubuff"))
test_kprobe_multi_fill_link_info(skel, true, true);
+ if (test__start_subtest("uprobe_multi_link_info"))
+ test_uprobe_multi_fill_link_info(skel, false, false);
+ if (test__start_subtest("uretprobe_multi_link_info"))
+ test_uprobe_multi_fill_link_info(skel, true, false);
+ if (test__start_subtest("uprobe_multi_invalid"))
+ test_uprobe_multi_fill_link_info(skel, false, true);
+
cleanup:
test_fill_link_info__destroy(skel);
}
diff --git a/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c b/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c
index a934d430c20c..a92807bfcd13 100644
--- a/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c
+++ b/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c
@@ -1337,7 +1337,8 @@ static void test_redir(struct test_sockmap_listen *skel, struct bpf_map *map,
}
static void pairs_redir_to_connected(int cli0, int peer0, int cli1, int peer1,
- int sock_mapfd, int verd_mapfd, enum redir_mode mode)
+ int sock_mapfd, int nop_mapfd,
+ int verd_mapfd, enum redir_mode mode)
{
const char *log_prefix = redir_mode_str(mode);
unsigned int pass;
@@ -1351,6 +1352,12 @@ static void pairs_redir_to_connected(int cli0, int peer0, int cli1, int peer1,
if (err)
return;
+ if (nop_mapfd >= 0) {
+ err = add_to_sockmap(nop_mapfd, cli0, cli1);
+ if (err)
+ return;
+ }
+
n = write(cli1, "a", 1);
if (n < 0)
FAIL_ERRNO("%s: write", log_prefix);
@@ -1387,7 +1394,7 @@ static void unix_redir_to_connected(int sotype, int sock_mapfd,
goto close0;
c1 = sfd[0], p1 = sfd[1];
- pairs_redir_to_connected(c0, p0, c1, p1, sock_mapfd, verd_mapfd, mode);
+ pairs_redir_to_connected(c0, p0, c1, p1, sock_mapfd, -1, verd_mapfd, mode);
xclose(c1);
xclose(p1);
@@ -1677,7 +1684,7 @@ static void udp_redir_to_connected(int family, int sock_mapfd, int verd_mapfd,
if (err)
goto close_cli0;
- pairs_redir_to_connected(c0, p0, c1, p1, sock_mapfd, verd_mapfd, mode);
+ pairs_redir_to_connected(c0, p0, c1, p1, sock_mapfd, -1, verd_mapfd, mode);
xclose(c1);
xclose(p1);
@@ -1735,7 +1742,7 @@ static void inet_unix_redir_to_connected(int family, int type, int sock_mapfd,
if (err)
goto close;
- pairs_redir_to_connected(c0, p0, c1, p1, sock_mapfd, verd_mapfd, mode);
+ pairs_redir_to_connected(c0, p0, c1, p1, sock_mapfd, -1, verd_mapfd, mode);
xclose(c1);
xclose(p1);
@@ -1770,8 +1777,10 @@ static void inet_unix_skb_redir_to_connected(struct test_sockmap_listen *skel,
xbpf_prog_detach2(verdict, sock_map, BPF_SK_SKB_VERDICT);
}
-static void unix_inet_redir_to_connected(int family, int type, int sock_mapfd,
- int verd_mapfd, enum redir_mode mode)
+static void unix_inet_redir_to_connected(int family, int type,
+ int sock_mapfd, int nop_mapfd,
+ int verd_mapfd,
+ enum redir_mode mode)
{
int c0, c1, p0, p1;
int sfd[2];
@@ -1785,7 +1794,8 @@ static void unix_inet_redir_to_connected(int family, int type, int sock_mapfd,
goto close_cli0;
c1 = sfd[0], p1 = sfd[1];
- pairs_redir_to_connected(c0, p0, c1, p1, sock_mapfd, verd_mapfd, mode);
+ pairs_redir_to_connected(c0, p0, c1, p1,
+ sock_mapfd, nop_mapfd, verd_mapfd, mode);
xclose(c1);
xclose(p1);
@@ -1799,6 +1809,7 @@ static void unix_inet_skb_redir_to_connected(struct test_sockmap_listen *skel,
struct bpf_map *inner_map, int family)
{
int verdict = bpf_program__fd(skel->progs.prog_skb_verdict);
+ int nop_map = bpf_map__fd(skel->maps.nop_map);
int verdict_map = bpf_map__fd(skel->maps.verdict_map);
int sock_map = bpf_map__fd(inner_map);
int err;
@@ -1808,14 +1819,32 @@ static void unix_inet_skb_redir_to_connected(struct test_sockmap_listen *skel,
return;
skel->bss->test_ingress = false;
- unix_inet_redir_to_connected(family, SOCK_DGRAM, sock_map, verdict_map,
+ unix_inet_redir_to_connected(family, SOCK_DGRAM,
+ sock_map, -1, verdict_map,
REDIR_EGRESS);
- unix_inet_redir_to_connected(family, SOCK_STREAM, sock_map, verdict_map,
+ unix_inet_redir_to_connected(family, SOCK_DGRAM,
+ sock_map, -1, verdict_map,
+ REDIR_EGRESS);
+
+ unix_inet_redir_to_connected(family, SOCK_DGRAM,
+ sock_map, nop_map, verdict_map,
+ REDIR_EGRESS);
+ unix_inet_redir_to_connected(family, SOCK_STREAM,
+ sock_map, nop_map, verdict_map,
REDIR_EGRESS);
skel->bss->test_ingress = true;
- unix_inet_redir_to_connected(family, SOCK_DGRAM, sock_map, verdict_map,
+ unix_inet_redir_to_connected(family, SOCK_DGRAM,
+ sock_map, -1, verdict_map,
+ REDIR_INGRESS);
+ unix_inet_redir_to_connected(family, SOCK_STREAM,
+ sock_map, -1, verdict_map,
+ REDIR_INGRESS);
+
+ unix_inet_redir_to_connected(family, SOCK_DGRAM,
+ sock_map, nop_map, verdict_map,
REDIR_INGRESS);
- unix_inet_redir_to_connected(family, SOCK_STREAM, sock_map, verdict_map,
+ unix_inet_redir_to_connected(family, SOCK_STREAM,
+ sock_map, nop_map, verdict_map,
REDIR_INGRESS);
xbpf_prog_detach2(verdict, sock_map, BPF_SK_SKB_VERDICT);
diff --git a/tools/testing/selftests/bpf/prog_tests/tailcalls.c b/tools/testing/selftests/bpf/prog_tests/tailcalls.c
index fc6b2954e8f5..59993fc9c0d7 100644
--- a/tools/testing/selftests/bpf/prog_tests/tailcalls.c
+++ b/tools/testing/selftests/bpf/prog_tests/tailcalls.c
@@ -1,6 +1,9 @@
// SPDX-License-Identifier: GPL-2.0
+#include <unistd.h>
#include <test_progs.h>
#include <network_helpers.h>
+#include "tailcall_poke.skel.h"
+
/* test_tailcall_1 checks basic functionality by patching multiple locations
* in a single program for a single tail call slot with nop->jmp, jmp->nop
@@ -1105,6 +1108,85 @@ out:
bpf_object__close(tgt_obj);
}
+#define JMP_TABLE "/sys/fs/bpf/jmp_table"
+
+static int poke_thread_exit;
+
+static void *poke_update(void *arg)
+{
+ __u32 zero = 0, prog1_fd, prog2_fd, map_fd;
+ struct tailcall_poke *call = arg;
+
+ map_fd = bpf_map__fd(call->maps.jmp_table);
+ prog1_fd = bpf_program__fd(call->progs.call1);
+ prog2_fd = bpf_program__fd(call->progs.call2);
+
+ while (!poke_thread_exit) {
+ bpf_map_update_elem(map_fd, &zero, &prog1_fd, BPF_ANY);
+ bpf_map_update_elem(map_fd, &zero, &prog2_fd, BPF_ANY);
+ }
+
+ return NULL;
+}
+
+/*
+ * We are trying to hit prog array update during another program load
+ * that shares the same prog array map.
+ *
+ * For that we share the jmp_table map between two skeleton instances
+ * by pinning the jmp_table to same path. Then first skeleton instance
+ * periodically updates jmp_table in 'poke update' thread while we load
+ * the second skeleton instance in the main thread.
+ */
+static void test_tailcall_poke(void)
+{
+ struct tailcall_poke *call, *test;
+ int err, cnt = 10;
+ pthread_t thread;
+
+ unlink(JMP_TABLE);
+
+ call = tailcall_poke__open_and_load();
+ if (!ASSERT_OK_PTR(call, "tailcall_poke__open"))
+ return;
+
+ err = bpf_map__pin(call->maps.jmp_table, JMP_TABLE);
+ if (!ASSERT_OK(err, "bpf_map__pin"))
+ goto out;
+
+ err = pthread_create(&thread, NULL, poke_update, call);
+ if (!ASSERT_OK(err, "new toggler"))
+ goto out;
+
+ while (cnt--) {
+ test = tailcall_poke__open();
+ if (!ASSERT_OK_PTR(test, "tailcall_poke__open"))
+ break;
+
+ err = bpf_map__set_pin_path(test->maps.jmp_table, JMP_TABLE);
+ if (!ASSERT_OK(err, "bpf_map__pin")) {
+ tailcall_poke__destroy(test);
+ break;
+ }
+
+ bpf_program__set_autoload(test->progs.test, true);
+ bpf_program__set_autoload(test->progs.call1, false);
+ bpf_program__set_autoload(test->progs.call2, false);
+
+ err = tailcall_poke__load(test);
+ tailcall_poke__destroy(test);
+ if (!ASSERT_OK(err, "tailcall_poke__load"))
+ break;
+ }
+
+ poke_thread_exit = 1;
+ ASSERT_OK(pthread_join(thread, NULL), "pthread_join");
+
+out:
+ bpf_map__unpin(call->maps.jmp_table, JMP_TABLE);
+ tailcall_poke__destroy(call);
+}
+
void test_tailcalls(void)
{
if (test__start_subtest("tailcall_1"))
@@ -1139,4 +1221,6 @@ void test_tailcalls(void)
test_tailcall_bpf2bpf_fentry_fexit();
if (test__start_subtest("tailcall_bpf2bpf_fentry_entry"))
test_tailcall_bpf2bpf_fentry_entry();
+ if (test__start_subtest("tailcall_poke"))
+ test_tailcall_poke();
}
diff --git a/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c b/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c
index cd051d3901a9..ece260cf2c0b 100644
--- a/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c
+++ b/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c
@@ -249,7 +249,7 @@ static void __test_link_api(struct child *child)
int link_extra_fd = -1;
int err;
- err = elf_resolve_syms_offsets(path, 3, syms, (unsigned long **) &offsets);
+ err = elf_resolve_syms_offsets(path, 3, syms, (unsigned long **) &offsets, STT_FUNC);
if (!ASSERT_OK(err, "elf_resolve_syms_offsets"))
return;
diff --git a/tools/testing/selftests/bpf/prog_tests/verifier.c b/tools/testing/selftests/bpf/prog_tests/verifier.c
index 5cfa7a6316b6..8d746642cbd7 100644
--- a/tools/testing/selftests/bpf/prog_tests/verifier.c
+++ b/tools/testing/selftests/bpf/prog_tests/verifier.c
@@ -25,6 +25,7 @@
#include "verifier_direct_stack_access_wraparound.skel.h"
#include "verifier_div0.skel.h"
#include "verifier_div_overflow.skel.h"
+#include "verifier_global_subprogs.skel.h"
#include "verifier_gotol.skel.h"
#include "verifier_helper_access_var_len.skel.h"
#include "verifier_helper_packet_access.skel.h"
@@ -134,6 +135,7 @@ void test_verifier_direct_packet_access(void) { RUN(verifier_direct_packet_acces
void test_verifier_direct_stack_access_wraparound(void) { RUN(verifier_direct_stack_access_wraparound); }
void test_verifier_div0(void) { RUN(verifier_div0); }
void test_verifier_div_overflow(void) { RUN(verifier_div_overflow); }
+void test_verifier_global_subprogs(void) { RUN(verifier_global_subprogs); }
void test_verifier_gotol(void) { RUN(verifier_gotol); }
void test_verifier_helper_access_var_len(void) { RUN(verifier_helper_access_var_len); }
void test_verifier_helper_packet_access(void) { RUN(verifier_helper_packet_access); }
diff --git a/tools/testing/selftests/bpf/prog_tests/xdp_metadata.c b/tools/testing/selftests/bpf/prog_tests/xdp_metadata.c
index 4439ba9392f8..33cdf88efa6b 100644
--- a/tools/testing/selftests/bpf/prog_tests/xdp_metadata.c
+++ b/tools/testing/selftests/bpf/prog_tests/xdp_metadata.c
@@ -56,7 +56,8 @@ static int open_xsk(int ifindex, struct xsk *xsk)
.fill_size = XSK_RING_PROD__DEFAULT_NUM_DESCS,
.comp_size = XSK_RING_CONS__DEFAULT_NUM_DESCS,
.frame_size = XSK_UMEM__DEFAULT_FRAME_SIZE,
- .flags = XDP_UMEM_UNALIGNED_CHUNK_FLAG,
+ .flags = XDP_UMEM_UNALIGNED_CHUNK_FLAG | XDP_UMEM_TX_SW_CSUM,
+ .tx_metadata_len = sizeof(struct xsk_tx_metadata),
};
__u32 idx;
u64 addr;
@@ -138,6 +139,7 @@ static void ip_csum(struct iphdr *iph)
static int generate_packet(struct xsk *xsk, __u16 dst_port)
{
+ struct xsk_tx_metadata *meta;
struct xdp_desc *tx_desc;
struct udphdr *udph;
struct ethhdr *eth;
@@ -151,10 +153,14 @@ static int generate_packet(struct xsk *xsk, __u16 dst_port)
return -1;
tx_desc = xsk_ring_prod__tx_desc(&xsk->tx, idx);
- tx_desc->addr = idx % (UMEM_NUM / 2) * UMEM_FRAME_SIZE;
+ tx_desc->addr = idx % (UMEM_NUM / 2) * UMEM_FRAME_SIZE + sizeof(struct xsk_tx_metadata);
printf("%p: tx_desc[%u]->addr=%llx\n", xsk, idx, tx_desc->addr);
data = xsk_umem__get_data(xsk->umem_area, tx_desc->addr);
+ meta = data - sizeof(struct xsk_tx_metadata);
+ memset(meta, 0, sizeof(*meta));
+ meta->flags = XDP_TXMD_FLAGS_TIMESTAMP;
+
eth = data;
iph = (void *)(eth + 1);
udph = (void *)(iph + 1);
@@ -178,11 +184,17 @@ static int generate_packet(struct xsk *xsk, __u16 dst_port)
udph->source = htons(AF_XDP_SOURCE_PORT);
udph->dest = htons(dst_port);
udph->len = htons(sizeof(*udph) + UDP_PAYLOAD_BYTES);
- udph->check = 0;
+ udph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
+ ntohs(udph->len), IPPROTO_UDP, 0);
memset(udph + 1, 0xAA, UDP_PAYLOAD_BYTES);
+ meta->flags |= XDP_TXMD_FLAGS_CHECKSUM;
+ meta->request.csum_start = sizeof(*eth) + sizeof(*iph);
+ meta->request.csum_offset = offsetof(struct udphdr, check);
+
tx_desc->len = sizeof(*eth) + sizeof(*iph) + sizeof(*udph) + UDP_PAYLOAD_BYTES;
+ tx_desc->options |= XDP_TX_METADATA;
xsk_ring_prod__submit(&xsk->tx, 1);
ret = sendto(xsk_socket__fd(xsk->socket), NULL, 0, MSG_DONTWAIT, NULL, 0);
@@ -194,13 +206,21 @@ static int generate_packet(struct xsk *xsk, __u16 dst_port)
static void complete_tx(struct xsk *xsk)
{
- __u32 idx;
+ struct xsk_tx_metadata *meta;
__u64 addr;
+ void *data;
+ __u32 idx;
if (ASSERT_EQ(xsk_ring_cons__peek(&xsk->comp, 1, &idx), 1, "xsk_ring_cons__peek")) {
addr = *xsk_ring_cons__comp_addr(&xsk->comp, idx);
printf("%p: complete tx idx=%u addr=%llx\n", xsk, idx, addr);
+
+ data = xsk_umem__get_data(xsk->umem_area, addr);
+ meta = data - sizeof(struct xsk_tx_metadata);
+
+ ASSERT_NEQ(meta->completion.tx_timestamp, 0, "tx_timestamp");
+
xsk_ring_cons__release(&xsk->comp, 1);
}
}
@@ -221,6 +241,7 @@ static int verify_xsk_metadata(struct xsk *xsk)
const struct xdp_desc *rx_desc;
struct pollfd fds = {};
struct xdp_meta *meta;
+ struct udphdr *udph;
struct ethhdr *eth;
struct iphdr *iph;
__u64 comp_addr;
@@ -257,6 +278,7 @@ static int verify_xsk_metadata(struct xsk *xsk)
ASSERT_EQ(eth->h_proto, htons(ETH_P_IP), "eth->h_proto");
iph = (void *)(eth + 1);
ASSERT_EQ((int)iph->version, 4, "iph->version");
+ udph = (void *)(iph + 1);
/* custom metadata */
@@ -270,6 +292,9 @@ static int verify_xsk_metadata(struct xsk *xsk)
ASSERT_EQ(meta->rx_hash_type, 0, "rx_hash_type");
+ /* checksum offload */
+ ASSERT_EQ(udph->check, htons(0x721c), "csum");
+
xsk_ring_cons__release(&xsk->rx, 1);
refill_rx(xsk, comp_addr);
diff --git a/tools/testing/selftests/bpf/progs/tailcall_poke.c b/tools/testing/selftests/bpf/progs/tailcall_poke.c
new file mode 100644
index 000000000000..c78b94b75e83
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/tailcall_poke.c
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/bpf.h>
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_tracing.h>
+
+char _license[] SEC("license") = "GPL";
+
+struct {
+ __uint(type, BPF_MAP_TYPE_PROG_ARRAY);
+ __uint(max_entries, 1);
+ __uint(key_size, sizeof(__u32));
+ __uint(value_size, sizeof(__u32));
+} jmp_table SEC(".maps");
+
+SEC("?fentry/bpf_fentry_test1")
+int BPF_PROG(test, int a)
+{
+ bpf_tail_call_static(ctx, &jmp_table, 0);
+ return 0;
+}
+
+SEC("fentry/bpf_fentry_test1")
+int BPF_PROG(call1, int a)
+{
+ return 0;
+}
+
+SEC("fentry/bpf_fentry_test1")
+int BPF_PROG(call2, int a)
+{
+ return 0;
+}
diff --git a/tools/testing/selftests/bpf/progs/test_fill_link_info.c b/tools/testing/selftests/bpf/progs/test_fill_link_info.c
index 564f402d56fe..69509f8bb680 100644
--- a/tools/testing/selftests/bpf/progs/test_fill_link_info.c
+++ b/tools/testing/selftests/bpf/progs/test_fill_link_info.c
@@ -39,4 +39,10 @@ int BPF_PROG(kmulti_run)
return 0;
}
+SEC("uprobe.multi")
+int BPF_PROG(umulti_run)
+{
+ return 0;
+}
+
char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/progs/test_global_func12.c b/tools/testing/selftests/bpf/progs/test_global_func12.c
index 7f159d83c6f6..6e03d42519a6 100644
--- a/tools/testing/selftests/bpf/progs/test_global_func12.c
+++ b/tools/testing/selftests/bpf/progs/test_global_func12.c
@@ -19,5 +19,7 @@ int global_func12(struct __sk_buff *skb)
{
const struct S s = {.x = skb->len };
- return foo(&s);
+ foo(&s);
+
+ return 1;
}
diff --git a/tools/testing/selftests/bpf/progs/test_global_func17.c b/tools/testing/selftests/bpf/progs/test_global_func17.c
index a32e11c7d933..5de44b09e8ec 100644
--- a/tools/testing/selftests/bpf/progs/test_global_func17.c
+++ b/tools/testing/selftests/bpf/progs/test_global_func17.c
@@ -5,6 +5,7 @@
__noinline int foo(int *p)
{
+ barrier_var(p);
return p ? (*p = 42) : 0;
}
diff --git a/tools/testing/selftests/bpf/progs/test_sockmap_listen.c b/tools/testing/selftests/bpf/progs/test_sockmap_listen.c
index 464d35bd57c7..b7250eb9c30c 100644
--- a/tools/testing/selftests/bpf/progs/test_sockmap_listen.c
+++ b/tools/testing/selftests/bpf/progs/test_sockmap_listen.c
@@ -15,6 +15,13 @@ struct {
} sock_map SEC(".maps");
struct {
+ __uint(type, BPF_MAP_TYPE_SOCKMAP);
+ __uint(max_entries, 2);
+ __type(key, __u32);
+ __type(value, __u64);
+} nop_map SEC(".maps");
+
+struct {
__uint(type, BPF_MAP_TYPE_SOCKHASH);
__uint(max_entries, 2);
__type(key, __u32);
diff --git a/tools/testing/selftests/bpf/progs/verifier_global_subprogs.c b/tools/testing/selftests/bpf/progs/verifier_global_subprogs.c
new file mode 100644
index 000000000000..a0a5efd1caa1
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/verifier_global_subprogs.c
@@ -0,0 +1,92 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */
+
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <linux/bpf.h>
+#include <bpf/bpf_helpers.h>
+#include "bpf_misc.h"
+
+int arr[1];
+int unkn_idx;
+
+__noinline long global_bad(void)
+{
+ return arr[unkn_idx]; /* BOOM */
+}
+
+__noinline long global_good(void)
+{
+ return arr[0];
+}
+
+__noinline long global_calls_bad(void)
+{
+ return global_good() + global_bad() /* does BOOM indirectly */;
+}
+
+__noinline long global_calls_good_only(void)
+{
+ return global_good();
+}
+
+SEC("?raw_tp")
+__success __log_level(2)
+/* main prog is validated completely first */
+__msg("('global_calls_good_only') is global and assumed valid.")
+__msg("1: (95) exit")
+/* eventually global_good() is transitively validated as well */
+__msg("Validating global_good() func")
+__msg("('global_good') is safe for any args that match its prototype")
+int chained_global_func_calls_success(void)
+{
+ return global_calls_good_only();
+}
+
+SEC("?raw_tp")
+__failure __log_level(2)
+/* main prog validated successfully first */
+__msg("1: (95) exit")
+/* eventually we validate global_bad() and fail */
+__msg("Validating global_bad() func")
+__msg("math between map_value pointer and register") /* BOOM */
+int chained_global_func_calls_bad(void)
+{
+ return global_calls_bad();
+}
+
+/* do out of bounds access forcing verifier to fail verification if this
+ * global func is called
+ */
+__noinline int global_unsupp(const int *mem)
+{
+ if (!mem)
+ return 0;
+ return mem[100]; /* BOOM */
+}
+
+const volatile bool skip_unsupp_global = true;
+
+SEC("?raw_tp")
+__success
+int guarded_unsupp_global_called(void)
+{
+ if (!skip_unsupp_global)
+ return global_unsupp(NULL);
+ return 0;
+}
+
+SEC("?raw_tp")
+__failure __log_level(2)
+__msg("Func#1 ('global_unsupp') is global and assumed valid.")
+__msg("Validating global_unsupp() func#1...")
+__msg("value is outside of the allowed memory range")
+int unguarded_unsupp_global_called(void)
+{
+ int x = 0;
+
+ return global_unsupp(&x);
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c b/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c
index f61d623b1ce8..b5efcaeaa1ae 100644
--- a/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c
+++ b/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c
@@ -370,12 +370,10 @@ __naked int parent_stack_slot_precise(void)
SEC("?raw_tp")
__success __log_level(2)
__msg("9: (0f) r1 += r6")
-__msg("mark_precise: frame0: last_idx 9 first_idx 6")
+__msg("mark_precise: frame0: last_idx 9 first_idx 0")
__msg("mark_precise: frame0: regs=r6 stack= before 8: (bf) r1 = r7")
__msg("mark_precise: frame0: regs=r6 stack= before 7: (27) r6 *= 4")
__msg("mark_precise: frame0: regs=r6 stack= before 6: (79) r6 = *(u64 *)(r10 -8)")
-__msg("mark_precise: frame0: parent state regs= stack=-8:")
-__msg("mark_precise: frame0: last_idx 5 first_idx 0")
__msg("mark_precise: frame0: regs= stack=-8 before 5: (85) call pc+6")
__msg("mark_precise: frame0: regs= stack=-8 before 4: (b7) r1 = 0")
__msg("mark_precise: frame0: regs= stack=-8 before 3: (7b) *(u64 *)(r10 -8) = r6")
diff --git a/tools/testing/selftests/bpf/test_offload.py b/tools/testing/selftests/bpf/test_offload.py
index 40cba8d368d9..6157f884d091 100755
--- a/tools/testing/selftests/bpf/test_offload.py
+++ b/tools/testing/selftests/bpf/test_offload.py
@@ -169,12 +169,14 @@ def bpftool(args, JSON=True, ns="", fail=True, include_stderr=False):
return tool("bpftool", args, {"json":"-p"}, JSON=JSON, ns=ns,
fail=fail, include_stderr=include_stderr)
-def bpftool_prog_list(expected=None, ns=""):
+def bpftool_prog_list(expected=None, ns="", exclude_orphaned=True):
_, progs = bpftool("prog show", JSON=True, ns=ns, fail=True)
# Remove the base progs
for p in base_progs:
if p in progs:
progs.remove(p)
+ if exclude_orphaned:
+ progs = [ p for p in progs if not p['orphaned'] ]
if expected is not None:
if len(progs) != expected:
fail(True, "%d BPF programs loaded, expected %d" %
@@ -612,11 +614,9 @@ def pin_map(file_name, idx=0, expected=1):
def check_dev_info_removed(prog_file=None, map_file=None):
bpftool_prog_list(expected=0)
+ bpftool_prog_list(expected=1, exclude_orphaned=False)
ret, err = bpftool("prog show pin %s" % (prog_file), fail=False)
- fail(ret == 0, "Showing prog with removed device did not fail")
- fail(err["error"].find("No such device") == -1,
- "Showing prog with removed device expected ENODEV, error is %s" %
- (err["error"]))
+ fail(ret != 0, "failed to show prog with removed device")
bpftool_map_list(expected=0)
ret, err = bpftool("map show pin %s" % (map_file), fail=False)
@@ -1395,10 +1395,7 @@ try:
start_test("Test multi-dev ASIC cross-dev destruction - orphaned...")
ret, out = bpftool("prog show %s" % (progB), fail=False)
- fail(ret == 0, "got information about orphaned program")
- fail("error" not in out, "no error reported for get info on orphaned")
- fail(out["error"] != "can't get prog info: No such device",
- "wrong error for get info on orphaned")
+ fail(ret != 0, "couldn't get information about orphaned program")
print("%s: OK" % (os.path.basename(__file__)))
diff --git a/tools/testing/selftests/bpf/xdp_hw_metadata.c b/tools/testing/selftests/bpf/xdp_hw_metadata.c
index c3ba40d0b9de..3291625ba4fb 100644
--- a/tools/testing/selftests/bpf/xdp_hw_metadata.c
+++ b/tools/testing/selftests/bpf/xdp_hw_metadata.c
@@ -10,7 +10,9 @@
* - rx_hash
*
* TX:
- * - TBD
+ * - UDP 9091 packets trigger TX reply
+ * - TX HW timestamp is requested and reported back upon completion
+ * - TX checksum is requested
*/
#include <test_progs.h>
@@ -24,15 +26,18 @@
#include <linux/net_tstamp.h>
#include <linux/udp.h>
#include <linux/sockios.h>
+#include <linux/if_xdp.h>
#include <sys/mman.h>
#include <net/if.h>
#include <ctype.h>
#include <poll.h>
#include <time.h>
+#include <unistd.h>
+#include <libgen.h>
#include "xdp_metadata.h"
-#define UMEM_NUM 16
+#define UMEM_NUM 256
#define UMEM_FRAME_SIZE XSK_UMEM__DEFAULT_FRAME_SIZE
#define UMEM_SIZE (UMEM_FRAME_SIZE * UMEM_NUM)
#define XDP_FLAGS (XDP_FLAGS_DRV_MODE | XDP_FLAGS_REPLACE)
@@ -48,11 +53,14 @@ struct xsk {
};
struct xdp_hw_metadata *bpf_obj;
-__u16 bind_flags = XDP_COPY;
+__u16 bind_flags = XDP_USE_NEED_WAKEUP | XDP_ZEROCOPY;
struct xsk *rx_xsk;
const char *ifname;
int ifindex;
int rxq;
+bool skip_tx;
+__u64 last_hw_rx_timestamp;
+__u64 last_xdp_rx_timestamp;
void test__fail(void) { /* for network_helpers.c */ }
@@ -68,7 +76,8 @@ static int open_xsk(int ifindex, struct xsk *xsk, __u32 queue_id)
.fill_size = XSK_RING_PROD__DEFAULT_NUM_DESCS,
.comp_size = XSK_RING_CONS__DEFAULT_NUM_DESCS,
.frame_size = XSK_UMEM__DEFAULT_FRAME_SIZE,
- .flags = XDP_UMEM_UNALIGNED_CHUNK_FLAG,
+ .flags = XSK_UMEM__DEFAULT_FLAGS,
+ .tx_metadata_len = sizeof(struct xsk_tx_metadata),
};
__u32 idx;
u64 addr;
@@ -110,7 +119,7 @@ static int open_xsk(int ifindex, struct xsk *xsk, __u32 queue_id)
for (i = 0; i < UMEM_NUM / 2; i++) {
addr = (UMEM_NUM / 2 + i) * UMEM_FRAME_SIZE;
printf("%p: rx_desc[%d] -> %lx\n", xsk, i, addr);
- *xsk_ring_prod__fill_addr(&xsk->fill, i) = addr;
+ *xsk_ring_prod__fill_addr(&xsk->fill, idx + i) = addr;
}
xsk_ring_prod__submit(&xsk->fill, ret);
@@ -131,12 +140,22 @@ static void refill_rx(struct xsk *xsk, __u64 addr)
__u32 idx;
if (xsk_ring_prod__reserve(&xsk->fill, 1, &idx) == 1) {
- printf("%p: complete idx=%u addr=%llx\n", xsk, idx, addr);
+ printf("%p: complete rx idx=%u addr=%llx\n", xsk, idx, addr);
*xsk_ring_prod__fill_addr(&xsk->fill, idx) = addr;
xsk_ring_prod__submit(&xsk->fill, 1);
}
}
+static int kick_tx(struct xsk *xsk)
+{
+ return sendto(xsk_socket__fd(xsk->socket), NULL, 0, MSG_DONTWAIT, NULL, 0);
+}
+
+static int kick_rx(struct xsk *xsk)
+{
+ return recvfrom(xsk_socket__fd(xsk->socket), NULL, 0, MSG_DONTWAIT, NULL, NULL);
+}
+
#define NANOSEC_PER_SEC 1000000000 /* 10^9 */
static __u64 gettime(clockid_t clock_id)
{
@@ -152,6 +171,17 @@ static __u64 gettime(clockid_t clock_id)
return (__u64) t.tv_sec * NANOSEC_PER_SEC + t.tv_nsec;
}
+static void print_tstamp_delta(const char *name, const char *refname,
+ __u64 tstamp, __u64 reference)
+{
+ __s64 delta = (__s64)reference - (__s64)tstamp;
+
+ printf("%s: %llu (sec:%0.4f) delta to %s sec:%0.4f (%0.3f usec)\n",
+ name, tstamp, (double)tstamp / NANOSEC_PER_SEC, refname,
+ (double)delta / NANOSEC_PER_SEC,
+ (double)delta / 1000);
+}
+
static void verify_xdp_metadata(void *data, clockid_t clock_id)
{
struct xdp_meta *meta;
@@ -164,25 +194,20 @@ static void verify_xdp_metadata(void *data, clockid_t clock_id)
printf("rx_hash: 0x%X with RSS type:0x%X\n",
meta->rx_hash, meta->rx_hash_type);
- printf("rx_timestamp: %llu (sec:%0.4f)\n", meta->rx_timestamp,
- (double)meta->rx_timestamp / NANOSEC_PER_SEC);
if (meta->rx_timestamp) {
- __u64 usr_clock = gettime(clock_id);
- __u64 xdp_clock = meta->xdp_timestamp;
- __s64 delta_X = xdp_clock - meta->rx_timestamp;
- __s64 delta_X2U = usr_clock - xdp_clock;
-
- printf("XDP RX-time: %llu (sec:%0.4f) delta sec:%0.4f (%0.3f usec)\n",
- xdp_clock, (double)xdp_clock / NANOSEC_PER_SEC,
- (double)delta_X / NANOSEC_PER_SEC,
- (double)delta_X / 1000);
-
- printf("AF_XDP time: %llu (sec:%0.4f) delta sec:%0.4f (%0.3f usec)\n",
- usr_clock, (double)usr_clock / NANOSEC_PER_SEC,
- (double)delta_X2U / NANOSEC_PER_SEC,
- (double)delta_X2U / 1000);
+ __u64 ref_tstamp = gettime(clock_id);
+
+ /* store received timestamps to calculate a delta at tx */
+ last_hw_rx_timestamp = meta->rx_timestamp;
+ last_xdp_rx_timestamp = meta->xdp_timestamp;
+
+ print_tstamp_delta("HW RX-time", "User RX-time",
+ meta->rx_timestamp, ref_tstamp);
+ print_tstamp_delta("XDP RX-time", "User RX-time",
+ meta->xdp_timestamp, ref_tstamp);
+ } else {
+ printf("No rx_timestamp\n");
}
-
}
static void verify_skb_metadata(int fd)
@@ -230,6 +255,129 @@ static void verify_skb_metadata(int fd)
printf("skb hwtstamp is not found!\n");
}
+static bool complete_tx(struct xsk *xsk, clockid_t clock_id)
+{
+ struct xsk_tx_metadata *meta;
+ __u64 addr;
+ void *data;
+ __u32 idx;
+
+ if (!xsk_ring_cons__peek(&xsk->comp, 1, &idx))
+ return false;
+
+ addr = *xsk_ring_cons__comp_addr(&xsk->comp, idx);
+ data = xsk_umem__get_data(xsk->umem_area, addr);
+ meta = data - sizeof(struct xsk_tx_metadata);
+
+ printf("%p: complete tx idx=%u addr=%llx\n", xsk, idx, addr);
+
+ if (meta->completion.tx_timestamp) {
+ __u64 ref_tstamp = gettime(clock_id);
+
+ print_tstamp_delta("HW TX-complete-time", "User TX-complete-time",
+ meta->completion.tx_timestamp, ref_tstamp);
+ print_tstamp_delta("XDP RX-time", "User TX-complete-time",
+ last_xdp_rx_timestamp, ref_tstamp);
+ print_tstamp_delta("HW RX-time", "HW TX-complete-time",
+ last_hw_rx_timestamp, meta->completion.tx_timestamp);
+ } else {
+ printf("No tx_timestamp\n");
+ }
+
+ xsk_ring_cons__release(&xsk->comp, 1);
+
+ return true;
+}
+
+#define swap(a, b, len) do { \
+ for (int i = 0; i < len; i++) { \
+ __u8 tmp = ((__u8 *)a)[i]; \
+ ((__u8 *)a)[i] = ((__u8 *)b)[i]; \
+ ((__u8 *)b)[i] = tmp; \
+ } \
+} while (0)
+
+static void ping_pong(struct xsk *xsk, void *rx_packet, clockid_t clock_id)
+{
+ struct xsk_tx_metadata *meta;
+ struct ipv6hdr *ip6h = NULL;
+ struct iphdr *iph = NULL;
+ struct xdp_desc *tx_desc;
+ struct udphdr *udph;
+ struct ethhdr *eth;
+ __sum16 want_csum;
+ void *data;
+ __u32 idx;
+ int ret;
+ int len;
+
+ ret = xsk_ring_prod__reserve(&xsk->tx, 1, &idx);
+ if (ret != 1) {
+ printf("%p: failed to reserve tx slot\n", xsk);
+ return;
+ }
+
+ tx_desc = xsk_ring_prod__tx_desc(&xsk->tx, idx);
+ tx_desc->addr = idx % (UMEM_NUM / 2) * UMEM_FRAME_SIZE + sizeof(struct xsk_tx_metadata);
+ data = xsk_umem__get_data(xsk->umem_area, tx_desc->addr);
+
+ meta = data - sizeof(struct xsk_tx_metadata);
+ memset(meta, 0, sizeof(*meta));
+ meta->flags = XDP_TXMD_FLAGS_TIMESTAMP;
+
+ eth = rx_packet;
+
+ if (eth->h_proto == htons(ETH_P_IP)) {
+ iph = (void *)(eth + 1);
+ udph = (void *)(iph + 1);
+ } else if (eth->h_proto == htons(ETH_P_IPV6)) {
+ ip6h = (void *)(eth + 1);
+ udph = (void *)(ip6h + 1);
+ } else {
+ printf("%p: failed to detect IP version for ping pong %04x\n", xsk, eth->h_proto);
+ xsk_ring_prod__cancel(&xsk->tx, 1);
+ return;
+ }
+
+ len = ETH_HLEN;
+ if (ip6h)
+ len += sizeof(*ip6h) + ntohs(ip6h->payload_len);
+ if (iph)
+ len += ntohs(iph->tot_len);
+
+ swap(eth->h_dest, eth->h_source, ETH_ALEN);
+ if (iph)
+ swap(&iph->saddr, &iph->daddr, 4);
+ else
+ swap(&ip6h->saddr, &ip6h->daddr, 16);
+ swap(&udph->source, &udph->dest, 2);
+
+ want_csum = udph->check;
+ if (ip6h)
+ udph->check = ~csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr,
+ ntohs(udph->len), IPPROTO_UDP, 0);
+ else
+ udph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
+ ntohs(udph->len), IPPROTO_UDP, 0);
+
+ meta->flags |= XDP_TXMD_FLAGS_CHECKSUM;
+ if (iph)
+ meta->request.csum_start = sizeof(*eth) + sizeof(*iph);
+ else
+ meta->request.csum_start = sizeof(*eth) + sizeof(*ip6h);
+ meta->request.csum_offset = offsetof(struct udphdr, check);
+
+ printf("%p: ping-pong with csum=%04x (want %04x) csum_start=%d csum_offset=%d\n",
+ xsk, ntohs(udph->check), ntohs(want_csum),
+ meta->request.csum_start, meta->request.csum_offset);
+
+ memcpy(data, rx_packet, len); /* don't share umem chunk for simplicity */
+ tx_desc->options |= XDP_TX_METADATA;
+ tx_desc->len = len;
+
+ xsk_ring_prod__submit(&xsk->tx, 1);
+}
+
static int verify_metadata(struct xsk *rx_xsk, int rxq, int server_fd, clockid_t clock_id)
{
const struct xdp_desc *rx_desc;
@@ -252,6 +400,13 @@ static int verify_metadata(struct xsk *rx_xsk, int rxq, int server_fd, clockid_t
while (true) {
errno = 0;
+
+ for (i = 0; i < rxq; i++) {
+ ret = kick_rx(&rx_xsk[i]);
+ if (ret)
+ printf("kick_rx ret=%d\n", ret);
+ }
+
ret = poll(fds, rxq + 1, 1000);
printf("poll: %d (%d) skip=%llu fail=%llu redir=%llu\n",
ret, errno, bpf_obj->bss->pkts_skip,
@@ -288,6 +443,22 @@ peek:
verify_xdp_metadata(xsk_umem__get_data(xsk->umem_area, addr),
clock_id);
first_seg = false;
+
+ if (!skip_tx) {
+ /* mirror first chunk back */
+ ping_pong(xsk, xsk_umem__get_data(xsk->umem_area, addr),
+ clock_id);
+
+ ret = kick_tx(xsk);
+ if (ret)
+ printf("kick_tx ret=%d\n", ret);
+
+ for (int j = 0; j < 500; j++) {
+ if (complete_tx(xsk, clock_id))
+ break;
+ usleep(10*1000);
+ }
+ }
}
xsk_ring_cons__release(&xsk->rx, 1);
@@ -420,8 +591,10 @@ static void print_usage(void)
{
const char *usage =
"Usage: xdp_hw_metadata [OPTIONS] [IFNAME]\n"
- " -m Enable multi-buffer XDP for larger MTU\n"
+ " -c Run in copy mode (zerocopy is default)\n"
" -h Display this help and exit\n\n"
+ " -m Enable multi-buffer XDP for larger MTU\n"
+ " -r Don't generate AF_XDP reply (rx metadata only)\n"
"Generate test packets on the other machine with:\n"
" echo -n xdp | nc -u -q1 <dst_ip> 9091\n";
@@ -432,14 +605,22 @@ static void read_args(int argc, char *argv[])
{
int opt;
- while ((opt = getopt(argc, argv, "mh")) != -1) {
+ while ((opt = getopt(argc, argv, "chmr")) != -1) {
switch (opt) {
- case 'm':
- bind_flags |= XDP_USE_SG;
+ case 'c':
+ bind_flags &= ~XDP_USE_NEED_WAKEUP;
+ bind_flags &= ~XDP_ZEROCOPY;
+ bind_flags |= XDP_COPY;
break;
case 'h':
print_usage();
exit(0);
+ case 'm':
+ bind_flags |= XDP_USE_SG;
+ break;
+ case 'r':
+ skip_tx = true;
+ break;
case '?':
if (isprint(optopt))
fprintf(stderr, "Unknown option: -%c\n", optopt);
diff --git a/tools/testing/selftests/bpf/xsk.c b/tools/testing/selftests/bpf/xsk.c
index e574711eeb84..25d568abf0f2 100644
--- a/tools/testing/selftests/bpf/xsk.c
+++ b/tools/testing/selftests/bpf/xsk.c
@@ -115,6 +115,7 @@ static void xsk_set_umem_config(struct xsk_umem_config *cfg,
cfg->frame_size = XSK_UMEM__DEFAULT_FRAME_SIZE;
cfg->frame_headroom = XSK_UMEM__DEFAULT_FRAME_HEADROOM;
cfg->flags = XSK_UMEM__DEFAULT_FLAGS;
+ cfg->tx_metadata_len = 0;
return;
}
@@ -123,6 +124,7 @@ static void xsk_set_umem_config(struct xsk_umem_config *cfg,
cfg->frame_size = usr_cfg->frame_size;
cfg->frame_headroom = usr_cfg->frame_headroom;
cfg->flags = usr_cfg->flags;
+ cfg->tx_metadata_len = usr_cfg->tx_metadata_len;
}
static int xsk_set_xdp_socket_config(struct xsk_socket_config *cfg,
@@ -252,6 +254,7 @@ int xsk_umem__create(struct xsk_umem **umem_ptr, void *umem_area,
mr.chunk_size = umem->config.frame_size;
mr.headroom = umem->config.frame_headroom;
mr.flags = umem->config.flags;
+ mr.tx_metadata_len = umem->config.tx_metadata_len;
err = setsockopt(umem->fd, SOL_XDP, XDP_UMEM_REG, &mr, sizeof(mr));
if (err) {
diff --git a/tools/testing/selftests/bpf/xsk.h b/tools/testing/selftests/bpf/xsk.h
index 771570bc3731..93c2cc413cfc 100644
--- a/tools/testing/selftests/bpf/xsk.h
+++ b/tools/testing/selftests/bpf/xsk.h
@@ -200,6 +200,7 @@ struct xsk_umem_config {
__u32 frame_size;
__u32 frame_headroom;
__u32 flags;
+ __u32 tx_metadata_len;
};
int xsk_attach_xdp_program(struct bpf_program *prog, int ifindex, u32 xdp_flags);
diff --git a/tools/testing/selftests/iommu/iommufd_utils.h b/tools/testing/selftests/iommu/iommufd_utils.h
index 050e9751321c..ad9202335656 100644
--- a/tools/testing/selftests/iommu/iommufd_utils.h
+++ b/tools/testing/selftests/iommu/iommufd_utils.h
@@ -293,15 +293,13 @@ static int _test_mock_dirty_bitmaps(int fd, __u32 hwpt_id, size_t length,
__u64 bitmap_size, __u32 flags,
struct __test_metadata *_metadata)
{
- unsigned long i, count, nbits = bitmap_size * BITS_PER_BYTE;
+ unsigned long i, nbits = bitmap_size * BITS_PER_BYTE;
unsigned long nr = nbits / 2;
__u64 out_dirty = 0;
/* Mark all even bits as dirty in the mock domain */
- for (count = 0, i = 0; i < nbits; count += !(i % 2), i++)
- if (!(i % 2))
- set_bit(i, (unsigned long *)bitmap);
- ASSERT_EQ(nr, count);
+ for (i = 0; i < nbits; i += 2)
+ set_bit(i, (unsigned long *)bitmap);
test_cmd_mock_domain_set_dirty(fd, hwpt_id, length, iova, page_size,
bitmap, &out_dirty);
@@ -311,9 +309,10 @@ static int _test_mock_dirty_bitmaps(int fd, __u32 hwpt_id, size_t length,
memset(bitmap, 0, bitmap_size);
test_cmd_get_dirty_bitmap(fd, hwpt_id, length, iova, page_size, bitmap,
flags);
- for (count = 0, i = 0; i < nbits; count += !(i % 2), i++)
+ /* Beware ASSERT_EQ() is two statements -- braces are not redundant! */
+ for (i = 0; i < nbits; i++) {
ASSERT_EQ(!(i % 2), test_bit(i, (unsigned long *)bitmap));
- ASSERT_EQ(count, out_dirty);
+ }
memset(bitmap, 0, bitmap_size);
test_cmd_get_dirty_bitmap(fd, hwpt_id, length, iova, page_size, bitmap,
diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile
index a5963ab9215b..963435959a92 100644
--- a/tools/testing/selftests/kvm/Makefile
+++ b/tools/testing/selftests/kvm/Makefile
@@ -18,12 +18,13 @@ else
endif
ifeq ($(ARCH),arm64)
-arm64_tools_dir := $(top_srcdir)/tools/arch/arm64/tools/
+tools_dir := $(top_srcdir)/tools
+arm64_tools_dir := $(tools_dir)/arch/arm64/tools/
GEN_HDRS := $(top_srcdir)/tools/arch/arm64/include/generated/
CFLAGS += -I$(GEN_HDRS)
$(GEN_HDRS): $(wildcard $(arm64_tools_dir)/*)
- $(MAKE) -C $(arm64_tools_dir)
+ $(MAKE) -C $(arm64_tools_dir) O=$(tools_dir)
endif
LIBKVM += lib/assert.c
@@ -223,7 +224,7 @@ else
LINUX_TOOL_ARCH_INCLUDE = $(top_srcdir)/tools/arch/$(ARCH)/include
endif
CFLAGS += -Wall -Wstrict-prototypes -Wuninitialized -O2 -g -std=gnu99 \
- -Wno-gnu-variable-sized-type-not-at-end -MD\
+ -Wno-gnu-variable-sized-type-not-at-end -MD -MP \
-fno-builtin-memcmp -fno-builtin-memcpy -fno-builtin-memset \
-fno-builtin-strnlen \
-fno-stack-protector -fno-PIE -I$(LINUX_TOOL_INCLUDE) \
diff --git a/tools/testing/selftests/kvm/x86_64/nx_huge_pages_test.c b/tools/testing/selftests/kvm/x86_64/nx_huge_pages_test.c
index 18ac5c1952a3..83e25bccc139 100644
--- a/tools/testing/selftests/kvm/x86_64/nx_huge_pages_test.c
+++ b/tools/testing/selftests/kvm/x86_64/nx_huge_pages_test.c
@@ -259,7 +259,7 @@ int main(int argc, char **argv)
__TEST_REQUIRE(token == MAGIC_TOKEN,
"This test must be run with the magic token %d.\n"
"This is done by nx_huge_pages_test.sh, which\n"
- "also handles environment setup for the test.");
+ "also handles environment setup for the test.", MAGIC_TOKEN);
run_test(reclaim_period_ms, false, reboot_permissions);
run_test(reclaim_period_ms, true, reboot_permissions);
diff --git a/tools/testing/selftests/mm/Makefile b/tools/testing/selftests/mm/Makefile
index 78dfec8bc676..dede0bcf97a3 100644
--- a/tools/testing/selftests/mm/Makefile
+++ b/tools/testing/selftests/mm/Makefile
@@ -60,7 +60,7 @@ TEST_GEN_FILES += mrelease_test
TEST_GEN_FILES += mremap_dontunmap
TEST_GEN_FILES += mremap_test
TEST_GEN_FILES += on-fault-limit
-TEST_GEN_PROGS += pagemap_ioctl
+TEST_GEN_FILES += pagemap_ioctl
TEST_GEN_FILES += thuge-gen
TEST_GEN_FILES += transhuge-stress
TEST_GEN_FILES += uffd-stress
@@ -72,7 +72,7 @@ TEST_GEN_FILES += mdwe_test
TEST_GEN_FILES += hugetlb_fault_after_madv
ifneq ($(ARCH),arm64)
-TEST_GEN_PROGS += soft-dirty
+TEST_GEN_FILES += soft-dirty
endif
ifeq ($(ARCH),x86_64)
diff --git a/tools/testing/selftests/mm/pagemap_ioctl.c b/tools/testing/selftests/mm/pagemap_ioctl.c
index befab43719ba..d59517ed3d48 100644
--- a/tools/testing/selftests/mm/pagemap_ioctl.c
+++ b/tools/testing/selftests/mm/pagemap_ioctl.c
@@ -36,6 +36,7 @@ int pagemap_fd;
int uffd;
int page_size;
int hpage_size;
+const char *progname;
#define LEN(region) ((region.end - region.start)/page_size)
@@ -1149,11 +1150,11 @@ int sanity_tests(void)
munmap(mem, mem_size);
/* 9. Memory mapped file */
- fd = open(__FILE__, O_RDONLY);
+ fd = open(progname, O_RDONLY);
if (fd < 0)
ksft_exit_fail_msg("%s Memory mapped file\n", __func__);
- ret = stat(__FILE__, &sbuf);
+ ret = stat(progname, &sbuf);
if (ret < 0)
ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno));
@@ -1472,12 +1473,14 @@ static void transact_test(int page_size)
extra_thread_faults);
}
-int main(void)
+int main(int argc, char *argv[])
{
int mem_size, shmid, buf_size, fd, i, ret;
char *mem, *map, *fmem;
struct stat sbuf;
+ progname = argv[0];
+
ksft_print_header();
if (init_uffd())
diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile
index 9274edfb76ff..14bd68da7466 100644
--- a/tools/testing/selftests/net/Makefile
+++ b/tools/testing/selftests/net/Makefile
@@ -54,7 +54,7 @@ TEST_PROGS += ip_local_port_range.sh
TEST_PROGS += rps_default_mask.sh
TEST_PROGS += big_tcp.sh
TEST_PROGS_EXTENDED := in_netns.sh setup_loopback.sh setup_veth.sh
-TEST_PROGS_EXTENDED += toeplitz_client.sh toeplitz.sh
+TEST_PROGS_EXTENDED += toeplitz_client.sh toeplitz.sh lib.sh
TEST_GEN_FILES = socket nettest
TEST_GEN_FILES += psock_fanout psock_tpacket msg_zerocopy reuseport_addr_any
TEST_GEN_FILES += tcp_mmap tcp_inq psock_snd txring_overwrite
diff --git a/tools/testing/selftests/net/af_unix/diag_uid.c b/tools/testing/selftests/net/af_unix/diag_uid.c
index 5b88f7129fea..79a3dd75590e 100644
--- a/tools/testing/selftests/net/af_unix/diag_uid.c
+++ b/tools/testing/selftests/net/af_unix/diag_uid.c
@@ -148,7 +148,6 @@ void receive_response(struct __test_metadata *_metadata,
.msg_iov = &iov,
.msg_iovlen = 1
};
- struct unix_diag_req *udr;
struct nlmsghdr *nlh;
int ret;
diff --git a/tools/testing/selftests/net/arp_ndisc_evict_nocarrier.sh b/tools/testing/selftests/net/arp_ndisc_evict_nocarrier.sh
index 4a110bb01e53..92eb880c52f2 100755
--- a/tools/testing/selftests/net/arp_ndisc_evict_nocarrier.sh
+++ b/tools/testing/selftests/net/arp_ndisc_evict_nocarrier.sh
@@ -12,7 +12,8 @@
# {arp,ndisc}_evict_nocarrer=0 should still contain the single ARP/ND entry
#
-readonly PEER_NS="ns-peer-$(mktemp -u XXXXXX)"
+source lib.sh
+
readonly V4_ADDR0=10.0.10.1
readonly V4_ADDR1=10.0.10.2
readonly V6_ADDR0=2001:db8:91::1
@@ -22,43 +23,29 @@ ret=0
cleanup_v6()
{
- ip netns del me
- ip netns del peer
+ cleanup_ns ${me} ${peer}
sysctl -w net.ipv6.conf.veth1.ndisc_evict_nocarrier=1 >/dev/null 2>&1
sysctl -w net.ipv6.conf.all.ndisc_evict_nocarrier=1 >/dev/null 2>&1
}
-create_ns()
-{
- local n=${1}
-
- ip netns del ${n} 2>/dev/null
-
- ip netns add ${n}
- ip netns set ${n} $((nsid++))
- ip -netns ${n} link set lo up
-}
-
-
setup_v6() {
- create_ns me
- create_ns peer
+ setup_ns me peer
- IP="ip -netns me"
+ IP="ip -netns ${me}"
$IP li add veth1 type veth peer name veth2
$IP li set veth1 up
$IP -6 addr add $V6_ADDR0/64 dev veth1 nodad
- $IP li set veth2 netns peer up
- ip -netns peer -6 addr add $V6_ADDR1/64 dev veth2 nodad
+ $IP li set veth2 netns ${peer} up
+ ip -netns ${peer} -6 addr add $V6_ADDR1/64 dev veth2 nodad
- ip netns exec me sysctl -w $1 >/dev/null 2>&1
+ ip netns exec ${me} sysctl -w $1 >/dev/null 2>&1
# Establish an ND cache entry
- ip netns exec me ping -6 -c1 -Iveth1 $V6_ADDR1 >/dev/null 2>&1
+ ip netns exec ${me} ping -6 -c1 -Iveth1 $V6_ADDR1 >/dev/null 2>&1
# Should have the veth1 entry in ND table
- ip netns exec me ip -6 neigh get $V6_ADDR1 dev veth1 >/dev/null 2>&1
+ ip netns exec ${me} ip -6 neigh get $V6_ADDR1 dev veth1 >/dev/null 2>&1
if [ $? -ne 0 ]; then
cleanup_v6
echo "failed"
@@ -66,11 +53,11 @@ setup_v6() {
fi
# Set veth2 down, which will put veth1 in NOCARRIER state
- ip netns exec peer ip link set veth2 down
+ ip netns exec ${peer} ip link set veth2 down
}
setup_v4() {
- ip netns add "${PEER_NS}"
+ setup_ns PEER_NS
ip link add name veth0 type veth peer name veth1
ip link set dev veth0 up
ip link set dev veth1 netns "${PEER_NS}"
@@ -99,8 +86,7 @@ setup_v4() {
cleanup_v4() {
ip neigh flush dev veth0
ip link del veth0
- local -r ns="$(ip netns list|grep $PEER_NS)"
- [ -n "$ns" ] && ip netns del $ns 2>/dev/null
+ cleanup_ns $PEER_NS
sysctl -w net.ipv4.conf.veth0.arp_evict_nocarrier=1 >/dev/null 2>&1
sysctl -w net.ipv4.conf.all.arp_evict_nocarrier=1 >/dev/null 2>&1
@@ -163,7 +149,7 @@ run_ndisc_evict_nocarrier_enabled() {
setup_v6 "net.ipv6.conf.veth1.ndisc_evict_nocarrier=1"
- ip netns exec me ip -6 neigh get $V6_ADDR1 dev veth1 >/dev/null 2>&1
+ ip netns exec ${me} ip -6 neigh get $V6_ADDR1 dev veth1 >/dev/null 2>&1
if [ $? -eq 0 ];then
echo "failed"
@@ -180,7 +166,7 @@ run_ndisc_evict_nocarrier_disabled() {
setup_v6 "net.ipv6.conf.veth1.ndisc_evict_nocarrier=0"
- ip netns exec me ip -6 neigh get $V6_ADDR1 dev veth1 >/dev/null 2>&1
+ ip netns exec ${me} ip -6 neigh get $V6_ADDR1 dev veth1 >/dev/null 2>&1
if [ $? -eq 0 ];then
echo "ok"
@@ -197,7 +183,7 @@ run_ndisc_evict_nocarrier_disabled_all() {
setup_v6 "net.ipv6.conf.all.ndisc_evict_nocarrier=0"
- ip netns exec me ip -6 neigh get $V6_ADDR1 dev veth1 >/dev/null 2>&1
+ ip netns exec ${me} ip -6 neigh get $V6_ADDR1 dev veth1 >/dev/null 2>&1
if [ $? -eq 0 ];then
echo "ok"
diff --git a/tools/testing/selftests/net/arp_ndisc_untracked_subnets.sh b/tools/testing/selftests/net/arp_ndisc_untracked_subnets.sh
index c899b446acb6..a40c0e9bd023 100755
--- a/tools/testing/selftests/net/arp_ndisc_untracked_subnets.sh
+++ b/tools/testing/selftests/net/arp_ndisc_untracked_subnets.sh
@@ -5,16 +5,14 @@
# garp to the router. Router accepts or ignores based on its arp_accept
# or accept_untracked_na configuration.
+source lib.sh
+
TESTS="arp ndisc"
-ROUTER_NS="ns-router"
-ROUTER_NS_V6="ns-router-v6"
ROUTER_INTF="veth-router"
ROUTER_ADDR="10.0.10.1"
ROUTER_ADDR_V6="2001:db8:abcd:0012::1"
-HOST_NS="ns-host"
-HOST_NS_V6="ns-host-v6"
HOST_INTF="veth-host"
HOST_ADDR="10.0.10.2"
HOST_ADDR_V6="2001:db8:abcd:0012::2"
@@ -23,13 +21,11 @@ SUBNET_WIDTH=24
PREFIX_WIDTH_V6=64
cleanup() {
- ip netns del ${HOST_NS}
- ip netns del ${ROUTER_NS}
+ cleanup_ns ${HOST_NS} ${ROUTER_NS}
}
cleanup_v6() {
- ip netns del ${HOST_NS_V6}
- ip netns del ${ROUTER_NS_V6}
+ cleanup_ns ${HOST_NS_V6} ${ROUTER_NS_V6}
}
setup() {
@@ -37,8 +33,7 @@ setup() {
local arp_accept=$1
# Set up two namespaces
- ip netns add ${ROUTER_NS}
- ip netns add ${HOST_NS}
+ setup_ns HOST_NS ROUTER_NS
# Set up interfaces veth0 and veth1, which are pairs in separate
# namespaces. veth0 is veth-router, veth1 is veth-host.
@@ -72,8 +67,7 @@ setup_v6() {
local accept_untracked_na=$1
# Set up two namespaces
- ip netns add ${ROUTER_NS_V6}
- ip netns add ${HOST_NS_V6}
+ setup_ns HOST_NS_V6 ROUTER_NS_V6
# Set up interfaces veth0 and veth1, which are pairs in separate
# namespaces. veth0 is veth-router, veth1 is veth-host.
@@ -150,7 +144,7 @@ arp_test_gratuitous() {
fi
# Supply arp_accept option to set up which sets it in sysctl
setup ${arp_accept}
- ip netns exec ${HOST_NS} arping -A -U ${HOST_ADDR} -c1 2>&1 >/dev/null
+ ip netns exec ${HOST_NS} arping -A -I ${HOST_INTF} -U ${HOST_ADDR} -c1 2>&1 >/dev/null
if verify_arp $1 $2; then
printf " TEST: %-60s [ OK ]\n" "${test_msg[*]}"
diff --git a/tools/testing/selftests/net/cmsg_ipv6.sh b/tools/testing/selftests/net/cmsg_ipv6.sh
index 330d0b1ceced..f30bd57d5e38 100755
--- a/tools/testing/selftests/net/cmsg_ipv6.sh
+++ b/tools/testing/selftests/net/cmsg_ipv6.sh
@@ -1,9 +1,8 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
-ksft_skip=4
+source lib.sh
-NS=ns
IP6=2001:db8:1::1/64
TGT6=2001:db8:1::2
TMPF=$(mktemp --suffix ".pcap")
@@ -11,13 +10,11 @@ TMPF=$(mktemp --suffix ".pcap")
cleanup()
{
rm -f $TMPF
- ip netns del $NS
+ cleanup_ns $NS
}
trap cleanup EXIT
-NSEXE="ip netns exec $NS"
-
tcpdump -h | grep immediate-mode >> /dev/null
if [ $? -ne 0 ]; then
echo "SKIP - tcpdump with --immediate-mode option required"
@@ -25,7 +22,8 @@ if [ $? -ne 0 ]; then
fi
# Namespaces
-ip netns add $NS
+setup_ns NS
+NSEXE="ip netns exec $NS"
$NSEXE sysctl -w net.ipv4.ping_group_range='0 2147483647' > /dev/null
diff --git a/tools/testing/selftests/net/cmsg_sender.c b/tools/testing/selftests/net/cmsg_sender.c
index 8d7575389f58..c79e65581dc3 100644
--- a/tools/testing/selftests/net/cmsg_sender.c
+++ b/tools/testing/selftests/net/cmsg_sender.c
@@ -428,9 +428,9 @@ int main(int argc, char *argv[])
{
struct addrinfo hints, *ai;
struct iovec iov[1];
+ unsigned char *buf;
struct msghdr msg;
char cbuf[1024];
- char *buf;
int err;
int fd;
int i;
diff --git a/tools/testing/selftests/net/cmsg_so_mark.sh b/tools/testing/selftests/net/cmsg_so_mark.sh
index 1650b8622f2f..772ad0cc2630 100755
--- a/tools/testing/selftests/net/cmsg_so_mark.sh
+++ b/tools/testing/selftests/net/cmsg_so_mark.sh
@@ -1,7 +1,8 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
-NS=ns
+source lib.sh
+
IP4=172.16.0.1/24
TGT4=172.16.0.2
IP6=2001:db8:1::1/64
@@ -10,13 +11,13 @@ MARK=1000
cleanup()
{
- ip netns del $NS
+ cleanup_ns $NS
}
trap cleanup EXIT
# Namespaces
-ip netns add $NS
+setup_ns NS
ip netns exec $NS sysctl -w net.ipv4.ping_group_range='0 2147483647' > /dev/null
diff --git a/tools/testing/selftests/net/cmsg_time.sh b/tools/testing/selftests/net/cmsg_time.sh
index 91161e1da734..af85267ad1e3 100755
--- a/tools/testing/selftests/net/cmsg_time.sh
+++ b/tools/testing/selftests/net/cmsg_time.sh
@@ -1,7 +1,8 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
-NS=ns
+source lib.sh
+
IP4=172.16.0.1/24
TGT4=172.16.0.2
IP6=2001:db8:1::1/64
@@ -9,13 +10,13 @@ TGT6=2001:db8:1::2
cleanup()
{
- ip netns del $NS
+ cleanup_ns $NS
}
trap cleanup EXIT
# Namespaces
-ip netns add $NS
+setup_ns NS
ip netns exec $NS sysctl -w net.ipv4.ping_group_range='0 2147483647' > /dev/null
diff --git a/tools/testing/selftests/net/drop_monitor_tests.sh b/tools/testing/selftests/net/drop_monitor_tests.sh
index b7650e30d18b..7c4818c971fc 100755
--- a/tools/testing/selftests/net/drop_monitor_tests.sh
+++ b/tools/testing/selftests/net/drop_monitor_tests.sh
@@ -2,10 +2,8 @@
# SPDX-License-Identifier: GPL-2.0
# This test is for checking drop monitor functionality.
-
+source lib.sh
ret=0
-# Kselftest framework requirement - SKIP code is 4.
-ksft_skip=4
# all tests in this script. Can be overridden with -t option
TESTS="
@@ -13,10 +11,6 @@ TESTS="
hw_drops
"
-IP="ip -netns ns1"
-TC="tc -netns ns1"
-DEVLINK="devlink -N ns1"
-NS_EXEC="ip netns exec ns1"
NETDEVSIM_PATH=/sys/bus/netdevsim/
DEV_ADDR=1337
DEV=netdevsim${DEV_ADDR}
@@ -43,7 +37,7 @@ setup()
modprobe netdevsim &> /dev/null
set -e
- ip netns add ns1
+ setup_ns NS1
$IP link add dummy10 up type dummy
$NS_EXEC echo "$DEV_ADDR 1" > ${NETDEVSIM_PATH}/new_device
@@ -57,7 +51,7 @@ setup()
cleanup()
{
$NS_EXEC echo "$DEV_ADDR" > ${NETDEVSIM_PATH}/del_device
- ip netns del ns1
+ cleanup_ns ${NS1}
}
sw_drops_test()
@@ -194,8 +188,15 @@ if [ $? -ne 0 ]; then
exit $ksft_skip
fi
-# start clean
+# create netns first so we can get the namespace name
+setup_ns NS1
cleanup &> /dev/null
+trap cleanup EXIT
+
+IP="ip -netns ${NS1}"
+TC="tc -netns ${NS1}"
+DEVLINK="devlink -N ${NS1}"
+NS_EXEC="ip netns exec ${NS1}"
for t in $TESTS
do
diff --git a/tools/testing/selftests/net/fcnal-test.sh b/tools/testing/selftests/net/fcnal-test.sh
index d32a14ba069a..0d4f252427e2 100755
--- a/tools/testing/selftests/net/fcnal-test.sh
+++ b/tools/testing/selftests/net/fcnal-test.sh
@@ -37,9 +37,7 @@
#
# server / client nomenclature relative to ns-A
-# Kselftest framework requirement - SKIP code is 4.
-ksft_skip=4
-
+source lib.sh
VERBOSE=0
NSA_DEV=eth1
@@ -82,14 +80,6 @@ MCAST=ff02::1
NSA_LINKIP6=
NSB_LINKIP6=
-NSA=ns-A
-NSB=ns-B
-NSC=ns-C
-
-NSA_CMD="ip netns exec ${NSA}"
-NSB_CMD="ip netns exec ${NSB}"
-NSC_CMD="ip netns exec ${NSC}"
-
which ping6 > /dev/null 2>&1 && ping6=$(which ping6) || ping6=$(which ping)
# Check if FIPS mode is enabled
@@ -406,9 +396,6 @@ create_ns()
local addr=$2
local addr6=$3
- ip netns add ${ns}
-
- ip -netns ${ns} link set lo up
if [ "${addr}" != "-" ]; then
ip -netns ${ns} addr add dev lo ${addr}
fi
@@ -467,13 +454,12 @@ cleanup()
ip -netns ${NSA} link del dev ${NSA_DEV}
ip netns pids ${NSA} | xargs kill 2>/dev/null
- ip netns del ${NSA}
+ cleanup_ns ${NSA}
fi
ip netns pids ${NSB} | xargs kill 2>/dev/null
- ip netns del ${NSB}
ip netns pids ${NSC} | xargs kill 2>/dev/null
- ip netns del ${NSC} >/dev/null 2>&1
+ cleanup_ns ${NSB} ${NSC}
}
cleanup_vrf_dup()
@@ -487,6 +473,8 @@ setup_vrf_dup()
{
# some VRF tests use ns-C which has the same config as
# ns-B but for a device NOT in the VRF
+ setup_ns NSC
+ NSC_CMD="ip netns exec ${NSC}"
create_ns ${NSC} "-" "-"
connect_ns ${NSA} ${NSA_DEV2} ${NSA_IP}/24 ${NSA_IP6}/64 \
${NSC} ${NSC_DEV} ${NSB_IP}/24 ${NSB_IP6}/64
@@ -503,6 +491,10 @@ setup()
log_debug "Configuring network namespaces"
set -e
+ setup_ns NSA NSB
+ NSA_CMD="ip netns exec ${NSA}"
+ NSB_CMD="ip netns exec ${NSB}"
+
create_ns ${NSA} ${NSA_LO_IP}/32 ${NSA_LO_IP6}/128
create_ns ${NSB} ${NSB_LO_IP}/32 ${NSB_LO_IP6}/128
connect_ns ${NSA} ${NSA_DEV} ${NSA_IP}/24 ${NSA_IP6}/64 \
@@ -545,6 +537,10 @@ setup_lla_only()
log_debug "Configuring network namespaces"
set -e
+ setup_ns NSA NSB NSC
+ NSA_CMD="ip netns exec ${NSA}"
+ NSB_CMD="ip netns exec ${NSB}"
+ NSC_CMD="ip netns exec ${NSC}"
create_ns ${NSA} "-" "-"
create_ns ${NSB} "-" "-"
create_ns ${NSC} "-" "-"
diff --git a/tools/testing/selftests/net/fdb_flush.sh b/tools/testing/selftests/net/fdb_flush.sh
index 90e7a29e0476..d5e3abb8658c 100755
--- a/tools/testing/selftests/net/fdb_flush.sh
+++ b/tools/testing/selftests/net/fdb_flush.sh
@@ -5,6 +5,8 @@
# Check that flush works as expected with all the supported arguments and verify
# some combinations of arguments.
+source lib.sh
+
FLUSH_BY_STATE_TESTS="
vxlan_test_flush_by_permanent
vxlan_test_flush_by_nopermanent
@@ -739,10 +741,9 @@ bridge_vxlan_test_flush()
setup()
{
- IP="ip -netns ns1"
- BRIDGE="bridge -netns ns1"
-
- ip netns add ns1
+ setup_ns NS
+ IP="ip -netns ${NS}"
+ BRIDGE="bridge -netns ${NS}"
$IP link add name vx10 type vxlan id 1000 dstport "$VXPORT"
$IP link add name vx20 type vxlan id 2000 dstport "$VXPORT"
@@ -759,7 +760,7 @@ cleanup()
$IP link del dev vx20
$IP link del dev vx10
- ip netns del ns1
+ cleanup_ns ${NS}
}
################################################################################
diff --git a/tools/testing/selftests/net/fib-onlink-tests.sh b/tools/testing/selftests/net/fib-onlink-tests.sh
index c287b90b8af8..ec2d6ceb1f08 100755
--- a/tools/testing/selftests/net/fib-onlink-tests.sh
+++ b/tools/testing/selftests/net/fib-onlink-tests.sh
@@ -3,6 +3,7 @@
# IPv4 and IPv6 onlink tests
+source lib.sh
PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no}
VERBOSE=0
@@ -74,9 +75,6 @@ TEST_NET4IN6[2]=10.2.1.254
# mcast address
MCAST6=ff02::1
-
-PEER_NS=bart
-PEER_CMD="ip netns exec ${PEER_NS}"
VRF=lisa
VRF_TABLE=1101
PBR_TABLE=101
@@ -176,8 +174,7 @@ setup()
set -e
# create namespace
- ip netns add ${PEER_NS}
- ip -netns ${PEER_NS} li set lo up
+ setup_ns PEER_NS
# add vrf table
ip li add ${VRF} type vrf table ${VRF_TABLE}
@@ -219,7 +216,7 @@ setup()
cleanup()
{
# make sure we start from a clean slate
- ip netns del ${PEER_NS} 2>/dev/null
+ cleanup_ns ${PEER_NS} 2>/dev/null
for n in 1 3 5 7; do
ip link del ${NETIFS[p${n}]} 2>/dev/null
done
diff --git a/tools/testing/selftests/net/fib_nexthop_multiprefix.sh b/tools/testing/selftests/net/fib_nexthop_multiprefix.sh
index 51df5e305855..e85248609af4 100755
--- a/tools/testing/selftests/net/fib_nexthop_multiprefix.sh
+++ b/tools/testing/selftests/net/fib_nexthop_multiprefix.sh
@@ -12,6 +12,7 @@
#
# routing in h0 to hN is done with nexthop objects.
+source lib.sh
PAUSE_ON_FAIL=no
VERBOSE=0
@@ -72,12 +73,6 @@ create_ns()
{
local ns=${1}
- ip netns del ${ns} 2>/dev/null
-
- ip netns add ${ns}
- ip -netns ${ns} addr add 127.0.0.1/8 dev lo
- ip -netns ${ns} link set lo up
-
ip netns exec ${ns} sysctl -q -w net.ipv6.conf.all.keep_addr_on_down=1
case ${ns} in
h*)
@@ -97,7 +92,13 @@ setup()
#set -e
- for ns in h0 r1 h1 h2 h3
+ setup_ns h0 r1 h1 h2 h3
+ h[0]=$h0
+ h[1]=$h1
+ h[2]=$h2
+ h[3]=$h3
+ r[1]=$r1
+ for ns in ${h[0]} ${r[1]} ${h[1]} ${h[2]} ${h[3]}
do
create_ns ${ns}
done
@@ -108,35 +109,35 @@ setup()
for i in 0 1 2 3
do
- ip -netns h${i} li add eth0 type veth peer name r1h${i}
- ip -netns h${i} li set eth0 up
- ip -netns h${i} li set r1h${i} netns r1 name eth${i} up
-
- ip -netns h${i} addr add dev eth0 172.16.10${i}.1/24
- ip -netns h${i} -6 addr add dev eth0 2001:db8:10${i}::1/64
- ip -netns r1 addr add dev eth${i} 172.16.10${i}.254/24
- ip -netns r1 -6 addr add dev eth${i} 2001:db8:10${i}::64/64
+ ip -netns ${h[$i]} li add eth0 type veth peer name r1h${i}
+ ip -netns ${h[$i]} li set eth0 up
+ ip -netns ${h[$i]} li set r1h${i} netns ${r[1]} name eth${i} up
+
+ ip -netns ${h[$i]} addr add dev eth0 172.16.10${i}.1/24
+ ip -netns ${h[$i]} -6 addr add dev eth0 2001:db8:10${i}::1/64
+ ip -netns ${r[1]} addr add dev eth${i} 172.16.10${i}.254/24
+ ip -netns ${r[1]} -6 addr add dev eth${i} 2001:db8:10${i}::64/64
done
- ip -netns h0 nexthop add id 4 via 172.16.100.254 dev eth0
- ip -netns h0 nexthop add id 6 via 2001:db8:100::64 dev eth0
+ ip -netns ${h[0]} nexthop add id 4 via 172.16.100.254 dev eth0
+ ip -netns ${h[0]} nexthop add id 6 via 2001:db8:100::64 dev eth0
- # routing from h0 to h1-h3 and back
+ # routing from ${h[0]} to h1-h3 and back
for i in 1 2 3
do
- ip -netns h0 ro add 172.16.10${i}.0/24 nhid 4
- ip -netns h${i} ro add 172.16.100.0/24 via 172.16.10${i}.254
+ ip -netns ${h[0]} ro add 172.16.10${i}.0/24 nhid 4
+ ip -netns ${h[$i]} ro add 172.16.100.0/24 via 172.16.10${i}.254
- ip -netns h0 -6 ro add 2001:db8:10${i}::/64 nhid 6
- ip -netns h${i} -6 ro add 2001:db8:100::/64 via 2001:db8:10${i}::64
+ ip -netns ${h[0]} -6 ro add 2001:db8:10${i}::/64 nhid 6
+ ip -netns ${h[$i]} -6 ro add 2001:db8:100::/64 via 2001:db8:10${i}::64
done
if [ "$VERBOSE" = "1" ]; then
echo
echo "host 1 config"
- ip -netns h0 li sh
- ip -netns h0 ro sh
- ip -netns h0 -6 ro sh
+ ip -netns ${h[0]} li sh
+ ip -netns ${h[0]} ro sh
+ ip -netns ${h[0]} -6 ro sh
fi
#set +e
@@ -144,10 +145,7 @@ setup()
cleanup()
{
- for n in h0 r1 h1 h2 h3
- do
- ip netns del ${n} 2>/dev/null
- done
+ cleanup_all_ns
}
change_mtu()
@@ -156,7 +154,7 @@ change_mtu()
local mtu=$2
run_cmd ip -netns h${hostid} li set eth0 mtu ${mtu}
- run_cmd ip -netns r1 li set eth${hostid} mtu ${mtu}
+ run_cmd ip -netns ${r1} li set eth${hostid} mtu ${mtu}
}
################################################################################
@@ -168,23 +166,23 @@ validate_v4_exception()
local mtu=$2
local ping_sz=$3
local dst="172.16.10${i}.1"
- local h0=172.16.100.1
- local r1=172.16.100.254
+ local h0_ip=172.16.100.1
+ local r1_ip=172.16.100.254
local rc
if [ ${ping_sz} != "0" ]; then
- run_cmd ip netns exec h0 ping -s ${ping_sz} -c5 -w5 ${dst}
+ run_cmd ip netns exec ${h0} ping -s ${ping_sz} -c5 -w5 ${dst}
fi
if [ "$VERBOSE" = "1" ]; then
echo "Route get"
- ip -netns h0 ro get ${dst}
+ ip -netns ${h0} ro get ${dst}
echo "Searching for:"
echo " cache .* mtu ${mtu}"
echo
fi
- ip -netns h0 ro get ${dst} | \
+ ip -netns ${h0} ro get ${dst} | \
grep -q "cache .* mtu ${mtu}"
rc=$?
@@ -197,24 +195,24 @@ validate_v6_exception()
local mtu=$2
local ping_sz=$3
local dst="2001:db8:10${i}::1"
- local h0=2001:db8:100::1
- local r1=2001:db8:100::64
+ local h0_ip=2001:db8:100::1
+ local r1_ip=2001:db8:100::64
local rc
if [ ${ping_sz} != "0" ]; then
- run_cmd ip netns exec h0 ${ping6} -s ${ping_sz} -c5 -w5 ${dst}
+ run_cmd ip netns exec ${h0} ${ping6} -s ${ping_sz} -c5 -w5 ${dst}
fi
if [ "$VERBOSE" = "1" ]; then
echo "Route get"
- ip -netns h0 -6 ro get ${dst}
+ ip -netns ${h0} -6 ro get ${dst}
echo "Searching for:"
- echo " ${dst} from :: via ${r1} dev eth0 src ${h0} .* mtu ${mtu}"
+ echo " ${dst}.* via ${r1_ip} dev eth0 src ${h0_ip} .* mtu ${mtu}"
echo
fi
- ip -netns h0 -6 ro get ${dst} | \
- grep -q "${dst} from :: via ${r1} dev eth0 src ${h0} .* mtu ${mtu}"
+ ip -netns ${h0} -6 ro get ${dst} | \
+ grep -q "${dst}.* via ${r1_ip} dev eth0 src ${h0_ip} .* mtu ${mtu}"
rc=$?
log_test $rc 0 "IPv6: host 0 to host ${i}, mtu ${mtu}"
@@ -242,11 +240,11 @@ for i in 1 2 3
do
# generate a cached route per-cpu
for c in ${cpus}; do
- run_cmd taskset -c ${c} ip netns exec h0 ping -c1 -w1 172.16.10${i}.1
- [ $? -ne 0 ] && printf "\nERROR: ping to h${i} failed\n" && ret=1
+ run_cmd taskset -c ${c} ip netns exec ${h0} ping -c1 -w1 172.16.10${i}.1
+ [ $? -ne 0 ] && printf "\nERROR: ping to ${h[$i]} failed\n" && ret=1
- run_cmd taskset -c ${c} ip netns exec h0 ${ping6} -c1 -w1 2001:db8:10${i}::1
- [ $? -ne 0 ] && printf "\nERROR: ping6 to h${i} failed\n" && ret=1
+ run_cmd taskset -c ${c} ip netns exec ${h0} ${ping6} -c1 -w1 2001:db8:10${i}::1
+ [ $? -ne 0 ] && printf "\nERROR: ping6 to ${h[$i]} failed\n" && ret=1
[ $ret -ne 0 ] && break
done
@@ -282,11 +280,11 @@ if [ $ret -eq 0 ]; then
validate_v6_exception 3 1400 0
# targeted deletes to trigger cleanup paths in kernel
- ip -netns h0 ro del 172.16.102.0/24 nhid 4
- ip -netns h0 -6 ro del 2001:db8:102::/64 nhid 6
+ ip -netns ${h0} ro del 172.16.102.0/24 nhid 4
+ ip -netns ${h0} -6 ro del 2001:db8:102::/64 nhid 6
- ip -netns h0 nexthop del id 4
- ip -netns h0 nexthop del id 6
+ ip -netns ${h0} nexthop del id 4
+ ip -netns ${h0} nexthop del id 6
fi
cleanup
diff --git a/tools/testing/selftests/net/fib_nexthop_nongw.sh b/tools/testing/selftests/net/fib_nexthop_nongw.sh
index b7b928b38ce4..1ccf56f10171 100755
--- a/tools/testing/selftests/net/fib_nexthop_nongw.sh
+++ b/tools/testing/selftests/net/fib_nexthop_nongw.sh
@@ -8,6 +8,7 @@
# veth0 <---|---> veth1
# Validate source address selection for route without gateway
+source lib.sh
PAUSE_ON_FAIL=no
VERBOSE=0
ret=0
@@ -64,35 +65,31 @@ run_cmd()
# config
setup()
{
- ip netns add h1
- ip -n h1 link set lo up
- ip netns add h2
- ip -n h2 link set lo up
+ setup_ns h1 h2
# Add a fake eth0 to support an ip address
- ip -n h1 link add name eth0 type dummy
- ip -n h1 link set eth0 up
- ip -n h1 address add 192.168.0.1/24 dev eth0
+ ip -n $h1 link add name eth0 type dummy
+ ip -n $h1 link set eth0 up
+ ip -n $h1 address add 192.168.0.1/24 dev eth0
# Configure veths (same @mac, arp off)
- ip -n h1 link add name veth0 type veth peer name veth1 netns h2
- ip -n h1 link set veth0 up
+ ip -n $h1 link add name veth0 type veth peer name veth1 netns $h2
+ ip -n $h1 link set veth0 up
- ip -n h2 link set veth1 up
+ ip -n $h2 link set veth1 up
# Configure @IP in the peer netns
- ip -n h2 address add 192.168.1.1/32 dev veth1
- ip -n h2 route add default dev veth1
+ ip -n $h2 address add 192.168.1.1/32 dev veth1
+ ip -n $h2 route add default dev veth1
# Add a nexthop without @gw and use it in a route
- ip -n h1 nexthop add id 1 dev veth0
- ip -n h1 route add 192.168.1.1 nhid 1
+ ip -n $h1 nexthop add id 1 dev veth0
+ ip -n $h1 route add 192.168.1.1 nhid 1
}
cleanup()
{
- ip netns del h1 2>/dev/null
- ip netns del h2 2>/dev/null
+ cleanup_ns $h1 $h2
}
trap cleanup EXIT
@@ -108,12 +105,11 @@ do
esac
done
-cleanup
setup
-run_cmd ip -netns h1 route get 192.168.1.1
+run_cmd ip -netns $h1 route get 192.168.1.1
log_test $? 0 "nexthop: get route with nexthop without gw"
-run_cmd ip netns exec h1 ping -c1 192.168.1.1
+run_cmd ip netns exec $h1 ping -c1 192.168.1.1
log_test $? 0 "nexthop: ping through nexthop without gw"
exit $ret
diff --git a/tools/testing/selftests/net/fib_nexthops.sh b/tools/testing/selftests/net/fib_nexthops.sh
index a6f2c0b9555d..d5a281aadbac 100755
--- a/tools/testing/selftests/net/fib_nexthops.sh
+++ b/tools/testing/selftests/net/fib_nexthops.sh
@@ -14,6 +14,7 @@
# objects. Device reference counts and network namespace cleanup tested
# by use of network namespace for peer.
+source lib.sh
ret=0
# Kselftest framework requirement - SKIP code is 4.
ksft_skip=4
@@ -148,13 +149,7 @@ create_ns()
{
local n=${1}
- ip netns del ${n} 2>/dev/null
-
set -e
- ip netns add ${n}
- ip netns set ${n} $((nsid++))
- ip -netns ${n} addr add 127.0.0.1/8 dev lo
- ip -netns ${n} link set lo up
ip netns exec ${n} sysctl -qw net.ipv4.ip_forward=1
ip netns exec ${n} sysctl -qw net.ipv4.fib_multipath_use_neigh=1
@@ -173,12 +168,13 @@ setup()
{
cleanup
- create_ns me
- create_ns peer
- create_ns remote
+ setup_ns me peer remote
+ create_ns $me
+ create_ns $peer
+ create_ns $remote
- IP="ip -netns me"
- BRIDGE="bridge -netns me"
+ IP="ip -netns $me"
+ BRIDGE="bridge -netns $me"
set -e
$IP li add veth1 type veth peer name veth2
$IP li set veth1 up
@@ -190,24 +186,24 @@ setup()
$IP addr add 172.16.2.1/24 dev veth3
$IP -6 addr add 2001:db8:92::1/64 dev veth3 nodad
- $IP li set veth2 netns peer up
- ip -netns peer addr add 172.16.1.2/24 dev veth2
- ip -netns peer -6 addr add 2001:db8:91::2/64 dev veth2 nodad
+ $IP li set veth2 netns $peer up
+ ip -netns $peer addr add 172.16.1.2/24 dev veth2
+ ip -netns $peer -6 addr add 2001:db8:91::2/64 dev veth2 nodad
- $IP li set veth4 netns peer up
- ip -netns peer addr add 172.16.2.2/24 dev veth4
- ip -netns peer -6 addr add 2001:db8:92::2/64 dev veth4 nodad
+ $IP li set veth4 netns $peer up
+ ip -netns $peer addr add 172.16.2.2/24 dev veth4
+ ip -netns $peer -6 addr add 2001:db8:92::2/64 dev veth4 nodad
- ip -netns remote li add veth5 type veth peer name veth6
- ip -netns remote li set veth5 up
- ip -netns remote addr add dev veth5 172.16.101.1/24
- ip -netns remote -6 addr add dev veth5 2001:db8:101::1/64 nodad
- ip -netns remote ro add 172.16.0.0/22 via 172.16.101.2
- ip -netns remote -6 ro add 2001:db8:90::/40 via 2001:db8:101::2
+ ip -netns $remote li add veth5 type veth peer name veth6
+ ip -netns $remote li set veth5 up
+ ip -netns $remote addr add dev veth5 172.16.101.1/24
+ ip -netns $remote -6 addr add dev veth5 2001:db8:101::1/64 nodad
+ ip -netns $remote ro add 172.16.0.0/22 via 172.16.101.2
+ ip -netns $remote -6 ro add 2001:db8:90::/40 via 2001:db8:101::2
- ip -netns remote li set veth6 netns peer up
- ip -netns peer addr add dev veth6 172.16.101.2/24
- ip -netns peer -6 addr add dev veth6 2001:db8:101::2/64 nodad
+ ip -netns $remote li set veth6 netns $peer up
+ ip -netns $peer addr add dev veth6 172.16.101.2/24
+ ip -netns $peer -6 addr add dev veth6 2001:db8:101::2/64 nodad
set +e
}
@@ -215,7 +211,7 @@ cleanup()
{
local ns
- for ns in me peer remote; do
+ for ns in $me $peer $remote; do
ip netns del ${ns} 2>/dev/null
done
}
@@ -779,7 +775,7 @@ ipv6_grp_refs()
run_cmd "$IP route add 2001:db8:101::1/128 nhid 102"
# create per-cpu dsts through nh 100
- run_cmd "ip netns exec me mausezahn -6 veth1.10 -B 2001:db8:101::1 -A 2001:db8:91::1 -c 5 -t tcp "dp=1-1023, flags=syn" >/dev/null 2>&1"
+ run_cmd "ip netns exec $me mausezahn -6 veth1.10 -B 2001:db8:101::1 -A 2001:db8:91::1 -c 5 -t tcp "dp=1-1023, flags=syn" >/dev/null 2>&1"
# remove nh 100 from the group to delete the route potentially leaving
# a stale per-cpu dst which holds a reference to the nexthop's net
@@ -805,7 +801,7 @@ ipv6_grp_refs()
# if a reference was lost this command will hang because the net device
# cannot be removed
- timeout -s KILL 5 ip netns exec me ip link del veth1.10 >/dev/null 2>&1
+ timeout -s KILL 5 ip netns exec $me ip link del veth1.10 >/dev/null 2>&1
# we can't cleanup if the command is hung trying to delete the netdev
if [ $? -eq 137 ]; then
@@ -1012,13 +1008,13 @@ ipv6_fcnal_runtime()
log_test $? 0 "Route delete"
run_cmd "$IP ro add 2001:db8:101::1/128 nhid 81"
- run_cmd "ip netns exec me ping -c1 -w$PING_TIMEOUT 2001:db8:101::1"
+ run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 2001:db8:101::1"
log_test $? 0 "Ping with nexthop"
run_cmd "$IP nexthop add id 82 via 2001:db8:92::2 dev veth3"
run_cmd "$IP nexthop add id 122 group 81/82"
run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 122"
- run_cmd "ip netns exec me ping -c1 -w$PING_TIMEOUT 2001:db8:101::1"
+ run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 2001:db8:101::1"
log_test $? 0 "Ping - multipath"
#
@@ -1026,26 +1022,26 @@ ipv6_fcnal_runtime()
#
run_cmd "$IP -6 nexthop add id 83 blackhole"
run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 83"
- run_cmd "ip netns exec me ping -c1 -w$PING_TIMEOUT 2001:db8:101::1"
+ run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 2001:db8:101::1"
log_test $? 2 "Ping - blackhole"
run_cmd "$IP nexthop replace id 83 via 2001:db8:91::2 dev veth1"
- run_cmd "ip netns exec me ping -c1 -w$PING_TIMEOUT 2001:db8:101::1"
+ run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 2001:db8:101::1"
log_test $? 0 "Ping - blackhole replaced with gateway"
run_cmd "$IP -6 nexthop replace id 83 blackhole"
- run_cmd "ip netns exec me ping -c1 -w$PING_TIMEOUT 2001:db8:101::1"
+ run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 2001:db8:101::1"
log_test $? 2 "Ping - gateway replaced by blackhole"
run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 122"
- run_cmd "ip netns exec me ping -c1 -w$PING_TIMEOUT 2001:db8:101::1"
+ run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 2001:db8:101::1"
if [ $? -eq 0 ]; then
run_cmd "$IP nexthop replace id 122 group 83"
- run_cmd "ip netns exec me ping -c1 -w$PING_TIMEOUT 2001:db8:101::1"
+ run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 2001:db8:101::1"
log_test $? 2 "Ping - group with blackhole"
run_cmd "$IP nexthop replace id 122 group 81/82"
- run_cmd "ip netns exec me ping -c1 -w$PING_TIMEOUT 2001:db8:101::1"
+ run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 2001:db8:101::1"
log_test $? 0 "Ping - group blackhole replaced with gateways"
else
log_test 2 0 "Ping - multipath failed"
@@ -1128,15 +1124,15 @@ ipv6_fcnal_runtime()
# rpfilter and default route
$IP nexthop flush >/dev/null 2>&1
- run_cmd "ip netns exec me ip6tables -t mangle -I PREROUTING 1 -m rpfilter --invert -j DROP"
+ run_cmd "ip netns exec $me ip6tables -t mangle -I PREROUTING 1 -m rpfilter --invert -j DROP"
run_cmd "$IP nexthop add id 91 via 2001:db8:91::2 dev veth1"
run_cmd "$IP nexthop add id 92 via 2001:db8:92::2 dev veth3"
run_cmd "$IP nexthop add id 93 group 91/92"
run_cmd "$IP -6 ro add default nhid 91"
- run_cmd "ip netns exec me ping -c1 -w$PING_TIMEOUT 2001:db8:101::1"
+ run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 2001:db8:101::1"
log_test $? 0 "Nexthop with default route and rpfilter"
run_cmd "$IP -6 ro replace default nhid 93"
- run_cmd "ip netns exec me ping -c1 -w$PING_TIMEOUT 2001:db8:101::1"
+ run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 2001:db8:101::1"
log_test $? 0 "Nexthop with multipath default route and rpfilter"
# TO-DO:
@@ -1216,11 +1212,11 @@ ipv6_torture()
pid1=$!
ipv6_grp_replace_loop &
pid2=$!
- ip netns exec me ping -f 2001:db8:101::1 >/dev/null 2>&1 &
+ ip netns exec $me ping -f 2001:db8:101::1 >/dev/null 2>&1 &
pid3=$!
- ip netns exec me ping -f 2001:db8:101::2 >/dev/null 2>&1 &
+ ip netns exec $me ping -f 2001:db8:101::2 >/dev/null 2>&1 &
pid4=$!
- ip netns exec me mausezahn -6 veth1 -B 2001:db8:101::2 -A 2001:db8:91::1 -c 0 -t tcp "dp=1-1023, flags=syn" >/dev/null 2>&1 &
+ ip netns exec $me mausezahn -6 veth1 -B 2001:db8:101::2 -A 2001:db8:91::1 -c 0 -t tcp "dp=1-1023, flags=syn" >/dev/null 2>&1 &
pid5=$!
sleep 300
@@ -1270,11 +1266,11 @@ ipv6_res_torture()
pid1=$!
ipv6_res_grp_replace_loop &
pid2=$!
- ip netns exec me ping -f 2001:db8:101::1 >/dev/null 2>&1 &
+ ip netns exec $me ping -f 2001:db8:101::1 >/dev/null 2>&1 &
pid3=$!
- ip netns exec me ping -f 2001:db8:101::2 >/dev/null 2>&1 &
+ ip netns exec $me ping -f 2001:db8:101::2 >/dev/null 2>&1 &
pid4=$!
- ip netns exec me mausezahn -6 veth1 \
+ ip netns exec $me mausezahn -6 veth1 \
-B 2001:db8:101::2 -A 2001:db8:91::1 -c 0 \
-t tcp "dp=1-1023, flags=syn" >/dev/null 2>&1 &
pid5=$!
@@ -1544,7 +1540,7 @@ ipv4_withv6_fcnal()
local lladdr
set -e
- lladdr=$(get_linklocal veth2 peer)
+ lladdr=$(get_linklocal veth2 $peer)
run_cmd "$IP nexthop add id 11 via ${lladdr} dev veth1"
set +e
run_cmd "$IP ro add 172.16.101.1/32 nhid 11"
@@ -1606,13 +1602,13 @@ ipv4_fcnal_runtime()
#
run_cmd "$IP nexthop replace id 21 via 172.16.1.2 dev veth1"
run_cmd "$IP ro replace 172.16.101.1/32 nhid 21"
- run_cmd "ip netns exec me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
+ run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
log_test $? 0 "Basic ping"
run_cmd "$IP nexthop replace id 22 via 172.16.2.2 dev veth3"
run_cmd "$IP nexthop add id 122 group 21/22"
run_cmd "$IP ro replace 172.16.101.1/32 nhid 122"
- run_cmd "ip netns exec me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
+ run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
log_test $? 0 "Ping - multipath"
run_cmd "$IP ro delete 172.16.101.1/32 nhid 122"
@@ -1623,7 +1619,7 @@ ipv4_fcnal_runtime()
run_cmd "$IP nexthop add id 501 via 172.16.1.2 dev veth1"
run_cmd "$IP ro add default nhid 501"
run_cmd "$IP ro add default via 172.16.1.3 dev veth1 metric 20"
- run_cmd "ip netns exec me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
+ run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
log_test $? 0 "Ping - multiple default routes, nh first"
# flip the order
@@ -1632,7 +1628,7 @@ ipv4_fcnal_runtime()
run_cmd "$IP ro add default via 172.16.1.2 dev veth1 metric 20"
run_cmd "$IP nexthop replace id 501 via 172.16.1.3 dev veth1"
run_cmd "$IP ro add default nhid 501 metric 20"
- run_cmd "ip netns exec me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
+ run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
log_test $? 0 "Ping - multiple default routes, nh second"
run_cmd "$IP nexthop delete nhid 501"
@@ -1643,26 +1639,26 @@ ipv4_fcnal_runtime()
#
run_cmd "$IP nexthop add id 23 blackhole"
run_cmd "$IP ro replace 172.16.101.1/32 nhid 23"
- run_cmd "ip netns exec me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
+ run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
log_test $? 2 "Ping - blackhole"
run_cmd "$IP nexthop replace id 23 via 172.16.1.2 dev veth1"
- run_cmd "ip netns exec me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
+ run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
log_test $? 0 "Ping - blackhole replaced with gateway"
run_cmd "$IP nexthop replace id 23 blackhole"
- run_cmd "ip netns exec me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
+ run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
log_test $? 2 "Ping - gateway replaced by blackhole"
run_cmd "$IP ro replace 172.16.101.1/32 nhid 122"
- run_cmd "ip netns exec me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
+ run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
if [ $? -eq 0 ]; then
run_cmd "$IP nexthop replace id 122 group 23"
- run_cmd "ip netns exec me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
+ run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
log_test $? 2 "Ping - group with blackhole"
run_cmd "$IP nexthop replace id 122 group 21/22"
- run_cmd "ip netns exec me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
+ run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
log_test $? 0 "Ping - group blackhole replaced with gateways"
else
log_test 2 0 "Ping - multipath failed"
@@ -1685,11 +1681,11 @@ ipv4_fcnal_runtime()
# IPv4 with IPv6
#
set -e
- lladdr=$(get_linklocal veth2 peer)
+ lladdr=$(get_linklocal veth2 $peer)
run_cmd "$IP nexthop add id 24 via ${lladdr} dev veth1"
set +e
run_cmd "$IP ro replace 172.16.101.1/32 nhid 24"
- run_cmd "ip netns exec me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
+ run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
log_test $? 0 "IPv6 nexthop with IPv4 route"
$IP neigh sh | grep -q "${lladdr} dev veth1"
@@ -1713,11 +1709,11 @@ ipv4_fcnal_runtime()
check_route "172.16.101.1" "172.16.101.1 nhid 101 nexthop via inet6 ${lladdr} dev veth1 weight 1 nexthop via 172.16.1.2 dev veth1 weight 1"
- run_cmd "ip netns exec me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
+ run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
log_test $? 0 "IPv6 nexthop with IPv4 route"
run_cmd "$IP ro replace 172.16.101.1/32 via inet6 ${lladdr} dev veth1"
- run_cmd "ip netns exec me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
+ run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
log_test $? 0 "IPv4 route with IPv6 gateway"
$IP neigh sh | grep -q "${lladdr} dev veth1"
@@ -1734,7 +1730,7 @@ ipv4_fcnal_runtime()
run_cmd "$IP ro del 172.16.101.1/32 via inet6 ${lladdr} dev veth1"
run_cmd "$IP -4 ro add default via inet6 ${lladdr} dev veth1"
- run_cmd "ip netns exec me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
+ run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
log_test $? 0 "IPv4 default route with IPv6 gateway"
#
@@ -1785,7 +1781,7 @@ sysctl_nexthop_compat_mode_check()
local sysctlname="net.ipv4.nexthop_compat_mode"
local lprefix=$1
- IPE="ip netns exec me"
+ IPE="ip netns exec $me"
$IPE sysctl -q $sysctlname 2>&1 >/dev/null
if [ $? -ne 0 ]; then
@@ -1804,7 +1800,7 @@ sysctl_nexthop_compat_mode_set()
local mode=$1
local lprefix=$2
- IPE="ip netns exec me"
+ IPE="ip netns exec $me"
out=$($IPE sysctl -w $sysctlname=$mode)
log_test $? 0 "$lprefix set compat mode - $mode"
@@ -1988,11 +1984,11 @@ ipv4_torture()
pid1=$!
ipv4_grp_replace_loop &
pid2=$!
- ip netns exec me ping -f 172.16.101.1 >/dev/null 2>&1 &
+ ip netns exec $me ping -f 172.16.101.1 >/dev/null 2>&1 &
pid3=$!
- ip netns exec me ping -f 172.16.101.2 >/dev/null 2>&1 &
+ ip netns exec $me ping -f 172.16.101.2 >/dev/null 2>&1 &
pid4=$!
- ip netns exec me mausezahn veth1 -B 172.16.101.2 -A 172.16.1.1 -c 0 -t tcp "dp=1-1023, flags=syn" >/dev/null 2>&1 &
+ ip netns exec $me mausezahn veth1 -B 172.16.101.2 -A 172.16.1.1 -c 0 -t tcp "dp=1-1023, flags=syn" >/dev/null 2>&1 &
pid5=$!
sleep 300
@@ -2042,11 +2038,11 @@ ipv4_res_torture()
pid1=$!
ipv4_res_grp_replace_loop &
pid2=$!
- ip netns exec me ping -f 172.16.101.1 >/dev/null 2>&1 &
+ ip netns exec $me ping -f 172.16.101.1 >/dev/null 2>&1 &
pid3=$!
- ip netns exec me ping -f 172.16.101.2 >/dev/null 2>&1 &
+ ip netns exec $me ping -f 172.16.101.2 >/dev/null 2>&1 &
pid4=$!
- ip netns exec me mausezahn veth1 \
+ ip netns exec $me mausezahn veth1 \
-B 172.16.101.2 -A 172.16.1.1 -c 0 \
-t tcp "dp=1-1023, flags=syn" >/dev/null 2>&1 &
pid5=$!
@@ -2081,10 +2077,10 @@ basic()
# create nh with linkdown device - fails
$IP li set veth1 up
- ip -netns peer li set veth2 down
+ ip -netns $peer li set veth2 down
run_cmd "$IP nexthop add id 1 dev veth1"
log_test $? 2 "Nexthop with device that is linkdown"
- ip -netns peer li set veth2 up
+ ip -netns $peer li set veth2 up
# device only
run_cmd "$IP nexthop add id 1 dev veth1"
@@ -2465,7 +2461,7 @@ fi
for t in $TESTS
do
case $t in
- none) IP="ip -netns peer"; setup; exit 0;;
+ none) IP="ip -netns $peer"; setup; exit 0;;
*) setup; $t; cleanup;;
esac
done
diff --git a/tools/testing/selftests/net/fib_rule_tests.sh b/tools/testing/selftests/net/fib_rule_tests.sh
index 63c3eaec8d30..51157a5559b7 100755
--- a/tools/testing/selftests/net/fib_rule_tests.sh
+++ b/tools/testing/selftests/net/fib_rule_tests.sh
@@ -3,14 +3,9 @@
# This test is for checking IPv4 and IPv6 FIB rules API
-# Kselftest framework requirement - SKIP code is 4.
-ksft_skip=4
-
+source lib.sh
ret=0
-
PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no}
-IP="ip -netns testns"
-IP_PEER="ip -netns peerns"
RTABLE=100
RTABLE_PEER=101
@@ -84,8 +79,8 @@ check_nettest()
setup()
{
set -e
- ip netns add testns
- $IP link set dev lo up
+ setup_ns testns
+ IP="ip -netns $testns"
$IP link add dummy0 type dummy
$IP link set dev dummy0 up
@@ -98,18 +93,19 @@ setup()
cleanup()
{
$IP link del dev dummy0 &> /dev/null
- ip netns del testns
+ cleanup_ns $testns
}
setup_peer()
{
set -e
- ip netns add peerns
+ setup_ns peerns
+ IP_PEER="ip -netns $peerns"
$IP_PEER link set dev lo up
- ip link add name veth0 netns testns type veth \
- peer name veth1 netns peerns
+ ip link add name veth0 netns $testns type veth \
+ peer name veth1 netns $peerns
$IP link set dev veth0 up
$IP_PEER link set dev veth1 up
@@ -131,7 +127,7 @@ setup_peer()
cleanup_peer()
{
$IP link del dev veth0
- ip netns del peerns
+ ip netns del $peerns
}
fib_check_iproute_support()
@@ -270,11 +266,11 @@ fib_rule6_connect_test()
# (Not-ECT: 0, ECT(1): 1, ECT(0): 2, CE: 3).
# The ECN bits shouldn't influence the result of the test.
for dsfield in 0x04 0x05 0x06 0x07; do
- nettest -q -6 -B -t 5 -N testns -O peerns -U -D \
+ nettest -q -6 -B -t 5 -N $testns -O $peerns -U -D \
-Q "${dsfield}" -l 2001:db8::1:11 -r 2001:db8::1:11
log_test $? 0 "rule6 dsfield udp connect (dsfield ${dsfield})"
- nettest -q -6 -B -t 5 -N testns -O peerns -Q "${dsfield}" \
+ nettest -q -6 -B -t 5 -N $testns -O $peerns -Q "${dsfield}" \
-l 2001:db8::1:11 -r 2001:db8::1:11
log_test $? 0 "rule6 dsfield tcp connect (dsfield ${dsfield})"
done
@@ -337,11 +333,11 @@ fib_rule4_test()
# need enable forwarding and disable rp_filter temporarily as all the
# addresses are in the same subnet and egress device == ingress device.
- ip netns exec testns sysctl -qw net.ipv4.ip_forward=1
- ip netns exec testns sysctl -qw net.ipv4.conf.$DEV.rp_filter=0
+ ip netns exec $testns sysctl -qw net.ipv4.ip_forward=1
+ ip netns exec $testns sysctl -qw net.ipv4.conf.$DEV.rp_filter=0
match="from $SRC_IP iif $DEV"
fib_rule4_test_match_n_redirect "$match" "$match" "iif redirect to table"
- ip netns exec testns sysctl -qw net.ipv4.ip_forward=0
+ ip netns exec $testns sysctl -qw net.ipv4.ip_forward=0
# Reject dsfield (tos) options which have ECN bits set
for cnt in $(seq 1 3); do
@@ -407,11 +403,11 @@ fib_rule4_connect_test()
# (Not-ECT: 0, ECT(1): 1, ECT(0): 2, CE: 3).
# The ECN bits shouldn't influence the result of the test.
for dsfield in 0x04 0x05 0x06 0x07; do
- nettest -q -B -t 5 -N testns -O peerns -D -U -Q "${dsfield}" \
+ nettest -q -B -t 5 -N $testns -O $peerns -D -U -Q "${dsfield}" \
-l 198.51.100.11 -r 198.51.100.11
log_test $? 0 "rule4 dsfield udp connect (dsfield ${dsfield})"
- nettest -q -B -t 5 -N testns -O peerns -Q "${dsfield}" \
+ nettest -q -B -t 5 -N $testns -O $peerns -Q "${dsfield}" \
-l 198.51.100.11 -r 198.51.100.11
log_test $? 0 "rule4 dsfield tcp connect (dsfield ${dsfield})"
done
diff --git a/tools/testing/selftests/net/fib_tests.sh b/tools/testing/selftests/net/fib_tests.sh
index 66d0db7a2614..b3ecccbbfcd2 100755
--- a/tools/testing/selftests/net/fib_tests.sh
+++ b/tools/testing/selftests/net/fib_tests.sh
@@ -3,10 +3,8 @@
# This test is for checking IPv4 and IPv6 FIB behavior in response to
# different events.
-
+source lib.sh
ret=0
-# Kselftest framework requirement - SKIP code is 4.
-ksft_skip=4
# all tests in this script. Can be overridden with -t option
TESTS="unregister down carrier nexthop suppress ipv6_notify ipv4_notify \
@@ -18,8 +16,6 @@ TESTS="unregister down carrier nexthop suppress ipv6_notify ipv4_notify \
VERBOSE=0
PAUSE_ON_FAIL=no
PAUSE=no
-IP="$(which ip) -netns ns1"
-NS_EXEC="$(which ip) netns exec ns1"
which ping6 > /dev/null 2>&1 && ping6=$(which ping6) || ping6=$(which ping)
@@ -55,11 +51,11 @@ log_test()
setup()
{
set -e
- ip netns add ns1
- ip netns set ns1 auto
- $IP link set dev lo up
- ip netns exec ns1 sysctl -qw net.ipv4.ip_forward=1
- ip netns exec ns1 sysctl -qw net.ipv6.conf.all.forwarding=1
+ setup_ns ns1
+ IP="$(which ip) -netns $ns1"
+ NS_EXEC="$(which ip) netns exec $ns1"
+ ip netns exec $ns1 sysctl -qw net.ipv4.ip_forward=1
+ ip netns exec $ns1 sysctl -qw net.ipv6.conf.all.forwarding=1
$IP link add dummy0 type dummy
$IP link set dev dummy0 up
@@ -72,8 +68,7 @@ setup()
cleanup()
{
$IP link del dev dummy0 &> /dev/null
- ip netns del ns1 &> /dev/null
- ip netns del ns2 &> /dev/null
+ cleanup_ns $ns1 $ns2
}
get_linklocal()
@@ -448,28 +443,25 @@ fib_rp_filter_test()
setup
set -e
- ip netns add ns2
- ip netns set ns2 auto
-
- ip -netns ns2 link set dev lo up
+ setup_ns ns2
$IP link add name veth1 type veth peer name veth2
- $IP link set dev veth2 netns ns2
+ $IP link set dev veth2 netns $ns2
$IP address add 192.0.2.1/24 dev veth1
- ip -netns ns2 address add 192.0.2.1/24 dev veth2
+ ip -netns $ns2 address add 192.0.2.1/24 dev veth2
$IP link set dev veth1 up
- ip -netns ns2 link set dev veth2 up
+ ip -netns $ns2 link set dev veth2 up
$IP link set dev lo address 52:54:00:6a:c7:5e
$IP link set dev veth1 address 52:54:00:6a:c7:5e
- ip -netns ns2 link set dev lo address 52:54:00:6a:c7:5e
- ip -netns ns2 link set dev veth2 address 52:54:00:6a:c7:5e
+ ip -netns $ns2 link set dev lo address 52:54:00:6a:c7:5e
+ ip -netns $ns2 link set dev veth2 address 52:54:00:6a:c7:5e
# 1. (ns2) redirect lo's egress to veth2's egress
- ip netns exec ns2 tc qdisc add dev lo parent root handle 1: fq_codel
- ip netns exec ns2 tc filter add dev lo parent 1: protocol arp basic \
+ ip netns exec $ns2 tc qdisc add dev lo parent root handle 1: fq_codel
+ ip netns exec $ns2 tc filter add dev lo parent 1: protocol arp basic \
action mirred egress redirect dev veth2
- ip netns exec ns2 tc filter add dev lo parent 1: protocol ip basic \
+ ip netns exec $ns2 tc filter add dev lo parent 1: protocol ip basic \
action mirred egress redirect dev veth2
# 2. (ns1) redirect veth1's ingress to lo's ingress
@@ -487,24 +479,24 @@ fib_rp_filter_test()
action mirred egress redirect dev veth1
# 4. (ns2) redirect veth2's ingress to lo's ingress
- ip netns exec ns2 tc qdisc add dev veth2 ingress
- ip netns exec ns2 tc filter add dev veth2 ingress protocol arp basic \
+ ip netns exec $ns2 tc qdisc add dev veth2 ingress
+ ip netns exec $ns2 tc filter add dev veth2 ingress protocol arp basic \
action mirred ingress redirect dev lo
- ip netns exec ns2 tc filter add dev veth2 ingress protocol ip basic \
+ ip netns exec $ns2 tc filter add dev veth2 ingress protocol ip basic \
action mirred ingress redirect dev lo
$NS_EXEC sysctl -qw net.ipv4.conf.all.rp_filter=1
$NS_EXEC sysctl -qw net.ipv4.conf.all.accept_local=1
$NS_EXEC sysctl -qw net.ipv4.conf.all.route_localnet=1
- ip netns exec ns2 sysctl -qw net.ipv4.conf.all.rp_filter=1
- ip netns exec ns2 sysctl -qw net.ipv4.conf.all.accept_local=1
- ip netns exec ns2 sysctl -qw net.ipv4.conf.all.route_localnet=1
+ ip netns exec $ns2 sysctl -qw net.ipv4.conf.all.rp_filter=1
+ ip netns exec $ns2 sysctl -qw net.ipv4.conf.all.accept_local=1
+ ip netns exec $ns2 sysctl -qw net.ipv4.conf.all.route_localnet=1
set +e
- run_cmd "ip netns exec ns2 ping -w1 -c1 192.0.2.1"
+ run_cmd "ip netns exec $ns2 ping -w1 -c1 192.0.2.1"
log_test $? 0 "rp_filter passes local packets"
- run_cmd "ip netns exec ns2 ping -w1 -c1 127.0.0.1"
+ run_cmd "ip netns exec $ns2 ping -w1 -c1 127.0.0.1"
log_test $? 0 "rp_filter passes loopback packets"
cleanup
@@ -959,34 +951,32 @@ route_setup()
[ "${VERBOSE}" = "1" ] && set -x
set -e
- ip netns add ns2
- ip netns set ns2 auto
- ip -netns ns2 link set dev lo up
- ip netns exec ns2 sysctl -qw net.ipv4.ip_forward=1
- ip netns exec ns2 sysctl -qw net.ipv6.conf.all.forwarding=1
+ setup_ns ns2
+ ip netns exec $ns2 sysctl -qw net.ipv4.ip_forward=1
+ ip netns exec $ns2 sysctl -qw net.ipv6.conf.all.forwarding=1
$IP li add veth1 type veth peer name veth2
$IP li add veth3 type veth peer name veth4
$IP li set veth1 up
$IP li set veth3 up
- $IP li set veth2 netns ns2 up
- $IP li set veth4 netns ns2 up
- ip -netns ns2 li add dummy1 type dummy
- ip -netns ns2 li set dummy1 up
+ $IP li set veth2 netns $ns2 up
+ $IP li set veth4 netns $ns2 up
+ ip -netns $ns2 li add dummy1 type dummy
+ ip -netns $ns2 li set dummy1 up
$IP -6 addr add 2001:db8:101::1/64 dev veth1 nodad
$IP -6 addr add 2001:db8:103::1/64 dev veth3 nodad
$IP addr add 172.16.101.1/24 dev veth1
$IP addr add 172.16.103.1/24 dev veth3
- ip -netns ns2 -6 addr add 2001:db8:101::2/64 dev veth2 nodad
- ip -netns ns2 -6 addr add 2001:db8:103::2/64 dev veth4 nodad
- ip -netns ns2 -6 addr add 2001:db8:104::1/64 dev dummy1 nodad
+ ip -netns $ns2 -6 addr add 2001:db8:101::2/64 dev veth2 nodad
+ ip -netns $ns2 -6 addr add 2001:db8:103::2/64 dev veth4 nodad
+ ip -netns $ns2 -6 addr add 2001:db8:104::1/64 dev dummy1 nodad
- ip -netns ns2 addr add 172.16.101.2/24 dev veth2
- ip -netns ns2 addr add 172.16.103.2/24 dev veth4
- ip -netns ns2 addr add 172.16.104.1/24 dev dummy1
+ ip -netns $ns2 addr add 172.16.101.2/24 dev veth2
+ ip -netns $ns2 addr add 172.16.103.2/24 dev veth4
+ ip -netns $ns2 addr add 172.16.104.1/24 dev dummy1
set +e
}
@@ -1238,7 +1228,7 @@ ipv6_addr_metric_test()
log_test $rc 0 "Modify metric of address"
# verify prefix route removed on down
- run_cmd "ip netns exec ns1 sysctl -qw net.ipv6.conf.all.keep_addr_on_down=1"
+ run_cmd "ip netns exec $ns1 sysctl -qw net.ipv6.conf.all.keep_addr_on_down=1"
run_cmd "$IP li set dev dummy2 down"
rc=$?
if [ $rc -eq 0 ]; then
@@ -1344,7 +1334,7 @@ ipv6_route_metrics_test()
log_test $rc 0 "Multipath route with mtu metric"
$IP -6 ro add 2001:db8:104::/64 via 2001:db8:101::2 mtu 1300
- run_cmd "ip netns exec ns1 ${ping6} -w1 -c1 -s 1500 2001:db8:104::1"
+ run_cmd "ip netns exec $ns1 ${ping6} -w1 -c1 -s 1500 2001:db8:104::1"
log_test $? 0 "Using route with mtu metric"
run_cmd "$IP -6 ro add 2001:db8:114::/64 via 2001:db8:101::2 congctl lock foo"
@@ -1599,19 +1589,19 @@ ipv4_rt_replace()
ipv4_local_rt_cache()
{
run_cmd "ip addr add 10.0.0.1/32 dev lo"
- run_cmd "ip netns add test-ns"
+ run_cmd "setup_ns test-ns"
run_cmd "ip link add veth-outside type veth peer name veth-inside"
run_cmd "ip link add vrf-100 type vrf table 1100"
run_cmd "ip link set veth-outside master vrf-100"
- run_cmd "ip link set veth-inside netns test-ns"
+ run_cmd "ip link set veth-inside netns $test-ns"
run_cmd "ip link set veth-outside up"
run_cmd "ip link set vrf-100 up"
run_cmd "ip route add 10.1.1.1/32 dev veth-outside table 1100"
- run_cmd "ip netns exec test-ns ip link set veth-inside up"
- run_cmd "ip netns exec test-ns ip addr add 10.1.1.1/32 dev veth-inside"
- run_cmd "ip netns exec test-ns ip route add 10.0.0.1/32 dev veth-inside"
- run_cmd "ip netns exec test-ns ip route add default via 10.0.0.1"
- run_cmd "ip netns exec test-ns ping 10.0.0.1 -c 1 -i 1"
+ run_cmd "ip netns exec $test-ns ip link set veth-inside up"
+ run_cmd "ip netns exec $test-ns ip addr add 10.1.1.1/32 dev veth-inside"
+ run_cmd "ip netns exec $test-ns ip route add 10.0.0.1/32 dev veth-inside"
+ run_cmd "ip netns exec $test-ns ip route add default via 10.0.0.1"
+ run_cmd "ip netns exec $test-ns ping 10.0.0.1 -c 1 -i 1"
run_cmd "ip link delete vrf-100"
# if we do not hang test is a success
@@ -1841,7 +1831,7 @@ ipv4_route_metrics_test()
log_test $rc 0 "Multipath route with mtu metric"
$IP ro add 172.16.104.0/24 via 172.16.101.2 mtu 1300
- run_cmd "ip netns exec ns1 ping -w1 -c1 -s 1500 172.16.104.1"
+ run_cmd "ip netns exec $ns1 ping -w1 -c1 -s 1500 172.16.104.1"
log_test $? 0 "Using route with mtu metric"
run_cmd "$IP ro add 172.16.111.0/24 via 172.16.101.2 congctl lock foo"
@@ -2105,7 +2095,7 @@ ipv4_route_v6_gw_test()
check_route "172.16.104.0/24 via inet6 2001:db8:101::2 dev veth1"
fi
- run_cmd "ip netns exec ns1 ping -w1 -c1 172.16.104.1"
+ run_cmd "ip netns exec $ns1 ping -w1 -c1 172.16.104.1"
log_test $rc 0 "Single path route with IPv6 gateway - ping"
run_cmd "$IP ro del 172.16.104.0/24 via inet6 2001:db8:101::2"
@@ -2196,7 +2186,7 @@ ipv4_mangle_test()
sleep 2
local tmp_file=$(mktemp)
- ip netns exec ns2 socat UDP4-LISTEN:54321,fork $tmp_file &
+ ip netns exec $ns2 socat UDP4-LISTEN:54321,fork $tmp_file &
# Add a FIB rule and a route that will direct our connection to the
# listening server.
@@ -2254,7 +2244,7 @@ ipv6_mangle_test()
sleep 2
local tmp_file=$(mktemp)
- ip netns exec ns2 socat UDP6-LISTEN:54321,fork $tmp_file &
+ ip netns exec $ns2 socat UDP6-LISTEN:54321,fork $tmp_file &
# Add a FIB rule and a route that will direct our connection to the
# listening server.
@@ -2423,37 +2413,37 @@ ipv4_mpath_list_test()
route_setup
set -e
- run_cmd "ip netns exec ns1 ethtool -K veth1 tcp-segmentation-offload off"
-
- run_cmd "ip netns exec ns2 bash -c \"echo 20000 > /sys/class/net/veth2/gro_flush_timeout\""
- run_cmd "ip netns exec ns2 bash -c \"echo 1 > /sys/class/net/veth2/napi_defer_hard_irqs\""
- run_cmd "ip netns exec ns2 ethtool -K veth2 generic-receive-offload on"
- run_cmd "ip -n ns2 link add name nh1 up type dummy"
- run_cmd "ip -n ns2 link add name nh2 up type dummy"
- run_cmd "ip -n ns2 address add 172.16.201.1/24 dev nh1"
- run_cmd "ip -n ns2 address add 172.16.202.1/24 dev nh2"
- run_cmd "ip -n ns2 neigh add 172.16.201.2 lladdr 00:11:22:33:44:55 nud perm dev nh1"
- run_cmd "ip -n ns2 neigh add 172.16.202.2 lladdr 00:aa:bb:cc:dd:ee nud perm dev nh2"
- run_cmd "ip -n ns2 route add 203.0.113.0/24
+ run_cmd "ip netns exec $ns1 ethtool -K veth1 tcp-segmentation-offload off"
+
+ run_cmd "ip netns exec $ns2 bash -c \"echo 20000 > /sys/class/net/veth2/gro_flush_timeout\""
+ run_cmd "ip netns exec $ns2 bash -c \"echo 1 > /sys/class/net/veth2/napi_defer_hard_irqs\""
+ run_cmd "ip netns exec $ns2 ethtool -K veth2 generic-receive-offload on"
+ run_cmd "ip -n $ns2 link add name nh1 up type dummy"
+ run_cmd "ip -n $ns2 link add name nh2 up type dummy"
+ run_cmd "ip -n $ns2 address add 172.16.201.1/24 dev nh1"
+ run_cmd "ip -n $ns2 address add 172.16.202.1/24 dev nh2"
+ run_cmd "ip -n $ns2 neigh add 172.16.201.2 lladdr 00:11:22:33:44:55 nud perm dev nh1"
+ run_cmd "ip -n $ns2 neigh add 172.16.202.2 lladdr 00:aa:bb:cc:dd:ee nud perm dev nh2"
+ run_cmd "ip -n $ns2 route add 203.0.113.0/24
nexthop via 172.16.201.2 nexthop via 172.16.202.2"
- run_cmd "ip netns exec ns2 sysctl -qw net.ipv4.fib_multipath_hash_policy=1"
- run_cmd "ip netns exec ns2 sysctl -qw net.ipv4.conf.veth2.rp_filter=0"
- run_cmd "ip netns exec ns2 sysctl -qw net.ipv4.conf.all.rp_filter=0"
- run_cmd "ip netns exec ns2 sysctl -qw net.ipv4.conf.default.rp_filter=0"
+ run_cmd "ip netns exec $ns2 sysctl -qw net.ipv4.fib_multipath_hash_policy=1"
+ run_cmd "ip netns exec $ns2 sysctl -qw net.ipv4.conf.veth2.rp_filter=0"
+ run_cmd "ip netns exec $ns2 sysctl -qw net.ipv4.conf.all.rp_filter=0"
+ run_cmd "ip netns exec $ns2 sysctl -qw net.ipv4.conf.default.rp_filter=0"
set +e
- local dmac=$(ip -n ns2 -j link show dev veth2 | jq -r '.[]["address"]')
+ local dmac=$(ip -n $ns2 -j link show dev veth2 | jq -r '.[]["address"]')
local tmp_file=$(mktemp)
- local cmd="ip netns exec ns1 mausezahn veth1 -a own -b $dmac
+ local cmd="ip netns exec $ns1 mausezahn veth1 -a own -b $dmac
-A 172.16.101.1 -B 203.0.113.1 -t udp 'sp=12345,dp=0-65535' -q"
# Packets forwarded in a list using a multipath route must not reuse a
# cached result so that a flow always hits the same nexthop. In other
# words, the FIB lookup tracepoint needs to be triggered for every
# packet.
- local t0_rx_pkts=$(link_stats_get ns2 veth2 rx packets)
+ local t0_rx_pkts=$(link_stats_get $ns2 veth2 rx packets)
run_cmd "perf stat -a -e fib:fib_table_lookup --filter 'err == 0' -j -o $tmp_file -- $cmd"
- local t1_rx_pkts=$(link_stats_get ns2 veth2 rx packets)
+ local t1_rx_pkts=$(link_stats_get $ns2 veth2 rx packets)
local diff=$(echo $t1_rx_pkts - $t0_rx_pkts | bc -l)
list_rcv_eval $tmp_file $diff
@@ -2471,34 +2461,34 @@ ipv6_mpath_list_test()
route_setup
set -e
- run_cmd "ip netns exec ns1 ethtool -K veth1 tcp-segmentation-offload off"
-
- run_cmd "ip netns exec ns2 bash -c \"echo 20000 > /sys/class/net/veth2/gro_flush_timeout\""
- run_cmd "ip netns exec ns2 bash -c \"echo 1 > /sys/class/net/veth2/napi_defer_hard_irqs\""
- run_cmd "ip netns exec ns2 ethtool -K veth2 generic-receive-offload on"
- run_cmd "ip -n ns2 link add name nh1 up type dummy"
- run_cmd "ip -n ns2 link add name nh2 up type dummy"
- run_cmd "ip -n ns2 -6 address add 2001:db8:201::1/64 dev nh1"
- run_cmd "ip -n ns2 -6 address add 2001:db8:202::1/64 dev nh2"
- run_cmd "ip -n ns2 -6 neigh add 2001:db8:201::2 lladdr 00:11:22:33:44:55 nud perm dev nh1"
- run_cmd "ip -n ns2 -6 neigh add 2001:db8:202::2 lladdr 00:aa:bb:cc:dd:ee nud perm dev nh2"
- run_cmd "ip -n ns2 -6 route add 2001:db8:301::/64
+ run_cmd "ip netns exec $ns1 ethtool -K veth1 tcp-segmentation-offload off"
+
+ run_cmd "ip netns exec $ns2 bash -c \"echo 20000 > /sys/class/net/veth2/gro_flush_timeout\""
+ run_cmd "ip netns exec $ns2 bash -c \"echo 1 > /sys/class/net/veth2/napi_defer_hard_irqs\""
+ run_cmd "ip netns exec $ns2 ethtool -K veth2 generic-receive-offload on"
+ run_cmd "ip -n $ns2 link add name nh1 up type dummy"
+ run_cmd "ip -n $ns2 link add name nh2 up type dummy"
+ run_cmd "ip -n $ns2 -6 address add 2001:db8:201::1/64 dev nh1"
+ run_cmd "ip -n $ns2 -6 address add 2001:db8:202::1/64 dev nh2"
+ run_cmd "ip -n $ns2 -6 neigh add 2001:db8:201::2 lladdr 00:11:22:33:44:55 nud perm dev nh1"
+ run_cmd "ip -n $ns2 -6 neigh add 2001:db8:202::2 lladdr 00:aa:bb:cc:dd:ee nud perm dev nh2"
+ run_cmd "ip -n $ns2 -6 route add 2001:db8:301::/64
nexthop via 2001:db8:201::2 nexthop via 2001:db8:202::2"
- run_cmd "ip netns exec ns2 sysctl -qw net.ipv6.fib_multipath_hash_policy=1"
+ run_cmd "ip netns exec $ns2 sysctl -qw net.ipv6.fib_multipath_hash_policy=1"
set +e
- local dmac=$(ip -n ns2 -j link show dev veth2 | jq -r '.[]["address"]')
+ local dmac=$(ip -n $ns2 -j link show dev veth2 | jq -r '.[]["address"]')
local tmp_file=$(mktemp)
- local cmd="ip netns exec ns1 mausezahn -6 veth1 -a own -b $dmac
+ local cmd="ip netns exec $ns1 mausezahn -6 veth1 -a own -b $dmac
-A 2001:db8:101::1 -B 2001:db8:301::1 -t udp 'sp=12345,dp=0-65535' -q"
# Packets forwarded in a list using a multipath route must not reuse a
# cached result so that a flow always hits the same nexthop. In other
# words, the FIB lookup tracepoint needs to be triggered for every
# packet.
- local t0_rx_pkts=$(link_stats_get ns2 veth2 rx packets)
+ local t0_rx_pkts=$(link_stats_get $ns2 veth2 rx packets)
run_cmd "perf stat -a -e fib6:fib6_table_lookup --filter 'err == 0' -j -o $tmp_file -- $cmd"
- local t1_rx_pkts=$(link_stats_get ns2 veth2 rx packets)
+ local t1_rx_pkts=$(link_stats_get $ns2 veth2 rx packets)
local diff=$(echo $t1_rx_pkts - $t0_rx_pkts | bc -l)
list_rcv_eval $tmp_file $diff
diff --git a/tools/testing/selftests/net/forwarding/Makefile b/tools/testing/selftests/net/forwarding/Makefile
index df593b7b3e6b..452693514be4 100644
--- a/tools/testing/selftests/net/forwarding/Makefile
+++ b/tools/testing/selftests/net/forwarding/Makefile
@@ -17,6 +17,7 @@ TEST_PROGS = bridge_fdb_learning_limit.sh \
dual_vxlan_bridge.sh \
ethtool_extended_state.sh \
ethtool_mm.sh \
+ ethtool_rmon.sh \
ethtool.sh \
gre_custom_multipath_hash.sh \
gre_inner_v4_multipath.sh \
diff --git a/tools/testing/selftests/net/forwarding/ethtool_rmon.sh b/tools/testing/selftests/net/forwarding/ethtool_rmon.sh
new file mode 100755
index 000000000000..41a34a61f763
--- /dev/null
+++ b/tools/testing/selftests/net/forwarding/ethtool_rmon.sh
@@ -0,0 +1,143 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+
+ALL_TESTS="
+ rmon_rx_histogram
+ rmon_tx_histogram
+"
+
+NUM_NETIFS=2
+source lib.sh
+
+ETH_FCS_LEN=4
+ETH_HLEN=$((6+6+2))
+
+declare -A netif_mtu
+
+ensure_mtu()
+{
+ local iface=$1; shift
+ local len=$1; shift
+ local current=$(ip -j link show dev $iface | jq -r '.[0].mtu')
+ local required=$((len - ETH_HLEN - ETH_FCS_LEN))
+
+ if [ $current -lt $required ]; then
+ ip link set dev $iface mtu $required || return 1
+ fi
+}
+
+bucket_test()
+{
+ local iface=$1; shift
+ local neigh=$1; shift
+ local set=$1; shift
+ local bucket=$1; shift
+ local len=$1; shift
+ local num_rx=10000
+ local num_tx=20000
+ local expected=
+ local before=
+ local after=
+ local delta=
+
+ # Mausezahn does not include FCS bytes in its length - but the
+ # histogram counters do
+ len=$((len - ETH_FCS_LEN))
+
+ before=$(ethtool --json -S $iface --groups rmon | \
+ jq -r ".[0].rmon[\"${set}-pktsNtoM\"][$bucket].val")
+
+ # Send 10k one way and 20k in the other, to detect counters
+ # mapped to the wrong direction
+ $MZ $neigh -q -c $num_rx -p $len -a own -b bcast -d 10us
+ $MZ $iface -q -c $num_tx -p $len -a own -b bcast -d 10us
+
+ after=$(ethtool --json -S $iface --groups rmon | \
+ jq -r ".[0].rmon[\"${set}-pktsNtoM\"][$bucket].val")
+
+ delta=$((after - before))
+
+ expected=$([ $set = rx ] && echo $num_rx || echo $num_tx)
+
+ # Allow some extra tolerance for other packets sent by the stack
+ [ $delta -ge $expected ] && [ $delta -le $((expected + 100)) ]
+}
+
+rmon_histogram()
+{
+ local iface=$1; shift
+ local neigh=$1; shift
+ local set=$1; shift
+ local nbuckets=0
+ local step=
+
+ RET=0
+
+ while read -r -a bucket; do
+ step="$set-pkts${bucket[0]}to${bucket[1]} on $iface"
+
+ for if in $iface $neigh; do
+ if ! ensure_mtu $if ${bucket[0]}; then
+ log_test_skip "$if does not support the required MTU for $step"
+ return
+ fi
+ done
+
+ if ! bucket_test $iface $neigh $set $nbuckets ${bucket[0]}; then
+ check_err 1 "$step failed"
+ return 1
+ fi
+ log_test "$step"
+ nbuckets=$((nbuckets + 1))
+ done < <(ethtool --json -S $iface --groups rmon | \
+ jq -r ".[0].rmon[\"${set}-pktsNtoM\"][]|[.low, .high]|@tsv" 2>/dev/null)
+
+ if [ $nbuckets -eq 0 ]; then
+ log_test_skip "$iface does not support $set histogram counters"
+ return
+ fi
+}
+
+rmon_rx_histogram()
+{
+ rmon_histogram $h1 $h2 rx
+ rmon_histogram $h2 $h1 rx
+}
+
+rmon_tx_histogram()
+{
+ rmon_histogram $h1 $h2 tx
+ rmon_histogram $h2 $h1 tx
+}
+
+setup_prepare()
+{
+ h1=${NETIFS[p1]}
+ h2=${NETIFS[p2]}
+
+ for iface in $h1 $h2; do
+ netif_mtu[$iface]=$(ip -j link show dev $iface | jq -r '.[0].mtu')
+ ip link set dev $iface up
+ done
+}
+
+cleanup()
+{
+ pre_cleanup
+
+ for iface in $h2 $h1; do
+ ip link set dev $iface \
+ mtu ${netif_mtu[$iface]} \
+ down
+ done
+}
+
+check_ethtool_counter_group_support
+trap cleanup EXIT
+
+setup_prepare
+setup_wait
+
+tests_run
+
+exit $EXIT_STATUS
diff --git a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh
index e37a15eda6c2..e3740163c384 100755
--- a/tools/testing/selftests/net/forwarding/lib.sh
+++ b/tools/testing/selftests/net/forwarding/lib.sh
@@ -4,9 +4,6 @@
##############################################################################
# Defines
-# Kselftest framework requirement - SKIP code is 4.
-ksft_skip=4
-
# Can be overridden by the configuration file.
PING=${PING:=ping}
PING6=${PING6:=ping6}
@@ -41,6 +38,7 @@ if [[ -f $relative_path/forwarding.config ]]; then
source "$relative_path/forwarding.config"
fi
+source ../lib.sh
##############################################################################
# Sanity checks
@@ -148,6 +146,15 @@ check_ethtool_mm_support()
fi
}
+check_ethtool_counter_group_support()
+{
+ ethtool --help 2>&1| grep -- '--all-groups' &> /dev/null
+ if [[ $? -ne 0 ]]; then
+ echo "SKIP: ethtool too old; it is missing standard counter group support"
+ exit $ksft_skip
+ fi
+}
+
check_locked_port_support()
{
if ! bridge -d link show | grep -q " locked"; then
@@ -395,29 +402,6 @@ log_info()
echo "INFO: $msg"
}
-busywait()
-{
- local timeout=$1; shift
-
- local start_time="$(date -u +%s%3N)"
- while true
- do
- local out
- out=$("$@")
- local ret=$?
- if ((!ret)); then
- echo -n "$out"
- return 0
- fi
-
- local current_time="$(date -u +%s%3N)"
- if ((current_time - start_time > timeout)); then
- echo -n "$out"
- return 1
- fi
- done
-}
-
not()
{
"$@"
diff --git a/tools/testing/selftests/net/icmp.sh b/tools/testing/selftests/net/icmp.sh
index e4b04cd1644a..824cb0e35eff 100755
--- a/tools/testing/selftests/net/icmp.sh
+++ b/tools/testing/selftests/net/icmp.sh
@@ -18,8 +18,8 @@
# that address space, so the kernel should substitute the dummy address
# 192.0.0.8 defined in RFC7600.
-NS1=ns1
-NS2=ns2
+source lib.sh
+
H1_IP=172.16.0.1/32
H1_IP6=2001:db8:1::1
RT1=172.16.1.0/24
@@ -32,15 +32,13 @@ TMPFILE=$(mktemp)
cleanup()
{
rm -f "$TMPFILE"
- ip netns del $NS1
- ip netns del $NS2
+ cleanup_ns $NS1 $NS2
}
trap cleanup EXIT
# Namespaces
-ip netns add $NS1
-ip netns add $NS2
+setup_ns NS1 NS2
# Connectivity
ip -netns $NS1 link add veth0 type veth peer name veth0 netns $NS2
diff --git a/tools/testing/selftests/net/icmp_redirect.sh b/tools/testing/selftests/net/icmp_redirect.sh
index 7b9d6e31b8e7..d6f0e449c029 100755
--- a/tools/testing/selftests/net/icmp_redirect.sh
+++ b/tools/testing/selftests/net/icmp_redirect.sh
@@ -19,6 +19,7 @@
# Route on r1 changed to go to r2 via eth0. This causes a redirect to be sent
# from r1 to h1 telling h1 to use r2 when talking to h2.
+source lib.sh
VERBOSE=0
PAUSE_ON_FAIL=no
@@ -140,11 +141,7 @@ get_linklocal()
cleanup()
{
- local ns
-
- for ns in h1 h2 r1 r2; do
- ip netns del $ns 2>/dev/null
- done
+ cleanup_ns $h1 $h2 $r1 $r2
}
create_vrf()
@@ -171,102 +168,99 @@ setup()
#
# create nodes as namespaces
- #
- for ns in h1 h2 r1 r2; do
- ip netns add $ns
- ip -netns $ns li set lo up
-
- case "${ns}" in
- h[12]) ip netns exec $ns sysctl -q -w net.ipv4.conf.all.accept_redirects=1
- ip netns exec $ns sysctl -q -w net.ipv6.conf.all.forwarding=0
- ip netns exec $ns sysctl -q -w net.ipv6.conf.all.accept_redirects=1
- ip netns exec $ns sysctl -q -w net.ipv6.conf.all.keep_addr_on_down=1
- ;;
- r[12]) ip netns exec $ns sysctl -q -w net.ipv4.ip_forward=1
- ip netns exec $ns sysctl -q -w net.ipv4.conf.all.send_redirects=1
- ip netns exec $ns sysctl -q -w net.ipv4.conf.default.rp_filter=0
- ip netns exec $ns sysctl -q -w net.ipv4.conf.all.rp_filter=0
-
- ip netns exec $ns sysctl -q -w net.ipv6.conf.all.forwarding=1
- ip netns exec $ns sysctl -q -w net.ipv6.route.mtu_expires=10
- esac
+ setup_ns h1 h2 r1 r2
+ for ns in $h1 $h2 $r1 $r2; do
+ if echo $ns | grep -q h[12]-; then
+ ip netns exec $ns sysctl -q -w net.ipv4.conf.all.accept_redirects=1
+ ip netns exec $ns sysctl -q -w net.ipv6.conf.all.forwarding=0
+ ip netns exec $ns sysctl -q -w net.ipv6.conf.all.accept_redirects=1
+ ip netns exec $ns sysctl -q -w net.ipv6.conf.all.keep_addr_on_down=1
+ else
+ ip netns exec $ns sysctl -q -w net.ipv4.ip_forward=1
+ ip netns exec $ns sysctl -q -w net.ipv4.conf.all.send_redirects=1
+ ip netns exec $ns sysctl -q -w net.ipv4.conf.default.rp_filter=0
+ ip netns exec $ns sysctl -q -w net.ipv4.conf.all.rp_filter=0
+
+ ip netns exec $ns sysctl -q -w net.ipv6.conf.all.forwarding=1
+ ip netns exec $ns sysctl -q -w net.ipv6.route.mtu_expires=10
+ fi
done
#
# create interconnects
#
- ip -netns h1 li add eth0 type veth peer name r1h1
- ip -netns h1 li set r1h1 netns r1 name eth0 up
+ ip -netns $h1 li add eth0 type veth peer name r1h1
+ ip -netns $h1 li set r1h1 netns $r1 name eth0 up
- ip -netns h1 li add eth1 type veth peer name r2h1
- ip -netns h1 li set r2h1 netns r2 name eth0 up
+ ip -netns $h1 li add eth1 type veth peer name r2h1
+ ip -netns $h1 li set r2h1 netns $r2 name eth0 up
- ip -netns h2 li add eth0 type veth peer name r2h2
- ip -netns h2 li set eth0 up
- ip -netns h2 li set r2h2 netns r2 name eth2 up
+ ip -netns $h2 li add eth0 type veth peer name r2h2
+ ip -netns $h2 li set eth0 up
+ ip -netns $h2 li set r2h2 netns $r2 name eth2 up
- ip -netns r1 li add eth1 type veth peer name r2r1
- ip -netns r1 li set eth1 up
- ip -netns r1 li set r2r1 netns r2 name eth1 up
+ ip -netns $r1 li add eth1 type veth peer name r2r1
+ ip -netns $r1 li set eth1 up
+ ip -netns $r1 li set r2r1 netns $r2 name eth1 up
#
# h1
#
if [ "${WITH_VRF}" = "yes" ]; then
- create_vrf "h1"
+ create_vrf "$h1"
H1_VRF_ARG="vrf ${VRF}"
H1_PING_ARG="-I ${VRF}"
else
H1_VRF_ARG=
H1_PING_ARG=
fi
- ip -netns h1 li add br0 type bridge
+ ip -netns $h1 li add br0 type bridge
if [ "${WITH_VRF}" = "yes" ]; then
- ip -netns h1 li set br0 vrf ${VRF} up
+ ip -netns $h1 li set br0 vrf ${VRF} up
else
- ip -netns h1 li set br0 up
+ ip -netns $h1 li set br0 up
fi
- ip -netns h1 addr add dev br0 ${H1_N1_IP}/24
- ip -netns h1 -6 addr add dev br0 ${H1_N1_IP6}/64 nodad
- ip -netns h1 li set eth0 master br0 up
- ip -netns h1 li set eth1 master br0 up
+ ip -netns $h1 addr add dev br0 ${H1_N1_IP}/24
+ ip -netns $h1 -6 addr add dev br0 ${H1_N1_IP6}/64 nodad
+ ip -netns $h1 li set eth0 master br0 up
+ ip -netns $h1 li set eth1 master br0 up
#
# h2
#
- ip -netns h2 addr add dev eth0 ${H2_N2_IP}/24
- ip -netns h2 ro add default via ${R2_N2_IP} dev eth0
- ip -netns h2 -6 addr add dev eth0 ${H2_N2_IP6}/64 nodad
- ip -netns h2 -6 ro add default via ${R2_N2_IP6} dev eth0
+ ip -netns $h2 addr add dev eth0 ${H2_N2_IP}/24
+ ip -netns $h2 ro add default via ${R2_N2_IP} dev eth0
+ ip -netns $h2 -6 addr add dev eth0 ${H2_N2_IP6}/64 nodad
+ ip -netns $h2 -6 ro add default via ${R2_N2_IP6} dev eth0
#
# r1
#
- ip -netns r1 addr add dev eth0 ${R1_N1_IP}/24
- ip -netns r1 -6 addr add dev eth0 ${R1_N1_IP6}/64 nodad
- ip -netns r1 addr add dev eth1 ${R1_R2_N1_IP}/30
- ip -netns r1 -6 addr add dev eth1 ${R1_R2_N1_IP6}/126 nodad
+ ip -netns $r1 addr add dev eth0 ${R1_N1_IP}/24
+ ip -netns $r1 -6 addr add dev eth0 ${R1_N1_IP6}/64 nodad
+ ip -netns $r1 addr add dev eth1 ${R1_R2_N1_IP}/30
+ ip -netns $r1 -6 addr add dev eth1 ${R1_R2_N1_IP6}/126 nodad
#
# r2
#
- ip -netns r2 addr add dev eth0 ${R2_N1_IP}/24
- ip -netns r2 -6 addr add dev eth0 ${R2_N1_IP6}/64 nodad
- ip -netns r2 addr add dev eth1 ${R2_R1_N1_IP}/30
- ip -netns r2 -6 addr add dev eth1 ${R2_R1_N1_IP6}/126 nodad
- ip -netns r2 addr add dev eth2 ${R2_N2_IP}/24
- ip -netns r2 -6 addr add dev eth2 ${R2_N2_IP6}/64 nodad
+ ip -netns $r2 addr add dev eth0 ${R2_N1_IP}/24
+ ip -netns $r2 -6 addr add dev eth0 ${R2_N1_IP6}/64 nodad
+ ip -netns $r2 addr add dev eth1 ${R2_R1_N1_IP}/30
+ ip -netns $r2 -6 addr add dev eth1 ${R2_R1_N1_IP6}/126 nodad
+ ip -netns $r2 addr add dev eth2 ${R2_N2_IP}/24
+ ip -netns $r2 -6 addr add dev eth2 ${R2_N2_IP6}/64 nodad
sleep 2
- R1_LLADDR=$(get_linklocal r1 eth0)
+ R1_LLADDR=$(get_linklocal $r1 eth0)
if [ $? -ne 0 ]; then
echo "Error: Failed to get link-local address of r1's eth0"
exit 1
fi
log_debug "initial gateway is R1's lladdr = ${R1_LLADDR}"
- R2_LLADDR=$(get_linklocal r2 eth0)
+ R2_LLADDR=$(get_linklocal $r2 eth0)
if [ $? -ne 0 ]; then
echo "Error: Failed to get link-local address of r2's eth0"
exit 1
@@ -278,8 +272,8 @@ change_h2_mtu()
{
local mtu=$1
- run_cmd ip -netns h2 li set eth0 mtu ${mtu}
- run_cmd ip -netns r2 li set eth2 mtu ${mtu}
+ run_cmd ip -netns $h2 li set eth0 mtu ${mtu}
+ run_cmd ip -netns $r2 li set eth2 mtu ${mtu}
}
check_exception()
@@ -291,40 +285,40 @@ check_exception()
# From 172.16.1.101: icmp_seq=1 Redirect Host(New nexthop: 172.16.1.102)
if [ "$VERBOSE" = "1" ]; then
echo "Commands to check for exception:"
- run_cmd ip -netns h1 ro get ${H1_VRF_ARG} ${H2_N2_IP}
- run_cmd ip -netns h1 -6 ro get ${H1_VRF_ARG} ${H2_N2_IP6}
+ run_cmd ip -netns $h1 ro get ${H1_VRF_ARG} ${H2_N2_IP}
+ run_cmd ip -netns $h1 -6 ro get ${H1_VRF_ARG} ${H2_N2_IP6}
fi
if [ -n "${mtu}" ]; then
mtu=" mtu ${mtu}"
fi
if [ "$with_redirect" = "yes" ]; then
- ip -netns h1 ro get ${H1_VRF_ARG} ${H2_N2_IP} | \
+ ip -netns $h1 ro get ${H1_VRF_ARG} ${H2_N2_IP} | \
grep -q "cache <redirected> expires [0-9]*sec${mtu}"
elif [ -n "${mtu}" ]; then
- ip -netns h1 ro get ${H1_VRF_ARG} ${H2_N2_IP} | \
+ ip -netns $h1 ro get ${H1_VRF_ARG} ${H2_N2_IP} | \
grep -q "cache expires [0-9]*sec${mtu}"
else
# want to verify that neither mtu nor redirected appears in
# the route get output. The -v will wipe out the cache line
# if either are set so the last grep -q will not find a match
- ip -netns h1 ro get ${H1_VRF_ARG} ${H2_N2_IP} | \
+ ip -netns $h1 ro get ${H1_VRF_ARG} ${H2_N2_IP} | \
grep -E -v 'mtu|redirected' | grep -q "cache"
fi
log_test $? 0 "IPv4: ${desc}" 0
# No PMTU info for test "redirect" and "mtu exception plus redirect"
if [ "$with_redirect" = "yes" ] && [ "$desc" != "redirect exception plus mtu" ]; then
- ip -netns h1 -6 ro get ${H1_VRF_ARG} ${H2_N2_IP6} | \
+ ip -netns $h1 -6 ro get ${H1_VRF_ARG} ${H2_N2_IP6} | \
grep -v "mtu" | grep -q "${H2_N2_IP6} .*via ${R2_LLADDR} dev br0"
elif [ -n "${mtu}" ]; then
- ip -netns h1 -6 ro get ${H1_VRF_ARG} ${H2_N2_IP6} | \
+ ip -netns $h1 -6 ro get ${H1_VRF_ARG} ${H2_N2_IP6} | \
grep -q "${mtu}"
else
# IPv6 is a bit harder. First strip out the match if it
# contains an mtu exception and then look for the first
# gateway - R1's lladdr
- ip -netns h1 -6 ro get ${H1_VRF_ARG} ${H2_N2_IP6} | \
+ ip -netns $h1 -6 ro get ${H1_VRF_ARG} ${H2_N2_IP6} | \
grep -v "mtu" | grep -q "${R1_LLADDR}"
fi
log_test $? 0 "IPv6: ${desc}" 1
@@ -334,21 +328,21 @@ run_ping()
{
local sz=$1
- run_cmd ip netns exec h1 ping -q -M want -i 0.5 -c 10 -w 2 -s ${sz} ${H1_PING_ARG} ${H2_N2_IP}
- run_cmd ip netns exec h1 ${ping6} -q -M want -i 0.5 -c 10 -w 2 -s ${sz} ${H1_PING_ARG} ${H2_N2_IP6}
+ run_cmd ip netns exec $h1 ping -q -M want -i 0.5 -c 10 -w 2 -s ${sz} ${H1_PING_ARG} ${H2_N2_IP}
+ run_cmd ip netns exec $h1 ${ping6} -q -M want -i 0.5 -c 10 -w 2 -s ${sz} ${H1_PING_ARG} ${H2_N2_IP6}
}
replace_route_new()
{
# r1 to h2 via r2 and eth0
- run_cmd ip -netns r1 nexthop replace id 1 via ${R2_N1_IP} dev eth0
- run_cmd ip -netns r1 nexthop replace id 2 via ${R2_LLADDR} dev eth0
+ run_cmd ip -netns $r1 nexthop replace id 1 via ${R2_N1_IP} dev eth0
+ run_cmd ip -netns $r1 nexthop replace id 2 via ${R2_LLADDR} dev eth0
}
reset_route_new()
{
- run_cmd ip -netns r1 nexthop flush
- run_cmd ip -netns h1 nexthop flush
+ run_cmd ip -netns $r1 nexthop flush
+ run_cmd ip -netns $h1 nexthop flush
initial_route_new
}
@@ -356,34 +350,34 @@ reset_route_new()
initial_route_new()
{
# r1 to h2 via r2 and eth1
- run_cmd ip -netns r1 nexthop add id 1 via ${R2_R1_N1_IP} dev eth1
- run_cmd ip -netns r1 ro add ${H2_N2} nhid 1
+ run_cmd ip -netns $r1 nexthop add id 1 via ${R2_R1_N1_IP} dev eth1
+ run_cmd ip -netns $r1 ro add ${H2_N2} nhid 1
- run_cmd ip -netns r1 nexthop add id 2 via ${R2_R1_N1_IP6} dev eth1
- run_cmd ip -netns r1 -6 ro add ${H2_N2_6} nhid 2
+ run_cmd ip -netns $r1 nexthop add id 2 via ${R2_R1_N1_IP6} dev eth1
+ run_cmd ip -netns $r1 -6 ro add ${H2_N2_6} nhid 2
# h1 to h2 via r1
- run_cmd ip -netns h1 nexthop add id 1 via ${R1_N1_IP} dev br0
- run_cmd ip -netns h1 ro add ${H1_VRF_ARG} ${H2_N2} nhid 1
+ run_cmd ip -netns $h1 nexthop add id 1 via ${R1_N1_IP} dev br0
+ run_cmd ip -netns $h1 ro add ${H1_VRF_ARG} ${H2_N2} nhid 1
- run_cmd ip -netns h1 nexthop add id 2 via ${R1_LLADDR} dev br0
- run_cmd ip -netns h1 -6 ro add ${H1_VRF_ARG} ${H2_N2_6} nhid 2
+ run_cmd ip -netns $h1 nexthop add id 2 via ${R1_LLADDR} dev br0
+ run_cmd ip -netns $h1 -6 ro add ${H1_VRF_ARG} ${H2_N2_6} nhid 2
}
replace_route_legacy()
{
# r1 to h2 via r2 and eth0
- run_cmd ip -netns r1 ro replace ${H2_N2} via ${R2_N1_IP} dev eth0
- run_cmd ip -netns r1 -6 ro replace ${H2_N2_6} via ${R2_LLADDR} dev eth0
+ run_cmd ip -netns $r1 ro replace ${H2_N2} via ${R2_N1_IP} dev eth0
+ run_cmd ip -netns $r1 -6 ro replace ${H2_N2_6} via ${R2_LLADDR} dev eth0
}
reset_route_legacy()
{
- run_cmd ip -netns r1 ro del ${H2_N2}
- run_cmd ip -netns r1 -6 ro del ${H2_N2_6}
+ run_cmd ip -netns $r1 ro del ${H2_N2}
+ run_cmd ip -netns $r1 -6 ro del ${H2_N2_6}
- run_cmd ip -netns h1 ro del ${H1_VRF_ARG} ${H2_N2}
- run_cmd ip -netns h1 -6 ro del ${H1_VRF_ARG} ${H2_N2_6}
+ run_cmd ip -netns $h1 ro del ${H1_VRF_ARG} ${H2_N2}
+ run_cmd ip -netns $h1 -6 ro del ${H1_VRF_ARG} ${H2_N2_6}
initial_route_legacy
}
@@ -391,22 +385,22 @@ reset_route_legacy()
initial_route_legacy()
{
# r1 to h2 via r2 and eth1
- run_cmd ip -netns r1 ro add ${H2_N2} via ${R2_R1_N1_IP} dev eth1
- run_cmd ip -netns r1 -6 ro add ${H2_N2_6} via ${R2_R1_N1_IP6} dev eth1
+ run_cmd ip -netns $r1 ro add ${H2_N2} via ${R2_R1_N1_IP} dev eth1
+ run_cmd ip -netns $r1 -6 ro add ${H2_N2_6} via ${R2_R1_N1_IP6} dev eth1
# h1 to h2 via r1
# - IPv6 redirect only works if gateway is the LLA
- run_cmd ip -netns h1 ro add ${H1_VRF_ARG} ${H2_N2} via ${R1_N1_IP} dev br0
- run_cmd ip -netns h1 -6 ro add ${H1_VRF_ARG} ${H2_N2_6} via ${R1_LLADDR} dev br0
+ run_cmd ip -netns $h1 ro add ${H1_VRF_ARG} ${H2_N2} via ${R1_N1_IP} dev br0
+ run_cmd ip -netns $h1 -6 ro add ${H1_VRF_ARG} ${H2_N2_6} via ${R1_LLADDR} dev br0
}
check_connectivity()
{
local rc
- run_cmd ip netns exec h1 ping -c1 -w1 ${H1_PING_ARG} ${H2_N2_IP}
+ run_cmd ip netns exec $h1 ping -c1 -w1 ${H1_PING_ARG} ${H2_N2_IP}
rc=$?
- run_cmd ip netns exec h1 ${ping6} -c1 -w1 ${H1_PING_ARG} ${H2_N2_IP6}
+ run_cmd ip netns exec $h1 ${ping6} -c1 -w1 ${H1_PING_ARG} ${H2_N2_IP6}
[ $? -ne 0 ] && rc=$?
return $rc
diff --git a/tools/testing/selftests/net/io_uring_zerocopy_tx.sh b/tools/testing/selftests/net/io_uring_zerocopy_tx.sh
index 9ac4456d48fc..123439545013 100755
--- a/tools/testing/selftests/net/io_uring_zerocopy_tx.sh
+++ b/tools/testing/selftests/net/io_uring_zerocopy_tx.sh
@@ -76,23 +76,22 @@ case "${TXMODE}" in
esac
# Start of state changes: install cleanup handler
-save_sysctl_mem="$(sysctl -n ${path_sysctl_mem})"
cleanup() {
ip netns del "${NS2}"
ip netns del "${NS1}"
- sysctl -w -q "${path_sysctl_mem}=${save_sysctl_mem}"
}
trap cleanup EXIT
-# Configure system settings
-sysctl -w -q "${path_sysctl_mem}=1000000"
-
# Create virtual ethernet pair between network namespaces
ip netns add "${NS1}"
ip netns add "${NS2}"
+# Configure system settings
+ip netns exec "${NS1}" sysctl -w -q "${path_sysctl_mem}=1000000"
+ip netns exec "${NS2}" sysctl -w -q "${path_sysctl_mem}=1000000"
+
ip link add "${DEV}" mtu "${DEV_MTU}" netns "${NS1}" type veth \
peer name "${DEV}" mtu "${DEV_MTU}" netns "${NS2}"
diff --git a/tools/testing/selftests/net/ioam6.sh b/tools/testing/selftests/net/ioam6.sh
index 4ceb401da1bf..fe59ca3e5596 100755
--- a/tools/testing/selftests/net/ioam6.sh
+++ b/tools/testing/selftests/net/ioam6.sh
@@ -117,8 +117,7 @@
# | Schema Data | |
# +-----------------------------------------------------------+
-# Kselftest framework requirement - SKIP code is 4.
-ksft_skip=4
+source lib.sh
################################################################################
# #
@@ -195,32 +194,32 @@ TESTS_GLOBAL="
check_kernel_compatibility()
{
- ip netns add ioam-tmp-node
- ip link add name veth0 netns ioam-tmp-node type veth \
- peer name veth1 netns ioam-tmp-node
+ setup_ns ioam_tmp_node
+ ip link add name veth0 netns $ioam_tmp_node type veth \
+ peer name veth1 netns $ioam_tmp_node
- ip -netns ioam-tmp-node link set veth0 up
- ip -netns ioam-tmp-node link set veth1 up
+ ip -netns $ioam_tmp_node link set veth0 up
+ ip -netns $ioam_tmp_node link set veth1 up
- ip -netns ioam-tmp-node ioam namespace add 0
+ ip -netns $ioam_tmp_node ioam namespace add 0
ns_ad=$?
- ip -netns ioam-tmp-node ioam namespace show | grep -q "namespace 0"
+ ip -netns $ioam_tmp_node ioam namespace show | grep -q "namespace 0"
ns_sh=$?
if [[ $ns_ad != 0 || $ns_sh != 0 ]]
then
echo "SKIP: kernel version probably too old, missing ioam support"
ip link del veth0 2>/dev/null || true
- ip netns del ioam-tmp-node || true
+ cleanup_ns $ioam_tmp_node || true
exit $ksft_skip
fi
- ip -netns ioam-tmp-node route add db02::/64 encap ioam6 mode inline \
+ ip -netns $ioam_tmp_node route add db02::/64 encap ioam6 mode inline \
trace prealloc type 0x800000 ns 0 size 4 dev veth0
tr_ad=$?
- ip -netns ioam-tmp-node -6 route | grep -q "encap ioam6"
+ ip -netns $ioam_tmp_node -6 route | grep -q "encap ioam6"
tr_sh=$?
if [[ $tr_ad != 0 || $tr_sh != 0 ]]
@@ -228,12 +227,12 @@ check_kernel_compatibility()
echo "SKIP: cannot attach an ioam trace to a route, did you compile" \
"without CONFIG_IPV6_IOAM6_LWTUNNEL?"
ip link del veth0 2>/dev/null || true
- ip netns del ioam-tmp-node || true
+ cleanup_ns $ioam_tmp_node || true
exit $ksft_skip
fi
ip link del veth0 2>/dev/null || true
- ip netns del ioam-tmp-node || true
+ cleanup_ns $ioam_tmp_node || true
lsmod | grep -q "ip6_tunnel"
ip6tnl_loaded=$?
@@ -265,9 +264,7 @@ cleanup()
ip link del ioam-veth-alpha 2>/dev/null || true
ip link del ioam-veth-gamma 2>/dev/null || true
- ip netns del ioam-node-alpha || true
- ip netns del ioam-node-beta || true
- ip netns del ioam-node-gamma || true
+ cleanup_ns $ioam_node_alpha $ioam_node_beta $ioam_node_gamma || true
if [ $ip6tnl_loaded != 0 ]
then
@@ -277,69 +274,67 @@ cleanup()
setup()
{
- ip netns add ioam-node-alpha
- ip netns add ioam-node-beta
- ip netns add ioam-node-gamma
-
- ip link add name ioam-veth-alpha netns ioam-node-alpha type veth \
- peer name ioam-veth-betaL netns ioam-node-beta
- ip link add name ioam-veth-betaR netns ioam-node-beta type veth \
- peer name ioam-veth-gamma netns ioam-node-gamma
-
- ip -netns ioam-node-alpha link set ioam-veth-alpha name veth0
- ip -netns ioam-node-beta link set ioam-veth-betaL name veth0
- ip -netns ioam-node-beta link set ioam-veth-betaR name veth1
- ip -netns ioam-node-gamma link set ioam-veth-gamma name veth0
-
- ip -netns ioam-node-alpha addr add db01::2/64 dev veth0
- ip -netns ioam-node-alpha link set veth0 up
- ip -netns ioam-node-alpha link set lo up
- ip -netns ioam-node-alpha route add db02::/64 via db01::1 dev veth0
- ip -netns ioam-node-alpha route del db01::/64
- ip -netns ioam-node-alpha route add db01::/64 dev veth0
-
- ip -netns ioam-node-beta addr add db01::1/64 dev veth0
- ip -netns ioam-node-beta addr add db02::1/64 dev veth1
- ip -netns ioam-node-beta link set veth0 up
- ip -netns ioam-node-beta link set veth1 up
- ip -netns ioam-node-beta link set lo up
-
- ip -netns ioam-node-gamma addr add db02::2/64 dev veth0
- ip -netns ioam-node-gamma link set veth0 up
- ip -netns ioam-node-gamma link set lo up
- ip -netns ioam-node-gamma route add db01::/64 via db02::1 dev veth0
+ setup_ns ioam_node_alpha ioam_node_beta ioam_node_gamma
+
+ ip link add name ioam-veth-alpha netns $ioam_node_alpha type veth \
+ peer name ioam-veth-betaL netns $ioam_node_beta
+ ip link add name ioam-veth-betaR netns $ioam_node_beta type veth \
+ peer name ioam-veth-gamma netns $ioam_node_gamma
+
+ ip -netns $ioam_node_alpha link set ioam-veth-alpha name veth0
+ ip -netns $ioam_node_beta link set ioam-veth-betaL name veth0
+ ip -netns $ioam_node_beta link set ioam-veth-betaR name veth1
+ ip -netns $ioam_node_gamma link set ioam-veth-gamma name veth0
+
+ ip -netns $ioam_node_alpha addr add db01::2/64 dev veth0
+ ip -netns $ioam_node_alpha link set veth0 up
+ ip -netns $ioam_node_alpha link set lo up
+ ip -netns $ioam_node_alpha route add db02::/64 via db01::1 dev veth0
+ ip -netns $ioam_node_alpha route del db01::/64
+ ip -netns $ioam_node_alpha route add db01::/64 dev veth0
+
+ ip -netns $ioam_node_beta addr add db01::1/64 dev veth0
+ ip -netns $ioam_node_beta addr add db02::1/64 dev veth1
+ ip -netns $ioam_node_beta link set veth0 up
+ ip -netns $ioam_node_beta link set veth1 up
+ ip -netns $ioam_node_beta link set lo up
+
+ ip -netns $ioam_node_gamma addr add db02::2/64 dev veth0
+ ip -netns $ioam_node_gamma link set veth0 up
+ ip -netns $ioam_node_gamma link set lo up
+ ip -netns $ioam_node_gamma route add db01::/64 via db02::1 dev veth0
# - IOAM config -
- ip netns exec ioam-node-alpha sysctl -wq net.ipv6.ioam6_id=${ALPHA[0]}
- ip netns exec ioam-node-alpha sysctl -wq net.ipv6.ioam6_id_wide=${ALPHA[1]}
- ip netns exec ioam-node-alpha sysctl -wq net.ipv6.conf.veth0.ioam6_id=${ALPHA[4]}
- ip netns exec ioam-node-alpha sysctl -wq net.ipv6.conf.veth0.ioam6_id_wide=${ALPHA[5]}
- ip -netns ioam-node-alpha ioam namespace add 123 data ${ALPHA[6]} wide ${ALPHA[7]}
- ip -netns ioam-node-alpha ioam schema add ${ALPHA[8]} "${ALPHA[9]}"
- ip -netns ioam-node-alpha ioam namespace set 123 schema ${ALPHA[8]}
-
- ip netns exec ioam-node-beta sysctl -wq net.ipv6.conf.all.forwarding=1
- ip netns exec ioam-node-beta sysctl -wq net.ipv6.ioam6_id=${BETA[0]}
- ip netns exec ioam-node-beta sysctl -wq net.ipv6.ioam6_id_wide=${BETA[1]}
- ip netns exec ioam-node-beta sysctl -wq net.ipv6.conf.veth0.ioam6_enabled=1
- ip netns exec ioam-node-beta sysctl -wq net.ipv6.conf.veth0.ioam6_id=${BETA[2]}
- ip netns exec ioam-node-beta sysctl -wq net.ipv6.conf.veth0.ioam6_id_wide=${BETA[3]}
- ip netns exec ioam-node-beta sysctl -wq net.ipv6.conf.veth1.ioam6_id=${BETA[4]}
- ip netns exec ioam-node-beta sysctl -wq net.ipv6.conf.veth1.ioam6_id_wide=${BETA[5]}
- ip -netns ioam-node-beta ioam namespace add 123 data ${BETA[6]} wide ${BETA[7]}
- ip -netns ioam-node-beta ioam schema add ${BETA[8]} "${BETA[9]}"
- ip -netns ioam-node-beta ioam namespace set 123 schema ${BETA[8]}
-
- ip netns exec ioam-node-gamma sysctl -wq net.ipv6.ioam6_id=${GAMMA[0]}
- ip netns exec ioam-node-gamma sysctl -wq net.ipv6.ioam6_id_wide=${GAMMA[1]}
- ip netns exec ioam-node-gamma sysctl -wq net.ipv6.conf.veth0.ioam6_enabled=1
- ip netns exec ioam-node-gamma sysctl -wq net.ipv6.conf.veth0.ioam6_id=${GAMMA[2]}
- ip netns exec ioam-node-gamma sysctl -wq net.ipv6.conf.veth0.ioam6_id_wide=${GAMMA[3]}
- ip -netns ioam-node-gamma ioam namespace add 123 data ${GAMMA[6]} wide ${GAMMA[7]}
+ ip netns exec $ioam_node_alpha sysctl -wq net.ipv6.ioam6_id=${ALPHA[0]}
+ ip netns exec $ioam_node_alpha sysctl -wq net.ipv6.ioam6_id_wide=${ALPHA[1]}
+ ip netns exec $ioam_node_alpha sysctl -wq net.ipv6.conf.veth0.ioam6_id=${ALPHA[4]}
+ ip netns exec $ioam_node_alpha sysctl -wq net.ipv6.conf.veth0.ioam6_id_wide=${ALPHA[5]}
+ ip -netns $ioam_node_alpha ioam namespace add 123 data ${ALPHA[6]} wide ${ALPHA[7]}
+ ip -netns $ioam_node_alpha ioam schema add ${ALPHA[8]} "${ALPHA[9]}"
+ ip -netns $ioam_node_alpha ioam namespace set 123 schema ${ALPHA[8]}
+
+ ip netns exec $ioam_node_beta sysctl -wq net.ipv6.conf.all.forwarding=1
+ ip netns exec $ioam_node_beta sysctl -wq net.ipv6.ioam6_id=${BETA[0]}
+ ip netns exec $ioam_node_beta sysctl -wq net.ipv6.ioam6_id_wide=${BETA[1]}
+ ip netns exec $ioam_node_beta sysctl -wq net.ipv6.conf.veth0.ioam6_enabled=1
+ ip netns exec $ioam_node_beta sysctl -wq net.ipv6.conf.veth0.ioam6_id=${BETA[2]}
+ ip netns exec $ioam_node_beta sysctl -wq net.ipv6.conf.veth0.ioam6_id_wide=${BETA[3]}
+ ip netns exec $ioam_node_beta sysctl -wq net.ipv6.conf.veth1.ioam6_id=${BETA[4]}
+ ip netns exec $ioam_node_beta sysctl -wq net.ipv6.conf.veth1.ioam6_id_wide=${BETA[5]}
+ ip -netns $ioam_node_beta ioam namespace add 123 data ${BETA[6]} wide ${BETA[7]}
+ ip -netns $ioam_node_beta ioam schema add ${BETA[8]} "${BETA[9]}"
+ ip -netns $ioam_node_beta ioam namespace set 123 schema ${BETA[8]}
+
+ ip netns exec $ioam_node_gamma sysctl -wq net.ipv6.ioam6_id=${GAMMA[0]}
+ ip netns exec $ioam_node_gamma sysctl -wq net.ipv6.ioam6_id_wide=${GAMMA[1]}
+ ip netns exec $ioam_node_gamma sysctl -wq net.ipv6.conf.veth0.ioam6_enabled=1
+ ip netns exec $ioam_node_gamma sysctl -wq net.ipv6.conf.veth0.ioam6_id=${GAMMA[2]}
+ ip netns exec $ioam_node_gamma sysctl -wq net.ipv6.conf.veth0.ioam6_id_wide=${GAMMA[3]}
+ ip -netns $ioam_node_gamma ioam namespace add 123 data ${GAMMA[6]} wide ${GAMMA[7]}
sleep 1
- ip netns exec ioam-node-alpha ping6 -c 5 -W 1 db02::2 &>/dev/null
+ ip netns exec $ioam_node_alpha ping6 -c 5 -W 1 db02::2 &>/dev/null
if [ $? != 0 ]
then
echo "Setup FAILED"
@@ -412,7 +407,7 @@ run()
echo
# set OUTPUT settings
- ip netns exec ioam-node-beta sysctl -wq net.ipv6.conf.veth0.ioam6_enabled=0
+ ip netns exec $ioam_node_beta sysctl -wq net.ipv6.conf.veth0.ioam6_enabled=0
for t in $TESTS_OUTPUT
do
@@ -421,8 +416,8 @@ run()
done
# clean OUTPUT settings
- ip netns exec ioam-node-beta sysctl -wq net.ipv6.conf.veth0.ioam6_enabled=1
- ip -netns ioam-node-alpha route change db01::/64 dev veth0
+ ip netns exec $ioam_node_beta sysctl -wq net.ipv6.conf.veth0.ioam6_enabled=1
+ ip -netns $ioam_node_alpha route change db01::/64 dev veth0
echo
@@ -433,7 +428,7 @@ run()
echo
# set INPUT settings
- ip -netns ioam-node-alpha ioam namespace del 123
+ ip -netns $ioam_node_alpha ioam namespace del 123
for t in $TESTS_INPUT
do
@@ -442,10 +437,10 @@ run()
done
# clean INPUT settings
- ip -netns ioam-node-alpha ioam namespace add 123 \
+ ip -netns $ioam_node_alpha ioam namespace add 123 \
data ${ALPHA[6]} wide ${ALPHA[7]}
- ip -netns ioam-node-alpha ioam namespace set 123 schema ${ALPHA[8]}
- ip -netns ioam-node-alpha route change db01::/64 dev veth0
+ ip -netns $ioam_node_alpha ioam namespace set 123 schema ${ALPHA[8]}
+ ip -netns $ioam_node_alpha route change db01::/64 dev veth0
echo
printf "%0.s-" {1..74}
@@ -488,15 +483,15 @@ out_undef_ns()
local desc="Unknown IOAM namespace"
[ "$1" = "encap" ] && mode="$1 tundst db01::1" || mode="$1"
- [ "$1" = "encap" ] && ip -netns ioam-node-beta link set ip6tnl0 up
+ [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 up
- ip -netns ioam-node-alpha route change db01::/64 encap ioam6 mode $mode \
+ ip -netns $ioam_node_alpha route change db01::/64 encap ioam6 mode $mode \
trace prealloc type 0x800000 ns 0 size 4 dev veth0
- run_test ${FUNCNAME[0]} "${desc} ($1 mode)" ioam-node-alpha ioam-node-beta \
+ run_test ${FUNCNAME[0]} "${desc} ($1 mode)" $ioam_node_alpha $ioam_node_beta \
db01::2 db01::1 veth0 0x800000 0
- [ "$1" = "encap" ] && ip -netns ioam-node-beta link set ip6tnl0 down
+ [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 down
}
out_no_room()
@@ -508,15 +503,15 @@ out_no_room()
local desc="Missing trace room"
[ "$1" = "encap" ] && mode="$1 tundst db01::1" || mode="$1"
- [ "$1" = "encap" ] && ip -netns ioam-node-beta link set ip6tnl0 up
+ [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 up
- ip -netns ioam-node-alpha route change db01::/64 encap ioam6 mode $mode \
+ ip -netns $ioam_node_alpha route change db01::/64 encap ioam6 mode $mode \
trace prealloc type 0xc00000 ns 123 size 4 dev veth0
- run_test ${FUNCNAME[0]} "${desc} ($1 mode)" ioam-node-alpha ioam-node-beta \
+ run_test ${FUNCNAME[0]} "${desc} ($1 mode)" $ioam_node_alpha $ioam_node_beta \
db01::2 db01::1 veth0 0xc00000 123
- [ "$1" = "encap" ] && ip -netns ioam-node-beta link set ip6tnl0 down
+ [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 down
}
out_bits()
@@ -532,11 +527,11 @@ out_bits()
bit2size[22]=$(( $tmp + ${#ALPHA[9]} + ((4 - (${#ALPHA[9]} % 4)) % 4) ))
[ "$1" = "encap" ] && mode="$1 tundst db01::1" || mode="$1"
- [ "$1" = "encap" ] && ip -netns ioam-node-beta link set ip6tnl0 up
+ [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 up
for i in {0..22}
do
- ip -netns ioam-node-alpha route change db01::/64 encap ioam6 mode $mode \
+ ip -netns $ioam_node_alpha route change db01::/64 encap ioam6 mode $mode \
trace prealloc type ${bit2type[$i]} ns 123 size ${bit2size[$i]} \
dev veth0 &>/dev/null
@@ -554,12 +549,12 @@ out_bits()
log_test_failed "$descr"
fi
else
- run_test "out_bit$i" "$descr ($1 mode)" ioam-node-alpha \
- ioam-node-beta db01::2 db01::1 veth0 ${bit2type[$i]} 123
+ run_test "out_bit$i" "$descr ($1 mode)" $ioam_node_alpha \
+ $ioam_node_beta db01::2 db01::1 veth0 ${bit2type[$i]} 123
fi
done
- [ "$1" = "encap" ] && ip -netns ioam-node-beta link set ip6tnl0 down
+ [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 down
bit2size[22]=$tmp
}
@@ -573,15 +568,15 @@ out_full_supp_trace()
local desc="Full supported trace"
[ "$1" = "encap" ] && mode="$1 tundst db01::1" || mode="$1"
- [ "$1" = "encap" ] && ip -netns ioam-node-beta link set ip6tnl0 up
+ [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 up
- ip -netns ioam-node-alpha route change db01::/64 encap ioam6 mode $mode \
+ ip -netns $ioam_node_alpha route change db01::/64 encap ioam6 mode $mode \
trace prealloc type 0xfff002 ns 123 size 100 dev veth0
- run_test ${FUNCNAME[0]} "${desc} ($1 mode)" ioam-node-alpha ioam-node-beta \
+ run_test ${FUNCNAME[0]} "${desc} ($1 mode)" $ioam_node_alpha $ioam_node_beta \
db01::2 db01::1 veth0 0xfff002 123
- [ "$1" = "encap" ] && ip -netns ioam-node-beta link set ip6tnl0 down
+ [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 down
}
@@ -603,15 +598,15 @@ in_undef_ns()
local desc="Unknown IOAM namespace"
[ "$1" = "encap" ] && mode="$1 tundst db01::1" || mode="$1"
- [ "$1" = "encap" ] && ip -netns ioam-node-beta link set ip6tnl0 up
+ [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 up
- ip -netns ioam-node-alpha route change db01::/64 encap ioam6 mode $mode \
+ ip -netns $ioam_node_alpha route change db01::/64 encap ioam6 mode $mode \
trace prealloc type 0x800000 ns 0 size 4 dev veth0
- run_test ${FUNCNAME[0]} "${desc} ($1 mode)" ioam-node-alpha ioam-node-beta \
+ run_test ${FUNCNAME[0]} "${desc} ($1 mode)" $ioam_node_alpha $ioam_node_beta \
db01::2 db01::1 veth0 0x800000 0
- [ "$1" = "encap" ] && ip -netns ioam-node-beta link set ip6tnl0 down
+ [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 down
}
in_no_room()
@@ -623,15 +618,15 @@ in_no_room()
local desc="Missing trace room"
[ "$1" = "encap" ] && mode="$1 tundst db01::1" || mode="$1"
- [ "$1" = "encap" ] && ip -netns ioam-node-beta link set ip6tnl0 up
+ [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 up
- ip -netns ioam-node-alpha route change db01::/64 encap ioam6 mode $mode \
+ ip -netns $ioam_node_alpha route change db01::/64 encap ioam6 mode $mode \
trace prealloc type 0xc00000 ns 123 size 4 dev veth0
- run_test ${FUNCNAME[0]} "${desc} ($1 mode)" ioam-node-alpha ioam-node-beta \
+ run_test ${FUNCNAME[0]} "${desc} ($1 mode)" $ioam_node_alpha $ioam_node_beta \
db01::2 db01::1 veth0 0xc00000 123
- [ "$1" = "encap" ] && ip -netns ioam-node-beta link set ip6tnl0 down
+ [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 down
}
in_bits()
@@ -647,19 +642,19 @@ in_bits()
bit2size[22]=$(( $tmp + ${#BETA[9]} + ((4 - (${#BETA[9]} % 4)) % 4) ))
[ "$1" = "encap" ] && mode="$1 tundst db01::1" || mode="$1"
- [ "$1" = "encap" ] && ip -netns ioam-node-beta link set ip6tnl0 up
+ [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 up
for i in {0..11} {22..22}
do
- ip -netns ioam-node-alpha route change db01::/64 encap ioam6 mode $mode \
+ ip -netns $ioam_node_alpha route change db01::/64 encap ioam6 mode $mode \
trace prealloc type ${bit2type[$i]} ns 123 size ${bit2size[$i]} \
dev veth0
- run_test "in_bit$i" "${desc/<n>/$i} ($1 mode)" ioam-node-alpha \
- ioam-node-beta db01::2 db01::1 veth0 ${bit2type[$i]} 123
+ run_test "in_bit$i" "${desc/<n>/$i} ($1 mode)" $ioam_node_alpha \
+ $ioam_node_beta db01::2 db01::1 veth0 ${bit2type[$i]} 123
done
- [ "$1" = "encap" ] && ip -netns ioam-node-beta link set ip6tnl0 down
+ [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 down
bit2size[22]=$tmp
}
@@ -675,22 +670,22 @@ in_oflag()
# Exception:
# Here, we need the sender to set the Overflow flag. For that, we will add
# back the IOAM namespace that was previously configured on the sender.
- ip -netns ioam-node-alpha ioam namespace add 123
+ ip -netns $ioam_node_alpha ioam namespace add 123
[ "$1" = "encap" ] && mode="$1 tundst db01::1" || mode="$1"
- [ "$1" = "encap" ] && ip -netns ioam-node-beta link set ip6tnl0 up
+ [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 up
- ip -netns ioam-node-alpha route change db01::/64 encap ioam6 mode $mode \
+ ip -netns $ioam_node_alpha route change db01::/64 encap ioam6 mode $mode \
trace prealloc type 0xc00000 ns 123 size 4 dev veth0
- run_test ${FUNCNAME[0]} "${desc} ($1 mode)" ioam-node-alpha ioam-node-beta \
+ run_test ${FUNCNAME[0]} "${desc} ($1 mode)" $ioam_node_alpha $ioam_node_beta \
db01::2 db01::1 veth0 0xc00000 123
- [ "$1" = "encap" ] && ip -netns ioam-node-beta link set ip6tnl0 down
+ [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 down
# And we clean the exception for this test to get things back to normal for
# other INPUT tests
- ip -netns ioam-node-alpha ioam namespace del 123
+ ip -netns $ioam_node_alpha ioam namespace del 123
}
in_full_supp_trace()
@@ -702,15 +697,15 @@ in_full_supp_trace()
local desc="Full supported trace"
[ "$1" = "encap" ] && mode="$1 tundst db01::1" || mode="$1"
- [ "$1" = "encap" ] && ip -netns ioam-node-beta link set ip6tnl0 up
+ [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 up
- ip -netns ioam-node-alpha route change db01::/64 encap ioam6 mode $mode \
+ ip -netns $ioam_node_alpha route change db01::/64 encap ioam6 mode $mode \
trace prealloc type 0xfff002 ns 123 size 80 dev veth0
- run_test ${FUNCNAME[0]} "${desc} ($1 mode)" ioam-node-alpha ioam-node-beta \
+ run_test ${FUNCNAME[0]} "${desc} ($1 mode)" $ioam_node_alpha $ioam_node_beta \
db01::2 db01::1 veth0 0xfff002 123
- [ "$1" = "encap" ] && ip -netns ioam-node-beta link set ip6tnl0 down
+ [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 down
}
@@ -730,15 +725,15 @@ fwd_full_supp_trace()
local desc="Forward - Full supported trace"
[ "$1" = "encap" ] && mode="$1 tundst db02::2" || mode="$1"
- [ "$1" = "encap" ] && ip -netns ioam-node-gamma link set ip6tnl0 up
+ [ "$1" = "encap" ] && ip -netns $ioam_node_gamma link set ip6tnl0 up
- ip -netns ioam-node-alpha route change db02::/64 encap ioam6 mode $mode \
+ ip -netns $ioam_node_alpha route change db02::/64 encap ioam6 mode $mode \
trace prealloc type 0xfff002 ns 123 size 244 via db01::1 dev veth0
- run_test ${FUNCNAME[0]} "${desc} ($1 mode)" ioam-node-alpha ioam-node-gamma \
+ run_test ${FUNCNAME[0]} "${desc} ($1 mode)" $ioam_node_alpha $ioam_node_gamma \
db01::2 db02::2 veth0 0xfff002 123
- [ "$1" = "encap" ] && ip -netns ioam-node-gamma link set ip6tnl0 down
+ [ "$1" = "encap" ] && ip -netns $ioam_node_gamma link set ip6tnl0 down
}
diff --git a/tools/testing/selftests/net/ipsec.c b/tools/testing/selftests/net/ipsec.c
index 9a8229abfa02..be4a30a0d02a 100644
--- a/tools/testing/selftests/net/ipsec.c
+++ b/tools/testing/selftests/net/ipsec.c
@@ -2263,7 +2263,7 @@ static int check_results(void)
int main(int argc, char **argv)
{
- unsigned int nr_process = 1;
+ long nr_process = 1;
int route_sock = -1, ret = KSFT_SKIP;
int test_desc_fd[2];
uint32_t route_seq;
@@ -2284,7 +2284,7 @@ int main(int argc, char **argv)
exit_usage(argv);
}
- if (nr_process > MAX_PROCESSES || !nr_process) {
+ if (nr_process > MAX_PROCESSES || nr_process < 1) {
printk("nr_process should be between [1; %u]",
MAX_PROCESSES);
exit_usage(argv);
diff --git a/tools/testing/selftests/net/l2tp.sh b/tools/testing/selftests/net/l2tp.sh
index 5782433886fc..88de7166c8ae 100755
--- a/tools/testing/selftests/net/l2tp.sh
+++ b/tools/testing/selftests/net/l2tp.sh
@@ -13,6 +13,7 @@
# 10.1.1.1 | | 10.1.2.1
# 2001:db8:1::1 | | 2001:db8:2::1
+source lib.sh
VERBOSE=0
PAUSE_ON_FAIL=no
@@ -80,9 +81,6 @@ create_ns()
[ -z "${addr}" ] && addr="-"
[ -z "${addr6}" ] && addr6="-"
- ip netns add ${ns}
-
- ip -netns ${ns} link set lo up
if [ "${addr}" != "-" ]; then
ip -netns ${ns} addr add dev lo ${addr}
fi
@@ -133,12 +131,7 @@ connect_ns()
cleanup()
{
- local ns
-
- for ns in host-1 host-2 router
- do
- ip netns del ${ns} 2>/dev/null
- done
+ cleanup_ns $host_1 $host_2 $router
}
setup_l2tp_ipv4()
@@ -146,28 +139,28 @@ setup_l2tp_ipv4()
#
# configure l2tpv3 tunnel on host-1
#
- ip -netns host-1 l2tp add tunnel tunnel_id 1041 peer_tunnel_id 1042 \
+ ip -netns $host_1 l2tp add tunnel tunnel_id 1041 peer_tunnel_id 1042 \
encap ip local 10.1.1.1 remote 10.1.2.1
- ip -netns host-1 l2tp add session name l2tp4 tunnel_id 1041 \
+ ip -netns $host_1 l2tp add session name l2tp4 tunnel_id 1041 \
session_id 1041 peer_session_id 1042
- ip -netns host-1 link set dev l2tp4 up
- ip -netns host-1 addr add dev l2tp4 172.16.1.1 peer 172.16.1.2
+ ip -netns $host_1 link set dev l2tp4 up
+ ip -netns $host_1 addr add dev l2tp4 172.16.1.1 peer 172.16.1.2
#
# configure l2tpv3 tunnel on host-2
#
- ip -netns host-2 l2tp add tunnel tunnel_id 1042 peer_tunnel_id 1041 \
+ ip -netns $host_2 l2tp add tunnel tunnel_id 1042 peer_tunnel_id 1041 \
encap ip local 10.1.2.1 remote 10.1.1.1
- ip -netns host-2 l2tp add session name l2tp4 tunnel_id 1042 \
+ ip -netns $host_2 l2tp add session name l2tp4 tunnel_id 1042 \
session_id 1042 peer_session_id 1041
- ip -netns host-2 link set dev l2tp4 up
- ip -netns host-2 addr add dev l2tp4 172.16.1.2 peer 172.16.1.1
+ ip -netns $host_2 link set dev l2tp4 up
+ ip -netns $host_2 addr add dev l2tp4 172.16.1.2 peer 172.16.1.1
#
# add routes to loopback addresses
#
- ip -netns host-1 ro add 172.16.101.2/32 via 172.16.1.2
- ip -netns host-2 ro add 172.16.101.1/32 via 172.16.1.1
+ ip -netns $host_1 ro add 172.16.101.2/32 via 172.16.1.2
+ ip -netns $host_2 ro add 172.16.101.1/32 via 172.16.1.1
}
setup_l2tp_ipv6()
@@ -175,28 +168,28 @@ setup_l2tp_ipv6()
#
# configure l2tpv3 tunnel on host-1
#
- ip -netns host-1 l2tp add tunnel tunnel_id 1061 peer_tunnel_id 1062 \
+ ip -netns $host_1 l2tp add tunnel tunnel_id 1061 peer_tunnel_id 1062 \
encap ip local 2001:db8:1::1 remote 2001:db8:2::1
- ip -netns host-1 l2tp add session name l2tp6 tunnel_id 1061 \
+ ip -netns $host_1 l2tp add session name l2tp6 tunnel_id 1061 \
session_id 1061 peer_session_id 1062
- ip -netns host-1 link set dev l2tp6 up
- ip -netns host-1 addr add dev l2tp6 fc00:1::1 peer fc00:1::2
+ ip -netns $host_1 link set dev l2tp6 up
+ ip -netns $host_1 addr add dev l2tp6 fc00:1::1 peer fc00:1::2
#
# configure l2tpv3 tunnel on host-2
#
- ip -netns host-2 l2tp add tunnel tunnel_id 1062 peer_tunnel_id 1061 \
+ ip -netns $host_2 l2tp add tunnel tunnel_id 1062 peer_tunnel_id 1061 \
encap ip local 2001:db8:2::1 remote 2001:db8:1::1
- ip -netns host-2 l2tp add session name l2tp6 tunnel_id 1062 \
+ ip -netns $host_2 l2tp add session name l2tp6 tunnel_id 1062 \
session_id 1062 peer_session_id 1061
- ip -netns host-2 link set dev l2tp6 up
- ip -netns host-2 addr add dev l2tp6 fc00:1::2 peer fc00:1::1
+ ip -netns $host_2 link set dev l2tp6 up
+ ip -netns $host_2 addr add dev l2tp6 fc00:1::2 peer fc00:1::1
#
# add routes to loopback addresses
#
- ip -netns host-1 -6 ro add fc00:101::2/128 via fc00:1::2
- ip -netns host-2 -6 ro add fc00:101::1/128 via fc00:1::1
+ ip -netns $host_1 -6 ro add fc00:101::2/128 via fc00:1::2
+ ip -netns $host_2 -6 ro add fc00:101::1/128 via fc00:1::1
}
setup()
@@ -205,21 +198,22 @@ setup()
cleanup
set -e
- create_ns host-1 172.16.101.1/32 fc00:101::1/128
- create_ns host-2 172.16.101.2/32 fc00:101::2/128
- create_ns router
+ setup_ns host_1 host_2 router
+ create_ns $host_1 172.16.101.1/32 fc00:101::1/128
+ create_ns $host_2 172.16.101.2/32 fc00:101::2/128
+ create_ns $router
- connect_ns host-1 eth0 10.1.1.1/24 2001:db8:1::1/64 \
- router eth1 10.1.1.2/24 2001:db8:1::2/64
+ connect_ns $host_1 eth0 10.1.1.1/24 2001:db8:1::1/64 \
+ $router eth1 10.1.1.2/24 2001:db8:1::2/64
- connect_ns host-2 eth0 10.1.2.1/24 2001:db8:2::1/64 \
- router eth2 10.1.2.2/24 2001:db8:2::2/64
+ connect_ns $host_2 eth0 10.1.2.1/24 2001:db8:2::1/64 \
+ $router eth2 10.1.2.2/24 2001:db8:2::2/64
- ip -netns host-1 ro add 10.1.2.0/24 via 10.1.1.2
- ip -netns host-1 -6 ro add 2001:db8:2::/64 via 2001:db8:1::2
+ ip -netns $host_1 ro add 10.1.2.0/24 via 10.1.1.2
+ ip -netns $host_1 -6 ro add 2001:db8:2::/64 via 2001:db8:1::2
- ip -netns host-2 ro add 10.1.1.0/24 via 10.1.2.2
- ip -netns host-2 -6 ro add 2001:db8:1::/64 via 2001:db8:2::2
+ ip -netns $host_2 ro add 10.1.1.0/24 via 10.1.2.2
+ ip -netns $host_2 -6 ro add 2001:db8:1::/64 via 2001:db8:2::2
setup_l2tp_ipv4
setup_l2tp_ipv6
@@ -231,38 +225,38 @@ setup_ipsec()
#
# IPv4
#
- run_cmd host-1 ip xfrm policy add \
+ run_cmd $host_1 ip xfrm policy add \
src 10.1.1.1 dst 10.1.2.1 dir out \
tmpl proto esp mode transport
- run_cmd host-1 ip xfrm policy add \
+ run_cmd $host_1 ip xfrm policy add \
src 10.1.2.1 dst 10.1.1.1 dir in \
tmpl proto esp mode transport
- run_cmd host-2 ip xfrm policy add \
+ run_cmd $host_2 ip xfrm policy add \
src 10.1.1.1 dst 10.1.2.1 dir in \
tmpl proto esp mode transport
- run_cmd host-2 ip xfrm policy add \
+ run_cmd $host_2 ip xfrm policy add \
src 10.1.2.1 dst 10.1.1.1 dir out \
tmpl proto esp mode transport
- ip -netns host-1 xfrm state add \
+ ip -netns $host_1 xfrm state add \
src 10.1.1.1 dst 10.1.2.1 \
spi 0x1000 proto esp aead 'rfc4106(gcm(aes))' \
0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode transport
- ip -netns host-1 xfrm state add \
+ ip -netns $host_1 xfrm state add \
src 10.1.2.1 dst 10.1.1.1 \
spi 0x1001 proto esp aead 'rfc4106(gcm(aes))' \
0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode transport
- ip -netns host-2 xfrm state add \
+ ip -netns $host_2 xfrm state add \
src 10.1.1.1 dst 10.1.2.1 \
spi 0x1000 proto esp aead 'rfc4106(gcm(aes))' \
0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode transport
- ip -netns host-2 xfrm state add \
+ ip -netns $host_2 xfrm state add \
src 10.1.2.1 dst 10.1.1.1 \
spi 0x1001 proto esp aead 'rfc4106(gcm(aes))' \
0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode transport
@@ -270,38 +264,38 @@ setup_ipsec()
#
# IPV6
#
- run_cmd host-1 ip -6 xfrm policy add \
+ run_cmd $host_1 ip -6 xfrm policy add \
src 2001:db8:1::1 dst 2001:db8:2::1 dir out \
tmpl proto esp mode transport
- run_cmd host-1 ip -6 xfrm policy add \
+ run_cmd $host_1 ip -6 xfrm policy add \
src 2001:db8:2::1 dst 2001:db8:1::1 dir in \
tmpl proto esp mode transport
- run_cmd host-2 ip -6 xfrm policy add \
+ run_cmd $host_2 ip -6 xfrm policy add \
src 2001:db8:1::1 dst 2001:db8:2::1 dir in \
tmpl proto esp mode transport
- run_cmd host-2 ip -6 xfrm policy add \
+ run_cmd $host_2 ip -6 xfrm policy add \
src 2001:db8:2::1 dst 2001:db8:1::1 dir out \
tmpl proto esp mode transport
- ip -netns host-1 -6 xfrm state add \
+ ip -netns $host_1 -6 xfrm state add \
src 2001:db8:1::1 dst 2001:db8:2::1 \
spi 0x1000 proto esp aead 'rfc4106(gcm(aes))' \
0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode transport
- ip -netns host-1 -6 xfrm state add \
+ ip -netns $host_1 -6 xfrm state add \
src 2001:db8:2::1 dst 2001:db8:1::1 \
spi 0x1001 proto esp aead 'rfc4106(gcm(aes))' \
0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode transport
- ip -netns host-2 -6 xfrm state add \
+ ip -netns $host_2 -6 xfrm state add \
src 2001:db8:1::1 dst 2001:db8:2::1 \
spi 0x1000 proto esp aead 'rfc4106(gcm(aes))' \
0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode transport
- ip -netns host-2 -6 xfrm state add \
+ ip -netns $host_2 -6 xfrm state add \
src 2001:db8:2::1 dst 2001:db8:1::1 \
spi 0x1001 proto esp aead 'rfc4106(gcm(aes))' \
0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode transport
@@ -309,10 +303,10 @@ setup_ipsec()
teardown_ipsec()
{
- run_cmd host-1 ip xfrm state flush
- run_cmd host-1 ip xfrm policy flush
- run_cmd host-2 ip xfrm state flush
- run_cmd host-2 ip xfrm policy flush
+ run_cmd $host_1 ip xfrm state flush
+ run_cmd $host_1 ip xfrm policy flush
+ run_cmd $host_2 ip xfrm state flush
+ run_cmd $host_2 ip xfrm policy flush
}
################################################################################
@@ -322,16 +316,16 @@ run_ping()
{
local desc="$1"
- run_cmd host-1 ping -c1 -w1 172.16.1.2
+ run_cmd $host_1 ping -c1 -w1 172.16.1.2
log_test $? 0 "IPv4 basic L2TP tunnel ${desc}"
- run_cmd host-1 ping -c1 -w1 -I 172.16.101.1 172.16.101.2
+ run_cmd $host_1 ping -c1 -w1 -I 172.16.101.1 172.16.101.2
log_test $? 0 "IPv4 route through L2TP tunnel ${desc}"
- run_cmd host-1 ${ping6} -c1 -w1 fc00:1::2
+ run_cmd $host_1 ${ping6} -c1 -w1 fc00:1::2
log_test $? 0 "IPv6 basic L2TP tunnel ${desc}"
- run_cmd host-1 ${ping6} -c1 -w1 -I fc00:101::1 fc00:101::2
+ run_cmd $host_1 ${ping6} -c1 -w1 -I fc00:101::1 fc00:101::2
log_test $? 0 "IPv6 route through L2TP tunnel ${desc}"
}
@@ -344,16 +338,16 @@ run_tests()
setup_ipsec
run_ping "- with IPsec"
- run_cmd host-1 ping -c1 -w1 172.16.1.2
+ run_cmd $host_1 ping -c1 -w1 172.16.1.2
log_test $? 0 "IPv4 basic L2TP tunnel ${desc}"
- run_cmd host-1 ping -c1 -w1 -I 172.16.101.1 172.16.101.2
+ run_cmd $host_1 ping -c1 -w1 -I 172.16.101.1 172.16.101.2
log_test $? 0 "IPv4 route through L2TP tunnel ${desc}"
- run_cmd host-1 ${ping6} -c1 -w1 fc00:1::2
+ run_cmd $host_1 ${ping6} -c1 -w1 fc00:1::2
log_test $? 0 "IPv6 basic L2TP tunnel - with IPsec"
- run_cmd host-1 ${ping6} -c1 -w1 -I fc00:101::1 fc00:101::2
+ run_cmd $host_1 ${ping6} -c1 -w1 -I fc00:101::1 fc00:101::2
log_test $? 0 "IPv6 route through L2TP tunnel - with IPsec"
teardown_ipsec
diff --git a/tools/testing/selftests/net/lib.sh b/tools/testing/selftests/net/lib.sh
new file mode 100644
index 000000000000..dca549443801
--- /dev/null
+++ b/tools/testing/selftests/net/lib.sh
@@ -0,0 +1,93 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+
+##############################################################################
+# Defines
+
+# Kselftest framework requirement - SKIP code is 4.
+ksft_skip=4
+# namespace list created by setup_ns
+NS_LIST=""
+
+##############################################################################
+# Helpers
+busywait()
+{
+ local timeout=$1; shift
+
+ local start_time="$(date -u +%s%3N)"
+ while true
+ do
+ local out
+ out=$("$@")
+ local ret=$?
+ if ((!ret)); then
+ echo -n "$out"
+ return 0
+ fi
+
+ local current_time="$(date -u +%s%3N)"
+ if ((current_time - start_time > timeout)); then
+ echo -n "$out"
+ return 1
+ fi
+ done
+}
+
+cleanup_ns()
+{
+ local ns=""
+ local errexit=0
+ local ret=0
+
+ # disable errexit temporary
+ if [[ $- =~ "e" ]]; then
+ errexit=1
+ set +e
+ fi
+
+ for ns in "$@"; do
+ ip netns delete "${ns}" &> /dev/null
+ if ! busywait 2 ip netns list \| grep -vq "^$ns$" &> /dev/null; then
+ echo "Warn: Failed to remove namespace $ns"
+ ret=1
+ fi
+ done
+
+ [ $errexit -eq 1 ] && set -e
+ return $ret
+}
+
+cleanup_all_ns()
+{
+ cleanup_ns $NS_LIST
+}
+
+# setup netns with given names as prefix. e.g
+# setup_ns local remote
+setup_ns()
+{
+ local ns=""
+ local ns_name=""
+ local ns_list=""
+ for ns_name in "$@"; do
+ # Some test may setup/remove same netns multi times
+ if unset ${ns_name} 2> /dev/null; then
+ ns="${ns_name,,}-$(mktemp -u XXXXXX)"
+ eval readonly ${ns_name}="$ns"
+ else
+ eval ns='$'${ns_name}
+ cleanup_ns "$ns"
+
+ fi
+
+ if ! ip netns add "$ns"; then
+ echo "Failed to create namespace $ns_name"
+ cleanup_ns "$ns_list"
+ return $ksft_skip
+ fi
+ ip -n "$ns" link set lo up
+ ns_list="$ns_list $ns"
+ done
+ NS_LIST="$NS_LIST $ns_list"
+}
diff --git a/tools/testing/selftests/net/mptcp/mptcp_connect.c b/tools/testing/selftests/net/mptcp/mptcp_connect.c
index c7f9ebeebc2c..d2043ec3bf6d 100644
--- a/tools/testing/selftests/net/mptcp/mptcp_connect.c
+++ b/tools/testing/selftests/net/mptcp/mptcp_connect.c
@@ -18,6 +18,7 @@
#include <sys/ioctl.h>
#include <sys/poll.h>
+#include <sys/random.h>
#include <sys/sendfile.h>
#include <sys/stat.h>
#include <sys/socket.h>
@@ -1125,15 +1126,11 @@ again:
static void init_rng(void)
{
- int fd = open("/dev/urandom", O_RDONLY);
unsigned int foo;
- if (fd > 0) {
- int ret = read(fd, &foo, sizeof(foo));
-
- if (ret < 0)
- srand(fd + foo);
- close(fd);
+ if (getrandom(&foo, sizeof(foo), 0) == -1) {
+ perror("getrandom");
+ exit(1);
}
srand(foo);
diff --git a/tools/testing/selftests/net/mptcp/mptcp_inq.c b/tools/testing/selftests/net/mptcp/mptcp_inq.c
index 8672d898f8cd..218aac467321 100644
--- a/tools/testing/selftests/net/mptcp/mptcp_inq.c
+++ b/tools/testing/selftests/net/mptcp/mptcp_inq.c
@@ -18,6 +18,7 @@
#include <time.h>
#include <sys/ioctl.h>
+#include <sys/random.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
@@ -519,15 +520,11 @@ static int client(int unixfd)
static void init_rng(void)
{
- int fd = open("/dev/urandom", O_RDONLY);
unsigned int foo;
- if (fd > 0) {
- int ret = read(fd, &foo, sizeof(foo));
-
- if (ret < 0)
- srand(fd + foo);
- close(fd);
+ if (getrandom(&foo, sizeof(foo), 0) == -1) {
+ perror("getrandom");
+ exit(1);
}
srand(foo);
diff --git a/tools/testing/selftests/net/msg_zerocopy.sh b/tools/testing/selftests/net/msg_zerocopy.sh
index 825ffec85cea..89c22f5320e0 100755
--- a/tools/testing/selftests/net/msg_zerocopy.sh
+++ b/tools/testing/selftests/net/msg_zerocopy.sh
@@ -70,23 +70,22 @@ case "${TXMODE}" in
esac
# Start of state changes: install cleanup handler
-save_sysctl_mem="$(sysctl -n ${path_sysctl_mem})"
cleanup() {
ip netns del "${NS2}"
ip netns del "${NS1}"
- sysctl -w -q "${path_sysctl_mem}=${save_sysctl_mem}"
}
trap cleanup EXIT
-# Configure system settings
-sysctl -w -q "${path_sysctl_mem}=1000000"
-
# Create virtual ethernet pair between network namespaces
ip netns add "${NS1}"
ip netns add "${NS2}"
+# Configure system settings
+ip netns exec "${NS1}" sysctl -w -q "${path_sysctl_mem}=1000000"
+ip netns exec "${NS2}" sysctl -w -q "${path_sysctl_mem}=1000000"
+
ip link add "${DEV}" mtu "${DEV_MTU}" netns "${NS1}" type veth \
peer name "${DEV}" mtu "${DEV_MTU}" netns "${NS2}"
diff --git a/tools/testing/selftests/net/ndisc_unsolicited_na_test.sh b/tools/testing/selftests/net/ndisc_unsolicited_na_test.sh
index 86e621b7b9c7..5db69dad0cfc 100755
--- a/tools/testing/selftests/net/ndisc_unsolicited_na_test.sh
+++ b/tools/testing/selftests/net/ndisc_unsolicited_na_test.sh
@@ -10,16 +10,12 @@
# 0 1 0 Don't update NC
# 0 1 1 Add a STALE NC entry
+source lib.sh
ret=0
-# Kselftest framework requirement - SKIP code is 4.
-ksft_skip=4
PAUSE_ON_FAIL=no
PAUSE=no
-HOST_NS="ns-host"
-ROUTER_NS="ns-router"
-
HOST_INTF="veth-host"
ROUTER_INTF="veth-router"
@@ -29,11 +25,6 @@ SUBNET_WIDTH=64
ROUTER_ADDR_WITH_MASK="${ROUTER_ADDR}/${SUBNET_WIDTH}"
HOST_ADDR_WITH_MASK="${HOST_ADDR}/${SUBNET_WIDTH}"
-IP_HOST="ip -6 -netns ${HOST_NS}"
-IP_HOST_EXEC="ip netns exec ${HOST_NS}"
-IP_ROUTER="ip -6 -netns ${ROUTER_NS}"
-IP_ROUTER_EXEC="ip netns exec ${ROUTER_NS}"
-
tcpdump_stdout=
tcpdump_stderr=
@@ -76,8 +67,12 @@ setup()
# Setup two namespaces and a veth tunnel across them.
# On end of the tunnel is a router and the other end is a host.
- ip netns add ${HOST_NS}
- ip netns add ${ROUTER_NS}
+ setup_ns HOST_NS ROUTER_NS
+ IP_HOST="ip -6 -netns ${HOST_NS}"
+ IP_HOST_EXEC="ip netns exec ${HOST_NS}"
+ IP_ROUTER="ip -6 -netns ${ROUTER_NS}"
+ IP_ROUTER_EXEC="ip netns exec ${ROUTER_NS}"
+
${IP_ROUTER} link add ${ROUTER_INTF} type veth \
peer name ${HOST_INTF} netns ${HOST_NS}
diff --git a/tools/testing/selftests/net/sctp_vrf.sh b/tools/testing/selftests/net/sctp_vrf.sh
index c721e952e5f3..c854034b6aa1 100755
--- a/tools/testing/selftests/net/sctp_vrf.sh
+++ b/tools/testing/selftests/net/sctp_vrf.sh
@@ -6,13 +6,11 @@
# SERVER_NS
# CLIENT_NS2 (veth1) <---> (veth2) -> vrf_s2
-CLIENT_NS1="client-ns1"
-CLIENT_NS2="client-ns2"
+source lib.sh
CLIENT_IP4="10.0.0.1"
CLIENT_IP6="2000::1"
CLIENT_PORT=1234
-SERVER_NS="server-ns"
SERVER_IP4="10.0.0.2"
SERVER_IP6="2000::2"
SERVER_PORT=1234
@@ -20,9 +18,7 @@ SERVER_PORT=1234
setup() {
modprobe sctp
modprobe sctp_diag
- ip netns add $CLIENT_NS1
- ip netns add $CLIENT_NS2
- ip netns add $SERVER_NS
+ setup_ns CLIENT_NS1 CLIENT_NS2 SERVER_NS
ip net exec $CLIENT_NS1 sysctl -w net.ipv6.conf.default.accept_dad=0 2>&1 >/dev/null
ip net exec $CLIENT_NS2 sysctl -w net.ipv6.conf.default.accept_dad=0 2>&1 >/dev/null
@@ -67,9 +63,7 @@ setup() {
cleanup() {
ip netns exec $SERVER_NS pkill sctp_hello 2>&1 >/dev/null
- ip netns del "$CLIENT_NS1"
- ip netns del "$CLIENT_NS2"
- ip netns del "$SERVER_NS"
+ cleanup_ns $CLIENT_NS1 $CLIENT_NS2 $SERVER_NS
}
wait_server() {
diff --git a/tools/testing/selftests/net/settings b/tools/testing/selftests/net/settings
index dfc27cdc6c05..ed8418e8217a 100644
--- a/tools/testing/selftests/net/settings
+++ b/tools/testing/selftests/net/settings
@@ -1 +1 @@
-timeout=1500
+timeout=3600
diff --git a/tools/testing/selftests/net/srv6_end_dt46_l3vpn_test.sh b/tools/testing/selftests/net/srv6_end_dt46_l3vpn_test.sh
index 441eededa031..02d617040793 100755
--- a/tools/testing/selftests/net/srv6_end_dt46_l3vpn_test.sh
+++ b/tools/testing/selftests/net/srv6_end_dt46_l3vpn_test.sh
@@ -193,8 +193,7 @@
# +---------------------------------------------------+
#
-# Kselftest framework requirement - SKIP code is 4.
-ksft_skip=4
+source lib.sh
readonly LOCALSID_TABLE_ID=90
readonly IPv6_RT_NETWORK=fd00
@@ -250,26 +249,22 @@ cleanup()
ip link del veth-rt-1 2>/dev/null || true
ip link del veth-rt-2 2>/dev/null || true
- # destroy routers rt-* and hosts hs-*
- for ns in $(ip netns show | grep -E 'rt-*|hs-*'); do
- ip netns del ${ns} || true
- done
+ cleanup_all_ns
}
# Setup the basic networking for the routers
setup_rt_networking()
{
- local rt=$1
- local nsname=rt-${rt}
+ local id=$1
+ eval local nsname=\${rt_${id}}
- ip netns add ${nsname}
- ip link set veth-rt-${rt} netns ${nsname}
- ip -netns ${nsname} link set veth-rt-${rt} name veth0
+ ip link set veth-rt-${id} netns ${nsname}
+ ip -netns ${nsname} link set veth-rt-${id} name veth0
ip netns exec ${nsname} sysctl -wq net.ipv6.conf.all.accept_dad=0
ip netns exec ${nsname} sysctl -wq net.ipv6.conf.default.accept_dad=0
- ip -netns ${nsname} addr add ${IPv6_RT_NETWORK}::${rt}/64 dev veth0 nodad
+ ip -netns ${nsname} addr add ${IPv6_RT_NETWORK}::${id}/64 dev veth0 nodad
ip -netns ${nsname} link set veth0 up
ip -netns ${nsname} link set lo up
@@ -279,16 +274,14 @@ setup_rt_networking()
setup_hs()
{
- local hs=$1
- local rt=$2
+ local hid=$1
+ local rid=$2
local tid=$3
- local hsname=hs-t${tid}-${hs}
- local rtname=rt-${rt}
+ eval local hsname=\${hs_t${tid}_${hid}}
+ eval local rtname=\${rt_${rid}}
local rtveth=veth-t${tid}
# set the networking for the host
- ip netns add ${hsname}
-
ip netns exec ${hsname} sysctl -wq net.ipv6.conf.all.accept_dad=0
ip netns exec ${hsname} sysctl -wq net.ipv6.conf.default.accept_dad=0
@@ -299,8 +292,8 @@ setup_hs()
ip -netns ${hsname} link add veth0 type veth peer name ${rtveth}
ip -netns ${hsname} link set ${rtveth} netns ${rtname}
- ip -netns ${hsname} addr add ${IPv6_HS_NETWORK}::${hs}/64 dev veth0 nodad
- ip -netns ${hsname} addr add ${IPv4_HS_NETWORK}.${hs}/24 dev veth0
+ ip -netns ${hsname} addr add ${IPv6_HS_NETWORK}::${hid}/64 dev veth0 nodad
+ ip -netns ${hsname} addr add ${IPv4_HS_NETWORK}.${hid}/24 dev veth0
ip -netns ${hsname} link set veth0 up
ip -netns ${hsname} link set lo up
@@ -332,10 +325,8 @@ setup_vpn_config()
local rtdst=$4
local tid=$5
- local hssrc_name=hs-t${tid}-${hssrc}
- local hsdst_name=hs-t${tid}-${hsdst}
- local rtsrc_name=rt-${rtsrc}
- local rtdst_name=rt-${rtdst}
+ eval local rtsrc_name=\${rt_${rtsrc}}
+ eval local rtdst_name=\${rt_${rtdst}}
local rtveth=veth-t${tid}
local vpn_sid=${VPN_LOCATOR_SERVICE}:${hssrc}${hsdst}:${tid}::6046
@@ -379,18 +370,21 @@ setup()
{
ip link add veth-rt-1 type veth peer name veth-rt-2
# setup the networking for router rt-1 and router rt-2
+ setup_ns rt_1 rt_2
setup_rt_networking 1
setup_rt_networking 2
# setup two hosts for the tenant 100.
# - host hs-1 is directly connected to the router rt-1;
# - host hs-2 is directly connected to the router rt-2.
+ setup_ns hs_t100_1 hs_t100_2
setup_hs 1 1 100 #args: host router tenant
setup_hs 2 2 100
# setup two hosts for the tenant 200
# - host hs-3 is directly connected to the router rt-1;
# - host hs-4 is directly connected to the router rt-2.
+ setup_ns hs_t200_3 hs_t200_4
setup_hs 3 1 200
setup_hs 4 2 200
@@ -409,8 +403,9 @@ check_rt_connectivity()
{
local rtsrc=$1
local rtdst=$2
+ eval local nsname=\${rt_${rtsrc}}
- ip netns exec rt-${rtsrc} ping -c 1 -W 1 ${IPv6_RT_NETWORK}::${rtdst} \
+ ip netns exec ${nsname} ping -c 1 -W 1 ${IPv6_RT_NETWORK}::${rtdst} \
>/dev/null 2>&1
}
@@ -428,8 +423,9 @@ check_hs_ipv6_connectivity()
local hssrc=$1
local hsdst=$2
local tid=$3
+ eval local nsname=\${hs_t${tid}_${hssrc}}
- ip netns exec hs-t${tid}-${hssrc} ping -c 1 -W ${PING_TIMEOUT_SEC} \
+ ip netns exec ${nsname} ping -c 1 -W ${PING_TIMEOUT_SEC} \
${IPv6_HS_NETWORK}::${hsdst} >/dev/null 2>&1
}
@@ -438,8 +434,9 @@ check_hs_ipv4_connectivity()
local hssrc=$1
local hsdst=$2
local tid=$3
+ eval local nsname=\${hs_t${tid}_${hssrc}}
- ip netns exec hs-t${tid}-${hssrc} ping -c 1 -W ${PING_TIMEOUT_SEC} \
+ ip netns exec ${nsname} ping -c 1 -W ${PING_TIMEOUT_SEC} \
${IPv4_HS_NETWORK}.${hsdst} >/dev/null 2>&1
}
diff --git a/tools/testing/selftests/net/srv6_end_dt4_l3vpn_test.sh b/tools/testing/selftests/net/srv6_end_dt4_l3vpn_test.sh
index f96282362811..79fb81e63c59 100755
--- a/tools/testing/selftests/net/srv6_end_dt4_l3vpn_test.sh
+++ b/tools/testing/selftests/net/srv6_end_dt4_l3vpn_test.sh
@@ -163,8 +163,7 @@
# +---------------------------------------------------+
#
-# Kselftest framework requirement - SKIP code is 4.
-ksft_skip=4
+source lib.sh
readonly LOCALSID_TABLE_ID=90
readonly IPv6_RT_NETWORK=fd00
@@ -219,27 +218,22 @@ cleanup()
ip link del veth-rt-1 2>/dev/null || true
ip link del veth-rt-2 2>/dev/null || true
- # destroy routers rt-* and hosts hs-*
- for ns in $(ip netns show | grep -E 'rt-*|hs-*'); do
- ip netns del ${ns} || true
- done
+ cleanup_all_ns
}
# Setup the basic networking for the routers
setup_rt_networking()
{
- local rt=$1
- local nsname=rt-${rt}
-
- ip netns add ${nsname}
+ local id=$1
+ eval local nsname=\${rt_${id}}
ip netns exec ${nsname} sysctl -wq net.ipv6.conf.all.accept_dad=0
ip netns exec ${nsname} sysctl -wq net.ipv6.conf.default.accept_dad=0
- ip link set veth-rt-${rt} netns ${nsname}
- ip -netns ${nsname} link set veth-rt-${rt} name veth0
+ ip link set veth-rt-${id} netns ${nsname}
+ ip -netns ${nsname} link set veth-rt-${id} name veth0
- ip -netns ${nsname} addr add ${IPv6_RT_NETWORK}::${rt}/64 dev veth0 nodad
+ ip -netns ${nsname} addr add ${IPv6_RT_NETWORK}::${id}/64 dev veth0 nodad
ip -netns ${nsname} link set veth0 up
ip -netns ${nsname} link set lo up
@@ -249,16 +243,13 @@ setup_rt_networking()
setup_hs()
{
- local hs=$1
- local rt=$2
+ local hid=$1
+ local rid=$2
local tid=$3
- local hsname=hs-t${tid}-${hs}
- local rtname=rt-${rt}
+ eval local hsname=\${hs_t${tid}_${hid}}
+ eval local rtname=\${rt_${rid}}
local rtveth=veth-t${tid}
- # set the networking for the host
- ip netns add ${hsname}
-
# disable the rp_filter otherwise the kernel gets confused about how
# to route decap ipv4 packets.
ip netns exec ${rtname} sysctl -wq net.ipv4.conf.all.rp_filter=0
@@ -266,7 +257,7 @@ setup_hs()
ip -netns ${hsname} link add veth0 type veth peer name ${rtveth}
ip -netns ${hsname} link set ${rtveth} netns ${rtname}
- ip -netns ${hsname} addr add ${IPv4_HS_NETWORK}.${hs}/24 dev veth0
+ ip -netns ${hsname} addr add ${IPv4_HS_NETWORK}.${hid}/24 dev veth0
ip -netns ${hsname} link set veth0 up
ip -netns ${hsname} link set lo up
@@ -293,10 +284,8 @@ setup_vpn_config()
local rtdst=$4
local tid=$5
- local hssrc_name=hs-t${tid}-${hssrc}
- local hsdst_name=hs-t${tid}-${hsdst}
- local rtsrc_name=rt-${rtsrc}
- local rtdst_name=rt-${rtdst}
+ eval local rtsrc_name=\${rt_${rtsrc}}
+ eval local rtdst_name=\${rt_${rtdst}}
local vpn_sid=${VPN_LOCATOR_SERVICE}:${hssrc}${hsdst}:${tid}::6004
# set the encap route for encapsulating packets which arrive from the
@@ -328,18 +317,21 @@ setup()
{
ip link add veth-rt-1 type veth peer name veth-rt-2
# setup the networking for router rt-1 and router rt-2
+ setup_ns rt_1 rt_2
setup_rt_networking 1
setup_rt_networking 2
# setup two hosts for the tenant 100.
# - host hs-1 is directly connected to the router rt-1;
# - host hs-2 is directly connected to the router rt-2.
+ setup_ns hs_t100_1 hs_t100_2
setup_hs 1 1 100 #args: host router tenant
setup_hs 2 2 100
# setup two hosts for the tenant 200
# - host hs-3 is directly connected to the router rt-1;
# - host hs-4 is directly connected to the router rt-2.
+ setup_ns hs_t200_3 hs_t200_4
setup_hs 3 1 200
setup_hs 4 2 200
@@ -358,8 +350,9 @@ check_rt_connectivity()
{
local rtsrc=$1
local rtdst=$2
+ eval local nsname=\${rt_${rtsrc}}
- ip netns exec rt-${rtsrc} ping -c 1 -W 1 ${IPv6_RT_NETWORK}::${rtdst} \
+ ip netns exec ${nsname} ping -c 1 -W 1 ${IPv6_RT_NETWORK}::${rtdst} \
>/dev/null 2>&1
}
@@ -377,8 +370,9 @@ check_hs_connectivity()
local hssrc=$1
local hsdst=$2
local tid=$3
+ eval local nsname=\${hs_t${tid}_${hssrc}}
- ip netns exec hs-t${tid}-${hssrc} ping -c 1 -W ${PING_TIMEOUT_SEC} \
+ ip netns exec ${nsname} ping -c 1 -W ${PING_TIMEOUT_SEC} \
${IPv4_HS_NETWORK}.${hsdst} >/dev/null 2>&1
}
diff --git a/tools/testing/selftests/net/srv6_end_dt6_l3vpn_test.sh b/tools/testing/selftests/net/srv6_end_dt6_l3vpn_test.sh
index b9b06ef80d88..e408406d8489 100755
--- a/tools/testing/selftests/net/srv6_end_dt6_l3vpn_test.sh
+++ b/tools/testing/selftests/net/srv6_end_dt6_l3vpn_test.sh
@@ -164,8 +164,7 @@
# +---------------------------------------------------+
#
-# Kselftest framework requirement - SKIP code is 4.
-ksft_skip=4
+source lib.sh
readonly LOCALSID_TABLE_ID=90
readonly IPv6_RT_NETWORK=fd00
@@ -220,26 +219,22 @@ cleanup()
ip link del veth-rt-1 2>/dev/null || true
ip link del veth-rt-2 2>/dev/null || true
- # destroy routers rt-* and hosts hs-*
- for ns in $(ip netns show | grep -E 'rt-*|hs-*'); do
- ip netns del ${ns} || true
- done
+ cleanup_all_ns
}
# Setup the basic networking for the routers
setup_rt_networking()
{
- local rt=$1
- local nsname=rt-${rt}
+ local id=$1
+ eval local nsname=\${rt_${id}}
- ip netns add ${nsname}
- ip link set veth-rt-${rt} netns ${nsname}
- ip -netns ${nsname} link set veth-rt-${rt} name veth0
+ ip link set veth-rt-${id} netns ${nsname}
+ ip -netns ${nsname} link set veth-rt-${id} name veth0
ip netns exec ${nsname} sysctl -wq net.ipv6.conf.all.accept_dad=0
ip netns exec ${nsname} sysctl -wq net.ipv6.conf.default.accept_dad=0
- ip -netns ${nsname} addr add ${IPv6_RT_NETWORK}::${rt}/64 dev veth0 nodad
+ ip -netns ${nsname} addr add ${IPv6_RT_NETWORK}::${id}/64 dev veth0 nodad
ip -netns ${nsname} link set veth0 up
ip -netns ${nsname} link set lo up
@@ -248,22 +243,20 @@ setup_rt_networking()
setup_hs()
{
- local hs=$1
- local rt=$2
+ local hid=$1
+ local rid=$2
local tid=$3
- local hsname=hs-t${tid}-${hs}
- local rtname=rt-${rt}
+ eval local hsname=\${hs_t${tid}_${hid}}
+ eval local rtname=\${rt_${rid}}
local rtveth=veth-t${tid}
# set the networking for the host
- ip netns add ${hsname}
-
ip netns exec ${hsname} sysctl -wq net.ipv6.conf.all.accept_dad=0
ip netns exec ${hsname} sysctl -wq net.ipv6.conf.default.accept_dad=0
ip -netns ${hsname} link add veth0 type veth peer name ${rtveth}
ip -netns ${hsname} link set ${rtveth} netns ${rtname}
- ip -netns ${hsname} addr add ${IPv6_HS_NETWORK}::${hs}/64 dev veth0 nodad
+ ip -netns ${hsname} addr add ${IPv6_HS_NETWORK}::${hid}/64 dev veth0 nodad
ip -netns ${hsname} link set veth0 up
ip -netns ${hsname} link set lo up
@@ -293,10 +286,8 @@ setup_vpn_config()
local rtdst=$4
local tid=$5
- local hssrc_name=hs-t${tid}-${hssrc}
- local hsdst_name=hs-t${tid}-${hsdst}
- local rtsrc_name=rt-${rtsrc}
- local rtdst_name=rt-${rtdst}
+ eval local rtsrc_name=\${rt_${rtsrc}}
+ eval local rtdst_name=\${rt_${rtdst}}
local rtveth=veth-t${tid}
local vpn_sid=${VPN_LOCATOR_SERVICE}:${hssrc}${hsdst}:${tid}::6006
@@ -331,18 +322,21 @@ setup()
{
ip link add veth-rt-1 type veth peer name veth-rt-2
# setup the networking for router rt-1 and router rt-2
+ setup_ns rt_1 rt_2
setup_rt_networking 1
setup_rt_networking 2
# setup two hosts for the tenant 100.
# - host hs-1 is directly connected to the router rt-1;
# - host hs-2 is directly connected to the router rt-2.
+ setup_ns hs_t100_1 hs_t100_2
setup_hs 1 1 100 #args: host router tenant
setup_hs 2 2 100
# setup two hosts for the tenant 200
# - host hs-3 is directly connected to the router rt-1;
# - host hs-4 is directly connected to the router rt-2.
+ setup_ns hs_t200_3 hs_t200_4
setup_hs 3 1 200
setup_hs 4 2 200
@@ -361,8 +355,9 @@ check_rt_connectivity()
{
local rtsrc=$1
local rtdst=$2
+ eval local nsname=\${rt_${rtsrc}}
- ip netns exec rt-${rtsrc} ping -c 1 -W 1 ${IPv6_RT_NETWORK}::${rtdst} \
+ ip netns exec ${nsname} ping -c 1 -W 1 ${IPv6_RT_NETWORK}::${rtdst} \
>/dev/null 2>&1
}
@@ -380,8 +375,9 @@ check_hs_connectivity()
local hssrc=$1
local hsdst=$2
local tid=$3
+ eval local nsname=\${hs_t${tid}_${hssrc}}
- ip netns exec hs-t${tid}-${hssrc} ping -c 1 -W ${PING_TIMEOUT_SEC} \
+ ip netns exec ${nsname} ping -c 1 -W ${PING_TIMEOUT_SEC} \
${IPv6_HS_NETWORK}::${hsdst} >/dev/null 2>&1
}
diff --git a/tools/testing/selftests/net/tcp_ao/.gitignore b/tools/testing/selftests/net/tcp_ao/.gitignore
new file mode 100644
index 000000000000..e8bb81b715b7
--- /dev/null
+++ b/tools/testing/selftests/net/tcp_ao/.gitignore
@@ -0,0 +1,2 @@
+*_ipv4
+*_ipv6
diff --git a/tools/testing/selftests/net/tcp_ao/Makefile b/tools/testing/selftests/net/tcp_ao/Makefile
new file mode 100644
index 000000000000..6343cfcf919b
--- /dev/null
+++ b/tools/testing/selftests/net/tcp_ao/Makefile
@@ -0,0 +1,59 @@
+# SPDX-License-Identifier: GPL-2.0
+TEST_BOTH_AF := bench-lookups
+TEST_BOTH_AF += connect
+TEST_BOTH_AF += connect-deny
+TEST_BOTH_AF += icmps-accept icmps-discard
+TEST_BOTH_AF += key-management
+TEST_BOTH_AF += restore
+TEST_BOTH_AF += rst
+TEST_BOTH_AF += self-connect
+TEST_BOTH_AF += seq-ext
+TEST_BOTH_AF += setsockopt-closed
+TEST_BOTH_AF += unsigned-md5
+
+TEST_IPV4_PROGS := $(TEST_BOTH_AF:%=%_ipv4)
+TEST_IPV6_PROGS := $(TEST_BOTH_AF:%=%_ipv6)
+
+TEST_GEN_PROGS := $(TEST_IPV4_PROGS) $(TEST_IPV6_PROGS)
+
+top_srcdir := ../../../../..
+KSFT_KHDR_INSTALL := 1
+include ../../lib.mk
+
+HOSTAR ?= ar
+
+# Drop it on port to linux/master with commit 8ce72dc32578
+.DEFAULT_GOAL := all
+
+LIBDIR := $(OUTPUT)/lib
+LIB := $(LIBDIR)/libaotst.a
+LDLIBS += $(LIB) -pthread
+LIBDEPS := lib/aolib.h Makefile
+
+CFLAGS := -Wall -O2 -g -D_GNU_SOURCE -fno-strict-aliasing
+CFLAGS += -I ../../../../../usr/include/ -iquote $(LIBDIR)
+CFLAGS += -I ../../../../include/
+
+# Library
+LIBSRC := kconfig.c netlink.c proc.c repair.c setup.c sock.c utils.c
+LIBOBJ := $(LIBSRC:%.c=$(LIBDIR)/%.o)
+EXTRA_CLEAN += $(LIBOBJ) $(LIB)
+
+$(LIB): $(LIBOBJ)
+ $(HOSTAR) rcs $@ $^
+
+$(LIBDIR)/%.o: ./lib/%.c $(LIBDEPS)
+ $(CC) $< $(CFLAGS) $(CPPFLAGS) -o $@ -c
+
+$(TEST_GEN_PROGS): $(LIB)
+
+$(OUTPUT)/%_ipv4: %.c
+ $(LINK.c) $^ $(LDLIBS) -o $@
+
+$(OUTPUT)/%_ipv6: %.c
+ $(LINK.c) -DIPV6_TEST $^ $(LDLIBS) -o $@
+
+$(OUTPUT)/icmps-accept_ipv4: CFLAGS+= -DTEST_ICMPS_ACCEPT
+$(OUTPUT)/icmps-accept_ipv6: CFLAGS+= -DTEST_ICMPS_ACCEPT
+$(OUTPUT)/bench-lookups_ipv4: LDFLAGS+= -lm
+$(OUTPUT)/bench-lookups_ipv6: LDFLAGS+= -lm
diff --git a/tools/testing/selftests/net/tcp_ao/bench-lookups.c b/tools/testing/selftests/net/tcp_ao/bench-lookups.c
new file mode 100644
index 000000000000..7be8a7d9308c
--- /dev/null
+++ b/tools/testing/selftests/net/tcp_ao/bench-lookups.c
@@ -0,0 +1,358 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Author: Dmitry Safonov <dima@arista.com> */
+#include <arpa/inet.h>
+#include <inttypes.h>
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+
+#include "../../../../include/linux/bits.h"
+#include "../../../../include/linux/kernel.h"
+#include "aolib.h"
+
+#define BENCH_NR_ITERS 100 /* number of times to run gathering statistics */
+
+static void gen_test_ips(union tcp_addr *ips, size_t ips_nr, bool use_rand)
+{
+ union tcp_addr net = {};
+ size_t i, j;
+
+ if (inet_pton(TEST_FAMILY, TEST_NETWORK, &net) != 1)
+ test_error("Can't convert ip address %s", TEST_NETWORK);
+
+ if (!use_rand) {
+ for (i = 0; i < ips_nr; i++)
+ ips[i] = gen_tcp_addr(net, 2 * i + 1);
+ return;
+ }
+ for (i = 0; i < ips_nr; i++) {
+ size_t r = (size_t)random() | 0x1;
+
+ ips[i] = gen_tcp_addr(net, r);
+
+ for (j = i - 1; j > 0 && i > 0; j--) {
+ if (!memcmp(&ips[i], &ips[j], sizeof(union tcp_addr))) {
+ i--; /* collision */
+ break;
+ }
+ }
+ }
+}
+
+static void test_add_routes(union tcp_addr *ips, size_t ips_nr)
+{
+ size_t i;
+
+ for (i = 0; i < ips_nr; i++) {
+ union tcp_addr *p = (union tcp_addr *)&ips[i];
+
+ if (ip_route_add(veth_name, TEST_FAMILY, this_ip_addr, *p))
+ test_error("Failed to add route");
+ }
+}
+
+static void server_apply_keys(int lsk, union tcp_addr *ips, size_t ips_nr)
+{
+ size_t i;
+
+ for (i = 0; i < ips_nr; i++) {
+ union tcp_addr *p = (union tcp_addr *)&ips[i];
+
+ if (test_add_key(lsk, DEFAULT_TEST_PASSWORD, *p, -1, 100, 100))
+ test_error("setsockopt(TCP_AO)");
+ }
+}
+
+static const size_t nr_keys[] = { 512, 1024, 2048, 4096, 8192 };
+static union tcp_addr *test_ips;
+
+struct bench_stats {
+ uint64_t min;
+ uint64_t max;
+ uint64_t nr;
+ double mean;
+ double s2;
+};
+
+static struct bench_tests {
+ struct bench_stats delete_last_key;
+ struct bench_stats add_key;
+ struct bench_stats delete_rand_key;
+ struct bench_stats connect_last_key;
+ struct bench_stats connect_rand_key;
+ struct bench_stats delete_async;
+} bench_results[ARRAY_SIZE(nr_keys)];
+
+#define NSEC_PER_SEC 1000000000ULL
+
+static void measure_call(struct bench_stats *st,
+ void (*f)(int, void *), int sk, void *arg)
+{
+ struct timespec start = {}, end = {};
+ double delta;
+ uint64_t nsec;
+
+ if (clock_gettime(CLOCK_MONOTONIC, &start))
+ test_error("clock_gettime()");
+
+ f(sk, arg);
+
+ if (clock_gettime(CLOCK_MONOTONIC, &end))
+ test_error("clock_gettime()");
+
+ nsec = (end.tv_sec - start.tv_sec) * NSEC_PER_SEC;
+ if (end.tv_nsec >= start.tv_nsec)
+ nsec += end.tv_nsec - start.tv_nsec;
+ else
+ nsec -= start.tv_nsec - end.tv_nsec;
+
+ if (st->nr == 0) {
+ st->min = st->max = nsec;
+ } else {
+ if (st->min > nsec)
+ st->min = nsec;
+ if (st->max < nsec)
+ st->max = nsec;
+ }
+
+ /* Welford-Knuth algorithm */
+ st->nr++;
+ delta = (double)nsec - st->mean;
+ st->mean += delta / st->nr;
+ st->s2 += delta * ((double)nsec - st->mean);
+}
+
+static void delete_mkt(int sk, void *arg)
+{
+ struct tcp_ao_del *ao = arg;
+
+ if (setsockopt(sk, IPPROTO_TCP, TCP_AO_DEL_KEY, ao, sizeof(*ao)))
+ test_error("setsockopt(TCP_AO_DEL_KEY)");
+}
+
+static void add_back_mkt(int sk, void *arg)
+{
+ union tcp_addr *p = arg;
+
+ if (test_add_key(sk, DEFAULT_TEST_PASSWORD, *p, -1, 100, 100))
+ test_error("setsockopt(TCP_AO)");
+}
+
+static void bench_delete(int lsk, struct bench_stats *add,
+ struct bench_stats *del,
+ union tcp_addr *ips, size_t ips_nr,
+ bool rand_order, bool async)
+{
+ struct tcp_ao_del ao_del = {};
+ union tcp_addr *p;
+ size_t i;
+
+ ao_del.sndid = 100;
+ ao_del.rcvid = 100;
+ ao_del.del_async = !!async;
+ ao_del.prefix = DEFAULT_TEST_PREFIX;
+
+ /* Remove the first added */
+ p = (union tcp_addr *)&ips[0];
+ tcp_addr_to_sockaddr_in(&ao_del.addr, p, 0);
+
+ for (i = 0; i < BENCH_NR_ITERS; i++) {
+ measure_call(del, delete_mkt, lsk, (void *)&ao_del);
+
+ /* Restore it back */
+ measure_call(add, add_back_mkt, lsk, (void *)p);
+
+ /*
+ * Slowest for FILO-linked-list:
+ * on (i) iteration removing ips[i] element. When it gets
+ * added to the list back - it becomes first to fetch, so
+ * on (i + 1) iteration go to ips[i + 1] element.
+ */
+ if (rand_order)
+ p = (union tcp_addr *)&ips[rand() % ips_nr];
+ else
+ p = (union tcp_addr *)&ips[i % ips_nr];
+ tcp_addr_to_sockaddr_in(&ao_del.addr, p, 0);
+ }
+}
+
+static void bench_connect_srv(int lsk, union tcp_addr *ips, size_t ips_nr)
+{
+ size_t i;
+
+ for (i = 0; i < BENCH_NR_ITERS; i++) {
+ int sk;
+
+ synchronize_threads();
+
+ if (test_wait_fd(lsk, TEST_TIMEOUT_SEC, 0))
+ test_error("test_wait_fd()");
+
+ sk = accept(lsk, NULL, NULL);
+ if (sk < 0)
+ test_error("accept()");
+
+ close(sk);
+ }
+}
+
+static void test_print_stats(const char *desc, size_t nr, struct bench_stats *bs)
+{
+ test_ok("%-20s\t%zu keys: min=%" PRIu64 "ms max=%" PRIu64 "ms mean=%gms stddev=%g",
+ desc, nr, bs->min / 1000000, bs->max / 1000000,
+ bs->mean / 1000000, sqrt((bs->mean / 1000000) / bs->nr));
+}
+
+static void *server_fn(void *arg)
+{
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(nr_keys); i++) {
+ struct bench_tests *bt = &bench_results[i];
+ int lsk;
+
+ test_ips = malloc(nr_keys[i] * sizeof(union tcp_addr));
+ if (!test_ips)
+ test_error("malloc()");
+
+ lsk = test_listen_socket(this_ip_addr, test_server_port + i, 1);
+
+ gen_test_ips(test_ips, nr_keys[i], false);
+ test_add_routes(test_ips, nr_keys[i]);
+ test_set_optmem(KERNEL_TCP_AO_KEY_SZ_ROUND_UP * nr_keys[i]);
+ server_apply_keys(lsk, test_ips, nr_keys[i]);
+
+ synchronize_threads();
+ bench_connect_srv(lsk, test_ips, nr_keys[i]);
+ bench_connect_srv(lsk, test_ips, nr_keys[i]);
+
+ /* The worst case for FILO-list */
+ bench_delete(lsk, &bt->add_key, &bt->delete_last_key,
+ test_ips, nr_keys[i], false, false);
+ test_print_stats("Add a new key",
+ nr_keys[i], &bt->add_key);
+ test_print_stats("Delete: worst case",
+ nr_keys[i], &bt->delete_last_key);
+
+ bench_delete(lsk, &bt->add_key, &bt->delete_rand_key,
+ test_ips, nr_keys[i], true, false);
+ test_print_stats("Delete: random-search",
+ nr_keys[i], &bt->delete_rand_key);
+
+ bench_delete(lsk, &bt->add_key, &bt->delete_async,
+ test_ips, nr_keys[i], false, true);
+ test_print_stats("Delete: async", nr_keys[i], &bt->delete_async);
+
+ free(test_ips);
+ close(lsk);
+ }
+
+ return NULL;
+}
+
+static void connect_client(int sk, void *arg)
+{
+ size_t *p = arg;
+
+ if (test_connect_socket(sk, this_ip_dest, test_server_port + *p) <= 0)
+ test_error("failed to connect()");
+}
+
+static void client_addr_setup(int sk, union tcp_addr taddr)
+{
+#ifdef IPV6_TEST
+ struct sockaddr_in6 addr = {
+ .sin6_family = AF_INET6,
+ .sin6_port = 0,
+ .sin6_addr = taddr.a6,
+ };
+#else
+ struct sockaddr_in addr = {
+ .sin_family = AF_INET,
+ .sin_port = 0,
+ .sin_addr = taddr.a4,
+ };
+#endif
+ int ret;
+
+ ret = ip_addr_add(veth_name, TEST_FAMILY, taddr, TEST_PREFIX);
+ if (ret && ret != -EEXIST)
+ test_error("Failed to add ip address");
+ ret = ip_route_add(veth_name, TEST_FAMILY, taddr, this_ip_dest);
+ if (ret && ret != -EEXIST)
+ test_error("Failed to add route");
+
+ if (bind(sk, &addr, sizeof(addr)))
+ test_error("bind()");
+}
+
+static void bench_connect_client(size_t port_off, struct bench_tests *bt,
+ union tcp_addr *ips, size_t ips_nr, bool rand_order)
+{
+ struct bench_stats *con;
+ union tcp_addr *p;
+ size_t i;
+
+ if (rand_order)
+ con = &bt->connect_rand_key;
+ else
+ con = &bt->connect_last_key;
+
+ p = (union tcp_addr *)&ips[0];
+
+ for (i = 0; i < BENCH_NR_ITERS; i++) {
+ int sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP);
+
+ if (sk < 0)
+ test_error("socket()");
+
+ client_addr_setup(sk, *p);
+ if (test_add_key(sk, DEFAULT_TEST_PASSWORD, this_ip_dest,
+ -1, 100, 100))
+ test_error("setsockopt(TCP_AO_ADD_KEY)");
+
+ synchronize_threads();
+
+ measure_call(con, connect_client, sk, (void *)&port_off);
+
+ close(sk);
+
+ /*
+ * Slowest for FILO-linked-list:
+ * on (i) iteration removing ips[i] element. When it gets
+ * added to the list back - it becomes first to fetch, so
+ * on (i + 1) iteration go to ips[i + 1] element.
+ */
+ if (rand_order)
+ p = (union tcp_addr *)&ips[rand() % ips_nr];
+ else
+ p = (union tcp_addr *)&ips[i % ips_nr];
+ }
+}
+
+static void *client_fn(void *arg)
+{
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(nr_keys); i++) {
+ struct bench_tests *bt = &bench_results[i];
+
+ synchronize_threads();
+ bench_connect_client(i, bt, test_ips, nr_keys[i], false);
+ test_print_stats("Connect: worst case",
+ nr_keys[i], &bt->connect_last_key);
+
+ bench_connect_client(i, bt, test_ips, nr_keys[i], false);
+ test_print_stats("Connect: random-search",
+ nr_keys[i], &bt->connect_last_key);
+ }
+ synchronize_threads();
+ return NULL;
+}
+
+int main(int argc, char *argv[])
+{
+ test_init(30, server_fn, client_fn);
+ return 0;
+}
diff --git a/tools/testing/selftests/net/tcp_ao/connect-deny.c b/tools/testing/selftests/net/tcp_ao/connect-deny.c
new file mode 100644
index 000000000000..1ca78040d8b7
--- /dev/null
+++ b/tools/testing/selftests/net/tcp_ao/connect-deny.c
@@ -0,0 +1,264 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Author: Dmitry Safonov <dima@arista.com> */
+#include <inttypes.h>
+#include "aolib.h"
+
+#define fault(type) (inj == FAULT_ ## type)
+
+static inline int test_add_key_maclen(int sk, const char *key, uint8_t maclen,
+ union tcp_addr in_addr, uint8_t prefix,
+ uint8_t sndid, uint8_t rcvid)
+{
+ struct tcp_ao_add tmp = {};
+ int err;
+
+ if (prefix > DEFAULT_TEST_PREFIX)
+ prefix = DEFAULT_TEST_PREFIX;
+
+ err = test_prepare_key(&tmp, DEFAULT_TEST_ALGO, in_addr, false, false,
+ prefix, 0, sndid, rcvid, maclen,
+ 0, strlen(key), key);
+ if (err)
+ return err;
+
+ err = setsockopt(sk, IPPROTO_TCP, TCP_AO_ADD_KEY, &tmp, sizeof(tmp));
+ if (err < 0)
+ return -errno;
+
+ return test_verify_socket_key(sk, &tmp);
+}
+
+static void try_accept(const char *tst_name, unsigned int port, const char *pwd,
+ union tcp_addr addr, uint8_t prefix,
+ uint8_t sndid, uint8_t rcvid, uint8_t maclen,
+ const char *cnt_name, test_cnt cnt_expected,
+ fault_t inj)
+{
+ struct tcp_ao_counters ao_cnt1, ao_cnt2;
+ uint64_t before_cnt = 0, after_cnt = 0; /* silence GCC */
+ int lsk, err, sk = 0;
+ time_t timeout;
+
+ lsk = test_listen_socket(this_ip_addr, port, 1);
+
+ if (pwd && test_add_key_maclen(lsk, pwd, maclen, addr, prefix, sndid, rcvid))
+ test_error("setsockopt(TCP_AO_ADD_KEY)");
+
+ if (cnt_name)
+ before_cnt = netstat_get_one(cnt_name, NULL);
+ if (pwd && test_get_tcp_ao_counters(lsk, &ao_cnt1))
+ test_error("test_get_tcp_ao_counters()");
+
+ synchronize_threads(); /* preparations done */
+
+ timeout = fault(TIMEOUT) ? TEST_RETRANSMIT_SEC : TEST_TIMEOUT_SEC;
+ err = test_wait_fd(lsk, timeout, 0);
+ if (err == -ETIMEDOUT) {
+ if (!fault(TIMEOUT))
+ test_fail("timeouted for accept()");
+ } else if (err < 0) {
+ test_error("test_wait_fd()");
+ } else {
+ if (fault(TIMEOUT))
+ test_fail("ready to accept");
+
+ sk = accept(lsk, NULL, NULL);
+ if (sk < 0) {
+ test_error("accept()");
+ } else {
+ if (fault(TIMEOUT))
+ test_fail("%s: accepted", tst_name);
+ }
+ }
+
+ if (pwd && test_get_tcp_ao_counters(lsk, &ao_cnt2))
+ test_error("test_get_tcp_ao_counters()");
+
+ close(lsk);
+ if (pwd)
+ test_tcp_ao_counters_cmp(tst_name, &ao_cnt1, &ao_cnt2, cnt_expected);
+
+ if (!cnt_name)
+ goto out;
+
+ after_cnt = netstat_get_one(cnt_name, NULL);
+
+ if (after_cnt <= before_cnt) {
+ test_fail("%s: %s counter did not increase: %zu <= %zu",
+ tst_name, cnt_name, after_cnt, before_cnt);
+ } else {
+ test_ok("%s: counter %s increased %zu => %zu",
+ tst_name, cnt_name, before_cnt, after_cnt);
+ }
+
+out:
+ synchronize_threads(); /* close() */
+ if (sk > 0)
+ close(sk);
+}
+
+static void *server_fn(void *arg)
+{
+ union tcp_addr wrong_addr, network_addr;
+ unsigned int port = test_server_port;
+
+ if (inet_pton(TEST_FAMILY, TEST_WRONG_IP, &wrong_addr) != 1)
+ test_error("Can't convert ip address %s", TEST_WRONG_IP);
+
+ try_accept("Non-AO server + AO client", port++, NULL,
+ this_ip_dest, -1, 100, 100, 0,
+ "TCPAOKeyNotFound", 0, FAULT_TIMEOUT);
+
+ try_accept("AO server + Non-AO client", port++, DEFAULT_TEST_PASSWORD,
+ this_ip_dest, -1, 100, 100, 0,
+ "TCPAORequired", TEST_CNT_AO_REQUIRED, FAULT_TIMEOUT);
+
+ try_accept("Wrong password", port++, "something that is not DEFAULT_TEST_PASSWORD",
+ this_ip_dest, -1, 100, 100, 0,
+ "TCPAOBad", TEST_CNT_BAD, FAULT_TIMEOUT);
+
+ try_accept("Wrong rcv id", port++, DEFAULT_TEST_PASSWORD,
+ this_ip_dest, -1, 100, 101, 0,
+ "TCPAOKeyNotFound", TEST_CNT_AO_KEY_NOT_FOUND, FAULT_TIMEOUT);
+
+ try_accept("Wrong snd id", port++, DEFAULT_TEST_PASSWORD,
+ this_ip_dest, -1, 101, 100, 0,
+ "TCPAOGood", TEST_CNT_GOOD, FAULT_TIMEOUT);
+
+ try_accept("Different maclen", port++, DEFAULT_TEST_PASSWORD,
+ this_ip_dest, -1, 100, 100, 8,
+ "TCPAOBad", TEST_CNT_BAD, FAULT_TIMEOUT);
+
+ try_accept("Server: Wrong addr", port++, DEFAULT_TEST_PASSWORD,
+ wrong_addr, -1, 100, 100, 0,
+ "TCPAOKeyNotFound", TEST_CNT_AO_KEY_NOT_FOUND, FAULT_TIMEOUT);
+
+ try_accept("Client: Wrong addr", port++, NULL,
+ this_ip_dest, -1, 100, 100, 0, NULL, 0, FAULT_TIMEOUT);
+
+ try_accept("rcv id != snd id", port++, DEFAULT_TEST_PASSWORD,
+ this_ip_dest, -1, 200, 100, 0,
+ "TCPAOGood", TEST_CNT_GOOD, 0);
+
+ if (inet_pton(TEST_FAMILY, TEST_NETWORK, &network_addr) != 1)
+ test_error("Can't convert ip address %s", TEST_NETWORK);
+
+ try_accept("Server: prefix match", port++, DEFAULT_TEST_PASSWORD,
+ network_addr, 16, 100, 100, 0,
+ "TCPAOGood", TEST_CNT_GOOD, 0);
+
+ try_accept("Client: prefix match", port++, DEFAULT_TEST_PASSWORD,
+ this_ip_dest, -1, 100, 100, 0,
+ "TCPAOGood", TEST_CNT_GOOD, 0);
+
+ /* client exits */
+ synchronize_threads();
+ return NULL;
+}
+
+static void try_connect(const char *tst_name, unsigned int port,
+ const char *pwd, union tcp_addr addr, uint8_t prefix,
+ uint8_t sndid, uint8_t rcvid,
+ test_cnt cnt_expected, fault_t inj)
+{
+ struct tcp_ao_counters ao_cnt1, ao_cnt2;
+ time_t timeout;
+ int sk, ret;
+
+ sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP);
+ if (sk < 0)
+ test_error("socket()");
+
+ if (pwd && test_add_key(sk, pwd, addr, prefix, sndid, rcvid))
+ test_error("setsockopt(TCP_AO_ADD_KEY)");
+
+ if (pwd && test_get_tcp_ao_counters(sk, &ao_cnt1))
+ test_error("test_get_tcp_ao_counters()");
+
+ synchronize_threads(); /* preparations done */
+
+ timeout = fault(TIMEOUT) ? TEST_RETRANSMIT_SEC : TEST_TIMEOUT_SEC;
+ ret = _test_connect_socket(sk, this_ip_dest, port, timeout);
+
+ if (ret < 0) {
+ if (fault(KEYREJECT) && ret == -EKEYREJECTED) {
+ test_ok("%s: connect() was prevented", tst_name);
+ } else if (ret == -ETIMEDOUT && fault(TIMEOUT)) {
+ test_ok("%s", tst_name);
+ } else if (ret == -ECONNREFUSED &&
+ (fault(TIMEOUT) || fault(KEYREJECT))) {
+ test_ok("%s: refused to connect", tst_name);
+ } else {
+ test_error("%s: connect() returned %d", tst_name, ret);
+ }
+ goto out;
+ }
+
+ if (fault(TIMEOUT) || fault(KEYREJECT))
+ test_fail("%s: connected", tst_name);
+ else
+ test_ok("%s: connected", tst_name);
+ if (pwd && ret > 0) {
+ if (test_get_tcp_ao_counters(sk, &ao_cnt2))
+ test_error("test_get_tcp_ao_counters()");
+ test_tcp_ao_counters_cmp(tst_name, &ao_cnt1, &ao_cnt2, cnt_expected);
+ }
+out:
+ synchronize_threads(); /* close() */
+
+ if (ret > 0)
+ close(sk);
+}
+
+static void *client_fn(void *arg)
+{
+ union tcp_addr wrong_addr, network_addr;
+ unsigned int port = test_server_port;
+
+ if (inet_pton(TEST_FAMILY, TEST_WRONG_IP, &wrong_addr) != 1)
+ test_error("Can't convert ip address %s", TEST_WRONG_IP);
+
+ try_connect("Non-AO server + AO client", port++, DEFAULT_TEST_PASSWORD,
+ this_ip_dest, -1, 100, 100, 0, FAULT_TIMEOUT);
+
+ try_connect("AO server + Non-AO client", port++, NULL,
+ this_ip_dest, -1, 100, 100, 0, FAULT_TIMEOUT);
+
+ try_connect("Wrong password", port++, DEFAULT_TEST_PASSWORD,
+ this_ip_dest, -1, 100, 100, 0, FAULT_TIMEOUT);
+
+ try_connect("Wrong rcv id", port++, DEFAULT_TEST_PASSWORD,
+ this_ip_dest, -1, 100, 100, 0, FAULT_TIMEOUT);
+
+ try_connect("Wrong snd id", port++, DEFAULT_TEST_PASSWORD,
+ this_ip_dest, -1, 100, 100, 0, FAULT_TIMEOUT);
+
+ try_connect("Different maclen", port++, DEFAULT_TEST_PASSWORD,
+ this_ip_dest, -1, 100, 100, 0, FAULT_TIMEOUT);
+
+ try_connect("Server: Wrong addr", port++, DEFAULT_TEST_PASSWORD,
+ this_ip_dest, -1, 100, 100, 0, FAULT_TIMEOUT);
+
+ try_connect("Client: Wrong addr", port++, DEFAULT_TEST_PASSWORD,
+ wrong_addr, -1, 100, 100, 0, FAULT_KEYREJECT);
+
+ try_connect("rcv id != snd id", port++, DEFAULT_TEST_PASSWORD,
+ this_ip_dest, -1, 100, 200, TEST_CNT_GOOD, 0);
+
+ if (inet_pton(TEST_FAMILY, TEST_NETWORK, &network_addr) != 1)
+ test_error("Can't convert ip address %s", TEST_NETWORK);
+
+ try_connect("Server: prefix match", port++, DEFAULT_TEST_PASSWORD,
+ this_ip_dest, -1, 100, 100, TEST_CNT_GOOD, 0);
+
+ try_connect("Client: prefix match", port++, DEFAULT_TEST_PASSWORD,
+ network_addr, 16, 100, 100, TEST_CNT_GOOD, 0);
+
+ return NULL;
+}
+
+int main(int argc, char *argv[])
+{
+ test_init(21, server_fn, client_fn);
+ return 0;
+}
diff --git a/tools/testing/selftests/net/tcp_ao/connect.c b/tools/testing/selftests/net/tcp_ao/connect.c
new file mode 100644
index 000000000000..81653b47f303
--- /dev/null
+++ b/tools/testing/selftests/net/tcp_ao/connect.c
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Author: Dmitry Safonov <dima@arista.com> */
+#include <inttypes.h>
+#include "aolib.h"
+
+static void *server_fn(void *arg)
+{
+ int sk, lsk;
+ ssize_t bytes;
+
+ lsk = test_listen_socket(this_ip_addr, test_server_port, 1);
+
+ if (test_add_key(lsk, DEFAULT_TEST_PASSWORD, this_ip_dest, -1, 100, 100))
+ test_error("setsockopt(TCP_AO_ADD_KEY)");
+ synchronize_threads();
+
+ if (test_wait_fd(lsk, TEST_TIMEOUT_SEC, 0))
+ test_error("test_wait_fd()");
+
+ sk = accept(lsk, NULL, NULL);
+ if (sk < 0)
+ test_error("accept()");
+
+ synchronize_threads();
+
+ bytes = test_server_run(sk, 0, 0);
+
+ test_fail("server served: %zd", bytes);
+ return NULL;
+}
+
+static void *client_fn(void *arg)
+{
+ int sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP);
+ uint64_t before_aogood, after_aogood;
+ const size_t nr_packets = 20;
+ struct netstat *ns_before, *ns_after;
+ struct tcp_ao_counters ao1, ao2;
+
+ if (sk < 0)
+ test_error("socket()");
+
+ if (test_add_key(sk, DEFAULT_TEST_PASSWORD, this_ip_dest, -1, 100, 100))
+ test_error("setsockopt(TCP_AO_ADD_KEY)");
+
+ synchronize_threads();
+ if (test_connect_socket(sk, this_ip_dest, test_server_port) <= 0)
+ test_error("failed to connect()");
+ synchronize_threads();
+
+ ns_before = netstat_read();
+ before_aogood = netstat_get(ns_before, "TCPAOGood", NULL);
+ if (test_get_tcp_ao_counters(sk, &ao1))
+ test_error("test_get_tcp_ao_counters()");
+
+ if (test_client_verify(sk, 100, nr_packets, TEST_TIMEOUT_SEC)) {
+ test_fail("verify failed");
+ return NULL;
+ }
+
+ ns_after = netstat_read();
+ after_aogood = netstat_get(ns_after, "TCPAOGood", NULL);
+ if (test_get_tcp_ao_counters(sk, &ao2))
+ test_error("test_get_tcp_ao_counters()");
+ netstat_print_diff(ns_before, ns_after);
+ netstat_free(ns_before);
+ netstat_free(ns_after);
+
+ if (nr_packets > (after_aogood - before_aogood)) {
+ test_fail("TCPAOGood counter mismatch: %zu > (%zu - %zu)",
+ nr_packets, after_aogood, before_aogood);
+ return NULL;
+ }
+ if (test_tcp_ao_counters_cmp("connect", &ao1, &ao2, TEST_CNT_GOOD))
+ return NULL;
+
+ test_ok("connect TCPAOGood %" PRIu64 "/%" PRIu64 "/%" PRIu64 " => %" PRIu64 "/%" PRIu64 "/%" PRIu64 ", sent %" PRIu64,
+ before_aogood, ao1.ao_info_pkt_good,
+ ao1.key_cnts[0].pkt_good,
+ after_aogood, ao2.ao_info_pkt_good,
+ ao2.key_cnts[0].pkt_good,
+ nr_packets);
+ return NULL;
+}
+
+int main(int argc, char *argv[])
+{
+ test_init(1, server_fn, client_fn);
+ return 0;
+}
diff --git a/tools/testing/selftests/net/tcp_ao/icmps-accept.c b/tools/testing/selftests/net/tcp_ao/icmps-accept.c
new file mode 120000
index 000000000000..0a5bb85eb260
--- /dev/null
+++ b/tools/testing/selftests/net/tcp_ao/icmps-accept.c
@@ -0,0 +1 @@
+icmps-discard.c \ No newline at end of file
diff --git a/tools/testing/selftests/net/tcp_ao/icmps-discard.c b/tools/testing/selftests/net/tcp_ao/icmps-discard.c
new file mode 100644
index 000000000000..d69bcba3c929
--- /dev/null
+++ b/tools/testing/selftests/net/tcp_ao/icmps-discard.c
@@ -0,0 +1,449 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Selftest that verifies that incomping ICMPs are ignored,
+ * the TCP connection stays alive, no hard or soft errors get reported
+ * to the usespace and the counter for ignored ICMPs is updated.
+ *
+ * RFC5925, 7.8:
+ * >> A TCP-AO implementation MUST default to ignore incoming ICMPv4
+ * messages of Type 3 (destination unreachable), Codes 2-4 (protocol
+ * unreachable, port unreachable, and fragmentation needed -- ’hard
+ * errors’), and ICMPv6 Type 1 (destination unreachable), Code 1
+ * (administratively prohibited) and Code 4 (port unreachable) intended
+ * for connections in synchronized states (ESTABLISHED, FIN-WAIT-1, FIN-
+ * WAIT-2, CLOSE-WAIT, CLOSING, LAST-ACK, TIME-WAIT) that match MKTs.
+ *
+ * Author: Dmitry Safonov <dima@arista.com>
+ */
+#include <inttypes.h>
+#include <linux/icmp.h>
+#include <linux/icmpv6.h>
+#include <linux/ipv6.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <sys/socket.h>
+#include "aolib.h"
+#include "../../../../include/linux/compiler.h"
+
+const size_t packets_nr = 20;
+const size_t packet_size = 100;
+const char *tcpao_icmps = "TCPAODroppedIcmps";
+
+#ifdef IPV6_TEST
+const char *dst_unreach = "Icmp6InDestUnreachs";
+const int sk_ip_level = SOL_IPV6;
+const int sk_recverr = IPV6_RECVERR;
+#else
+const char *dst_unreach = "InDestUnreachs";
+const int sk_ip_level = SOL_IP;
+const int sk_recverr = IP_RECVERR;
+#endif
+
+/* Server is expected to fail with hard error if ::accept_icmp is set */
+#ifdef TEST_ICMPS_ACCEPT
+# define test_icmps_fail test_ok
+# define test_icmps_ok test_fail
+#else
+# define test_icmps_fail test_fail
+# define test_icmps_ok test_ok
+#endif
+
+static void serve_interfered(int sk)
+{
+ ssize_t test_quota = packet_size * packets_nr * 10;
+ uint64_t dest_unreach_a, dest_unreach_b;
+ uint64_t icmp_ignored_a, icmp_ignored_b;
+ struct tcp_ao_counters ao_cnt1, ao_cnt2;
+ bool counter_not_found;
+ struct netstat *ns_after, *ns_before;
+ ssize_t bytes;
+
+ ns_before = netstat_read();
+ dest_unreach_a = netstat_get(ns_before, dst_unreach, NULL);
+ icmp_ignored_a = netstat_get(ns_before, tcpao_icmps, NULL);
+ if (test_get_tcp_ao_counters(sk, &ao_cnt1))
+ test_error("test_get_tcp_ao_counters()");
+ bytes = test_server_run(sk, test_quota, 0);
+ ns_after = netstat_read();
+ netstat_print_diff(ns_before, ns_after);
+ dest_unreach_b = netstat_get(ns_after, dst_unreach, NULL);
+ icmp_ignored_b = netstat_get(ns_after, tcpao_icmps,
+ &counter_not_found);
+ if (test_get_tcp_ao_counters(sk, &ao_cnt2))
+ test_error("test_get_tcp_ao_counters()");
+
+ netstat_free(ns_before);
+ netstat_free(ns_after);
+
+ if (dest_unreach_a >= dest_unreach_b) {
+ test_fail("%s counter didn't change: %" PRIu64 " >= %" PRIu64,
+ dst_unreach, dest_unreach_a, dest_unreach_b);
+ return;
+ }
+ test_ok("%s delivered %" PRIu64,
+ dst_unreach, dest_unreach_b - dest_unreach_a);
+ if (bytes < 0)
+ test_icmps_fail("Server failed with %zd: %s", bytes, strerrordesc_np(-bytes));
+ else
+ test_icmps_ok("Server survived %zd bytes of traffic", test_quota);
+ if (counter_not_found) {
+ test_fail("Not found %s counter", tcpao_icmps);
+ return;
+ }
+#ifdef TEST_ICMPS_ACCEPT
+ test_tcp_ao_counters_cmp(NULL, &ao_cnt1, &ao_cnt2, TEST_CNT_GOOD);
+#else
+ test_tcp_ao_counters_cmp(NULL, &ao_cnt1, &ao_cnt2, TEST_CNT_GOOD | TEST_CNT_AO_DROPPED_ICMP);
+#endif
+ if (icmp_ignored_a >= icmp_ignored_b) {
+ test_icmps_fail("%s counter didn't change: %" PRIu64 " >= %" PRIu64,
+ tcpao_icmps, icmp_ignored_a, icmp_ignored_b);
+ return;
+ }
+ test_icmps_ok("ICMPs ignored %" PRIu64, icmp_ignored_b - icmp_ignored_a);
+}
+
+static void *server_fn(void *arg)
+{
+ int val, sk, lsk;
+ bool accept_icmps = false;
+
+ lsk = test_listen_socket(this_ip_addr, test_server_port, 1);
+
+#ifdef TEST_ICMPS_ACCEPT
+ accept_icmps = true;
+#endif
+
+ if (test_set_ao_flags(lsk, false, accept_icmps))
+ test_error("setsockopt(TCP_AO_INFO)");
+
+ if (test_add_key(lsk, DEFAULT_TEST_PASSWORD, this_ip_dest, -1, 100, 100))
+ test_error("setsockopt(TCP_AO_ADD_KEY)");
+ synchronize_threads();
+
+ if (test_wait_fd(lsk, TEST_TIMEOUT_SEC, 0))
+ test_error("test_wait_fd()");
+
+ sk = accept(lsk, NULL, NULL);
+ if (sk < 0)
+ test_error("accept()");
+
+ /* Fail on hard ip errors, such as dest unreachable (RFC1122) */
+ val = 1;
+ if (setsockopt(sk, sk_ip_level, sk_recverr, &val, sizeof(val)))
+ test_error("setsockopt()");
+
+ synchronize_threads();
+
+ serve_interfered(sk);
+ return NULL;
+}
+
+static size_t packets_sent;
+static size_t icmps_sent;
+
+static uint32_t checksum4_nofold(void *data, size_t len, uint32_t sum)
+{
+ uint16_t *words = data;
+ size_t i;
+
+ for (i = 0; i < len / sizeof(uint16_t); i++)
+ sum += words[i];
+ if (len & 1)
+ sum += ((char *)data)[len - 1];
+ return sum;
+}
+
+static uint16_t checksum4_fold(void *data, size_t len, uint32_t sum)
+{
+ sum = checksum4_nofold(data, len, sum);
+ while (sum > 0xFFFF)
+ sum = (sum & 0xFFFF) + (sum >> 16);
+ return ~sum;
+}
+
+static void set_ip4hdr(struct iphdr *iph, size_t packet_len, int proto,
+ struct sockaddr_in *src, struct sockaddr_in *dst)
+{
+ iph->version = 4;
+ iph->ihl = 5;
+ iph->tos = 0;
+ iph->tot_len = htons(packet_len);
+ iph->ttl = 2;
+ iph->protocol = proto;
+ iph->saddr = src->sin_addr.s_addr;
+ iph->daddr = dst->sin_addr.s_addr;
+ iph->check = checksum4_fold((void *)iph, iph->ihl << 1, 0);
+}
+
+static void icmp_interfere4(uint8_t type, uint8_t code, uint32_t rcv_nxt,
+ struct sockaddr_in *src, struct sockaddr_in *dst)
+{
+ int sk = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
+ struct {
+ struct iphdr iph;
+ struct icmphdr icmph;
+ struct iphdr iphe;
+ struct {
+ uint16_t sport;
+ uint16_t dport;
+ uint32_t seq;
+ } tcph;
+ } packet = {};
+ size_t packet_len;
+ ssize_t bytes;
+
+ if (sk < 0)
+ test_error("socket(AF_INET, SOCK_RAW, IPPROTO_RAW)");
+
+ packet_len = sizeof(packet);
+ set_ip4hdr(&packet.iph, packet_len, IPPROTO_ICMP, src, dst);
+
+ packet.icmph.type = type;
+ packet.icmph.code = code;
+ if (code == ICMP_FRAG_NEEDED) {
+ randomize_buffer(&packet.icmph.un.frag.mtu,
+ sizeof(packet.icmph.un.frag.mtu));
+ }
+
+ packet_len = sizeof(packet.iphe) + sizeof(packet.tcph);
+ set_ip4hdr(&packet.iphe, packet_len, IPPROTO_TCP, dst, src);
+
+ packet.tcph.sport = dst->sin_port;
+ packet.tcph.dport = src->sin_port;
+ packet.tcph.seq = htonl(rcv_nxt);
+
+ packet_len = sizeof(packet) - sizeof(packet.iph);
+ packet.icmph.checksum = checksum4_fold((void *)&packet.icmph,
+ packet_len, 0);
+
+ bytes = sendto(sk, &packet, sizeof(packet), 0,
+ (struct sockaddr *)dst, sizeof(*dst));
+ if (bytes != sizeof(packet))
+ test_error("send(): %zd", bytes);
+ icmps_sent++;
+
+ close(sk);
+}
+
+static void set_ip6hdr(struct ipv6hdr *iph, size_t packet_len, int proto,
+ struct sockaddr_in6 *src, struct sockaddr_in6 *dst)
+{
+ iph->version = 6;
+ iph->payload_len = htons(packet_len);
+ iph->nexthdr = proto;
+ iph->hop_limit = 2;
+ iph->saddr = src->sin6_addr;
+ iph->daddr = dst->sin6_addr;
+}
+
+static inline uint16_t csum_fold(uint32_t csum)
+{
+ uint32_t sum = csum;
+
+ sum = (sum & 0xffff) + (sum >> 16);
+ sum = (sum & 0xffff) + (sum >> 16);
+ return (uint16_t)~sum;
+}
+
+static inline uint32_t csum_add(uint32_t csum, uint32_t addend)
+{
+ uint32_t res = csum;
+
+ res += addend;
+ return res + (res < addend);
+}
+
+noinline uint32_t checksum6_nofold(void *data, size_t len, uint32_t sum)
+{
+ uint16_t *words = data;
+ size_t i;
+
+ for (i = 0; i < len / sizeof(uint16_t); i++)
+ sum = csum_add(sum, words[i]);
+ if (len & 1)
+ sum = csum_add(sum, ((char *)data)[len - 1]);
+ return sum;
+}
+
+noinline uint16_t icmp6_checksum(struct sockaddr_in6 *src,
+ struct sockaddr_in6 *dst,
+ void *ptr, size_t len, uint8_t proto)
+{
+ struct {
+ struct in6_addr saddr;
+ struct in6_addr daddr;
+ uint32_t payload_len;
+ uint8_t zero[3];
+ uint8_t nexthdr;
+ } pseudo_header = {};
+ uint32_t sum;
+
+ pseudo_header.saddr = src->sin6_addr;
+ pseudo_header.daddr = dst->sin6_addr;
+ pseudo_header.payload_len = htonl(len);
+ pseudo_header.nexthdr = proto;
+
+ sum = checksum6_nofold(&pseudo_header, sizeof(pseudo_header), 0);
+ sum = checksum6_nofold(ptr, len, sum);
+
+ return csum_fold(sum);
+}
+
+static void icmp6_interfere(int type, int code, uint32_t rcv_nxt,
+ struct sockaddr_in6 *src, struct sockaddr_in6 *dst)
+{
+ int sk = socket(AF_INET6, SOCK_RAW, IPPROTO_RAW);
+ struct sockaddr_in6 dst_raw = *dst;
+ struct {
+ struct ipv6hdr iph;
+ struct icmp6hdr icmph;
+ struct ipv6hdr iphe;
+ struct {
+ uint16_t sport;
+ uint16_t dport;
+ uint32_t seq;
+ } tcph;
+ } packet = {};
+ size_t packet_len;
+ ssize_t bytes;
+
+
+ if (sk < 0)
+ test_error("socket(AF_INET6, SOCK_RAW, IPPROTO_RAW)");
+
+ packet_len = sizeof(packet) - sizeof(packet.iph);
+ set_ip6hdr(&packet.iph, packet_len, IPPROTO_ICMPV6, src, dst);
+
+ packet.icmph.icmp6_type = type;
+ packet.icmph.icmp6_code = code;
+
+ packet_len = sizeof(packet.iphe) + sizeof(packet.tcph);
+ set_ip6hdr(&packet.iphe, packet_len, IPPROTO_TCP, dst, src);
+
+ packet.tcph.sport = dst->sin6_port;
+ packet.tcph.dport = src->sin6_port;
+ packet.tcph.seq = htonl(rcv_nxt);
+
+ packet_len = sizeof(packet) - sizeof(packet.iph);
+
+ packet.icmph.icmp6_cksum = icmp6_checksum(src, dst,
+ (void *)&packet.icmph, packet_len, IPPROTO_ICMPV6);
+
+ dst_raw.sin6_port = htons(IPPROTO_RAW);
+ bytes = sendto(sk, &packet, sizeof(packet), 0,
+ (struct sockaddr *)&dst_raw, sizeof(dst_raw));
+ if (bytes != sizeof(packet))
+ test_error("send(): %zd", bytes);
+ icmps_sent++;
+
+ close(sk);
+}
+
+static uint32_t get_rcv_nxt(int sk)
+{
+ int val = TCP_REPAIR_ON;
+ uint32_t ret;
+ socklen_t sz = sizeof(ret);
+
+ if (setsockopt(sk, SOL_TCP, TCP_REPAIR, &val, sizeof(val)))
+ test_error("setsockopt(TCP_REPAIR)");
+ val = TCP_RECV_QUEUE;
+ if (setsockopt(sk, SOL_TCP, TCP_REPAIR_QUEUE, &val, sizeof(val)))
+ test_error("setsockopt(TCP_REPAIR_QUEUE)");
+ if (getsockopt(sk, SOL_TCP, TCP_QUEUE_SEQ, &ret, &sz))
+ test_error("getsockopt(TCP_QUEUE_SEQ)");
+ val = TCP_REPAIR_OFF_NO_WP;
+ if (setsockopt(sk, SOL_TCP, TCP_REPAIR, &val, sizeof(val)))
+ test_error("setsockopt(TCP_REPAIR)");
+ return ret;
+}
+
+static void icmp_interfere(const size_t nr, uint32_t rcv_nxt, void *src, void *dst)
+{
+ struct sockaddr_in *saddr4 = src;
+ struct sockaddr_in *daddr4 = dst;
+ struct sockaddr_in6 *saddr6 = src;
+ struct sockaddr_in6 *daddr6 = dst;
+ size_t i;
+
+ if (saddr4->sin_family != daddr4->sin_family)
+ test_error("Different address families");
+
+ for (i = 0; i < nr; i++) {
+ if (saddr4->sin_family == AF_INET) {
+ icmp_interfere4(ICMP_DEST_UNREACH, ICMP_PROT_UNREACH,
+ rcv_nxt, saddr4, daddr4);
+ icmp_interfere4(ICMP_DEST_UNREACH, ICMP_PORT_UNREACH,
+ rcv_nxt, saddr4, daddr4);
+ icmp_interfere4(ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
+ rcv_nxt, saddr4, daddr4);
+ icmps_sent += 3;
+ } else if (saddr4->sin_family == AF_INET6) {
+ icmp6_interfere(ICMPV6_DEST_UNREACH,
+ ICMPV6_ADM_PROHIBITED,
+ rcv_nxt, saddr6, daddr6);
+ icmp6_interfere(ICMPV6_DEST_UNREACH,
+ ICMPV6_PORT_UNREACH,
+ rcv_nxt, saddr6, daddr6);
+ icmps_sent += 2;
+ } else {
+ test_error("Not ip address family");
+ }
+ }
+}
+
+static void send_interfered(int sk)
+{
+ const unsigned int timeout = TEST_TIMEOUT_SEC;
+ struct sockaddr_in6 src, dst;
+ socklen_t addr_sz;
+
+ addr_sz = sizeof(src);
+ if (getsockname(sk, &src, &addr_sz))
+ test_error("getsockname()");
+ addr_sz = sizeof(dst);
+ if (getpeername(sk, &dst, &addr_sz))
+ test_error("getpeername()");
+
+ while (1) {
+ uint32_t rcv_nxt;
+
+ if (test_client_verify(sk, packet_size, packets_nr, timeout)) {
+ test_fail("client: connection is broken");
+ return;
+ }
+ packets_sent += packets_nr;
+ rcv_nxt = get_rcv_nxt(sk);
+ icmp_interfere(packets_nr, rcv_nxt, (void *)&src, (void *)&dst);
+ }
+}
+
+static void *client_fn(void *arg)
+{
+ int sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP);
+
+ if (sk < 0)
+ test_error("socket()");
+
+ if (test_add_key(sk, DEFAULT_TEST_PASSWORD, this_ip_dest, -1, 100, 100))
+ test_error("setsockopt(TCP_AO_ADD_KEY)");
+
+ synchronize_threads();
+ if (test_connect_socket(sk, this_ip_dest, test_server_port) <= 0)
+ test_error("failed to connect()");
+ synchronize_threads();
+
+ send_interfered(sk);
+
+ /* Not expecting client to quit */
+ test_fail("client disconnected");
+
+ return NULL;
+}
+
+int main(int argc, char *argv[])
+{
+ test_init(3, server_fn, client_fn);
+ return 0;
+}
diff --git a/tools/testing/selftests/net/tcp_ao/key-management.c b/tools/testing/selftests/net/tcp_ao/key-management.c
new file mode 100644
index 000000000000..c48b4970ca17
--- /dev/null
+++ b/tools/testing/selftests/net/tcp_ao/key-management.c
@@ -0,0 +1,1180 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Author: Dmitry Safonov <dima@arista.com> */
+#include <inttypes.h>
+#include "../../../../include/linux/kernel.h"
+#include "aolib.h"
+
+const size_t nr_packets = 20;
+const size_t msg_len = 100;
+const size_t quota = nr_packets * msg_len;
+union tcp_addr wrong_addr;
+#define SECOND_PASSWORD "at all times sincere friends of freedom have been rare"
+#define fault(type) (inj == FAULT_ ## type)
+
+static const int test_vrf_ifindex = 200;
+static const uint8_t test_vrf_tabid = 42;
+static void setup_vrfs(void)
+{
+ int err;
+
+ if (!kernel_config_has(KCONFIG_NET_VRF))
+ return;
+
+ err = add_vrf("ksft-vrf", test_vrf_tabid, test_vrf_ifindex, -1);
+ if (err)
+ test_error("Failed to add a VRF: %d", err);
+
+ err = link_set_up("ksft-vrf");
+ if (err)
+ test_error("Failed to bring up a VRF");
+
+ err = ip_route_add_vrf(veth_name, TEST_FAMILY,
+ this_ip_addr, this_ip_dest, test_vrf_tabid);
+ if (err)
+ test_error("Failed to add a route to VRF");
+}
+
+
+static int prepare_sk(union tcp_addr *addr, uint8_t sndid, uint8_t rcvid)
+{
+ int sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP);
+
+ if (sk < 0)
+ test_error("socket()");
+
+ if (test_add_key(sk, DEFAULT_TEST_PASSWORD, this_ip_dest,
+ DEFAULT_TEST_PREFIX, 100, 100))
+ test_error("test_add_key()");
+
+ if (addr && test_add_key(sk, SECOND_PASSWORD, *addr,
+ DEFAULT_TEST_PREFIX, sndid, rcvid))
+ test_error("test_add_key()");
+
+ return sk;
+}
+
+static int prepare_lsk(union tcp_addr *addr, uint8_t sndid, uint8_t rcvid)
+{
+ int sk = prepare_sk(addr, sndid, rcvid);
+
+ if (listen(sk, 10))
+ test_error("listen()");
+
+ return sk;
+}
+
+static int test_del_key(int sk, uint8_t sndid, uint8_t rcvid, bool async,
+ int current_key, int rnext_key)
+{
+ struct tcp_ao_info_opt ao_info = {};
+ struct tcp_ao_getsockopt key = {};
+ struct tcp_ao_del del = {};
+ sockaddr_af sockaddr;
+ int err;
+
+ tcp_addr_to_sockaddr_in(&del.addr, &this_ip_dest, 0);
+ del.prefix = DEFAULT_TEST_PREFIX;
+ del.sndid = sndid;
+ del.rcvid = rcvid;
+
+ if (current_key >= 0) {
+ del.set_current = 1;
+ del.current_key = (uint8_t)current_key;
+ }
+ if (rnext_key >= 0) {
+ del.set_rnext = 1;
+ del.rnext = (uint8_t)rnext_key;
+ }
+
+ err = setsockopt(sk, IPPROTO_TCP, TCP_AO_DEL_KEY, &del, sizeof(del));
+ if (err < 0)
+ return -errno;
+
+ if (async)
+ return 0;
+
+ tcp_addr_to_sockaddr_in(&sockaddr, &this_ip_dest, 0);
+ err = test_get_one_ao(sk, &key, &sockaddr, sizeof(sockaddr),
+ DEFAULT_TEST_PREFIX, sndid, rcvid);
+ if (!err)
+ return -EEXIST;
+ if (err != -E2BIG)
+ test_error("getsockopt()");
+ if (current_key < 0 && rnext_key < 0)
+ return 0;
+ if (test_get_ao_info(sk, &ao_info))
+ test_error("getsockopt(TCP_AO_INFO) failed");
+ if (current_key >= 0 && ao_info.current_key != (uint8_t)current_key)
+ return -ENOTRECOVERABLE;
+ if (rnext_key >= 0 && ao_info.rnext != (uint8_t)rnext_key)
+ return -ENOTRECOVERABLE;
+ return 0;
+}
+
+static void try_delete_key(char *tst_name, int sk, uint8_t sndid, uint8_t rcvid,
+ bool async, int current_key, int rnext_key,
+ fault_t inj)
+{
+ int err;
+
+ err = test_del_key(sk, sndid, rcvid, async, current_key, rnext_key);
+ if ((err == -EBUSY && fault(BUSY)) || (err == -EINVAL && fault(CURRNEXT))) {
+ test_ok("%s: key deletion was prevented", tst_name);
+ return;
+ }
+ if (err && fault(FIXME)) {
+ test_xfail("%s: failed to delete the key %u:%u %d",
+ tst_name, sndid, rcvid, err);
+ return;
+ }
+ if (!err) {
+ if (fault(BUSY) || fault(CURRNEXT)) {
+ test_fail("%s: the key was deleted %u:%u %d", tst_name,
+ sndid, rcvid, err);
+ } else {
+ test_ok("%s: the key was deleted", tst_name);
+ }
+ return;
+ }
+ test_fail("%s: can't delete the key %u:%u %d", tst_name, sndid, rcvid, err);
+}
+
+static int test_set_key(int sk, int current_keyid, int rnext_keyid)
+{
+ struct tcp_ao_info_opt ao_info = {};
+ int err;
+
+ if (current_keyid >= 0) {
+ ao_info.set_current = 1;
+ ao_info.current_key = (uint8_t)current_keyid;
+ }
+ if (rnext_keyid >= 0) {
+ ao_info.set_rnext = 1;
+ ao_info.rnext = (uint8_t)rnext_keyid;
+ }
+
+ err = test_set_ao_info(sk, &ao_info);
+ if (err)
+ return err;
+ if (test_get_ao_info(sk, &ao_info))
+ test_error("getsockopt(TCP_AO_INFO) failed");
+ if (current_keyid >= 0 && ao_info.current_key != (uint8_t)current_keyid)
+ return -ENOTRECOVERABLE;
+ if (rnext_keyid >= 0 && ao_info.rnext != (uint8_t)rnext_keyid)
+ return -ENOTRECOVERABLE;
+ return 0;
+}
+
+static int test_add_current_rnext_key(int sk, const char *key, uint8_t keyflags,
+ union tcp_addr in_addr, uint8_t prefix,
+ bool set_current, bool set_rnext,
+ uint8_t sndid, uint8_t rcvid)
+{
+ struct tcp_ao_add tmp = {};
+ int err;
+
+ err = test_prepare_key(&tmp, DEFAULT_TEST_ALGO, in_addr,
+ set_current, set_rnext,
+ prefix, 0, sndid, rcvid, 0, keyflags,
+ strlen(key), key);
+ if (err)
+ return err;
+
+
+ err = setsockopt(sk, IPPROTO_TCP, TCP_AO_ADD_KEY, &tmp, sizeof(tmp));
+ if (err < 0)
+ return -errno;
+
+ return test_verify_socket_key(sk, &tmp);
+}
+
+static int __try_add_current_rnext_key(int sk, const char *key, uint8_t keyflags,
+ union tcp_addr in_addr, uint8_t prefix,
+ bool set_current, bool set_rnext,
+ uint8_t sndid, uint8_t rcvid)
+{
+ struct tcp_ao_info_opt ao_info = {};
+ int err;
+
+ err = test_add_current_rnext_key(sk, key, keyflags, in_addr, prefix,
+ set_current, set_rnext, sndid, rcvid);
+ if (err)
+ return err;
+
+ if (test_get_ao_info(sk, &ao_info))
+ test_error("getsockopt(TCP_AO_INFO) failed");
+ if (set_current && ao_info.current_key != sndid)
+ return -ENOTRECOVERABLE;
+ if (set_rnext && ao_info.rnext != rcvid)
+ return -ENOTRECOVERABLE;
+ return 0;
+}
+
+static void try_add_current_rnext_key(char *tst_name, int sk, const char *key,
+ uint8_t keyflags,
+ union tcp_addr in_addr, uint8_t prefix,
+ bool set_current, bool set_rnext,
+ uint8_t sndid, uint8_t rcvid, fault_t inj)
+{
+ int err;
+
+ err = __try_add_current_rnext_key(sk, key, keyflags, in_addr, prefix,
+ set_current, set_rnext, sndid, rcvid);
+ if (!err && !fault(CURRNEXT)) {
+ test_ok("%s", tst_name);
+ return;
+ }
+ if (err == -EINVAL && fault(CURRNEXT)) {
+ test_ok("%s", tst_name);
+ return;
+ }
+ test_fail("%s", tst_name);
+}
+
+static void check_closed_socket(void)
+{
+ int sk;
+
+ sk = prepare_sk(&this_ip_dest, 200, 200);
+ try_delete_key("closed socket, delete a key", sk, 200, 200, 0, -1, -1, 0);
+ try_delete_key("closed socket, delete all keys", sk, 100, 100, 0, -1, -1, 0);
+ close(sk);
+
+ sk = prepare_sk(&this_ip_dest, 200, 200);
+ if (test_set_key(sk, 100, 200))
+ test_error("failed to set current/rnext keys");
+ try_delete_key("closed socket, delete current key", sk, 100, 100, 0, -1, -1, FAULT_BUSY);
+ try_delete_key("closed socket, delete rnext key", sk, 200, 200, 0, -1, -1, FAULT_BUSY);
+ close(sk);
+
+ sk = prepare_sk(&this_ip_dest, 200, 200);
+ if (test_add_key(sk, "Glory to heros!", this_ip_dest,
+ DEFAULT_TEST_PREFIX, 10, 11))
+ test_error("test_add_key()");
+ if (test_add_key(sk, "Glory to Ukraine!", this_ip_dest,
+ DEFAULT_TEST_PREFIX, 12, 13))
+ test_error("test_add_key()");
+ try_delete_key("closed socket, delete a key + set current/rnext", sk, 100, 100, 0, 10, 13, 0);
+ try_delete_key("closed socket, force-delete current key", sk, 10, 11, 0, 200, -1, 0);
+ try_delete_key("closed socket, force-delete rnext key", sk, 12, 13, 0, -1, 200, 0);
+ try_delete_key("closed socket, delete current+rnext key", sk, 200, 200, 0, -1, -1, FAULT_BUSY);
+ close(sk);
+
+ sk = prepare_sk(&this_ip_dest, 200, 200);
+ if (test_set_key(sk, 100, 200))
+ test_error("failed to set current/rnext keys");
+ try_add_current_rnext_key("closed socket, add + change current key",
+ sk, "Laaaa! Lalala-la-la-lalala...", 0,
+ this_ip_dest, DEFAULT_TEST_PREFIX,
+ true, false, 10, 20, 0);
+ try_add_current_rnext_key("closed socket, add + change rnext key",
+ sk, "Laaaa! Lalala-la-la-lalala...", 0,
+ this_ip_dest, DEFAULT_TEST_PREFIX,
+ false, true, 20, 10, 0);
+ close(sk);
+}
+
+static void assert_no_current_rnext(const char *tst_msg, int sk)
+{
+ struct tcp_ao_info_opt ao_info = {};
+
+ if (test_get_ao_info(sk, &ao_info))
+ test_error("getsockopt(TCP_AO_INFO) failed");
+
+ errno = 0;
+ if (ao_info.set_current || ao_info.set_rnext) {
+ test_xfail("%s: the socket has current/rnext keys: %d:%d",
+ tst_msg,
+ (ao_info.set_current) ? ao_info.current_key : -1,
+ (ao_info.set_rnext) ? ao_info.rnext : -1);
+ } else {
+ test_ok("%s: the socket has no current/rnext keys", tst_msg);
+ }
+}
+
+static void assert_no_tcp_repair(void)
+{
+ struct tcp_ao_repair ao_img = {};
+ socklen_t len = sizeof(ao_img);
+ int sk, err;
+
+ sk = prepare_sk(&this_ip_dest, 200, 200);
+ test_enable_repair(sk);
+ if (listen(sk, 10))
+ test_error("listen()");
+ errno = 0;
+ err = getsockopt(sk, SOL_TCP, TCP_AO_REPAIR, &ao_img, &len);
+ if (err && errno == EPERM)
+ test_ok("listen socket, getsockopt(TCP_AO_REPAIR) is restricted");
+ else
+ test_fail("listen socket, getsockopt(TCP_AO_REPAIR) works");
+ errno = 0;
+ err = setsockopt(sk, SOL_TCP, TCP_AO_REPAIR, &ao_img, sizeof(ao_img));
+ if (err && errno == EPERM)
+ test_ok("listen socket, setsockopt(TCP_AO_REPAIR) is restricted");
+ else
+ test_fail("listen socket, setsockopt(TCP_AO_REPAIR) works");
+ close(sk);
+}
+
+static void check_listen_socket(void)
+{
+ int sk, err;
+
+ sk = prepare_lsk(&this_ip_dest, 200, 200);
+ try_delete_key("listen socket, delete a key", sk, 200, 200, 0, -1, -1, 0);
+ try_delete_key("listen socket, delete all keys", sk, 100, 100, 0, -1, -1, 0);
+ close(sk);
+
+ sk = prepare_lsk(&this_ip_dest, 200, 200);
+ err = test_set_key(sk, 100, -1);
+ if (err == -EINVAL)
+ test_ok("listen socket, setting current key not allowed");
+ else
+ test_fail("listen socket, set current key");
+ err = test_set_key(sk, -1, 200);
+ if (err == -EINVAL)
+ test_ok("listen socket, setting rnext key not allowed");
+ else
+ test_fail("listen socket, set rnext key");
+ close(sk);
+
+ sk = prepare_sk(&this_ip_dest, 200, 200);
+ if (test_set_key(sk, 100, 200))
+ test_error("failed to set current/rnext keys");
+ if (listen(sk, 10))
+ test_error("listen()");
+ assert_no_current_rnext("listen() after current/rnext keys set", sk);
+ try_delete_key("listen socket, delete current key from before listen()", sk, 100, 100, 0, -1, -1, FAULT_FIXME);
+ try_delete_key("listen socket, delete rnext key from before listen()", sk, 200, 200, 0, -1, -1, FAULT_FIXME);
+ close(sk);
+
+ assert_no_tcp_repair();
+
+ sk = prepare_lsk(&this_ip_dest, 200, 200);
+ if (test_add_key(sk, "Glory to heros!", this_ip_dest,
+ DEFAULT_TEST_PREFIX, 10, 11))
+ test_error("test_add_key()");
+ if (test_add_key(sk, "Glory to Ukraine!", this_ip_dest,
+ DEFAULT_TEST_PREFIX, 12, 13))
+ test_error("test_add_key()");
+ try_delete_key("listen socket, delete a key + set current/rnext", sk,
+ 100, 100, 0, 10, 13, FAULT_CURRNEXT);
+ try_delete_key("listen socket, force-delete current key", sk,
+ 10, 11, 0, 200, -1, FAULT_CURRNEXT);
+ try_delete_key("listen socket, force-delete rnext key", sk,
+ 12, 13, 0, -1, 200, FAULT_CURRNEXT);
+ try_delete_key("listen socket, delete a key", sk,
+ 200, 200, 0, -1, -1, 0);
+ close(sk);
+
+ sk = prepare_lsk(&this_ip_dest, 200, 200);
+ try_add_current_rnext_key("listen socket, add + change current key",
+ sk, "Laaaa! Lalala-la-la-lalala...", 0,
+ this_ip_dest, DEFAULT_TEST_PREFIX,
+ true, false, 10, 20, FAULT_CURRNEXT);
+ try_add_current_rnext_key("listen socket, add + change rnext key",
+ sk, "Laaaa! Lalala-la-la-lalala...", 0,
+ this_ip_dest, DEFAULT_TEST_PREFIX,
+ false, true, 20, 10, FAULT_CURRNEXT);
+ close(sk);
+}
+
+static const char *fips_fpath = "/proc/sys/crypto/fips_enabled";
+static bool is_fips_enabled(void)
+{
+ static int fips_checked = -1;
+ FILE *fenabled;
+ int enabled;
+
+ if (fips_checked >= 0)
+ return !!fips_checked;
+ if (access(fips_fpath, R_OK)) {
+ if (errno != ENOENT)
+ test_error("Can't open %s", fips_fpath);
+ fips_checked = 0;
+ return false;
+ }
+ fenabled = fopen(fips_fpath, "r");
+ if (!fenabled)
+ test_error("Can't open %s", fips_fpath);
+ if (fscanf(fenabled, "%d", &enabled) != 1)
+ test_error("Can't read from %s", fips_fpath);
+ fclose(fenabled);
+ fips_checked = !!enabled;
+ return !!fips_checked;
+}
+
+struct test_key {
+ char password[TCP_AO_MAXKEYLEN];
+ const char *alg;
+ unsigned int len;
+ uint8_t client_keyid;
+ uint8_t server_keyid;
+ uint8_t maclen;
+ uint8_t matches_client : 1,
+ matches_server : 1,
+ matches_vrf : 1,
+ is_current : 1,
+ is_rnext : 1,
+ used_on_handshake : 1,
+ used_after_accept : 1,
+ used_on_client : 1;
+};
+
+struct key_collection {
+ unsigned int nr_keys;
+ struct test_key *keys;
+};
+
+static struct key_collection collection;
+
+#define TEST_MAX_MACLEN 16
+const char *test_algos[] = {
+ "cmac(aes128)",
+ "hmac(sha1)", "hmac(sha512)", "hmac(sha384)", "hmac(sha256)",
+ "hmac(sha224)", "hmac(sha3-512)",
+ /* only if !CONFIG_FIPS */
+#define TEST_NON_FIPS_ALGOS 2
+ "hmac(rmd160)", "hmac(md5)"
+};
+const unsigned int test_maclens[] = { 1, 4, 12, 16 };
+#define MACLEN_SHIFT 2
+#define ALGOS_SHIFT 4
+
+static unsigned int make_mask(unsigned int shift, unsigned int prev_shift)
+{
+ unsigned int ret = BIT(shift) - 1;
+
+ return ret << prev_shift;
+}
+
+static void init_key_in_collection(unsigned int index, bool randomized)
+{
+ struct test_key *key = &collection.keys[index];
+ unsigned int algos_nr, algos_index;
+
+ /* Same for randomized and non-randomized test flows */
+ key->client_keyid = index;
+ key->server_keyid = 127 + index;
+ key->matches_client = 1;
+ key->matches_server = 1;
+ key->matches_vrf = 1;
+ /* not really even random, but good enough for a test */
+ key->len = rand() % (TCP_AO_MAXKEYLEN - TEST_TCP_AO_MINKEYLEN);
+ key->len += TEST_TCP_AO_MINKEYLEN;
+ randomize_buffer(key->password, key->len);
+
+ if (randomized) {
+ key->maclen = (rand() % TEST_MAX_MACLEN) + 1;
+ algos_index = rand();
+ } else {
+ unsigned int shift = MACLEN_SHIFT;
+
+ key->maclen = test_maclens[index & make_mask(shift, 0)];
+ algos_index = index & make_mask(ALGOS_SHIFT, shift);
+ }
+ algos_nr = ARRAY_SIZE(test_algos);
+ if (is_fips_enabled())
+ algos_nr -= TEST_NON_FIPS_ALGOS;
+ key->alg = test_algos[algos_index % algos_nr];
+}
+
+static int init_default_key_collection(unsigned int nr_keys, bool randomized)
+{
+ size_t key_sz = sizeof(collection.keys[0]);
+
+ if (!nr_keys) {
+ free(collection.keys);
+ collection.keys = NULL;
+ return 0;
+ }
+
+ /*
+ * All keys have uniq sndid/rcvid and sndid != rcvid in order to
+ * check for any bugs/issues for different keyids, visible to both
+ * peers. Keyid == 254 is unused.
+ */
+ if (nr_keys > 127)
+ test_error("Test requires too many keys, correct the source");
+
+ collection.keys = reallocarray(collection.keys, nr_keys, key_sz);
+ if (!collection.keys)
+ return -ENOMEM;
+
+ memset(collection.keys, 0, nr_keys * key_sz);
+ collection.nr_keys = nr_keys;
+ while (nr_keys--)
+ init_key_in_collection(nr_keys, randomized);
+
+ return 0;
+}
+
+static void test_key_error(const char *msg, struct test_key *key)
+{
+ test_error("%s: key: { %s, %u:%u, %u, %u:%u:%u:%u:%u (%u)}",
+ msg, key->alg, key->client_keyid, key->server_keyid,
+ key->maclen, key->matches_client, key->matches_server,
+ key->matches_vrf, key->is_current, key->is_rnext, key->len);
+}
+
+static int test_add_key_cr(int sk, const char *pwd, unsigned int pwd_len,
+ union tcp_addr addr, uint8_t vrf,
+ uint8_t sndid, uint8_t rcvid,
+ uint8_t maclen, const char *alg,
+ bool set_current, bool set_rnext)
+{
+ struct tcp_ao_add tmp = {};
+ uint8_t keyflags = 0;
+ int err;
+
+ if (!alg)
+ alg = DEFAULT_TEST_ALGO;
+
+ if (vrf)
+ keyflags |= TCP_AO_KEYF_IFINDEX;
+ err = test_prepare_key(&tmp, alg, addr, set_current, set_rnext,
+ DEFAULT_TEST_PREFIX, vrf, sndid, rcvid, maclen,
+ keyflags, pwd_len, pwd);
+ if (err)
+ return err;
+
+ err = setsockopt(sk, IPPROTO_TCP, TCP_AO_ADD_KEY, &tmp, sizeof(tmp));
+ if (err < 0)
+ return -errno;
+
+ return test_verify_socket_key(sk, &tmp);
+}
+
+static void verify_current_rnext(const char *tst, int sk,
+ int current_keyid, int rnext_keyid)
+{
+ struct tcp_ao_info_opt ao_info = {};
+
+ if (test_get_ao_info(sk, &ao_info))
+ test_error("getsockopt(TCP_AO_INFO) failed");
+
+ errno = 0;
+ if (current_keyid >= 0) {
+ if (!ao_info.set_current)
+ test_fail("%s: the socket doesn't have current key", tst);
+ else if (ao_info.current_key != current_keyid)
+ test_fail("%s: current key is not the expected one %d != %u",
+ tst, current_keyid, ao_info.current_key);
+ else
+ test_ok("%s: current key %u as expected",
+ tst, ao_info.current_key);
+ }
+ if (rnext_keyid >= 0) {
+ if (!ao_info.set_rnext)
+ test_fail("%s: the socket doesn't have rnext key", tst);
+ else if (ao_info.rnext != rnext_keyid)
+ test_fail("%s: rnext key is not the expected one %d != %u",
+ tst, rnext_keyid, ao_info.rnext);
+ else
+ test_ok("%s: rnext key %u as expected", tst, ao_info.rnext);
+ }
+}
+
+
+static int key_collection_socket(bool server, unsigned int port)
+{
+ unsigned int i;
+ int sk;
+
+ if (server)
+ sk = test_listen_socket(this_ip_addr, port, 1);
+ else
+ sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP);
+ if (sk < 0)
+ test_error("socket()");
+
+ for (i = 0; i < collection.nr_keys; i++) {
+ struct test_key *key = &collection.keys[i];
+ union tcp_addr *addr = &wrong_addr;
+ uint8_t sndid, rcvid, vrf;
+ bool set_current = false, set_rnext = false;
+
+ if (key->matches_vrf)
+ vrf = 0;
+ else
+ vrf = test_vrf_ifindex;
+ if (server) {
+ if (key->matches_client)
+ addr = &this_ip_dest;
+ sndid = key->server_keyid;
+ rcvid = key->client_keyid;
+ } else {
+ if (key->matches_server)
+ addr = &this_ip_dest;
+ sndid = key->client_keyid;
+ rcvid = key->server_keyid;
+ set_current = key->is_current;
+ set_rnext = key->is_rnext;
+ }
+
+ if (test_add_key_cr(sk, key->password, key->len,
+ *addr, vrf, sndid, rcvid, key->maclen,
+ key->alg, set_current, set_rnext))
+ test_key_error("setsockopt(TCP_AO_ADD_KEY)", key);
+ if (set_current || set_rnext)
+ key->used_on_handshake = 1;
+#ifdef DEBUG
+ test_print("%s [%u/%u] key: { %s, %u:%u, %u, %u:%u:%u:%u (%u)}",
+ server ? "server" : "client", i, collection.nr_keys,
+ key->alg, rcvid, sndid, key->maclen,
+ key->matches_client, key->matches_server,
+ key->is_current, key->is_rnext, key->len);
+#endif
+ }
+ return sk;
+}
+
+static void verify_counters(const char *tst_name, bool is_listen_sk, bool server,
+ struct tcp_ao_counters *a, struct tcp_ao_counters *b)
+{
+ unsigned int i;
+
+ __test_tcp_ao_counters_cmp(tst_name, a, b, TEST_CNT_GOOD);
+
+ for (i = 0; i < collection.nr_keys; i++) {
+ struct test_key *key = &collection.keys[i];
+ uint8_t sndid, rcvid;
+ bool was_used;
+
+ if (server) {
+ sndid = key->server_keyid;
+ rcvid = key->client_keyid;
+ if (is_listen_sk)
+ was_used = key->used_on_handshake;
+ else
+ was_used = key->used_after_accept;
+ } else {
+ sndid = key->client_keyid;
+ rcvid = key->server_keyid;
+ was_used = key->used_on_client;
+ }
+
+ test_tcp_ao_key_counters_cmp(tst_name, a, b, was_used,
+ sndid, rcvid);
+ }
+ test_tcp_ao_counters_free(a);
+ test_tcp_ao_counters_free(b);
+ test_ok("%s: passed counters checks", tst_name);
+}
+
+static struct tcp_ao_getsockopt *lookup_key(struct tcp_ao_getsockopt *buf,
+ size_t len, int sndid, int rcvid)
+{
+ size_t i;
+
+ for (i = 0; i < len; i++) {
+ if (sndid >= 0 && buf[i].sndid != sndid)
+ continue;
+ if (rcvid >= 0 && buf[i].rcvid != rcvid)
+ continue;
+ return &buf[i];
+ }
+ return NULL;
+}
+
+static void verify_keys(const char *tst_name, int sk,
+ bool is_listen_sk, bool server)
+{
+ socklen_t len = sizeof(struct tcp_ao_getsockopt);
+ struct tcp_ao_getsockopt *keys;
+ bool passed_test = true;
+ unsigned int i;
+
+ keys = calloc(collection.nr_keys, len);
+ if (!keys)
+ test_error("calloc()");
+
+ keys->nkeys = collection.nr_keys;
+ keys->get_all = 1;
+
+ if (getsockopt(sk, IPPROTO_TCP, TCP_AO_GET_KEYS, keys, &len)) {
+ free(keys);
+ test_error("getsockopt(TCP_AO_GET_KEYS)");
+ }
+
+ for (i = 0; i < collection.nr_keys; i++) {
+ struct test_key *key = &collection.keys[i];
+ struct tcp_ao_getsockopt *dump_key;
+ bool is_kdf_aes_128_cmac = false;
+ bool is_cmac_aes = false;
+ uint8_t sndid, rcvid;
+ bool matches = false;
+
+ if (server) {
+ if (key->matches_client)
+ matches = true;
+ sndid = key->server_keyid;
+ rcvid = key->client_keyid;
+ } else {
+ if (key->matches_server)
+ matches = true;
+ sndid = key->client_keyid;
+ rcvid = key->server_keyid;
+ }
+ if (!key->matches_vrf)
+ matches = false;
+ /* no keys get removed on the original listener socket */
+ if (is_listen_sk)
+ matches = true;
+
+ dump_key = lookup_key(keys, keys->nkeys, sndid, rcvid);
+ if (matches != !!dump_key) {
+ test_fail("%s: key %u:%u %s%s on the socket",
+ tst_name, sndid, rcvid,
+ key->matches_vrf ? "" : "[vrf] ",
+ matches ? "disappeared" : "yet present");
+ passed_test = false;
+ goto out;
+ }
+ if (!dump_key)
+ continue;
+
+ if (!strcmp("cmac(aes128)", key->alg)) {
+ is_kdf_aes_128_cmac = (key->len != 16);
+ is_cmac_aes = true;
+ }
+
+ if (is_cmac_aes) {
+ if (strcmp(dump_key->alg_name, "cmac(aes)")) {
+ test_fail("%s: key %u:%u cmac(aes) has unexpected alg %s",
+ tst_name, sndid, rcvid,
+ dump_key->alg_name);
+ passed_test = false;
+ continue;
+ }
+ } else if (strcmp(dump_key->alg_name, key->alg)) {
+ test_fail("%s: key %u:%u has unexpected alg %s != %s",
+ tst_name, sndid, rcvid,
+ dump_key->alg_name, key->alg);
+ passed_test = false;
+ continue;
+ }
+ if (is_kdf_aes_128_cmac) {
+ if (dump_key->keylen != 16) {
+ test_fail("%s: key %u:%u cmac(aes128) has unexpected len %u",
+ tst_name, sndid, rcvid,
+ dump_key->keylen);
+ continue;
+ }
+ } else if (dump_key->keylen != key->len) {
+ test_fail("%s: key %u:%u changed password len %u != %u",
+ tst_name, sndid, rcvid,
+ dump_key->keylen, key->len);
+ passed_test = false;
+ continue;
+ }
+ if (!is_kdf_aes_128_cmac &&
+ memcmp(dump_key->key, key->password, key->len)) {
+ test_fail("%s: key %u:%u has different password",
+ tst_name, sndid, rcvid);
+ passed_test = false;
+ continue;
+ }
+ if (dump_key->maclen != key->maclen) {
+ test_fail("%s: key %u:%u changed maclen %u != %u",
+ tst_name, sndid, rcvid,
+ dump_key->maclen, key->maclen);
+ passed_test = false;
+ continue;
+ }
+ }
+
+ if (passed_test)
+ test_ok("%s: The socket keys are consistent with the expectations",
+ tst_name);
+out:
+ free(keys);
+}
+
+static int start_server(const char *tst_name, unsigned int port, size_t quota,
+ struct tcp_ao_counters *begin,
+ unsigned int current_index, unsigned int rnext_index)
+{
+ struct tcp_ao_counters lsk_c1, lsk_c2;
+ ssize_t bytes;
+ int sk, lsk;
+
+ synchronize_threads(); /* 1: key collection initialized */
+ lsk = key_collection_socket(true, port);
+ if (test_get_tcp_ao_counters(lsk, &lsk_c1))
+ test_error("test_get_tcp_ao_counters()");
+ synchronize_threads(); /* 2: MKTs added => connect() */
+ if (test_wait_fd(lsk, TEST_TIMEOUT_SEC, 0))
+ test_error("test_wait_fd()");
+
+ sk = accept(lsk, NULL, NULL);
+ if (sk < 0)
+ test_error("accept()");
+ if (test_get_tcp_ao_counters(sk, begin))
+ test_error("test_get_tcp_ao_counters()");
+
+ synchronize_threads(); /* 3: accepted => send data */
+ if (test_get_tcp_ao_counters(lsk, &lsk_c2))
+ test_error("test_get_tcp_ao_counters()");
+ verify_keys(tst_name, lsk, true, true);
+ close(lsk);
+
+ bytes = test_server_run(sk, quota, TEST_TIMEOUT_SEC);
+ if (bytes != quota)
+ test_fail("%s: server served: %zd", tst_name, bytes);
+ else
+ test_ok("%s: server alive", tst_name);
+
+ verify_counters(tst_name, true, true, &lsk_c1, &lsk_c2);
+
+ return sk;
+}
+
+static void end_server(const char *tst_name, int sk,
+ struct tcp_ao_counters *begin)
+{
+ struct tcp_ao_counters end;
+
+ if (test_get_tcp_ao_counters(sk, &end))
+ test_error("test_get_tcp_ao_counters()");
+ verify_keys(tst_name, sk, false, true);
+
+ synchronize_threads(); /* 4: verified => closed */
+ close(sk);
+
+ verify_counters(tst_name, true, false, begin, &end);
+ synchronize_threads(); /* 5: counters */
+}
+
+static void try_server_run(const char *tst_name, unsigned int port, size_t quota,
+ unsigned int current_index, unsigned int rnext_index)
+{
+ struct tcp_ao_counters tmp;
+ int sk;
+
+ sk = start_server(tst_name, port, quota, &tmp,
+ current_index, rnext_index);
+ end_server(tst_name, sk, &tmp);
+}
+
+static void server_rotations(const char *tst_name, unsigned int port,
+ size_t quota, unsigned int rotations,
+ unsigned int current_index, unsigned int rnext_index)
+{
+ struct tcp_ao_counters tmp;
+ unsigned int i;
+ int sk;
+
+ sk = start_server(tst_name, port, quota, &tmp,
+ current_index, rnext_index);
+
+ for (i = current_index + 1; rotations > 0; i++, rotations--) {
+ ssize_t bytes;
+
+ if (i >= collection.nr_keys)
+ i = 0;
+ bytes = test_server_run(sk, quota, TEST_TIMEOUT_SEC);
+ if (bytes != quota) {
+ test_fail("%s: server served: %zd", tst_name, bytes);
+ return;
+ }
+ verify_current_rnext(tst_name, sk,
+ collection.keys[i].server_keyid, -1);
+ synchronize_threads(); /* verify current/rnext */
+ }
+ end_server(tst_name, sk, &tmp);
+}
+
+static int run_client(const char *tst_name, unsigned int port,
+ unsigned int nr_keys, int current_index, int rnext_index,
+ struct tcp_ao_counters *before,
+ const size_t msg_sz, const size_t msg_nr)
+{
+ int sk;
+
+ synchronize_threads(); /* 1: key collection initialized */
+ sk = key_collection_socket(false, port);
+
+ if (current_index >= 0 || rnext_index >= 0) {
+ int sndid = -1, rcvid = -1;
+
+ if (current_index >= 0)
+ sndid = collection.keys[current_index].client_keyid;
+ if (rnext_index >= 0)
+ rcvid = collection.keys[rnext_index].server_keyid;
+ if (test_set_key(sk, sndid, rcvid))
+ test_error("failed to set current/rnext keys");
+ }
+ if (before && test_get_tcp_ao_counters(sk, before))
+ test_error("test_get_tcp_ao_counters()");
+
+ synchronize_threads(); /* 2: MKTs added => connect() */
+ if (test_connect_socket(sk, this_ip_dest, port++) <= 0)
+ test_error("failed to connect()");
+ if (current_index < 0)
+ current_index = nr_keys - 1;
+ if (rnext_index < 0)
+ rnext_index = nr_keys - 1;
+ collection.keys[current_index].used_on_handshake = 1;
+ collection.keys[rnext_index].used_after_accept = 1;
+ collection.keys[rnext_index].used_on_client = 1;
+
+ synchronize_threads(); /* 3: accepted => send data */
+ if (test_client_verify(sk, msg_sz, msg_nr, TEST_TIMEOUT_SEC)) {
+ test_fail("verify failed");
+ close(sk);
+ if (before)
+ test_tcp_ao_counters_free(before);
+ return -1;
+ }
+
+ return sk;
+}
+
+static int start_client(const char *tst_name, unsigned int port,
+ unsigned int nr_keys, int current_index, int rnext_index,
+ struct tcp_ao_counters *before,
+ const size_t msg_sz, const size_t msg_nr)
+{
+ if (init_default_key_collection(nr_keys, true))
+ test_error("Failed to init the key collection");
+
+ return run_client(tst_name, port, nr_keys, current_index,
+ rnext_index, before, msg_sz, msg_nr);
+}
+
+static void end_client(const char *tst_name, int sk, unsigned int nr_keys,
+ int current_index, int rnext_index,
+ struct tcp_ao_counters *start)
+{
+ struct tcp_ao_counters end;
+
+ /* Some application may become dependent on this kernel choice */
+ if (current_index < 0)
+ current_index = nr_keys - 1;
+ if (rnext_index < 0)
+ rnext_index = nr_keys - 1;
+ verify_current_rnext(tst_name, sk,
+ collection.keys[current_index].client_keyid,
+ collection.keys[rnext_index].server_keyid);
+ if (start && test_get_tcp_ao_counters(sk, &end))
+ test_error("test_get_tcp_ao_counters()");
+ verify_keys(tst_name, sk, false, false);
+ synchronize_threads(); /* 4: verify => closed */
+ close(sk);
+ if (start)
+ verify_counters(tst_name, false, false, start, &end);
+ synchronize_threads(); /* 5: counters */
+}
+
+static void try_unmatched_keys(int sk, int *rnext_index)
+{
+ struct test_key *key;
+ unsigned int i = 0;
+ int err;
+
+ do {
+ key = &collection.keys[i];
+ if (!key->matches_server)
+ break;
+ } while (++i < collection.nr_keys);
+ if (key->matches_server)
+ test_error("all keys on client match the server");
+
+ err = test_add_key_cr(sk, key->password, key->len, wrong_addr,
+ 0, key->client_keyid, key->server_keyid,
+ key->maclen, key->alg, 0, 0);
+ if (!err) {
+ test_fail("Added a key with non-matching ip-address for established sk");
+ return;
+ }
+ if (err == -EINVAL)
+ test_ok("Can't add a key with non-matching ip-address for established sk");
+ else
+ test_error("Failed to add a key");
+
+ err = test_add_key_cr(sk, key->password, key->len, this_ip_dest,
+ test_vrf_ifindex,
+ key->client_keyid, key->server_keyid,
+ key->maclen, key->alg, 0, 0);
+ if (!err) {
+ test_fail("Added a key with non-matching VRF for established sk");
+ return;
+ }
+ if (err == -EINVAL)
+ test_ok("Can't add a key with non-matching VRF for established sk");
+ else
+ test_error("Failed to add a key");
+
+ for (i = 0; i < collection.nr_keys; i++) {
+ key = &collection.keys[i];
+ if (!key->matches_client)
+ break;
+ }
+ if (key->matches_client)
+ test_error("all keys on server match the client");
+ if (test_set_key(sk, -1, key->server_keyid))
+ test_error("Can't change the current key");
+ if (test_client_verify(sk, msg_len, nr_packets, TEST_TIMEOUT_SEC))
+ test_fail("verify failed");
+ *rnext_index = i;
+}
+
+static int client_non_matching(const char *tst_name, unsigned int port,
+ unsigned int nr_keys,
+ int current_index, int rnext_index,
+ const size_t msg_sz, const size_t msg_nr)
+{
+ unsigned int i;
+
+ if (init_default_key_collection(nr_keys, true))
+ test_error("Failed to init the key collection");
+
+ for (i = 0; i < nr_keys; i++) {
+ /* key (0, 0) matches */
+ collection.keys[i].matches_client = !!((i + 3) % 4);
+ collection.keys[i].matches_server = !!((i + 2) % 4);
+ if (kernel_config_has(KCONFIG_NET_VRF))
+ collection.keys[i].matches_vrf = !!((i + 1) % 4);
+ }
+
+ return run_client(tst_name, port, nr_keys, current_index,
+ rnext_index, NULL, msg_sz, msg_nr);
+}
+
+static void check_current_back(const char *tst_name, unsigned int port,
+ unsigned int nr_keys,
+ unsigned int current_index, unsigned int rnext_index,
+ unsigned int rotate_to_index)
+{
+ struct tcp_ao_counters tmp;
+ int sk;
+
+ sk = start_client(tst_name, port, nr_keys, current_index, rnext_index,
+ &tmp, msg_len, nr_packets);
+ if (sk < 0)
+ return;
+ if (test_set_key(sk, collection.keys[rotate_to_index].client_keyid, -1))
+ test_error("Can't change the current key");
+ if (test_client_verify(sk, msg_len, nr_packets, TEST_TIMEOUT_SEC))
+ test_fail("verify failed");
+ collection.keys[rotate_to_index].used_after_accept = 1;
+
+ end_client(tst_name, sk, nr_keys, current_index, rnext_index, &tmp);
+}
+
+static void roll_over_keys(const char *tst_name, unsigned int port,
+ unsigned int nr_keys, unsigned int rotations,
+ unsigned int current_index, unsigned int rnext_index)
+{
+ struct tcp_ao_counters tmp;
+ unsigned int i;
+ int sk;
+
+ sk = start_client(tst_name, port, nr_keys, current_index, rnext_index,
+ &tmp, msg_len, nr_packets);
+ if (sk < 0)
+ return;
+ for (i = rnext_index + 1; rotations > 0; i++, rotations--) {
+ if (i >= collection.nr_keys)
+ i = 0;
+ if (test_set_key(sk, -1, collection.keys[i].server_keyid))
+ test_error("Can't change the Rnext key");
+ if (test_client_verify(sk, msg_len, nr_packets, TEST_TIMEOUT_SEC)) {
+ test_fail("verify failed");
+ close(sk);
+ test_tcp_ao_counters_free(&tmp);
+ return;
+ }
+ verify_current_rnext(tst_name, sk, -1,
+ collection.keys[i].server_keyid);
+ collection.keys[i].used_on_client = 1;
+ synchronize_threads(); /* verify current/rnext */
+ }
+ end_client(tst_name, sk, nr_keys, current_index, rnext_index, &tmp);
+}
+
+static void try_client_run(const char *tst_name, unsigned int port,
+ unsigned int nr_keys, int current_index, int rnext_index)
+{
+ struct tcp_ao_counters tmp;
+ int sk;
+
+ sk = start_client(tst_name, port, nr_keys, current_index, rnext_index,
+ &tmp, msg_len, nr_packets);
+ if (sk < 0)
+ return;
+ end_client(tst_name, sk, nr_keys, current_index, rnext_index, &tmp);
+}
+
+static void try_client_match(const char *tst_name, unsigned int port,
+ unsigned int nr_keys,
+ int current_index, int rnext_index)
+{
+ int sk;
+
+ sk = client_non_matching(tst_name, port, nr_keys, current_index,
+ rnext_index, msg_len, nr_packets);
+ if (sk < 0)
+ return;
+ try_unmatched_keys(sk, &rnext_index);
+ end_client(tst_name, sk, nr_keys, current_index, rnext_index, NULL);
+}
+
+static void *server_fn(void *arg)
+{
+ unsigned int port = test_server_port;
+
+ setup_vrfs();
+ try_server_run("server: Check current/rnext keys unset before connect()",
+ port++, quota, 19, 19);
+ try_server_run("server: Check current/rnext keys set before connect()",
+ port++, quota, 10, 10);
+ try_server_run("server: Check current != rnext keys set before connect()",
+ port++, quota, 5, 10);
+ try_server_run("server: Check current flapping back on peer's RnextKey request",
+ port++, quota * 2, 5, 10);
+ server_rotations("server: Rotate over all different keys", port++,
+ quota, 20, 0, 0);
+ try_server_run("server: Check accept() => established key matching",
+ port++, quota * 2, 0, 0);
+
+ synchronize_threads(); /* don't race to exit: client exits */
+ return NULL;
+}
+
+static void check_established_socket(void)
+{
+ unsigned int port = test_server_port;
+
+ setup_vrfs();
+ try_client_run("client: Check current/rnext keys unset before connect()",
+ port++, 20, -1, -1);
+ try_client_run("client: Check current/rnext keys set before connect()",
+ port++, 20, 10, 10);
+ try_client_run("client: Check current != rnext keys set before connect()",
+ port++, 20, 10, 5);
+ check_current_back("client: Check current flapping back on peer's RnextKey request",
+ port++, 20, 10, 5, 2);
+ roll_over_keys("client: Rotate over all different keys", port++,
+ 20, 20, 0, 0);
+ try_client_match("client: Check connect() => established key matching",
+ port++, 20, 0, 0);
+}
+
+static void *client_fn(void *arg)
+{
+ if (inet_pton(TEST_FAMILY, TEST_WRONG_IP, &wrong_addr) != 1)
+ test_error("Can't convert ip address %s", TEST_WRONG_IP);
+ check_closed_socket();
+ check_listen_socket();
+ check_established_socket();
+ return NULL;
+}
+
+int main(int argc, char *argv[])
+{
+ test_init(120, server_fn, client_fn);
+ return 0;
+}
diff --git a/tools/testing/selftests/net/tcp_ao/lib/aolib.h b/tools/testing/selftests/net/tcp_ao/lib/aolib.h
new file mode 100644
index 000000000000..fbc7f6111815
--- /dev/null
+++ b/tools/testing/selftests/net/tcp_ao/lib/aolib.h
@@ -0,0 +1,605 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * TCP-AO selftest library. Provides helpers to unshare network
+ * namespaces, create veth, assign ip addresses, set routes,
+ * manipulate socket options, read network counter and etc.
+ * Author: Dmitry Safonov <dima@arista.com>
+ */
+#ifndef _AOLIB_H_
+#define _AOLIB_H_
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <linux/snmp.h>
+#include <linux/tcp.h>
+#include <netinet/in.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#include "../../../../../include/linux/stringify.h"
+#include "../../../../../include/linux/bits.h"
+
+#ifndef SOL_TCP
+/* can't include <netinet/tcp.h> as including <linux/tcp.h> */
+# define SOL_TCP 6 /* TCP level */
+#endif
+
+/* Working around ksft, see the comment in lib/setup.c */
+extern void __test_msg(const char *buf);
+extern void __test_ok(const char *buf);
+extern void __test_fail(const char *buf);
+extern void __test_xfail(const char *buf);
+extern void __test_error(const char *buf);
+extern void __test_skip(const char *buf);
+
+__attribute__((__format__(__printf__, 2, 3)))
+static inline void __test_print(void (*fn)(const char *), const char *fmt, ...)
+{
+#define TEST_MSG_BUFFER_SIZE 4096
+ char buf[TEST_MSG_BUFFER_SIZE];
+ va_list arg;
+
+ va_start(arg, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, arg);
+ va_end(arg);
+ fn(buf);
+}
+
+#define test_print(fmt, ...) \
+ __test_print(__test_msg, "%ld[%s:%u] " fmt "\n", \
+ syscall(SYS_gettid), \
+ __FILE__, __LINE__, ##__VA_ARGS__)
+
+#define test_ok(fmt, ...) \
+ __test_print(__test_ok, fmt "\n", ##__VA_ARGS__)
+#define test_skip(fmt, ...) \
+ __test_print(__test_skip, fmt "\n", ##__VA_ARGS__)
+#define test_xfail(fmt, ...) \
+ __test_print(__test_xfail, fmt "\n", ##__VA_ARGS__)
+
+#define test_fail(fmt, ...) \
+do { \
+ if (errno) \
+ __test_print(__test_fail, fmt ": %m\n", ##__VA_ARGS__); \
+ else \
+ __test_print(__test_fail, fmt "\n", ##__VA_ARGS__); \
+ test_failed(); \
+} while (0)
+
+#define KSFT_FAIL 1
+#define test_error(fmt, ...) \
+do { \
+ if (errno) \
+ __test_print(__test_error, "%ld[%s:%u] " fmt ": %m\n", \
+ syscall(SYS_gettid), __FILE__, __LINE__, \
+ ##__VA_ARGS__); \
+ else \
+ __test_print(__test_error, "%ld[%s:%u] " fmt "\n", \
+ syscall(SYS_gettid), __FILE__, __LINE__, \
+ ##__VA_ARGS__); \
+ exit(KSFT_FAIL); \
+} while (0)
+
+enum test_fault {
+ FAULT_TIMEOUT = 1,
+ FAULT_KEYREJECT,
+ FAULT_PREINSTALL_AO,
+ FAULT_PREINSTALL_MD5,
+ FAULT_POSTINSTALL,
+ FAULT_BUSY,
+ FAULT_CURRNEXT,
+ FAULT_FIXME,
+};
+typedef enum test_fault fault_t;
+
+enum test_needs_kconfig {
+ KCONFIG_NET_NS = 0, /* required */
+ KCONFIG_VETH, /* required */
+ KCONFIG_TCP_AO, /* required */
+ KCONFIG_TCP_MD5, /* optional, for TCP-MD5 features */
+ KCONFIG_NET_VRF, /* optional, for L3/VRF testing */
+ __KCONFIG_LAST__
+};
+extern bool kernel_config_has(enum test_needs_kconfig k);
+extern const char *tests_skip_reason[__KCONFIG_LAST__];
+static inline bool should_skip_test(const char *tst_name,
+ enum test_needs_kconfig k)
+{
+ if (kernel_config_has(k))
+ return false;
+ test_skip("%s: %s", tst_name, tests_skip_reason[k]);
+ return true;
+}
+
+union tcp_addr {
+ struct in_addr a4;
+ struct in6_addr a6;
+};
+
+typedef void *(*thread_fn)(void *);
+extern void test_failed(void);
+extern void __test_init(unsigned int ntests, int family, unsigned int prefix,
+ union tcp_addr addr1, union tcp_addr addr2,
+ thread_fn peer1, thread_fn peer2);
+
+static inline void test_init2(unsigned int ntests,
+ thread_fn peer1, thread_fn peer2,
+ int family, unsigned int prefix,
+ const char *addr1, const char *addr2)
+{
+ union tcp_addr taddr1, taddr2;
+
+ if (inet_pton(family, addr1, &taddr1) != 1)
+ test_error("Can't convert ip address %s", addr1);
+ if (inet_pton(family, addr2, &taddr2) != 1)
+ test_error("Can't convert ip address %s", addr2);
+
+ __test_init(ntests, family, prefix, taddr1, taddr2, peer1, peer2);
+}
+extern void test_add_destructor(void (*d)(void));
+
+/* To adjust optmem socket limit, approximately estimate a number,
+ * that is bigger than sizeof(struct tcp_ao_key).
+ */
+#define KERNEL_TCP_AO_KEY_SZ_ROUND_UP 300
+
+extern void test_set_optmem(size_t value);
+extern size_t test_get_optmem(void);
+
+extern const struct sockaddr_in6 addr_any6;
+extern const struct sockaddr_in addr_any4;
+
+#ifdef IPV6_TEST
+# define __TEST_CLIENT_IP(n) ("2001:db8:" __stringify(n) "::1")
+# define TEST_CLIENT_IP __TEST_CLIENT_IP(1)
+# define TEST_WRONG_IP "2001:db8:253::1"
+# define TEST_SERVER_IP "2001:db8:254::1"
+# define TEST_NETWORK "2001::"
+# define TEST_PREFIX 128
+# define TEST_FAMILY AF_INET6
+# define SOCKADDR_ANY addr_any6
+# define sockaddr_af struct sockaddr_in6
+#else
+# define __TEST_CLIENT_IP(n) ("10.0." __stringify(n) ".1")
+# define TEST_CLIENT_IP __TEST_CLIENT_IP(1)
+# define TEST_WRONG_IP "10.0.253.1"
+# define TEST_SERVER_IP "10.0.254.1"
+# define TEST_NETWORK "10.0.0.0"
+# define TEST_PREFIX 32
+# define TEST_FAMILY AF_INET
+# define SOCKADDR_ANY addr_any4
+# define sockaddr_af struct sockaddr_in
+#endif
+
+static inline union tcp_addr gen_tcp_addr(union tcp_addr net, size_t n)
+{
+ union tcp_addr ret = net;
+
+#ifdef IPV6_TEST
+ ret.a6.s6_addr32[3] = htonl(n & (BIT(32) - 1));
+ ret.a6.s6_addr32[2] = htonl((n >> 32) & (BIT(32) - 1));
+#else
+ ret.a4.s_addr = htonl(ntohl(net.a4.s_addr) + n);
+#endif
+
+ return ret;
+}
+
+static inline void tcp_addr_to_sockaddr_in(void *dest,
+ const union tcp_addr *src,
+ unsigned int port)
+{
+ sockaddr_af *out = dest;
+
+ memset(out, 0, sizeof(*out));
+#ifdef IPV6_TEST
+ out->sin6_family = AF_INET6;
+ out->sin6_port = port;
+ out->sin6_addr = src->a6;
+#else
+ out->sin_family = AF_INET;
+ out->sin_port = port;
+ out->sin_addr = src->a4;
+#endif
+}
+
+static inline void test_init(unsigned int ntests,
+ thread_fn peer1, thread_fn peer2)
+{
+ test_init2(ntests, peer1, peer2, TEST_FAMILY, TEST_PREFIX,
+ TEST_SERVER_IP, TEST_CLIENT_IP);
+}
+extern void synchronize_threads(void);
+extern void switch_ns(int fd);
+
+extern __thread union tcp_addr this_ip_addr;
+extern __thread union tcp_addr this_ip_dest;
+extern int test_family;
+
+extern void randomize_buffer(void *buf, size_t buflen);
+extern int open_netns(void);
+extern int unshare_open_netns(void);
+extern const char veth_name[];
+extern int add_veth(const char *name, int nsfda, int nsfdb);
+extern int add_vrf(const char *name, uint32_t tabid, int ifindex, int nsfd);
+extern int ip_addr_add(const char *intf, int family,
+ union tcp_addr addr, uint8_t prefix);
+extern int ip_route_add(const char *intf, int family,
+ union tcp_addr src, union tcp_addr dst);
+extern int ip_route_add_vrf(const char *intf, int family,
+ union tcp_addr src, union tcp_addr dst,
+ uint8_t vrf);
+extern int link_set_up(const char *intf);
+
+extern const unsigned int test_server_port;
+extern int test_wait_fd(int sk, time_t sec, bool write);
+extern int __test_connect_socket(int sk, const char *device,
+ void *addr, size_t addr_sz, time_t timeout);
+extern int __test_listen_socket(int backlog, void *addr, size_t addr_sz);
+
+static inline int test_listen_socket(const union tcp_addr taddr,
+ unsigned int port, int backlog)
+{
+ sockaddr_af addr;
+
+ tcp_addr_to_sockaddr_in(&addr, &taddr, htons(port));
+ return __test_listen_socket(backlog, (void *)&addr, sizeof(addr));
+}
+
+/*
+ * In order for selftests to work under CONFIG_CRYPTO_FIPS=y,
+ * the password should be loger than 14 bytes, see hmac_setkey()
+ */
+#define TEST_TCP_AO_MINKEYLEN 14
+#define DEFAULT_TEST_PASSWORD "In this hour, I do not believe that any darkness will endure."
+
+#ifndef DEFAULT_TEST_ALGO
+#define DEFAULT_TEST_ALGO "cmac(aes128)"
+#endif
+
+#ifdef IPV6_TEST
+#define DEFAULT_TEST_PREFIX 128
+#else
+#define DEFAULT_TEST_PREFIX 32
+#endif
+
+/*
+ * Timeout on syscalls where failure is not expected.
+ * You may want to rise it if the test machine is very busy.
+ */
+#ifndef TEST_TIMEOUT_SEC
+#define TEST_TIMEOUT_SEC 5
+#endif
+
+/*
+ * Timeout on connect() where a failure is expected.
+ * If set to 0 - kernel will try to retransmit SYN number of times, set in
+ * /proc/sys/net/ipv4/tcp_syn_retries
+ * By default set to 1 to make tests pass faster on non-busy machine.
+ */
+#ifndef TEST_RETRANSMIT_SEC
+#define TEST_RETRANSMIT_SEC 1
+#endif
+
+static inline int _test_connect_socket(int sk, const union tcp_addr taddr,
+ unsigned int port, time_t timeout)
+{
+ sockaddr_af addr;
+
+ tcp_addr_to_sockaddr_in(&addr, &taddr, htons(port));
+ return __test_connect_socket(sk, veth_name,
+ (void *)&addr, sizeof(addr), timeout);
+}
+
+static inline int test_connect_socket(int sk, const union tcp_addr taddr,
+ unsigned int port)
+{
+ return _test_connect_socket(sk, taddr, port, TEST_TIMEOUT_SEC);
+}
+
+extern int __test_set_md5(int sk, void *addr, size_t addr_sz,
+ uint8_t prefix, int vrf, const char *password);
+static inline int test_set_md5(int sk, const union tcp_addr in_addr,
+ uint8_t prefix, int vrf, const char *password)
+{
+ sockaddr_af addr;
+
+ if (prefix > DEFAULT_TEST_PREFIX)
+ prefix = DEFAULT_TEST_PREFIX;
+
+ tcp_addr_to_sockaddr_in(&addr, &in_addr, 0);
+ return __test_set_md5(sk, (void *)&addr, sizeof(addr),
+ prefix, vrf, password);
+}
+
+extern int test_prepare_key_sockaddr(struct tcp_ao_add *ao, const char *alg,
+ void *addr, size_t addr_sz, bool set_current, bool set_rnext,
+ uint8_t prefix, uint8_t vrf,
+ uint8_t sndid, uint8_t rcvid, uint8_t maclen,
+ uint8_t keyflags, uint8_t keylen, const char *key);
+
+static inline int test_prepare_key(struct tcp_ao_add *ao,
+ const char *alg, union tcp_addr taddr,
+ bool set_current, bool set_rnext,
+ uint8_t prefix, uint8_t vrf,
+ uint8_t sndid, uint8_t rcvid, uint8_t maclen,
+ uint8_t keyflags, uint8_t keylen, const char *key)
+{
+ sockaddr_af addr;
+
+ tcp_addr_to_sockaddr_in(&addr, &taddr, 0);
+ return test_prepare_key_sockaddr(ao, alg, (void *)&addr, sizeof(addr),
+ set_current, set_rnext, prefix, vrf, sndid, rcvid,
+ maclen, keyflags, keylen, key);
+}
+
+static inline int test_prepare_def_key(struct tcp_ao_add *ao,
+ const char *key, uint8_t keyflags,
+ union tcp_addr in_addr, uint8_t prefix, uint8_t vrf,
+ uint8_t sndid, uint8_t rcvid)
+{
+ if (prefix > DEFAULT_TEST_PREFIX)
+ prefix = DEFAULT_TEST_PREFIX;
+
+ return test_prepare_key(ao, DEFAULT_TEST_ALGO, in_addr, false, false,
+ prefix, vrf, sndid, rcvid, 0, keyflags,
+ strlen(key), key);
+}
+
+extern int test_get_one_ao(int sk, struct tcp_ao_getsockopt *out,
+ void *addr, size_t addr_sz,
+ uint8_t prefix, uint8_t sndid, uint8_t rcvid);
+extern int test_get_ao_info(int sk, struct tcp_ao_info_opt *out);
+extern int test_set_ao_info(int sk, struct tcp_ao_info_opt *in);
+extern int test_cmp_getsockopt_setsockopt(const struct tcp_ao_add *a,
+ const struct tcp_ao_getsockopt *b);
+extern int test_cmp_getsockopt_setsockopt_ao(const struct tcp_ao_info_opt *a,
+ const struct tcp_ao_info_opt *b);
+
+static inline int test_verify_socket_key(int sk, struct tcp_ao_add *key)
+{
+ struct tcp_ao_getsockopt key2 = {};
+ int err;
+
+ err = test_get_one_ao(sk, &key2, &key->addr, sizeof(key->addr),
+ key->prefix, key->sndid, key->rcvid);
+ if (err)
+ return err;
+
+ return test_cmp_getsockopt_setsockopt(key, &key2);
+}
+
+static inline int test_add_key_vrf(int sk,
+ const char *key, uint8_t keyflags,
+ union tcp_addr in_addr, uint8_t prefix,
+ uint8_t vrf, uint8_t sndid, uint8_t rcvid)
+{
+ struct tcp_ao_add tmp = {};
+ int err;
+
+ err = test_prepare_def_key(&tmp, key, keyflags, in_addr, prefix,
+ vrf, sndid, rcvid);
+ if (err)
+ return err;
+
+ err = setsockopt(sk, IPPROTO_TCP, TCP_AO_ADD_KEY, &tmp, sizeof(tmp));
+ if (err < 0)
+ return -errno;
+
+ return test_verify_socket_key(sk, &tmp);
+}
+
+static inline int test_add_key(int sk, const char *key,
+ union tcp_addr in_addr, uint8_t prefix,
+ uint8_t sndid, uint8_t rcvid)
+{
+ return test_add_key_vrf(sk, key, 0, in_addr, prefix, 0, sndid, rcvid);
+}
+
+static inline int test_verify_socket_ao(int sk, struct tcp_ao_info_opt *ao)
+{
+ struct tcp_ao_info_opt ao2 = {};
+ int err;
+
+ err = test_get_ao_info(sk, &ao2);
+ if (err)
+ return err;
+
+ return test_cmp_getsockopt_setsockopt_ao(ao, &ao2);
+}
+
+static inline int test_set_ao_flags(int sk, bool ao_required, bool accept_icmps)
+{
+ struct tcp_ao_info_opt ao = {};
+ int err;
+
+ err = test_get_ao_info(sk, &ao);
+ /* Maybe ao_info wasn't allocated yet */
+ if (err && err != -ENOENT)
+ return err;
+
+ ao.ao_required = !!ao_required;
+ ao.accept_icmps = !!accept_icmps;
+ err = test_set_ao_info(sk, &ao);
+ if (err)
+ return err;
+
+ return test_verify_socket_ao(sk, &ao);
+}
+
+extern ssize_t test_server_run(int sk, ssize_t quota, time_t timeout_sec);
+extern ssize_t test_client_loop(int sk, char *buf, size_t buf_sz,
+ const size_t msg_len, time_t timeout_sec);
+extern int test_client_verify(int sk, const size_t msg_len, const size_t nr,
+ time_t timeout_sec);
+
+struct tcp_ao_key_counters {
+ uint8_t sndid;
+ uint8_t rcvid;
+ uint64_t pkt_good;
+ uint64_t pkt_bad;
+};
+
+struct tcp_ao_counters {
+ /* per-netns */
+ uint64_t netns_ao_good;
+ uint64_t netns_ao_bad;
+ uint64_t netns_ao_key_not_found;
+ uint64_t netns_ao_required;
+ uint64_t netns_ao_dropped_icmp;
+ /* per-socket */
+ uint64_t ao_info_pkt_good;
+ uint64_t ao_info_pkt_bad;
+ uint64_t ao_info_pkt_key_not_found;
+ uint64_t ao_info_pkt_ao_required;
+ uint64_t ao_info_pkt_dropped_icmp;
+ /* per-key */
+ size_t nr_keys;
+ struct tcp_ao_key_counters *key_cnts;
+};
+extern int test_get_tcp_ao_counters(int sk, struct tcp_ao_counters *out);
+
+#define TEST_CNT_KEY_GOOD BIT(0)
+#define TEST_CNT_KEY_BAD BIT(1)
+#define TEST_CNT_SOCK_GOOD BIT(2)
+#define TEST_CNT_SOCK_BAD BIT(3)
+#define TEST_CNT_SOCK_KEY_NOT_FOUND BIT(4)
+#define TEST_CNT_SOCK_AO_REQUIRED BIT(5)
+#define TEST_CNT_SOCK_DROPPED_ICMP BIT(6)
+#define TEST_CNT_NS_GOOD BIT(7)
+#define TEST_CNT_NS_BAD BIT(8)
+#define TEST_CNT_NS_KEY_NOT_FOUND BIT(9)
+#define TEST_CNT_NS_AO_REQUIRED BIT(10)
+#define TEST_CNT_NS_DROPPED_ICMP BIT(11)
+typedef uint16_t test_cnt;
+
+#define TEST_CNT_AO_GOOD (TEST_CNT_SOCK_GOOD | TEST_CNT_NS_GOOD)
+#define TEST_CNT_AO_BAD (TEST_CNT_SOCK_BAD | TEST_CNT_NS_BAD)
+#define TEST_CNT_AO_KEY_NOT_FOUND (TEST_CNT_SOCK_KEY_NOT_FOUND | \
+ TEST_CNT_NS_KEY_NOT_FOUND)
+#define TEST_CNT_AO_REQUIRED (TEST_CNT_SOCK_AO_REQUIRED | \
+ TEST_CNT_NS_AO_REQUIRED)
+#define TEST_CNT_AO_DROPPED_ICMP (TEST_CNT_SOCK_DROPPED_ICMP | \
+ TEST_CNT_NS_DROPPED_ICMP)
+#define TEST_CNT_GOOD (TEST_CNT_KEY_GOOD | TEST_CNT_AO_GOOD)
+#define TEST_CNT_BAD (TEST_CNT_KEY_BAD | TEST_CNT_AO_BAD)
+
+extern int __test_tcp_ao_counters_cmp(const char *tst_name,
+ struct tcp_ao_counters *before, struct tcp_ao_counters *after,
+ test_cnt expected);
+extern int test_tcp_ao_key_counters_cmp(const char *tst_name,
+ struct tcp_ao_counters *before, struct tcp_ao_counters *after,
+ test_cnt expected, int sndid, int rcvid);
+extern void test_tcp_ao_counters_free(struct tcp_ao_counters *cnts);
+/*
+ * Frees buffers allocated in test_get_tcp_ao_counters().
+ * The function doesn't expect new keys or keys removed between calls
+ * to test_get_tcp_ao_counters(). Check key counters manually if they
+ * may change.
+ */
+static inline int test_tcp_ao_counters_cmp(const char *tst_name,
+ struct tcp_ao_counters *before,
+ struct tcp_ao_counters *after,
+ test_cnt expected)
+{
+ int ret;
+
+ ret = __test_tcp_ao_counters_cmp(tst_name, before, after, expected);
+ if (ret)
+ goto out;
+ ret = test_tcp_ao_key_counters_cmp(tst_name, before, after,
+ expected, -1, -1);
+out:
+ test_tcp_ao_counters_free(before);
+ test_tcp_ao_counters_free(after);
+ return ret;
+}
+
+struct netstat;
+extern struct netstat *netstat_read(void);
+extern void netstat_free(struct netstat *ns);
+extern void netstat_print_diff(struct netstat *nsa, struct netstat *nsb);
+extern uint64_t netstat_get(struct netstat *ns,
+ const char *name, bool *not_found);
+
+static inline uint64_t netstat_get_one(const char *name, bool *not_found)
+{
+ struct netstat *ns = netstat_read();
+ uint64_t ret;
+
+ ret = netstat_get(ns, name, not_found);
+
+ netstat_free(ns);
+ return ret;
+}
+
+struct tcp_sock_queue {
+ uint32_t seq;
+ void *buf;
+};
+
+struct tcp_sock_state {
+ struct tcp_info info;
+ struct tcp_repair_window trw;
+ struct tcp_sock_queue out;
+ int outq_len; /* output queue size (not sent + not acked) */
+ int outq_nsd_len; /* output queue size (not sent only) */
+ struct tcp_sock_queue in;
+ int inq_len;
+ int mss;
+ int timestamp;
+};
+
+extern void __test_sock_checkpoint(int sk, struct tcp_sock_state *state,
+ void *addr, size_t addr_size);
+static inline void test_sock_checkpoint(int sk, struct tcp_sock_state *state,
+ sockaddr_af *saddr)
+{
+ __test_sock_checkpoint(sk, state, saddr, sizeof(*saddr));
+}
+extern void test_ao_checkpoint(int sk, struct tcp_ao_repair *state);
+extern void __test_sock_restore(int sk, const char *device,
+ struct tcp_sock_state *state,
+ void *saddr, void *daddr, size_t addr_size);
+static inline void test_sock_restore(int sk, struct tcp_sock_state *state,
+ sockaddr_af *saddr,
+ const union tcp_addr daddr,
+ unsigned int dport)
+{
+ sockaddr_af addr;
+
+ tcp_addr_to_sockaddr_in(&addr, &daddr, htons(dport));
+ __test_sock_restore(sk, veth_name, state, saddr, &addr, sizeof(addr));
+}
+extern void test_ao_restore(int sk, struct tcp_ao_repair *state);
+extern void test_sock_state_free(struct tcp_sock_state *state);
+extern void test_enable_repair(int sk);
+extern void test_disable_repair(int sk);
+extern void test_kill_sk(int sk);
+static inline int test_add_repaired_key(int sk,
+ const char *key, uint8_t keyflags,
+ union tcp_addr in_addr, uint8_t prefix,
+ uint8_t sndid, uint8_t rcvid)
+{
+ struct tcp_ao_add tmp = {};
+ int err;
+
+ err = test_prepare_def_key(&tmp, key, keyflags, in_addr, prefix,
+ 0, sndid, rcvid);
+ if (err)
+ return err;
+
+ tmp.set_current = 1;
+ tmp.set_rnext = 1;
+ if (setsockopt(sk, IPPROTO_TCP, TCP_AO_ADD_KEY, &tmp, sizeof(tmp)) < 0)
+ return -errno;
+
+ return test_verify_socket_key(sk, &tmp);
+}
+
+#endif /* _AOLIB_H_ */
diff --git a/tools/testing/selftests/net/tcp_ao/lib/kconfig.c b/tools/testing/selftests/net/tcp_ao/lib/kconfig.c
new file mode 100644
index 000000000000..f279ffc3843b
--- /dev/null
+++ b/tools/testing/selftests/net/tcp_ao/lib/kconfig.c
@@ -0,0 +1,148 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Check what features does the kernel support (where the selftest is running).
+ * Somewhat inspired by CRIU kerndat/kdat kernel features detector.
+ */
+#include <pthread.h>
+#include "aolib.h"
+
+struct kconfig_t {
+ int _errno; /* the returned error if not supported */
+ int (*check_kconfig)(int *error);
+};
+
+static int has_net_ns(int *err)
+{
+ if (access("/proc/self/ns/net", F_OK) < 0) {
+ *err = errno;
+ if (errno == ENOENT)
+ return 0;
+ test_print("Unable to access /proc/self/ns/net: %m");
+ return -errno;
+ }
+ return *err = errno = 0;
+}
+
+static int has_veth(int *err)
+{
+ int orig_netns, ns_a, ns_b;
+
+ orig_netns = open_netns();
+ ns_a = unshare_open_netns();
+ ns_b = unshare_open_netns();
+
+ *err = add_veth("check_veth", ns_a, ns_b);
+
+ switch_ns(orig_netns);
+ close(orig_netns);
+ close(ns_a);
+ close(ns_b);
+ return 0;
+}
+
+static int has_tcp_ao(int *err)
+{
+ struct sockaddr_in addr = {
+ .sin_family = test_family,
+ };
+ struct tcp_ao_add tmp = {};
+ const char *password = DEFAULT_TEST_PASSWORD;
+ int sk, ret = 0;
+
+ sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP);
+ if (sk < 0) {
+ test_print("socket(): %m");
+ return -errno;
+ }
+
+ tmp.sndid = 100;
+ tmp.rcvid = 100;
+ tmp.keylen = strlen(password);
+ memcpy(tmp.key, password, strlen(password));
+ strcpy(tmp.alg_name, "hmac(sha1)");
+ memcpy(&tmp.addr, &addr, sizeof(addr));
+ *err = 0;
+ if (setsockopt(sk, IPPROTO_TCP, TCP_AO_ADD_KEY, &tmp, sizeof(tmp)) < 0) {
+ *err = errno;
+ if (errno != ENOPROTOOPT)
+ ret = -errno;
+ }
+ close(sk);
+ return ret;
+}
+
+static int has_tcp_md5(int *err)
+{
+ union tcp_addr addr_any = {};
+ int sk, ret = 0;
+
+ sk = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (sk < 0) {
+ test_print("socket(): %m");
+ return -errno;
+ }
+
+ /*
+ * Under CONFIG_CRYPTO_FIPS=y it fails with ENOMEM, rather with
+ * anything more descriptive. Oh well.
+ */
+ *err = 0;
+ if (test_set_md5(sk, addr_any, 0, -1, DEFAULT_TEST_PASSWORD)) {
+ *err = errno;
+ if (errno != ENOPROTOOPT && errno == ENOMEM) {
+ test_print("setsockopt(TCP_MD5SIG_EXT): %m");
+ ret = -errno;
+ }
+ }
+ close(sk);
+ return ret;
+}
+
+static int has_vrfs(int *err)
+{
+ int orig_netns, ns_test, ret = 0;
+
+ orig_netns = open_netns();
+ ns_test = unshare_open_netns();
+
+ *err = add_vrf("ksft-check", 55, 101, ns_test);
+ if (*err && *err != -EOPNOTSUPP) {
+ test_print("Failed to add a VRF: %d", *err);
+ ret = *err;
+ }
+
+ switch_ns(orig_netns);
+ close(orig_netns);
+ close(ns_test);
+ return ret;
+}
+
+static pthread_mutex_t kconfig_lock = PTHREAD_MUTEX_INITIALIZER;
+static struct kconfig_t kconfig[__KCONFIG_LAST__] = {
+ { -1, has_net_ns },
+ { -1, has_veth },
+ { -1, has_tcp_ao },
+ { -1, has_tcp_md5 },
+ { -1, has_vrfs },
+};
+
+const char *tests_skip_reason[__KCONFIG_LAST__] = {
+ "Tests require network namespaces support (CONFIG_NET_NS)",
+ "Tests require veth support (CONFIG_VETH)",
+ "Tests require TCP-AO support (CONFIG_TCP_AO)",
+ "setsockopt(TCP_MD5SIG_EXT) is not supported (CONFIG_TCP_MD5)",
+ "VRFs are not supported (CONFIG_NET_VRF)",
+};
+
+bool kernel_config_has(enum test_needs_kconfig k)
+{
+ bool ret;
+
+ pthread_mutex_lock(&kconfig_lock);
+ if (kconfig[k]._errno == -1) {
+ if (kconfig[k].check_kconfig(&kconfig[k]._errno))
+ test_error("Failed to initialize kconfig %u", k);
+ }
+ ret = kconfig[k]._errno == 0;
+ pthread_mutex_unlock(&kconfig_lock);
+ return ret;
+}
diff --git a/tools/testing/selftests/net/tcp_ao/lib/netlink.c b/tools/testing/selftests/net/tcp_ao/lib/netlink.c
new file mode 100644
index 000000000000..b731f2c84083
--- /dev/null
+++ b/tools/testing/selftests/net/tcp_ao/lib/netlink.c
@@ -0,0 +1,415 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Original from tools/testing/selftests/net/ipsec.c */
+#include <linux/netlink.h>
+#include <linux/random.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+#include <net/if.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/socket.h>
+
+#include "aolib.h"
+
+#define MAX_PAYLOAD 2048
+
+static int netlink_sock(int *sock, uint32_t *seq_nr, int proto)
+{
+ if (*sock > 0) {
+ seq_nr++;
+ return 0;
+ }
+
+ *sock = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, proto);
+ if (*sock < 0) {
+ test_print("socket(AF_NETLINK)");
+ return -1;
+ }
+
+ randomize_buffer(seq_nr, sizeof(*seq_nr));
+
+ return 0;
+}
+
+static int netlink_check_answer(int sock, bool quite)
+{
+ struct nlmsgerror {
+ struct nlmsghdr hdr;
+ int error;
+ struct nlmsghdr orig_msg;
+ } answer;
+
+ if (recv(sock, &answer, sizeof(answer), 0) < 0) {
+ test_print("recv()");
+ return -1;
+ } else if (answer.hdr.nlmsg_type != NLMSG_ERROR) {
+ test_print("expected NLMSG_ERROR, got %d",
+ (int)answer.hdr.nlmsg_type);
+ return -1;
+ } else if (answer.error) {
+ if (!quite) {
+ test_print("NLMSG_ERROR: %d: %s",
+ answer.error, strerror(-answer.error));
+ }
+ return answer.error;
+ }
+
+ return 0;
+}
+
+static inline struct rtattr *rtattr_hdr(struct nlmsghdr *nh)
+{
+ return (struct rtattr *)((char *)(nh) + RTA_ALIGN((nh)->nlmsg_len));
+}
+
+static int rtattr_pack(struct nlmsghdr *nh, size_t req_sz,
+ unsigned short rta_type, const void *payload, size_t size)
+{
+ /* NLMSG_ALIGNTO == RTA_ALIGNTO, nlmsg_len already aligned */
+ struct rtattr *attr = rtattr_hdr(nh);
+ size_t nl_size = RTA_ALIGN(nh->nlmsg_len) + RTA_LENGTH(size);
+
+ if (req_sz < nl_size) {
+ test_print("req buf is too small: %zu < %zu", req_sz, nl_size);
+ return -1;
+ }
+ nh->nlmsg_len = nl_size;
+
+ attr->rta_len = RTA_LENGTH(size);
+ attr->rta_type = rta_type;
+ memcpy(RTA_DATA(attr), payload, size);
+
+ return 0;
+}
+
+static struct rtattr *_rtattr_begin(struct nlmsghdr *nh, size_t req_sz,
+ unsigned short rta_type, const void *payload, size_t size)
+{
+ struct rtattr *ret = rtattr_hdr(nh);
+
+ if (rtattr_pack(nh, req_sz, rta_type, payload, size))
+ return 0;
+
+ return ret;
+}
+
+static inline struct rtattr *rtattr_begin(struct nlmsghdr *nh, size_t req_sz,
+ unsigned short rta_type)
+{
+ return _rtattr_begin(nh, req_sz, rta_type, 0, 0);
+}
+
+static inline void rtattr_end(struct nlmsghdr *nh, struct rtattr *attr)
+{
+ char *nlmsg_end = (char *)nh + nh->nlmsg_len;
+
+ attr->rta_len = nlmsg_end - (char *)attr;
+}
+
+static int veth_pack_peerb(struct nlmsghdr *nh, size_t req_sz,
+ const char *peer, int ns)
+{
+ struct ifinfomsg pi;
+ struct rtattr *peer_attr;
+
+ memset(&pi, 0, sizeof(pi));
+ pi.ifi_family = AF_UNSPEC;
+ pi.ifi_change = 0xFFFFFFFF;
+
+ peer_attr = _rtattr_begin(nh, req_sz, VETH_INFO_PEER, &pi, sizeof(pi));
+ if (!peer_attr)
+ return -1;
+
+ if (rtattr_pack(nh, req_sz, IFLA_IFNAME, peer, strlen(peer)))
+ return -1;
+
+ if (rtattr_pack(nh, req_sz, IFLA_NET_NS_FD, &ns, sizeof(ns)))
+ return -1;
+
+ rtattr_end(nh, peer_attr);
+
+ return 0;
+}
+
+static int __add_veth(int sock, uint32_t seq, const char *name,
+ int ns_a, int ns_b)
+{
+ uint16_t flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE;
+ struct {
+ struct nlmsghdr nh;
+ struct ifinfomsg info;
+ char attrbuf[MAX_PAYLOAD];
+ } req;
+ static const char veth_type[] = "veth";
+ struct rtattr *link_info, *info_data;
+
+ memset(&req, 0, sizeof(req));
+ req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.info));
+ req.nh.nlmsg_type = RTM_NEWLINK;
+ req.nh.nlmsg_flags = flags;
+ req.nh.nlmsg_seq = seq;
+ req.info.ifi_family = AF_UNSPEC;
+ req.info.ifi_change = 0xFFFFFFFF;
+
+ if (rtattr_pack(&req.nh, sizeof(req), IFLA_IFNAME, name, strlen(name)))
+ return -1;
+
+ if (rtattr_pack(&req.nh, sizeof(req), IFLA_NET_NS_FD, &ns_a, sizeof(ns_a)))
+ return -1;
+
+ link_info = rtattr_begin(&req.nh, sizeof(req), IFLA_LINKINFO);
+ if (!link_info)
+ return -1;
+
+ if (rtattr_pack(&req.nh, sizeof(req), IFLA_INFO_KIND, veth_type, sizeof(veth_type)))
+ return -1;
+
+ info_data = rtattr_begin(&req.nh, sizeof(req), IFLA_INFO_DATA);
+ if (!info_data)
+ return -1;
+
+ if (veth_pack_peerb(&req.nh, sizeof(req), name, ns_b))
+ return -1;
+
+ rtattr_end(&req.nh, info_data);
+ rtattr_end(&req.nh, link_info);
+
+ if (send(sock, &req, req.nh.nlmsg_len, 0) < 0) {
+ test_print("send()");
+ return -1;
+ }
+ return netlink_check_answer(sock, false);
+}
+
+int add_veth(const char *name, int nsfda, int nsfdb)
+{
+ int route_sock = -1, ret;
+ uint32_t route_seq;
+
+ if (netlink_sock(&route_sock, &route_seq, NETLINK_ROUTE))
+ test_error("Failed to open netlink route socket\n");
+
+ ret = __add_veth(route_sock, route_seq++, name, nsfda, nsfdb);
+ close(route_sock);
+ return ret;
+}
+
+static int __ip_addr_add(int sock, uint32_t seq, const char *intf,
+ int family, union tcp_addr addr, uint8_t prefix)
+{
+ uint16_t flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE;
+ struct {
+ struct nlmsghdr nh;
+ struct ifaddrmsg info;
+ char attrbuf[MAX_PAYLOAD];
+ } req;
+ size_t addr_len = (family == AF_INET) ? sizeof(struct in_addr) :
+ sizeof(struct in6_addr);
+
+ memset(&req, 0, sizeof(req));
+ req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.info));
+ req.nh.nlmsg_type = RTM_NEWADDR;
+ req.nh.nlmsg_flags = flags;
+ req.nh.nlmsg_seq = seq;
+ req.info.ifa_family = family;
+ req.info.ifa_prefixlen = prefix;
+ req.info.ifa_index = if_nametoindex(intf);
+ req.info.ifa_flags = IFA_F_NODAD;
+
+ if (rtattr_pack(&req.nh, sizeof(req), IFA_LOCAL, &addr, addr_len))
+ return -1;
+
+ if (send(sock, &req, req.nh.nlmsg_len, 0) < 0) {
+ test_print("send()");
+ return -1;
+ }
+ return netlink_check_answer(sock, true);
+}
+
+int ip_addr_add(const char *intf, int family,
+ union tcp_addr addr, uint8_t prefix)
+{
+ int route_sock = -1, ret;
+ uint32_t route_seq;
+
+ if (netlink_sock(&route_sock, &route_seq, NETLINK_ROUTE))
+ test_error("Failed to open netlink route socket\n");
+
+ ret = __ip_addr_add(route_sock, route_seq++, intf,
+ family, addr, prefix);
+
+ close(route_sock);
+ return ret;
+}
+
+static int __ip_route_add(int sock, uint32_t seq, const char *intf, int family,
+ union tcp_addr src, union tcp_addr dst, uint8_t vrf)
+{
+ struct {
+ struct nlmsghdr nh;
+ struct rtmsg rt;
+ char attrbuf[MAX_PAYLOAD];
+ } req;
+ unsigned int index = if_nametoindex(intf);
+ size_t addr_len = (family == AF_INET) ? sizeof(struct in_addr) :
+ sizeof(struct in6_addr);
+
+ memset(&req, 0, sizeof(req));
+ req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.rt));
+ req.nh.nlmsg_type = RTM_NEWROUTE;
+ req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE;
+ req.nh.nlmsg_seq = seq;
+ req.rt.rtm_family = family;
+ req.rt.rtm_dst_len = (family == AF_INET) ? 32 : 128;
+ req.rt.rtm_table = RT_TABLE_MAIN;
+ req.rt.rtm_protocol = RTPROT_BOOT;
+ req.rt.rtm_scope = RT_SCOPE_UNIVERSE;
+ req.rt.rtm_type = RTN_UNICAST;
+
+ if (rtattr_pack(&req.nh, sizeof(req), RTA_DST, &dst, addr_len))
+ return -1;
+
+ if (rtattr_pack(&req.nh, sizeof(req), RTA_PREFSRC, &src, addr_len))
+ return -1;
+
+ if (rtattr_pack(&req.nh, sizeof(req), RTA_OIF, &index, sizeof(index)))
+ return -1;
+
+ if (send(sock, &req, req.nh.nlmsg_len, 0) < 0) {
+ test_print("send()");
+ return -1;
+ }
+
+ return netlink_check_answer(sock, true);
+}
+
+int ip_route_add_vrf(const char *intf, int family,
+ union tcp_addr src, union tcp_addr dst, uint8_t vrf)
+{
+ int route_sock = -1, ret;
+ uint32_t route_seq;
+
+ if (netlink_sock(&route_sock, &route_seq, NETLINK_ROUTE))
+ test_error("Failed to open netlink route socket\n");
+
+ ret = __ip_route_add(route_sock, route_seq++, intf,
+ family, src, dst, vrf);
+ if (ret == -EEXIST) /* ignoring */
+ ret = 0;
+
+ close(route_sock);
+ return ret;
+}
+
+int ip_route_add(const char *intf, int family,
+ union tcp_addr src, union tcp_addr dst)
+{
+ return ip_route_add_vrf(intf, family, src, dst, RT_TABLE_MAIN);
+}
+
+static int __link_set_up(int sock, uint32_t seq, const char *intf)
+{
+ struct {
+ struct nlmsghdr nh;
+ struct ifinfomsg info;
+ char attrbuf[MAX_PAYLOAD];
+ } req;
+
+ memset(&req, 0, sizeof(req));
+ req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.info));
+ req.nh.nlmsg_type = RTM_NEWLINK;
+ req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+ req.nh.nlmsg_seq = seq;
+ req.info.ifi_family = AF_UNSPEC;
+ req.info.ifi_change = 0xFFFFFFFF;
+ req.info.ifi_index = if_nametoindex(intf);
+ req.info.ifi_flags = IFF_UP;
+ req.info.ifi_change = IFF_UP;
+
+ if (send(sock, &req, req.nh.nlmsg_len, 0) < 0) {
+ test_print("send()");
+ return -1;
+ }
+ return netlink_check_answer(sock, false);
+}
+
+int link_set_up(const char *intf)
+{
+ int route_sock = -1, ret;
+ uint32_t route_seq;
+
+ if (netlink_sock(&route_sock, &route_seq, NETLINK_ROUTE))
+ test_error("Failed to open netlink route socket\n");
+
+ ret = __link_set_up(route_sock, route_seq++, intf);
+
+ close(route_sock);
+ return ret;
+}
+
+static int __add_vrf(int sock, uint32_t seq, const char *name,
+ uint32_t tabid, int ifindex, int nsfd)
+{
+ uint16_t flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE;
+ struct {
+ struct nlmsghdr nh;
+ struct ifinfomsg info;
+ char attrbuf[MAX_PAYLOAD];
+ } req;
+ static const char vrf_type[] = "vrf";
+ struct rtattr *link_info, *info_data;
+
+ memset(&req, 0, sizeof(req));
+ req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.info));
+ req.nh.nlmsg_type = RTM_NEWLINK;
+ req.nh.nlmsg_flags = flags;
+ req.nh.nlmsg_seq = seq;
+ req.info.ifi_family = AF_UNSPEC;
+ req.info.ifi_change = 0xFFFFFFFF;
+ req.info.ifi_index = ifindex;
+
+ if (rtattr_pack(&req.nh, sizeof(req), IFLA_IFNAME, name, strlen(name)))
+ return -1;
+
+ if (nsfd >= 0)
+ if (rtattr_pack(&req.nh, sizeof(req), IFLA_NET_NS_FD,
+ &nsfd, sizeof(nsfd)))
+ return -1;
+
+ link_info = rtattr_begin(&req.nh, sizeof(req), IFLA_LINKINFO);
+ if (!link_info)
+ return -1;
+
+ if (rtattr_pack(&req.nh, sizeof(req), IFLA_INFO_KIND, vrf_type, sizeof(vrf_type)))
+ return -1;
+
+ info_data = rtattr_begin(&req.nh, sizeof(req), IFLA_INFO_DATA);
+ if (!info_data)
+ return -1;
+
+ if (rtattr_pack(&req.nh, sizeof(req), IFLA_VRF_TABLE,
+ &tabid, sizeof(tabid)))
+ return -1;
+
+ rtattr_end(&req.nh, info_data);
+ rtattr_end(&req.nh, link_info);
+
+ if (send(sock, &req, req.nh.nlmsg_len, 0) < 0) {
+ test_print("send()");
+ return -1;
+ }
+ return netlink_check_answer(sock, true);
+}
+
+int add_vrf(const char *name, uint32_t tabid, int ifindex, int nsfd)
+{
+ int route_sock = -1, ret;
+ uint32_t route_seq;
+
+ if (netlink_sock(&route_sock, &route_seq, NETLINK_ROUTE))
+ test_error("Failed to open netlink route socket\n");
+
+ ret = __add_vrf(route_sock, route_seq++, name, tabid, ifindex, nsfd);
+ close(route_sock);
+ return ret;
+}
diff --git a/tools/testing/selftests/net/tcp_ao/lib/proc.c b/tools/testing/selftests/net/tcp_ao/lib/proc.c
new file mode 100644
index 000000000000..2322f4d4676d
--- /dev/null
+++ b/tools/testing/selftests/net/tcp_ao/lib/proc.c
@@ -0,0 +1,273 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <inttypes.h>
+#include <pthread.h>
+#include <stdio.h>
+#include "../../../../../include/linux/compiler.h"
+#include "../../../../../include/linux/kernel.h"
+#include "aolib.h"
+
+struct netstat_counter {
+ uint64_t val;
+ char *name;
+};
+
+struct netstat {
+ char *header_name;
+ struct netstat *next;
+ size_t counters_nr;
+ struct netstat_counter *counters;
+};
+
+static struct netstat *lookup_type(struct netstat *ns,
+ const char *type, size_t len)
+{
+ while (ns != NULL) {
+ size_t cmp = max(len, strlen(ns->header_name));
+
+ if (!strncmp(ns->header_name, type, cmp))
+ return ns;
+ ns = ns->next;
+ }
+ return NULL;
+}
+
+static struct netstat *lookup_get(struct netstat *ns,
+ const char *type, const size_t len)
+{
+ struct netstat *ret;
+
+ ret = lookup_type(ns, type, len);
+ if (ret != NULL)
+ return ret;
+
+ ret = malloc(sizeof(struct netstat));
+ if (!ret)
+ test_error("malloc()");
+
+ ret->header_name = strndup(type, len);
+ if (ret->header_name == NULL)
+ test_error("strndup()");
+ ret->next = ns;
+ ret->counters_nr = 0;
+ ret->counters = NULL;
+
+ return ret;
+}
+
+static struct netstat *lookup_get_column(struct netstat *ns, const char *line)
+{
+ char *column;
+
+ column = strchr(line, ':');
+ if (!column)
+ test_error("can't parse netstat file");
+
+ return lookup_get(ns, line, column - line);
+}
+
+static void netstat_read_type(FILE *fnetstat, struct netstat **dest, char *line)
+{
+ struct netstat *type = lookup_get_column(*dest, line);
+ const char *pos = line;
+ size_t i, nr_elems = 0;
+ char tmp;
+
+ while ((pos = strchr(pos, ' '))) {
+ nr_elems++;
+ pos++;
+ }
+
+ *dest = type;
+ type->counters = reallocarray(type->counters,
+ type->counters_nr + nr_elems,
+ sizeof(struct netstat_counter));
+ if (!type->counters)
+ test_error("reallocarray()");
+
+ pos = strchr(line, ' ') + 1;
+
+ if (fscanf(fnetstat, type->header_name) == EOF)
+ test_error("fscanf(%s)", type->header_name);
+ if (fread(&tmp, 1, 1, fnetstat) != 1 || tmp != ':')
+ test_error("Unexpected netstat format (%c)", tmp);
+
+ for (i = type->counters_nr; i < type->counters_nr + nr_elems; i++) {
+ struct netstat_counter *nc = &type->counters[i];
+ const char *new_pos = strchr(pos, ' ');
+ const char *fmt = " %" PRIu64;
+
+ if (new_pos == NULL)
+ new_pos = strchr(pos, '\n');
+
+ nc->name = strndup(pos, new_pos - pos);
+ if (nc->name == NULL)
+ test_error("strndup()");
+
+ if (unlikely(!strcmp(nc->name, "MaxConn")))
+ fmt = " %" PRId64; /* MaxConn is signed, RFC 2012 */
+ if (fscanf(fnetstat, fmt, &nc->val) != 1)
+ test_error("fscanf(%s)", nc->name);
+ pos = new_pos + 1;
+ }
+ type->counters_nr += nr_elems;
+
+ if (fread(&tmp, 1, 1, fnetstat) != 1 || tmp != '\n')
+ test_error("Unexpected netstat format");
+}
+
+static const char *snmp6_name = "Snmp6";
+static void snmp6_read(FILE *fnetstat, struct netstat **dest)
+{
+ struct netstat *type = lookup_get(*dest, snmp6_name, strlen(snmp6_name));
+ char *counter_name;
+ size_t i;
+
+ for (i = type->counters_nr;; i++) {
+ struct netstat_counter *nc;
+ uint64_t counter;
+
+ if (fscanf(fnetstat, "%ms", &counter_name) == EOF)
+ break;
+ if (fscanf(fnetstat, "%" PRIu64, &counter) == EOF)
+ test_error("Unexpected snmp6 format");
+ type->counters = reallocarray(type->counters, i + 1,
+ sizeof(struct netstat_counter));
+ if (!type->counters)
+ test_error("reallocarray()");
+ nc = &type->counters[i];
+ nc->name = counter_name;
+ nc->val = counter;
+ }
+ type->counters_nr = i;
+ *dest = type;
+}
+
+struct netstat *netstat_read(void)
+{
+ struct netstat *ret = 0;
+ size_t line_sz = 0;
+ char *line = NULL;
+ FILE *fnetstat;
+
+ /*
+ * Opening thread-self instead of /proc/net/... as the latter
+ * points to /proc/self/net/ which instantiates thread-leader's
+ * net-ns, see:
+ * commit 155134fef2b6 ("Revert "proc: Point /proc/{mounts,net} at..")
+ */
+ errno = 0;
+ fnetstat = fopen("/proc/thread-self/net/netstat", "r");
+ if (fnetstat == NULL)
+ test_error("failed to open /proc/net/netstat");
+
+ while (getline(&line, &line_sz, fnetstat) != -1)
+ netstat_read_type(fnetstat, &ret, line);
+ fclose(fnetstat);
+
+ errno = 0;
+ fnetstat = fopen("/proc/thread-self/net/snmp", "r");
+ if (fnetstat == NULL)
+ test_error("failed to open /proc/net/snmp");
+
+ while (getline(&line, &line_sz, fnetstat) != -1)
+ netstat_read_type(fnetstat, &ret, line);
+ fclose(fnetstat);
+
+ errno = 0;
+ fnetstat = fopen("/proc/thread-self/net/snmp6", "r");
+ if (fnetstat == NULL)
+ test_error("failed to open /proc/net/snmp6");
+
+ snmp6_read(fnetstat, &ret);
+ fclose(fnetstat);
+
+ free(line);
+ return ret;
+}
+
+void netstat_free(struct netstat *ns)
+{
+ while (ns != NULL) {
+ struct netstat *prev = ns;
+ size_t i;
+
+ free(ns->header_name);
+ for (i = 0; i < ns->counters_nr; i++)
+ free(ns->counters[i].name);
+ free(ns->counters);
+ ns = ns->next;
+ free(prev);
+ }
+}
+
+static inline void
+__netstat_print_diff(uint64_t a, struct netstat *nsb, size_t i)
+{
+ if (unlikely(!strcmp(nsb->header_name, "MaxConn"))) {
+ test_print("%8s %25s: %" PRId64 " => %" PRId64,
+ nsb->header_name, nsb->counters[i].name,
+ a, nsb->counters[i].val);
+ return;
+ }
+
+ test_print("%8s %25s: %" PRIu64 " => %" PRIu64, nsb->header_name,
+ nsb->counters[i].name, a, nsb->counters[i].val);
+}
+
+void netstat_print_diff(struct netstat *nsa, struct netstat *nsb)
+{
+ size_t i, j;
+
+ while (nsb != NULL) {
+ if (unlikely(strcmp(nsb->header_name, nsa->header_name))) {
+ for (i = 0; i < nsb->counters_nr; i++)
+ __netstat_print_diff(0, nsb, i);
+ nsb = nsb->next;
+ continue;
+ }
+
+ if (nsb->counters_nr < nsa->counters_nr)
+ test_error("Unexpected: some counters dissapeared!");
+
+ for (j = 0, i = 0; i < nsb->counters_nr; i++) {
+ if (strcmp(nsb->counters[i].name, nsa->counters[j].name)) {
+ __netstat_print_diff(0, nsb, i);
+ continue;
+ }
+
+ if (nsa->counters[j].val == nsb->counters[i].val) {
+ j++;
+ continue;
+ }
+
+ __netstat_print_diff(nsa->counters[j].val, nsb, i);
+ j++;
+ }
+ if (j != nsa->counters_nr)
+ test_error("Unexpected: some counters dissapeared!");
+
+ nsb = nsb->next;
+ nsa = nsa->next;
+ }
+}
+
+uint64_t netstat_get(struct netstat *ns, const char *name, bool *not_found)
+{
+ if (not_found)
+ *not_found = false;
+
+ while (ns != NULL) {
+ size_t i;
+
+ for (i = 0; i < ns->counters_nr; i++) {
+ if (!strcmp(name, ns->counters[i].name))
+ return ns->counters[i].val;
+ }
+
+ ns = ns->next;
+ }
+
+ if (not_found)
+ *not_found = true;
+ return 0;
+}
diff --git a/tools/testing/selftests/net/tcp_ao/lib/repair.c b/tools/testing/selftests/net/tcp_ao/lib/repair.c
new file mode 100644
index 000000000000..9893b3ba69f5
--- /dev/null
+++ b/tools/testing/selftests/net/tcp_ao/lib/repair.c
@@ -0,0 +1,254 @@
+// SPDX-License-Identifier: GPL-2.0
+/* This is over-simplified TCP_REPAIR for TCP_ESTABLISHED sockets
+ * It tests that TCP-AO enabled connection can be restored.
+ * For the proper socket repair see:
+ * https://github.com/checkpoint-restore/criu/blob/criu-dev/soccr/soccr.h
+ */
+#include <fcntl.h>
+#include <linux/sockios.h>
+#include <sys/ioctl.h>
+#include "aolib.h"
+
+#ifndef TCPOPT_MAXSEG
+# define TCPOPT_MAXSEG 2
+#endif
+#ifndef TCPOPT_WINDOW
+# define TCPOPT_WINDOW 3
+#endif
+#ifndef TCPOPT_SACK_PERMITTED
+# define TCPOPT_SACK_PERMITTED 4
+#endif
+#ifndef TCPOPT_TIMESTAMP
+# define TCPOPT_TIMESTAMP 8
+#endif
+
+enum {
+ TCP_ESTABLISHED = 1,
+ TCP_SYN_SENT,
+ TCP_SYN_RECV,
+ TCP_FIN_WAIT1,
+ TCP_FIN_WAIT2,
+ TCP_TIME_WAIT,
+ TCP_CLOSE,
+ TCP_CLOSE_WAIT,
+ TCP_LAST_ACK,
+ TCP_LISTEN,
+ TCP_CLOSING, /* Now a valid state */
+ TCP_NEW_SYN_RECV,
+
+ TCP_MAX_STATES /* Leave at the end! */
+};
+
+static void test_sock_checkpoint_queue(int sk, int queue, int qlen,
+ struct tcp_sock_queue *q)
+{
+ socklen_t len;
+ int ret;
+
+ if (setsockopt(sk, SOL_TCP, TCP_REPAIR_QUEUE, &queue, sizeof(queue)))
+ test_error("setsockopt(TCP_REPAIR_QUEUE)");
+
+ len = sizeof(q->seq);
+ ret = getsockopt(sk, SOL_TCP, TCP_QUEUE_SEQ, &q->seq, &len);
+ if (ret || len != sizeof(q->seq))
+ test_error("getsockopt(TCP_QUEUE_SEQ): %d", (int)len);
+
+ if (!qlen) {
+ q->buf = NULL;
+ return;
+ }
+
+ q->buf = malloc(qlen);
+ if (q->buf == NULL)
+ test_error("malloc()");
+ ret = recv(sk, q->buf, qlen, MSG_PEEK | MSG_DONTWAIT);
+ if (ret != qlen)
+ test_error("recv(%d): %d", qlen, ret);
+}
+
+void __test_sock_checkpoint(int sk, struct tcp_sock_state *state,
+ void *addr, size_t addr_size)
+{
+ socklen_t len = sizeof(state->info);
+ int ret;
+
+ memset(state, 0, sizeof(*state));
+
+ ret = getsockopt(sk, SOL_TCP, TCP_INFO, &state->info, &len);
+ if (ret || len != sizeof(state->info))
+ test_error("getsockopt(TCP_INFO): %d", (int)len);
+
+ len = addr_size;
+ if (getsockname(sk, addr, &len) || len != addr_size)
+ test_error("getsockname(): %d", (int)len);
+
+ len = sizeof(state->trw);
+ ret = getsockopt(sk, SOL_TCP, TCP_REPAIR_WINDOW, &state->trw, &len);
+ if (ret || len != sizeof(state->trw))
+ test_error("getsockopt(TCP_REPAIR_WINDOW): %d", (int)len);
+
+ if (ioctl(sk, SIOCOUTQ, &state->outq_len))
+ test_error("ioctl(SIOCOUTQ)");
+
+ if (ioctl(sk, SIOCOUTQNSD, &state->outq_nsd_len))
+ test_error("ioctl(SIOCOUTQNSD)");
+ test_sock_checkpoint_queue(sk, TCP_SEND_QUEUE, state->outq_len, &state->out);
+
+ if (ioctl(sk, SIOCINQ, &state->inq_len))
+ test_error("ioctl(SIOCINQ)");
+ test_sock_checkpoint_queue(sk, TCP_RECV_QUEUE, state->inq_len, &state->in);
+
+ if (state->info.tcpi_state == TCP_CLOSE)
+ state->outq_len = state->outq_nsd_len = 0;
+
+ len = sizeof(state->mss);
+ ret = getsockopt(sk, SOL_TCP, TCP_MAXSEG, &state->mss, &len);
+ if (ret || len != sizeof(state->mss))
+ test_error("getsockopt(TCP_MAXSEG): %d", (int)len);
+
+ len = sizeof(state->timestamp);
+ ret = getsockopt(sk, SOL_TCP, TCP_TIMESTAMP, &state->timestamp, &len);
+ if (ret || len != sizeof(state->timestamp))
+ test_error("getsockopt(TCP_TIMESTAMP): %d", (int)len);
+}
+
+void test_ao_checkpoint(int sk, struct tcp_ao_repair *state)
+{
+ socklen_t len = sizeof(*state);
+ int ret;
+
+ memset(state, 0, sizeof(*state));
+
+ ret = getsockopt(sk, SOL_TCP, TCP_AO_REPAIR, state, &len);
+ if (ret || len != sizeof(*state))
+ test_error("getsockopt(TCP_AO_REPAIR): %d", (int)len);
+}
+
+static void test_sock_restore_seq(int sk, int queue, uint32_t seq)
+{
+ if (setsockopt(sk, SOL_TCP, TCP_REPAIR_QUEUE, &queue, sizeof(queue)))
+ test_error("setsockopt(TCP_REPAIR_QUEUE)");
+
+ if (setsockopt(sk, SOL_TCP, TCP_QUEUE_SEQ, &seq, sizeof(seq)))
+ test_error("setsockopt(TCP_QUEUE_SEQ)");
+}
+
+static void test_sock_restore_queue(int sk, int queue, void *buf, int len)
+{
+ int chunk = len;
+ size_t off = 0;
+
+ if (len == 0)
+ return;
+
+ if (setsockopt(sk, SOL_TCP, TCP_REPAIR_QUEUE, &queue, sizeof(queue)))
+ test_error("setsockopt(TCP_REPAIR_QUEUE)");
+
+ do {
+ int ret;
+
+ ret = send(sk, buf + off, chunk, 0);
+ if (ret <= 0) {
+ if (chunk > 1024) {
+ chunk >>= 1;
+ continue;
+ }
+ test_error("send()");
+ }
+ off += ret;
+ len -= ret;
+ } while (len > 0);
+}
+
+void __test_sock_restore(int sk, const char *device,
+ struct tcp_sock_state *state,
+ void *saddr, void *daddr, size_t addr_size)
+{
+ struct tcp_repair_opt opts[4];
+ unsigned int opt_nr = 0;
+ long flags;
+
+ if (bind(sk, saddr, addr_size))
+ test_error("bind()");
+
+ flags = fcntl(sk, F_GETFL);
+ if ((flags < 0) || (fcntl(sk, F_SETFL, flags | O_NONBLOCK) < 0))
+ test_error("fcntl()");
+
+ test_sock_restore_seq(sk, TCP_RECV_QUEUE, state->in.seq - state->inq_len);
+ test_sock_restore_seq(sk, TCP_SEND_QUEUE, state->out.seq - state->outq_len);
+
+ if (device != NULL && setsockopt(sk, SOL_SOCKET, SO_BINDTODEVICE,
+ device, strlen(device) + 1))
+ test_error("setsockopt(SO_BINDTODEVICE, %s)", device);
+
+ if (connect(sk, daddr, addr_size))
+ test_error("connect()");
+
+ if (state->info.tcpi_options & TCPI_OPT_SACK) {
+ opts[opt_nr].opt_code = TCPOPT_SACK_PERMITTED;
+ opts[opt_nr].opt_val = 0;
+ opt_nr++;
+ }
+ if (state->info.tcpi_options & TCPI_OPT_WSCALE) {
+ opts[opt_nr].opt_code = TCPOPT_WINDOW;
+ opts[opt_nr].opt_val = state->info.tcpi_snd_wscale +
+ (state->info.tcpi_rcv_wscale << 16);
+ opt_nr++;
+ }
+ if (state->info.tcpi_options & TCPI_OPT_TIMESTAMPS) {
+ opts[opt_nr].opt_code = TCPOPT_TIMESTAMP;
+ opts[opt_nr].opt_val = 0;
+ opt_nr++;
+ }
+ opts[opt_nr].opt_code = TCPOPT_MAXSEG;
+ opts[opt_nr].opt_val = state->mss;
+ opt_nr++;
+
+ if (setsockopt(sk, SOL_TCP, TCP_REPAIR_OPTIONS, opts, opt_nr * sizeof(opts[0])))
+ test_error("setsockopt(TCP_REPAIR_OPTIONS)");
+
+ if (state->info.tcpi_options & TCPI_OPT_TIMESTAMPS) {
+ if (setsockopt(sk, SOL_TCP, TCP_TIMESTAMP,
+ &state->timestamp, opt_nr * sizeof(opts[0])))
+ test_error("setsockopt(TCP_TIMESTAMP)");
+ }
+ test_sock_restore_queue(sk, TCP_RECV_QUEUE, state->in.buf, state->inq_len);
+ test_sock_restore_queue(sk, TCP_SEND_QUEUE, state->out.buf, state->outq_len);
+ if (setsockopt(sk, SOL_TCP, TCP_REPAIR_WINDOW, &state->trw, sizeof(state->trw)))
+ test_error("setsockopt(TCP_REPAIR_WINDOW)");
+}
+
+void test_ao_restore(int sk, struct tcp_ao_repair *state)
+{
+ if (setsockopt(sk, SOL_TCP, TCP_AO_REPAIR, state, sizeof(*state)))
+ test_error("setsockopt(TCP_AO_REPAIR)");
+}
+
+void test_sock_state_free(struct tcp_sock_state *state)
+{
+ free(state->out.buf);
+ free(state->in.buf);
+}
+
+void test_enable_repair(int sk)
+{
+ int val = TCP_REPAIR_ON;
+
+ if (setsockopt(sk, SOL_TCP, TCP_REPAIR, &val, sizeof(val)))
+ test_error("setsockopt(TCP_REPAIR)");
+}
+
+void test_disable_repair(int sk)
+{
+ int val = TCP_REPAIR_OFF_NO_WP;
+
+ if (setsockopt(sk, SOL_TCP, TCP_REPAIR, &val, sizeof(val)))
+ test_error("setsockopt(TCP_REPAIR)");
+}
+
+void test_kill_sk(int sk)
+{
+ test_enable_repair(sk);
+ close(sk);
+}
diff --git a/tools/testing/selftests/net/tcp_ao/lib/setup.c b/tools/testing/selftests/net/tcp_ao/lib/setup.c
new file mode 100644
index 000000000000..374b27c26ebd
--- /dev/null
+++ b/tools/testing/selftests/net/tcp_ao/lib/setup.c
@@ -0,0 +1,342 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <fcntl.h>
+#include <pthread.h>
+#include <sched.h>
+#include <signal.h>
+#include "aolib.h"
+
+/*
+ * Can't be included in the header: it defines static variables which
+ * will be unique to every object. Let's include it only once here.
+ */
+#include "../../../kselftest.h"
+
+/* Prevent overriding of one thread's output by another */
+static pthread_mutex_t ksft_print_lock = PTHREAD_MUTEX_INITIALIZER;
+
+void __test_msg(const char *buf)
+{
+ pthread_mutex_lock(&ksft_print_lock);
+ ksft_print_msg(buf);
+ pthread_mutex_unlock(&ksft_print_lock);
+}
+void __test_ok(const char *buf)
+{
+ pthread_mutex_lock(&ksft_print_lock);
+ ksft_test_result_pass(buf);
+ pthread_mutex_unlock(&ksft_print_lock);
+}
+void __test_fail(const char *buf)
+{
+ pthread_mutex_lock(&ksft_print_lock);
+ ksft_test_result_fail(buf);
+ pthread_mutex_unlock(&ksft_print_lock);
+}
+void __test_xfail(const char *buf)
+{
+ pthread_mutex_lock(&ksft_print_lock);
+ ksft_test_result_xfail(buf);
+ pthread_mutex_unlock(&ksft_print_lock);
+}
+void __test_error(const char *buf)
+{
+ pthread_mutex_lock(&ksft_print_lock);
+ ksft_test_result_error(buf);
+ pthread_mutex_unlock(&ksft_print_lock);
+}
+void __test_skip(const char *buf)
+{
+ pthread_mutex_lock(&ksft_print_lock);
+ ksft_test_result_skip(buf);
+ pthread_mutex_unlock(&ksft_print_lock);
+}
+
+static volatile int failed;
+static volatile int skipped;
+
+void test_failed(void)
+{
+ failed = 1;
+}
+
+static void test_exit(void)
+{
+ if (failed) {
+ ksft_exit_fail();
+ } else if (skipped) {
+ /* ksft_exit_skip() is different from ksft_exit_*() */
+ ksft_print_cnts();
+ exit(KSFT_SKIP);
+ } else {
+ ksft_exit_pass();
+ }
+}
+
+struct dlist_t {
+ void (*destruct)(void);
+ struct dlist_t *next;
+};
+static struct dlist_t *destructors_list;
+
+void test_add_destructor(void (*d)(void))
+{
+ struct dlist_t *p;
+
+ p = malloc(sizeof(struct dlist_t));
+ if (p == NULL)
+ test_error("malloc() failed");
+
+ p->next = destructors_list;
+ p->destruct = d;
+ destructors_list = p;
+}
+
+static void test_destructor(void) __attribute__((destructor));
+static void test_destructor(void)
+{
+ while (destructors_list) {
+ struct dlist_t *p = destructors_list->next;
+
+ destructors_list->destruct();
+ free(destructors_list);
+ destructors_list = p;
+ }
+ test_exit();
+}
+
+static void sig_int(int signo)
+{
+ test_error("Caught SIGINT - exiting");
+}
+
+int open_netns(void)
+{
+ const char *netns_path = "/proc/self/ns/net";
+ int fd;
+
+ fd = open(netns_path, O_RDONLY);
+ if (fd < 0)
+ test_error("open(%s)", netns_path);
+ return fd;
+}
+
+int unshare_open_netns(void)
+{
+ if (unshare(CLONE_NEWNET) != 0)
+ test_error("unshare()");
+
+ return open_netns();
+}
+
+void switch_ns(int fd)
+{
+ if (setns(fd, CLONE_NEWNET))
+ test_error("setns()");
+}
+
+int switch_save_ns(int new_ns)
+{
+ int ret = open_netns();
+
+ switch_ns(new_ns);
+ return ret;
+}
+
+static int nsfd_outside = -1;
+static int nsfd_parent = -1;
+static int nsfd_child = -1;
+const char veth_name[] = "ktst-veth";
+
+static void init_namespaces(void)
+{
+ nsfd_outside = open_netns();
+ nsfd_parent = unshare_open_netns();
+ nsfd_child = unshare_open_netns();
+}
+
+static void link_init(const char *veth, int family, uint8_t prefix,
+ union tcp_addr addr, union tcp_addr dest)
+{
+ if (link_set_up(veth))
+ test_error("Failed to set link up");
+ if (ip_addr_add(veth, family, addr, prefix))
+ test_error("Failed to add ip address");
+ if (ip_route_add(veth, family, addr, dest))
+ test_error("Failed to add route");
+}
+
+static unsigned int nr_threads = 1;
+
+static pthread_mutex_t sync_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t sync_cond = PTHREAD_COND_INITIALIZER;
+static volatile unsigned int stage_threads[2];
+static volatile unsigned int stage_nr;
+
+/* synchronize all threads in the same stage */
+void synchronize_threads(void)
+{
+ unsigned int q = stage_nr;
+
+ pthread_mutex_lock(&sync_lock);
+ stage_threads[q]++;
+ if (stage_threads[q] == nr_threads) {
+ stage_nr ^= 1;
+ stage_threads[stage_nr] = 0;
+ pthread_cond_signal(&sync_cond);
+ }
+ while (stage_threads[q] < nr_threads)
+ pthread_cond_wait(&sync_cond, &sync_lock);
+ pthread_mutex_unlock(&sync_lock);
+}
+
+__thread union tcp_addr this_ip_addr;
+__thread union tcp_addr this_ip_dest;
+int test_family;
+
+struct new_pthread_arg {
+ thread_fn func;
+ union tcp_addr my_ip;
+ union tcp_addr dest_ip;
+};
+static void *new_pthread_entry(void *arg)
+{
+ struct new_pthread_arg *p = arg;
+
+ this_ip_addr = p->my_ip;
+ this_ip_dest = p->dest_ip;
+ p->func(NULL); /* shouldn't return */
+ exit(KSFT_FAIL);
+}
+
+static void __test_skip_all(const char *msg)
+{
+ ksft_set_plan(1);
+ ksft_print_header();
+ skipped = 1;
+ test_skip("%s", msg);
+ exit(KSFT_SKIP);
+}
+
+void __test_init(unsigned int ntests, int family, unsigned int prefix,
+ union tcp_addr addr1, union tcp_addr addr2,
+ thread_fn peer1, thread_fn peer2)
+{
+ struct sigaction sa = {
+ .sa_handler = sig_int,
+ .sa_flags = SA_RESTART,
+ };
+ time_t seed = time(NULL);
+
+ sigemptyset(&sa.sa_mask);
+ if (sigaction(SIGINT, &sa, NULL))
+ test_error("Can't set SIGINT handler");
+
+ test_family = family;
+ if (!kernel_config_has(KCONFIG_NET_NS))
+ __test_skip_all(tests_skip_reason[KCONFIG_NET_NS]);
+ if (!kernel_config_has(KCONFIG_VETH))
+ __test_skip_all(tests_skip_reason[KCONFIG_VETH]);
+ if (!kernel_config_has(KCONFIG_TCP_AO))
+ __test_skip_all(tests_skip_reason[KCONFIG_TCP_AO]);
+
+ ksft_set_plan(ntests);
+ test_print("rand seed %u", (unsigned int)seed);
+ srand(seed);
+
+
+ ksft_print_header();
+ init_namespaces();
+
+ if (add_veth(veth_name, nsfd_parent, nsfd_child))
+ test_error("Failed to add veth");
+
+ switch_ns(nsfd_child);
+ link_init(veth_name, family, prefix, addr2, addr1);
+ if (peer2) {
+ struct new_pthread_arg targ;
+ pthread_t t;
+
+ targ.my_ip = addr2;
+ targ.dest_ip = addr1;
+ targ.func = peer2;
+ nr_threads++;
+ if (pthread_create(&t, NULL, new_pthread_entry, &targ))
+ test_error("Failed to create pthread");
+ }
+ switch_ns(nsfd_parent);
+ link_init(veth_name, family, prefix, addr1, addr2);
+
+ this_ip_addr = addr1;
+ this_ip_dest = addr2;
+ peer1(NULL);
+ if (failed)
+ exit(KSFT_FAIL);
+ else
+ exit(KSFT_PASS);
+}
+
+/* /proc/sys/net/core/optmem_max artifically limits the amount of memory
+ * that can be allocated with sock_kmalloc() on each socket in the system.
+ * It is not virtualized, so it has to written outside test namespaces.
+ * To be nice a test will revert optmem back to the old value.
+ * Keeping it simple without any file lock, which means the tests that
+ * need to set/increase optmem value shouldn't run in parallel.
+ * Also, not re-entrant.
+ */
+static const char *optmem_file = "/proc/sys/net/core/optmem_max";
+static size_t saved_optmem;
+
+size_t test_get_optmem(void)
+{
+ FILE *foptmem;
+ int old_ns;
+ size_t ret;
+
+ old_ns = switch_save_ns(nsfd_outside);
+ foptmem = fopen(optmem_file, "r");
+ if (!foptmem)
+ test_error("failed to open %s", optmem_file);
+
+ if (fscanf(foptmem, "%zu", &ret) != 1)
+ test_error("can't read from %s", optmem_file);
+ fclose(foptmem);
+ switch_ns(old_ns);
+ return ret;
+}
+
+static void __test_set_optmem(size_t new, size_t *old)
+{
+ FILE *foptmem;
+ int old_ns;
+
+ if (old != NULL)
+ *old = test_get_optmem();
+
+ old_ns = switch_save_ns(nsfd_outside);
+ foptmem = fopen(optmem_file, "w");
+ if (!foptmem)
+ test_error("failed to open %s", optmem_file);
+
+ if (fprintf(foptmem, "%zu", new) <= 0)
+ test_error("can't write %zu to %s", new, optmem_file);
+ fclose(foptmem);
+ switch_ns(old_ns);
+}
+
+static void test_revert_optmem(void)
+{
+ if (saved_optmem == 0)
+ return;
+
+ __test_set_optmem(saved_optmem, NULL);
+}
+
+void test_set_optmem(size_t value)
+{
+ if (saved_optmem == 0) {
+ __test_set_optmem(value, &saved_optmem);
+ test_add_destructor(test_revert_optmem);
+ } else {
+ __test_set_optmem(value, NULL);
+ }
+}
diff --git a/tools/testing/selftests/net/tcp_ao/lib/sock.c b/tools/testing/selftests/net/tcp_ao/lib/sock.c
new file mode 100644
index 000000000000..c75d82885a2e
--- /dev/null
+++ b/tools/testing/selftests/net/tcp_ao/lib/sock.c
@@ -0,0 +1,592 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <alloca.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <string.h>
+#include "../../../../../include/linux/kernel.h"
+#include "../../../../../include/linux/stringify.h"
+#include "aolib.h"
+
+const unsigned int test_server_port = 7010;
+int __test_listen_socket(int backlog, void *addr, size_t addr_sz)
+{
+ int err, sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP);
+ long flags;
+
+ if (sk < 0)
+ test_error("socket()");
+
+ err = setsockopt(sk, SOL_SOCKET, SO_BINDTODEVICE, veth_name,
+ strlen(veth_name) + 1);
+ if (err < 0)
+ test_error("setsockopt(SO_BINDTODEVICE)");
+
+ if (bind(sk, (struct sockaddr *)addr, addr_sz) < 0)
+ test_error("bind()");
+
+ flags = fcntl(sk, F_GETFL);
+ if ((flags < 0) || (fcntl(sk, F_SETFL, flags | O_NONBLOCK) < 0))
+ test_error("fcntl()");
+
+ if (listen(sk, backlog))
+ test_error("listen()");
+
+ return sk;
+}
+
+int test_wait_fd(int sk, time_t sec, bool write)
+{
+ struct timeval tv = { .tv_sec = sec };
+ struct timeval *ptv = NULL;
+ fd_set fds, efds;
+ int ret;
+ socklen_t slen = sizeof(ret);
+
+ FD_ZERO(&fds);
+ FD_SET(sk, &fds);
+ FD_ZERO(&efds);
+ FD_SET(sk, &efds);
+
+ if (sec)
+ ptv = &tv;
+
+ errno = 0;
+ if (write)
+ ret = select(sk + 1, NULL, &fds, &efds, ptv);
+ else
+ ret = select(sk + 1, &fds, NULL, &efds, ptv);
+ if (ret < 0)
+ return -errno;
+ if (ret == 0) {
+ errno = ETIMEDOUT;
+ return -ETIMEDOUT;
+ }
+
+ if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &ret, &slen) || ret)
+ return -ret;
+ return 0;
+}
+
+int __test_connect_socket(int sk, const char *device,
+ void *addr, size_t addr_sz, time_t timeout)
+{
+ long flags;
+ int err;
+
+ if (device != NULL) {
+ err = setsockopt(sk, SOL_SOCKET, SO_BINDTODEVICE, device,
+ strlen(device) + 1);
+ if (err < 0)
+ test_error("setsockopt(SO_BINDTODEVICE, %s)", device);
+ }
+
+ if (!timeout) {
+ err = connect(sk, addr, addr_sz);
+ if (err) {
+ err = -errno;
+ goto out;
+ }
+ return 0;
+ }
+
+ flags = fcntl(sk, F_GETFL);
+ if ((flags < 0) || (fcntl(sk, F_SETFL, flags | O_NONBLOCK) < 0))
+ test_error("fcntl()");
+
+ if (connect(sk, addr, addr_sz) < 0) {
+ if (errno != EINPROGRESS) {
+ err = -errno;
+ goto out;
+ }
+ if (timeout < 0)
+ return sk;
+ err = test_wait_fd(sk, timeout, 1);
+ if (err)
+ goto out;
+ }
+ return sk;
+
+out:
+ close(sk);
+ return err;
+}
+
+int __test_set_md5(int sk, void *addr, size_t addr_sz, uint8_t prefix,
+ int vrf, const char *password)
+{
+ size_t pwd_len = strlen(password);
+ struct tcp_md5sig md5sig = {};
+
+ md5sig.tcpm_keylen = pwd_len;
+ memcpy(md5sig.tcpm_key, password, pwd_len);
+ md5sig.tcpm_flags = TCP_MD5SIG_FLAG_PREFIX;
+ md5sig.tcpm_prefixlen = prefix;
+ if (vrf >= 0) {
+ md5sig.tcpm_flags |= TCP_MD5SIG_FLAG_IFINDEX;
+ md5sig.tcpm_ifindex = (uint8_t)vrf;
+ }
+ memcpy(&md5sig.tcpm_addr, addr, addr_sz);
+
+ errno = 0;
+ return setsockopt(sk, IPPROTO_TCP, TCP_MD5SIG_EXT,
+ &md5sig, sizeof(md5sig));
+}
+
+
+int test_prepare_key_sockaddr(struct tcp_ao_add *ao, const char *alg,
+ void *addr, size_t addr_sz, bool set_current, bool set_rnext,
+ uint8_t prefix, uint8_t vrf, uint8_t sndid, uint8_t rcvid,
+ uint8_t maclen, uint8_t keyflags,
+ uint8_t keylen, const char *key)
+{
+ memset(ao, 0, sizeof(struct tcp_ao_add));
+
+ ao->set_current = !!set_current;
+ ao->set_rnext = !!set_rnext;
+ ao->prefix = prefix;
+ ao->sndid = sndid;
+ ao->rcvid = rcvid;
+ ao->maclen = maclen;
+ ao->keyflags = keyflags;
+ ao->keylen = keylen;
+ ao->ifindex = vrf;
+
+ memcpy(&ao->addr, addr, addr_sz);
+
+ if (strlen(alg) > 64)
+ return -ENOBUFS;
+ strncpy(ao->alg_name, alg, 64);
+
+ memcpy(ao->key, key,
+ (keylen > TCP_AO_MAXKEYLEN) ? TCP_AO_MAXKEYLEN : keylen);
+ return 0;
+}
+
+static int test_get_ao_keys_nr(int sk)
+{
+ struct tcp_ao_getsockopt tmp = {};
+ socklen_t tmp_sz = sizeof(tmp);
+ int ret;
+
+ tmp.nkeys = 1;
+ tmp.get_all = 1;
+
+ ret = getsockopt(sk, IPPROTO_TCP, TCP_AO_GET_KEYS, &tmp, &tmp_sz);
+ if (ret)
+ return -errno;
+ return (int)tmp.nkeys;
+}
+
+int test_get_one_ao(int sk, struct tcp_ao_getsockopt *out,
+ void *addr, size_t addr_sz, uint8_t prefix,
+ uint8_t sndid, uint8_t rcvid)
+{
+ struct tcp_ao_getsockopt tmp = {};
+ socklen_t tmp_sz = sizeof(tmp);
+ int ret;
+
+ memcpy(&tmp.addr, addr, addr_sz);
+ tmp.prefix = prefix;
+ tmp.sndid = sndid;
+ tmp.rcvid = rcvid;
+ tmp.nkeys = 1;
+
+ ret = getsockopt(sk, IPPROTO_TCP, TCP_AO_GET_KEYS, &tmp, &tmp_sz);
+ if (ret)
+ return ret;
+ if (tmp.nkeys != 1)
+ return -E2BIG;
+ *out = tmp;
+ return 0;
+}
+
+int test_get_ao_info(int sk, struct tcp_ao_info_opt *out)
+{
+ socklen_t sz = sizeof(*out);
+
+ out->reserved = 0;
+ out->reserved2 = 0;
+ if (getsockopt(sk, IPPROTO_TCP, TCP_AO_INFO, out, &sz))
+ return -errno;
+ if (sz != sizeof(*out))
+ return -EMSGSIZE;
+ return 0;
+}
+
+int test_set_ao_info(int sk, struct tcp_ao_info_opt *in)
+{
+ socklen_t sz = sizeof(*in);
+
+ in->reserved = 0;
+ in->reserved2 = 0;
+ if (setsockopt(sk, IPPROTO_TCP, TCP_AO_INFO, in, sz))
+ return -errno;
+ return 0;
+}
+
+int test_cmp_getsockopt_setsockopt(const struct tcp_ao_add *a,
+ const struct tcp_ao_getsockopt *b)
+{
+ bool is_kdf_aes_128_cmac = false;
+ bool is_cmac_aes = false;
+
+ if (!strcmp("cmac(aes128)", a->alg_name)) {
+ is_kdf_aes_128_cmac = (a->keylen != 16);
+ is_cmac_aes = true;
+ }
+
+#define __cmp_ao(member) \
+do { \
+ if (b->member != a->member) { \
+ test_fail("getsockopt(): " __stringify(member) " %u != %u", \
+ b->member, a->member); \
+ return -1; \
+ } \
+} while(0)
+ __cmp_ao(sndid);
+ __cmp_ao(rcvid);
+ __cmp_ao(prefix);
+ __cmp_ao(keyflags);
+ __cmp_ao(ifindex);
+ if (a->maclen) {
+ __cmp_ao(maclen);
+ } else if (b->maclen != 12) {
+ test_fail("getsockopt(): expected default maclen 12, but it's %u",
+ b->maclen);
+ return -1;
+ }
+ if (!is_kdf_aes_128_cmac) {
+ __cmp_ao(keylen);
+ } else if (b->keylen != 16) {
+ test_fail("getsockopt(): expected keylen 16 for cmac(aes128), but it's %u",
+ b->keylen);
+ return -1;
+ }
+#undef __cmp_ao
+ if (!is_kdf_aes_128_cmac && memcmp(b->key, a->key, a->keylen)) {
+ test_fail("getsockopt(): returned key is different `%s' != `%s'",
+ b->key, a->key);
+ return -1;
+ }
+ if (memcmp(&b->addr, &a->addr, sizeof(b->addr))) {
+ test_fail("getsockopt(): returned address is different");
+ return -1;
+ }
+ if (!is_cmac_aes && strcmp(b->alg_name, a->alg_name)) {
+ test_fail("getsockopt(): returned algorithm %s is different than %s", b->alg_name, a->alg_name);
+ return -1;
+ }
+ if (is_cmac_aes && strcmp(b->alg_name, "cmac(aes)")) {
+ test_fail("getsockopt(): returned algorithm %s is different than cmac(aes)", b->alg_name);
+ return -1;
+ }
+ /* For a established key rotation test don't add a key with
+ * set_current = 1, as it's likely to change by peer's request;
+ * rather use setsockopt(TCP_AO_INFO)
+ */
+ if (a->set_current != b->is_current) {
+ test_fail("getsockopt(): returned key is not Current_key");
+ return -1;
+ }
+ if (a->set_rnext != b->is_rnext) {
+ test_fail("getsockopt(): returned key is not RNext_key");
+ return -1;
+ }
+
+ return 0;
+}
+
+int test_cmp_getsockopt_setsockopt_ao(const struct tcp_ao_info_opt *a,
+ const struct tcp_ao_info_opt *b)
+{
+ /* No check for ::current_key, as it may change by the peer */
+ if (a->ao_required != b->ao_required) {
+ test_fail("getsockopt(): returned ao doesn't have ao_required");
+ return -1;
+ }
+ if (a->accept_icmps != b->accept_icmps) {
+ test_fail("getsockopt(): returned ao doesn't accept ICMPs");
+ return -1;
+ }
+ if (a->set_rnext && a->rnext != b->rnext) {
+ test_fail("getsockopt(): RNext KeyID has changed");
+ return -1;
+ }
+#define __cmp_cnt(member) \
+do { \
+ if (b->member != a->member) { \
+ test_fail("getsockopt(): " __stringify(member) " %llu != %llu", \
+ b->member, a->member); \
+ return -1; \
+ } \
+} while(0)
+ if (a->set_counters) {
+ __cmp_cnt(pkt_good);
+ __cmp_cnt(pkt_bad);
+ __cmp_cnt(pkt_key_not_found);
+ __cmp_cnt(pkt_ao_required);
+ __cmp_cnt(pkt_dropped_icmp);
+ }
+#undef __cmp_cnt
+ return 0;
+}
+
+int test_get_tcp_ao_counters(int sk, struct tcp_ao_counters *out)
+{
+ struct tcp_ao_getsockopt *key_dump;
+ socklen_t key_dump_sz = sizeof(*key_dump);
+ struct tcp_ao_info_opt info = {};
+ bool c1, c2, c3, c4, c5;
+ struct netstat *ns;
+ int err, nr_keys;
+
+ memset(out, 0, sizeof(*out));
+
+ /* per-netns */
+ ns = netstat_read();
+ out->netns_ao_good = netstat_get(ns, "TCPAOGood", &c1);
+ out->netns_ao_bad = netstat_get(ns, "TCPAOBad", &c2);
+ out->netns_ao_key_not_found = netstat_get(ns, "TCPAOKeyNotFound", &c3);
+ out->netns_ao_required = netstat_get(ns, "TCPAORequired", &c4);
+ out->netns_ao_dropped_icmp = netstat_get(ns, "TCPAODroppedIcmps", &c5);
+ netstat_free(ns);
+ if (c1 || c2 || c3 || c4 || c5)
+ return -EOPNOTSUPP;
+
+ err = test_get_ao_info(sk, &info);
+ if (err)
+ return err;
+
+ /* per-socket */
+ out->ao_info_pkt_good = info.pkt_good;
+ out->ao_info_pkt_bad = info.pkt_bad;
+ out->ao_info_pkt_key_not_found = info.pkt_key_not_found;
+ out->ao_info_pkt_ao_required = info.pkt_ao_required;
+ out->ao_info_pkt_dropped_icmp = info.pkt_dropped_icmp;
+
+ /* per-key */
+ nr_keys = test_get_ao_keys_nr(sk);
+ if (nr_keys < 0)
+ return nr_keys;
+ if (nr_keys == 0)
+ test_error("test_get_ao_keys_nr() == 0");
+ out->nr_keys = (size_t)nr_keys;
+ key_dump = calloc(nr_keys, key_dump_sz);
+ if (!key_dump)
+ return -errno;
+
+ key_dump[0].nkeys = nr_keys;
+ key_dump[0].get_all = 1;
+ key_dump[0].get_all = 1;
+ err = getsockopt(sk, IPPROTO_TCP, TCP_AO_GET_KEYS,
+ key_dump, &key_dump_sz);
+ if (err) {
+ free(key_dump);
+ return -errno;
+ }
+
+ out->key_cnts = calloc(nr_keys, sizeof(out->key_cnts[0]));
+ if (!out->key_cnts) {
+ free(key_dump);
+ return -errno;
+ }
+
+ while (nr_keys--) {
+ out->key_cnts[nr_keys].sndid = key_dump[nr_keys].sndid;
+ out->key_cnts[nr_keys].rcvid = key_dump[nr_keys].rcvid;
+ out->key_cnts[nr_keys].pkt_good = key_dump[nr_keys].pkt_good;
+ out->key_cnts[nr_keys].pkt_bad = key_dump[nr_keys].pkt_bad;
+ }
+ free(key_dump);
+
+ return 0;
+}
+
+int __test_tcp_ao_counters_cmp(const char *tst_name,
+ struct tcp_ao_counters *before,
+ struct tcp_ao_counters *after,
+ test_cnt expected)
+{
+#define __cmp_ao(cnt, expecting_inc) \
+do { \
+ if (before->cnt > after->cnt) { \
+ test_fail("%s: Decreased counter " __stringify(cnt) " %" PRIu64 " > %" PRIu64, \
+ tst_name ?: "", before->cnt, after->cnt); \
+ return -1; \
+ } \
+ if ((before->cnt != after->cnt) != (expecting_inc)) { \
+ test_fail("%s: Counter " __stringify(cnt) " was %sexpected to increase %" PRIu64 " => %" PRIu64, \
+ tst_name ?: "", (expecting_inc) ? "" : "not ", \
+ before->cnt, after->cnt); \
+ return -1; \
+ } \
+} while(0)
+
+ errno = 0;
+ /* per-netns */
+ __cmp_ao(netns_ao_good, !!(expected & TEST_CNT_NS_GOOD));
+ __cmp_ao(netns_ao_bad, !!(expected & TEST_CNT_NS_BAD));
+ __cmp_ao(netns_ao_key_not_found,
+ !!(expected & TEST_CNT_NS_KEY_NOT_FOUND));
+ __cmp_ao(netns_ao_required, !!(expected & TEST_CNT_NS_AO_REQUIRED));
+ __cmp_ao(netns_ao_dropped_icmp,
+ !!(expected & TEST_CNT_NS_DROPPED_ICMP));
+ /* per-socket */
+ __cmp_ao(ao_info_pkt_good, !!(expected & TEST_CNT_SOCK_GOOD));
+ __cmp_ao(ao_info_pkt_bad, !!(expected & TEST_CNT_SOCK_BAD));
+ __cmp_ao(ao_info_pkt_key_not_found,
+ !!(expected & TEST_CNT_SOCK_KEY_NOT_FOUND));
+ __cmp_ao(ao_info_pkt_ao_required, !!(expected & TEST_CNT_SOCK_AO_REQUIRED));
+ __cmp_ao(ao_info_pkt_dropped_icmp,
+ !!(expected & TEST_CNT_SOCK_DROPPED_ICMP));
+ return 0;
+#undef __cmp_ao
+}
+
+int test_tcp_ao_key_counters_cmp(const char *tst_name,
+ struct tcp_ao_counters *before,
+ struct tcp_ao_counters *after,
+ test_cnt expected,
+ int sndid, int rcvid)
+{
+ size_t i;
+#define __cmp_ao(i, cnt, expecting_inc) \
+do { \
+ if (before->key_cnts[i].cnt > after->key_cnts[i].cnt) { \
+ test_fail("%s: Decreased counter " __stringify(cnt) " %" PRIu64 " > %" PRIu64 " for key %u:%u", \
+ tst_name ?: "", before->key_cnts[i].cnt, \
+ after->key_cnts[i].cnt, \
+ before->key_cnts[i].sndid, \
+ before->key_cnts[i].rcvid); \
+ return -1; \
+ } \
+ if ((before->key_cnts[i].cnt != after->key_cnts[i].cnt) != (expecting_inc)) { \
+ test_fail("%s: Counter " __stringify(cnt) " was %sexpected to increase %" PRIu64 " => %" PRIu64 " for key %u:%u", \
+ tst_name ?: "", (expecting_inc) ? "" : "not ",\
+ before->key_cnts[i].cnt, \
+ after->key_cnts[i].cnt, \
+ before->key_cnts[i].sndid, \
+ before->key_cnts[i].rcvid); \
+ return -1; \
+ } \
+} while(0)
+
+ if (before->nr_keys != after->nr_keys) {
+ test_fail("%s: Keys changed on the socket %zu != %zu",
+ tst_name, before->nr_keys, after->nr_keys);
+ return -1;
+ }
+
+ /* per-key */
+ i = before->nr_keys;
+ while (i--) {
+ if (sndid >= 0 && before->key_cnts[i].sndid != sndid)
+ continue;
+ if (rcvid >= 0 && before->key_cnts[i].rcvid != rcvid)
+ continue;
+ __cmp_ao(i, pkt_good, !!(expected & TEST_CNT_KEY_GOOD));
+ __cmp_ao(i, pkt_bad, !!(expected & TEST_CNT_KEY_BAD));
+ }
+ return 0;
+#undef __cmp_ao
+}
+
+void test_tcp_ao_counters_free(struct tcp_ao_counters *cnts)
+{
+ free(cnts->key_cnts);
+}
+
+#define TEST_BUF_SIZE 4096
+ssize_t test_server_run(int sk, ssize_t quota, time_t timeout_sec)
+{
+ ssize_t total = 0;
+
+ do {
+ char buf[TEST_BUF_SIZE];
+ ssize_t bytes, sent;
+ int ret;
+
+ ret = test_wait_fd(sk, timeout_sec, 0);
+ if (ret)
+ return ret;
+
+ bytes = recv(sk, buf, sizeof(buf), 0);
+
+ if (bytes < 0)
+ test_error("recv(): %zd", bytes);
+ if (bytes == 0)
+ break;
+
+ ret = test_wait_fd(sk, timeout_sec, 1);
+ if (ret)
+ return ret;
+
+ sent = send(sk, buf, bytes, 0);
+ if (sent == 0)
+ break;
+ if (sent != bytes)
+ test_error("send()");
+ total += bytes;
+ } while (!quota || total < quota);
+
+ return total;
+}
+
+ssize_t test_client_loop(int sk, char *buf, size_t buf_sz,
+ const size_t msg_len, time_t timeout_sec)
+{
+ char msg[msg_len];
+ int nodelay = 1;
+ size_t i;
+
+ if (setsockopt(sk, IPPROTO_TCP, TCP_NODELAY, &nodelay, sizeof(nodelay)))
+ test_error("setsockopt(TCP_NODELAY)");
+
+ for (i = 0; i < buf_sz; i += min(msg_len, buf_sz - i)) {
+ size_t sent, bytes = min(msg_len, buf_sz - i);
+ int ret;
+
+ ret = test_wait_fd(sk, timeout_sec, 1);
+ if (ret)
+ return ret;
+
+ sent = send(sk, buf + i, bytes, 0);
+ if (sent == 0)
+ break;
+ if (sent != bytes)
+ test_error("send()");
+
+ bytes = 0;
+ do {
+ ssize_t got;
+
+ ret = test_wait_fd(sk, timeout_sec, 0);
+ if (ret)
+ return ret;
+
+ got = recv(sk, msg + bytes, sizeof(msg) - bytes, 0);
+ if (got <= 0)
+ return i;
+ bytes += got;
+ } while (bytes < sent);
+ if (bytes > sent)
+ test_error("recv(): %zd > %zd", bytes, sent);
+ if (memcmp(buf + i, msg, bytes) != 0) {
+ test_fail("received message differs");
+ return -1;
+ }
+ }
+ return i;
+}
+
+int test_client_verify(int sk, const size_t msg_len, const size_t nr,
+ time_t timeout_sec)
+{
+ size_t buf_sz = msg_len * nr;
+ char *buf = alloca(buf_sz);
+
+ randomize_buffer(buf, buf_sz);
+ if (test_client_loop(sk, buf, buf_sz, msg_len, timeout_sec) != buf_sz)
+ return -1;
+ return 0;
+}
diff --git a/tools/testing/selftests/net/tcp_ao/lib/utils.c b/tools/testing/selftests/net/tcp_ao/lib/utils.c
new file mode 100644
index 000000000000..372daca525f5
--- /dev/null
+++ b/tools/testing/selftests/net/tcp_ao/lib/utils.c
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: GPL-2.0
+#include "aolib.h"
+#include <string.h>
+
+void randomize_buffer(void *buf, size_t buflen)
+{
+ int *p = (int *)buf;
+ size_t words = buflen / sizeof(int);
+ size_t leftover = buflen % sizeof(int);
+
+ if (!buflen)
+ return;
+
+ while (words--)
+ *p++ = rand();
+
+ if (leftover) {
+ int tmp = rand();
+
+ memcpy(buf + buflen - leftover, &tmp, leftover);
+ }
+}
+
+const struct sockaddr_in6 addr_any6 = {
+ .sin6_family = AF_INET6,
+};
+
+const struct sockaddr_in addr_any4 = {
+ .sin_family = AF_INET,
+};
diff --git a/tools/testing/selftests/net/tcp_ao/restore.c b/tools/testing/selftests/net/tcp_ao/restore.c
new file mode 100644
index 000000000000..8fdc808df325
--- /dev/null
+++ b/tools/testing/selftests/net/tcp_ao/restore.c
@@ -0,0 +1,236 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Author: Dmitry Safonov <dima@arista.com> */
+/* This is over-simplified TCP_REPAIR for TCP_ESTABLISHED sockets
+ * It tests that TCP-AO enabled connection can be restored.
+ * For the proper socket repair see:
+ * https://github.com/checkpoint-restore/criu/blob/criu-dev/soccr/soccr.h
+ */
+#include <inttypes.h>
+#include "aolib.h"
+
+const size_t nr_packets = 20;
+const size_t msg_len = 100;
+const size_t quota = nr_packets * msg_len;
+#define fault(type) (inj == FAULT_ ## type)
+
+static void try_server_run(const char *tst_name, unsigned int port,
+ fault_t inj, test_cnt cnt_expected)
+{
+ const char *cnt_name = "TCPAOGood";
+ struct tcp_ao_counters ao1, ao2;
+ uint64_t before_cnt, after_cnt;
+ int sk, lsk;
+ time_t timeout;
+ ssize_t bytes;
+
+ if (fault(TIMEOUT))
+ cnt_name = "TCPAOBad";
+ lsk = test_listen_socket(this_ip_addr, port, 1);
+
+ if (test_add_key(lsk, DEFAULT_TEST_PASSWORD, this_ip_dest, -1, 100, 100))
+ test_error("setsockopt(TCP_AO_ADD_KEY)");
+ synchronize_threads(); /* 1: MKT added => connect() */
+
+ if (test_wait_fd(lsk, TEST_TIMEOUT_SEC, 0))
+ test_error("test_wait_fd()");
+
+ sk = accept(lsk, NULL, NULL);
+ if (sk < 0)
+ test_error("accept()");
+
+ synchronize_threads(); /* 2: accepted => send data */
+ close(lsk);
+
+ bytes = test_server_run(sk, quota, TEST_TIMEOUT_SEC);
+ if (bytes != quota) {
+ test_fail("%s: server served: %zd", tst_name, bytes);
+ goto out;
+ }
+
+ before_cnt = netstat_get_one(cnt_name, NULL);
+ if (test_get_tcp_ao_counters(sk, &ao1))
+ test_error("test_get_tcp_ao_counters()");
+
+ timeout = fault(TIMEOUT) ? TEST_RETRANSMIT_SEC : TEST_TIMEOUT_SEC;
+ bytes = test_server_run(sk, quota, timeout);
+ if (fault(TIMEOUT)) {
+ if (bytes > 0)
+ test_fail("%s: server served: %zd", tst_name, bytes);
+ else
+ test_ok("%s: server couldn't serve", tst_name);
+ } else {
+ if (bytes != quota)
+ test_fail("%s: server served: %zd", tst_name, bytes);
+ else
+ test_ok("%s: server alive", tst_name);
+ }
+ if (test_get_tcp_ao_counters(sk, &ao2))
+ test_error("test_get_tcp_ao_counters()");
+ after_cnt = netstat_get_one(cnt_name, NULL);
+
+ test_tcp_ao_counters_cmp(tst_name, &ao1, &ao2, cnt_expected);
+
+ if (after_cnt <= before_cnt) {
+ test_fail("%s: %s counter did not increase: %zu <= %zu",
+ tst_name, cnt_name, after_cnt, before_cnt);
+ } else {
+ test_ok("%s: counter %s increased %zu => %zu",
+ tst_name, cnt_name, before_cnt, after_cnt);
+ }
+
+ /*
+ * Before close() as that will send FIN and move the peer in TCP_CLOSE
+ * and that will prevent reading AO counters from the peer's socket.
+ */
+ synchronize_threads(); /* 3: verified => closed */
+out:
+ close(sk);
+}
+
+static void *server_fn(void *arg)
+{
+ unsigned int port = test_server_port;
+
+ try_server_run("TCP-AO migrate to another socket", port++,
+ 0, TEST_CNT_GOOD);
+ try_server_run("TCP-AO with wrong send ISN", port++,
+ FAULT_TIMEOUT, TEST_CNT_BAD);
+ try_server_run("TCP-AO with wrong receive ISN", port++,
+ FAULT_TIMEOUT, TEST_CNT_BAD);
+ try_server_run("TCP-AO with wrong send SEQ ext number", port++,
+ FAULT_TIMEOUT, TEST_CNT_BAD);
+ try_server_run("TCP-AO with wrong receive SEQ ext number", port++,
+ FAULT_TIMEOUT, TEST_CNT_NS_BAD | TEST_CNT_GOOD);
+
+ synchronize_threads(); /* don't race to exit: client exits */
+ return NULL;
+}
+
+static void test_get_sk_checkpoint(unsigned int server_port, sockaddr_af *saddr,
+ struct tcp_sock_state *img,
+ struct tcp_ao_repair *ao_img)
+{
+ int sk;
+
+ sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP);
+ if (sk < 0)
+ test_error("socket()");
+
+ if (test_add_key(sk, DEFAULT_TEST_PASSWORD, this_ip_dest, -1, 100, 100))
+ test_error("setsockopt(TCP_AO_ADD_KEY)");
+
+ synchronize_threads(); /* 1: MKT added => connect() */
+ if (test_connect_socket(sk, this_ip_dest, server_port) <= 0)
+ test_error("failed to connect()");
+
+ synchronize_threads(); /* 2: accepted => send data */
+ if (test_client_verify(sk, msg_len, nr_packets, TEST_TIMEOUT_SEC))
+ test_fail("pre-migrate verify failed");
+
+ test_enable_repair(sk);
+ test_sock_checkpoint(sk, img, saddr);
+ test_ao_checkpoint(sk, ao_img);
+ test_kill_sk(sk);
+}
+
+static void test_sk_restore(const char *tst_name, unsigned int server_port,
+ sockaddr_af *saddr, struct tcp_sock_state *img,
+ struct tcp_ao_repair *ao_img,
+ fault_t inj, test_cnt cnt_expected)
+{
+ const char *cnt_name = "TCPAOGood";
+ struct tcp_ao_counters ao1, ao2;
+ uint64_t before_cnt, after_cnt;
+ time_t timeout;
+ int sk;
+
+ if (fault(TIMEOUT))
+ cnt_name = "TCPAOBad";
+
+ before_cnt = netstat_get_one(cnt_name, NULL);
+ sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP);
+ if (sk < 0)
+ test_error("socket()");
+
+ test_enable_repair(sk);
+ test_sock_restore(sk, img, saddr, this_ip_dest, server_port);
+ if (test_add_repaired_key(sk, DEFAULT_TEST_PASSWORD, 0, this_ip_dest, -1, 100, 100))
+ test_error("setsockopt(TCP_AO_ADD_KEY)");
+ test_ao_restore(sk, ao_img);
+
+ if (test_get_tcp_ao_counters(sk, &ao1))
+ test_error("test_get_tcp_ao_counters()");
+
+ test_disable_repair(sk);
+ test_sock_state_free(img);
+
+ timeout = fault(TIMEOUT) ? TEST_RETRANSMIT_SEC : TEST_TIMEOUT_SEC;
+ if (test_client_verify(sk, msg_len, nr_packets, timeout)) {
+ if (fault(TIMEOUT))
+ test_ok("%s: post-migrate connection is broken", tst_name);
+ else
+ test_fail("%s: post-migrate connection is working", tst_name);
+ } else {
+ if (fault(TIMEOUT))
+ test_fail("%s: post-migrate connection still working", tst_name);
+ else
+ test_ok("%s: post-migrate connection is alive", tst_name);
+ }
+ if (test_get_tcp_ao_counters(sk, &ao2))
+ test_error("test_get_tcp_ao_counters()");
+ after_cnt = netstat_get_one(cnt_name, NULL);
+
+ test_tcp_ao_counters_cmp(tst_name, &ao1, &ao2, cnt_expected);
+
+ if (after_cnt <= before_cnt) {
+ test_fail("%s: %s counter did not increase: %zu <= %zu",
+ tst_name, cnt_name, after_cnt, before_cnt);
+ } else {
+ test_ok("%s: counter %s increased %zu => %zu",
+ tst_name, cnt_name, before_cnt, after_cnt);
+ }
+ synchronize_threads(); /* 3: verified => closed */
+ close(sk);
+}
+
+static void *client_fn(void *arg)
+{
+ unsigned int port = test_server_port;
+ struct tcp_sock_state tcp_img;
+ struct tcp_ao_repair ao_img;
+ sockaddr_af saddr;
+
+ test_get_sk_checkpoint(port, &saddr, &tcp_img, &ao_img);
+ test_sk_restore("TCP-AO migrate to another socket", port++,
+ &saddr, &tcp_img, &ao_img, 0, TEST_CNT_GOOD);
+
+ test_get_sk_checkpoint(port, &saddr, &tcp_img, &ao_img);
+ ao_img.snt_isn += 1;
+ test_sk_restore("TCP-AO with wrong send ISN", port++,
+ &saddr, &tcp_img, &ao_img, FAULT_TIMEOUT, TEST_CNT_BAD);
+
+ test_get_sk_checkpoint(port, &saddr, &tcp_img, &ao_img);
+ ao_img.rcv_isn += 1;
+ test_sk_restore("TCP-AO with wrong receive ISN", port++,
+ &saddr, &tcp_img, &ao_img, FAULT_TIMEOUT, TEST_CNT_BAD);
+
+ test_get_sk_checkpoint(port, &saddr, &tcp_img, &ao_img);
+ ao_img.snd_sne += 1;
+ test_sk_restore("TCP-AO with wrong send SEQ ext number", port++,
+ &saddr, &tcp_img, &ao_img, FAULT_TIMEOUT,
+ TEST_CNT_NS_BAD | TEST_CNT_GOOD);
+
+ test_get_sk_checkpoint(port, &saddr, &tcp_img, &ao_img);
+ ao_img.rcv_sne += 1;
+ test_sk_restore("TCP-AO with wrong receive SEQ ext number", port++,
+ &saddr, &tcp_img, &ao_img, FAULT_TIMEOUT,
+ TEST_CNT_NS_GOOD | TEST_CNT_BAD);
+
+ return NULL;
+}
+
+int main(int argc, char *argv[])
+{
+ test_init(20, server_fn, client_fn);
+ return 0;
+}
diff --git a/tools/testing/selftests/net/tcp_ao/rst.c b/tools/testing/selftests/net/tcp_ao/rst.c
new file mode 100644
index 000000000000..ac06009a7f5f
--- /dev/null
+++ b/tools/testing/selftests/net/tcp_ao/rst.c
@@ -0,0 +1,415 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Author: Dmitry Safonov <dima@arista.com> */
+#include <inttypes.h>
+#include "../../../../include/linux/kernel.h"
+#include "aolib.h"
+
+const size_t quota = 1000;
+/*
+ * Backlog == 0 means 1 connection in queue, see:
+ * commit 64a146513f8f ("[NET]: Revert incorrect accept queue...")
+ */
+const unsigned int backlog;
+
+static void netstats_check(struct netstat *before, struct netstat *after,
+ char *msg)
+{
+ uint64_t before_cnt, after_cnt;
+
+ before_cnt = netstat_get(before, "TCPAORequired", NULL);
+ after_cnt = netstat_get(after, "TCPAORequired", NULL);
+ if (after_cnt > before_cnt)
+ test_fail("Segments without AO sign (%s): %" PRIu64 " => %" PRIu64,
+ msg, before_cnt, after_cnt);
+ else
+ test_ok("No segments without AO sign (%s)", msg);
+
+ before_cnt = netstat_get(before, "TCPAOGood", NULL);
+ after_cnt = netstat_get(after, "TCPAOGood", NULL);
+ if (after_cnt <= before_cnt)
+ test_fail("Signed AO segments (%s): %" PRIu64 " => %" PRIu64,
+ msg, before_cnt, after_cnt);
+ else
+ test_ok("Signed AO segments (%s): %" PRIu64 " => %" PRIu64,
+ msg, before_cnt, after_cnt);
+
+ before_cnt = netstat_get(before, "TCPAOBad", NULL);
+ after_cnt = netstat_get(after, "TCPAOBad", NULL);
+ if (after_cnt > before_cnt)
+ test_fail("Segments with bad AO sign (%s): %" PRIu64 " => %" PRIu64,
+ msg, before_cnt, after_cnt);
+ else
+ test_ok("No segments with bad AO sign (%s)", msg);
+}
+
+/*
+ * Another way to send RST, but not through tcp_v{4,6}_send_reset()
+ * is tcp_send_active_reset(), that is not in reply to inbound segment,
+ * but rather active send. It uses tcp_transmit_skb(), so that should
+ * work, but as it also sends RST - nice that it can be covered as well.
+ */
+static void close_forced(int sk)
+{
+ struct linger sl;
+
+ sl.l_onoff = 1;
+ sl.l_linger = 0;
+ if (setsockopt(sk, SOL_SOCKET, SO_LINGER, &sl, sizeof(sl)))
+ test_error("setsockopt(SO_LINGER)");
+ close(sk);
+}
+
+static int test_wait_for_exception(int sk, time_t sec)
+{
+ struct timeval tv = { .tv_sec = sec };
+ struct timeval *ptv = NULL;
+ fd_set efds;
+ int ret;
+
+ FD_ZERO(&efds);
+ FD_SET(sk, &efds);
+
+ if (sec)
+ ptv = &tv;
+
+ errno = 0;
+ ret = select(sk + 1, NULL, NULL, &efds, ptv);
+ if (ret < 0)
+ return -errno;
+ return ret ? sk : 0;
+}
+
+static void test_server_active_rst(unsigned int port)
+{
+ struct tcp_ao_counters cnt1, cnt2;
+ ssize_t bytes;
+ int sk, lsk;
+
+ lsk = test_listen_socket(this_ip_addr, port, backlog);
+ if (test_add_key(lsk, DEFAULT_TEST_PASSWORD, this_ip_dest, -1, 100, 100))
+ test_error("setsockopt(TCP_AO_ADD_KEY)");
+ if (test_get_tcp_ao_counters(lsk, &cnt1))
+ test_error("test_get_tcp_ao_counters()");
+
+ synchronize_threads(); /* 1: MKT added */
+ if (test_wait_fd(lsk, TEST_TIMEOUT_SEC, 0))
+ test_error("test_wait_fd()");
+
+ sk = accept(lsk, NULL, NULL);
+ if (sk < 0)
+ test_error("accept()");
+
+ synchronize_threads(); /* 2: connection accept()ed, another queued */
+ if (test_get_tcp_ao_counters(lsk, &cnt2))
+ test_error("test_get_tcp_ao_counters()");
+
+ synchronize_threads(); /* 3: close listen socket */
+ close(lsk);
+ bytes = test_server_run(sk, quota, 0);
+ if (bytes != quota)
+ test_error("servered only %zd bytes", bytes);
+ else
+ test_ok("servered %zd bytes", bytes);
+
+ synchronize_threads(); /* 4: finishing up */
+ close_forced(sk);
+
+ synchronize_threads(); /* 5: closed active sk */
+
+ synchronize_threads(); /* 6: counters checks */
+ if (test_tcp_ao_counters_cmp("active RST server", &cnt1, &cnt2, TEST_CNT_GOOD))
+ test_fail("MKT counters (server) have not only good packets");
+ else
+ test_ok("MKT counters are good on server");
+}
+
+static void test_server_passive_rst(unsigned int port)
+{
+ struct tcp_ao_counters ao1, ao2;
+ int sk, lsk;
+ ssize_t bytes;
+
+ lsk = test_listen_socket(this_ip_addr, port, 1);
+
+ if (test_add_key(lsk, DEFAULT_TEST_PASSWORD, this_ip_dest, -1, 100, 100))
+ test_error("setsockopt(TCP_AO_ADD_KEY)");
+
+ synchronize_threads(); /* 1: MKT added => connect() */
+ if (test_wait_fd(lsk, TEST_TIMEOUT_SEC, 0))
+ test_error("test_wait_fd()");
+
+ sk = accept(lsk, NULL, NULL);
+ if (sk < 0)
+ test_error("accept()");
+
+ synchronize_threads(); /* 2: accepted => send data */
+ close(lsk);
+ if (test_get_tcp_ao_counters(sk, &ao1))
+ test_error("test_get_tcp_ao_counters()");
+
+ bytes = test_server_run(sk, quota, TEST_TIMEOUT_SEC);
+ if (bytes != quota) {
+ if (bytes > 0)
+ test_fail("server served: %zd", bytes);
+ else
+ test_fail("server returned %zd", bytes);
+ }
+
+ synchronize_threads(); /* 3: chekpoint/restore the connection */
+ if (test_get_tcp_ao_counters(sk, &ao2))
+ test_error("test_get_tcp_ao_counters()");
+
+ synchronize_threads(); /* 4: terminate server + send more on client */
+ bytes = test_server_run(sk, quota, TEST_RETRANSMIT_SEC);
+ close(sk);
+ test_tcp_ao_counters_cmp("passive RST server", &ao1, &ao2, TEST_CNT_GOOD);
+
+ synchronize_threads(); /* 5: verified => closed */
+ close(sk);
+}
+
+static void *server_fn(void *arg)
+{
+ struct netstat *ns_before, *ns_after;
+ unsigned int port = test_server_port;
+
+ ns_before = netstat_read();
+
+ test_server_active_rst(port++);
+ test_server_passive_rst(port++);
+
+ ns_after = netstat_read();
+ netstats_check(ns_before, ns_after, "server");
+ netstat_free(ns_after);
+ netstat_free(ns_before);
+ synchronize_threads(); /* exit */
+
+ synchronize_threads(); /* don't race to exit() - client exits */
+ return NULL;
+}
+
+static int test_wait_fds(int sk[], size_t nr, bool is_writable[],
+ ssize_t wait_for, time_t sec)
+{
+ struct timeval tv = { .tv_sec = sec };
+ struct timeval *ptv = NULL;
+ fd_set left;
+ size_t i;
+ int ret;
+
+ FD_ZERO(&left);
+ for (i = 0; i < nr; i++) {
+ FD_SET(sk[i], &left);
+ if (is_writable)
+ is_writable[i] = false;
+ }
+
+ if (sec)
+ ptv = &tv;
+
+ do {
+ bool is_empty = true;
+ fd_set fds, efds;
+ int nfd = 0;
+
+ FD_ZERO(&fds);
+ FD_ZERO(&efds);
+ for (i = 0; i < nr; i++) {
+ if (!FD_ISSET(sk[i], &left))
+ continue;
+
+ if (sk[i] > nfd)
+ nfd = sk[i];
+
+ FD_SET(sk[i], &fds);
+ FD_SET(sk[i], &efds);
+ is_empty = false;
+ }
+ if (is_empty)
+ return -ENOENT;
+
+ errno = 0;
+ ret = select(nfd + 1, NULL, &fds, &efds, ptv);
+ if (ret < 0)
+ return -errno;
+ if (!ret)
+ return -ETIMEDOUT;
+ for (i = 0; i < nr; i++) {
+ if (FD_ISSET(sk[i], &fds)) {
+ if (is_writable)
+ is_writable[i] = true;
+ FD_CLR(sk[i], &left);
+ wait_for--;
+ continue;
+ }
+ if (FD_ISSET(sk[i], &efds)) {
+ FD_CLR(sk[i], &left);
+ wait_for--;
+ }
+ }
+ } while (wait_for > 0);
+
+ return 0;
+}
+
+static void test_client_active_rst(unsigned int port)
+{
+ /* one in queue, another accept()ed */
+ unsigned int wait_for = backlog + 2;
+ int i, sk[3], err;
+ bool is_writable[ARRAY_SIZE(sk)] = {false};
+ unsigned int last = ARRAY_SIZE(sk) - 1;
+
+ for (i = 0; i < ARRAY_SIZE(sk); i++) {
+ sk[i] = socket(test_family, SOCK_STREAM, IPPROTO_TCP);
+ if (sk[i] < 0)
+ test_error("socket()");
+ if (test_add_key(sk[i], DEFAULT_TEST_PASSWORD,
+ this_ip_dest, -1, 100, 100))
+ test_error("setsockopt(TCP_AO_ADD_KEY)");
+ }
+
+ synchronize_threads(); /* 1: MKT added */
+ for (i = 0; i < last; i++) {
+ err = _test_connect_socket(sk[i], this_ip_dest, port,
+ (i == 0) ? TEST_TIMEOUT_SEC : -1);
+
+ if (err < 0)
+ test_error("failed to connect()");
+ }
+
+ synchronize_threads(); /* 2: connection accept()ed, another queued */
+ err = test_wait_fds(sk, last, is_writable, wait_for, TEST_TIMEOUT_SEC);
+ if (err < 0)
+ test_error("test_wait_fds(): %d", err);
+
+ synchronize_threads(); /* 3: close listen socket */
+ if (test_client_verify(sk[0], 100, quota / 100, TEST_TIMEOUT_SEC))
+ test_fail("Failed to send data on connected socket");
+ else
+ test_ok("Verified established tcp connection");
+
+ synchronize_threads(); /* 4: finishing up */
+ err = _test_connect_socket(sk[last], this_ip_dest, port, -1);
+ if (err < 0)
+ test_error("failed to connect()");
+
+ synchronize_threads(); /* 5: closed active sk */
+ err = test_wait_fds(sk, ARRAY_SIZE(sk), NULL,
+ wait_for, TEST_TIMEOUT_SEC);
+ if (err < 0)
+ test_error("select(): %d", err);
+
+ for (i = 0; i < ARRAY_SIZE(sk); i++) {
+ socklen_t slen = sizeof(err);
+
+ if (getsockopt(sk[i], SOL_SOCKET, SO_ERROR, &err, &slen))
+ test_error("getsockopt()");
+ if (is_writable[i] && err != ECONNRESET) {
+ test_fail("sk[%d] = %d, err = %d, connection wasn't reset",
+ i, sk[i], err);
+ } else {
+ test_ok("sk[%d] = %d%s", i, sk[i],
+ is_writable[i] ? ", connection was reset" : "");
+ }
+ }
+ synchronize_threads(); /* 6: counters checks */
+}
+
+static void test_client_passive_rst(unsigned int port)
+{
+ struct tcp_ao_counters ao1, ao2;
+ struct tcp_ao_repair ao_img;
+ struct tcp_sock_state img;
+ sockaddr_af saddr;
+ int sk, err;
+ socklen_t slen = sizeof(err);
+
+ sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP);
+ if (sk < 0)
+ test_error("socket()");
+
+ if (test_add_key(sk, DEFAULT_TEST_PASSWORD, this_ip_dest, -1, 100, 100))
+ test_error("setsockopt(TCP_AO_ADD_KEY)");
+
+ synchronize_threads(); /* 1: MKT added => connect() */
+ if (test_connect_socket(sk, this_ip_dest, port) <= 0)
+ test_error("failed to connect()");
+
+ synchronize_threads(); /* 2: accepted => send data */
+ if (test_client_verify(sk, 100, quota / 100, TEST_TIMEOUT_SEC))
+ test_fail("Failed to send data on connected socket");
+ else
+ test_ok("Verified established tcp connection");
+
+ synchronize_threads(); /* 3: chekpoint/restore the connection */
+ test_enable_repair(sk);
+ test_sock_checkpoint(sk, &img, &saddr);
+ test_ao_checkpoint(sk, &ao_img);
+ test_kill_sk(sk);
+
+ img.out.seq += quota;
+
+ sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP);
+ if (sk < 0)
+ test_error("socket()");
+
+ test_enable_repair(sk);
+ test_sock_restore(sk, &img, &saddr, this_ip_dest, port);
+ if (test_add_repaired_key(sk, DEFAULT_TEST_PASSWORD, 0, this_ip_dest, -1, 100, 100))
+ test_error("setsockopt(TCP_AO_ADD_KEY)");
+ test_ao_restore(sk, &ao_img);
+
+ if (test_get_tcp_ao_counters(sk, &ao1))
+ test_error("test_get_tcp_ao_counters()");
+
+ test_disable_repair(sk);
+ test_sock_state_free(&img);
+
+ synchronize_threads(); /* 4: terminate server + send more on client */
+ if (test_client_verify(sk, 100, quota / 100, 2 * TEST_TIMEOUT_SEC))
+ test_ok("client connection broken post-seq-adjust");
+ else
+ test_fail("client connection still works post-seq-adjust");
+
+ test_wait_for_exception(sk, TEST_TIMEOUT_SEC);
+
+ if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &err, &slen))
+ test_error("getsockopt()");
+ if (err != ECONNRESET && err != EPIPE)
+ test_fail("client connection was not reset: %d", err);
+ else
+ test_ok("client connection was reset");
+
+ if (test_get_tcp_ao_counters(sk, &ao2))
+ test_error("test_get_tcp_ao_counters()");
+
+ synchronize_threads(); /* 5: verified => closed */
+ close(sk);
+ test_tcp_ao_counters_cmp("client passive RST", &ao1, &ao2, TEST_CNT_GOOD);
+}
+
+static void *client_fn(void *arg)
+{
+ struct netstat *ns_before, *ns_after;
+ unsigned int port = test_server_port;
+
+ ns_before = netstat_read();
+
+ test_client_active_rst(port++);
+ test_client_passive_rst(port++);
+
+ ns_after = netstat_read();
+ netstats_check(ns_before, ns_after, "client");
+ netstat_free(ns_after);
+ netstat_free(ns_before);
+
+ synchronize_threads(); /* exit */
+ return NULL;
+}
+
+int main(int argc, char *argv[])
+{
+ test_init(15, server_fn, client_fn);
+ return 0;
+}
diff --git a/tools/testing/selftests/net/tcp_ao/self-connect.c b/tools/testing/selftests/net/tcp_ao/self-connect.c
new file mode 100644
index 000000000000..e154d9e198a9
--- /dev/null
+++ b/tools/testing/selftests/net/tcp_ao/self-connect.c
@@ -0,0 +1,197 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Author: Dmitry Safonov <dima@arista.com> */
+#include <inttypes.h>
+#include "aolib.h"
+
+static union tcp_addr local_addr;
+
+static void __setup_lo_intf(const char *lo_intf,
+ const char *addr_str, uint8_t prefix)
+{
+ if (inet_pton(TEST_FAMILY, addr_str, &local_addr) != 1)
+ test_error("Can't convert local ip address");
+
+ if (ip_addr_add(lo_intf, TEST_FAMILY, local_addr, prefix))
+ test_error("Failed to add %s ip address", lo_intf);
+
+ if (link_set_up(lo_intf))
+ test_error("Failed to bring %s up", lo_intf);
+}
+
+static void setup_lo_intf(const char *lo_intf)
+{
+#ifdef IPV6_TEST
+ __setup_lo_intf(lo_intf, "::1", 128);
+#else
+ __setup_lo_intf(lo_intf, "127.0.0.1", 8);
+#endif
+}
+
+static void tcp_self_connect(const char *tst, unsigned int port,
+ bool different_keyids, bool check_restore)
+{
+ uint64_t before_challenge_ack, after_challenge_ack;
+ uint64_t before_syn_challenge, after_syn_challenge;
+ struct tcp_ao_counters before_ao, after_ao;
+ uint64_t before_aogood, after_aogood;
+ struct netstat *ns_before, *ns_after;
+ const size_t nr_packets = 20;
+ struct tcp_ao_repair ao_img;
+ struct tcp_sock_state img;
+ sockaddr_af addr;
+ int sk;
+
+ tcp_addr_to_sockaddr_in(&addr, &local_addr, htons(port));
+
+ sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP);
+ if (sk < 0)
+ test_error("socket()");
+
+ if (different_keyids) {
+ if (test_add_key(sk, DEFAULT_TEST_PASSWORD, local_addr, -1, 5, 7))
+ test_error("setsockopt(TCP_AO_ADD_KEY)");
+ if (test_add_key(sk, DEFAULT_TEST_PASSWORD, local_addr, -1, 7, 5))
+ test_error("setsockopt(TCP_AO_ADD_KEY)");
+ } else {
+ if (test_add_key(sk, DEFAULT_TEST_PASSWORD, local_addr, -1, 100, 100))
+ test_error("setsockopt(TCP_AO_ADD_KEY)");
+ }
+
+ if (bind(sk, (struct sockaddr *)&addr, sizeof(addr)) < 0)
+ test_error("bind()");
+
+ ns_before = netstat_read();
+ before_aogood = netstat_get(ns_before, "TCPAOGood", NULL);
+ before_challenge_ack = netstat_get(ns_before, "TCPChallengeACK", NULL);
+ before_syn_challenge = netstat_get(ns_before, "TCPSYNChallenge", NULL);
+ if (test_get_tcp_ao_counters(sk, &before_ao))
+ test_error("test_get_tcp_ao_counters()");
+
+ if (__test_connect_socket(sk, "lo", (struct sockaddr *)&addr,
+ sizeof(addr), TEST_TIMEOUT_SEC) < 0) {
+ ns_after = netstat_read();
+ netstat_print_diff(ns_before, ns_after);
+ test_error("failed to connect()");
+ }
+
+ if (test_client_verify(sk, 100, nr_packets, TEST_TIMEOUT_SEC)) {
+ test_fail("%s: tcp connection verify failed", tst);
+ close(sk);
+ return;
+ }
+
+ ns_after = netstat_read();
+ after_aogood = netstat_get(ns_after, "TCPAOGood", NULL);
+ after_challenge_ack = netstat_get(ns_after, "TCPChallengeACK", NULL);
+ after_syn_challenge = netstat_get(ns_after, "TCPSYNChallenge", NULL);
+ if (test_get_tcp_ao_counters(sk, &after_ao))
+ test_error("test_get_tcp_ao_counters()");
+ if (!check_restore) {
+ /* to debug: netstat_print_diff(ns_before, ns_after); */
+ netstat_free(ns_before);
+ }
+ netstat_free(ns_after);
+
+ if (after_aogood <= before_aogood) {
+ test_fail("%s: TCPAOGood counter mismatch: %zu <= %zu",
+ tst, after_aogood, before_aogood);
+ close(sk);
+ return;
+ }
+ if (after_challenge_ack <= before_challenge_ack ||
+ after_syn_challenge <= before_syn_challenge) {
+ /*
+ * It's also meant to test simultaneous open, so check
+ * these counters as well.
+ */
+ test_fail("%s: Didn't challenge SYN or ACK: %zu <= %zu OR %zu <= %zu",
+ tst, after_challenge_ack, before_challenge_ack,
+ after_syn_challenge, before_syn_challenge);
+ close(sk);
+ return;
+ }
+
+ if (test_tcp_ao_counters_cmp(tst, &before_ao, &after_ao, TEST_CNT_GOOD)) {
+ close(sk);
+ return;
+ }
+
+ if (!check_restore) {
+ test_ok("%s: connect TCPAOGood %" PRIu64 " => %" PRIu64,
+ tst, before_aogood, after_aogood);
+ close(sk);
+ return;
+ }
+
+ test_enable_repair(sk);
+ test_sock_checkpoint(sk, &img, &addr);
+#ifdef IPV6_TEST
+ addr.sin6_port = htons(port + 1);
+#else
+ addr.sin_port = htons(port + 1);
+#endif
+ test_ao_checkpoint(sk, &ao_img);
+ test_kill_sk(sk);
+
+ sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP);
+ if (sk < 0)
+ test_error("socket()");
+
+ test_enable_repair(sk);
+ __test_sock_restore(sk, "lo", &img, &addr, &addr, sizeof(addr));
+ if (different_keyids) {
+ if (test_add_repaired_key(sk, DEFAULT_TEST_PASSWORD, 0,
+ local_addr, -1, 7, 5))
+ test_error("setsockopt(TCP_AO_ADD_KEY)");
+ if (test_add_repaired_key(sk, DEFAULT_TEST_PASSWORD, 0,
+ local_addr, -1, 5, 7))
+ test_error("setsockopt(TCP_AO_ADD_KEY)");
+ } else {
+ if (test_add_repaired_key(sk, DEFAULT_TEST_PASSWORD, 0,
+ local_addr, -1, 100, 100))
+ test_error("setsockopt(TCP_AO_ADD_KEY)");
+ }
+ test_ao_restore(sk, &ao_img);
+ test_disable_repair(sk);
+ test_sock_state_free(&img);
+ if (test_client_verify(sk, 100, nr_packets, TEST_TIMEOUT_SEC)) {
+ test_fail("%s: tcp connection verify failed", tst);
+ close(sk);
+ return;
+ }
+ ns_after = netstat_read();
+ after_aogood = netstat_get(ns_after, "TCPAOGood", NULL);
+ /* to debug: netstat_print_diff(ns_before, ns_after); */
+ netstat_free(ns_before);
+ netstat_free(ns_after);
+ close(sk);
+ if (after_aogood <= before_aogood) {
+ test_fail("%s: TCPAOGood counter mismatch: %zu <= %zu",
+ tst, after_aogood, before_aogood);
+ return;
+ }
+ test_ok("%s: connect TCPAOGood %" PRIu64 " => %" PRIu64,
+ tst, before_aogood, after_aogood);
+}
+
+static void *client_fn(void *arg)
+{
+ unsigned int port = test_server_port;
+
+ setup_lo_intf("lo");
+
+ tcp_self_connect("self-connect(same keyids)", port++, false, false);
+ tcp_self_connect("self-connect(different keyids)", port++, true, false);
+ tcp_self_connect("self-connect(restore)", port, false, true);
+ port += 2;
+ tcp_self_connect("self-connect(restore, different keyids)", port, true, true);
+ port += 2;
+
+ return NULL;
+}
+
+int main(int argc, char *argv[])
+{
+ test_init(4, client_fn, NULL);
+ return 0;
+}
diff --git a/tools/testing/selftests/net/tcp_ao/seq-ext.c b/tools/testing/selftests/net/tcp_ao/seq-ext.c
new file mode 100644
index 000000000000..ad4e77d6823e
--- /dev/null
+++ b/tools/testing/selftests/net/tcp_ao/seq-ext.c
@@ -0,0 +1,245 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Check that after SEQ number wrap-around:
+ * 1. SEQ-extension has upper bytes set
+ * 2. TCP conneciton is alive and no TCPAOBad segments
+ * In order to test (2), the test doesn't just adjust seq number for a queue
+ * on a connected socket, but migrates it to another sk+port number, so
+ * that there won't be any delayed packets that will fail to verify
+ * with the new SEQ numbers.
+ */
+#include <inttypes.h>
+#include "aolib.h"
+
+const unsigned int nr_packets = 1000;
+const unsigned int msg_len = 1000;
+const unsigned int quota = nr_packets * msg_len;
+unsigned int client_new_port;
+
+/* Move them closer to roll-over */
+static void test_adjust_seqs(struct tcp_sock_state *img,
+ struct tcp_ao_repair *ao_img,
+ bool server)
+{
+ uint32_t new_seq1, new_seq2;
+
+ /* make them roll-over during quota, but on different segments */
+ if (server) {
+ new_seq1 = ((uint32_t)-1) - msg_len;
+ new_seq2 = ((uint32_t)-1) - (quota - 2 * msg_len);
+ } else {
+ new_seq1 = ((uint32_t)-1) - (quota - 2 * msg_len);
+ new_seq2 = ((uint32_t)-1) - msg_len;
+ }
+
+ img->in.seq = new_seq1;
+ img->trw.snd_wl1 = img->in.seq - msg_len;
+ img->out.seq = new_seq2;
+ img->trw.rcv_wup = img->in.seq;
+}
+
+static int test_sk_restore(struct tcp_sock_state *img,
+ struct tcp_ao_repair *ao_img, sockaddr_af *saddr,
+ const union tcp_addr daddr, unsigned int dport,
+ struct tcp_ao_counters *cnt)
+{
+ int sk;
+
+ sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP);
+ if (sk < 0)
+ test_error("socket()");
+
+ test_enable_repair(sk);
+ test_sock_restore(sk, img, saddr, daddr, dport);
+ if (test_add_repaired_key(sk, DEFAULT_TEST_PASSWORD, 0, daddr, -1, 100, 100))
+ test_error("setsockopt(TCP_AO_ADD_KEY)");
+ test_ao_restore(sk, ao_img);
+
+ if (test_get_tcp_ao_counters(sk, cnt))
+ test_error("test_get_tcp_ao_counters()");
+
+ test_disable_repair(sk);
+ test_sock_state_free(img);
+ return sk;
+}
+
+static void *server_fn(void *arg)
+{
+ uint64_t before_good, after_good, after_bad;
+ struct tcp_ao_counters ao1, ao2;
+ struct tcp_sock_state img;
+ struct tcp_ao_repair ao_img;
+ sockaddr_af saddr;
+ ssize_t bytes;
+ int sk, lsk;
+
+ lsk = test_listen_socket(this_ip_addr, test_server_port, 1);
+
+ if (test_add_key(lsk, DEFAULT_TEST_PASSWORD, this_ip_dest, -1, 100, 100))
+ test_error("setsockopt(TCP_AO_ADD_KEY)");
+
+ synchronize_threads(); /* 1: MKT added => connect() */
+
+ if (test_wait_fd(lsk, TEST_TIMEOUT_SEC, 0))
+ test_error("test_wait_fd()");
+
+ sk = accept(lsk, NULL, NULL);
+ if (sk < 0)
+ test_error("accept()");
+
+ synchronize_threads(); /* 2: accepted => send data */
+ close(lsk);
+
+ bytes = test_server_run(sk, quota, TEST_TIMEOUT_SEC);
+ if (bytes != quota) {
+ if (bytes > 0)
+ test_fail("server served: %zd", bytes);
+ else
+ test_fail("server returned: %zd", bytes);
+ goto out;
+ }
+
+ before_good = netstat_get_one("TCPAOGood", NULL);
+
+ synchronize_threads(); /* 3: restore the connection on another port */
+
+ test_enable_repair(sk);
+ test_sock_checkpoint(sk, &img, &saddr);
+ test_ao_checkpoint(sk, &ao_img);
+ test_kill_sk(sk);
+#ifdef IPV6_TEST
+ saddr.sin6_port = htons(ntohs(saddr.sin6_port) + 1);
+#else
+ saddr.sin_port = htons(ntohs(saddr.sin_port) + 1);
+#endif
+ test_adjust_seqs(&img, &ao_img, true);
+ synchronize_threads(); /* 4: dump finished */
+ sk = test_sk_restore(&img, &ao_img, &saddr, this_ip_dest,
+ client_new_port, &ao1);
+
+ synchronize_threads(); /* 5: verify counters during SEQ-number rollover */
+ bytes = test_server_run(sk, quota, TEST_TIMEOUT_SEC);
+ if (bytes != quota) {
+ if (bytes > 0)
+ test_fail("server served: %zd", bytes);
+ else
+ test_fail("server returned: %zd", bytes);
+ } else {
+ test_ok("server alive");
+ }
+
+ if (test_get_tcp_ao_counters(sk, &ao2))
+ test_error("test_get_tcp_ao_counters()");
+ after_good = netstat_get_one("TCPAOGood", NULL);
+
+ test_tcp_ao_counters_cmp(NULL, &ao1, &ao2, TEST_CNT_GOOD);
+
+ if (after_good <= before_good) {
+ test_fail("TCPAOGood counter did not increase: %zu <= %zu",
+ after_good, before_good);
+ } else {
+ test_ok("TCPAOGood counter increased %zu => %zu",
+ before_good, after_good);
+ }
+ after_bad = netstat_get_one("TCPAOBad", NULL);
+ if (after_bad)
+ test_fail("TCPAOBad counter is non-zero: %zu", after_bad);
+ else
+ test_ok("TCPAOBad counter didn't increase");
+ test_enable_repair(sk);
+ test_ao_checkpoint(sk, &ao_img);
+ if (ao_img.snd_sne && ao_img.rcv_sne) {
+ test_ok("SEQ extension incremented: %u/%u",
+ ao_img.snd_sne, ao_img.rcv_sne);
+ } else {
+ test_fail("SEQ extension was not incremented: %u/%u",
+ ao_img.snd_sne, ao_img.rcv_sne);
+ }
+
+ synchronize_threads(); /* 6: verified => closed */
+out:
+ close(sk);
+ return NULL;
+}
+
+static void *client_fn(void *arg)
+{
+ uint64_t before_good, after_good, after_bad;
+ struct tcp_ao_counters ao1, ao2;
+ struct tcp_sock_state img;
+ struct tcp_ao_repair ao_img;
+ sockaddr_af saddr;
+ int sk;
+
+ sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP);
+ if (sk < 0)
+ test_error("socket()");
+
+ if (test_add_key(sk, DEFAULT_TEST_PASSWORD, this_ip_dest, -1, 100, 100))
+ test_error("setsockopt(TCP_AO_ADD_KEY)");
+
+ synchronize_threads(); /* 1: MKT added => connect() */
+ if (test_connect_socket(sk, this_ip_dest, test_server_port) <= 0)
+ test_error("failed to connect()");
+
+ synchronize_threads(); /* 2: accepted => send data */
+ if (test_client_verify(sk, msg_len, nr_packets, TEST_TIMEOUT_SEC)) {
+ test_fail("pre-migrate verify failed");
+ return NULL;
+ }
+
+ before_good = netstat_get_one("TCPAOGood", NULL);
+
+ synchronize_threads(); /* 3: restore the connection on another port */
+ test_enable_repair(sk);
+ test_sock_checkpoint(sk, &img, &saddr);
+ test_ao_checkpoint(sk, &ao_img);
+ test_kill_sk(sk);
+#ifdef IPV6_TEST
+ client_new_port = ntohs(saddr.sin6_port) + 1;
+ saddr.sin6_port = htons(ntohs(saddr.sin6_port) + 1);
+#else
+ client_new_port = ntohs(saddr.sin_port) + 1;
+ saddr.sin_port = htons(ntohs(saddr.sin_port) + 1);
+#endif
+ test_adjust_seqs(&img, &ao_img, false);
+ synchronize_threads(); /* 4: dump finished */
+ sk = test_sk_restore(&img, &ao_img, &saddr, this_ip_dest,
+ test_server_port + 1, &ao1);
+
+ synchronize_threads(); /* 5: verify counters during SEQ-number rollover */
+ if (test_client_verify(sk, msg_len, nr_packets, TEST_TIMEOUT_SEC))
+ test_fail("post-migrate verify failed");
+ else
+ test_ok("post-migrate connection alive");
+
+ if (test_get_tcp_ao_counters(sk, &ao2))
+ test_error("test_get_tcp_ao_counters()");
+ after_good = netstat_get_one("TCPAOGood", NULL);
+
+ test_tcp_ao_counters_cmp(NULL, &ao1, &ao2, TEST_CNT_GOOD);
+
+ if (after_good <= before_good) {
+ test_fail("TCPAOGood counter did not increase: %zu <= %zu",
+ after_good, before_good);
+ } else {
+ test_ok("TCPAOGood counter increased %zu => %zu",
+ before_good, after_good);
+ }
+ after_bad = netstat_get_one("TCPAOBad", NULL);
+ if (after_bad)
+ test_fail("TCPAOBad counter is non-zero: %zu", after_bad);
+ else
+ test_ok("TCPAOBad counter didn't increase");
+
+ synchronize_threads(); /* 6: verified => closed */
+ close(sk);
+
+ synchronize_threads(); /* don't race to exit: let server exit() */
+ return NULL;
+}
+
+int main(int argc, char *argv[])
+{
+ test_init(7, server_fn, client_fn);
+ return 0;
+}
diff --git a/tools/testing/selftests/net/tcp_ao/setsockopt-closed.c b/tools/testing/selftests/net/tcp_ao/setsockopt-closed.c
new file mode 100644
index 000000000000..7e4601b3f6a3
--- /dev/null
+++ b/tools/testing/selftests/net/tcp_ao/setsockopt-closed.c
@@ -0,0 +1,835 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Author: Dmitry Safonov <dima@arista.com> */
+#include <inttypes.h>
+#include "../../../../include/linux/kernel.h"
+#include "aolib.h"
+
+static union tcp_addr tcp_md5_client;
+
+static int test_port = 7788;
+static void make_listen(int sk)
+{
+ sockaddr_af addr;
+
+ tcp_addr_to_sockaddr_in(&addr, &this_ip_addr, htons(test_port++));
+ if (bind(sk, (struct sockaddr *)&addr, sizeof(addr)) < 0)
+ test_error("bind()");
+ if (listen(sk, 1))
+ test_error("listen()");
+}
+
+static void test_vefify_ao_info(int sk, struct tcp_ao_info_opt *info,
+ const char *tst)
+{
+ struct tcp_ao_info_opt tmp;
+ socklen_t len = sizeof(tmp);
+
+ if (getsockopt(sk, IPPROTO_TCP, TCP_AO_INFO, &tmp, &len))
+ test_error("getsockopt(TCP_AO_INFO) failed");
+
+#define __cmp_ao(member) \
+do { \
+ if (info->member != tmp.member) { \
+ test_fail("%s: getsockopt(): " __stringify(member) " %zu != %zu", \
+ tst, (size_t)info->member, (size_t)tmp.member); \
+ return; \
+ } \
+} while(0)
+ if (info->set_current)
+ __cmp_ao(current_key);
+ if (info->set_rnext)
+ __cmp_ao(rnext);
+ if (info->set_counters) {
+ __cmp_ao(pkt_good);
+ __cmp_ao(pkt_bad);
+ __cmp_ao(pkt_key_not_found);
+ __cmp_ao(pkt_ao_required);
+ __cmp_ao(pkt_dropped_icmp);
+ }
+ __cmp_ao(ao_required);
+ __cmp_ao(accept_icmps);
+
+ test_ok("AO info get: %s", tst);
+#undef __cmp_ao
+}
+
+static void __setsockopt_checked(int sk, int optname, bool get,
+ void *optval, socklen_t *len,
+ int err, const char *tst, const char *tst2)
+{
+ int ret;
+
+ if (!tst)
+ tst = "";
+ if (!tst2)
+ tst2 = "";
+
+ errno = 0;
+ if (get)
+ ret = getsockopt(sk, IPPROTO_TCP, optname, optval, len);
+ else
+ ret = setsockopt(sk, IPPROTO_TCP, optname, optval, *len);
+ if (ret == -1) {
+ if (errno == err)
+ test_ok("%s%s", tst ?: "", tst2 ?: "");
+ else
+ test_fail("%s%s: %setsockopt() failed",
+ tst, tst2, get ? "g" : "s");
+ close(sk);
+ return;
+ }
+
+ if (err) {
+ test_fail("%s%s: %setsockopt() was expected to fail with %d",
+ tst, tst2, get ? "g" : "s", err);
+ } else {
+ test_ok("%s%s", tst ?: "", tst2 ?: "");
+ if (optname == TCP_AO_ADD_KEY) {
+ test_verify_socket_key(sk, optval);
+ } else if (optname == TCP_AO_INFO && !get) {
+ test_vefify_ao_info(sk, optval, tst2);
+ } else if (optname == TCP_AO_GET_KEYS) {
+ if (*len != sizeof(struct tcp_ao_getsockopt))
+ test_fail("%s%s: get keys returned wrong tcp_ao_getsockopt size",
+ tst, tst2);
+ }
+ }
+ close(sk);
+}
+
+static void setsockopt_checked(int sk, int optname, void *optval,
+ int err, const char *tst)
+{
+ const char *cmd = NULL;
+ socklen_t len;
+
+ switch (optname) {
+ case TCP_AO_ADD_KEY:
+ cmd = "key add: ";
+ len = sizeof(struct tcp_ao_add);
+ break;
+ case TCP_AO_DEL_KEY:
+ cmd = "key del: ";
+ len = sizeof(struct tcp_ao_del);
+ break;
+ case TCP_AO_INFO:
+ cmd = "AO info set: ";
+ len = sizeof(struct tcp_ao_info_opt);
+ break;
+ default:
+ break;
+ };
+
+ __setsockopt_checked(sk, optname, false, optval, &len, err, cmd, tst);
+}
+
+static int prepare_defs(int cmd, void *optval)
+{
+ int sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP);
+
+ if (sk < 0)
+ test_error("socket()");
+
+ switch (cmd) {
+ case TCP_AO_ADD_KEY: {
+ struct tcp_ao_add *add = optval;
+
+ if (test_prepare_def_key(add, DEFAULT_TEST_PASSWORD, 0, this_ip_dest,
+ -1, 0, 100, 100))
+ test_error("prepare default tcp_ao_add");
+ break;
+ }
+ case TCP_AO_DEL_KEY: {
+ struct tcp_ao_del *del = optval;
+
+ if (test_add_key(sk, DEFAULT_TEST_PASSWORD, this_ip_dest,
+ DEFAULT_TEST_PREFIX, 100, 100))
+ test_error("add default key");
+ memset(del, 0, sizeof(struct tcp_ao_del));
+ del->sndid = 100;
+ del->rcvid = 100;
+ del->prefix = DEFAULT_TEST_PREFIX;
+ tcp_addr_to_sockaddr_in(&del->addr, &this_ip_dest, 0);
+ break;
+ }
+ case TCP_AO_INFO: {
+ struct tcp_ao_info_opt *info = optval;
+
+ if (test_add_key(sk, DEFAULT_TEST_PASSWORD, this_ip_dest,
+ DEFAULT_TEST_PREFIX, 100, 100))
+ test_error("add default key");
+ memset(info, 0, sizeof(struct tcp_ao_info_opt));
+ break;
+ }
+ case TCP_AO_GET_KEYS: {
+ struct tcp_ao_getsockopt *get = optval;
+
+ if (test_add_key(sk, DEFAULT_TEST_PASSWORD, this_ip_dest,
+ DEFAULT_TEST_PREFIX, 100, 100))
+ test_error("add default key");
+ memset(get, 0, sizeof(struct tcp_ao_getsockopt));
+ get->nkeys = 1;
+ get->get_all = 1;
+ break;
+ }
+ default:
+ test_error("unknown cmd");
+ }
+
+ return sk;
+}
+
+static void test_extend(int cmd, bool get, const char *tst, socklen_t under_size)
+{
+ struct {
+ union {
+ struct tcp_ao_add add;
+ struct tcp_ao_del del;
+ struct tcp_ao_getsockopt get;
+ struct tcp_ao_info_opt info;
+ };
+ char *extend[100];
+ } tmp_opt;
+ socklen_t extended_size = sizeof(tmp_opt);
+ int sk;
+
+ memset(&tmp_opt, 0, sizeof(tmp_opt));
+ sk = prepare_defs(cmd, &tmp_opt);
+ __setsockopt_checked(sk, cmd, get, &tmp_opt, &under_size,
+ EINVAL, tst, ": minimum size");
+
+ memset(&tmp_opt, 0, sizeof(tmp_opt));
+ sk = prepare_defs(cmd, &tmp_opt);
+ __setsockopt_checked(sk, cmd, get, &tmp_opt, &extended_size,
+ 0, tst, ": extended size");
+
+ memset(&tmp_opt, 0, sizeof(tmp_opt));
+ sk = prepare_defs(cmd, &tmp_opt);
+ __setsockopt_checked(sk, cmd, get, NULL, &extended_size,
+ EFAULT, tst, ": null optval");
+
+ if (get) {
+ memset(&tmp_opt, 0, sizeof(tmp_opt));
+ sk = prepare_defs(cmd, &tmp_opt);
+ __setsockopt_checked(sk, cmd, get, &tmp_opt, NULL,
+ EFAULT, tst, ": null optlen");
+ }
+}
+
+static void extend_tests(void)
+{
+ test_extend(TCP_AO_ADD_KEY, false, "AO add",
+ offsetof(struct tcp_ao_add, key));
+ test_extend(TCP_AO_DEL_KEY, false, "AO del",
+ offsetof(struct tcp_ao_del, keyflags));
+ test_extend(TCP_AO_INFO, false, "AO set info",
+ offsetof(struct tcp_ao_info_opt, pkt_dropped_icmp));
+ test_extend(TCP_AO_INFO, true, "AO get info", -1);
+ test_extend(TCP_AO_GET_KEYS, true, "AO get keys", -1);
+}
+
+static void test_optmem_limit(void)
+{
+ size_t i, keys_limit, current_optmem = test_get_optmem();
+ struct tcp_ao_add ao;
+ union tcp_addr net = {};
+ int sk;
+
+ if (inet_pton(TEST_FAMILY, TEST_NETWORK, &net) != 1)
+ test_error("Can't convert ip address %s", TEST_NETWORK);
+
+ sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
+ keys_limit = current_optmem / KERNEL_TCP_AO_KEY_SZ_ROUND_UP;
+ for (i = 0;; i++) {
+ union tcp_addr key_peer;
+ int err;
+
+ key_peer = gen_tcp_addr(net, i + 1);
+ tcp_addr_to_sockaddr_in(&ao.addr, &key_peer, 0);
+ err = setsockopt(sk, IPPROTO_TCP, TCP_AO_ADD_KEY,
+ &ao, sizeof(ao));
+ if (!err) {
+ /*
+ * TCP_AO_ADD_KEY should be the same order as the real
+ * sizeof(struct tcp_ao_key) in kernel.
+ */
+ if (i <= keys_limit * 10)
+ continue;
+ test_fail("optmem limit test failed: added %zu key", i);
+ break;
+ }
+ if (i < keys_limit) {
+ test_fail("optmem limit test failed: couldn't add %zu key", i);
+ break;
+ }
+ test_ok("optmem limit was hit on adding %zu key", i);
+ break;
+ }
+ close(sk);
+}
+
+static void test_einval_add_key(void)
+{
+ struct tcp_ao_add ao;
+ int sk;
+
+ sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
+ ao.keylen = TCP_AO_MAXKEYLEN + 1;
+ setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, EINVAL, "too big keylen");
+
+ sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
+ ao.reserved = 1;
+ setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, EINVAL, "using reserved padding");
+
+ sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
+ ao.reserved2 = 1;
+ setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, EINVAL, "using reserved2 padding");
+
+ /* tcp_ao_verify_ipv{4,6}() checks */
+ sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
+ ao.addr.ss_family = AF_UNIX;
+ memcpy(&ao.addr, &SOCKADDR_ANY, sizeof(SOCKADDR_ANY));
+ setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, EINVAL, "wrong address family");
+
+ sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
+ tcp_addr_to_sockaddr_in(&ao.addr, &this_ip_dest, 1234);
+ setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, EINVAL, "port (unsupported)");
+
+ sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
+ ao.prefix = 0;
+ setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, EINVAL, "no prefix, addr");
+
+ sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
+ ao.prefix = 0;
+ memcpy(&ao.addr, &SOCKADDR_ANY, sizeof(SOCKADDR_ANY));
+ setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, 0, "no prefix, any addr");
+
+ sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
+ ao.prefix = 32;
+ memcpy(&ao.addr, &SOCKADDR_ANY, sizeof(SOCKADDR_ANY));
+ setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, EINVAL, "prefix, any addr");
+
+ sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
+ ao.prefix = 129;
+ setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, EINVAL, "too big prefix");
+
+ sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
+ ao.prefix = 2;
+ setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, EINVAL, "too short prefix");
+
+ sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
+ ao.keyflags = (uint8_t)(-1);
+ setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, EINVAL, "bad key flags");
+
+ sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
+ make_listen(sk);
+ ao.set_current = 1;
+ setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, EINVAL, "add current key on a listen socket");
+
+ sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
+ make_listen(sk);
+ ao.set_rnext = 1;
+ setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, EINVAL, "add rnext key on a listen socket");
+
+ sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
+ make_listen(sk);
+ ao.set_current = 1;
+ ao.set_rnext = 1;
+ setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, EINVAL, "add current+rnext key on a listen socket");
+
+ sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
+ ao.set_current = 1;
+ setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, 0, "add key and set as current");
+
+ sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
+ ao.set_rnext = 1;
+ setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, 0, "add key and set as rnext");
+
+ sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
+ ao.set_current = 1;
+ ao.set_rnext = 1;
+ setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, 0, "add key and set as current+rnext");
+
+ sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
+ ao.ifindex = 42;
+ setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, EINVAL,
+ "ifindex without TCP_AO_KEYF_IFNINDEX");
+
+ sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
+ ao.keyflags |= TCP_AO_KEYF_IFINDEX;
+ ao.ifindex = 42;
+ setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, EINVAL, "non-existent VRF");
+ /*
+ * tcp_md5_do_lookup{,_any_l3index}() are checked in unsigned-md5
+ * see client_vrf_tests().
+ */
+
+ test_optmem_limit();
+
+ /* tcp_ao_parse_crypto() */
+ sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
+ ao.maclen = 100;
+ setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, EMSGSIZE, "maclen bigger than TCP hdr");
+
+ sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
+ strcpy(ao.alg_name, "imaginary hash algo");
+ setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, ENOENT, "bad algo");
+}
+
+static void test_einval_del_key(void)
+{
+ struct tcp_ao_del del;
+ int sk;
+
+ sk = prepare_defs(TCP_AO_DEL_KEY, &del);
+ del.reserved = 1;
+ setsockopt_checked(sk, TCP_AO_DEL_KEY, &del, EINVAL, "using reserved padding");
+
+ sk = prepare_defs(TCP_AO_DEL_KEY, &del);
+ del.reserved2 = 1;
+ setsockopt_checked(sk, TCP_AO_DEL_KEY, &del, EINVAL, "using reserved2 padding");
+
+ sk = prepare_defs(TCP_AO_DEL_KEY, &del);
+ make_listen(sk);
+ if (test_add_key(sk, DEFAULT_TEST_PASSWORD, this_ip_dest, DEFAULT_TEST_PREFIX, 0, 0))
+ test_error("add key");
+ del.set_current = 1;
+ setsockopt_checked(sk, TCP_AO_DEL_KEY, &del, EINVAL, "del and set current key on a listen socket");
+
+ sk = prepare_defs(TCP_AO_DEL_KEY, &del);
+ make_listen(sk);
+ if (test_add_key(sk, DEFAULT_TEST_PASSWORD, this_ip_dest, DEFAULT_TEST_PREFIX, 0, 0))
+ test_error("add key");
+ del.set_rnext = 1;
+ setsockopt_checked(sk, TCP_AO_DEL_KEY, &del, EINVAL, "del and set rnext key on a listen socket");
+
+ sk = prepare_defs(TCP_AO_DEL_KEY, &del);
+ make_listen(sk);
+ if (test_add_key(sk, DEFAULT_TEST_PASSWORD, this_ip_dest, DEFAULT_TEST_PREFIX, 0, 0))
+ test_error("add key");
+ del.set_current = 1;
+ del.set_rnext = 1;
+ setsockopt_checked(sk, TCP_AO_DEL_KEY, &del, EINVAL, "del and set current+rnext key on a listen socket");
+
+ sk = prepare_defs(TCP_AO_DEL_KEY, &del);
+ del.keyflags = (uint8_t)(-1);
+ setsockopt_checked(sk, TCP_AO_DEL_KEY, &del, EINVAL, "bad key flags");
+
+ sk = prepare_defs(TCP_AO_DEL_KEY, &del);
+ del.ifindex = 42;
+ setsockopt_checked(sk, TCP_AO_DEL_KEY, &del, EINVAL,
+ "ifindex without TCP_AO_KEYF_IFNINDEX");
+
+ sk = prepare_defs(TCP_AO_DEL_KEY, &del);
+ del.keyflags |= TCP_AO_KEYF_IFINDEX;
+ del.ifindex = 42;
+ setsockopt_checked(sk, TCP_AO_DEL_KEY, &del, ENOENT, "non-existent VRF");
+
+ sk = prepare_defs(TCP_AO_DEL_KEY, &del);
+ del.set_current = 1;
+ setsockopt_checked(sk, TCP_AO_DEL_KEY, &del, ENOENT, "set non-exising current key");
+
+ sk = prepare_defs(TCP_AO_DEL_KEY, &del);
+ del.set_rnext = 1;
+ setsockopt_checked(sk, TCP_AO_DEL_KEY, &del, ENOENT, "set non-existing rnext key");
+
+ sk = prepare_defs(TCP_AO_DEL_KEY, &del);
+ del.set_current = 1;
+ del.set_rnext = 1;
+ setsockopt_checked(sk, TCP_AO_DEL_KEY, &del, ENOENT, "set non-existing current+rnext key");
+
+ sk = prepare_defs(TCP_AO_DEL_KEY, &del);
+ if (test_add_key(sk, DEFAULT_TEST_PASSWORD, this_ip_dest, DEFAULT_TEST_PREFIX, 0, 0))
+ test_error("add key");
+ del.set_current = 1;
+ setsockopt_checked(sk, TCP_AO_DEL_KEY, &del, 0, "set current key");
+
+ sk = prepare_defs(TCP_AO_DEL_KEY, &del);
+ if (test_add_key(sk, DEFAULT_TEST_PASSWORD, this_ip_dest, DEFAULT_TEST_PREFIX, 0, 0))
+ test_error("add key");
+ del.set_rnext = 1;
+ setsockopt_checked(sk, TCP_AO_DEL_KEY, &del, 0, "set rnext key");
+
+ sk = prepare_defs(TCP_AO_DEL_KEY, &del);
+ if (test_add_key(sk, DEFAULT_TEST_PASSWORD, this_ip_dest, DEFAULT_TEST_PREFIX, 0, 0))
+ test_error("add key");
+ del.set_current = 1;
+ del.set_rnext = 1;
+ setsockopt_checked(sk, TCP_AO_DEL_KEY, &del, 0, "set current+rnext key");
+
+ sk = prepare_defs(TCP_AO_DEL_KEY, &del);
+ del.set_current = 1;
+ del.current_key = 100;
+ setsockopt_checked(sk, TCP_AO_DEL_KEY, &del, ENOENT, "set as current key to be removed");
+
+ sk = prepare_defs(TCP_AO_DEL_KEY, &del);
+ del.set_rnext = 1;
+ del.rnext = 100;
+ setsockopt_checked(sk, TCP_AO_DEL_KEY, &del, ENOENT, "set as rnext key to be removed");
+
+ sk = prepare_defs(TCP_AO_DEL_KEY, &del);
+ del.set_current = 1;
+ del.current_key = 100;
+ del.set_rnext = 1;
+ del.rnext = 100;
+ setsockopt_checked(sk, TCP_AO_DEL_KEY, &del, ENOENT, "set as current+rnext key to be removed");
+
+ sk = prepare_defs(TCP_AO_DEL_KEY, &del);
+ del.del_async = 1;
+ setsockopt_checked(sk, TCP_AO_DEL_KEY, &del, EINVAL, "async on non-listen");
+
+ sk = prepare_defs(TCP_AO_DEL_KEY, &del);
+ del.sndid = 101;
+ setsockopt_checked(sk, TCP_AO_DEL_KEY, &del, ENOENT, "non-existing sndid");
+
+ sk = prepare_defs(TCP_AO_DEL_KEY, &del);
+ del.rcvid = 101;
+ setsockopt_checked(sk, TCP_AO_DEL_KEY, &del, ENOENT, "non-existing rcvid");
+
+ sk = prepare_defs(TCP_AO_DEL_KEY, &del);
+ tcp_addr_to_sockaddr_in(&del.addr, &this_ip_addr, 0);
+ setsockopt_checked(sk, TCP_AO_DEL_KEY, &del, ENOENT, "incorrect addr");
+
+ sk = prepare_defs(TCP_AO_DEL_KEY, &del);
+ setsockopt_checked(sk, TCP_AO_DEL_KEY, &del, 0, "correct key delete");
+}
+
+static void test_einval_ao_info(void)
+{
+ struct tcp_ao_info_opt info;
+ int sk;
+
+ sk = prepare_defs(TCP_AO_INFO, &info);
+ make_listen(sk);
+ info.set_current = 1;
+ setsockopt_checked(sk, TCP_AO_INFO, &info, EINVAL, "set current key on a listen socket");
+
+ sk = prepare_defs(TCP_AO_INFO, &info);
+ make_listen(sk);
+ info.set_rnext = 1;
+ setsockopt_checked(sk, TCP_AO_INFO, &info, EINVAL, "set rnext key on a listen socket");
+
+ sk = prepare_defs(TCP_AO_INFO, &info);
+ make_listen(sk);
+ info.set_current = 1;
+ info.set_rnext = 1;
+ setsockopt_checked(sk, TCP_AO_INFO, &info, EINVAL, "set current+rnext key on a listen socket");
+
+ sk = prepare_defs(TCP_AO_INFO, &info);
+ info.reserved = 1;
+ setsockopt_checked(sk, TCP_AO_INFO, &info, EINVAL, "using reserved padding");
+
+ sk = prepare_defs(TCP_AO_INFO, &info);
+ info.reserved2 = 1;
+ setsockopt_checked(sk, TCP_AO_INFO, &info, EINVAL, "using reserved2 padding");
+
+ sk = prepare_defs(TCP_AO_INFO, &info);
+ info.accept_icmps = 1;
+ setsockopt_checked(sk, TCP_AO_INFO, &info, 0, "accept_icmps");
+
+ sk = prepare_defs(TCP_AO_INFO, &info);
+ info.ao_required = 1;
+ setsockopt_checked(sk, TCP_AO_INFO, &info, 0, "ao required");
+
+ if (!should_skip_test("ao required with MD5 key", KCONFIG_TCP_MD5)) {
+ sk = prepare_defs(TCP_AO_INFO, &info);
+ info.ao_required = 1;
+ if (test_set_md5(sk, tcp_md5_client, TEST_PREFIX, -1,
+ "long long secret")) {
+ test_error("setsockopt(TCP_MD5SIG_EXT)");
+ close(sk);
+ } else {
+ setsockopt_checked(sk, TCP_AO_INFO, &info, EKEYREJECTED,
+ "ao required with MD5 key");
+ }
+ }
+
+ sk = prepare_defs(TCP_AO_INFO, &info);
+ info.set_current = 1;
+ setsockopt_checked(sk, TCP_AO_INFO, &info, ENOENT, "set non-existing current key");
+
+ sk = prepare_defs(TCP_AO_INFO, &info);
+ info.set_rnext = 1;
+ setsockopt_checked(sk, TCP_AO_INFO, &info, ENOENT, "set non-existing rnext key");
+
+ sk = prepare_defs(TCP_AO_INFO, &info);
+ info.set_current = 1;
+ info.set_rnext = 1;
+ setsockopt_checked(sk, TCP_AO_INFO, &info, ENOENT, "set non-existing current+rnext key");
+
+ sk = prepare_defs(TCP_AO_INFO, &info);
+ info.set_current = 1;
+ info.current_key = 100;
+ setsockopt_checked(sk, TCP_AO_INFO, &info, 0, "set current key");
+
+ sk = prepare_defs(TCP_AO_INFO, &info);
+ info.set_rnext = 1;
+ info.rnext = 100;
+ setsockopt_checked(sk, TCP_AO_INFO, &info, 0, "set rnext key");
+
+ sk = prepare_defs(TCP_AO_INFO, &info);
+ info.set_current = 1;
+ info.set_rnext = 1;
+ info.current_key = 100;
+ info.rnext = 100;
+ setsockopt_checked(sk, TCP_AO_INFO, &info, 0, "set current+rnext key");
+
+ sk = prepare_defs(TCP_AO_INFO, &info);
+ info.set_counters = 1;
+ info.pkt_good = 321;
+ info.pkt_bad = 888;
+ info.pkt_key_not_found = 654;
+ info.pkt_ao_required = 987654;
+ info.pkt_dropped_icmp = 10000;
+ setsockopt_checked(sk, TCP_AO_INFO, &info, 0, "set counters");
+
+ sk = prepare_defs(TCP_AO_INFO, &info);
+ setsockopt_checked(sk, TCP_AO_INFO, &info, 0, "no-op");
+}
+
+static void getsockopt_checked(int sk, struct tcp_ao_getsockopt *optval,
+ int err, const char *tst)
+{
+ socklen_t len = sizeof(struct tcp_ao_getsockopt);
+
+ __setsockopt_checked(sk, TCP_AO_GET_KEYS, true, optval, &len, err,
+ "get keys: ", tst);
+}
+
+static void test_einval_get_keys(void)
+{
+ struct tcp_ao_getsockopt out;
+ int sk;
+
+ sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP);
+ if (sk < 0)
+ test_error("socket()");
+ getsockopt_checked(sk, &out, ENOENT, "no ao_info");
+
+ sk = prepare_defs(TCP_AO_GET_KEYS, &out);
+ getsockopt_checked(sk, &out, 0, "proper tcp_ao_get_mkts()");
+
+ sk = prepare_defs(TCP_AO_GET_KEYS, &out);
+ out.pkt_good = 643;
+ getsockopt_checked(sk, &out, EINVAL, "set out-only pkt_good counter");
+
+ sk = prepare_defs(TCP_AO_GET_KEYS, &out);
+ out.pkt_bad = 94;
+ getsockopt_checked(sk, &out, EINVAL, "set out-only pkt_bad counter");
+
+ sk = prepare_defs(TCP_AO_GET_KEYS, &out);
+ out.keyflags = (uint8_t)(-1);
+ getsockopt_checked(sk, &out, EINVAL, "bad keyflags");
+
+ sk = prepare_defs(TCP_AO_GET_KEYS, &out);
+ out.ifindex = 42;
+ getsockopt_checked(sk, &out, EINVAL,
+ "ifindex without TCP_AO_KEYF_IFNINDEX");
+
+ sk = prepare_defs(TCP_AO_GET_KEYS, &out);
+ out.reserved = 1;
+ getsockopt_checked(sk, &out, EINVAL, "using reserved field");
+
+ sk = prepare_defs(TCP_AO_GET_KEYS, &out);
+ out.get_all = 0;
+ out.prefix = 0;
+ tcp_addr_to_sockaddr_in(&out.addr, &this_ip_dest, 0);
+ getsockopt_checked(sk, &out, EINVAL, "no prefix, addr");
+
+ sk = prepare_defs(TCP_AO_GET_KEYS, &out);
+ out.get_all = 0;
+ out.prefix = 0;
+ memcpy(&out.addr, &SOCKADDR_ANY, sizeof(SOCKADDR_ANY));
+ getsockopt_checked(sk, &out, 0, "no prefix, any addr");
+
+ sk = prepare_defs(TCP_AO_GET_KEYS, &out);
+ out.get_all = 0;
+ out.prefix = 32;
+ memcpy(&out.addr, &SOCKADDR_ANY, sizeof(SOCKADDR_ANY));
+ getsockopt_checked(sk, &out, EINVAL, "prefix, any addr");
+
+ sk = prepare_defs(TCP_AO_GET_KEYS, &out);
+ out.get_all = 0;
+ out.prefix = 129;
+ tcp_addr_to_sockaddr_in(&out.addr, &this_ip_dest, 0);
+ getsockopt_checked(sk, &out, EINVAL, "too big prefix");
+
+ sk = prepare_defs(TCP_AO_GET_KEYS, &out);
+ out.get_all = 0;
+ out.prefix = 2;
+ tcp_addr_to_sockaddr_in(&out.addr, &this_ip_dest, 0);
+ getsockopt_checked(sk, &out, EINVAL, "too short prefix");
+
+ sk = prepare_defs(TCP_AO_GET_KEYS, &out);
+ out.get_all = 0;
+ out.prefix = DEFAULT_TEST_PREFIX;
+ tcp_addr_to_sockaddr_in(&out.addr, &this_ip_dest, 0);
+ getsockopt_checked(sk, &out, 0, "prefix + addr");
+
+ sk = prepare_defs(TCP_AO_GET_KEYS, &out);
+ out.get_all = 1;
+ out.prefix = DEFAULT_TEST_PREFIX;
+ getsockopt_checked(sk, &out, EINVAL, "get_all + prefix");
+
+ sk = prepare_defs(TCP_AO_GET_KEYS, &out);
+ out.get_all = 1;
+ tcp_addr_to_sockaddr_in(&out.addr, &this_ip_dest, 0);
+ getsockopt_checked(sk, &out, EINVAL, "get_all + addr");
+
+ sk = prepare_defs(TCP_AO_GET_KEYS, &out);
+ out.get_all = 1;
+ out.sndid = 1;
+ getsockopt_checked(sk, &out, EINVAL, "get_all + sndid");
+
+ sk = prepare_defs(TCP_AO_GET_KEYS, &out);
+ out.get_all = 1;
+ out.rcvid = 1;
+ getsockopt_checked(sk, &out, EINVAL, "get_all + rcvid");
+
+ sk = prepare_defs(TCP_AO_GET_KEYS, &out);
+ out.get_all = 0;
+ out.is_current = 1;
+ out.prefix = DEFAULT_TEST_PREFIX;
+ getsockopt_checked(sk, &out, EINVAL, "current + prefix");
+
+ sk = prepare_defs(TCP_AO_GET_KEYS, &out);
+ out.get_all = 0;
+ out.is_current = 1;
+ tcp_addr_to_sockaddr_in(&out.addr, &this_ip_dest, 0);
+ getsockopt_checked(sk, &out, EINVAL, "current + addr");
+
+ sk = prepare_defs(TCP_AO_GET_KEYS, &out);
+ out.get_all = 0;
+ out.is_current = 1;
+ out.sndid = 1;
+ getsockopt_checked(sk, &out, EINVAL, "current + sndid");
+
+ sk = prepare_defs(TCP_AO_GET_KEYS, &out);
+ out.get_all = 0;
+ out.is_current = 1;
+ out.rcvid = 1;
+ getsockopt_checked(sk, &out, EINVAL, "current + rcvid");
+
+ sk = prepare_defs(TCP_AO_GET_KEYS, &out);
+ out.get_all = 0;
+ out.is_rnext = 1;
+ out.prefix = DEFAULT_TEST_PREFIX;
+ getsockopt_checked(sk, &out, EINVAL, "rnext + prefix");
+
+ sk = prepare_defs(TCP_AO_GET_KEYS, &out);
+ out.get_all = 0;
+ out.is_rnext = 1;
+ tcp_addr_to_sockaddr_in(&out.addr, &this_ip_dest, 0);
+ getsockopt_checked(sk, &out, EINVAL, "rnext + addr");
+
+ sk = prepare_defs(TCP_AO_GET_KEYS, &out);
+ out.get_all = 0;
+ out.is_rnext = 1;
+ out.sndid = 1;
+ getsockopt_checked(sk, &out, EINVAL, "rnext + sndid");
+
+ sk = prepare_defs(TCP_AO_GET_KEYS, &out);
+ out.get_all = 0;
+ out.is_rnext = 1;
+ out.rcvid = 1;
+ getsockopt_checked(sk, &out, EINVAL, "rnext + rcvid");
+
+ sk = prepare_defs(TCP_AO_GET_KEYS, &out);
+ out.get_all = 1;
+ out.is_current = 1;
+ getsockopt_checked(sk, &out, EINVAL, "get_all + current");
+
+ sk = prepare_defs(TCP_AO_GET_KEYS, &out);
+ out.get_all = 1;
+ out.is_rnext = 1;
+ getsockopt_checked(sk, &out, EINVAL, "get_all + rnext");
+
+ sk = prepare_defs(TCP_AO_GET_KEYS, &out);
+ out.get_all = 0;
+ out.is_current = 1;
+ out.is_rnext = 1;
+ getsockopt_checked(sk, &out, 0, "current + rnext");
+}
+
+static void einval_tests(void)
+{
+ test_einval_add_key();
+ test_einval_del_key();
+ test_einval_ao_info();
+ test_einval_get_keys();
+}
+
+static void duplicate_tests(void)
+{
+ union tcp_addr network_dup;
+ struct tcp_ao_add ao, ao2;
+ int sk;
+
+ sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
+ if (setsockopt(sk, IPPROTO_TCP, TCP_AO_ADD_KEY, &ao, sizeof(ao)))
+ test_error("setsockopt()");
+ setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, EEXIST, "duplicate: full copy");
+
+ sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
+ ao2 = ao;
+ memcpy(&ao2.addr, &SOCKADDR_ANY, sizeof(SOCKADDR_ANY));
+ ao2.prefix = 0;
+ if (setsockopt(sk, IPPROTO_TCP, TCP_AO_ADD_KEY, &ao2, sizeof(ao)))
+ test_error("setsockopt()");
+ setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, EEXIST, "duplicate: any addr key on the socket");
+
+ sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
+ if (setsockopt(sk, IPPROTO_TCP, TCP_AO_ADD_KEY, &ao, sizeof(ao)))
+ test_error("setsockopt()");
+ memcpy(&ao.addr, &SOCKADDR_ANY, sizeof(SOCKADDR_ANY));
+ ao.prefix = 0;
+ setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, EEXIST, "duplicate: add any addr key");
+
+ if (inet_pton(TEST_FAMILY, TEST_NETWORK, &network_dup) != 1)
+ test_error("Can't convert ip address %s", TEST_NETWORK);
+ sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
+ if (setsockopt(sk, IPPROTO_TCP, TCP_AO_ADD_KEY, &ao, sizeof(ao)))
+ test_error("setsockopt()");
+ if (test_prepare_def_key(&ao, "password", 0, network_dup,
+ 16, 0, 100, 100))
+ test_error("prepare default tcp_ao_add");
+ setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, EEXIST, "duplicate: add any addr for the same subnet");
+
+ sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
+ if (setsockopt(sk, IPPROTO_TCP, TCP_AO_ADD_KEY, &ao, sizeof(ao)))
+ test_error("setsockopt()");
+ setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, EEXIST, "duplicate: full copy of a key");
+
+ sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
+ if (setsockopt(sk, IPPROTO_TCP, TCP_AO_ADD_KEY, &ao, sizeof(ao)))
+ test_error("setsockopt()");
+ ao.rcvid = 101;
+ setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, EEXIST, "duplicate: RecvID differs");
+
+ sk = prepare_defs(TCP_AO_ADD_KEY, &ao);
+ if (setsockopt(sk, IPPROTO_TCP, TCP_AO_ADD_KEY, &ao, sizeof(ao)))
+ test_error("setsockopt()");
+ ao.sndid = 101;
+ setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, EEXIST, "duplicate: SendID differs");
+}
+
+static void *client_fn(void *arg)
+{
+ if (inet_pton(TEST_FAMILY, __TEST_CLIENT_IP(2), &tcp_md5_client) != 1)
+ test_error("Can't convert ip address");
+ extend_tests();
+ einval_tests();
+ duplicate_tests();
+ /*
+ * TODO: check getsockopt(TCP_AO_GET_KEYS) with different filters
+ * returning proper nr & keys;
+ */
+
+ return NULL;
+}
+
+int main(int argc, char *argv[])
+{
+ test_init(120, client_fn, NULL);
+ return 0;
+}
diff --git a/tools/testing/selftests/net/tcp_ao/unsigned-md5.c b/tools/testing/selftests/net/tcp_ao/unsigned-md5.c
new file mode 100644
index 000000000000..7cffde02d2be
--- /dev/null
+++ b/tools/testing/selftests/net/tcp_ao/unsigned-md5.c
@@ -0,0 +1,742 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Author: Dmitry Safonov <dima@arista.com> */
+#include <inttypes.h>
+#include "aolib.h"
+
+#define fault(type) (inj == FAULT_ ## type)
+static const char *md5_password = "Some evil genius, enemy to mankind, must have been the first contriver.";
+static const char *ao_password = DEFAULT_TEST_PASSWORD;
+
+static union tcp_addr client2;
+static union tcp_addr client3;
+
+static const int test_vrf_ifindex = 200;
+static const uint8_t test_vrf_tabid = 42;
+static void setup_vrfs(void)
+{
+ int err;
+
+ if (!kernel_config_has(KCONFIG_NET_VRF))
+ return;
+
+ err = add_vrf("ksft-vrf", test_vrf_tabid, test_vrf_ifindex, -1);
+ if (err)
+ test_error("Failed to add a VRF: %d", err);
+
+ err = link_set_up("ksft-vrf");
+ if (err)
+ test_error("Failed to bring up a VRF");
+
+ err = ip_route_add_vrf(veth_name, TEST_FAMILY,
+ this_ip_addr, this_ip_dest, test_vrf_tabid);
+ if (err)
+ test_error("Failed to add a route to VRF");
+}
+
+static void try_accept(const char *tst_name, unsigned int port,
+ union tcp_addr *md5_addr, uint8_t md5_prefix,
+ union tcp_addr *ao_addr, uint8_t ao_prefix,
+ bool set_ao_required,
+ uint8_t sndid, uint8_t rcvid, uint8_t vrf,
+ const char *cnt_name, test_cnt cnt_expected,
+ int needs_tcp_md5, fault_t inj)
+{
+ struct tcp_ao_counters ao_cnt1, ao_cnt2;
+ uint64_t before_cnt = 0, after_cnt = 0; /* silence GCC */
+ int lsk, err, sk = 0;
+ time_t timeout;
+
+ if (needs_tcp_md5 && should_skip_test(tst_name, KCONFIG_TCP_MD5))
+ return;
+
+ lsk = test_listen_socket(this_ip_addr, port, 1);
+
+ if (md5_addr && test_set_md5(lsk, *md5_addr, md5_prefix, -1, md5_password))
+ test_error("setsockopt(TCP_MD5SIG_EXT)");
+
+ if (ao_addr && test_add_key(lsk, ao_password,
+ *ao_addr, ao_prefix, sndid, rcvid))
+ test_error("setsockopt(TCP_AO_ADD_KEY)");
+
+ if (set_ao_required && test_set_ao_flags(lsk, true, false))
+ test_error("setsockopt(TCP_AO_INFO)");
+
+ if (cnt_name)
+ before_cnt = netstat_get_one(cnt_name, NULL);
+ if (ao_addr && test_get_tcp_ao_counters(lsk, &ao_cnt1))
+ test_error("test_get_tcp_ao_counters()");
+
+ synchronize_threads(); /* preparations done */
+
+ timeout = fault(TIMEOUT) ? TEST_RETRANSMIT_SEC : TEST_TIMEOUT_SEC;
+ err = test_wait_fd(lsk, timeout, 0);
+ if (err == -ETIMEDOUT) {
+ if (!fault(TIMEOUT))
+ test_fail("timeouted for accept()");
+ } else if (err < 0) {
+ test_error("test_wait_fd()");
+ } else {
+ if (fault(TIMEOUT))
+ test_fail("ready to accept");
+
+ sk = accept(lsk, NULL, NULL);
+ if (sk < 0) {
+ test_error("accept()");
+ } else {
+ if (fault(TIMEOUT))
+ test_fail("%s: accepted", tst_name);
+ }
+ }
+
+ if (ao_addr && test_get_tcp_ao_counters(lsk, &ao_cnt2))
+ test_error("test_get_tcp_ao_counters()");
+ close(lsk);
+
+ if (!cnt_name) {
+ test_ok("%s: no counter checks", tst_name);
+ goto out;
+ }
+
+ after_cnt = netstat_get_one(cnt_name, NULL);
+
+ if (after_cnt <= before_cnt) {
+ test_fail("%s: %s counter did not increase: %zu <= %zu",
+ tst_name, cnt_name, after_cnt, before_cnt);
+ } else {
+ test_ok("%s: counter %s increased %zu => %zu",
+ tst_name, cnt_name, before_cnt, after_cnt);
+ }
+ if (ao_addr)
+ test_tcp_ao_counters_cmp(tst_name, &ao_cnt1, &ao_cnt2, cnt_expected);
+
+out:
+ synchronize_threads(); /* close() */
+ if (sk > 0)
+ close(sk);
+}
+
+static void server_add_routes(void)
+{
+ int family = TEST_FAMILY;
+
+ synchronize_threads(); /* client_add_ips() */
+
+ if (ip_route_add(veth_name, family, this_ip_addr, client2))
+ test_error("Failed to add route");
+ if (ip_route_add(veth_name, family, this_ip_addr, client3))
+ test_error("Failed to add route");
+}
+
+static void server_add_fail_tests(unsigned int *port)
+{
+ union tcp_addr addr_any = {};
+
+ try_accept("TCP-AO established: add TCP-MD5 key", (*port)++, NULL, 0,
+ &addr_any, 0, 0, 100, 100, 0, "TCPAOGood", TEST_CNT_GOOD,
+ 1, 0);
+ try_accept("TCP-MD5 established: add TCP-AO key", (*port)++, &addr_any,
+ 0, NULL, 0, 0, 0, 0, 0, NULL, 0, 1, 0);
+ try_accept("non-signed established: add TCP-AO key", (*port)++, NULL, 0,
+ NULL, 0, 0, 0, 0, 0, "CurrEstab", 0, 0, 0);
+}
+
+static void server_vrf_tests(unsigned int *port)
+{
+ setup_vrfs();
+}
+
+static void *server_fn(void *arg)
+{
+ unsigned int port = test_server_port;
+ union tcp_addr addr_any = {};
+
+ server_add_routes();
+
+ try_accept("AO server (INADDR_ANY): AO client", port++, NULL, 0,
+ &addr_any, 0, 0, 100, 100, 0, "TCPAOGood",
+ TEST_CNT_GOOD, 0, 0);
+ try_accept("AO server (INADDR_ANY): MD5 client", port++, NULL, 0,
+ &addr_any, 0, 0, 100, 100, 0, "TCPMD5Unexpected",
+ 0, 1, FAULT_TIMEOUT);
+ try_accept("AO server (INADDR_ANY): no sign client", port++, NULL, 0,
+ &addr_any, 0, 0, 100, 100, 0, "TCPAORequired",
+ TEST_CNT_AO_REQUIRED, 0, FAULT_TIMEOUT);
+ try_accept("AO server (AO_REQUIRED): AO client", port++, NULL, 0,
+ &this_ip_dest, TEST_PREFIX, true,
+ 100, 100, 0, "TCPAOGood", TEST_CNT_GOOD, 0, 0);
+ try_accept("AO server (AO_REQUIRED): unsigned client", port++, NULL, 0,
+ &this_ip_dest, TEST_PREFIX, true,
+ 100, 100, 0, "TCPAORequired",
+ TEST_CNT_AO_REQUIRED, 0, FAULT_TIMEOUT);
+
+ try_accept("MD5 server (INADDR_ANY): AO client", port++, &addr_any, 0,
+ NULL, 0, 0, 0, 0, 0, "TCPAOKeyNotFound",
+ 0, 1, FAULT_TIMEOUT);
+ try_accept("MD5 server (INADDR_ANY): MD5 client", port++, &addr_any, 0,
+ NULL, 0, 0, 0, 0, 0, NULL, 0, 1, 0);
+ try_accept("MD5 server (INADDR_ANY): no sign client", port++, &addr_any,
+ 0, NULL, 0, 0, 0, 0, 0, "TCPMD5NotFound",
+ 0, 1, FAULT_TIMEOUT);
+
+ try_accept("no sign server: AO client", port++, NULL, 0,
+ NULL, 0, 0, 0, 0, 0, "TCPAOKeyNotFound",
+ TEST_CNT_AO_KEY_NOT_FOUND, 0, FAULT_TIMEOUT);
+ try_accept("no sign server: MD5 client", port++, NULL, 0,
+ NULL, 0, 0, 0, 0, 0, "TCPMD5Unexpected",
+ 0, 1, FAULT_TIMEOUT);
+ try_accept("no sign server: no sign client", port++, NULL, 0,
+ NULL, 0, 0, 0, 0, 0, "CurrEstab", 0, 0, 0);
+
+ try_accept("AO+MD5 server: AO client (matching)", port++,
+ &this_ip_dest, TEST_PREFIX, &client2, TEST_PREFIX, 0,
+ 100, 100, 0, "TCPAOGood", TEST_CNT_GOOD, 1, 0);
+ try_accept("AO+MD5 server: AO client (misconfig, matching MD5)", port++,
+ &this_ip_dest, TEST_PREFIX, &client2, TEST_PREFIX, 0,
+ 100, 100, 0, "TCPAOKeyNotFound", TEST_CNT_AO_KEY_NOT_FOUND,
+ 1, FAULT_TIMEOUT);
+ try_accept("AO+MD5 server: AO client (misconfig, non-matching)", port++,
+ &this_ip_dest, TEST_PREFIX, &client2, TEST_PREFIX, 0,
+ 100, 100, 0, "TCPAOKeyNotFound", TEST_CNT_AO_KEY_NOT_FOUND,
+ 1, FAULT_TIMEOUT);
+ try_accept("AO+MD5 server: MD5 client (matching)", port++,
+ &this_ip_dest, TEST_PREFIX, &client2, TEST_PREFIX, 0,
+ 100, 100, 0, NULL, 0, 1, 0);
+ try_accept("AO+MD5 server: MD5 client (misconfig, matching AO)", port++,
+ &this_ip_dest, TEST_PREFIX, &client2, TEST_PREFIX, 0,
+ 100, 100, 0, "TCPMD5Unexpected", 0, 1, FAULT_TIMEOUT);
+ try_accept("AO+MD5 server: MD5 client (misconfig, non-matching)", port++,
+ &this_ip_dest, TEST_PREFIX, &client2, TEST_PREFIX, 0,
+ 100, 100, 0, "TCPMD5Unexpected", 0, 1, FAULT_TIMEOUT);
+ try_accept("AO+MD5 server: no sign client (unmatched)", port++,
+ &this_ip_dest, TEST_PREFIX, &client2, TEST_PREFIX, 0,
+ 100, 100, 0, "CurrEstab", 0, 1, 0);
+ try_accept("AO+MD5 server: no sign client (misconfig, matching AO)",
+ port++, &this_ip_dest, TEST_PREFIX, &client2, TEST_PREFIX, 0,
+ 100, 100, 0, "TCPAORequired",
+ TEST_CNT_AO_REQUIRED, 1, FAULT_TIMEOUT);
+ try_accept("AO+MD5 server: no sign client (misconfig, matching MD5)",
+ port++, &this_ip_dest, TEST_PREFIX, &client2, TEST_PREFIX, 0,
+ 100, 100, 0, "TCPMD5NotFound", 0, 1, FAULT_TIMEOUT);
+
+ try_accept("AO+MD5 server: client with both [TCP-MD5] and TCP-AO keys",
+ port++, &this_ip_dest, TEST_PREFIX, &client2, TEST_PREFIX, 0,
+ 100, 100, 0, NULL, 0, 1, FAULT_TIMEOUT);
+ try_accept("AO+MD5 server: client with both TCP-MD5 and [TCP-AO] keys",
+ port++, &this_ip_dest, TEST_PREFIX, &client2, TEST_PREFIX, 0,
+ 100, 100, 0, NULL, 0, 1, FAULT_TIMEOUT);
+
+ server_add_fail_tests(&port);
+
+ server_vrf_tests(&port);
+
+ /* client exits */
+ synchronize_threads();
+ return NULL;
+}
+
+static int client_bind(int sk, union tcp_addr bind_addr)
+{
+#ifdef IPV6_TEST
+ struct sockaddr_in6 addr = {
+ .sin6_family = AF_INET6,
+ .sin6_port = 0,
+ .sin6_addr = bind_addr.a6,
+ };
+#else
+ struct sockaddr_in addr = {
+ .sin_family = AF_INET,
+ .sin_port = 0,
+ .sin_addr = bind_addr.a4,
+ };
+#endif
+ return bind(sk, &addr, sizeof(addr));
+}
+
+static void try_connect(const char *tst_name, unsigned int port,
+ union tcp_addr *md5_addr, uint8_t md5_prefix,
+ union tcp_addr *ao_addr, uint8_t ao_prefix,
+ uint8_t sndid, uint8_t rcvid, uint8_t vrf,
+ fault_t inj, int needs_tcp_md5, union tcp_addr *bind_addr)
+{
+ time_t timeout;
+ int sk, ret;
+
+ if (needs_tcp_md5 && should_skip_test(tst_name, KCONFIG_TCP_MD5))
+ return;
+
+ sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP);
+ if (sk < 0)
+ test_error("socket()");
+
+ if (bind_addr && client_bind(sk, *bind_addr))
+ test_error("bind()");
+
+ if (md5_addr && test_set_md5(sk, *md5_addr, md5_prefix, -1, md5_password))
+ test_error("setsockopt(TCP_MD5SIG_EXT)");
+
+ if (ao_addr && test_add_key(sk, ao_password, *ao_addr,
+ ao_prefix, sndid, rcvid))
+ test_error("setsockopt(TCP_AO_ADD_KEY)");
+
+ synchronize_threads(); /* preparations done */
+
+ timeout = fault(TIMEOUT) ? TEST_RETRANSMIT_SEC : TEST_TIMEOUT_SEC;
+ ret = _test_connect_socket(sk, this_ip_dest, port, timeout);
+
+ if (ret < 0) {
+ if (fault(KEYREJECT) && ret == -EKEYREJECTED)
+ test_ok("%s: connect() was prevented", tst_name);
+ else if (ret == -ETIMEDOUT && fault(TIMEOUT))
+ test_ok("%s", tst_name);
+ else if (ret == -ECONNREFUSED &&
+ (fault(TIMEOUT) || fault(KEYREJECT)))
+ test_ok("%s: refused to connect", tst_name);
+ else
+ test_error("%s: connect() returned %d", tst_name, ret);
+ goto out;
+ }
+
+ if (fault(TIMEOUT) || fault(KEYREJECT))
+ test_fail("%s: connected", tst_name);
+ else
+ test_ok("%s: connected", tst_name);
+
+out:
+ synchronize_threads(); /* close() */
+ /* _test_connect_socket() cleans up on failure */
+ if (ret > 0)
+ close(sk);
+}
+
+#define PREINSTALL_MD5_FIRST BIT(0)
+#define PREINSTALL_AO BIT(1)
+#define POSTINSTALL_AO BIT(2)
+#define PREINSTALL_MD5 BIT(3)
+#define POSTINSTALL_MD5 BIT(4)
+
+static int try_add_key_vrf(int sk, union tcp_addr in_addr, uint8_t prefix,
+ int vrf, uint8_t sndid, uint8_t rcvid,
+ bool set_ao_required)
+{
+ uint8_t keyflags = 0;
+
+ if (vrf >= 0)
+ keyflags |= TCP_AO_KEYF_IFINDEX;
+ else
+ vrf = 0;
+ if (set_ao_required) {
+ int err = test_set_ao_flags(sk, true, 0);
+
+ if (err)
+ return err;
+ }
+ return test_add_key_vrf(sk, ao_password, keyflags, in_addr, prefix,
+ (uint8_t)vrf, sndid, rcvid);
+}
+
+static bool test_continue(const char *tst_name, int err,
+ fault_t inj, bool added_ao)
+{
+ bool expected_to_fail;
+
+ expected_to_fail = fault(PREINSTALL_AO) && added_ao;
+ expected_to_fail |= fault(PREINSTALL_MD5) && !added_ao;
+
+ if (!err) {
+ if (!expected_to_fail)
+ return true;
+ test_fail("%s: setsockopt()s were expected to fail", tst_name);
+ return false;
+ }
+ if (err != -EKEYREJECTED || !expected_to_fail) {
+ test_error("%s: setsockopt(%s) = %d", tst_name,
+ added_ao ? "TCP_AO_ADD_KEY" : "TCP_MD5SIG_EXT", err);
+ return false;
+ }
+ test_ok("%s: prefailed as expected: %m", tst_name);
+ return false;
+}
+
+static int open_add(const char *tst_name, unsigned int port,
+ unsigned int strategy,
+ union tcp_addr md5_addr, uint8_t md5_prefix, int md5_vrf,
+ union tcp_addr ao_addr, uint8_t ao_prefix,
+ int ao_vrf, bool set_ao_required,
+ uint8_t sndid, uint8_t rcvid,
+ fault_t inj)
+{
+ int sk;
+
+ sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP);
+ if (sk < 0)
+ test_error("socket()");
+
+ if (client_bind(sk, this_ip_addr))
+ test_error("bind()");
+
+ if (strategy & PREINSTALL_MD5_FIRST) {
+ if (test_set_md5(sk, md5_addr, md5_prefix, md5_vrf, md5_password))
+ test_error("setsockopt(TCP_MD5SIG_EXT)");
+ }
+
+ if (strategy & PREINSTALL_AO) {
+ int err = try_add_key_vrf(sk, ao_addr, ao_prefix, ao_vrf,
+ sndid, rcvid, set_ao_required);
+
+ if (!test_continue(tst_name, err, inj, true)) {
+ close(sk);
+ return -1;
+ }
+ }
+
+ if (strategy & PREINSTALL_MD5) {
+ errno = 0;
+ test_set_md5(sk, md5_addr, md5_prefix, md5_vrf, md5_password);
+ if (!test_continue(tst_name, -errno, inj, false)) {
+ close(sk);
+ return -1;
+ }
+ }
+
+ return sk;
+}
+
+static void try_to_preadd(const char *tst_name, unsigned int port,
+ unsigned int strategy,
+ union tcp_addr md5_addr, uint8_t md5_prefix,
+ int md5_vrf,
+ union tcp_addr ao_addr, uint8_t ao_prefix,
+ int ao_vrf, bool set_ao_required,
+ uint8_t sndid, uint8_t rcvid,
+ int needs_tcp_md5, int needs_vrf, fault_t inj)
+{
+ int sk;
+
+ if (needs_tcp_md5 && should_skip_test(tst_name, KCONFIG_TCP_MD5))
+ return;
+ if (needs_vrf && should_skip_test(tst_name, KCONFIG_NET_VRF))
+ return;
+
+ sk = open_add(tst_name, port, strategy, md5_addr, md5_prefix, md5_vrf,
+ ao_addr, ao_prefix, ao_vrf, set_ao_required,
+ sndid, rcvid, inj);
+ if (sk < 0)
+ return;
+
+ test_ok("%s", tst_name);
+ close(sk);
+}
+
+static void try_to_add(const char *tst_name, unsigned int port,
+ unsigned int strategy,
+ union tcp_addr md5_addr, uint8_t md5_prefix,
+ int md5_vrf,
+ union tcp_addr ao_addr, uint8_t ao_prefix,
+ int ao_vrf, uint8_t sndid, uint8_t rcvid,
+ int needs_tcp_md5, fault_t inj)
+{
+ time_t timeout;
+ int sk, ret;
+
+ if (needs_tcp_md5 && should_skip_test(tst_name, KCONFIG_TCP_MD5))
+ return;
+
+ sk = open_add(tst_name, port, strategy, md5_addr, md5_prefix, md5_vrf,
+ ao_addr, ao_prefix, ao_vrf, 0, sndid, rcvid, inj);
+ if (sk < 0)
+ return;
+
+ synchronize_threads(); /* preparations done */
+
+ timeout = fault(TIMEOUT) ? TEST_RETRANSMIT_SEC : TEST_TIMEOUT_SEC;
+ ret = _test_connect_socket(sk, this_ip_dest, port, timeout);
+
+ if (ret <= 0) {
+ test_error("%s: connect() returned %d", tst_name, ret);
+ goto out;
+ }
+
+ if (strategy & POSTINSTALL_MD5) {
+ if (test_set_md5(sk, md5_addr, md5_prefix, md5_vrf, md5_password)) {
+ if (fault(POSTINSTALL)) {
+ test_ok("%s: postfailed as expected", tst_name);
+ goto out;
+ } else {
+ test_error("setsockopt(TCP_MD5SIG_EXT)");
+ }
+ } else if (fault(POSTINSTALL)) {
+ test_fail("%s: post setsockopt() was expected to fail", tst_name);
+ goto out;
+ }
+ }
+
+ if (strategy & POSTINSTALL_AO) {
+ if (try_add_key_vrf(sk, ao_addr, ao_prefix, ao_vrf,
+ sndid, rcvid, 0)) {
+ if (fault(POSTINSTALL)) {
+ test_ok("%s: postfailed as expected", tst_name);
+ goto out;
+ } else {
+ test_error("setsockopt(TCP_AO_ADD_KEY)");
+ }
+ } else if (fault(POSTINSTALL)) {
+ test_fail("%s: post setsockopt() was expected to fail", tst_name);
+ goto out;
+ }
+ }
+
+out:
+ synchronize_threads(); /* close() */
+ /* _test_connect_socket() cleans up on failure */
+ if (ret > 0)
+ close(sk);
+}
+
+static void client_add_ip(union tcp_addr *client, const char *ip)
+{
+ int family = TEST_FAMILY;
+
+ if (inet_pton(family, ip, client) != 1)
+ test_error("Can't convert ip address %s", ip);
+
+ if (ip_addr_add(veth_name, family, *client, TEST_PREFIX))
+ test_error("Failed to add ip address");
+ if (ip_route_add(veth_name, family, *client, this_ip_dest))
+ test_error("Failed to add route");
+}
+
+static void client_add_ips(void)
+{
+ client_add_ip(&client2, __TEST_CLIENT_IP(2));
+ client_add_ip(&client3, __TEST_CLIENT_IP(3));
+ synchronize_threads(); /* server_add_routes() */
+}
+
+static void client_add_fail_tests(unsigned int *port)
+{
+ try_to_add("TCP-AO established: add TCP-MD5 key",
+ (*port)++, POSTINSTALL_MD5 | PREINSTALL_AO,
+ this_ip_dest, TEST_PREFIX, -1, this_ip_dest, TEST_PREFIX, 0,
+ 100, 100, 1, FAULT_POSTINSTALL);
+ try_to_add("TCP-MD5 established: add TCP-AO key",
+ (*port)++, PREINSTALL_MD5 | POSTINSTALL_AO,
+ this_ip_dest, TEST_PREFIX, -1, this_ip_dest, TEST_PREFIX, 0,
+ 100, 100, 1, FAULT_POSTINSTALL);
+ try_to_add("non-signed established: add TCP-AO key",
+ (*port)++, POSTINSTALL_AO,
+ this_ip_dest, TEST_PREFIX, -1, this_ip_dest, TEST_PREFIX, 0,
+ 100, 100, 0, FAULT_POSTINSTALL);
+
+ try_to_add("TCP-AO key intersects with existing TCP-MD5 key",
+ (*port)++, PREINSTALL_MD5_FIRST | PREINSTALL_AO,
+ this_ip_addr, TEST_PREFIX, -1, this_ip_addr, TEST_PREFIX, -1,
+ 100, 100, 1, FAULT_PREINSTALL_AO);
+ try_to_add("TCP-MD5 key intersects with existing TCP-AO key",
+ (*port)++, PREINSTALL_MD5 | PREINSTALL_AO,
+ this_ip_addr, TEST_PREFIX, -1, this_ip_addr, TEST_PREFIX, -1,
+ 100, 100, 1, FAULT_PREINSTALL_MD5);
+
+ try_to_preadd("TCP-MD5 key + TCP-AO required",
+ (*port)++, PREINSTALL_MD5_FIRST | PREINSTALL_AO,
+ this_ip_addr, TEST_PREFIX, -1,
+ this_ip_addr, TEST_PREFIX, -1, true,
+ 100, 100, 1, 0, FAULT_PREINSTALL_AO);
+ try_to_preadd("TCP-AO required on socket + TCP-MD5 key",
+ (*port)++, PREINSTALL_MD5 | PREINSTALL_AO,
+ this_ip_addr, TEST_PREFIX, -1,
+ this_ip_addr, TEST_PREFIX, -1, true,
+ 100, 100, 1, 0, FAULT_PREINSTALL_MD5);
+}
+
+static void client_vrf_tests(unsigned int *port)
+{
+ setup_vrfs();
+
+ /* The following restrictions for setsockopt()s are expected:
+ *
+ * |--------------|-----------------|-------------|-------------|
+ * | | MD5 key without | MD5 key | MD5 key |
+ * | | l3index | l3index=0 | l3index=N |
+ * |--------------|-----------------|-------------|-------------|
+ * | TCP-AO key | | | |
+ * | without | reject | reject | reject |
+ * | l3index | | | |
+ * |--------------|-----------------|-------------|-------------|
+ * | TCP-AO key | | | |
+ * | l3index=0 | reject | reject | allow |
+ * |--------------|-----------------|-------------|-------------|
+ * | TCP-AO key | | | |
+ * | l3index=N | reject | allow | reject |
+ * |--------------|-----------------|-------------|-------------|
+ */
+ try_to_preadd("VRF: TCP-AO key (no l3index) + TCP-MD5 key (no l3index)",
+ (*port)++, PREINSTALL_MD5 | PREINSTALL_AO,
+ this_ip_addr, TEST_PREFIX, -1,
+ this_ip_addr, TEST_PREFIX, -1, 0, 100, 100,
+ 1, 1, FAULT_PREINSTALL_MD5);
+ try_to_preadd("VRF: TCP-MD5 key (no l3index) + TCP-AO key (no l3index)",
+ (*port)++, PREINSTALL_MD5_FIRST | PREINSTALL_AO,
+ this_ip_addr, TEST_PREFIX, -1,
+ this_ip_addr, TEST_PREFIX, -1, 0, 100, 100,
+ 1, 1, FAULT_PREINSTALL_AO);
+ try_to_preadd("VRF: TCP-AO key (no l3index) + TCP-MD5 key (l3index=0)",
+ (*port)++, PREINSTALL_MD5 | PREINSTALL_AO,
+ this_ip_addr, TEST_PREFIX, 0,
+ this_ip_addr, TEST_PREFIX, -1, 0, 100, 100,
+ 1, 1, FAULT_PREINSTALL_MD5);
+ try_to_preadd("VRF: TCP-MD5 key (l3index=0) + TCP-AO key (no l3index)",
+ (*port)++, PREINSTALL_MD5_FIRST | PREINSTALL_AO,
+ this_ip_addr, TEST_PREFIX, 0,
+ this_ip_addr, TEST_PREFIX, -1, 0, 100, 100,
+ 1, 1, FAULT_PREINSTALL_AO);
+ try_to_preadd("VRF: TCP-AO key (no l3index) + TCP-MD5 key (l3index=N)",
+ (*port)++, PREINSTALL_MD5 | PREINSTALL_AO,
+ this_ip_addr, TEST_PREFIX, test_vrf_ifindex,
+ this_ip_addr, TEST_PREFIX, -1, 0, 100, 100,
+ 1, 1, FAULT_PREINSTALL_MD5);
+ try_to_preadd("VRF: TCP-MD5 key (l3index=N) + TCP-AO key (no l3index)",
+ (*port)++, PREINSTALL_MD5_FIRST | PREINSTALL_AO,
+ this_ip_addr, TEST_PREFIX, test_vrf_ifindex,
+ this_ip_addr, TEST_PREFIX, -1, 0, 100, 100,
+ 1, 1, FAULT_PREINSTALL_AO);
+
+ try_to_preadd("VRF: TCP-AO key (l3index=0) + TCP-MD5 key (no l3index)",
+ (*port)++, PREINSTALL_MD5 | PREINSTALL_AO,
+ this_ip_addr, TEST_PREFIX, -1,
+ this_ip_addr, TEST_PREFIX, 0, 0, 100, 100,
+ 1, 1, FAULT_PREINSTALL_MD5);
+ try_to_preadd("VRF: TCP-MD5 key (no l3index) + TCP-AO key (l3index=0)",
+ (*port)++, PREINSTALL_MD5_FIRST | PREINSTALL_AO,
+ this_ip_addr, TEST_PREFIX, -1,
+ this_ip_addr, TEST_PREFIX, 0, 0, 100, 100,
+ 1, 1, FAULT_PREINSTALL_AO);
+ try_to_preadd("VRF: TCP-AO key (l3index=0) + TCP-MD5 key (l3index=0)",
+ (*port)++, PREINSTALL_MD5 | PREINSTALL_AO,
+ this_ip_addr, TEST_PREFIX, 0,
+ this_ip_addr, TEST_PREFIX, 0, 0, 100, 100,
+ 1, 1, FAULT_PREINSTALL_MD5);
+ try_to_preadd("VRF: TCP-MD5 key (l3index=0) + TCP-AO key (l3index=0)",
+ (*port)++, PREINSTALL_MD5_FIRST | PREINSTALL_AO,
+ this_ip_addr, TEST_PREFIX, 0,
+ this_ip_addr, TEST_PREFIX, 0, 0, 100, 100,
+ 1, 1, FAULT_PREINSTALL_AO);
+ try_to_preadd("VRF: TCP-AO key (l3index=0) + TCP-MD5 key (l3index=N)",
+ (*port)++, PREINSTALL_MD5 | PREINSTALL_AO,
+ this_ip_addr, TEST_PREFIX, test_vrf_ifindex,
+ this_ip_addr, TEST_PREFIX, 0, 0, 100, 100,
+ 1, 1, 0);
+ try_to_preadd("VRF: TCP-MD5 key (l3index=N) + TCP-AO key (l3index=0)",
+ (*port)++, PREINSTALL_MD5_FIRST | PREINSTALL_AO,
+ this_ip_addr, TEST_PREFIX, test_vrf_ifindex,
+ this_ip_addr, TEST_PREFIX, 0, 0, 100, 100,
+ 1, 1, 0);
+
+ try_to_preadd("VRF: TCP-AO key (l3index=N) + TCP-MD5 key (no l3index)",
+ (*port)++, PREINSTALL_MD5 | PREINSTALL_AO,
+ this_ip_addr, TEST_PREFIX, test_vrf_ifindex,
+ this_ip_addr, TEST_PREFIX, -1, 0, 100, 100,
+ 1, 1, FAULT_PREINSTALL_MD5);
+ try_to_preadd("VRF: TCP-MD5 key (no l3index) + TCP-AO key (l3index=N)",
+ (*port)++, PREINSTALL_MD5_FIRST | PREINSTALL_AO,
+ this_ip_addr, TEST_PREFIX, -1,
+ this_ip_addr, TEST_PREFIX, test_vrf_ifindex, 0, 100, 100,
+ 1, 1, FAULT_PREINSTALL_AO);
+ try_to_preadd("VRF: TCP-AO key (l3index=N) + TCP-MD5 key (l3index=0)",
+ (*port)++, PREINSTALL_MD5 | PREINSTALL_AO,
+ this_ip_addr, TEST_PREFIX, 0,
+ this_ip_addr, TEST_PREFIX, test_vrf_ifindex, 0, 100, 100,
+ 1, 1, 0);
+ try_to_preadd("VRF: TCP-MD5 key (l3index=0) + TCP-AO key (l3index=N)",
+ (*port)++, PREINSTALL_MD5_FIRST | PREINSTALL_AO,
+ this_ip_addr, TEST_PREFIX, 0,
+ this_ip_addr, TEST_PREFIX, test_vrf_ifindex, 0, 100, 100,
+ 1, 1, 0);
+ try_to_preadd("VRF: TCP-AO key (l3index=N) + TCP-MD5 key (l3index=N)",
+ (*port)++, PREINSTALL_MD5 | PREINSTALL_AO,
+ this_ip_addr, TEST_PREFIX, test_vrf_ifindex,
+ this_ip_addr, TEST_PREFIX, test_vrf_ifindex, 0, 100, 100,
+ 1, 1, FAULT_PREINSTALL_MD5);
+ try_to_preadd("VRF: TCP-MD5 key (l3index=N) + TCP-AO key (l3index=N)",
+ (*port)++, PREINSTALL_MD5_FIRST | PREINSTALL_AO,
+ this_ip_addr, TEST_PREFIX, test_vrf_ifindex,
+ this_ip_addr, TEST_PREFIX, test_vrf_ifindex, 0, 100, 100,
+ 1, 1, FAULT_PREINSTALL_AO);
+}
+
+static void *client_fn(void *arg)
+{
+ unsigned int port = test_server_port;
+ union tcp_addr addr_any = {};
+
+ client_add_ips();
+
+ try_connect("AO server (INADDR_ANY): AO client", port++, NULL, 0,
+ &addr_any, 0, 100, 100, 0, 0, 0, &this_ip_addr);
+ try_connect("AO server (INADDR_ANY): MD5 client", port++, &addr_any, 0,
+ NULL, 0, 100, 100, 0, FAULT_TIMEOUT, 1, &this_ip_addr);
+ try_connect("AO server (INADDR_ANY): unsigned client", port++, NULL, 0,
+ NULL, 0, 100, 100, 0, FAULT_TIMEOUT, 0, &this_ip_addr);
+ try_connect("AO server (AO_REQUIRED): AO client", port++, NULL, 0,
+ &addr_any, 0, 100, 100, 0, 0, 0, &this_ip_addr);
+ try_connect("AO server (AO_REQUIRED): unsigned client", port++, NULL, 0,
+ NULL, 0, 100, 100, 0, FAULT_TIMEOUT, 0, &client2);
+
+ try_connect("MD5 server (INADDR_ANY): AO client", port++, NULL, 0,
+ &addr_any, 0, 100, 100, 0, FAULT_TIMEOUT, 1, &this_ip_addr);
+ try_connect("MD5 server (INADDR_ANY): MD5 client", port++, &addr_any, 0,
+ NULL, 0, 100, 100, 0, 0, 1, &this_ip_addr);
+ try_connect("MD5 server (INADDR_ANY): no sign client", port++, NULL, 0,
+ NULL, 0, 100, 100, 0, FAULT_TIMEOUT, 1, &this_ip_addr);
+
+ try_connect("no sign server: AO client", port++, NULL, 0,
+ &addr_any, 0, 100, 100, 0, FAULT_TIMEOUT, 0, &this_ip_addr);
+ try_connect("no sign server: MD5 client", port++, &addr_any, 0,
+ NULL, 0, 100, 100, 0, FAULT_TIMEOUT, 1, &this_ip_addr);
+ try_connect("no sign server: no sign client", port++, NULL, 0,
+ NULL, 0, 100, 100, 0, 0, 0, &this_ip_addr);
+
+ try_connect("AO+MD5 server: AO client (matching)", port++, NULL, 0,
+ &addr_any, 0, 100, 100, 0, 0, 1, &client2);
+ try_connect("AO+MD5 server: AO client (misconfig, matching MD5)",
+ port++, NULL, 0, &addr_any, 0, 100, 100, 0,
+ FAULT_TIMEOUT, 1, &this_ip_addr);
+ try_connect("AO+MD5 server: AO client (misconfig, non-matching)",
+ port++, NULL, 0, &addr_any, 0, 100, 100, 0,
+ FAULT_TIMEOUT, 1, &client3);
+ try_connect("AO+MD5 server: MD5 client (matching)", port++, &addr_any, 0,
+ NULL, 0, 100, 100, 0, 0, 1, &this_ip_addr);
+ try_connect("AO+MD5 server: MD5 client (misconfig, matching AO)",
+ port++, &addr_any, 0, NULL, 0, 100, 100, 0, FAULT_TIMEOUT,
+ 1, &client2);
+ try_connect("AO+MD5 server: MD5 client (misconfig, non-matching)",
+ port++, &addr_any, 0, NULL, 0, 100, 100, 0, FAULT_TIMEOUT,
+ 1, &client3);
+ try_connect("AO+MD5 server: no sign client (unmatched)",
+ port++, NULL, 0, NULL, 0, 100, 100, 0, 0, 1, &client3);
+ try_connect("AO+MD5 server: no sign client (misconfig, matching AO)",
+ port++, NULL, 0, NULL, 0, 100, 100, 0, FAULT_TIMEOUT,
+ 1, &client2);
+ try_connect("AO+MD5 server: no sign client (misconfig, matching MD5)",
+ port++, NULL, 0, NULL, 0, 100, 100, 0, FAULT_TIMEOUT,
+ 1, &this_ip_addr);
+
+ try_connect("AO+MD5 server: client with both [TCP-MD5] and TCP-AO keys",
+ port++, &this_ip_addr, TEST_PREFIX,
+ &client2, TEST_PREFIX, 100, 100, 0, FAULT_KEYREJECT,
+ 1, &this_ip_addr);
+ try_connect("AO+MD5 server: client with both TCP-MD5 and [TCP-AO] keys",
+ port++, &this_ip_addr, TEST_PREFIX,
+ &client2, TEST_PREFIX, 100, 100, 0, FAULT_KEYREJECT,
+ 1, &client2);
+
+ client_add_fail_tests(&port);
+ client_vrf_tests(&port);
+
+ return NULL;
+}
+
+int main(int argc, char *argv[])
+{
+ test_init(72, server_fn, client_fn);
+ return 0;
+}
diff --git a/tools/testing/selftests/net/test_bridge_backup_port.sh b/tools/testing/selftests/net/test_bridge_backup_port.sh
index 112cfd8a10ad..70a7d87ba2d2 100755
--- a/tools/testing/selftests/net/test_bridge_backup_port.sh
+++ b/tools/testing/selftests/net/test_bridge_backup_port.sh
@@ -35,9 +35,8 @@
# | sw1 | | sw2 |
# +------------------------------------+ +------------------------------------+
+source lib.sh
ret=0
-# Kselftest framework requirement - SKIP code is 4.
-ksft_skip=4
# All tests in this script. Can be overridden with -t option.
TESTS="
@@ -132,9 +131,6 @@ setup_topo_ns()
{
local ns=$1; shift
- ip netns add $ns
- ip -n $ns link set dev lo up
-
ip netns exec $ns sysctl -qw net.ipv6.conf.all.keep_addr_on_down=1
ip netns exec $ns sysctl -qw net.ipv6.conf.default.ignore_routes_with_linkdown=1
ip netns exec $ns sysctl -qw net.ipv6.conf.all.accept_dad=0
@@ -145,13 +141,14 @@ setup_topo()
{
local ns
- for ns in sw1 sw2; do
+ setup_ns sw1 sw2
+ for ns in $sw1 $sw2; do
setup_topo_ns $ns
done
ip link add name veth0 type veth peer name veth1
- ip link set dev veth0 netns sw1 name veth0
- ip link set dev veth1 netns sw2 name veth0
+ ip link set dev veth0 netns $sw1 name veth0
+ ip link set dev veth1 netns $sw2 name veth0
}
setup_sw_common()
@@ -190,7 +187,7 @@ setup_sw_common()
setup_sw1()
{
- local ns=sw1
+ local ns=$sw1
local local_addr=192.0.2.33
local remote_addr=192.0.2.34
local veth_addr=192.0.2.49
@@ -203,7 +200,7 @@ setup_sw1()
setup_sw2()
{
- local ns=sw2
+ local ns=$sw2
local local_addr=192.0.2.34
local remote_addr=192.0.2.33
local veth_addr=192.0.2.50
@@ -229,11 +226,7 @@ setup()
cleanup()
{
- local ns
-
- for ns in h1 h2 sw1 sw2; do
- ip netns del $ns &> /dev/null
- done
+ cleanup_ns $sw1 $sw2
}
################################################################################
@@ -248,85 +241,85 @@ backup_port()
echo "Backup port"
echo "-----------"
- run_cmd "tc -n sw1 qdisc replace dev swp1 clsact"
- run_cmd "tc -n sw1 filter replace dev swp1 egress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac action pass"
+ run_cmd "tc -n $sw1 qdisc replace dev swp1 clsact"
+ run_cmd "tc -n $sw1 filter replace dev swp1 egress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac action pass"
- run_cmd "tc -n sw1 qdisc replace dev vx0 clsact"
- run_cmd "tc -n sw1 filter replace dev vx0 egress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac action pass"
+ run_cmd "tc -n $sw1 qdisc replace dev vx0 clsact"
+ run_cmd "tc -n $sw1 filter replace dev vx0 egress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac action pass"
- run_cmd "bridge -n sw1 fdb replace $dmac dev swp1 master static vlan 10"
+ run_cmd "bridge -n $sw1 fdb replace $dmac dev swp1 master static vlan 10"
# Initial state - check that packets are forwarded out of swp1 when it
# has a carrier and not forwarded out of any port when it does not have
# a carrier.
- run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
- tc_check_packets sw1 "dev swp1 egress" 101 1
+ run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
+ tc_check_packets $sw1 "dev swp1 egress" 101 1
log_test $? 0 "Forwarding out of swp1"
- tc_check_packets sw1 "dev vx0 egress" 101 0
+ tc_check_packets $sw1 "dev vx0 egress" 101 0
log_test $? 0 "No forwarding out of vx0"
- run_cmd "ip -n sw1 link set dev swp1 carrier off"
+ run_cmd "ip -n $sw1 link set dev swp1 carrier off"
log_test $? 0 "swp1 carrier off"
- run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
- tc_check_packets sw1 "dev swp1 egress" 101 1
+ run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
+ tc_check_packets $sw1 "dev swp1 egress" 101 1
log_test $? 0 "No forwarding out of swp1"
- tc_check_packets sw1 "dev vx0 egress" 101 0
+ tc_check_packets $sw1 "dev vx0 egress" 101 0
log_test $? 0 "No forwarding out of vx0"
- run_cmd "ip -n sw1 link set dev swp1 carrier on"
+ run_cmd "ip -n $sw1 link set dev swp1 carrier on"
log_test $? 0 "swp1 carrier on"
# Configure vx0 as the backup port of swp1 and check that packets are
# forwarded out of swp1 when it has a carrier and out of vx0 when swp1
# does not have a carrier.
- run_cmd "bridge -n sw1 link set dev swp1 backup_port vx0"
- run_cmd "bridge -n sw1 -d link show dev swp1 | grep \"backup_port vx0\""
+ run_cmd "bridge -n $sw1 link set dev swp1 backup_port vx0"
+ run_cmd "bridge -n $sw1 -d link show dev swp1 | grep \"backup_port vx0\""
log_test $? 0 "vx0 configured as backup port of swp1"
- run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
- tc_check_packets sw1 "dev swp1 egress" 101 2
+ run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
+ tc_check_packets $sw1 "dev swp1 egress" 101 2
log_test $? 0 "Forwarding out of swp1"
- tc_check_packets sw1 "dev vx0 egress" 101 0
+ tc_check_packets $sw1 "dev vx0 egress" 101 0
log_test $? 0 "No forwarding out of vx0"
- run_cmd "ip -n sw1 link set dev swp1 carrier off"
+ run_cmd "ip -n $sw1 link set dev swp1 carrier off"
log_test $? 0 "swp1 carrier off"
- run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
- tc_check_packets sw1 "dev swp1 egress" 101 2
+ run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
+ tc_check_packets $sw1 "dev swp1 egress" 101 2
log_test $? 0 "No forwarding out of swp1"
- tc_check_packets sw1 "dev vx0 egress" 101 1
+ tc_check_packets $sw1 "dev vx0 egress" 101 1
log_test $? 0 "Forwarding out of vx0"
- run_cmd "ip -n sw1 link set dev swp1 carrier on"
+ run_cmd "ip -n $sw1 link set dev swp1 carrier on"
log_test $? 0 "swp1 carrier on"
- run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
- tc_check_packets sw1 "dev swp1 egress" 101 3
+ run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
+ tc_check_packets $sw1 "dev swp1 egress" 101 3
log_test $? 0 "Forwarding out of swp1"
- tc_check_packets sw1 "dev vx0 egress" 101 1
+ tc_check_packets $sw1 "dev vx0 egress" 101 1
log_test $? 0 "No forwarding out of vx0"
# Remove vx0 as the backup port of swp1 and check that packets are no
# longer forwarded out of vx0 when swp1 does not have a carrier.
- run_cmd "bridge -n sw1 link set dev swp1 nobackup_port"
- run_cmd "bridge -n sw1 -d link show dev swp1 | grep \"backup_port vx0\""
+ run_cmd "bridge -n $sw1 link set dev swp1 nobackup_port"
+ run_cmd "bridge -n $sw1 -d link show dev swp1 | grep \"backup_port vx0\""
log_test $? 1 "vx0 not configured as backup port of swp1"
- run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
- tc_check_packets sw1 "dev swp1 egress" 101 4
+ run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
+ tc_check_packets $sw1 "dev swp1 egress" 101 4
log_test $? 0 "Forwarding out of swp1"
- tc_check_packets sw1 "dev vx0 egress" 101 1
+ tc_check_packets $sw1 "dev vx0 egress" 101 1
log_test $? 0 "No forwarding out of vx0"
- run_cmd "ip -n sw1 link set dev swp1 carrier off"
+ run_cmd "ip -n $sw1 link set dev swp1 carrier off"
log_test $? 0 "swp1 carrier off"
- run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
- tc_check_packets sw1 "dev swp1 egress" 101 4
+ run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
+ tc_check_packets $sw1 "dev swp1 egress" 101 4
log_test $? 0 "No forwarding out of swp1"
- tc_check_packets sw1 "dev vx0 egress" 101 1
+ tc_check_packets $sw1 "dev vx0 egress" 101 1
log_test $? 0 "No forwarding out of vx0"
}
@@ -339,125 +332,125 @@ backup_nhid()
echo "Backup nexthop ID"
echo "-----------------"
- run_cmd "tc -n sw1 qdisc replace dev swp1 clsact"
- run_cmd "tc -n sw1 filter replace dev swp1 egress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac action pass"
+ run_cmd "tc -n $sw1 qdisc replace dev swp1 clsact"
+ run_cmd "tc -n $sw1 filter replace dev swp1 egress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac action pass"
- run_cmd "tc -n sw1 qdisc replace dev vx0 clsact"
- run_cmd "tc -n sw1 filter replace dev vx0 egress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac action pass"
+ run_cmd "tc -n $sw1 qdisc replace dev vx0 clsact"
+ run_cmd "tc -n $sw1 filter replace dev vx0 egress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac action pass"
- run_cmd "ip -n sw1 nexthop replace id 1 via 192.0.2.34 fdb"
- run_cmd "ip -n sw1 nexthop replace id 2 via 192.0.2.34 fdb"
- run_cmd "ip -n sw1 nexthop replace id 10 group 1/2 fdb"
+ run_cmd "ip -n $sw1 nexthop replace id 1 via 192.0.2.34 fdb"
+ run_cmd "ip -n $sw1 nexthop replace id 2 via 192.0.2.34 fdb"
+ run_cmd "ip -n $sw1 nexthop replace id 10 group 1/2 fdb"
- run_cmd "bridge -n sw1 fdb replace $dmac dev swp1 master static vlan 10"
- run_cmd "bridge -n sw1 fdb replace $dmac dev vx0 self static dst 192.0.2.36 src_vni 10010"
+ run_cmd "bridge -n $sw1 fdb replace $dmac dev swp1 master static vlan 10"
+ run_cmd "bridge -n $sw1 fdb replace $dmac dev vx0 self static dst 192.0.2.36 src_vni 10010"
- run_cmd "ip -n sw2 address replace 192.0.2.36/32 dev lo"
+ run_cmd "ip -n $sw2 address replace 192.0.2.36/32 dev lo"
# The first filter matches on packets forwarded using the backup
# nexthop ID and the second filter matches on packets forwarded using a
# regular VXLAN FDB entry.
- run_cmd "tc -n sw2 qdisc replace dev vx0 clsact"
- run_cmd "tc -n sw2 filter replace dev vx0 ingress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac enc_key_id 10010 enc_dst_ip 192.0.2.34 action pass"
- run_cmd "tc -n sw2 filter replace dev vx0 ingress pref 1 handle 102 proto ip flower src_mac $smac dst_mac $dmac enc_key_id 10010 enc_dst_ip 192.0.2.36 action pass"
+ run_cmd "tc -n $sw2 qdisc replace dev vx0 clsact"
+ run_cmd "tc -n $sw2 filter replace dev vx0 ingress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac enc_key_id 10010 enc_dst_ip 192.0.2.34 action pass"
+ run_cmd "tc -n $sw2 filter replace dev vx0 ingress pref 1 handle 102 proto ip flower src_mac $smac dst_mac $dmac enc_key_id 10010 enc_dst_ip 192.0.2.36 action pass"
# Configure vx0 as the backup port of swp1 and check that packets are
# forwarded out of swp1 when it has a carrier and out of vx0 when swp1
# does not have a carrier. When packets are forwarded out of vx0, check
# that they are forwarded by the VXLAN FDB entry.
- run_cmd "bridge -n sw1 link set dev swp1 backup_port vx0"
- run_cmd "bridge -n sw1 -d link show dev swp1 | grep \"backup_port vx0\""
+ run_cmd "bridge -n $sw1 link set dev swp1 backup_port vx0"
+ run_cmd "bridge -n $sw1 -d link show dev swp1 | grep \"backup_port vx0\""
log_test $? 0 "vx0 configured as backup port of swp1"
- run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
- tc_check_packets sw1 "dev swp1 egress" 101 1
+ run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
+ tc_check_packets $sw1 "dev swp1 egress" 101 1
log_test $? 0 "Forwarding out of swp1"
- tc_check_packets sw1 "dev vx0 egress" 101 0
+ tc_check_packets $sw1 "dev vx0 egress" 101 0
log_test $? 0 "No forwarding out of vx0"
- run_cmd "ip -n sw1 link set dev swp1 carrier off"
+ run_cmd "ip -n $sw1 link set dev swp1 carrier off"
log_test $? 0 "swp1 carrier off"
- run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
- tc_check_packets sw1 "dev swp1 egress" 101 1
+ run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
+ tc_check_packets $sw1 "dev swp1 egress" 101 1
log_test $? 0 "No forwarding out of swp1"
- tc_check_packets sw1 "dev vx0 egress" 101 1
+ tc_check_packets $sw1 "dev vx0 egress" 101 1
log_test $? 0 "Forwarding out of vx0"
- tc_check_packets sw2 "dev vx0 ingress" 101 0
+ tc_check_packets $sw2 "dev vx0 ingress" 101 0
log_test $? 0 "No forwarding using backup nexthop ID"
- tc_check_packets sw2 "dev vx0 ingress" 102 1
+ tc_check_packets $sw2 "dev vx0 ingress" 102 1
log_test $? 0 "Forwarding using VXLAN FDB entry"
- run_cmd "ip -n sw1 link set dev swp1 carrier on"
+ run_cmd "ip -n $sw1 link set dev swp1 carrier on"
log_test $? 0 "swp1 carrier on"
# Configure nexthop ID 10 as the backup nexthop ID of swp1 and check
# that when packets are forwarded out of vx0, they are forwarded using
# the backup nexthop ID.
- run_cmd "bridge -n sw1 link set dev swp1 backup_nhid 10"
- run_cmd "bridge -n sw1 -d link show dev swp1 | grep \"backup_nhid 10\""
+ run_cmd "bridge -n $sw1 link set dev swp1 backup_nhid 10"
+ run_cmd "bridge -n $sw1 -d link show dev swp1 | grep \"backup_nhid 10\""
log_test $? 0 "nexthop ID 10 configured as backup nexthop ID of swp1"
- run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
- tc_check_packets sw1 "dev swp1 egress" 101 2
+ run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
+ tc_check_packets $sw1 "dev swp1 egress" 101 2
log_test $? 0 "Forwarding out of swp1"
- tc_check_packets sw1 "dev vx0 egress" 101 1
+ tc_check_packets $sw1 "dev vx0 egress" 101 1
log_test $? 0 "No forwarding out of vx0"
- run_cmd "ip -n sw1 link set dev swp1 carrier off"
+ run_cmd "ip -n $sw1 link set dev swp1 carrier off"
log_test $? 0 "swp1 carrier off"
- run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
- tc_check_packets sw1 "dev swp1 egress" 101 2
+ run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
+ tc_check_packets $sw1 "dev swp1 egress" 101 2
log_test $? 0 "No forwarding out of swp1"
- tc_check_packets sw1 "dev vx0 egress" 101 2
+ tc_check_packets $sw1 "dev vx0 egress" 101 2
log_test $? 0 "Forwarding out of vx0"
- tc_check_packets sw2 "dev vx0 ingress" 101 1
+ tc_check_packets $sw2 "dev vx0 ingress" 101 1
log_test $? 0 "Forwarding using backup nexthop ID"
- tc_check_packets sw2 "dev vx0 ingress" 102 1
+ tc_check_packets $sw2 "dev vx0 ingress" 102 1
log_test $? 0 "No forwarding using VXLAN FDB entry"
- run_cmd "ip -n sw1 link set dev swp1 carrier on"
+ run_cmd "ip -n $sw1 link set dev swp1 carrier on"
log_test $? 0 "swp1 carrier on"
- run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
- tc_check_packets sw1 "dev swp1 egress" 101 3
+ run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
+ tc_check_packets $sw1 "dev swp1 egress" 101 3
log_test $? 0 "Forwarding out of swp1"
- tc_check_packets sw1 "dev vx0 egress" 101 2
+ tc_check_packets $sw1 "dev vx0 egress" 101 2
log_test $? 0 "No forwarding out of vx0"
- tc_check_packets sw2 "dev vx0 ingress" 101 1
+ tc_check_packets $sw2 "dev vx0 ingress" 101 1
log_test $? 0 "No forwarding using backup nexthop ID"
- tc_check_packets sw2 "dev vx0 ingress" 102 1
+ tc_check_packets $sw2 "dev vx0 ingress" 102 1
log_test $? 0 "No forwarding using VXLAN FDB entry"
# Reset the backup nexthop ID to 0 and check that packets are no longer
# forwarded using the backup nexthop ID when swp1 does not have a
# carrier and are instead forwarded by the VXLAN FDB.
- run_cmd "bridge -n sw1 link set dev swp1 backup_nhid 0"
- run_cmd "bridge -n sw1 -d link show dev swp1 | grep \"backup_nhid\""
+ run_cmd "bridge -n $sw1 link set dev swp1 backup_nhid 0"
+ run_cmd "bridge -n $sw1 -d link show dev swp1 | grep \"backup_nhid\""
log_test $? 1 "No backup nexthop ID configured for swp1"
- run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
- tc_check_packets sw1 "dev swp1 egress" 101 4
+ run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
+ tc_check_packets $sw1 "dev swp1 egress" 101 4
log_test $? 0 "Forwarding out of swp1"
- tc_check_packets sw1 "dev vx0 egress" 101 2
+ tc_check_packets $sw1 "dev vx0 egress" 101 2
log_test $? 0 "No forwarding out of vx0"
- tc_check_packets sw2 "dev vx0 ingress" 101 1
+ tc_check_packets $sw2 "dev vx0 ingress" 101 1
log_test $? 0 "No forwarding using backup nexthop ID"
- tc_check_packets sw2 "dev vx0 ingress" 102 1
+ tc_check_packets $sw2 "dev vx0 ingress" 102 1
log_test $? 0 "No forwarding using VXLAN FDB entry"
- run_cmd "ip -n sw1 link set dev swp1 carrier off"
+ run_cmd "ip -n $sw1 link set dev swp1 carrier off"
log_test $? 0 "swp1 carrier off"
- run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
- tc_check_packets sw1 "dev swp1 egress" 101 4
+ run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
+ tc_check_packets $sw1 "dev swp1 egress" 101 4
log_test $? 0 "No forwarding out of swp1"
- tc_check_packets sw1 "dev vx0 egress" 101 3
+ tc_check_packets $sw1 "dev vx0 egress" 101 3
log_test $? 0 "Forwarding out of vx0"
- tc_check_packets sw2 "dev vx0 ingress" 101 1
+ tc_check_packets $sw2 "dev vx0 ingress" 101 1
log_test $? 0 "No forwarding using backup nexthop ID"
- tc_check_packets sw2 "dev vx0 ingress" 102 2
+ tc_check_packets $sw2 "dev vx0 ingress" 102 2
log_test $? 0 "Forwarding using VXLAN FDB entry"
}
@@ -475,109 +468,109 @@ backup_nhid_invalid()
# is forwarded out of the VXLAN port, but dropped by the VXLAN driver
# and does not crash the host.
- run_cmd "tc -n sw1 qdisc replace dev swp1 clsact"
- run_cmd "tc -n sw1 filter replace dev swp1 egress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac action pass"
+ run_cmd "tc -n $sw1 qdisc replace dev swp1 clsact"
+ run_cmd "tc -n $sw1 filter replace dev swp1 egress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac action pass"
- run_cmd "tc -n sw1 qdisc replace dev vx0 clsact"
- run_cmd "tc -n sw1 filter replace dev vx0 egress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac action pass"
+ run_cmd "tc -n $sw1 qdisc replace dev vx0 clsact"
+ run_cmd "tc -n $sw1 filter replace dev vx0 egress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac action pass"
# Drop all other Tx traffic to avoid changes to Tx drop counter.
- run_cmd "tc -n sw1 filter replace dev vx0 egress pref 2 handle 102 proto all matchall action drop"
+ run_cmd "tc -n $sw1 filter replace dev vx0 egress pref 2 handle 102 proto all matchall action drop"
- tx_drop=$(ip -n sw1 -s -j link show dev vx0 | jq '.[]["stats64"]["tx"]["dropped"]')
+ tx_drop=$(ip -n $sw1 -s -j link show dev vx0 | jq '.[]["stats64"]["tx"]["dropped"]')
- run_cmd "ip -n sw1 nexthop replace id 1 via 192.0.2.34 fdb"
- run_cmd "ip -n sw1 nexthop replace id 2 via 192.0.2.34 fdb"
- run_cmd "ip -n sw1 nexthop replace id 10 group 1/2 fdb"
+ run_cmd "ip -n $sw1 nexthop replace id 1 via 192.0.2.34 fdb"
+ run_cmd "ip -n $sw1 nexthop replace id 2 via 192.0.2.34 fdb"
+ run_cmd "ip -n $sw1 nexthop replace id 10 group 1/2 fdb"
- run_cmd "bridge -n sw1 fdb replace $dmac dev swp1 master static vlan 10"
+ run_cmd "bridge -n $sw1 fdb replace $dmac dev swp1 master static vlan 10"
- run_cmd "tc -n sw2 qdisc replace dev vx0 clsact"
- run_cmd "tc -n sw2 filter replace dev vx0 ingress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac enc_key_id 10010 enc_dst_ip 192.0.2.34 action pass"
+ run_cmd "tc -n $sw2 qdisc replace dev vx0 clsact"
+ run_cmd "tc -n $sw2 filter replace dev vx0 ingress pref 1 handle 101 proto ip flower src_mac $smac dst_mac $dmac enc_key_id 10010 enc_dst_ip 192.0.2.34 action pass"
# First, check that redirection works.
- run_cmd "bridge -n sw1 link set dev swp1 backup_port vx0"
- run_cmd "bridge -n sw1 -d link show dev swp1 | grep \"backup_port vx0\""
+ run_cmd "bridge -n $sw1 link set dev swp1 backup_port vx0"
+ run_cmd "bridge -n $sw1 -d link show dev swp1 | grep \"backup_port vx0\""
log_test $? 0 "vx0 configured as backup port of swp1"
- run_cmd "bridge -n sw1 link set dev swp1 backup_nhid 10"
- run_cmd "bridge -n sw1 -d link show dev swp1 | grep \"backup_nhid 10\""
+ run_cmd "bridge -n $sw1 link set dev swp1 backup_nhid 10"
+ run_cmd "bridge -n $sw1 -d link show dev swp1 | grep \"backup_nhid 10\""
log_test $? 0 "Valid nexthop as backup nexthop"
- run_cmd "ip -n sw1 link set dev swp1 carrier off"
+ run_cmd "ip -n $sw1 link set dev swp1 carrier off"
log_test $? 0 "swp1 carrier off"
- run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
- tc_check_packets sw1 "dev swp1 egress" 101 0
+ run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
+ tc_check_packets $sw1 "dev swp1 egress" 101 0
log_test $? 0 "No forwarding out of swp1"
- tc_check_packets sw1 "dev vx0 egress" 101 1
+ tc_check_packets $sw1 "dev vx0 egress" 101 1
log_test $? 0 "Forwarding out of vx0"
- tc_check_packets sw2 "dev vx0 ingress" 101 1
+ tc_check_packets $sw2 "dev vx0 ingress" 101 1
log_test $? 0 "Forwarding using backup nexthop ID"
- run_cmd "ip -n sw1 -s -j link show dev vx0 | jq -e '.[][\"stats64\"][\"tx\"][\"dropped\"] == $tx_drop'"
+ run_cmd "ip -n $sw1 -s -j link show dev vx0 | jq -e '.[][\"stats64\"][\"tx\"][\"dropped\"] == $tx_drop'"
log_test $? 0 "No Tx drop increase"
# Use a non-existent nexthop ID.
- run_cmd "bridge -n sw1 link set dev swp1 backup_nhid 20"
- run_cmd "bridge -n sw1 -d link show dev swp1 | grep \"backup_nhid 20\""
+ run_cmd "bridge -n $sw1 link set dev swp1 backup_nhid 20"
+ run_cmd "bridge -n $sw1 -d link show dev swp1 | grep \"backup_nhid 20\""
log_test $? 0 "Non-existent nexthop as backup nexthop"
- run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
- tc_check_packets sw1 "dev swp1 egress" 101 0
+ run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
+ tc_check_packets $sw1 "dev swp1 egress" 101 0
log_test $? 0 "No forwarding out of swp1"
- tc_check_packets sw1 "dev vx0 egress" 101 2
+ tc_check_packets $sw1 "dev vx0 egress" 101 2
log_test $? 0 "Forwarding out of vx0"
- tc_check_packets sw2 "dev vx0 ingress" 101 1
+ tc_check_packets $sw2 "dev vx0 ingress" 101 1
log_test $? 0 "No forwarding using backup nexthop ID"
- run_cmd "ip -n sw1 -s -j link show dev vx0 | jq -e '.[][\"stats64\"][\"tx\"][\"dropped\"] == $((tx_drop + 1))'"
+ run_cmd "ip -n $sw1 -s -j link show dev vx0 | jq -e '.[][\"stats64\"][\"tx\"][\"dropped\"] == $((tx_drop + 1))'"
log_test $? 0 "Tx drop increased"
# Use a blckhole nexthop.
- run_cmd "ip -n sw1 nexthop replace id 30 blackhole"
- run_cmd "bridge -n sw1 link set dev swp1 backup_nhid 30"
- run_cmd "bridge -n sw1 -d link show dev swp1 | grep \"backup_nhid 30\""
+ run_cmd "ip -n $sw1 nexthop replace id 30 blackhole"
+ run_cmd "bridge -n $sw1 link set dev swp1 backup_nhid 30"
+ run_cmd "bridge -n $sw1 -d link show dev swp1 | grep \"backup_nhid 30\""
log_test $? 0 "Blackhole nexthop as backup nexthop"
- run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
- tc_check_packets sw1 "dev swp1 egress" 101 0
+ run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
+ tc_check_packets $sw1 "dev swp1 egress" 101 0
log_test $? 0 "No forwarding out of swp1"
- tc_check_packets sw1 "dev vx0 egress" 101 3
+ tc_check_packets $sw1 "dev vx0 egress" 101 3
log_test $? 0 "Forwarding out of vx0"
- tc_check_packets sw2 "dev vx0 ingress" 101 1
+ tc_check_packets $sw2 "dev vx0 ingress" 101 1
log_test $? 0 "No forwarding using backup nexthop ID"
- run_cmd "ip -n sw1 -s -j link show dev vx0 | jq -e '.[][\"stats64\"][\"tx\"][\"dropped\"] == $((tx_drop + 2))'"
+ run_cmd "ip -n $sw1 -s -j link show dev vx0 | jq -e '.[][\"stats64\"][\"tx\"][\"dropped\"] == $((tx_drop + 2))'"
log_test $? 0 "Tx drop increased"
# Non-group FDB nexthop.
- run_cmd "bridge -n sw1 link set dev swp1 backup_nhid 1"
- run_cmd "bridge -n sw1 -d link show dev swp1 | grep \"backup_nhid 1\""
+ run_cmd "bridge -n $sw1 link set dev swp1 backup_nhid 1"
+ run_cmd "bridge -n $sw1 -d link show dev swp1 | grep \"backup_nhid 1\""
log_test $? 0 "Non-group FDB nexthop as backup nexthop"
- run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
- tc_check_packets sw1 "dev swp1 egress" 101 0
+ run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
+ tc_check_packets $sw1 "dev swp1 egress" 101 0
log_test $? 0 "No forwarding out of swp1"
- tc_check_packets sw1 "dev vx0 egress" 101 4
+ tc_check_packets $sw1 "dev vx0 egress" 101 4
log_test $? 0 "Forwarding out of vx0"
- tc_check_packets sw2 "dev vx0 ingress" 101 1
+ tc_check_packets $sw2 "dev vx0 ingress" 101 1
log_test $? 0 "No forwarding using backup nexthop ID"
- run_cmd "ip -n sw1 -s -j link show dev vx0 | jq -e '.[][\"stats64\"][\"tx\"][\"dropped\"] == $((tx_drop + 3))'"
+ run_cmd "ip -n $sw1 -s -j link show dev vx0 | jq -e '.[][\"stats64\"][\"tx\"][\"dropped\"] == $((tx_drop + 3))'"
log_test $? 0 "Tx drop increased"
# IPv6 address family nexthop.
- run_cmd "ip -n sw1 nexthop replace id 100 via 2001:db8:100::1 fdb"
- run_cmd "ip -n sw1 nexthop replace id 200 via 2001:db8:100::1 fdb"
- run_cmd "ip -n sw1 nexthop replace id 300 group 100/200 fdb"
- run_cmd "bridge -n sw1 link set dev swp1 backup_nhid 300"
- run_cmd "bridge -n sw1 -d link show dev swp1 | grep \"backup_nhid 300\""
+ run_cmd "ip -n $sw1 nexthop replace id 100 via 2001:db8:100::1 fdb"
+ run_cmd "ip -n $sw1 nexthop replace id 200 via 2001:db8:100::1 fdb"
+ run_cmd "ip -n $sw1 nexthop replace id 300 group 100/200 fdb"
+ run_cmd "bridge -n $sw1 link set dev swp1 backup_nhid 300"
+ run_cmd "bridge -n $sw1 -d link show dev swp1 | grep \"backup_nhid 300\""
log_test $? 0 "IPv6 address family nexthop as backup nexthop"
- run_cmd "ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
- tc_check_packets sw1 "dev swp1 egress" 101 0
+ run_cmd "ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 1"
+ tc_check_packets $sw1 "dev swp1 egress" 101 0
log_test $? 0 "No forwarding out of swp1"
- tc_check_packets sw1 "dev vx0 egress" 101 5
+ tc_check_packets $sw1 "dev vx0 egress" 101 5
log_test $? 0 "Forwarding out of vx0"
- tc_check_packets sw2 "dev vx0 ingress" 101 1
+ tc_check_packets $sw2 "dev vx0 ingress" 101 1
log_test $? 0 "No forwarding using backup nexthop ID"
- run_cmd "ip -n sw1 -s -j link show dev vx0 | jq -e '.[][\"stats64\"][\"tx\"][\"dropped\"] == $((tx_drop + 4))'"
+ run_cmd "ip -n $sw1 -s -j link show dev vx0 | jq -e '.[][\"stats64\"][\"tx\"][\"dropped\"] == $((tx_drop + 4))'"
log_test $? 0 "Tx drop increased"
}
@@ -591,44 +584,44 @@ backup_nhid_ping()
echo "------------------------"
# Test bidirectional traffic when traffic is redirected in both VTEPs.
- sw1_mac=$(ip -n sw1 -j -p link show br0.10 | jq -r '.[]["address"]')
- sw2_mac=$(ip -n sw2 -j -p link show br0.10 | jq -r '.[]["address"]')
+ sw1_mac=$(ip -n $sw1 -j -p link show br0.10 | jq -r '.[]["address"]')
+ sw2_mac=$(ip -n $sw2 -j -p link show br0.10 | jq -r '.[]["address"]')
- run_cmd "bridge -n sw1 fdb replace $sw2_mac dev swp1 master static vlan 10"
- run_cmd "bridge -n sw2 fdb replace $sw1_mac dev swp1 master static vlan 10"
+ run_cmd "bridge -n $sw1 fdb replace $sw2_mac dev swp1 master static vlan 10"
+ run_cmd "bridge -n $sw2 fdb replace $sw1_mac dev swp1 master static vlan 10"
- run_cmd "ip -n sw1 neigh replace 192.0.2.66 lladdr $sw2_mac nud perm dev br0.10"
- run_cmd "ip -n sw2 neigh replace 192.0.2.65 lladdr $sw1_mac nud perm dev br0.10"
+ run_cmd "ip -n $sw1 neigh replace 192.0.2.66 lladdr $sw2_mac nud perm dev br0.10"
+ run_cmd "ip -n $sw2 neigh replace 192.0.2.65 lladdr $sw1_mac nud perm dev br0.10"
- run_cmd "ip -n sw1 nexthop replace id 1 via 192.0.2.34 fdb"
- run_cmd "ip -n sw2 nexthop replace id 1 via 192.0.2.33 fdb"
- run_cmd "ip -n sw1 nexthop replace id 10 group 1 fdb"
- run_cmd "ip -n sw2 nexthop replace id 10 group 1 fdb"
+ run_cmd "ip -n $sw1 nexthop replace id 1 via 192.0.2.34 fdb"
+ run_cmd "ip -n $sw2 nexthop replace id 1 via 192.0.2.33 fdb"
+ run_cmd "ip -n $sw1 nexthop replace id 10 group 1 fdb"
+ run_cmd "ip -n $sw2 nexthop replace id 10 group 1 fdb"
- run_cmd "bridge -n sw1 link set dev swp1 backup_port vx0"
- run_cmd "bridge -n sw2 link set dev swp1 backup_port vx0"
- run_cmd "bridge -n sw1 link set dev swp1 backup_nhid 10"
- run_cmd "bridge -n sw2 link set dev swp1 backup_nhid 10"
+ run_cmd "bridge -n $sw1 link set dev swp1 backup_port vx0"
+ run_cmd "bridge -n $sw2 link set dev swp1 backup_port vx0"
+ run_cmd "bridge -n $sw1 link set dev swp1 backup_nhid 10"
+ run_cmd "bridge -n $sw2 link set dev swp1 backup_nhid 10"
- run_cmd "ip -n sw1 link set dev swp1 carrier off"
- run_cmd "ip -n sw2 link set dev swp1 carrier off"
+ run_cmd "ip -n $sw1 link set dev swp1 carrier off"
+ run_cmd "ip -n $sw2 link set dev swp1 carrier off"
- run_cmd "ip netns exec sw1 ping -i 0.1 -c 10 -w $PING_TIMEOUT 192.0.2.66"
+ run_cmd "ip netns exec $sw1 ping -i 0.1 -c 10 -w $PING_TIMEOUT 192.0.2.66"
log_test $? 0 "Ping with backup nexthop ID"
# Reset the backup nexthop ID to 0 and check that ping fails.
- run_cmd "bridge -n sw1 link set dev swp1 backup_nhid 0"
- run_cmd "bridge -n sw2 link set dev swp1 backup_nhid 0"
+ run_cmd "bridge -n $sw1 link set dev swp1 backup_nhid 0"
+ run_cmd "bridge -n $sw2 link set dev swp1 backup_nhid 0"
- run_cmd "ip netns exec sw1 ping -i 0.1 -c 10 -w $PING_TIMEOUT 192.0.2.66"
+ run_cmd "ip netns exec $sw1 ping -i 0.1 -c 10 -w $PING_TIMEOUT 192.0.2.66"
log_test $? 1 "Ping after disabling backup nexthop ID"
}
backup_nhid_add_del_loop()
{
while true; do
- ip -n sw1 nexthop del id 10
- ip -n sw1 nexthop replace id 10 group 1/2 fdb
+ ip -n $sw1 nexthop del id 10
+ ip -n $sw1 nexthop replace id 10 group 1/2 fdb
done >/dev/null 2>&1
}
@@ -648,19 +641,19 @@ backup_nhid_torture()
# deleting the group. The test is considered successful if nothing
# crashed.
- run_cmd "ip -n sw1 nexthop replace id 1 via 192.0.2.34 fdb"
- run_cmd "ip -n sw1 nexthop replace id 2 via 192.0.2.34 fdb"
- run_cmd "ip -n sw1 nexthop replace id 10 group 1/2 fdb"
+ run_cmd "ip -n $sw1 nexthop replace id 1 via 192.0.2.34 fdb"
+ run_cmd "ip -n $sw1 nexthop replace id 2 via 192.0.2.34 fdb"
+ run_cmd "ip -n $sw1 nexthop replace id 10 group 1/2 fdb"
- run_cmd "bridge -n sw1 fdb replace $dmac dev swp1 master static vlan 10"
+ run_cmd "bridge -n $sw1 fdb replace $dmac dev swp1 master static vlan 10"
- run_cmd "bridge -n sw1 link set dev swp1 backup_port vx0"
- run_cmd "bridge -n sw1 link set dev swp1 backup_nhid 10"
- run_cmd "ip -n sw1 link set dev swp1 carrier off"
+ run_cmd "bridge -n $sw1 link set dev swp1 backup_port vx0"
+ run_cmd "bridge -n $sw1 link set dev swp1 backup_nhid 10"
+ run_cmd "ip -n $sw1 link set dev swp1 carrier off"
backup_nhid_add_del_loop &
pid1=$!
- ip netns exec sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 0 &
+ ip netns exec $sw1 mausezahn br0.10 -a $smac -b $dmac -A 198.51.100.1 -B 198.51.100.2 -t ip -p 100 -q -c 0 &
pid2=$!
sleep 30
diff --git a/tools/testing/selftests/net/test_bridge_neigh_suppress.sh b/tools/testing/selftests/net/test_bridge_neigh_suppress.sh
index d80f2cd87614..8533393a4f18 100755
--- a/tools/testing/selftests/net/test_bridge_neigh_suppress.sh
+++ b/tools/testing/selftests/net/test_bridge_neigh_suppress.sh
@@ -45,9 +45,8 @@
# | sw1 | | sw2 |
# +------------------------------------+ +------------------------------------+
+source lib.sh
ret=0
-# Kselftest framework requirement - SKIP code is 4.
-ksft_skip=4
# All tests in this script. Can be overridden with -t option.
TESTS="
@@ -140,9 +139,6 @@ setup_topo_ns()
{
local ns=$1; shift
- ip netns add $ns
- ip -n $ns link set dev lo up
-
ip netns exec $ns sysctl -qw net.ipv6.conf.all.keep_addr_on_down=1
ip netns exec $ns sysctl -qw net.ipv6.conf.default.ignore_routes_with_linkdown=1
ip netns exec $ns sysctl -qw net.ipv6.conf.all.accept_dad=0
@@ -153,21 +149,22 @@ setup_topo()
{
local ns
- for ns in h1 h2 sw1 sw2; do
+ setup_ns h1 h2 sw1 sw2
+ for ns in $h1 $h2 $sw1 $sw2; do
setup_topo_ns $ns
done
ip link add name veth0 type veth peer name veth1
- ip link set dev veth0 netns h1 name eth0
- ip link set dev veth1 netns sw1 name swp1
+ ip link set dev veth0 netns $h1 name eth0
+ ip link set dev veth1 netns $sw1 name swp1
ip link add name veth0 type veth peer name veth1
- ip link set dev veth0 netns sw1 name veth0
- ip link set dev veth1 netns sw2 name veth0
+ ip link set dev veth0 netns $sw1 name veth0
+ ip link set dev veth1 netns $sw2 name veth0
ip link add name veth0 type veth peer name veth1
- ip link set dev veth0 netns h2 name eth0
- ip link set dev veth1 netns sw2 name swp1
+ ip link set dev veth0 netns $h2 name eth0
+ ip link set dev veth1 netns $sw2 name swp1
}
setup_host_common()
@@ -190,7 +187,7 @@ setup_host_common()
setup_h1()
{
- local ns=h1
+ local ns=$h1
local v4addr1=192.0.2.1/28
local v4addr2=192.0.2.17/28
local v6addr1=2001:db8:1::1/64
@@ -201,7 +198,7 @@ setup_h1()
setup_h2()
{
- local ns=h2
+ local ns=$h2
local v4addr1=192.0.2.2/28
local v4addr2=192.0.2.18/28
local v6addr1=2001:db8:1::2/64
@@ -254,7 +251,7 @@ setup_sw_common()
setup_sw1()
{
- local ns=sw1
+ local ns=$sw1
local local_addr=192.0.2.33
local remote_addr=192.0.2.34
local veth_addr=192.0.2.49
@@ -265,7 +262,7 @@ setup_sw1()
setup_sw2()
{
- local ns=sw2
+ local ns=$sw2
local local_addr=192.0.2.34
local remote_addr=192.0.2.33
local veth_addr=192.0.2.50
@@ -291,11 +288,7 @@ setup()
cleanup()
{
- local ns
-
- for ns in h1 h2 sw1 sw2; do
- ip netns del $ns &> /dev/null
- done
+ cleanup_ns $h1 $h2 $sw1 $sw2
}
################################################################################
@@ -312,80 +305,80 @@ neigh_suppress_arp_common()
echo "Per-port ARP suppression - VLAN $vid"
echo "----------------------------------"
- run_cmd "tc -n sw1 qdisc replace dev vx0 clsact"
- run_cmd "tc -n sw1 filter replace dev vx0 egress pref 1 handle 101 proto 0x0806 flower indev swp1 arp_tip $tip arp_sip $sip arp_op request action pass"
+ run_cmd "tc -n $sw1 qdisc replace dev vx0 clsact"
+ run_cmd "tc -n $sw1 filter replace dev vx0 egress pref 1 handle 101 proto 0x0806 flower indev swp1 arp_tip $tip arp_sip $sip arp_op request action pass"
# Initial state - check that ARP requests are not suppressed and that
# ARP replies are received.
- run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip -I eth0.$vid $tip"
+ run_cmd "ip netns exec $h1 arping -q -b -c 1 -w 5 -s $sip -I eth0.$vid $tip"
log_test $? 0 "arping"
- tc_check_packets sw1 "dev vx0 egress" 101 1
+ tc_check_packets $sw1 "dev vx0 egress" 101 1
log_test $? 0 "ARP suppression"
# Enable neighbor suppression and check that nothing changes compared
# to the initial state.
- run_cmd "bridge -n sw1 link set dev vx0 neigh_suppress on"
- run_cmd "bridge -n sw1 -d link show dev vx0 | grep \"neigh_suppress on\""
+ run_cmd "bridge -n $sw1 link set dev vx0 neigh_suppress on"
+ run_cmd "bridge -n $sw1 -d link show dev vx0 | grep \"neigh_suppress on\""
log_test $? 0 "\"neigh_suppress\" is on"
- run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip -I eth0.$vid $tip"
+ run_cmd "ip netns exec $h1 arping -q -b -c 1 -w 5 -s $sip -I eth0.$vid $tip"
log_test $? 0 "arping"
- tc_check_packets sw1 "dev vx0 egress" 101 2
+ tc_check_packets $sw1 "dev vx0 egress" 101 2
log_test $? 0 "ARP suppression"
# Install an FDB entry for the remote host and check that nothing
# changes compared to the initial state.
- h2_mac=$(ip -n h2 -j -p link show eth0.$vid | jq -r '.[]["address"]')
- run_cmd "bridge -n sw1 fdb replace $h2_mac dev vx0 master static vlan $vid"
+ h2_mac=$(ip -n $h2 -j -p link show eth0.$vid | jq -r '.[]["address"]')
+ run_cmd "bridge -n $sw1 fdb replace $h2_mac dev vx0 master static vlan $vid"
log_test $? 0 "FDB entry installation"
- run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip -I eth0.$vid $tip"
+ run_cmd "ip netns exec $h1 arping -q -b -c 1 -w 5 -s $sip -I eth0.$vid $tip"
log_test $? 0 "arping"
- tc_check_packets sw1 "dev vx0 egress" 101 3
+ tc_check_packets $sw1 "dev vx0 egress" 101 3
log_test $? 0 "ARP suppression"
# Install a neighbor on the matching SVI interface and check that ARP
# requests are suppressed.
- run_cmd "ip -n sw1 neigh replace $tip lladdr $h2_mac nud permanent dev br0.$vid"
+ run_cmd "ip -n $sw1 neigh replace $tip lladdr $h2_mac nud permanent dev br0.$vid"
log_test $? 0 "Neighbor entry installation"
- run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip -I eth0.$vid $tip"
+ run_cmd "ip netns exec $h1 arping -q -b -c 1 -w 5 -s $sip -I eth0.$vid $tip"
log_test $? 0 "arping"
- tc_check_packets sw1 "dev vx0 egress" 101 3
+ tc_check_packets $sw1 "dev vx0 egress" 101 3
log_test $? 0 "ARP suppression"
# Take the second host down and check that ARP requests are suppressed
# and that ARP replies are received.
- run_cmd "ip -n h2 link set dev eth0.$vid down"
+ run_cmd "ip -n $h2 link set dev eth0.$vid down"
log_test $? 0 "H2 down"
- run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip -I eth0.$vid $tip"
+ run_cmd "ip netns exec $h1 arping -q -b -c 1 -w 5 -s $sip -I eth0.$vid $tip"
log_test $? 0 "arping"
- tc_check_packets sw1 "dev vx0 egress" 101 3
+ tc_check_packets $sw1 "dev vx0 egress" 101 3
log_test $? 0 "ARP suppression"
- run_cmd "ip -n h2 link set dev eth0.$vid up"
+ run_cmd "ip -n $h2 link set dev eth0.$vid up"
log_test $? 0 "H2 up"
# Disable neighbor suppression and check that ARP requests are no
# longer suppressed.
- run_cmd "bridge -n sw1 link set dev vx0 neigh_suppress off"
- run_cmd "bridge -n sw1 -d link show dev vx0 | grep \"neigh_suppress off\""
+ run_cmd "bridge -n $sw1 link set dev vx0 neigh_suppress off"
+ run_cmd "bridge -n $sw1 -d link show dev vx0 | grep \"neigh_suppress off\""
log_test $? 0 "\"neigh_suppress\" is off"
- run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip -I eth0.$vid $tip"
+ run_cmd "ip netns exec $h1 arping -q -b -c 1 -w 5 -s $sip -I eth0.$vid $tip"
log_test $? 0 "arping"
- tc_check_packets sw1 "dev vx0 egress" 101 4
+ tc_check_packets $sw1 "dev vx0 egress" 101 4
log_test $? 0 "ARP suppression"
# Take the second host down and check that ARP requests are not
# suppressed and that ARP replies are not received.
- run_cmd "ip -n h2 link set dev eth0.$vid down"
+ run_cmd "ip -n $h2 link set dev eth0.$vid down"
log_test $? 0 "H2 down"
- run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip -I eth0.$vid $tip"
+ run_cmd "ip netns exec $h1 arping -q -b -c 1 -w 5 -s $sip -I eth0.$vid $tip"
log_test $? 1 "arping"
- tc_check_packets sw1 "dev vx0 egress" 101 5
+ tc_check_packets $sw1 "dev vx0 egress" 101 5
log_test $? 0 "ARP suppression"
}
@@ -415,80 +408,80 @@ neigh_suppress_ns_common()
echo "Per-port NS suppression - VLAN $vid"
echo "---------------------------------"
- run_cmd "tc -n sw1 qdisc replace dev vx0 clsact"
- run_cmd "tc -n sw1 filter replace dev vx0 egress pref 1 handle 101 proto ipv6 flower indev swp1 ip_proto icmpv6 dst_ip $maddr src_ip $saddr type 135 code 0 action pass"
+ run_cmd "tc -n $sw1 qdisc replace dev vx0 clsact"
+ run_cmd "tc -n $sw1 filter replace dev vx0 egress pref 1 handle 101 proto ipv6 flower indev swp1 ip_proto icmpv6 dst_ip $maddr src_ip $saddr type 135 code 0 action pass"
# Initial state - check that NS messages are not suppressed and that ND
# messages are received.
- run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr -w 5000 $daddr eth0.$vid"
+ run_cmd "ip netns exec $h1 ndisc6 -q -r 1 -s $saddr -w 5000 $daddr eth0.$vid"
log_test $? 0 "ndisc6"
- tc_check_packets sw1 "dev vx0 egress" 101 1
+ tc_check_packets $sw1 "dev vx0 egress" 101 1
log_test $? 0 "NS suppression"
# Enable neighbor suppression and check that nothing changes compared
# to the initial state.
- run_cmd "bridge -n sw1 link set dev vx0 neigh_suppress on"
- run_cmd "bridge -n sw1 -d link show dev vx0 | grep \"neigh_suppress on\""
+ run_cmd "bridge -n $sw1 link set dev vx0 neigh_suppress on"
+ run_cmd "bridge -n $sw1 -d link show dev vx0 | grep \"neigh_suppress on\""
log_test $? 0 "\"neigh_suppress\" is on"
- run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr -w 5000 $daddr eth0.$vid"
+ run_cmd "ip netns exec $h1 ndisc6 -q -r 1 -s $saddr -w 5000 $daddr eth0.$vid"
log_test $? 0 "ndisc6"
- tc_check_packets sw1 "dev vx0 egress" 101 2
+ tc_check_packets $sw1 "dev vx0 egress" 101 2
log_test $? 0 "NS suppression"
# Install an FDB entry for the remote host and check that nothing
# changes compared to the initial state.
- h2_mac=$(ip -n h2 -j -p link show eth0.$vid | jq -r '.[]["address"]')
- run_cmd "bridge -n sw1 fdb replace $h2_mac dev vx0 master static vlan $vid"
+ h2_mac=$(ip -n $h2 -j -p link show eth0.$vid | jq -r '.[]["address"]')
+ run_cmd "bridge -n $sw1 fdb replace $h2_mac dev vx0 master static vlan $vid"
log_test $? 0 "FDB entry installation"
- run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr -w 5000 $daddr eth0.$vid"
+ run_cmd "ip netns exec $h1 ndisc6 -q -r 1 -s $saddr -w 5000 $daddr eth0.$vid"
log_test $? 0 "ndisc6"
- tc_check_packets sw1 "dev vx0 egress" 101 3
+ tc_check_packets $sw1 "dev vx0 egress" 101 3
log_test $? 0 "NS suppression"
# Install a neighbor on the matching SVI interface and check that NS
# messages are suppressed.
- run_cmd "ip -n sw1 neigh replace $daddr lladdr $h2_mac nud permanent dev br0.$vid"
+ run_cmd "ip -n $sw1 neigh replace $daddr lladdr $h2_mac nud permanent dev br0.$vid"
log_test $? 0 "Neighbor entry installation"
- run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr -w 5000 $daddr eth0.$vid"
+ run_cmd "ip netns exec $h1 ndisc6 -q -r 1 -s $saddr -w 5000 $daddr eth0.$vid"
log_test $? 0 "ndisc6"
- tc_check_packets sw1 "dev vx0 egress" 101 3
+ tc_check_packets $sw1 "dev vx0 egress" 101 3
log_test $? 0 "NS suppression"
# Take the second host down and check that NS messages are suppressed
# and that ND messages are received.
- run_cmd "ip -n h2 link set dev eth0.$vid down"
+ run_cmd "ip -n $h2 link set dev eth0.$vid down"
log_test $? 0 "H2 down"
- run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr -w 5000 $daddr eth0.$vid"
+ run_cmd "ip netns exec $h1 ndisc6 -q -r 1 -s $saddr -w 5000 $daddr eth0.$vid"
log_test $? 0 "ndisc6"
- tc_check_packets sw1 "dev vx0 egress" 101 3
+ tc_check_packets $sw1 "dev vx0 egress" 101 3
log_test $? 0 "NS suppression"
- run_cmd "ip -n h2 link set dev eth0.$vid up"
+ run_cmd "ip -n $h2 link set dev eth0.$vid up"
log_test $? 0 "H2 up"
# Disable neighbor suppression and check that NS messages are no longer
# suppressed.
- run_cmd "bridge -n sw1 link set dev vx0 neigh_suppress off"
- run_cmd "bridge -n sw1 -d link show dev vx0 | grep \"neigh_suppress off\""
+ run_cmd "bridge -n $sw1 link set dev vx0 neigh_suppress off"
+ run_cmd "bridge -n $sw1 -d link show dev vx0 | grep \"neigh_suppress off\""
log_test $? 0 "\"neigh_suppress\" is off"
- run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr -w 5000 $daddr eth0.$vid"
+ run_cmd "ip netns exec $h1 ndisc6 -q -r 1 -s $saddr -w 5000 $daddr eth0.$vid"
log_test $? 0 "ndisc6"
- tc_check_packets sw1 "dev vx0 egress" 101 4
+ tc_check_packets $sw1 "dev vx0 egress" 101 4
log_test $? 0 "NS suppression"
# Take the second host down and check that NS messages are not
# suppressed and that ND messages are not received.
- run_cmd "ip -n h2 link set dev eth0.$vid down"
+ run_cmd "ip -n $h2 link set dev eth0.$vid down"
log_test $? 0 "H2 down"
- run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr -w 5000 $daddr eth0.$vid"
+ run_cmd "ip netns exec $h1 ndisc6 -q -r 1 -s $saddr -w 5000 $daddr eth0.$vid"
log_test $? 2 "ndisc6"
- tc_check_packets sw1 "dev vx0 egress" 101 5
+ tc_check_packets $sw1 "dev vx0 egress" 101 5
log_test $? 0 "NS suppression"
}
@@ -524,118 +517,118 @@ neigh_vlan_suppress_arp()
echo "Per-{Port, VLAN} ARP suppression"
echo "--------------------------------"
- run_cmd "tc -n sw1 qdisc replace dev vx0 clsact"
- run_cmd "tc -n sw1 filter replace dev vx0 egress pref 1 handle 101 proto 0x0806 flower indev swp1 arp_tip $tip1 arp_sip $sip1 arp_op request action pass"
- run_cmd "tc -n sw1 filter replace dev vx0 egress pref 1 handle 102 proto 0x0806 flower indev swp1 arp_tip $tip2 arp_sip $sip2 arp_op request action pass"
+ run_cmd "tc -n $sw1 qdisc replace dev vx0 clsact"
+ run_cmd "tc -n $sw1 filter replace dev vx0 egress pref 1 handle 101 proto 0x0806 flower indev swp1 arp_tip $tip1 arp_sip $sip1 arp_op request action pass"
+ run_cmd "tc -n $sw1 filter replace dev vx0 egress pref 1 handle 102 proto 0x0806 flower indev swp1 arp_tip $tip2 arp_sip $sip2 arp_op request action pass"
- h2_mac1=$(ip -n h2 -j -p link show eth0.$vid1 | jq -r '.[]["address"]')
- h2_mac2=$(ip -n h2 -j -p link show eth0.$vid2 | jq -r '.[]["address"]')
- run_cmd "bridge -n sw1 fdb replace $h2_mac1 dev vx0 master static vlan $vid1"
- run_cmd "bridge -n sw1 fdb replace $h2_mac2 dev vx0 master static vlan $vid2"
- run_cmd "ip -n sw1 neigh replace $tip1 lladdr $h2_mac1 nud permanent dev br0.$vid1"
- run_cmd "ip -n sw1 neigh replace $tip2 lladdr $h2_mac2 nud permanent dev br0.$vid2"
+ h2_mac1=$(ip -n $h2 -j -p link show eth0.$vid1 | jq -r '.[]["address"]')
+ h2_mac2=$(ip -n $h2 -j -p link show eth0.$vid2 | jq -r '.[]["address"]')
+ run_cmd "bridge -n $sw1 fdb replace $h2_mac1 dev vx0 master static vlan $vid1"
+ run_cmd "bridge -n $sw1 fdb replace $h2_mac2 dev vx0 master static vlan $vid2"
+ run_cmd "ip -n $sw1 neigh replace $tip1 lladdr $h2_mac1 nud permanent dev br0.$vid1"
+ run_cmd "ip -n $sw1 neigh replace $tip2 lladdr $h2_mac2 nud permanent dev br0.$vid2"
# Enable per-{Port, VLAN} neighbor suppression and check that ARP
# requests are not suppressed and that ARP replies are received.
- run_cmd "bridge -n sw1 link set dev vx0 neigh_vlan_suppress on"
- run_cmd "bridge -n sw1 -d link show dev vx0 | grep \"neigh_vlan_suppress on\""
+ run_cmd "bridge -n $sw1 link set dev vx0 neigh_vlan_suppress on"
+ run_cmd "bridge -n $sw1 -d link show dev vx0 | grep \"neigh_vlan_suppress on\""
log_test $? 0 "\"neigh_vlan_suppress\" is on"
- run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip1 -I eth0.$vid1 $tip1"
+ run_cmd "ip netns exec $h1 arping -q -b -c 1 -w 5 -s $sip1 -I eth0.$vid1 $tip1"
log_test $? 0 "arping (VLAN $vid1)"
- run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip2 -I eth0.$vid2 $tip2"
+ run_cmd "ip netns exec $h1 arping -q -b -c 1 -w 5 -s $sip2 -I eth0.$vid2 $tip2"
log_test $? 0 "arping (VLAN $vid2)"
- tc_check_packets sw1 "dev vx0 egress" 101 1
+ tc_check_packets $sw1 "dev vx0 egress" 101 1
log_test $? 0 "ARP suppression (VLAN $vid1)"
- tc_check_packets sw1 "dev vx0 egress" 102 1
+ tc_check_packets $sw1 "dev vx0 egress" 102 1
log_test $? 0 "ARP suppression (VLAN $vid2)"
# Enable neighbor suppression on VLAN 10 and check that only on this
# VLAN ARP requests are suppressed.
- run_cmd "bridge -n sw1 vlan set vid $vid1 dev vx0 neigh_suppress on"
- run_cmd "bridge -n sw1 -d vlan show dev vx0 vid $vid1 | grep \"neigh_suppress on\""
+ run_cmd "bridge -n $sw1 vlan set vid $vid1 dev vx0 neigh_suppress on"
+ run_cmd "bridge -n $sw1 -d vlan show dev vx0 vid $vid1 | grep \"neigh_suppress on\""
log_test $? 0 "\"neigh_suppress\" is on (VLAN $vid1)"
- run_cmd "bridge -n sw1 -d vlan show dev vx0 vid $vid2 | grep \"neigh_suppress off\""
+ run_cmd "bridge -n $sw1 -d vlan show dev vx0 vid $vid2 | grep \"neigh_suppress off\""
log_test $? 0 "\"neigh_suppress\" is off (VLAN $vid2)"
- run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip1 -I eth0.$vid1 $tip1"
+ run_cmd "ip netns exec $h1 arping -q -b -c 1 -w 5 -s $sip1 -I eth0.$vid1 $tip1"
log_test $? 0 "arping (VLAN $vid1)"
- run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip2 -I eth0.$vid2 $tip2"
+ run_cmd "ip netns exec $h1 arping -q -b -c 1 -w 5 -s $sip2 -I eth0.$vid2 $tip2"
log_test $? 0 "arping (VLAN $vid2)"
- tc_check_packets sw1 "dev vx0 egress" 101 1
+ tc_check_packets $sw1 "dev vx0 egress" 101 1
log_test $? 0 "ARP suppression (VLAN $vid1)"
- tc_check_packets sw1 "dev vx0 egress" 102 2
+ tc_check_packets $sw1 "dev vx0 egress" 102 2
log_test $? 0 "ARP suppression (VLAN $vid2)"
# Enable neighbor suppression on the port and check that it has no
# effect compared to previous state.
- run_cmd "bridge -n sw1 link set dev vx0 neigh_suppress on"
- run_cmd "bridge -n sw1 -d link show dev vx0 | grep \"neigh_suppress on\""
+ run_cmd "bridge -n $sw1 link set dev vx0 neigh_suppress on"
+ run_cmd "bridge -n $sw1 -d link show dev vx0 | grep \"neigh_suppress on\""
log_test $? 0 "\"neigh_suppress\" is on"
- run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip1 -I eth0.$vid1 $tip1"
+ run_cmd "ip netns exec $h1 arping -q -b -c 1 -w 5 -s $sip1 -I eth0.$vid1 $tip1"
log_test $? 0 "arping (VLAN $vid1)"
- run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip2 -I eth0.$vid2 $tip2"
+ run_cmd "ip netns exec $h1 arping -q -b -c 1 -w 5 -s $sip2 -I eth0.$vid2 $tip2"
log_test $? 0 "arping (VLAN $vid2)"
- tc_check_packets sw1 "dev vx0 egress" 101 1
+ tc_check_packets $sw1 "dev vx0 egress" 101 1
log_test $? 0 "ARP suppression (VLAN $vid1)"
- tc_check_packets sw1 "dev vx0 egress" 102 3
+ tc_check_packets $sw1 "dev vx0 egress" 102 3
log_test $? 0 "ARP suppression (VLAN $vid2)"
# Disable neighbor suppression on the port and check that it has no
# effect compared to previous state.
- run_cmd "bridge -n sw1 link set dev vx0 neigh_suppress off"
- run_cmd "bridge -n sw1 -d link show dev vx0 | grep \"neigh_suppress off\""
+ run_cmd "bridge -n $sw1 link set dev vx0 neigh_suppress off"
+ run_cmd "bridge -n $sw1 -d link show dev vx0 | grep \"neigh_suppress off\""
log_test $? 0 "\"neigh_suppress\" is off"
- run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip1 -I eth0.$vid1 $tip1"
+ run_cmd "ip netns exec $h1 arping -q -b -c 1 -w 5 -s $sip1 -I eth0.$vid1 $tip1"
log_test $? 0 "arping (VLAN $vid1)"
- run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip2 -I eth0.$vid2 $tip2"
+ run_cmd "ip netns exec $h1 arping -q -b -c 1 -w 5 -s $sip2 -I eth0.$vid2 $tip2"
log_test $? 0 "arping (VLAN $vid2)"
- tc_check_packets sw1 "dev vx0 egress" 101 1
+ tc_check_packets $sw1 "dev vx0 egress" 101 1
log_test $? 0 "ARP suppression (VLAN $vid1)"
- tc_check_packets sw1 "dev vx0 egress" 102 4
+ tc_check_packets $sw1 "dev vx0 egress" 102 4
log_test $? 0 "ARP suppression (VLAN $vid2)"
# Disable neighbor suppression on VLAN 10 and check that ARP requests
# are no longer suppressed on this VLAN.
- run_cmd "bridge -n sw1 vlan set vid $vid1 dev vx0 neigh_suppress off"
- run_cmd "bridge -n sw1 -d vlan show dev vx0 vid $vid1 | grep \"neigh_suppress off\""
+ run_cmd "bridge -n $sw1 vlan set vid $vid1 dev vx0 neigh_suppress off"
+ run_cmd "bridge -n $sw1 -d vlan show dev vx0 vid $vid1 | grep \"neigh_suppress off\""
log_test $? 0 "\"neigh_suppress\" is off (VLAN $vid1)"
- run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip1 -I eth0.$vid1 $tip1"
+ run_cmd "ip netns exec $h1 arping -q -b -c 1 -w 5 -s $sip1 -I eth0.$vid1 $tip1"
log_test $? 0 "arping (VLAN $vid1)"
- run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip2 -I eth0.$vid2 $tip2"
+ run_cmd "ip netns exec $h1 arping -q -b -c 1 -w 5 -s $sip2 -I eth0.$vid2 $tip2"
log_test $? 0 "arping (VLAN $vid2)"
- tc_check_packets sw1 "dev vx0 egress" 101 2
+ tc_check_packets $sw1 "dev vx0 egress" 101 2
log_test $? 0 "ARP suppression (VLAN $vid1)"
- tc_check_packets sw1 "dev vx0 egress" 102 5
+ tc_check_packets $sw1 "dev vx0 egress" 102 5
log_test $? 0 "ARP suppression (VLAN $vid2)"
# Disable per-{Port, VLAN} neighbor suppression, enable neighbor
# suppression on the port and check that on both VLANs ARP requests are
# suppressed.
- run_cmd "bridge -n sw1 link set dev vx0 neigh_vlan_suppress off"
- run_cmd "bridge -n sw1 -d link show dev vx0 | grep \"neigh_vlan_suppress off\""
+ run_cmd "bridge -n $sw1 link set dev vx0 neigh_vlan_suppress off"
+ run_cmd "bridge -n $sw1 -d link show dev vx0 | grep \"neigh_vlan_suppress off\""
log_test $? 0 "\"neigh_vlan_suppress\" is off"
- run_cmd "bridge -n sw1 link set dev vx0 neigh_suppress on"
- run_cmd "bridge -n sw1 -d link show dev vx0 | grep \"neigh_suppress on\""
+ run_cmd "bridge -n $sw1 link set dev vx0 neigh_suppress on"
+ run_cmd "bridge -n $sw1 -d link show dev vx0 | grep \"neigh_suppress on\""
log_test $? 0 "\"neigh_suppress\" is on"
- run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip1 -I eth0.$vid1 $tip1"
+ run_cmd "ip netns exec $h1 arping -q -b -c 1 -w 5 -s $sip1 -I eth0.$vid1 $tip1"
log_test $? 0 "arping (VLAN $vid1)"
- run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip2 -I eth0.$vid2 $tip2"
+ run_cmd "ip netns exec $h1 arping -q -b -c 1 -w 5 -s $sip2 -I eth0.$vid2 $tip2"
log_test $? 0 "arping (VLAN $vid2)"
- tc_check_packets sw1 "dev vx0 egress" 101 2
+ tc_check_packets $sw1 "dev vx0 egress" 101 2
log_test $? 0 "ARP suppression (VLAN $vid1)"
- tc_check_packets sw1 "dev vx0 egress" 102 5
+ tc_check_packets $sw1 "dev vx0 egress" 102 5
log_test $? 0 "ARP suppression (VLAN $vid2)"
}
@@ -655,118 +648,118 @@ neigh_vlan_suppress_ns()
echo "Per-{Port, VLAN} NS suppression"
echo "-------------------------------"
- run_cmd "tc -n sw1 qdisc replace dev vx0 clsact"
- run_cmd "tc -n sw1 filter replace dev vx0 egress pref 1 handle 101 proto ipv6 flower indev swp1 ip_proto icmpv6 dst_ip $maddr src_ip $saddr1 type 135 code 0 action pass"
- run_cmd "tc -n sw1 filter replace dev vx0 egress pref 1 handle 102 proto ipv6 flower indev swp1 ip_proto icmpv6 dst_ip $maddr src_ip $saddr2 type 135 code 0 action pass"
+ run_cmd "tc -n $sw1 qdisc replace dev vx0 clsact"
+ run_cmd "tc -n $sw1 filter replace dev vx0 egress pref 1 handle 101 proto ipv6 flower indev swp1 ip_proto icmpv6 dst_ip $maddr src_ip $saddr1 type 135 code 0 action pass"
+ run_cmd "tc -n $sw1 filter replace dev vx0 egress pref 1 handle 102 proto ipv6 flower indev swp1 ip_proto icmpv6 dst_ip $maddr src_ip $saddr2 type 135 code 0 action pass"
- h2_mac1=$(ip -n h2 -j -p link show eth0.$vid1 | jq -r '.[]["address"]')
- h2_mac2=$(ip -n h2 -j -p link show eth0.$vid2 | jq -r '.[]["address"]')
- run_cmd "bridge -n sw1 fdb replace $h2_mac1 dev vx0 master static vlan $vid1"
- run_cmd "bridge -n sw1 fdb replace $h2_mac2 dev vx0 master static vlan $vid2"
- run_cmd "ip -n sw1 neigh replace $daddr1 lladdr $h2_mac1 nud permanent dev br0.$vid1"
- run_cmd "ip -n sw1 neigh replace $daddr2 lladdr $h2_mac2 nud permanent dev br0.$vid2"
+ h2_mac1=$(ip -n $h2 -j -p link show eth0.$vid1 | jq -r '.[]["address"]')
+ h2_mac2=$(ip -n $h2 -j -p link show eth0.$vid2 | jq -r '.[]["address"]')
+ run_cmd "bridge -n $sw1 fdb replace $h2_mac1 dev vx0 master static vlan $vid1"
+ run_cmd "bridge -n $sw1 fdb replace $h2_mac2 dev vx0 master static vlan $vid2"
+ run_cmd "ip -n $sw1 neigh replace $daddr1 lladdr $h2_mac1 nud permanent dev br0.$vid1"
+ run_cmd "ip -n $sw1 neigh replace $daddr2 lladdr $h2_mac2 nud permanent dev br0.$vid2"
# Enable per-{Port, VLAN} neighbor suppression and check that NS
# messages are not suppressed and that ND messages are received.
- run_cmd "bridge -n sw1 link set dev vx0 neigh_vlan_suppress on"
- run_cmd "bridge -n sw1 -d link show dev vx0 | grep \"neigh_vlan_suppress on\""
+ run_cmd "bridge -n $sw1 link set dev vx0 neigh_vlan_suppress on"
+ run_cmd "bridge -n $sw1 -d link show dev vx0 | grep \"neigh_vlan_suppress on\""
log_test $? 0 "\"neigh_vlan_suppress\" is on"
- run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr1 -w 5000 $daddr1 eth0.$vid1"
+ run_cmd "ip netns exec $h1 ndisc6 -q -r 1 -s $saddr1 -w 5000 $daddr1 eth0.$vid1"
log_test $? 0 "ndisc6 (VLAN $vid1)"
- run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr2 -w 5000 $daddr2 eth0.$vid2"
+ run_cmd "ip netns exec $h1 ndisc6 -q -r 1 -s $saddr2 -w 5000 $daddr2 eth0.$vid2"
log_test $? 0 "ndisc6 (VLAN $vid2)"
- tc_check_packets sw1 "dev vx0 egress" 101 1
+ tc_check_packets $sw1 "dev vx0 egress" 101 1
log_test $? 0 "NS suppression (VLAN $vid1)"
- tc_check_packets sw1 "dev vx0 egress" 102 1
+ tc_check_packets $sw1 "dev vx0 egress" 102 1
log_test $? 0 "NS suppression (VLAN $vid2)"
# Enable neighbor suppression on VLAN 10 and check that only on this
# VLAN NS messages are suppressed.
- run_cmd "bridge -n sw1 vlan set vid $vid1 dev vx0 neigh_suppress on"
- run_cmd "bridge -n sw1 -d vlan show dev vx0 vid $vid1 | grep \"neigh_suppress on\""
+ run_cmd "bridge -n $sw1 vlan set vid $vid1 dev vx0 neigh_suppress on"
+ run_cmd "bridge -n $sw1 -d vlan show dev vx0 vid $vid1 | grep \"neigh_suppress on\""
log_test $? 0 "\"neigh_suppress\" is on (VLAN $vid1)"
- run_cmd "bridge -n sw1 -d vlan show dev vx0 vid $vid2 | grep \"neigh_suppress off\""
+ run_cmd "bridge -n $sw1 -d vlan show dev vx0 vid $vid2 | grep \"neigh_suppress off\""
log_test $? 0 "\"neigh_suppress\" is off (VLAN $vid2)"
- run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr1 -w 5000 $daddr1 eth0.$vid1"
+ run_cmd "ip netns exec $h1 ndisc6 -q -r 1 -s $saddr1 -w 5000 $daddr1 eth0.$vid1"
log_test $? 0 "ndisc6 (VLAN $vid1)"
- run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr2 -w 5000 $daddr2 eth0.$vid2"
+ run_cmd "ip netns exec $h1 ndisc6 -q -r 1 -s $saddr2 -w 5000 $daddr2 eth0.$vid2"
log_test $? 0 "ndisc6 (VLAN $vid2)"
- tc_check_packets sw1 "dev vx0 egress" 101 1
+ tc_check_packets $sw1 "dev vx0 egress" 101 1
log_test $? 0 "NS suppression (VLAN $vid1)"
- tc_check_packets sw1 "dev vx0 egress" 102 2
+ tc_check_packets $sw1 "dev vx0 egress" 102 2
log_test $? 0 "NS suppression (VLAN $vid2)"
# Enable neighbor suppression on the port and check that it has no
# effect compared to previous state.
- run_cmd "bridge -n sw1 link set dev vx0 neigh_suppress on"
- run_cmd "bridge -n sw1 -d link show dev vx0 | grep \"neigh_suppress on\""
+ run_cmd "bridge -n $sw1 link set dev vx0 neigh_suppress on"
+ run_cmd "bridge -n $sw1 -d link show dev vx0 | grep \"neigh_suppress on\""
log_test $? 0 "\"neigh_suppress\" is on"
- run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr1 -w 5000 $daddr1 eth0.$vid1"
+ run_cmd "ip netns exec $h1 ndisc6 -q -r 1 -s $saddr1 -w 5000 $daddr1 eth0.$vid1"
log_test $? 0 "ndisc6 (VLAN $vid1)"
- run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr2 -w 5000 $daddr2 eth0.$vid2"
+ run_cmd "ip netns exec $h1 ndisc6 -q -r 1 -s $saddr2 -w 5000 $daddr2 eth0.$vid2"
log_test $? 0 "ndisc6 (VLAN $vid2)"
- tc_check_packets sw1 "dev vx0 egress" 101 1
+ tc_check_packets $sw1 "dev vx0 egress" 101 1
log_test $? 0 "NS suppression (VLAN $vid1)"
- tc_check_packets sw1 "dev vx0 egress" 102 3
+ tc_check_packets $sw1 "dev vx0 egress" 102 3
log_test $? 0 "NS suppression (VLAN $vid2)"
# Disable neighbor suppression on the port and check that it has no
# effect compared to previous state.
- run_cmd "bridge -n sw1 link set dev vx0 neigh_suppress off"
- run_cmd "bridge -n sw1 -d link show dev vx0 | grep \"neigh_suppress off\""
+ run_cmd "bridge -n $sw1 link set dev vx0 neigh_suppress off"
+ run_cmd "bridge -n $sw1 -d link show dev vx0 | grep \"neigh_suppress off\""
log_test $? 0 "\"neigh_suppress\" is off"
- run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr1 -w 5000 $daddr1 eth0.$vid1"
+ run_cmd "ip netns exec $h1 ndisc6 -q -r 1 -s $saddr1 -w 5000 $daddr1 eth0.$vid1"
log_test $? 0 "ndisc6 (VLAN $vid1)"
- run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr2 -w 5000 $daddr2 eth0.$vid2"
+ run_cmd "ip netns exec $h1 ndisc6 -q -r 1 -s $saddr2 -w 5000 $daddr2 eth0.$vid2"
log_test $? 0 "ndisc6 (VLAN $vid2)"
- tc_check_packets sw1 "dev vx0 egress" 101 1
+ tc_check_packets $sw1 "dev vx0 egress" 101 1
log_test $? 0 "NS suppression (VLAN $vid1)"
- tc_check_packets sw1 "dev vx0 egress" 102 4
+ tc_check_packets $sw1 "dev vx0 egress" 102 4
log_test $? 0 "NS suppression (VLAN $vid2)"
# Disable neighbor suppression on VLAN 10 and check that NS messages
# are no longer suppressed on this VLAN.
- run_cmd "bridge -n sw1 vlan set vid $vid1 dev vx0 neigh_suppress off"
- run_cmd "bridge -n sw1 -d vlan show dev vx0 vid $vid1 | grep \"neigh_suppress off\""
+ run_cmd "bridge -n $sw1 vlan set vid $vid1 dev vx0 neigh_suppress off"
+ run_cmd "bridge -n $sw1 -d vlan show dev vx0 vid $vid1 | grep \"neigh_suppress off\""
log_test $? 0 "\"neigh_suppress\" is off (VLAN $vid1)"
- run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr1 -w 5000 $daddr1 eth0.$vid1"
+ run_cmd "ip netns exec $h1 ndisc6 -q -r 1 -s $saddr1 -w 5000 $daddr1 eth0.$vid1"
log_test $? 0 "ndisc6 (VLAN $vid1)"
- run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr2 -w 5000 $daddr2 eth0.$vid2"
+ run_cmd "ip netns exec $h1 ndisc6 -q -r 1 -s $saddr2 -w 5000 $daddr2 eth0.$vid2"
log_test $? 0 "ndisc6 (VLAN $vid2)"
- tc_check_packets sw1 "dev vx0 egress" 101 2
+ tc_check_packets $sw1 "dev vx0 egress" 101 2
log_test $? 0 "NS suppression (VLAN $vid1)"
- tc_check_packets sw1 "dev vx0 egress" 102 5
+ tc_check_packets $sw1 "dev vx0 egress" 102 5
log_test $? 0 "NS suppression (VLAN $vid2)"
# Disable per-{Port, VLAN} neighbor suppression, enable neighbor
# suppression on the port and check that on both VLANs NS messages are
# suppressed.
- run_cmd "bridge -n sw1 link set dev vx0 neigh_vlan_suppress off"
- run_cmd "bridge -n sw1 -d link show dev vx0 | grep \"neigh_vlan_suppress off\""
+ run_cmd "bridge -n $sw1 link set dev vx0 neigh_vlan_suppress off"
+ run_cmd "bridge -n $sw1 -d link show dev vx0 | grep \"neigh_vlan_suppress off\""
log_test $? 0 "\"neigh_vlan_suppress\" is off"
- run_cmd "bridge -n sw1 link set dev vx0 neigh_suppress on"
- run_cmd "bridge -n sw1 -d link show dev vx0 | grep \"neigh_suppress on\""
+ run_cmd "bridge -n $sw1 link set dev vx0 neigh_suppress on"
+ run_cmd "bridge -n $sw1 -d link show dev vx0 | grep \"neigh_suppress on\""
log_test $? 0 "\"neigh_suppress\" is on"
- run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr1 -w 5000 $daddr1 eth0.$vid1"
+ run_cmd "ip netns exec $h1 ndisc6 -q -r 1 -s $saddr1 -w 5000 $daddr1 eth0.$vid1"
log_test $? 0 "ndisc6 (VLAN $vid1)"
- run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr2 -w 5000 $daddr2 eth0.$vid2"
+ run_cmd "ip netns exec $h1 ndisc6 -q -r 1 -s $saddr2 -w 5000 $daddr2 eth0.$vid2"
log_test $? 0 "ndisc6 (VLAN $vid2)"
- tc_check_packets sw1 "dev vx0 egress" 101 2
+ tc_check_packets $sw1 "dev vx0 egress" 101 2
log_test $? 0 "NS suppression (VLAN $vid1)"
- tc_check_packets sw1 "dev vx0 egress" 102 5
+ tc_check_packets $sw1 "dev vx0 egress" 102 5
log_test $? 0 "NS suppression (VLAN $vid2)"
}
diff --git a/tools/testing/selftests/net/test_vxlan_mdb.sh b/tools/testing/selftests/net/test_vxlan_mdb.sh
index 6e996f8063cd..6725fd9157b9 100755
--- a/tools/testing/selftests/net/test_vxlan_mdb.sh
+++ b/tools/testing/selftests/net/test_vxlan_mdb.sh
@@ -55,9 +55,8 @@
# | ns2_v4 | | ns2_v6 |
# +------------------------------------+ +------------------------------------+
+source lib.sh
ret=0
-# Kselftest framework requirement - SKIP code is 4.
-ksft_skip=4
CONTROL_PATH_TESTS="
basic_star_g_ipv4_ipv4
@@ -260,9 +259,6 @@ setup_common()
local local_addr1=$1; shift
local local_addr2=$1; shift
- ip netns add $ns1
- ip netns add $ns2
-
ip link add name veth0 type veth peer name veth1
ip link set dev veth0 netns $ns1 name veth0
ip link set dev veth1 netns $ns2 name veth0
@@ -273,36 +269,36 @@ setup_common()
setup_v4()
{
- setup_common ns1_v4 ns2_v4 192.0.2.1 192.0.2.2
+ setup_ns ns1_v4 ns2_v4
+ setup_common $ns1_v4 $ns2_v4 192.0.2.1 192.0.2.2
- ip -n ns1_v4 address add 192.0.2.17/28 dev veth0
- ip -n ns2_v4 address add 192.0.2.18/28 dev veth0
+ ip -n $ns1_v4 address add 192.0.2.17/28 dev veth0
+ ip -n $ns2_v4 address add 192.0.2.18/28 dev veth0
- ip -n ns1_v4 route add default via 192.0.2.18
- ip -n ns2_v4 route add default via 192.0.2.17
+ ip -n $ns1_v4 route add default via 192.0.2.18
+ ip -n $ns2_v4 route add default via 192.0.2.17
}
cleanup_v4()
{
- ip netns del ns2_v4
- ip netns del ns1_v4
+ cleanup_ns $ns2_v4 $ns1_v4
}
setup_v6()
{
- setup_common ns1_v6 ns2_v6 2001:db8:1::1 2001:db8:1::2
+ setup_ns ns1_v6 ns2_v6
+ setup_common $ns1_v6 $ns2_v6 2001:db8:1::1 2001:db8:1::2
- ip -n ns1_v6 address add 2001:db8:2::1/64 dev veth0 nodad
- ip -n ns2_v6 address add 2001:db8:2::2/64 dev veth0 nodad
+ ip -n $ns1_v6 address add 2001:db8:2::1/64 dev veth0 nodad
+ ip -n $ns2_v6 address add 2001:db8:2::2/64 dev veth0 nodad
- ip -n ns1_v6 route add default via 2001:db8:2::2
- ip -n ns2_v6 route add default via 2001:db8:2::1
+ ip -n $ns1_v6 route add default via 2001:db8:2::2
+ ip -n $ns2_v6 route add default via 2001:db8:2::1
}
cleanup_v6()
{
- ip netns del ns2_v6
- ip netns del ns1_v6
+ cleanup_ns $ns2_v6 $ns1_v6
}
setup()
@@ -433,7 +429,7 @@ basic_common()
basic_star_g_ipv4_ipv4()
{
- local ns1=ns1_v4
+ local ns1=$ns1_v4
local grp_key="grp 239.1.1.1"
local vtep_ip=198.51.100.100
@@ -446,7 +442,7 @@ basic_star_g_ipv4_ipv4()
basic_star_g_ipv6_ipv4()
{
- local ns1=ns1_v4
+ local ns1=$ns1_v4
local grp_key="grp ff0e::1"
local vtep_ip=198.51.100.100
@@ -459,7 +455,7 @@ basic_star_g_ipv6_ipv4()
basic_star_g_ipv4_ipv6()
{
- local ns1=ns1_v6
+ local ns1=$ns1_v6
local grp_key="grp 239.1.1.1"
local vtep_ip=2001:db8:1000::1
@@ -472,7 +468,7 @@ basic_star_g_ipv4_ipv6()
basic_star_g_ipv6_ipv6()
{
- local ns1=ns1_v6
+ local ns1=$ns1_v6
local grp_key="grp ff0e::1"
local vtep_ip=2001:db8:1000::1
@@ -485,7 +481,7 @@ basic_star_g_ipv6_ipv6()
basic_sg_ipv4_ipv4()
{
- local ns1=ns1_v4
+ local ns1=$ns1_v4
local grp_key="grp 239.1.1.1 src 192.0.2.129"
local vtep_ip=198.51.100.100
@@ -498,7 +494,7 @@ basic_sg_ipv4_ipv4()
basic_sg_ipv6_ipv4()
{
- local ns1=ns1_v4
+ local ns1=$ns1_v4
local grp_key="grp ff0e::1 src 2001:db8:100::1"
local vtep_ip=198.51.100.100
@@ -511,7 +507,7 @@ basic_sg_ipv6_ipv4()
basic_sg_ipv4_ipv6()
{
- local ns1=ns1_v6
+ local ns1=$ns1_v6
local grp_key="grp 239.1.1.1 src 192.0.2.129"
local vtep_ip=2001:db8:1000::1
@@ -524,7 +520,7 @@ basic_sg_ipv4_ipv6()
basic_sg_ipv6_ipv6()
{
- local ns1=ns1_v6
+ local ns1=$ns1_v6
local grp_key="grp ff0e::1 src 2001:db8:100::1"
local vtep_ip=2001:db8:1000::1
@@ -694,7 +690,7 @@ star_g_common()
star_g_ipv4_ipv4()
{
- local ns1=ns1_v4
+ local ns1=$ns1_v4
local grp=239.1.1.1
local src1=192.0.2.129
local src2=192.0.2.130
@@ -711,7 +707,7 @@ star_g_ipv4_ipv4()
star_g_ipv6_ipv4()
{
- local ns1=ns1_v4
+ local ns1=$ns1_v4
local grp=ff0e::1
local src1=2001:db8:100::1
local src2=2001:db8:100::2
@@ -728,7 +724,7 @@ star_g_ipv6_ipv4()
star_g_ipv4_ipv6()
{
- local ns1=ns1_v6
+ local ns1=$ns1_v6
local grp=239.1.1.1
local src1=192.0.2.129
local src2=192.0.2.130
@@ -745,7 +741,7 @@ star_g_ipv4_ipv6()
star_g_ipv6_ipv6()
{
- local ns1=ns1_v6
+ local ns1=$ns1_v6
local grp=ff0e::1
local src1=2001:db8:100::1
local src2=2001:db8:100::2
@@ -793,7 +789,7 @@ sg_common()
sg_ipv4_ipv4()
{
- local ns1=ns1_v4
+ local ns1=$ns1_v4
local grp=239.1.1.1
local src=192.0.2.129
local vtep_ip=198.51.100.100
@@ -808,7 +804,7 @@ sg_ipv4_ipv4()
sg_ipv6_ipv4()
{
- local ns1=ns1_v4
+ local ns1=$ns1_v4
local grp=ff0e::1
local src=2001:db8:100::1
local vtep_ip=198.51.100.100
@@ -823,7 +819,7 @@ sg_ipv6_ipv4()
sg_ipv4_ipv6()
{
- local ns1=ns1_v6
+ local ns1=$ns1_v6
local grp=239.1.1.1
local src=192.0.2.129
local vtep_ip=2001:db8:1000::1
@@ -838,7 +834,7 @@ sg_ipv4_ipv6()
sg_ipv6_ipv6()
{
- local ns1=ns1_v6
+ local ns1=$ns1_v6
local grp=ff0e::1
local src=2001:db8:100::1
local vtep_ip=2001:db8:1000::1
@@ -918,7 +914,7 @@ dump_common()
dump_ipv4_ipv4()
{
- local ns1=ns1_v4
+ local ns1=$ns1_v4
local local_addr=192.0.2.1
local remote_prefix=198.51.100.
local fn=ipv4_grps_get
@@ -932,7 +928,7 @@ dump_ipv4_ipv4()
dump_ipv6_ipv4()
{
- local ns1=ns1_v4
+ local ns1=$ns1_v4
local local_addr=192.0.2.1
local remote_prefix=198.51.100.
local fn=ipv6_grps_get
@@ -946,7 +942,7 @@ dump_ipv6_ipv4()
dump_ipv4_ipv6()
{
- local ns1=ns1_v6
+ local ns1=$ns1_v6
local local_addr=2001:db8:1::1
local remote_prefix=2001:db8:1000::
local fn=ipv4_grps_get
@@ -960,7 +956,7 @@ dump_ipv4_ipv6()
dump_ipv6_ipv6()
{
- local ns1=ns1_v6
+ local ns1=$ns1_v6
local local_addr=2001:db8:1::1
local remote_prefix=2001:db8:1000::
local fn=ipv6_grps_get
@@ -1072,8 +1068,8 @@ encap_params_common()
encap_params_ipv4_ipv4()
{
- local ns1=ns1_v4
- local ns2=ns2_v4
+ local ns1=$ns1_v4
+ local ns2=$ns2_v4
local vtep1_ip=198.51.100.100
local vtep2_ip=198.51.100.200
local plen=32
@@ -1091,8 +1087,8 @@ encap_params_ipv4_ipv4()
encap_params_ipv6_ipv4()
{
- local ns1=ns1_v4
- local ns2=ns2_v4
+ local ns1=$ns1_v4
+ local ns2=$ns2_v4
local vtep1_ip=198.51.100.100
local vtep2_ip=198.51.100.200
local plen=32
@@ -1110,8 +1106,8 @@ encap_params_ipv6_ipv4()
encap_params_ipv4_ipv6()
{
- local ns1=ns1_v6
- local ns2=ns2_v6
+ local ns1=$ns1_v6
+ local ns2=$ns2_v6
local vtep1_ip=2001:db8:1000::1
local vtep2_ip=2001:db8:2000::1
local plen=128
@@ -1129,8 +1125,8 @@ encap_params_ipv4_ipv6()
encap_params_ipv6_ipv6()
{
- local ns1=ns1_v6
- local ns2=ns2_v6
+ local ns1=$ns1_v6
+ local ns2=$ns2_v6
local vtep1_ip=2001:db8:1000::1
local vtep2_ip=2001:db8:2000::1
local plen=128
@@ -1208,8 +1204,8 @@ starg_exclude_ir_common()
starg_exclude_ir_ipv4_ipv4()
{
- local ns1=ns1_v4
- local ns2=ns2_v4
+ local ns1=$ns1_v4
+ local ns2=$ns2_v4
local vtep1_ip=198.51.100.100
local vtep2_ip=198.51.100.200
local plen=32
@@ -1227,8 +1223,8 @@ starg_exclude_ir_ipv4_ipv4()
starg_exclude_ir_ipv6_ipv4()
{
- local ns1=ns1_v4
- local ns2=ns2_v4
+ local ns1=$ns1_v4
+ local ns2=$ns2_v4
local vtep1_ip=198.51.100.100
local vtep2_ip=198.51.100.200
local plen=32
@@ -1246,8 +1242,8 @@ starg_exclude_ir_ipv6_ipv4()
starg_exclude_ir_ipv4_ipv6()
{
- local ns1=ns1_v6
- local ns2=ns2_v6
+ local ns1=$ns1_v6
+ local ns2=$ns2_v6
local vtep1_ip=2001:db8:1000::1
local vtep2_ip=2001:db8:2000::1
local plen=128
@@ -1265,8 +1261,8 @@ starg_exclude_ir_ipv4_ipv6()
starg_exclude_ir_ipv6_ipv6()
{
- local ns1=ns1_v6
- local ns2=ns2_v6
+ local ns1=$ns1_v6
+ local ns2=$ns2_v6
local vtep1_ip=2001:db8:1000::1
local vtep2_ip=2001:db8:2000::1
local plen=128
@@ -1344,8 +1340,8 @@ starg_include_ir_common()
starg_include_ir_ipv4_ipv4()
{
- local ns1=ns1_v4
- local ns2=ns2_v4
+ local ns1=$ns1_v4
+ local ns2=$ns2_v4
local vtep1_ip=198.51.100.100
local vtep2_ip=198.51.100.200
local plen=32
@@ -1363,8 +1359,8 @@ starg_include_ir_ipv4_ipv4()
starg_include_ir_ipv6_ipv4()
{
- local ns1=ns1_v4
- local ns2=ns2_v4
+ local ns1=$ns1_v4
+ local ns2=$ns2_v4
local vtep1_ip=198.51.100.100
local vtep2_ip=198.51.100.200
local plen=32
@@ -1382,8 +1378,8 @@ starg_include_ir_ipv6_ipv4()
starg_include_ir_ipv4_ipv6()
{
- local ns1=ns1_v6
- local ns2=ns2_v6
+ local ns1=$ns1_v6
+ local ns2=$ns2_v6
local vtep1_ip=2001:db8:1000::1
local vtep2_ip=2001:db8:2000::1
local plen=128
@@ -1401,8 +1397,8 @@ starg_include_ir_ipv4_ipv6()
starg_include_ir_ipv6_ipv6()
{
- local ns1=ns1_v6
- local ns2=ns2_v6
+ local ns1=$ns1_v6
+ local ns2=$ns2_v6
local vtep1_ip=2001:db8:1000::1
local vtep2_ip=2001:db8:2000::1
local plen=128
@@ -1462,8 +1458,8 @@ starg_exclude_p2mp_common()
starg_exclude_p2mp_ipv4_ipv4()
{
- local ns1=ns1_v4
- local ns2=ns2_v4
+ local ns1=$ns1_v4
+ local ns2=$ns2_v4
local mcast_grp=238.1.1.1
local plen=32
local grp=239.1.1.1
@@ -1480,8 +1476,8 @@ starg_exclude_p2mp_ipv4_ipv4()
starg_exclude_p2mp_ipv6_ipv4()
{
- local ns1=ns1_v4
- local ns2=ns2_v4
+ local ns1=$ns1_v4
+ local ns2=$ns2_v4
local mcast_grp=238.1.1.1
local plen=32
local grp=ff0e::1
@@ -1498,8 +1494,8 @@ starg_exclude_p2mp_ipv6_ipv4()
starg_exclude_p2mp_ipv4_ipv6()
{
- local ns1=ns1_v6
- local ns2=ns2_v6
+ local ns1=$ns1_v6
+ local ns2=$ns2_v6
local mcast_grp=ff0e::2
local plen=128
local grp=239.1.1.1
@@ -1516,8 +1512,8 @@ starg_exclude_p2mp_ipv4_ipv6()
starg_exclude_p2mp_ipv6_ipv6()
{
- local ns1=ns1_v6
- local ns2=ns2_v6
+ local ns1=$ns1_v6
+ local ns2=$ns2_v6
local mcast_grp=ff0e::2
local plen=128
local grp=ff0e::1
@@ -1576,8 +1572,8 @@ starg_include_p2mp_common()
starg_include_p2mp_ipv4_ipv4()
{
- local ns1=ns1_v4
- local ns2=ns2_v4
+ local ns1=$ns1_v4
+ local ns2=$ns2_v4
local mcast_grp=238.1.1.1
local plen=32
local grp=239.1.1.1
@@ -1594,8 +1590,8 @@ starg_include_p2mp_ipv4_ipv4()
starg_include_p2mp_ipv6_ipv4()
{
- local ns1=ns1_v4
- local ns2=ns2_v4
+ local ns1=$ns1_v4
+ local ns2=$ns2_v4
local mcast_grp=238.1.1.1
local plen=32
local grp=ff0e::1
@@ -1612,8 +1608,8 @@ starg_include_p2mp_ipv6_ipv4()
starg_include_p2mp_ipv4_ipv6()
{
- local ns1=ns1_v6
- local ns2=ns2_v6
+ local ns1=$ns1_v6
+ local ns2=$ns2_v6
local mcast_grp=ff0e::2
local plen=128
local grp=239.1.1.1
@@ -1630,8 +1626,8 @@ starg_include_p2mp_ipv4_ipv6()
starg_include_p2mp_ipv6_ipv6()
{
- local ns1=ns1_v6
- local ns2=ns2_v6
+ local ns1=$ns1_v6
+ local ns2=$ns2_v6
local mcast_grp=ff0e::2
local plen=128
local grp=ff0e::1
@@ -1709,8 +1705,8 @@ egress_vni_translation_common()
egress_vni_translation_ipv4_ipv4()
{
- local ns1=ns1_v4
- local ns2=ns2_v4
+ local ns1=$ns1_v4
+ local ns2=$ns2_v4
local mcast_grp=238.1.1.1
local plen=32
local proto="ipv4"
@@ -1727,8 +1723,8 @@ egress_vni_translation_ipv4_ipv4()
egress_vni_translation_ipv6_ipv4()
{
- local ns1=ns1_v4
- local ns2=ns2_v4
+ local ns1=$ns1_v4
+ local ns2=$ns2_v4
local mcast_grp=238.1.1.1
local plen=32
local proto="ipv6"
@@ -1745,8 +1741,8 @@ egress_vni_translation_ipv6_ipv4()
egress_vni_translation_ipv4_ipv6()
{
- local ns1=ns1_v6
- local ns2=ns2_v6
+ local ns1=$ns1_v6
+ local ns2=$ns2_v6
local mcast_grp=ff0e::2
local plen=128
local proto="ipv4"
@@ -1763,8 +1759,8 @@ egress_vni_translation_ipv4_ipv6()
egress_vni_translation_ipv6_ipv6()
{
- local ns1=ns1_v6
- local ns2=ns2_v6
+ local ns1=$ns1_v6
+ local ns2=$ns2_v6
local mcast_grp=ff0e::2
local plen=128
local proto="ipv6"
@@ -1929,8 +1925,8 @@ all_zeros_mdb_common()
all_zeros_mdb_ipv4()
{
- local ns1=ns1_v4
- local ns2=ns2_v4
+ local ns1=$ns1_v4
+ local ns2=$ns2_v4
local vtep1_ip=198.51.100.101
local vtep2_ip=198.51.100.102
local vtep3_ip=198.51.100.103
@@ -1947,8 +1943,8 @@ all_zeros_mdb_ipv4()
all_zeros_mdb_ipv6()
{
- local ns1=ns1_v6
- local ns2=ns2_v6
+ local ns1=$ns1_v6
+ local ns2=$ns2_v6
local vtep1_ip=2001:db8:1000::1
local vtep2_ip=2001:db8:2000::1
local vtep3_ip=2001:db8:3000::1
@@ -2021,8 +2017,8 @@ mdb_fdb_common()
mdb_fdb_ipv4_ipv4()
{
- local ns1=ns1_v4
- local ns2=ns2_v4
+ local ns1=$ns1_v4
+ local ns2=$ns2_v4
local vtep1_ip=198.51.100.100
local vtep2_ip=198.51.100.200
local plen=32
@@ -2040,8 +2036,8 @@ mdb_fdb_ipv4_ipv4()
mdb_fdb_ipv6_ipv4()
{
- local ns1=ns1_v4
- local ns2=ns2_v4
+ local ns1=$ns1_v4
+ local ns2=$ns2_v4
local vtep1_ip=198.51.100.100
local vtep2_ip=198.51.100.200
local plen=32
@@ -2059,8 +2055,8 @@ mdb_fdb_ipv6_ipv4()
mdb_fdb_ipv4_ipv6()
{
- local ns1=ns1_v6
- local ns2=ns2_v6
+ local ns1=$ns1_v6
+ local ns2=$ns2_v6
local vtep1_ip=2001:db8:1000::1
local vtep2_ip=2001:db8:2000::1
local plen=128
@@ -2078,8 +2074,8 @@ mdb_fdb_ipv4_ipv6()
mdb_fdb_ipv6_ipv6()
{
- local ns1=ns1_v6
- local ns2=ns2_v6
+ local ns1=$ns1_v6
+ local ns2=$ns2_v6
local vtep1_ip=2001:db8:1000::1
local vtep2_ip=2001:db8:2000::1
local plen=128
@@ -2166,7 +2162,7 @@ mdb_torture_common()
mdb_torture_ipv4_ipv4()
{
- local ns1=ns1_v4
+ local ns1=$ns1_v4
local vtep1_ip=198.51.100.100
local vtep2_ip=198.51.100.200
local grp1=239.1.1.1
@@ -2183,7 +2179,7 @@ mdb_torture_ipv4_ipv4()
mdb_torture_ipv6_ipv4()
{
- local ns1=ns1_v4
+ local ns1=$ns1_v4
local vtep1_ip=198.51.100.100
local vtep2_ip=198.51.100.200
local grp1=ff0e::1
@@ -2200,7 +2196,7 @@ mdb_torture_ipv6_ipv4()
mdb_torture_ipv4_ipv6()
{
- local ns1=ns1_v6
+ local ns1=$ns1_v6
local vtep1_ip=2001:db8:1000::1
local vtep2_ip=2001:db8:2000::1
local grp1=239.1.1.1
@@ -2217,7 +2213,7 @@ mdb_torture_ipv4_ipv6()
mdb_torture_ipv6_ipv6()
{
- local ns1=ns1_v6
+ local ns1=$ns1_v6
local vtep1_ip=2001:db8:1000::1
local vtep2_ip=2001:db8:2000::1
local grp1=ff0e::1
diff --git a/tools/testing/selftests/net/test_vxlan_nolocalbypass.sh b/tools/testing/selftests/net/test_vxlan_nolocalbypass.sh
index f75212bf142c..b8805983b728 100755
--- a/tools/testing/selftests/net/test_vxlan_nolocalbypass.sh
+++ b/tools/testing/selftests/net/test_vxlan_nolocalbypass.sh
@@ -9,9 +9,8 @@
# option and verifies that packets are no longer received by the second VXLAN
# device.
+source lib.sh
ret=0
-# Kselftest framework requirement - SKIP code is 4.
-ksft_skip=4
TESTS="
nolocalbypass
@@ -98,20 +97,19 @@ tc_check_packets()
setup()
{
- ip netns add ns1
+ setup_ns ns1
- ip -n ns1 link set dev lo up
- ip -n ns1 address add 192.0.2.1/32 dev lo
- ip -n ns1 address add 198.51.100.1/32 dev lo
+ ip -n $ns1 address add 192.0.2.1/32 dev lo
+ ip -n $ns1 address add 198.51.100.1/32 dev lo
- ip -n ns1 link add name vx0 up type vxlan id 100 local 198.51.100.1 \
+ ip -n $ns1 link add name vx0 up type vxlan id 100 local 198.51.100.1 \
dstport 4789 nolearning
- ip -n ns1 link add name vx1 up type vxlan id 100 dstport 4790
+ ip -n $ns1 link add name vx1 up type vxlan id 100 dstport 4790
}
cleanup()
{
- ip netns del ns1 &> /dev/null
+ cleanup_ns $ns1
}
################################################################################
@@ -122,40 +120,40 @@ nolocalbypass()
local smac=00:01:02:03:04:05
local dmac=00:0a:0b:0c:0d:0e
- run_cmd "bridge -n ns1 fdb add $dmac dev vx0 self static dst 192.0.2.1 port 4790"
+ run_cmd "bridge -n $ns1 fdb add $dmac dev vx0 self static dst 192.0.2.1 port 4790"
- run_cmd "tc -n ns1 qdisc add dev vx1 clsact"
- run_cmd "tc -n ns1 filter add dev vx1 ingress pref 1 handle 101 proto all flower src_mac $smac dst_mac $dmac action pass"
+ run_cmd "tc -n $ns1 qdisc add dev vx1 clsact"
+ run_cmd "tc -n $ns1 filter add dev vx1 ingress pref 1 handle 101 proto all flower src_mac $smac dst_mac $dmac action pass"
- run_cmd "tc -n ns1 qdisc add dev lo clsact"
- run_cmd "tc -n ns1 filter add dev lo ingress pref 1 handle 101 proto ip flower ip_proto udp dst_port 4790 action drop"
+ run_cmd "tc -n $ns1 qdisc add dev lo clsact"
+ run_cmd "tc -n $ns1 filter add dev lo ingress pref 1 handle 101 proto ip flower ip_proto udp dst_port 4790 action drop"
- run_cmd "ip -n ns1 -d -j link show dev vx0 | jq -e '.[][\"linkinfo\"][\"info_data\"][\"localbypass\"] == true'"
+ run_cmd "ip -n $ns1 -d -j link show dev vx0 | jq -e '.[][\"linkinfo\"][\"info_data\"][\"localbypass\"] == true'"
log_test $? 0 "localbypass enabled"
- run_cmd "ip netns exec ns1 mausezahn vx0 -a $smac -b $dmac -c 1 -p 100 -q"
+ run_cmd "ip netns exec $ns1 mausezahn vx0 -a $smac -b $dmac -c 1 -p 100 -q"
- tc_check_packets "ns1" "dev vx1 ingress" 101 1
+ tc_check_packets "$ns1" "dev vx1 ingress" 101 1
log_test $? 0 "Packet received by local VXLAN device - localbypass"
- run_cmd "ip -n ns1 link set dev vx0 type vxlan nolocalbypass"
+ run_cmd "ip -n $ns1 link set dev vx0 type vxlan nolocalbypass"
- run_cmd "ip -n ns1 -d -j link show dev vx0 | jq -e '.[][\"linkinfo\"][\"info_data\"][\"localbypass\"] == false'"
+ run_cmd "ip -n $ns1 -d -j link show dev vx0 | jq -e '.[][\"linkinfo\"][\"info_data\"][\"localbypass\"] == false'"
log_test $? 0 "localbypass disabled"
- run_cmd "ip netns exec ns1 mausezahn vx0 -a $smac -b $dmac -c 1 -p 100 -q"
+ run_cmd "ip netns exec $ns1 mausezahn vx0 -a $smac -b $dmac -c 1 -p 100 -q"
- tc_check_packets "ns1" "dev vx1 ingress" 101 1
+ tc_check_packets "$ns1" "dev vx1 ingress" 101 1
log_test $? 0 "Packet not received by local VXLAN device - nolocalbypass"
- run_cmd "ip -n ns1 link set dev vx0 type vxlan localbypass"
+ run_cmd "ip -n $ns1 link set dev vx0 type vxlan localbypass"
- run_cmd "ip -n ns1 -d -j link show dev vx0 | jq -e '.[][\"linkinfo\"][\"info_data\"][\"localbypass\"] == true'"
+ run_cmd "ip -n $ns1 -d -j link show dev vx0 | jq -e '.[][\"linkinfo\"][\"info_data\"][\"localbypass\"] == true'"
log_test $? 0 "localbypass enabled"
- run_cmd "ip netns exec ns1 mausezahn vx0 -a $smac -b $dmac -c 1 -p 100 -q"
+ run_cmd "ip netns exec $ns1 mausezahn vx0 -a $smac -b $dmac -c 1 -p 100 -q"
- tc_check_packets "ns1" "dev vx1 ingress" 101 2
+ tc_check_packets "$ns1" "dev vx1 ingress" 101 2
log_test $? 0 "Packet received by local VXLAN device - localbypass"
}
diff --git a/tools/testing/selftests/net/test_vxlan_under_vrf.sh b/tools/testing/selftests/net/test_vxlan_under_vrf.sh
index 1fd1250ebc66..ae8fbe3f0779 100755
--- a/tools/testing/selftests/net/test_vxlan_under_vrf.sh
+++ b/tools/testing/selftests/net/test_vxlan_under_vrf.sh
@@ -43,15 +43,14 @@
# This tests both the connectivity between vm-1 and vm-2, and that the underlay
# can be moved in and out of the vrf by unsetting and setting veth0's master.
+source lib.sh
set -e
cleanup() {
ip link del veth-hv-1 2>/dev/null || true
ip link del veth-tap 2>/dev/null || true
- for ns in hv-1 hv-2 vm-1 vm-2; do
- ip netns del $ns 2>/dev/null || true
- done
+ cleanup_ns $hv_1 $hv_2 $vm_1 $vm_2
}
# Clean start
@@ -60,72 +59,75 @@ cleanup &> /dev/null
[[ $1 == "clean" ]] && exit 0
trap cleanup EXIT
+setup_ns hv_1 hv_2 vm_1 vm_2
+hv[1]=$hv_1
+hv[2]=$hv_2
+vm[1]=$vm_1
+vm[2]=$vm_2
# Setup "Hypervisors" simulated with netns
ip link add veth-hv-1 type veth peer name veth-hv-2
setup-hv-networking() {
- hv=$1
+ id=$1
- ip netns add hv-$hv
- ip link set veth-hv-$hv netns hv-$hv
- ip -netns hv-$hv link set veth-hv-$hv name veth0
+ ip link set veth-hv-$id netns ${hv[$id]}
+ ip -netns ${hv[$id]} link set veth-hv-$id name veth0
- ip -netns hv-$hv link add vrf-underlay type vrf table 1
- ip -netns hv-$hv link set vrf-underlay up
- ip -netns hv-$hv addr add 172.16.0.$hv/24 dev veth0
- ip -netns hv-$hv link set veth0 up
+ ip -netns ${hv[$id]} link add vrf-underlay type vrf table 1
+ ip -netns ${hv[$id]} link set vrf-underlay up
+ ip -netns ${hv[$id]} addr add 172.16.0.$id/24 dev veth0
+ ip -netns ${hv[$id]} link set veth0 up
- ip -netns hv-$hv link add br0 type bridge
- ip -netns hv-$hv link set br0 up
+ ip -netns ${hv[$id]} link add br0 type bridge
+ ip -netns ${hv[$id]} link set br0 up
- ip -netns hv-$hv link add vxlan0 type vxlan id 10 local 172.16.0.$hv dev veth0 dstport 4789
- ip -netns hv-$hv link set vxlan0 master br0
- ip -netns hv-$hv link set vxlan0 up
+ ip -netns ${hv[$id]} link add vxlan0 type vxlan id 10 local 172.16.0.$id dev veth0 dstport 4789
+ ip -netns ${hv[$id]} link set vxlan0 master br0
+ ip -netns ${hv[$id]} link set vxlan0 up
}
setup-hv-networking 1
setup-hv-networking 2
# Check connectivity between HVs by pinging hv-2 from hv-1
echo -n "Checking HV connectivity "
-ip netns exec hv-1 ping -c 1 -W 1 172.16.0.2 &> /dev/null || (echo "[FAIL]"; false)
+ip netns exec $hv_1 ping -c 1 -W 1 172.16.0.2 &> /dev/null || (echo "[FAIL]"; false)
echo "[ OK ]"
# Setups a "VM" simulated by a netns an a veth pair
setup-vm() {
id=$1
- ip netns add vm-$id
ip link add veth-tap type veth peer name veth-hv
- ip link set veth-tap netns hv-$id
- ip -netns hv-$id link set veth-tap master br0
- ip -netns hv-$id link set veth-tap up
+ ip link set veth-tap netns ${hv[$id]}
+ ip -netns ${hv[$id]} link set veth-tap master br0
+ ip -netns ${hv[$id]} link set veth-tap up
ip link set veth-hv address 02:1d:8d:dd:0c:6$id
- ip link set veth-hv netns vm-$id
- ip -netns vm-$id addr add 10.0.0.$id/24 dev veth-hv
- ip -netns vm-$id link set veth-hv up
+ ip link set veth-hv netns ${vm[$id]}
+ ip -netns ${vm[$id]} addr add 10.0.0.$id/24 dev veth-hv
+ ip -netns ${vm[$id]} link set veth-hv up
}
setup-vm 1
setup-vm 2
# Setup VTEP routes to make ARP work
-bridge -netns hv-1 fdb add 00:00:00:00:00:00 dev vxlan0 dst 172.16.0.2 self permanent
-bridge -netns hv-2 fdb add 00:00:00:00:00:00 dev vxlan0 dst 172.16.0.1 self permanent
+bridge -netns $hv_1 fdb add 00:00:00:00:00:00 dev vxlan0 dst 172.16.0.2 self permanent
+bridge -netns $hv_2 fdb add 00:00:00:00:00:00 dev vxlan0 dst 172.16.0.1 self permanent
echo -n "Check VM connectivity through VXLAN (underlay in the default VRF) "
-ip netns exec vm-1 ping -c 1 -W 1 10.0.0.2 &> /dev/null || (echo "[FAIL]"; false)
+ip netns exec $vm_1 ping -c 1 -W 1 10.0.0.2 &> /dev/null || (echo "[FAIL]"; false)
echo "[ OK ]"
# Move the underlay to a non-default VRF
-ip -netns hv-1 link set veth0 vrf vrf-underlay
-ip -netns hv-1 link set vxlan0 down
-ip -netns hv-1 link set vxlan0 up
-ip -netns hv-2 link set veth0 vrf vrf-underlay
-ip -netns hv-2 link set vxlan0 down
-ip -netns hv-2 link set vxlan0 up
+ip -netns $hv_1 link set veth0 vrf vrf-underlay
+ip -netns $hv_1 link set vxlan0 down
+ip -netns $hv_1 link set vxlan0 up
+ip -netns $hv_2 link set veth0 vrf vrf-underlay
+ip -netns $hv_2 link set vxlan0 down
+ip -netns $hv_2 link set vxlan0 up
echo -n "Check VM connectivity through VXLAN (underlay in a VRF) "
-ip netns exec vm-1 ping -c 1 -W 1 10.0.0.2 &> /dev/null || (echo "[FAIL]"; false)
+ip netns exec $vm_1 ping -c 1 -W 1 10.0.0.2 &> /dev/null || (echo "[FAIL]"; false)
echo "[ OK ]"
diff --git a/tools/testing/selftests/net/test_vxlan_vnifiltering.sh b/tools/testing/selftests/net/test_vxlan_vnifiltering.sh
index 8c3ac0a72545..6127a78ee988 100755
--- a/tools/testing/selftests/net/test_vxlan_vnifiltering.sh
+++ b/tools/testing/selftests/net/test_vxlan_vnifiltering.sh
@@ -78,10 +78,8 @@
#
#
# This test tests the new vxlan vnifiltering api
-
+source lib.sh
ret=0
-# Kselftest framework requirement - SKIP code is 4.
-ksft_skip=4
# all tests in this script. Can be overridden with -t option
TESTS="
@@ -148,18 +146,18 @@ run_cmd()
}
check_hv_connectivity() {
- ip netns exec hv-1 ping -c 1 -W 1 $1 &>/dev/null
+ ip netns exec $hv_1 ping -c 1 -W 1 $1 &>/dev/null
sleep 1
- ip netns exec hv-1 ping -c 1 -W 1 $2 &>/dev/null
+ ip netns exec $hv_1 ping -c 1 -W 1 $2 &>/dev/null
return $?
}
check_vm_connectivity() {
- run_cmd "ip netns exec vm-11 ping -c 1 -W 1 10.0.10.12"
+ run_cmd "ip netns exec $vm_11 ping -c 1 -W 1 10.0.10.12"
log_test $? 0 "VM connectivity over $1 (ipv4 default rdst)"
- run_cmd "ip netns exec vm-21 ping -c 1 -W 1 10.0.10.22"
+ run_cmd "ip netns exec $vm_21 ping -c 1 -W 1 10.0.10.22"
log_test $? 0 "VM connectivity over $1 (ipv6 default rdst)"
}
@@ -167,26 +165,23 @@ cleanup() {
ip link del veth-hv-1 2>/dev/null || true
ip link del vethhv-11 vethhv-12 vethhv-21 vethhv-22 2>/dev/null || true
- for ns in hv-1 hv-2 vm-11 vm-21 vm-12 vm-22 vm-31 vm-32; do
- ip netns del $ns 2>/dev/null || true
- done
+ cleanup_ns $hv_1 $hv_2 $vm_11 $vm_21 $vm_12 $vm_22 $vm_31 $vm_32
}
trap cleanup EXIT
setup-hv-networking() {
- hv=$1
+ id=$1
local1=$2
mask1=$3
local2=$4
mask2=$5
- ip netns add hv-$hv
- ip link set veth-hv-$hv netns hv-$hv
- ip -netns hv-$hv link set veth-hv-$hv name veth0
- ip -netns hv-$hv addr add $local1/$mask1 dev veth0
- ip -netns hv-$hv addr add $local2/$mask2 dev veth0
- ip -netns hv-$hv link set veth0 up
+ ip link set veth-hv-$id netns ${hv[$id]}
+ ip -netns ${hv[$id]} link set veth-hv-$id name veth0
+ ip -netns ${hv[$id]} addr add $local1/$mask1 dev veth0
+ ip -netns ${hv[$id]} addr add $local2/$mask2 dev veth0
+ ip -netns ${hv[$id]} link set veth0 up
}
# Setups a "VM" simulated by a netns an a veth pair
@@ -208,21 +203,20 @@ setup-vm() {
lastvxlandev=""
# create bridge
- ip -netns hv-$hvid link add br$brid type bridge vlan_filtering 1 vlan_default_pvid 0 \
+ ip -netns ${hv[$hvid]} link add br$brid type bridge vlan_filtering 1 vlan_default_pvid 0 \
mcast_snooping 0
- ip -netns hv-$hvid link set br$brid up
+ ip -netns ${hv[$hvid]} link set br$brid up
# create vm namespace and interfaces and connect to hypervisor
# namespace
- ip netns add vm-$vmid
hvvethif="vethhv-$vmid"
vmvethif="veth-$vmid"
ip link add $hvvethif type veth peer name $vmvethif
- ip link set $hvvethif netns hv-$hvid
- ip link set $vmvethif netns vm-$vmid
- ip -netns hv-$hvid link set $hvvethif up
- ip -netns vm-$vmid link set $vmvethif up
- ip -netns hv-$hvid link set $hvvethif master br$brid
+ ip link set $hvvethif netns ${hv[$hvid]}
+ ip link set $vmvethif netns ${vm[$vmid]}
+ ip -netns ${hv[$hvid]} link set $hvvethif up
+ ip -netns ${vm[$vmid]} link set $vmvethif up
+ ip -netns ${hv[$hvid]} link set $hvvethif master br$brid
# configure VM vlan/vni filtering on hypervisor
for vmap in $(echo $vattrs | cut -d "," -f1- --output-delimiter=' ')
@@ -234,9 +228,9 @@ setup-vm() {
local vtype=$(echo $vmap | awk -F'-' '{print ($5)}')
local port=$(echo $vmap | awk -F'-' '{print ($6)}')
- ip -netns vm-$vmid link add name $vmvethif.$vid link $vmvethif type vlan id $vid
- ip -netns vm-$vmid addr add 10.0.$vid.$vmid/24 dev $vmvethif.$vid
- ip -netns vm-$vmid link set $vmvethif.$vid up
+ ip -netns ${vm[$vmid]} link add name $vmvethif.$vid link $vmvethif type vlan id $vid
+ ip -netns ${vm[$vmid]} addr add 10.0.$vid.$vmid/24 dev $vmvethif.$vid
+ ip -netns ${vm[$vmid]} link set $vmvethif.$vid up
tid=$vid
vxlandev="vxlan$brid"
@@ -268,35 +262,35 @@ setup-vm() {
# create vxlan device
if [ "$vxlandev" != "$lastvxlandev" ]; then
- ip -netns hv-$hvid link add $vxlandev type vxlan local $localip $vxlandevflags dev veth0 2>/dev/null
- ip -netns hv-$hvid link set $vxlandev master br$brid
- ip -netns hv-$hvid link set $vxlandev up
+ ip -netns ${hv[$hvid]} link add $vxlandev type vxlan local $localip $vxlandevflags dev veth0 2>/dev/null
+ ip -netns ${hv[$hvid]} link set $vxlandev master br$brid
+ ip -netns ${hv[$hvid]} link set $vxlandev up
lastvxlandev=$vxlandev
fi
# add vlan
- bridge -netns hv-$hvid vlan add vid $vid dev $hvvethif
- bridge -netns hv-$hvid vlan add vid $vid pvid dev $vxlandev
+ bridge -netns ${hv[$hvid]} vlan add vid $vid dev $hvvethif
+ bridge -netns ${hv[$hvid]} vlan add vid $vid pvid dev $vxlandev
# Add bridge vni filter for tx
if [[ -n $vtype && $vtype == "metadata" || $vtype == "vnifilter" || $vtype == "vnifilterg" ]]; then
- bridge -netns hv-$hvid link set dev $vxlandev vlan_tunnel on
- bridge -netns hv-$hvid vlan add dev $vxlandev vid $vid tunnel_info id $tid
+ bridge -netns ${hv[$hvid]} link set dev $vxlandev vlan_tunnel on
+ bridge -netns ${hv[$hvid]} vlan add dev $vxlandev vid $vid tunnel_info id $tid
fi
if [[ -n $vtype && $vtype == "metadata" ]]; then
- bridge -netns hv-$hvid fdb add 00:00:00:00:00:00 dev $vxlandev \
+ bridge -netns ${hv[$hvid]} fdb add 00:00:00:00:00:00 dev $vxlandev \
src_vni $tid vni $tid dst $group self
elif [[ -n $vtype && $vtype == "vnifilter" ]]; then
# Add per vni rx filter with 'bridge vni' api
- bridge -netns hv-$hvid vni add dev $vxlandev vni $tid
+ bridge -netns ${hv[$hvid]} vni add dev $vxlandev vni $tid
elif [[ -n $vtype && $vtype == "vnifilterg" ]]; then
# Add per vni group config with 'bridge vni' api
if [ -n "$group" ]; then
if [ $mcast -eq 1 ]; then
- bridge -netns hv-$hvid vni add dev $vxlandev vni $tid group $group
+ bridge -netns ${hv[$hvid]} vni add dev $vxlandev vni $tid group $group
else
- bridge -netns hv-$hvid vni add dev $vxlandev vni $tid remote $group
+ bridge -netns ${hv[$hvid]} vni add dev $vxlandev vni $tid remote $group
fi
fi
fi
@@ -306,14 +300,14 @@ setup-vm() {
setup_vnifilter_api()
{
ip link add veth-host type veth peer name veth-testns
- ip netns add testns
- ip link set veth-testns netns testns
+ setup_ns testns
+ ip link set veth-testns netns $testns
}
cleanup_vnifilter_api()
{
ip link del veth-host 2>/dev/null || true
- ip netns del testns 2>/dev/null || true
+ ip netns del $testns 2>/dev/null || true
}
# tests vxlan filtering api
@@ -331,52 +325,52 @@ vxlan_vnifilter_api()
# Duplicate vni test
# create non-vnifiltering traditional vni device
- run_cmd "ip -netns testns link add vxlan100 type vxlan id 100 local $localip dev veth-testns dstport 4789"
+ run_cmd "ip -netns $testns link add vxlan100 type vxlan id 100 local $localip dev veth-testns dstport 4789"
log_test $? 0 "Create traditional vxlan device"
# create vni filtering device
- run_cmd "ip -netns testns link add vxlan-ext1 type vxlan vnifilter local $localip dev veth-testns dstport 4789"
+ run_cmd "ip -netns $testns link add vxlan-ext1 type vxlan vnifilter local $localip dev veth-testns dstport 4789"
log_test $? 1 "Cannot create vnifilter device without external flag"
- run_cmd "ip -netns testns link add vxlan-ext1 type vxlan external vnifilter local $localip dev veth-testns dstport 4789"
+ run_cmd "ip -netns $testns link add vxlan-ext1 type vxlan external vnifilter local $localip dev veth-testns dstport 4789"
log_test $? 0 "Creating external vxlan device with vnifilter flag"
- run_cmd "bridge -netns testns vni add dev vxlan-ext1 vni 100"
+ run_cmd "bridge -netns $testns vni add dev vxlan-ext1 vni 100"
log_test $? 0 "Cannot set in-use vni id on vnifiltering device"
- run_cmd "bridge -netns testns vni add dev vxlan-ext1 vni 200"
+ run_cmd "bridge -netns $testns vni add dev vxlan-ext1 vni 200"
log_test $? 0 "Set new vni id on vnifiltering device"
- run_cmd "ip -netns testns link add vxlan-ext2 type vxlan external vnifilter local $localip dev veth-testns dstport 4789"
+ run_cmd "ip -netns $testns link add vxlan-ext2 type vxlan external vnifilter local $localip dev veth-testns dstport 4789"
log_test $? 0 "Create second external vxlan device with vnifilter flag"
- run_cmd "bridge -netns testns vni add dev vxlan-ext2 vni 200"
+ run_cmd "bridge -netns $testns vni add dev vxlan-ext2 vni 200"
log_test $? 255 "Cannot set in-use vni id on vnifiltering device"
- run_cmd "bridge -netns testns vni add dev vxlan-ext2 vni 300"
+ run_cmd "bridge -netns $testns vni add dev vxlan-ext2 vni 300"
log_test $? 0 "Set new vni id on vnifiltering device"
# check in bridge vni show
- run_cmd "bridge -netns testns vni add dev vxlan-ext2 vni 300"
+ run_cmd "bridge -netns $testns vni add dev vxlan-ext2 vni 300"
log_test $? 0 "Update vni id on vnifiltering device"
- run_cmd "bridge -netns testns vni add dev vxlan-ext2 vni 400"
+ run_cmd "bridge -netns $testns vni add dev vxlan-ext2 vni 400"
log_test $? 0 "Add new vni id on vnifiltering device"
# add multicast group per vni
- run_cmd "bridge -netns testns vni add dev vxlan-ext1 vni 200 group $group"
+ run_cmd "bridge -netns $testns vni add dev vxlan-ext1 vni 200 group $group"
log_test $? 0 "Set multicast group on existing vni"
# add multicast group per vni
- run_cmd "bridge -netns testns vni add dev vxlan-ext2 vni 300 group $group"
+ run_cmd "bridge -netns $testns vni add dev vxlan-ext2 vni 300 group $group"
log_test $? 0 "Set multicast group on existing vni"
# set vnifilter on an existing external vxlan device
- run_cmd "ip -netns testns link set dev vxlan-ext1 type vxlan external vnifilter"
+ run_cmd "ip -netns $testns link set dev vxlan-ext1 type vxlan external vnifilter"
log_test $? 2 "Cannot set vnifilter flag on a device"
# change vxlan vnifilter flag
- run_cmd "ip -netns testns link set dev vxlan-ext1 type vxlan external novnifilter"
+ run_cmd "ip -netns $testns link set dev vxlan-ext1 type vxlan external novnifilter"
log_test $? 2 "Cannot unset vnifilter flag on a device"
}
@@ -390,12 +384,20 @@ vxlan_vnifilter_datapath()
hv1addr2="2002:fee1::1"
hv2addr2="2002:fee1::2"
+ setup_ns hv_1 hv_2
+ hv[1]=$hv_1
+ hv[2]=$hv_2
ip link add veth-hv-1 type veth peer name veth-hv-2
setup-hv-networking 1 $hv1addr1 24 $hv1addr2 64 $hv2addr1 $hv2addr2
setup-hv-networking 2 $hv2addr1 24 $hv2addr2 64 $hv1addr1 $hv1addr2
check_hv_connectivity hv2addr1 hv2addr2
+ setup_ns vm_11 vm_21 vm_12 vm_22
+ vm[11]=$vm_11
+ vm[21]=$vm_21
+ vm[12]=$vm_12
+ vm[22]=$vm_22
setup-vm 1 11 1 10-v4-$hv1addr1-$hv2addr1-vnifilter,20-v4-$hv1addr1-$hv2addr1-vnifilter 0
setup-vm 1 21 2 10-v6-$hv1addr2-$hv2addr2-vnifilter,20-v6-$hv1addr2-$hv2addr2-vnifilter 0
@@ -415,12 +417,20 @@ vxlan_vnifilter_datapath_pervni()
hv1addr2="2002:fee1::1"
hv2addr2="2002:fee1::2"
+ setup_ns hv_1 hv_2
+ hv[1]=$hv_1
+ hv[2]=$hv_2
ip link add veth-hv-1 type veth peer name veth-hv-2
setup-hv-networking 1 $hv1addr1 24 $hv1addr2 64
setup-hv-networking 2 $hv2addr1 24 $hv2addr2 64
check_hv_connectivity hv2addr1 hv2addr2
+ setup_ns vm_11 vm_21 vm_12 vm_22
+ vm[11]=$vm_11
+ vm[21]=$vm_21
+ vm[12]=$vm_12
+ vm[22]=$vm_22
setup-vm 1 11 1 10-v4-$hv1addr1-$hv2addr1-vnifilterg,20-v4-$hv1addr1-$hv2addr1-vnifilterg 0
setup-vm 1 21 2 10-v6-$hv1addr2-$hv2addr2-vnifilterg,20-v6-$hv1addr2-$hv2addr2-vnifilterg 0
@@ -440,12 +450,20 @@ vxlan_vnifilter_datapath_mgroup()
group="239.1.1.100"
group6="ff07::1"
+ setup_ns hv_1 hv_2
+ hv[1]=$hv_1
+ hv[2]=$hv_2
ip link add veth-hv-1 type veth peer name veth-hv-2
setup-hv-networking 1 $hv1addr1 24 $hv1addr2 64
setup-hv-networking 2 $hv2addr1 24 $hv2addr2 64
check_hv_connectivity hv2addr1 hv2addr2
+ setup_ns vm_11 vm_21 vm_12 vm_22
+ vm[11]=$vm_11
+ vm[21]=$vm_21
+ vm[12]=$vm_12
+ vm[22]=$vm_22
setup-vm 1 11 1 10-v4-$hv1addr1-$group-vnifilter,20-v4-$hv1addr1-$group-vnifilter 1
setup-vm 1 21 2 "10-v6-$hv1addr2-$group6-vnifilter,20-v6-$hv1addr2-$group6-vnifilter" 1
@@ -464,12 +482,20 @@ vxlan_vnifilter_datapath_mgroup_pervni()
group="239.1.1.100"
group6="ff07::1"
+ setup_ns hv_1 hv_2
+ hv[1]=$hv_1
+ hv[2]=$hv_2
ip link add veth-hv-1 type veth peer name veth-hv-2
setup-hv-networking 1 $hv1addr1 24 $hv1addr2 64
setup-hv-networking 2 $hv2addr1 24 $hv2addr2 64
check_hv_connectivity hv2addr1 hv2addr2
+ setup_ns vm_11 vm_21 vm_12 vm_22
+ vm[11]=$vm_11
+ vm[21]=$vm_21
+ vm[12]=$vm_12
+ vm[22]=$vm_22
setup-vm 1 11 1 10-v4-$hv1addr1-$group-vnifilterg,20-v4-$hv1addr1-$group-vnifilterg 1
setup-vm 1 21 2 10-v6-$hv1addr2-$group6-vnifilterg,20-v6-$hv1addr2-$group6-vnifilterg 1
@@ -486,12 +512,22 @@ vxlan_vnifilter_metadata_and_traditional_mix()
hv1addr2="2002:fee1::1"
hv2addr2="2002:fee1::2"
+ setup_ns hv_1 hv_2
+ hv[1]=$hv_1
+ hv[2]=$hv_2
ip link add veth-hv-1 type veth peer name veth-hv-2
setup-hv-networking 1 $hv1addr1 24 $hv1addr2 64
setup-hv-networking 2 $hv2addr1 24 $hv2addr2 64
check_hv_connectivity hv2addr1 hv2addr2
+ setup_ns vm_11 vm_21 vm_31 vm_12 vm_22 vm_32
+ vm[11]=$vm_11
+ vm[21]=$vm_21
+ vm[31]=$vm_31
+ vm[12]=$vm_12
+ vm[22]=$vm_22
+ vm[32]=$vm_32
setup-vm 1 11 1 10-v4-$hv1addr1-$hv2addr1-vnifilter,20-v4-$hv1addr1-$hv2addr1-vnifilter 0
setup-vm 1 21 2 10-v6-$hv1addr2-$hv2addr2-vnifilter,20-v6-$hv1addr2-$hv2addr2-vnifilter 0
setup-vm 1 31 3 30-v4-$hv1addr1-$hv2addr1-default-4790,40-v6-$hv1addr2-$hv2addr2-default-4790,50-v4-$hv1addr1-$hv2addr1-metadata-4791 0
@@ -504,13 +540,13 @@ vxlan_vnifilter_metadata_and_traditional_mix()
check_vm_connectivity "vnifiltering vxlan pervni remote mix"
# check VM connectivity over traditional/non-vxlan filtering vxlan devices
- run_cmd "ip netns exec vm-31 ping -c 1 -W 1 10.0.30.32"
+ run_cmd "ip netns exec $vm_31 ping -c 1 -W 1 10.0.30.32"
log_test $? 0 "VM connectivity over traditional vxlan (ipv4 default rdst)"
- run_cmd "ip netns exec vm-31 ping -c 1 -W 1 10.0.40.32"
+ run_cmd "ip netns exec $vm_31 ping -c 1 -W 1 10.0.40.32"
log_test $? 0 "VM connectivity over traditional vxlan (ipv6 default rdst)"
- run_cmd "ip netns exec vm-31 ping -c 1 -W 1 10.0.50.32"
+ run_cmd "ip netns exec $vm_31 ping -c 1 -W 1 10.0.50.32"
log_test $? 0 "VM connectivity over metadata nonfiltering vxlan (ipv4 default rdst)"
}
diff --git a/tools/testing/selftests/net/traceroute.sh b/tools/testing/selftests/net/traceroute.sh
index de9ca97abc30..282f14760940 100755
--- a/tools/testing/selftests/net/traceroute.sh
+++ b/tools/testing/selftests/net/traceroute.sh
@@ -4,6 +4,7 @@
# Run traceroute/traceroute6 tests
#
+source lib.sh
VERBOSE=0
PAUSE_ON_FAIL=no
@@ -69,9 +70,6 @@ create_ns()
[ -z "${addr}" ] && addr="-"
[ -z "${addr6}" ] && addr6="-"
- ip netns add ${ns}
-
- ip netns exec ${ns} ip link set lo up
if [ "${addr}" != "-" ]; then
ip netns exec ${ns} ip addr add dev lo ${addr}
fi
@@ -160,12 +158,7 @@ connect_ns()
cleanup_traceroute6()
{
- local ns
-
- for ns in host-1 host-2 router-1 router-2
- do
- ip netns del ${ns} 2>/dev/null
- done
+ cleanup_ns $h1 $h2 $r1 $r2
}
setup_traceroute6()
@@ -176,33 +169,34 @@ setup_traceroute6()
cleanup_traceroute6
set -e
- create_ns host-1
- create_ns host-2
- create_ns router-1
- create_ns router-2
+ setup_ns h1 h2 r1 r2
+ create_ns $h1
+ create_ns $h2
+ create_ns $r1
+ create_ns $r2
# Setup N3
- connect_ns router-2 eth3 - 2000:103::2/64 host-2 eth3 - 2000:103::4/64
- ip netns exec host-2 ip route add default via 2000:103::2
+ connect_ns $r2 eth3 - 2000:103::2/64 $h2 eth3 - 2000:103::4/64
+ ip netns exec $h2 ip route add default via 2000:103::2
# Setup N2
- connect_ns router-1 eth2 - 2000:102::1/64 router-2 eth2 - 2000:102::2/64
- ip netns exec router-1 ip route add default via 2000:102::2
+ connect_ns $r1 eth2 - 2000:102::1/64 $r2 eth2 - 2000:102::2/64
+ ip netns exec $r1 ip route add default via 2000:102::2
# Setup N1. host-1 and router-2 connect to a bridge in router-1.
- ip netns exec router-1 ip link add name ${brdev} type bridge
- ip netns exec router-1 ip link set ${brdev} up
- ip netns exec router-1 ip addr add 2000:101::1/64 dev ${brdev}
+ ip netns exec $r1 ip link add name ${brdev} type bridge
+ ip netns exec $r1 ip link set ${brdev} up
+ ip netns exec $r1 ip addr add 2000:101::1/64 dev ${brdev}
- connect_ns host-1 eth0 - 2000:101::3/64 router-1 eth0 - -
- ip netns exec router-1 ip link set dev eth0 master ${brdev}
- ip netns exec host-1 ip route add default via 2000:101::1
+ connect_ns $h1 eth0 - 2000:101::3/64 $r1 eth0 - -
+ ip netns exec $r1 ip link set dev eth0 master ${brdev}
+ ip netns exec $h1 ip route add default via 2000:101::1
- connect_ns router-2 eth1 - 2000:101::2/64 router-1 eth1 - -
- ip netns exec router-1 ip link set dev eth1 master ${brdev}
+ connect_ns $r2 eth1 - 2000:101::2/64 $r1 eth1 - -
+ ip netns exec $r1 ip link set dev eth1 master ${brdev}
# Prime the network
- ip netns exec host-1 ping6 -c5 2000:103::4 >/dev/null 2>&1
+ ip netns exec $h1 ping6 -c5 2000:103::4 >/dev/null 2>&1
set +e
}
@@ -217,7 +211,7 @@ run_traceroute6()
setup_traceroute6
# traceroute6 host-2 from host-1 (expects 2000:102::2)
- run_cmd host-1 "traceroute6 2000:103::4 | grep -q 2000:102::2"
+ run_cmd $h1 "traceroute6 2000:103::4 | grep -q 2000:102::2"
log_test $? 0 "IPV6 traceroute"
cleanup_traceroute6
@@ -240,12 +234,7 @@ run_traceroute6()
cleanup_traceroute()
{
- local ns
-
- for ns in host-1 host-2 router
- do
- ip netns del ${ns} 2>/dev/null
- done
+ cleanup_ns $h1 $h2 $router
}
setup_traceroute()
@@ -254,24 +243,25 @@ setup_traceroute()
cleanup_traceroute
set -e
- create_ns host-1
- create_ns host-2
- create_ns router
+ setup_ns h1 h2 router
+ create_ns $h1
+ create_ns $h2
+ create_ns $router
- connect_ns host-1 eth0 1.0.1.3/24 - \
- router eth1 1.0.3.1/24 -
- ip netns exec host-1 ip route add default via 1.0.1.1
+ connect_ns $h1 eth0 1.0.1.3/24 - \
+ $router eth1 1.0.3.1/24 -
+ ip netns exec $h1 ip route add default via 1.0.1.1
- ip netns exec router ip addr add 1.0.1.1/24 dev eth1
- ip netns exec router sysctl -qw \
+ ip netns exec $router ip addr add 1.0.1.1/24 dev eth1
+ ip netns exec $router sysctl -qw \
net.ipv4.icmp_errors_use_inbound_ifaddr=1
- connect_ns host-2 eth0 1.0.2.4/24 - \
- router eth2 1.0.2.1/24 -
- ip netns exec host-2 ip route add default via 1.0.2.1
+ connect_ns $h2 eth0 1.0.2.4/24 - \
+ $router eth2 1.0.2.1/24 -
+ ip netns exec $h2 ip route add default via 1.0.2.1
# Prime the network
- ip netns exec host-1 ping -c5 1.0.2.4 >/dev/null 2>&1
+ ip netns exec $h1 ping -c5 1.0.2.4 >/dev/null 2>&1
set +e
}
@@ -286,7 +276,7 @@ run_traceroute()
setup_traceroute
# traceroute host-2 from host-1 (expects 1.0.1.1). Takes a while.
- run_cmd host-1 "traceroute 1.0.2.4 | grep -q 1.0.1.1"
+ run_cmd $h1 "traceroute 1.0.2.4 | grep -q 1.0.1.1"
log_test $? 0 "IPV4 traceroute"
cleanup_traceroute
diff --git a/tools/testing/selftests/net/unicast_extensions.sh b/tools/testing/selftests/net/unicast_extensions.sh
index 2d10ccac898a..b7a2cb9e7477 100755
--- a/tools/testing/selftests/net/unicast_extensions.sh
+++ b/tools/testing/selftests/net/unicast_extensions.sh
@@ -28,8 +28,7 @@
# These tests provide an easy way to flip the expected result of any
# of these behaviors for testing kernel patches that change them.
-# Kselftest framework requirement - SKIP code is 4.
-ksft_skip=4
+source ./lib.sh
# nettest can be run from PATH or from same directory as this selftest
if ! which nettest >/dev/null; then
@@ -61,20 +60,20 @@ _do_segmenttest(){
# foo --- bar
# Arguments: ip_a ip_b prefix_length test_description
#
- # Caller must set up foo-ns and bar-ns namespaces
+ # Caller must set up $foo_ns and $bar_ns namespaces
# containing linked veth devices foo and bar,
# respectively.
- ip -n foo-ns address add $1/$3 dev foo || return 1
- ip -n foo-ns link set foo up || return 1
- ip -n bar-ns address add $2/$3 dev bar || return 1
- ip -n bar-ns link set bar up || return 1
+ ip -n $foo_ns address add $1/$3 dev foo || return 1
+ ip -n $foo_ns link set foo up || return 1
+ ip -n $bar_ns address add $2/$3 dev bar || return 1
+ ip -n $bar_ns link set bar up || return 1
- ip netns exec foo-ns timeout 2 ping -c 1 $2 || return 1
- ip netns exec bar-ns timeout 2 ping -c 1 $1 || return 1
+ ip netns exec $foo_ns timeout 2 ping -c 1 $2 || return 1
+ ip netns exec $bar_ns timeout 2 ping -c 1 $1 || return 1
- nettest -B -N bar-ns -O foo-ns -r $1 || return 1
- nettest -B -N foo-ns -O bar-ns -r $2 || return 1
+ nettest -B -N $bar_ns -O $foo_ns -r $1 || return 1
+ nettest -B -N $foo_ns -O $bar_ns -r $2 || return 1
return 0
}
@@ -88,31 +87,31 @@ _do_route_test(){
# Arguments: foo_ip foo1_ip bar1_ip bar_ip prefix_len test_description
# Displays test result and returns success or failure.
- # Caller must set up foo-ns, bar-ns, and router-ns
+ # Caller must set up $foo_ns, $bar_ns, and $router_ns
# containing linked veth devices foo-foo1, bar1-bar
- # (foo in foo-ns, foo1 and bar1 in router-ns, and
- # bar in bar-ns).
-
- ip -n foo-ns address add $1/$5 dev foo || return 1
- ip -n foo-ns link set foo up || return 1
- ip -n foo-ns route add default via $2 || return 1
- ip -n bar-ns address add $4/$5 dev bar || return 1
- ip -n bar-ns link set bar up || return 1
- ip -n bar-ns route add default via $3 || return 1
- ip -n router-ns address add $2/$5 dev foo1 || return 1
- ip -n router-ns link set foo1 up || return 1
- ip -n router-ns address add $3/$5 dev bar1 || return 1
- ip -n router-ns link set bar1 up || return 1
-
- echo 1 | ip netns exec router-ns tee /proc/sys/net/ipv4/ip_forward
-
- ip netns exec foo-ns timeout 2 ping -c 1 $2 || return 1
- ip netns exec foo-ns timeout 2 ping -c 1 $4 || return 1
- ip netns exec bar-ns timeout 2 ping -c 1 $3 || return 1
- ip netns exec bar-ns timeout 2 ping -c 1 $1 || return 1
-
- nettest -B -N bar-ns -O foo-ns -r $1 || return 1
- nettest -B -N foo-ns -O bar-ns -r $4 || return 1
+ # (foo in $foo_ns, foo1 and bar1 in $router_ns, and
+ # bar in $bar_ns).
+
+ ip -n $foo_ns address add $1/$5 dev foo || return 1
+ ip -n $foo_ns link set foo up || return 1
+ ip -n $foo_ns route add default via $2 || return 1
+ ip -n $bar_ns address add $4/$5 dev bar || return 1
+ ip -n $bar_ns link set bar up || return 1
+ ip -n $bar_ns route add default via $3 || return 1
+ ip -n $router_ns address add $2/$5 dev foo1 || return 1
+ ip -n $router_ns link set foo1 up || return 1
+ ip -n $router_ns address add $3/$5 dev bar1 || return 1
+ ip -n $router_ns link set bar1 up || return 1
+
+ echo 1 | ip netns exec $router_ns tee /proc/sys/net/ipv4/ip_forward
+
+ ip netns exec $foo_ns timeout 2 ping -c 1 $2 || return 1
+ ip netns exec $foo_ns timeout 2 ping -c 1 $4 || return 1
+ ip netns exec $bar_ns timeout 2 ping -c 1 $3 || return 1
+ ip netns exec $bar_ns timeout 2 ping -c 1 $1 || return 1
+
+ nettest -B -N $bar_ns -O $foo_ns -r $1 || return 1
+ nettest -B -N $foo_ns -O $bar_ns -r $4 || return 1
return 0
}
@@ -121,17 +120,15 @@ segmenttest(){
# Sets up veth link and tries to connect over it.
# Arguments: ip_a ip_b prefix_len test_description
hide_output
- ip netns add foo-ns
- ip netns add bar-ns
- ip link add foo netns foo-ns type veth peer name bar netns bar-ns
+ setup_ns foo_ns bar_ns
+ ip link add foo netns $foo_ns type veth peer name bar netns $bar_ns
test_result=0
_do_segmenttest "$@" || test_result=1
- ip netns pids foo-ns | xargs -r kill -9
- ip netns pids bar-ns | xargs -r kill -9
- ip netns del foo-ns
- ip netns del bar-ns
+ ip netns pids $foo_ns | xargs -r kill -9
+ ip netns pids $bar_ns | xargs -r kill -9
+ cleanup_ns $foo_ns $bar_ns
show_output
# inverted tests will expect failure instead of success
@@ -147,21 +144,17 @@ route_test(){
# Returns success or failure.
hide_output
- ip netns add foo-ns
- ip netns add bar-ns
- ip netns add router-ns
- ip link add foo netns foo-ns type veth peer name foo1 netns router-ns
- ip link add bar netns bar-ns type veth peer name bar1 netns router-ns
+ setup_ns foo_ns bar_ns router_ns
+ ip link add foo netns $foo_ns type veth peer name foo1 netns $router_ns
+ ip link add bar netns $bar_ns type veth peer name bar1 netns $router_ns
test_result=0
_do_route_test "$@" || test_result=1
- ip netns pids foo-ns | xargs -r kill -9
- ip netns pids bar-ns | xargs -r kill -9
- ip netns pids router-ns | xargs -r kill -9
- ip netns del foo-ns
- ip netns del bar-ns
- ip netns del router-ns
+ ip netns pids $foo_ns | xargs -r kill -9
+ ip netns pids $bar_ns | xargs -r kill -9
+ ip netns pids $router_ns | xargs -r kill -9
+ cleanup_ns $foo_ns $bar_ns $router_ns
show_output
diff --git a/tools/testing/selftests/net/vrf-xfrm-tests.sh b/tools/testing/selftests/net/vrf-xfrm-tests.sh
index 452638ae8aed..b64dd891699d 100755
--- a/tools/testing/selftests/net/vrf-xfrm-tests.sh
+++ b/tools/testing/selftests/net/vrf-xfrm-tests.sh
@@ -3,9 +3,7 @@
#
# Various combinations of VRF with xfrms and qdisc.
-# Kselftest framework requirement - SKIP code is 4.
-ksft_skip=4
-
+source lib.sh
PAUSE_ON_FAIL=no
VERBOSE=0
ret=0
@@ -67,7 +65,7 @@ run_cmd_host1()
printf " COMMAND: $cmd\n"
fi
- out=$(eval ip netns exec host1 $cmd 2>&1)
+ out=$(eval ip netns exec $host1 $cmd 2>&1)
rc=$?
if [ "$VERBOSE" = "1" ]; then
if [ -n "$out" ]; then
@@ -116,9 +114,6 @@ create_ns()
[ -z "${addr}" ] && addr="-"
[ -z "${addr6}" ] && addr6="-"
- ip netns add ${ns}
-
- ip -netns ${ns} link set lo up
if [ "${addr}" != "-" ]; then
ip -netns ${ns} addr add dev lo ${addr}
fi
@@ -177,25 +172,25 @@ connect_ns()
cleanup()
{
- ip netns del host1
- ip netns del host2
+ cleanup_ns $host1 $host2
}
setup()
{
- create_ns "host1"
- create_ns "host2"
+ setup_ns host1 host2
+ create_ns "$host1"
+ create_ns "$host2"
- connect_ns "host1" eth0 ${HOST1_4}/24 ${HOST1_6}/64 \
- "host2" eth0 ${HOST2_4}/24 ${HOST2_6}/64
+ connect_ns "$host1" eth0 ${HOST1_4}/24 ${HOST1_6}/64 \
+ "$host2" eth0 ${HOST2_4}/24 ${HOST2_6}/64
- create_vrf "host1" ${VRF} ${TABLE}
- ip -netns host1 link set dev eth0 master ${VRF}
+ create_vrf "$host1" ${VRF} ${TABLE}
+ ip -netns $host1 link set dev eth0 master ${VRF}
}
cleanup_xfrm()
{
- for ns in host1 host2
+ for ns in $host1 $host2
do
for x in state policy
do
@@ -218,57 +213,57 @@ setup_xfrm()
#
# host1 - IPv4 out
- ip -netns host1 xfrm policy add \
+ ip -netns $host1 xfrm policy add \
src ${h1_4} dst ${h2_4} ${devarg} dir out \
tmpl src ${HOST1_4} dst ${HOST2_4} proto esp mode tunnel
# host2 - IPv4 in
- ip -netns host2 xfrm policy add \
+ ip -netns $host2 xfrm policy add \
src ${h1_4} dst ${h2_4} dir in \
tmpl src ${HOST1_4} dst ${HOST2_4} proto esp mode tunnel
# host1 - IPv4 in
- ip -netns host1 xfrm policy add \
+ ip -netns $host1 xfrm policy add \
src ${h2_4} dst ${h1_4} ${devarg} dir in \
tmpl src ${HOST2_4} dst ${HOST1_4} proto esp mode tunnel
# host2 - IPv4 out
- ip -netns host2 xfrm policy add \
+ ip -netns $host2 xfrm policy add \
src ${h2_4} dst ${h1_4} dir out \
tmpl src ${HOST2_4} dst ${HOST1_4} proto esp mode tunnel
# host1 - IPv6 out
- ip -6 -netns host1 xfrm policy add \
+ ip -6 -netns $host1 xfrm policy add \
src ${h1_6} dst ${h2_6} ${devarg} dir out \
tmpl src ${HOST1_6} dst ${HOST2_6} proto esp mode tunnel
# host2 - IPv6 in
- ip -6 -netns host2 xfrm policy add \
+ ip -6 -netns $host2 xfrm policy add \
src ${h1_6} dst ${h2_6} dir in \
tmpl src ${HOST1_6} dst ${HOST2_6} proto esp mode tunnel
# host1 - IPv6 in
- ip -6 -netns host1 xfrm policy add \
+ ip -6 -netns $host1 xfrm policy add \
src ${h2_6} dst ${h1_6} ${devarg} dir in \
tmpl src ${HOST2_6} dst ${HOST1_6} proto esp mode tunnel
# host2 - IPv6 out
- ip -6 -netns host2 xfrm policy add \
+ ip -6 -netns $host2 xfrm policy add \
src ${h2_6} dst ${h1_6} dir out \
tmpl src ${HOST2_6} dst ${HOST1_6} proto esp mode tunnel
#
# state
#
- ip -netns host1 xfrm state add src ${HOST1_4} dst ${HOST2_4} \
+ ip -netns $host1 xfrm state add src ${HOST1_4} dst ${HOST2_4} \
proto esp spi ${SPI_1} reqid 0 mode tunnel \
replay-window 4 replay-oseq 0x4 \
auth-trunc 'hmac(sha1)' ${AUTH_1} 96 \
enc 'cbc(aes)' ${ENC_1} \
sel src ${h1_4} dst ${h2_4} ${devarg}
- ip -netns host2 xfrm state add src ${HOST1_4} dst ${HOST2_4} \
+ ip -netns $host2 xfrm state add src ${HOST1_4} dst ${HOST2_4} \
proto esp spi ${SPI_1} reqid 0 mode tunnel \
replay-window 4 replay-oseq 0x4 \
auth-trunc 'hmac(sha1)' ${AUTH_1} 96 \
@@ -276,14 +271,14 @@ setup_xfrm()
sel src ${h1_4} dst ${h2_4}
- ip -netns host1 xfrm state add src ${HOST2_4} dst ${HOST1_4} \
+ ip -netns $host1 xfrm state add src ${HOST2_4} dst ${HOST1_4} \
proto esp spi ${SPI_2} reqid 0 mode tunnel \
replay-window 4 replay-oseq 0x4 \
auth-trunc 'hmac(sha1)' ${AUTH_2} 96 \
enc 'cbc(aes)' ${ENC_2} \
sel src ${h2_4} dst ${h1_4} ${devarg}
- ip -netns host2 xfrm state add src ${HOST2_4} dst ${HOST1_4} \
+ ip -netns $host2 xfrm state add src ${HOST2_4} dst ${HOST1_4} \
proto esp spi ${SPI_2} reqid 0 mode tunnel \
replay-window 4 replay-oseq 0x4 \
auth-trunc 'hmac(sha1)' ${AUTH_2} 96 \
@@ -291,14 +286,14 @@ setup_xfrm()
sel src ${h2_4} dst ${h1_4}
- ip -6 -netns host1 xfrm state add src ${HOST1_6} dst ${HOST2_6} \
+ ip -6 -netns $host1 xfrm state add src ${HOST1_6} dst ${HOST2_6} \
proto esp spi ${SPI_1} reqid 0 mode tunnel \
replay-window 4 replay-oseq 0x4 \
auth-trunc 'hmac(sha1)' ${AUTH_1} 96 \
enc 'cbc(aes)' ${ENC_1} \
sel src ${h1_6} dst ${h2_6} ${devarg}
- ip -6 -netns host2 xfrm state add src ${HOST1_6} dst ${HOST2_6} \
+ ip -6 -netns $host2 xfrm state add src ${HOST1_6} dst ${HOST2_6} \
proto esp spi ${SPI_1} reqid 0 mode tunnel \
replay-window 4 replay-oseq 0x4 \
auth-trunc 'hmac(sha1)' ${AUTH_1} 96 \
@@ -306,14 +301,14 @@ setup_xfrm()
sel src ${h1_6} dst ${h2_6}
- ip -6 -netns host1 xfrm state add src ${HOST2_6} dst ${HOST1_6} \
+ ip -6 -netns $host1 xfrm state add src ${HOST2_6} dst ${HOST1_6} \
proto esp spi ${SPI_2} reqid 0 mode tunnel \
replay-window 4 replay-oseq 0x4 \
auth-trunc 'hmac(sha1)' ${AUTH_2} 96 \
enc 'cbc(aes)' ${ENC_2} \
sel src ${h2_6} dst ${h1_6} ${devarg}
- ip -6 -netns host2 xfrm state add src ${HOST2_6} dst ${HOST1_6} \
+ ip -6 -netns $host2 xfrm state add src ${HOST2_6} dst ${HOST1_6} \
proto esp spi ${SPI_2} reqid 0 mode tunnel \
replay-window 4 replay-oseq 0x4 \
auth-trunc 'hmac(sha1)' ${AUTH_2} 96 \
@@ -323,22 +318,22 @@ setup_xfrm()
cleanup_xfrm_dev()
{
- ip -netns host1 li del xfrm0
- ip -netns host2 addr del ${XFRM2_4}/24 dev eth0
- ip -netns host2 addr del ${XFRM2_6}/64 dev eth0
+ ip -netns $host1 li del xfrm0
+ ip -netns $host2 addr del ${XFRM2_4}/24 dev eth0
+ ip -netns $host2 addr del ${XFRM2_6}/64 dev eth0
}
setup_xfrm_dev()
{
local vrfarg="vrf ${VRF}"
- ip -netns host1 li add type xfrm dev eth0 if_id ${IF_ID}
- ip -netns host1 li set xfrm0 ${vrfarg} up
- ip -netns host1 addr add ${XFRM1_4}/24 dev xfrm0
- ip -netns host1 addr add ${XFRM1_6}/64 dev xfrm0
+ ip -netns $host1 li add type xfrm dev eth0 if_id ${IF_ID}
+ ip -netns $host1 li set xfrm0 ${vrfarg} up
+ ip -netns $host1 addr add ${XFRM1_4}/24 dev xfrm0
+ ip -netns $host1 addr add ${XFRM1_6}/64 dev xfrm0
- ip -netns host2 addr add ${XFRM2_4}/24 dev eth0
- ip -netns host2 addr add ${XFRM2_6}/64 dev eth0
+ ip -netns $host2 addr add ${XFRM2_4}/24 dev eth0
+ ip -netns $host2 addr add ${XFRM2_6}/64 dev eth0
setup_xfrm ${XFRM1_4} ${XFRM2_4} ${XFRM1_6} ${XFRM2_6} "if_id ${IF_ID}"
}
diff --git a/tools/testing/selftests/net/vrf_route_leaking.sh b/tools/testing/selftests/net/vrf_route_leaking.sh
index dedc52562b4f..2da32f4c479b 100755
--- a/tools/testing/selftests/net/vrf_route_leaking.sh
+++ b/tools/testing/selftests/net/vrf_route_leaking.sh
@@ -58,6 +58,7 @@
# to send an ICMP error back to the source when the ttl of a packet reaches 1
# while it is forwarded between different vrfs.
+source lib.sh
VERBOSE=0
PAUSE_ON_FAIL=no
DEFAULT_TTYPE=sym
@@ -171,11 +172,7 @@ run_cmd_grep()
cleanup()
{
- local ns
-
- for ns in h1 h2 r1 r2; do
- ip netns del $ns 2>/dev/null
- done
+ cleanup_ns $h1 $h2 $r1 $r2
}
setup_vrf()
@@ -212,72 +209,69 @@ setup_sym()
#
# create nodes as namespaces
- #
- for ns in h1 h2 r1; do
- ip netns add $ns
- ip -netns $ns link set lo up
-
- case "${ns}" in
- h[12]) ip netns exec $ns sysctl -q -w net.ipv6.conf.all.forwarding=0
- ip netns exec $ns sysctl -q -w net.ipv6.conf.all.keep_addr_on_down=1
- ;;
- r1) ip netns exec $ns sysctl -q -w net.ipv4.ip_forward=1
- ip netns exec $ns sysctl -q -w net.ipv6.conf.all.forwarding=1
- esac
+ setup_ns h1 h2 r1
+ for ns in $h1 $h2 $r1; do
+ if echo $ns | grep -q h[12]-; then
+ ip netns exec $ns sysctl -q -w net.ipv6.conf.all.forwarding=0
+ ip netns exec $ns sysctl -q -w net.ipv6.conf.all.keep_addr_on_down=1
+ else
+ ip netns exec $ns sysctl -q -w net.ipv4.ip_forward=1
+ ip netns exec $ns sysctl -q -w net.ipv6.conf.all.forwarding=1
+ fi
done
#
# create interconnects
#
- ip -netns h1 link add eth0 type veth peer name r1h1
- ip -netns h1 link set r1h1 netns r1 name eth0 up
+ ip -netns $h1 link add eth0 type veth peer name r1h1
+ ip -netns $h1 link set r1h1 netns $r1 name eth0 up
- ip -netns h2 link add eth0 type veth peer name r1h2
- ip -netns h2 link set r1h2 netns r1 name eth1 up
+ ip -netns $h2 link add eth0 type veth peer name r1h2
+ ip -netns $h2 link set r1h2 netns $r1 name eth1 up
#
# h1
#
- ip -netns h1 addr add dev eth0 ${H1_N1_IP}/24
- ip -netns h1 -6 addr add dev eth0 ${H1_N1_IP6}/64 nodad
- ip -netns h1 link set eth0 up
+ ip -netns $h1 addr add dev eth0 ${H1_N1_IP}/24
+ ip -netns $h1 -6 addr add dev eth0 ${H1_N1_IP6}/64 nodad
+ ip -netns $h1 link set eth0 up
# h1 to h2 via r1
- ip -netns h1 route add ${H2_N2} via ${R1_N1_IP} dev eth0
- ip -netns h1 -6 route add ${H2_N2_6} via "${R1_N1_IP6}" dev eth0
+ ip -netns $h1 route add ${H2_N2} via ${R1_N1_IP} dev eth0
+ ip -netns $h1 -6 route add ${H2_N2_6} via "${R1_N1_IP6}" dev eth0
#
# h2
#
- ip -netns h2 addr add dev eth0 ${H2_N2_IP}/24
- ip -netns h2 -6 addr add dev eth0 ${H2_N2_IP6}/64 nodad
- ip -netns h2 link set eth0 up
+ ip -netns $h2 addr add dev eth0 ${H2_N2_IP}/24
+ ip -netns $h2 -6 addr add dev eth0 ${H2_N2_IP6}/64 nodad
+ ip -netns $h2 link set eth0 up
# h2 to h1 via r1
- ip -netns h2 route add default via ${R1_N2_IP} dev eth0
- ip -netns h2 -6 route add default via ${R1_N2_IP6} dev eth0
+ ip -netns $h2 route add default via ${R1_N2_IP} dev eth0
+ ip -netns $h2 -6 route add default via ${R1_N2_IP6} dev eth0
#
# r1
#
- setup_vrf r1
- create_vrf r1 blue 1101
- create_vrf r1 red 1102
- ip -netns r1 link set mtu 1400 dev eth1
- ip -netns r1 link set eth0 vrf blue up
- ip -netns r1 link set eth1 vrf red up
- ip -netns r1 addr add dev eth0 ${R1_N1_IP}/24
- ip -netns r1 -6 addr add dev eth0 ${R1_N1_IP6}/64 nodad
- ip -netns r1 addr add dev eth1 ${R1_N2_IP}/24
- ip -netns r1 -6 addr add dev eth1 ${R1_N2_IP6}/64 nodad
+ setup_vrf $r1
+ create_vrf $r1 blue 1101
+ create_vrf $r1 red 1102
+ ip -netns $r1 link set mtu 1400 dev eth1
+ ip -netns $r1 link set eth0 vrf blue up
+ ip -netns $r1 link set eth1 vrf red up
+ ip -netns $r1 addr add dev eth0 ${R1_N1_IP}/24
+ ip -netns $r1 -6 addr add dev eth0 ${R1_N1_IP6}/64 nodad
+ ip -netns $r1 addr add dev eth1 ${R1_N2_IP}/24
+ ip -netns $r1 -6 addr add dev eth1 ${R1_N2_IP6}/64 nodad
# Route leak from blue to red
- ip -netns r1 route add vrf blue ${H2_N2} dev red
- ip -netns r1 -6 route add vrf blue ${H2_N2_6} dev red
+ ip -netns $r1 route add vrf blue ${H2_N2} dev red
+ ip -netns $r1 -6 route add vrf blue ${H2_N2_6} dev red
# Route leak from red to blue
- ip -netns r1 route add vrf red ${H1_N1} dev blue
- ip -netns r1 -6 route add vrf red ${H1_N1_6} dev blue
+ ip -netns $r1 route add vrf red ${H1_N1} dev blue
+ ip -netns $r1 -6 route add vrf red ${H1_N1_6} dev blue
# Wait for ip config to settle
@@ -293,90 +287,87 @@ setup_asym()
#
# create nodes as namespaces
- #
- for ns in h1 h2 r1 r2; do
- ip netns add $ns
- ip -netns $ns link set lo up
-
- case "${ns}" in
- h[12]) ip netns exec $ns sysctl -q -w net.ipv6.conf.all.forwarding=0
- ip netns exec $ns sysctl -q -w net.ipv6.conf.all.keep_addr_on_down=1
- ;;
- r[12]) ip netns exec $ns sysctl -q -w net.ipv4.ip_forward=1
- ip netns exec $ns sysctl -q -w net.ipv6.conf.all.forwarding=1
- esac
+ setup_ns h1 h2 r1 r2
+ for ns in $h1 $h2 $r1 $r2; do
+ if echo $ns | grep -q h[12]-; then
+ ip netns exec $ns sysctl -q -w net.ipv6.conf.all.forwarding=0
+ ip netns exec $ns sysctl -q -w net.ipv6.conf.all.keep_addr_on_down=1
+ else
+ ip netns exec $ns sysctl -q -w net.ipv4.ip_forward=1
+ ip netns exec $ns sysctl -q -w net.ipv6.conf.all.forwarding=1
+ fi
done
#
# create interconnects
#
- ip -netns h1 link add eth0 type veth peer name r1h1
- ip -netns h1 link set r1h1 netns r1 name eth0 up
+ ip -netns $h1 link add eth0 type veth peer name r1h1
+ ip -netns $h1 link set r1h1 netns $r1 name eth0 up
- ip -netns h1 link add eth1 type veth peer name r2h1
- ip -netns h1 link set r2h1 netns r2 name eth0 up
+ ip -netns $h1 link add eth1 type veth peer name r2h1
+ ip -netns $h1 link set r2h1 netns $r2 name eth0 up
- ip -netns h2 link add eth0 type veth peer name r1h2
- ip -netns h2 link set r1h2 netns r1 name eth1 up
+ ip -netns $h2 link add eth0 type veth peer name r1h2
+ ip -netns $h2 link set r1h2 netns $r1 name eth1 up
- ip -netns h2 link add eth1 type veth peer name r2h2
- ip -netns h2 link set r2h2 netns r2 name eth1 up
+ ip -netns $h2 link add eth1 type veth peer name r2h2
+ ip -netns $h2 link set r2h2 netns $r2 name eth1 up
#
# h1
#
- ip -netns h1 link add br0 type bridge
- ip -netns h1 link set br0 up
- ip -netns h1 addr add dev br0 ${H1_N1_IP}/24
- ip -netns h1 -6 addr add dev br0 ${H1_N1_IP6}/64 nodad
- ip -netns h1 link set eth0 master br0 up
- ip -netns h1 link set eth1 master br0 up
+ ip -netns $h1 link add br0 type bridge
+ ip -netns $h1 link set br0 up
+ ip -netns $h1 addr add dev br0 ${H1_N1_IP}/24
+ ip -netns $h1 -6 addr add dev br0 ${H1_N1_IP6}/64 nodad
+ ip -netns $h1 link set eth0 master br0 up
+ ip -netns $h1 link set eth1 master br0 up
# h1 to h2 via r1
- ip -netns h1 route add ${H2_N2} via ${R1_N1_IP} dev br0
- ip -netns h1 -6 route add ${H2_N2_6} via "${R1_N1_IP6}" dev br0
+ ip -netns $h1 route add ${H2_N2} via ${R1_N1_IP} dev br0
+ ip -netns $h1 -6 route add ${H2_N2_6} via "${R1_N1_IP6}" dev br0
#
# h2
#
- ip -netns h2 link add br0 type bridge
- ip -netns h2 link set br0 up
- ip -netns h2 addr add dev br0 ${H2_N2_IP}/24
- ip -netns h2 -6 addr add dev br0 ${H2_N2_IP6}/64 nodad
- ip -netns h2 link set eth0 master br0 up
- ip -netns h2 link set eth1 master br0 up
+ ip -netns $h2 link add br0 type bridge
+ ip -netns $h2 link set br0 up
+ ip -netns $h2 addr add dev br0 ${H2_N2_IP}/24
+ ip -netns $h2 -6 addr add dev br0 ${H2_N2_IP6}/64 nodad
+ ip -netns $h2 link set eth0 master br0 up
+ ip -netns $h2 link set eth1 master br0 up
# h2 to h1 via r2
- ip -netns h2 route add default via ${R2_N2_IP} dev br0
- ip -netns h2 -6 route add default via ${R2_N2_IP6} dev br0
+ ip -netns $h2 route add default via ${R2_N2_IP} dev br0
+ ip -netns $h2 -6 route add default via ${R2_N2_IP6} dev br0
#
# r1
#
- setup_vrf r1
- create_vrf r1 blue 1101
- create_vrf r1 red 1102
- ip -netns r1 link set mtu 1400 dev eth1
- ip -netns r1 link set eth0 vrf blue up
- ip -netns r1 link set eth1 vrf red up
- ip -netns r1 addr add dev eth0 ${R1_N1_IP}/24
- ip -netns r1 -6 addr add dev eth0 ${R1_N1_IP6}/64 nodad
- ip -netns r1 addr add dev eth1 ${R1_N2_IP}/24
- ip -netns r1 -6 addr add dev eth1 ${R1_N2_IP6}/64 nodad
+ setup_vrf $r1
+ create_vrf $r1 blue 1101
+ create_vrf $r1 red 1102
+ ip -netns $r1 link set mtu 1400 dev eth1
+ ip -netns $r1 link set eth0 vrf blue up
+ ip -netns $r1 link set eth1 vrf red up
+ ip -netns $r1 addr add dev eth0 ${R1_N1_IP}/24
+ ip -netns $r1 -6 addr add dev eth0 ${R1_N1_IP6}/64 nodad
+ ip -netns $r1 addr add dev eth1 ${R1_N2_IP}/24
+ ip -netns $r1 -6 addr add dev eth1 ${R1_N2_IP6}/64 nodad
# Route leak from blue to red
- ip -netns r1 route add vrf blue ${H2_N2} dev red
- ip -netns r1 -6 route add vrf blue ${H2_N2_6} dev red
+ ip -netns $r1 route add vrf blue ${H2_N2} dev red
+ ip -netns $r1 -6 route add vrf blue ${H2_N2_6} dev red
# No route leak from red to blue
#
# r2
#
- ip -netns r2 addr add dev eth0 ${R2_N1_IP}/24
- ip -netns r2 -6 addr add dev eth0 ${R2_N1_IP6}/64 nodad
- ip -netns r2 addr add dev eth1 ${R2_N2_IP}/24
- ip -netns r2 -6 addr add dev eth1 ${R2_N2_IP6}/64 nodad
+ ip -netns $r2 addr add dev eth0 ${R2_N1_IP}/24
+ ip -netns $r2 -6 addr add dev eth0 ${R2_N1_IP6}/64 nodad
+ ip -netns $r2 addr add dev eth1 ${R2_N2_IP}/24
+ ip -netns $r2 -6 addr add dev eth1 ${R2_N2_IP6}/64 nodad
# Wait for ip config to settle
sleep 2
@@ -384,14 +375,14 @@ setup_asym()
check_connectivity()
{
- ip netns exec h1 ping -c1 -w1 ${H2_N2_IP} >/dev/null 2>&1
+ ip netns exec $h1 ping -c1 -w1 ${H2_N2_IP} >/dev/null 2>&1
log_test $? 0 "Basic IPv4 connectivity"
return $?
}
check_connectivity6()
{
- ip netns exec h1 "${ping6}" -c1 -w1 ${H2_N2_IP6} >/dev/null 2>&1
+ ip netns exec $h1 "${ping6}" -c1 -w1 ${H2_N2_IP6} >/dev/null 2>&1
log_test $? 0 "Basic IPv6 connectivity"
return $?
}
@@ -426,7 +417,7 @@ ipv4_traceroute()
check_connectivity || return
- run_cmd_grep "${R1_N1_IP}" ip netns exec h1 traceroute ${H2_N2_IP}
+ run_cmd_grep "${R1_N1_IP}" ip netns exec $h1 traceroute ${H2_N2_IP}
log_test $? 0 "Traceroute reports a hop on r1"
}
@@ -449,7 +440,7 @@ ipv6_traceroute()
check_connectivity6 || return
- run_cmd_grep "${R1_N1_IP6}" ip netns exec h1 traceroute6 ${H2_N2_IP6}
+ run_cmd_grep "${R1_N1_IP6}" ip netns exec $h1 traceroute6 ${H2_N2_IP6}
log_test $? 0 "Traceroute6 reports a hop on r1"
}
@@ -470,7 +461,7 @@ ipv4_ping_ttl()
check_connectivity || return
- run_cmd_grep "Time to live exceeded" ip netns exec h1 ping -t1 -c1 -W2 ${H2_N2_IP}
+ run_cmd_grep "Time to live exceeded" ip netns exec $h1 ping -t1 -c1 -W2 ${H2_N2_IP}
log_test $? 0 "Ping received ICMP ttl exceeded"
}
@@ -491,7 +482,7 @@ ipv4_ping_frag()
check_connectivity || return
- run_cmd_grep "Frag needed" ip netns exec h1 ping -s 1450 -Mdo -c1 -W2 ${H2_N2_IP}
+ run_cmd_grep "Frag needed" ip netns exec $h1 ping -s 1450 -Mdo -c1 -W2 ${H2_N2_IP}
log_test $? 0 "Ping received ICMP Frag needed"
}
@@ -512,7 +503,7 @@ ipv6_ping_ttl()
check_connectivity6 || return
- run_cmd_grep "Time exceeded: Hop limit" ip netns exec h1 "${ping6}" -t1 -c1 -W2 ${H2_N2_IP6}
+ run_cmd_grep "Time exceeded: Hop limit" ip netns exec $h1 "${ping6}" -t1 -c1 -W2 ${H2_N2_IP6}
log_test $? 0 "Ping received ICMP Hop limit"
}
@@ -533,7 +524,7 @@ ipv6_ping_frag()
check_connectivity6 || return
- run_cmd_grep "Packet too big" ip netns exec h1 "${ping6}" -s 1450 -Mdo -c1 -W2 ${H2_N2_IP6}
+ run_cmd_grep "Packet too big" ip netns exec $h1 "${ping6}" -s 1450 -Mdo -c1 -W2 ${H2_N2_IP6}
log_test $? 0 "Ping received ICMP Packet too big"
}
diff --git a/tools/testing/selftests/net/vrf_strict_mode_test.sh b/tools/testing/selftests/net/vrf_strict_mode_test.sh
index 417d214264f3..01552b542544 100755
--- a/tools/testing/selftests/net/vrf_strict_mode_test.sh
+++ b/tools/testing/selftests/net/vrf_strict_mode_test.sh
@@ -3,9 +3,7 @@
# This test is designed for testing the new VRF strict_mode functionality.
-# Kselftest framework requirement - SKIP code is 4.
-ksft_skip=4
-
+source lib.sh
ret=0
# identifies the "init" network namespace which is often called root network
@@ -247,13 +245,12 @@ setup()
{
modprobe vrf
- ip netns add testns
- ip netns exec testns ip link set lo up
+ setup_ns testns
}
cleanup()
{
- ip netns del testns 2>/dev/null
+ ip netns del $testns 2>/dev/null
ip link del vrf100 2>/dev/null
ip link del vrf101 2>/dev/null
@@ -298,28 +295,28 @@ vrf_strict_mode_tests_testns()
{
log_section "VRF strict_mode test on testns network namespace"
- vrf_strict_mode_check_support testns
+ vrf_strict_mode_check_support $testns
- strict_mode_check_default testns
+ strict_mode_check_default $testns
- enable_strict_mode_and_check testns
+ enable_strict_mode_and_check $testns
- add_vrf_and_check testns vrf100 100
- config_vrf_and_check testns 10.0.100.1/24 vrf100
+ add_vrf_and_check $testns vrf100 100
+ config_vrf_and_check $testns 10.0.100.1/24 vrf100
- add_vrf_and_check_fail testns vrf101 100
+ add_vrf_and_check_fail $testns vrf101 100
- add_vrf_and_check_fail testns vrf102 100
+ add_vrf_and_check_fail $testns vrf102 100
- add_vrf_and_check testns vrf200 200
+ add_vrf_and_check $testns vrf200 200
- disable_strict_mode_and_check testns
+ disable_strict_mode_and_check $testns
- add_vrf_and_check testns vrf101 100
+ add_vrf_and_check $testns vrf101 100
- add_vrf_and_check testns vrf102 100
+ add_vrf_and_check $testns vrf102 100
- #the strict_mode is disabled in the testns
+ #the strict_mode is disabled in the $testns
}
vrf_strict_mode_tests_mix()
@@ -328,25 +325,25 @@ vrf_strict_mode_tests_mix()
read_strict_mode_compare_and_check init 1
- read_strict_mode_compare_and_check testns 0
+ read_strict_mode_compare_and_check $testns 0
- del_vrf_and_check testns vrf101
+ del_vrf_and_check $testns vrf101
- del_vrf_and_check testns vrf102
+ del_vrf_and_check $testns vrf102
disable_strict_mode_and_check init
- enable_strict_mode_and_check testns
+ enable_strict_mode_and_check $testns
enable_strict_mode_and_check init
enable_strict_mode_and_check init
- disable_strict_mode_and_check testns
- disable_strict_mode_and_check testns
+ disable_strict_mode_and_check $testns
+ disable_strict_mode_and_check $testns
read_strict_mode_compare_and_check init 1
- read_strict_mode_compare_and_check testns 0
+ read_strict_mode_compare_and_check $testns 0
}
################################################################################
diff --git a/tools/testing/selftests/tc-testing/Makefile b/tools/testing/selftests/tc-testing/Makefile
index e8b3dde4fa16..9153e3428a77 100644
--- a/tools/testing/selftests/tc-testing/Makefile
+++ b/tools/testing/selftests/tc-testing/Makefile
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
-TEST_PROGS += ./tdc.sh
+TEST_PROGS += tdc.sh
TEST_FILES := action-ebpf tdc*.py Tdc*.py plugins plugin-lib tc-tests scripts
include ../lib.mk
diff --git a/tools/testing/selftests/tc-testing/tc-tests/filters/concurrency.json b/tools/testing/selftests/tc-testing/tc-tests/filters/flower.json
index c2a433a4737e..6b08c0642069 100644
--- a/tools/testing/selftests/tc-testing/tc-tests/filters/concurrency.json
+++ b/tools/testing/selftests/tc-testing/tc-tests/filters/flower.json
@@ -173,5 +173,103 @@
"$TC qdisc del dev $DEV2 ingress",
"/bin/rm -rf $BATCH_DIR"
]
+ },
+ {
+ "id": "2ff3",
+ "name": "Add flower with max handle and then dump it",
+ "category": [
+ "filter",
+ "flower"
+ ],
+ "setup": [
+ "$TC qdisc add dev $DEV2 ingress"
+ ],
+ "cmdUnderTest": "$TC filter add dev $DEV2 protocol ip pref 1 ingress handle 0xffffffff flower action ok",
+ "expExitCode": "0",
+ "verifyCmd": "$TC filter show dev $DEV2 ingress",
+ "matchPattern": "filter protocol ip pref 1 flower.*handle 0xffffffff",
+ "matchCount": "1",
+ "teardown": [
+ "$TC qdisc del dev $DEV2 ingress"
+ ]
+ },
+ {
+ "id": "d052",
+ "name": "Add 1M filters with the same action",
+ "category": [
+ "filter",
+ "flower"
+ ],
+ "setup": [
+ "$TC qdisc add dev $DEV2 ingress",
+ "./tdc_batch.py $DEV2 $BATCH_FILE --share_action -n 1000000"
+ ],
+ "cmdUnderTest": "$TC -b $BATCH_FILE",
+ "expExitCode": "0",
+ "verifyCmd": "$TC actions list action gact",
+ "matchPattern": "action order 0: gact action drop.*index 1 ref 1000000 bind 1000000",
+ "matchCount": "1",
+ "teardown": [
+ "$TC qdisc del dev $DEV2 ingress",
+ "/bin/rm $BATCH_FILE"
+ ]
+ },
+ {
+ "id": "4cbd",
+ "name": "Try to add filter with duplicate key",
+ "category": [
+ "filter",
+ "flower"
+ ],
+ "setup": [
+ "$TC qdisc add dev $DEV2 ingress",
+ "$TC filter add dev $DEV2 protocol ip prio 1 ingress flower dst_mac e4:11:22:11:4a:51 src_mac e4:11:22:11:4a:50 ip_proto tcp src_ip 1.1.1.1 dst_ip 2.2.2.2 action drop"
+ ],
+ "cmdUnderTest": "$TC filter add dev $DEV2 protocol ip prio 1 ingress flower dst_mac e4:11:22:11:4a:51 src_mac e4:11:22:11:4a:50 ip_proto tcp src_ip 1.1.1.1 dst_ip 2.2.2.2 action drop",
+ "expExitCode": "2",
+ "verifyCmd": "$TC -s filter show dev $DEV2 ingress",
+ "matchPattern": "filter protocol ip pref 1 flower chain 0 handle",
+ "matchCount": "1",
+ "teardown": [
+ "$TC qdisc del dev $DEV2 ingress"
+ ]
+ },
+ {
+ "id": "7c65",
+ "name": "Add flower filter and then terse dump it",
+ "category": [
+ "filter",
+ "flower"
+ ],
+ "setup": [
+ "$TC qdisc add dev $DEV2 ingress"
+ ],
+ "cmdUnderTest": "$TC filter add dev $DEV2 protocol ip pref 1 ingress flower dst_mac e4:11:22:11:4a:51 action drop",
+ "expExitCode": "0",
+ "verifyCmd": "$TC -br filter show dev $DEV2 ingress",
+ "matchPattern": "filter protocol ip pref 1 flower.*handle",
+ "matchCount": "1",
+ "teardown": [
+ "$TC qdisc del dev $DEV2 ingress"
+ ]
+ },
+ {
+ "id": "d45e",
+ "name": "Add flower filter and verify that terse dump doesn't output filter key",
+ "category": [
+ "filter",
+ "flower"
+ ],
+ "setup": [
+ "$TC qdisc add dev $DEV2 ingress"
+ ],
+ "cmdUnderTest": "$TC filter add dev $DEV2 protocol ip pref 1 ingress flower dst_mac e4:11:22:11:4a:51 action drop",
+ "expExitCode": "0",
+ "verifyCmd": "$TC -br filter show dev $DEV2 ingress",
+ "matchPattern": " dst_mac e4:11:22:11:4a:51",
+ "matchCount": "0",
+ "teardown": [
+ "$TC qdisc del dev $DEV2 ingress"
+ ]
}
]
diff --git a/tools/testing/selftests/tc-testing/tc-tests/filters/matchall.json b/tools/testing/selftests/tc-testing/tc-tests/filters/matchall.json
index afa1b9b0c856..f8d28c415bc3 100644
--- a/tools/testing/selftests/tc-testing/tc-tests/filters/matchall.json
+++ b/tools/testing/selftests/tc-testing/tc-tests/filters/matchall.json
@@ -480,5 +480,28 @@
"$TC qdisc del dev $DUMMY ingress",
"$TC actions del action police index 199"
]
+ },
+ {
+ "id": "2638",
+ "name": "Add matchall and try to get it",
+ "category": [
+ "filter",
+ "matchall"
+ ],
+ "plugins": {
+ "requires": "nsPlugin"
+ },
+ "setup": [
+ "$TC qdisc add dev $DEV1 clsact",
+ "$TC filter add dev $DEV1 protocol all pref 1 ingress handle 0x1234 matchall action ok"
+ ],
+ "cmdUnderTest": "$TC filter get dev $DEV1 protocol all pref 1 ingress handle 0x1234 matchall",
+ "expExitCode": "0",
+ "verifyCmd": "$TC filter show dev $DEV1 ingress",
+ "matchPattern": "filter protocol all pref 1 matchall chain 0 handle 0x1234",
+ "matchCount": "1",
+ "teardown": [
+ "$TC qdisc del dev $DEV1 clsact"
+ ]
}
]
diff --git a/tools/testing/selftests/tc-testing/tc-tests/filters/tests.json b/tools/testing/selftests/tc-testing/tc-tests/filters/tests.json
deleted file mode 100644
index 361235ad574b..000000000000
--- a/tools/testing/selftests/tc-testing/tc-tests/filters/tests.json
+++ /dev/null
@@ -1,129 +0,0 @@
-[
- {
- "id": "2638",
- "name": "Add matchall and try to get it",
- "category": [
- "filter",
- "matchall"
- ],
- "plugins": {
- "requires": "nsPlugin"
- },
- "setup": [
- "$TC qdisc add dev $DEV1 clsact",
- "$TC filter add dev $DEV1 protocol all pref 1 ingress handle 0x1234 matchall action ok"
- ],
- "cmdUnderTest": "$TC filter get dev $DEV1 protocol all pref 1 ingress handle 0x1234 matchall",
- "expExitCode": "0",
- "verifyCmd": "$TC filter show dev $DEV1 ingress",
- "matchPattern": "filter protocol all pref 1 matchall chain 0 handle 0x1234",
- "matchCount": "1",
- "teardown": [
- "$TC qdisc del dev $DEV1 clsact"
- ]
- },
- {
- "id": "2ff3",
- "name": "Add flower with max handle and then dump it",
- "category": [
- "filter",
- "flower"
- ],
- "setup": [
- "$TC qdisc add dev $DEV2 ingress"
- ],
- "cmdUnderTest": "$TC filter add dev $DEV2 protocol ip pref 1 ingress handle 0xffffffff flower action ok",
- "expExitCode": "0",
- "verifyCmd": "$TC filter show dev $DEV2 ingress",
- "matchPattern": "filter protocol ip pref 1 flower.*handle 0xffffffff",
- "matchCount": "1",
- "teardown": [
- "$TC qdisc del dev $DEV2 ingress"
- ]
- },
- {
- "id": "d052",
- "name": "Add 1M filters with the same action",
- "category": [
- "filter",
- "flower"
- ],
- "plugins": {
- "requires": "nsPlugin"
- },
- "setup": [
- "$TC qdisc add dev $DEV2 ingress",
- "./tdc_batch.py $DEV2 $BATCH_FILE --share_action -n 1000000"
- ],
- "cmdUnderTest": "$TC -b $BATCH_FILE",
- "expExitCode": "0",
- "verifyCmd": "$TC actions list action gact",
- "matchPattern": "action order 0: gact action drop.*index 1 ref 1000000 bind 1000000",
- "matchCount": "1",
- "teardown": [
- "$TC qdisc del dev $DEV2 ingress",
- "/bin/rm $BATCH_FILE"
- ]
- },
- {
- "id": "4cbd",
- "name": "Try to add filter with duplicate key",
- "category": [
- "filter",
- "flower"
- ],
- "plugins": {
- "requires": "nsPlugin"
- },
- "setup": [
- "$TC qdisc add dev $DEV2 ingress",
- "$TC filter add dev $DEV2 protocol ip prio 1 ingress flower dst_mac e4:11:22:11:4a:51 src_mac e4:11:22:11:4a:50 ip_proto tcp src_ip 1.1.1.1 dst_ip 2.2.2.2 action drop"
- ],
- "cmdUnderTest": "$TC filter add dev $DEV2 protocol ip prio 1 ingress flower dst_mac e4:11:22:11:4a:51 src_mac e4:11:22:11:4a:50 ip_proto tcp src_ip 1.1.1.1 dst_ip 2.2.2.2 action drop",
- "expExitCode": "2",
- "verifyCmd": "$TC -s filter show dev $DEV2 ingress",
- "matchPattern": "filter protocol ip pref 1 flower chain 0 handle",
- "matchCount": "1",
- "teardown": [
- "$TC qdisc del dev $DEV2 ingress"
- ]
- },
- {
- "id": "7c65",
- "name": "Add flower filter and then terse dump it",
- "category": [
- "filter",
- "flower"
- ],
- "setup": [
- "$TC qdisc add dev $DEV2 ingress"
- ],
- "cmdUnderTest": "$TC filter add dev $DEV2 protocol ip pref 1 ingress flower dst_mac e4:11:22:11:4a:51 action drop",
- "expExitCode": "0",
- "verifyCmd": "$TC -br filter show dev $DEV2 ingress",
- "matchPattern": "filter protocol ip pref 1 flower.*handle",
- "matchCount": "1",
- "teardown": [
- "$TC qdisc del dev $DEV2 ingress"
- ]
- },
- {
- "id": "d45e",
- "name": "Add flower filter and verify that terse dump doesn't output filter key",
- "category": [
- "filter",
- "flower"
- ],
- "setup": [
- "$TC qdisc add dev $DEV2 ingress"
- ],
- "cmdUnderTest": "$TC filter add dev $DEV2 protocol ip pref 1 ingress flower dst_mac e4:11:22:11:4a:51 action drop",
- "expExitCode": "0",
- "verifyCmd": "$TC -br filter show dev $DEV2 ingress",
- "matchPattern": " dst_mac e4:11:22:11:4a:51",
- "matchCount": "0",
- "teardown": [
- "$TC qdisc del dev $DEV2 ingress"
- ]
- }
-]
diff --git a/tools/testing/vsock/vsock_test.c b/tools/testing/vsock/vsock_test.c
index 01fa816868bc..66246d81d654 100644
--- a/tools/testing/vsock/vsock_test.c
+++ b/tools/testing/vsock/vsock_test.c
@@ -1232,6 +1232,171 @@ static void test_double_bind_connect_client(const struct test_opts *opts)
}
}
+#define RCVLOWAT_CREDIT_UPD_BUF_SIZE (1024 * 128)
+/* This define is the same as in 'include/linux/virtio_vsock.h':
+ * it is used to decide when to send credit update message during
+ * reading from rx queue of a socket. Value and its usage in
+ * kernel is important for this test.
+ */
+#define VIRTIO_VSOCK_MAX_PKT_BUF_SIZE (1024 * 64)
+
+static void test_stream_rcvlowat_def_cred_upd_client(const struct test_opts *opts)
+{
+ size_t buf_size;
+ void *buf;
+ int fd;
+
+ fd = vsock_stream_connect(opts->peer_cid, 1234);
+ if (fd < 0) {
+ perror("connect");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Send 1 byte more than peer's buffer size. */
+ buf_size = RCVLOWAT_CREDIT_UPD_BUF_SIZE + 1;
+
+ buf = malloc(buf_size);
+ if (!buf) {
+ perror("malloc");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Wait until peer sets needed buffer size. */
+ recv_byte(fd, 1, 0);
+
+ if (send(fd, buf, buf_size, 0) != buf_size) {
+ perror("send failed");
+ exit(EXIT_FAILURE);
+ }
+
+ free(buf);
+ close(fd);
+}
+
+static void test_stream_credit_update_test(const struct test_opts *opts,
+ bool low_rx_bytes_test)
+{
+ size_t recv_buf_size;
+ struct pollfd fds;
+ size_t buf_size;
+ void *buf;
+ int fd;
+
+ fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
+ if (fd < 0) {
+ perror("accept");
+ exit(EXIT_FAILURE);
+ }
+
+ buf_size = RCVLOWAT_CREDIT_UPD_BUF_SIZE;
+
+ if (setsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_SIZE,
+ &buf_size, sizeof(buf_size))) {
+ perror("setsockopt(SO_VM_SOCKETS_BUFFER_SIZE)");
+ exit(EXIT_FAILURE);
+ }
+
+ if (low_rx_bytes_test) {
+ /* Set new SO_RCVLOWAT here. This enables sending credit
+ * update when number of bytes if our rx queue become <
+ * SO_RCVLOWAT value.
+ */
+ recv_buf_size = 1 + VIRTIO_VSOCK_MAX_PKT_BUF_SIZE;
+
+ if (setsockopt(fd, SOL_SOCKET, SO_RCVLOWAT,
+ &recv_buf_size, sizeof(recv_buf_size))) {
+ perror("setsockopt(SO_RCVLOWAT)");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ /* Send one dummy byte here, because 'setsockopt()' above also
+ * sends special packet which tells sender to update our buffer
+ * size. This 'send_byte()' will serialize such packet with data
+ * reads in a loop below. Sender starts transmission only when
+ * it receives this single byte.
+ */
+ send_byte(fd, 1, 0);
+
+ buf = malloc(buf_size);
+ if (!buf) {
+ perror("malloc");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Wait until there will be 128KB of data in rx queue. */
+ while (1) {
+ ssize_t res;
+
+ res = recv(fd, buf, buf_size, MSG_PEEK);
+ if (res == buf_size)
+ break;
+
+ if (res <= 0) {
+ fprintf(stderr, "unexpected 'recv()' return: %zi\n", res);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ /* There is 128KB of data in the socket's rx queue, dequeue first
+ * 64KB, credit update is sent if 'low_rx_bytes_test' == true.
+ * Otherwise, credit update is sent in 'if (!low_rx_bytes_test)'.
+ */
+ recv_buf_size = VIRTIO_VSOCK_MAX_PKT_BUF_SIZE;
+ recv_buf(fd, buf, recv_buf_size, 0, recv_buf_size);
+
+ if (!low_rx_bytes_test) {
+ recv_buf_size++;
+
+ /* Updating SO_RCVLOWAT will send credit update. */
+ if (setsockopt(fd, SOL_SOCKET, SO_RCVLOWAT,
+ &recv_buf_size, sizeof(recv_buf_size))) {
+ perror("setsockopt(SO_RCVLOWAT)");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ fds.fd = fd;
+ fds.events = POLLIN | POLLRDNORM | POLLERR |
+ POLLRDHUP | POLLHUP;
+
+ /* This 'poll()' will return once we receive last byte
+ * sent by client.
+ */
+ if (poll(&fds, 1, -1) < 0) {
+ perror("poll");
+ exit(EXIT_FAILURE);
+ }
+
+ if (fds.revents & POLLERR) {
+ fprintf(stderr, "'poll()' error\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (fds.revents & (POLLIN | POLLRDNORM)) {
+ recv_buf(fd, buf, recv_buf_size, MSG_DONTWAIT, recv_buf_size);
+ } else {
+ /* These flags must be set, as there is at
+ * least 64KB of data ready to read.
+ */
+ fprintf(stderr, "POLLIN | POLLRDNORM expected\n");
+ exit(EXIT_FAILURE);
+ }
+
+ free(buf);
+ close(fd);
+}
+
+static void test_stream_cred_upd_on_low_rx_bytes(const struct test_opts *opts)
+{
+ test_stream_credit_update_test(opts, true);
+}
+
+static void test_stream_cred_upd_on_set_rcvlowat(const struct test_opts *opts)
+{
+ test_stream_credit_update_test(opts, false);
+}
+
static struct test_case test_cases[] = {
{
.name = "SOCK_STREAM connection reset",
@@ -1342,6 +1507,16 @@ static struct test_case test_cases[] = {
.run_client = test_double_bind_connect_client,
.run_server = test_double_bind_connect_server,
},
+ {
+ .name = "SOCK_STREAM virtio credit update + SO_RCVLOWAT",
+ .run_client = test_stream_rcvlowat_def_cred_upd_client,
+ .run_server = test_stream_cred_upd_on_set_rcvlowat,
+ },
+ {
+ .name = "SOCK_STREAM virtio credit update + low rx_bytes",
+ .run_client = test_stream_rcvlowat_def_cred_upd_client,
+ .run_server = test_stream_cred_upd_on_low_rx_bytes,
+ },
{},
};