Merge branch 'for-6.10-fixes' into for-6.11

This commit is contained in:
Tejun Heo
2024-07-14 18:04:03 -10:00
1114 changed files with 12865 additions and 6691 deletions

View File

@@ -3,6 +3,7 @@
#include <linux/platform_device.h>
#include <linux/mod_devicetable.h>
#include <linux/vmalloc.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/sizes.h>

View File

@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
#
CFLAGS += $(shell pkg-config --cflags alsa)
CFLAGS += $(shell pkg-config --cflags alsa) $(KHDR_INCLUDES)
LDLIBS += $(shell pkg-config --libs alsa)
ifeq ($(LDLIBS),)
LDLIBS += -lasound

View File

@@ -73,6 +73,16 @@ static int create_netkit(int mode, int policy, int peer_policy, int *ifindex,
"up primary");
ASSERT_OK(system("ip addr add dev " netkit_name " 10.0.0.1/24"),
"addr primary");
if (mode == NETKIT_L3) {
ASSERT_EQ(system("ip link set dev " netkit_name
" addr ee:ff:bb:cc:aa:dd 2> /dev/null"), 512,
"set hwaddress");
} else {
ASSERT_OK(system("ip link set dev " netkit_name
" addr ee:ff:bb:cc:aa:dd"),
"set hwaddress");
}
if (same_netns) {
ASSERT_OK(system("ip link set dev " netkit_peer " up"),
"up peer");
@@ -89,6 +99,16 @@ static int create_netkit(int mode, int policy, int peer_policy, int *ifindex,
return err;
}
static void move_netkit(void)
{
ASSERT_OK(system("ip link set " netkit_peer " netns foo"),
"move peer");
ASSERT_OK(system("ip netns exec foo ip link set dev "
netkit_peer " up"), "up peer");
ASSERT_OK(system("ip netns exec foo ip addr add dev "
netkit_peer " 10.0.0.2/24"), "addr peer");
}
static void destroy_netkit(void)
{
ASSERT_OK(system("ip link del dev " netkit_name), "del primary");
@@ -685,3 +705,77 @@ void serial_test_tc_netkit_neigh_links(void)
serial_test_tc_netkit_neigh_links_target(NETKIT_L2, BPF_NETKIT_PRIMARY);
serial_test_tc_netkit_neigh_links_target(NETKIT_L3, BPF_NETKIT_PRIMARY);
}
static void serial_test_tc_netkit_pkt_type_mode(int mode)
{
LIBBPF_OPTS(bpf_netkit_opts, optl_nk);
LIBBPF_OPTS(bpf_tcx_opts, optl_tcx);
int err, ifindex, ifindex2;
struct test_tc_link *skel;
struct bpf_link *link;
err = create_netkit(mode, NETKIT_PASS, NETKIT_PASS,
&ifindex, true);
if (err)
return;
ifindex2 = if_nametoindex(netkit_peer);
ASSERT_NEQ(ifindex, ifindex2, "ifindex_1_2");
skel = test_tc_link__open();
if (!ASSERT_OK_PTR(skel, "skel_open"))
goto cleanup;
ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1,
BPF_NETKIT_PRIMARY), 0, "tc1_attach_type");
ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc7,
BPF_TCX_INGRESS), 0, "tc7_attach_type");
err = test_tc_link__load(skel);
if (!ASSERT_OK(err, "skel_load"))
goto cleanup;
assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PRIMARY, 0);
assert_mprog_count_ifindex(ifindex2, BPF_TCX_INGRESS, 0);
link = bpf_program__attach_netkit(skel->progs.tc1, ifindex, &optl_nk);
if (!ASSERT_OK_PTR(link, "link_attach"))
goto cleanup;
skel->links.tc1 = link;
assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PRIMARY, 1);
assert_mprog_count_ifindex(ifindex2, BPF_TCX_INGRESS, 0);
link = bpf_program__attach_tcx(skel->progs.tc7, ifindex2, &optl_tcx);
if (!ASSERT_OK_PTR(link, "link_attach"))
goto cleanup;
skel->links.tc7 = link;
assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PRIMARY, 1);
assert_mprog_count_ifindex(ifindex2, BPF_TCX_INGRESS, 1);
move_netkit();
tc_skel_reset_all_seen(skel);
skel->bss->set_type = true;
ASSERT_EQ(send_icmp(), 0, "icmp_pkt");
ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
ASSERT_EQ(skel->bss->seen_tc7, true, "seen_tc7");
ASSERT_EQ(skel->bss->seen_host, true, "seen_host");
ASSERT_EQ(skel->bss->seen_mcast, true, "seen_mcast");
cleanup:
test_tc_link__destroy(skel);
assert_mprog_count_ifindex(ifindex, BPF_NETKIT_PRIMARY, 0);
destroy_netkit();
}
void serial_test_tc_netkit_pkt_type(void)
{
serial_test_tc_netkit_pkt_type_mode(NETKIT_L2);
serial_test_tc_netkit_pkt_type_mode(NETKIT_L3);
}

View File

@@ -1,12 +1,14 @@
// SPDX-License-Identifier: GPL-2.0
#include <unistd.h>
#include <pthread.h>
#include <test_progs.h>
#include "uprobe_multi.skel.h"
#include "uprobe_multi_bench.skel.h"
#include "uprobe_multi_usdt.skel.h"
#include "bpf/libbpf_internal.h"
#include "testing_helpers.h"
#include "../sdt.h"
static char test_data[] = "test_data";
@@ -25,9 +27,17 @@ noinline void uprobe_multi_func_3(void)
asm volatile ("");
}
noinline void usdt_trigger(void)
{
STAP_PROBE(test, pid_filter_usdt);
}
struct child {
int go[2];
int c2p[2]; /* child -> parent channel */
int pid;
int tid;
pthread_t thread;
};
static void release_child(struct child *child)
@@ -38,6 +48,10 @@ static void release_child(struct child *child)
return;
close(child->go[1]);
close(child->go[0]);
if (child->thread)
pthread_join(child->thread, NULL);
close(child->c2p[0]);
close(child->c2p[1]);
if (child->pid > 0)
waitpid(child->pid, &child_status, 0);
}
@@ -63,7 +77,7 @@ static struct child *spawn_child(void)
if (pipe(child.go))
return NULL;
child.pid = fork();
child.pid = child.tid = fork();
if (child.pid < 0) {
release_child(&child);
errno = EINVAL;
@@ -82,6 +96,7 @@ static struct child *spawn_child(void)
uprobe_multi_func_1();
uprobe_multi_func_2();
uprobe_multi_func_3();
usdt_trigger();
exit(errno);
}
@@ -89,6 +104,67 @@ static struct child *spawn_child(void)
return &child;
}
static void *child_thread(void *ctx)
{
struct child *child = ctx;
int c = 0, err;
child->tid = syscall(SYS_gettid);
/* let parent know we are ready */
err = write(child->c2p[1], &c, 1);
if (err != 1)
pthread_exit(&err);
/* wait for parent's kick */
err = read(child->go[0], &c, 1);
if (err != 1)
pthread_exit(&err);
uprobe_multi_func_1();
uprobe_multi_func_2();
uprobe_multi_func_3();
usdt_trigger();
err = 0;
pthread_exit(&err);
}
static struct child *spawn_thread(void)
{
static struct child child;
int c, err;
/* pipe to notify child to execute the trigger functions */
if (pipe(child.go))
return NULL;
/* pipe to notify parent that child thread is ready */
if (pipe(child.c2p)) {
close(child.go[0]);
close(child.go[1]);
return NULL;
}
child.pid = getpid();
err = pthread_create(&child.thread, NULL, child_thread, &child);
if (err) {
err = -errno;
close(child.go[0]);
close(child.go[1]);
close(child.c2p[0]);
close(child.c2p[1]);
errno = -err;
return NULL;
}
err = read(child.c2p[0], &c, 1);
if (!ASSERT_EQ(err, 1, "child_thread_ready"))
return NULL;
return &child;
}
static void uprobe_multi_test_run(struct uprobe_multi *skel, struct child *child)
{
skel->bss->uprobe_multi_func_1_addr = (__u64) uprobe_multi_func_1;
@@ -103,15 +179,23 @@ static void uprobe_multi_test_run(struct uprobe_multi *skel, struct child *child
* passed at the probe attach.
*/
skel->bss->pid = child ? 0 : getpid();
skel->bss->expect_pid = child ? child->pid : 0;
/* trigger all probes, if we are testing child *process*, just to make
* sure that PID filtering doesn't let through activations from wrong
* PIDs; when we test child *thread*, we don't want to do this to
* avoid double counting number of triggering events
*/
if (!child || !child->thread) {
uprobe_multi_func_1();
uprobe_multi_func_2();
uprobe_multi_func_3();
usdt_trigger();
}
if (child)
kick_child(child);
/* trigger all probes */
uprobe_multi_func_1();
uprobe_multi_func_2();
uprobe_multi_func_3();
/*
* There are 2 entry and 2 exit probe called for each uprobe_multi_func_[123]
* function and each slepable probe (6) increments uprobe_multi_sleep_result.
@@ -126,8 +210,12 @@ static void uprobe_multi_test_run(struct uprobe_multi *skel, struct child *child
ASSERT_EQ(skel->bss->uprobe_multi_sleep_result, 6, "uprobe_multi_sleep_result");
if (child)
ASSERT_FALSE(skel->bss->bad_pid_seen, "bad_pid_seen");
if (child) {
ASSERT_EQ(skel->bss->child_pid, child->pid, "uprobe_multi_child_pid");
ASSERT_EQ(skel->bss->child_tid, child->tid, "uprobe_multi_child_tid");
}
}
static void test_skel_api(void)
@@ -190,8 +278,24 @@ __test_attach_api(const char *binary, const char *pattern, struct bpf_uprobe_mul
if (!ASSERT_OK_PTR(skel->links.uprobe_extra, "bpf_program__attach_uprobe_multi"))
goto cleanup;
/* Attach (uprobe-backed) USDTs */
skel->links.usdt_pid = bpf_program__attach_usdt(skel->progs.usdt_pid, pid, binary,
"test", "pid_filter_usdt", NULL);
if (!ASSERT_OK_PTR(skel->links.usdt_pid, "attach_usdt_pid"))
goto cleanup;
skel->links.usdt_extra = bpf_program__attach_usdt(skel->progs.usdt_extra, -1, binary,
"test", "pid_filter_usdt", NULL);
if (!ASSERT_OK_PTR(skel->links.usdt_extra, "attach_usdt_extra"))
goto cleanup;
uprobe_multi_test_run(skel, child);
ASSERT_FALSE(skel->bss->bad_pid_seen_usdt, "bad_pid_seen_usdt");
if (child) {
ASSERT_EQ(skel->bss->child_pid_usdt, child->pid, "usdt_multi_child_pid");
ASSERT_EQ(skel->bss->child_tid_usdt, child->tid, "usdt_multi_child_tid");
}
cleanup:
uprobe_multi__destroy(skel);
}
@@ -210,6 +314,13 @@ test_attach_api(const char *binary, const char *pattern, struct bpf_uprobe_multi
return;
__test_attach_api(binary, pattern, opts, child);
/* pid filter (thread) */
child = spawn_thread();
if (!ASSERT_OK_PTR(child, "spawn_thread"))
return;
__test_attach_api(binary, pattern, opts, child);
}
static void test_attach_api_pattern(void)
@@ -397,7 +508,7 @@ static void test_attach_api_fails(void)
link_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts);
if (!ASSERT_ERR(link_fd, "link_fd"))
goto cleanup;
ASSERT_EQ(link_fd, -ESRCH, "pid_is_wrong");
ASSERT_EQ(link_fd, -EINVAL, "pid_is_wrong");
cleanup:
if (link_fd >= 0)
@@ -495,6 +606,13 @@ static void test_link_api(void)
return;
__test_link_api(child);
/* pid filter (thread) */
child = spawn_thread();
if (!ASSERT_OK_PTR(child, "spawn_thread"))
return;
__test_link_api(child);
}
static void test_bench_attach_uprobe(void)

View File

@@ -53,6 +53,7 @@
#include "verifier_movsx.skel.h"
#include "verifier_netfilter_ctx.skel.h"
#include "verifier_netfilter_retcode.skel.h"
#include "verifier_or_jmp32_k.skel.h"
#include "verifier_precision.skel.h"
#include "verifier_prevent_map_lookup.skel.h"
#include "verifier_raw_stack.skel.h"
@@ -67,6 +68,7 @@
#include "verifier_search_pruning.skel.h"
#include "verifier_sock.skel.h"
#include "verifier_sock_addr.skel.h"
#include "verifier_sockmap_mutate.skel.h"
#include "verifier_spill_fill.skel.h"
#include "verifier_spin_lock.skel.h"
#include "verifier_stack_ptr.skel.h"
@@ -169,6 +171,7 @@ void test_verifier_meta_access(void) { RUN(verifier_meta_access); }
void test_verifier_movsx(void) { RUN(verifier_movsx); }
void test_verifier_netfilter_ctx(void) { RUN(verifier_netfilter_ctx); }
void test_verifier_netfilter_retcode(void) { RUN(verifier_netfilter_retcode); }
void test_verifier_or_jmp32_k(void) { RUN(verifier_or_jmp32_k); }
void test_verifier_precision(void) { RUN(verifier_precision); }
void test_verifier_prevent_map_lookup(void) { RUN(verifier_prevent_map_lookup); }
void test_verifier_raw_stack(void) { RUN(verifier_raw_stack); }
@@ -183,6 +186,7 @@ void test_verifier_sdiv(void) { RUN(verifier_sdiv); }
void test_verifier_search_pruning(void) { RUN(verifier_search_pruning); }
void test_verifier_sock(void) { RUN(verifier_sock); }
void test_verifier_sock_addr(void) { RUN(verifier_sock_addr); }
void test_verifier_sockmap_mutate(void) { RUN(verifier_sockmap_mutate); }
void test_verifier_spill_fill(void) { RUN(verifier_spill_fill); }
void test_verifier_spin_lock(void) { RUN(verifier_spin_lock); }
void test_verifier_stack_ptr(void) { RUN(verifier_stack_ptr); }

View File

@@ -84,7 +84,7 @@ int BPF_PROG(trace_tcp_connect, struct sock *sk)
}
SEC("fexit/inet_csk_accept")
int BPF_PROG(inet_csk_accept, struct sock *sk, int flags, int *err, bool kern,
int BPF_PROG(inet_csk_accept, struct sock *sk, struct proto_accept_arg *arg,
struct sock *accepted_sk)
{
set_task_info(accepted_sk);

View File

@@ -4,7 +4,8 @@
#include <linux/bpf.h>
#include <linux/if_ether.h>
#include <linux/stddef.h>
#include <linux/if_packet.h>
#include <bpf/bpf_endian.h>
#include <bpf/bpf_helpers.h>
@@ -16,7 +17,13 @@ bool seen_tc3;
bool seen_tc4;
bool seen_tc5;
bool seen_tc6;
bool seen_tc7;
bool set_type;
bool seen_eth;
bool seen_host;
bool seen_mcast;
SEC("tc/ingress")
int tc1(struct __sk_buff *skb)
@@ -28,8 +35,16 @@ int tc1(struct __sk_buff *skb)
if (bpf_skb_load_bytes(skb, 0, &eth, sizeof(eth)))
goto out;
seen_eth = eth.h_proto == bpf_htons(ETH_P_IP);
seen_host = skb->pkt_type == PACKET_HOST;
if (seen_host && set_type) {
eth.h_dest[0] = 4;
if (bpf_skb_store_bytes(skb, 0, &eth, sizeof(eth), 0))
goto fail;
bpf_skb_change_type(skb, PACKET_MULTICAST);
}
out:
seen_tc1 = true;
fail:
return TCX_NEXT;
}
@@ -67,3 +82,21 @@ int tc6(struct __sk_buff *skb)
seen_tc6 = true;
return TCX_PASS;
}
SEC("tc/ingress")
int tc7(struct __sk_buff *skb)
{
struct ethhdr eth = {};
if (skb->protocol != __bpf_constant_htons(ETH_P_IP))
goto out;
if (bpf_skb_load_bytes(skb, 0, &eth, sizeof(eth)))
goto out;
if (eth.h_dest[0] == 4 && set_type) {
seen_mcast = skb->pkt_type == PACKET_MULTICAST;
bpf_skb_change_type(skb, PACKET_HOST);
}
out:
seen_tc7 = true;
return TCX_PASS;
}

View File

@@ -1,8 +1,8 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/bpf.h>
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include <stdbool.h>
#include <bpf/usdt.bpf.h>
char _license[] SEC("license") = "GPL";
@@ -22,6 +22,13 @@ __u64 uprobe_multi_sleep_result = 0;
int pid = 0;
int child_pid = 0;
int child_tid = 0;
int child_pid_usdt = 0;
int child_tid_usdt = 0;
int expect_pid = 0;
bool bad_pid_seen = false;
bool bad_pid_seen_usdt = false;
bool test_cookie = false;
void *user_ptr = 0;
@@ -36,11 +43,19 @@ static __always_inline bool verify_sleepable_user_copy(void)
static void uprobe_multi_check(void *ctx, bool is_return, bool is_sleep)
{
child_pid = bpf_get_current_pid_tgid() >> 32;
__u64 cur_pid_tgid = bpf_get_current_pid_tgid();
__u32 cur_pid;
if (pid && child_pid != pid)
cur_pid = cur_pid_tgid >> 32;
if (pid && cur_pid != pid)
return;
if (expect_pid && cur_pid != expect_pid)
bad_pid_seen = true;
child_pid = cur_pid_tgid >> 32;
child_tid = (__u32)cur_pid_tgid;
__u64 cookie = test_cookie ? bpf_get_attach_cookie(ctx) : 0;
__u64 addr = bpf_get_func_ip(ctx);
@@ -97,5 +112,32 @@ int uretprobe_sleep(struct pt_regs *ctx)
SEC("uprobe.multi//proc/self/exe:uprobe_multi_func_*")
int uprobe_extra(struct pt_regs *ctx)
{
/* we need this one just to mix PID-filtered and global uprobes */
return 0;
}
SEC("usdt")
int usdt_pid(struct pt_regs *ctx)
{
__u64 cur_pid_tgid = bpf_get_current_pid_tgid();
__u32 cur_pid;
cur_pid = cur_pid_tgid >> 32;
if (pid && cur_pid != pid)
return 0;
if (expect_pid && cur_pid != expect_pid)
bad_pid_seen_usdt = true;
child_pid_usdt = cur_pid_tgid >> 32;
child_tid_usdt = (__u32)cur_pid_tgid;
return 0;
}
SEC("usdt")
int usdt_extra(struct pt_regs *ctx)
{
/* we need this one just to mix PID-filtered and global USDT probes */
return 0;
}

View File

@@ -0,0 +1,41 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include "bpf_misc.h"
SEC("socket")
__description("or_jmp32_k: bit ops + branch on unknown value")
__failure
__msg("R0 invalid mem access 'scalar'")
__naked void or_jmp32_k(void)
{
asm volatile (" \
r0 = 0xffffffff; \
r0 /= 1; \
r1 = 0; \
w1 = -1; \
w1 >>= 1; \
w0 &= w1; \
w0 |= 2; \
if w0 != 0x7ffffffd goto l1; \
r0 = 1; \
exit; \
l3: \
r0 = 5; \
*(u64*)(r0 - 8) = r0; \
exit; \
l2: \
w0 -= 0xe; \
if w0 == 1 goto l3; \
r0 = 4; \
exit; \
l1: \
w0 -= 0x7ffffff0; \
if w0 s>= 0xe goto l2; \
r0 = 3; \
exit; \
" ::: __clobber_all);
}
char _license[] SEC("license") = "GPL";

View File

@@ -0,0 +1,187 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include "bpf_misc.h"
#define __always_unused __attribute__((unused))
char _license[] SEC("license") = "GPL";
struct sock {
} __attribute__((preserve_access_index));
struct bpf_iter__sockmap {
union {
struct sock *sk;
};
} __attribute__((preserve_access_index));
struct {
__uint(type, BPF_MAP_TYPE_SOCKHASH);
__uint(max_entries, 1);
__type(key, int);
__type(value, int);
} sockhash SEC(".maps");
struct {
__uint(type, BPF_MAP_TYPE_SOCKMAP);
__uint(max_entries, 1);
__type(key, int);
__type(value, int);
} sockmap SEC(".maps");
enum { CG_OK = 1 };
int zero = 0;
static __always_inline void test_sockmap_delete(void)
{
bpf_map_delete_elem(&sockmap, &zero);
bpf_map_delete_elem(&sockhash, &zero);
}
static __always_inline void test_sockmap_update(void *sk)
{
if (sk) {
bpf_map_update_elem(&sockmap, &zero, sk, BPF_ANY);
bpf_map_update_elem(&sockhash, &zero, sk, BPF_ANY);
}
}
static __always_inline void test_sockmap_lookup_and_update(void)
{
struct bpf_sock *sk = bpf_map_lookup_elem(&sockmap, &zero);
if (sk) {
test_sockmap_update(sk);
bpf_sk_release(sk);
}
}
static __always_inline void test_sockmap_mutate(void *sk)
{
test_sockmap_delete();
test_sockmap_update(sk);
}
static __always_inline void test_sockmap_lookup_and_mutate(void)
{
test_sockmap_delete();
test_sockmap_lookup_and_update();
}
SEC("action")
__success
int test_sched_act(struct __sk_buff *skb)
{
test_sockmap_mutate(skb->sk);
return 0;
}
SEC("classifier")
__success
int test_sched_cls(struct __sk_buff *skb)
{
test_sockmap_mutate(skb->sk);
return 0;
}
SEC("flow_dissector")
__success
int test_flow_dissector_delete(struct __sk_buff *skb __always_unused)
{
test_sockmap_delete();
return 0;
}
SEC("flow_dissector")
__failure __msg("program of this type cannot use helper bpf_sk_release")
int test_flow_dissector_update(struct __sk_buff *skb __always_unused)
{
test_sockmap_lookup_and_update(); /* no access to skb->sk */
return 0;
}
SEC("iter/sockmap")
__success
int test_trace_iter(struct bpf_iter__sockmap *ctx)
{
test_sockmap_mutate(ctx->sk);
return 0;
}
SEC("raw_tp/kfree")
__failure __msg("cannot update sockmap in this context")
int test_raw_tp_delete(const void *ctx __always_unused)
{
test_sockmap_delete();
return 0;
}
SEC("raw_tp/kfree")
__failure __msg("cannot update sockmap in this context")
int test_raw_tp_update(const void *ctx __always_unused)
{
test_sockmap_lookup_and_update();
return 0;
}
SEC("sk_lookup")
__success
int test_sk_lookup(struct bpf_sk_lookup *ctx)
{
test_sockmap_mutate(ctx->sk);
return 0;
}
SEC("sk_reuseport")
__success
int test_sk_reuseport(struct sk_reuseport_md *ctx)
{
test_sockmap_mutate(ctx->sk);
return 0;
}
SEC("socket")
__success
int test_socket_filter(struct __sk_buff *skb)
{
test_sockmap_mutate(skb->sk);
return 0;
}
SEC("sockops")
__success
int test_sockops_delete(struct bpf_sock_ops *ctx __always_unused)
{
test_sockmap_delete();
return CG_OK;
}
SEC("sockops")
__failure __msg("cannot update sockmap in this context")
int test_sockops_update(struct bpf_sock_ops *ctx)
{
test_sockmap_update(ctx->sk);
return CG_OK;
}
SEC("sockops")
__success
int test_sockops_update_dedicated(struct bpf_sock_ops *ctx)
{
bpf_sock_map_update(ctx, &sockmap, &zero, BPF_ANY);
bpf_sock_hash_update(ctx, &sockhash, &zero, BPF_ANY);
return CG_OK;
}
SEC("xdp")
__success
int test_xdp(struct xdp_md *ctx __always_unused)
{
test_sockmap_lookup_and_mutate();
return XDP_PASS;
}

View File

@@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
#define _GNU_SOURCE
#define __SANE_USERSPACE_TYPES__ // Use ll64
#include <stdio.h>
#include <stdbool.h>

View File

@@ -1,2 +1,8 @@
CONFIG_VIRTIO_NET=y
CONFIG_BPF_SYSCALL=y
CONFIG_CGROUP_BPF=y
CONFIG_IPV6=y
CONFIG_IPV6_MULTIPLE_TABLES=y
CONFIG_NET_L3_MASTER_DEV=y
CONFIG_NET_VRF=m
CONFIG_VIRTIO_DEBUG=y
CONFIG_VIRTIO_NET=y

View File

@@ -1,6 +1,15 @@
# SPDX-License-Identifier: GPL-2.0-or-later
CFLAGS += -Wall -O2 -g -fsanitize=address -fsanitize=undefined -static-libasan $(KHDR_INCLUDES)
CFLAGS += -Wall -O2 -g -fsanitize=address -fsanitize=undefined $(KHDR_INCLUDES)
# gcc requires -static-libasan in order to ensure that Address Sanitizer's
# library is the first one loaded. However, clang already statically links the
# Address Sanitizer if -fsanitize is specified. Therefore, simply omit
# -static-libasan for clang builds.
ifeq ($(LLVM),)
CFLAGS += -static-libasan
endif
TEST_GEN_PROGS := fchmodat2_test
include ../lib.mk

View File

@@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
#define _GNU_SOURCE
#define __SANE_USERSPACE_TYPES__ // Use ll64
#include <inttypes.h>
#include <unistd.h>

View File

@@ -125,8 +125,16 @@ static uint32_t old_root_id, old_parent_id;
static void cleanup_namespace(void)
{
fchdir(orig_root);
chroot(".");
int ret;
ret = fchdir(orig_root);
if (ret == -1)
ksft_perror("fchdir to original root");
ret = chroot(".");
if (ret == -1)
ksft_perror("chroot to original root");
umount2(root_mntpoint, MNT_DETACH);
rmdir(root_mntpoint);
}

View File

@@ -1,16 +1,28 @@
CONFIG_KPROBES=y
CONFIG_BPF_SYSCALL=y
CONFIG_DEBUG_INFO_BTF=y
CONFIG_DEBUG_INFO_DWARF4=y
CONFIG_EPROBE_EVENTS=y
CONFIG_FPROBE=y
CONFIG_FPROBE_EVENTS=y
CONFIG_FTRACE=y
CONFIG_FTRACE_SYSCALLS=y
CONFIG_FUNCTION_GRAPH_RETVAL=y
CONFIG_FUNCTION_PROFILER=y
CONFIG_TRACER_SNAPSHOT=y
CONFIG_STACK_TRACER=y
CONFIG_HIST_TRIGGERS=y
CONFIG_SCHED_TRACER=y
CONFIG_PREEMPT_TRACER=y
CONFIG_IRQSOFF_TRACER=y
CONFIG_PREEMPTIRQ_DELAY_TEST=m
CONFIG_KALLSYMS_ALL=y
CONFIG_KPROBES=y
CONFIG_KPROBE_EVENTS=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_PREEMPTIRQ_DELAY_TEST=m
CONFIG_PREEMPT_TRACER=y
CONFIG_PROBE_EVENTS_BTF_ARGS=y
CONFIG_SAMPLES=y
CONFIG_SAMPLE_FTRACE_DIRECT=m
CONFIG_SAMPLE_TRACE_PRINTK=m
CONFIG_KALLSYMS_ALL=y
CONFIG_SCHED_TRACER=y
CONFIG_STACK_TRACER=y
CONFIG_TRACER_SNAPSHOT=y
CONFIG_UPROBES=y
CONFIG_UPROBE_EVENTS=y

View File

@@ -1,7 +1,7 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Generic dynamic event - check if duplicate events are caught
# requires: dynamic_events "e[:[<group>/][<event>]] <attached-group>.<attached-event> [<args>]":README
# requires: dynamic_events "e[:[<group>/][<event>]] <attached-group>.<attached-event> [<args>]":README events/syscalls/sys_enter_openat
echo 0 > events/enable

View File

@@ -10,7 +10,6 @@ fail() { #msg
}
sample_events() {
echo > trace
echo 1 > events/kmem/kmem_cache_free/enable
echo 1 > tracing_on
ls > /dev/null
@@ -22,6 +21,7 @@ echo 0 > tracing_on
echo 0 > events/enable
echo "Get the most frequently calling function"
echo > trace
sample_events
target_func=`cat trace | grep -o 'call_site=\([^+]*\)' | sed 's/call_site=//' | sort | uniq -c | sort | tail -n 1 | sed 's/^[ 0-9]*//'`
@@ -32,7 +32,16 @@ echo > trace
echo "Test event filter function name"
echo "call_site.function == $target_func" > events/kmem/kmem_cache_free/filter
sample_events
max_retry=10
while [ `grep kmem_cache_free trace| wc -l` -eq 0 ]; do
sample_events
max_retry=$((max_retry - 1))
if [ $max_retry -eq 0 ]; then
exit_fail
fi
done
hitcnt=`grep kmem_cache_free trace| grep $target_func | wc -l`
misscnt=`grep kmem_cache_free trace| grep -v $target_func | wc -l`
@@ -49,7 +58,16 @@ address=`grep " ${target_func}\$" /proc/kallsyms | cut -d' ' -f1`
echo "Test event filter function address"
echo "call_site.function == 0x$address" > events/kmem/kmem_cache_free/filter
echo > trace
sample_events
max_retry=10
while [ `grep kmem_cache_free trace| wc -l` -eq 0 ]; do
sample_events
max_retry=$((max_retry - 1))
if [ $max_retry -eq 0 ]; then
exit_fail
fi
done
hitcnt=`grep kmem_cache_free trace| grep $target_func | wc -l`
misscnt=`grep kmem_cache_free trace| grep -v $target_func | wc -l`

View File

@@ -30,7 +30,8 @@ find_dot_func() {
fi
grep " [tT] .*\.isra\..*" /proc/kallsyms | cut -f 3 -d " " | while read f; do
if grep -s $f available_filter_functions; then
cnt=`grep -s $f available_filter_functions | wc -l`;
if [ $cnt -eq 1 ]; then
echo $f
break
fi

View File

@@ -3,8 +3,6 @@ SUBDIRS := functional
TEST_PROGS := run.sh
.PHONY: all clean
include ../lib.mk
all:

View File

@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
INCLUDES := -I../include -I../../ $(KHDR_INCLUDES)
CFLAGS := $(CFLAGS) -g -O2 -Wall -D_GNU_SOURCE -pthread $(INCLUDES) $(KHDR_INCLUDES)
CFLAGS := $(CFLAGS) -g -O2 -Wall -D_GNU_SOURCE= -pthread $(INCLUDES) $(KHDR_INCLUDES)
LDLIBS := -lpthread -lrt
LOCAL_HDRS := \

View File

@@ -360,7 +360,7 @@ out:
int main(int argc, char *argv[])
{
const char *test_name;
char *test_name;
int c, ret;
while ((c = getopt(argc, argv, "bchlot:v:")) != -1) {

View File

@@ -183,6 +183,7 @@ TEST_GEN_PROGS_s390x += s390x/sync_regs_test
TEST_GEN_PROGS_s390x += s390x/tprot
TEST_GEN_PROGS_s390x += s390x/cmma_test
TEST_GEN_PROGS_s390x += s390x/debug_test
TEST_GEN_PROGS_s390x += s390x/shared_zeropage_test
TEST_GEN_PROGS_s390x += demand_paging_test
TEST_GEN_PROGS_s390x += dirty_log_test
TEST_GEN_PROGS_s390x += guest_print_test

View File

@@ -277,6 +277,7 @@ struct kvm_x86_cpu_property {
#define X86_PROPERTY_MAX_EXT_LEAF KVM_X86_CPU_PROPERTY(0x80000000, 0, EAX, 0, 31)
#define X86_PROPERTY_MAX_PHY_ADDR KVM_X86_CPU_PROPERTY(0x80000008, 0, EAX, 0, 7)
#define X86_PROPERTY_MAX_VIRT_ADDR KVM_X86_CPU_PROPERTY(0x80000008, 0, EAX, 8, 15)
#define X86_PROPERTY_GUEST_MAX_PHY_ADDR KVM_X86_CPU_PROPERTY(0x80000008, 0, EAX, 16, 23)
#define X86_PROPERTY_SEV_C_BIT KVM_X86_CPU_PROPERTY(0x8000001F, 0, EBX, 0, 5)
#define X86_PROPERTY_PHYS_ADDR_REDUCTION KVM_X86_CPU_PROPERTY(0x8000001F, 0, EBX, 6, 11)

View File

@@ -9,6 +9,7 @@
#include "kvm_util.h"
#include "processor.h"
#include "sbi.h"
void *ucall_arch_get_ucall(struct kvm_vcpu *vcpu)
{

View File

@@ -1247,9 +1247,20 @@ unsigned long vm_compute_max_gfn(struct kvm_vm *vm)
{
const unsigned long num_ht_pages = 12 << (30 - vm->page_shift); /* 12 GiB */
unsigned long ht_gfn, max_gfn, max_pfn;
uint8_t maxphyaddr;
uint8_t maxphyaddr, guest_maxphyaddr;
max_gfn = (1ULL << (vm->pa_bits - vm->page_shift)) - 1;
/*
* Use "guest MAXPHYADDR" from KVM if it's available. Guest MAXPHYADDR
* enumerates the max _mappable_ GPA, which can be less than the raw
* MAXPHYADDR, e.g. if MAXPHYADDR=52, KVM is using TDP, and the CPU
* doesn't support 5-level TDP.
*/
guest_maxphyaddr = kvm_cpu_property(X86_PROPERTY_GUEST_MAX_PHY_ADDR);
guest_maxphyaddr = guest_maxphyaddr ?: vm->pa_bits;
TEST_ASSERT(guest_maxphyaddr <= vm->pa_bits,
"Guest MAXPHYADDR should never be greater than raw MAXPHYADDR");
max_gfn = (1ULL << (guest_maxphyaddr - vm->page_shift)) - 1;
/* Avoid reserved HyperTransport region on AMD processors. */
if (!host_cpu_is_amd)

View File

@@ -6,6 +6,7 @@
*
*/
#include "kvm_util.h"
#include "ucall_common.h"
#define LABEL_ADDRESS(v) ((uint64_t)&(v))

View File

@@ -15,6 +15,7 @@
#include "processor.h"
#include "sbi.h"
#include "arch_timer.h"
#include "ucall_common.h"
/* Maximum counters(firmware + hardware) */
#define RISCV_MAX_PMU_COUNTERS 64

View File

@@ -0,0 +1,111 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Test shared zeropage handling (with/without storage keys)
*
* Copyright (C) 2024, Red Hat, Inc.
*/
#include <sys/mman.h>
#include <linux/fs.h>
#include "test_util.h"
#include "kvm_util.h"
#include "kselftest.h"
#include "ucall_common.h"
static void set_storage_key(void *addr, uint8_t skey)
{
asm volatile("sske %0,%1" : : "d" (skey), "a" (addr));
}
static void guest_code(void)
{
/* Issue some storage key instruction. */
set_storage_key((void *)0, 0x98);
GUEST_DONE();
}
/*
* Returns 1 if the shared zeropage is mapped, 0 if something else is mapped.
* Returns < 0 on error or if nothing is mapped.
*/
static int maps_shared_zeropage(int pagemap_fd, void *addr)
{
struct page_region region;
struct pm_scan_arg arg = {
.start = (uintptr_t)addr,
.end = (uintptr_t)addr + 4096,
.vec = (uintptr_t)&region,
.vec_len = 1,
.size = sizeof(struct pm_scan_arg),
.category_mask = PAGE_IS_PFNZERO,
.category_anyof_mask = PAGE_IS_PRESENT,
.return_mask = PAGE_IS_PFNZERO,
};
return ioctl(pagemap_fd, PAGEMAP_SCAN, &arg);
}
int main(int argc, char *argv[])
{
char *mem, *page0, *page1, *page2, tmp;
const size_t pagesize = getpagesize();
struct kvm_vcpu *vcpu;
struct kvm_vm *vm;
struct ucall uc;
int pagemap_fd;
ksft_print_header();
ksft_set_plan(3);
/*
* We'll use memory that is not mapped into the VM for simplicity.
* Shared zeropages are enabled/disabled per-process.
*/
mem = mmap(0, 3 * pagesize, PROT_READ, MAP_PRIVATE | MAP_ANON, -1, 0);
TEST_ASSERT(mem != MAP_FAILED, "mmap() failed");
/* Disable THP. Ignore errors on older kernels. */
madvise(mem, 3 * pagesize, MADV_NOHUGEPAGE);
page0 = mem;
page1 = page0 + pagesize;
page2 = page1 + pagesize;
/* Can we even detect shared zeropages? */
pagemap_fd = open("/proc/self/pagemap", O_RDONLY);
TEST_REQUIRE(pagemap_fd >= 0);
tmp = *page0;
asm volatile("" : "+r" (tmp));
TEST_REQUIRE(maps_shared_zeropage(pagemap_fd, page0) == 1);
vm = vm_create_with_one_vcpu(&vcpu, guest_code);
/* Verify that we get the shared zeropage after VM creation. */
tmp = *page1;
asm volatile("" : "+r" (tmp));
ksft_test_result(maps_shared_zeropage(pagemap_fd, page1) == 1,
"Shared zeropages should be enabled\n");
/*
* Let our VM execute a storage key instruction that should
* unshare all shared zeropages.
*/
vcpu_run(vcpu);
get_ucall(vcpu, &uc);
TEST_ASSERT_EQ(uc.cmd, UCALL_DONE);
/* Verify that we don't have a shared zeropage anymore. */
ksft_test_result(!maps_shared_zeropage(pagemap_fd, page1),
"Shared zeropage should be gone\n");
/* Verify that we don't get any new shared zeropages. */
tmp = *page2;
asm volatile("" : "+r" (tmp));
ksft_test_result(!maps_shared_zeropage(pagemap_fd, page2),
"Shared zeropages should be disabled\n");
kvm_vm_free(vm);
ksft_finished();
}

View File

@@ -105,11 +105,11 @@ void test_features(uint32_t vm_type, uint64_t supported_features)
int i;
for (i = 0; i < 64; i++) {
if (!(supported_features & (1u << i)))
if (!(supported_features & BIT_ULL(i)))
test_init2_invalid(vm_type,
&(struct kvm_sev_init){ .vmsa_features = BIT_ULL(i) },
"unknown feature");
else if (KNOWN_FEATURES & (1u << i))
else if (KNOWN_FEATURES & BIT_ULL(i))
test_init2(vm_type,
&(struct kvm_sev_init){ .vmsa_features = BIT_ULL(i) });
}

View File

@@ -35,6 +35,7 @@
* See https://sourceware.org/glibc/wiki/Synchronizing_Headers.
*/
#include <linux/fs.h>
#include <linux/mount.h>
#include "common.h"
@@ -47,6 +48,13 @@ int renameat2(int olddirfd, const char *oldpath, int newdirfd,
}
#endif
#ifndef open_tree
int open_tree(int dfd, const char *filename, unsigned int flags)
{
return syscall(__NR_open_tree, dfd, filename, flags);
}
#endif
#ifndef RENAME_EXCHANGE
#define RENAME_EXCHANGE (1 << 1)
#endif
@@ -2400,6 +2408,43 @@ TEST_F_FORK(layout1, refer_denied_by_default4)
layer_dir_s1d1_refer);
}
/*
* Tests walking through a denied root mount.
*/
TEST_F_FORK(layout1, refer_mount_root_deny)
{
const struct landlock_ruleset_attr ruleset_attr = {
.handled_access_fs = LANDLOCK_ACCESS_FS_MAKE_DIR,
};
int root_fd, ruleset_fd;
/* Creates a mount object from a non-mount point. */
set_cap(_metadata, CAP_SYS_ADMIN);
root_fd =
open_tree(AT_FDCWD, dir_s1d1,
AT_EMPTY_PATH | OPEN_TREE_CLONE | OPEN_TREE_CLOEXEC);
clear_cap(_metadata, CAP_SYS_ADMIN);
ASSERT_LE(0, root_fd);
ruleset_fd =
landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
ASSERT_LE(0, ruleset_fd);
ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
ASSERT_EQ(0, landlock_restrict_self(ruleset_fd, 0));
EXPECT_EQ(0, close(ruleset_fd));
/* Link denied by Landlock: EACCES. */
EXPECT_EQ(-1, linkat(root_fd, ".", root_fd, "does_not_exist", 0));
EXPECT_EQ(EACCES, errno);
/* renameat2() always returns EBUSY. */
EXPECT_EQ(-1, renameat2(root_fd, ".", root_fd, "does_not_exist", 0));
EXPECT_EQ(EBUSY, errno);
EXPECT_EQ(0, close(root_fd));
}
TEST_F_FORK(layout1, reparent_link)
{
const struct rule layer1[] = {

View File

@@ -67,7 +67,8 @@ int main(void)
dump_maps();
ksft_exit_fail_msg("Error: munmap failed!?\n");
}
ksft_test_result_pass("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p);
ksft_print_msg("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p);
ksft_test_result_pass("mmap() 5*PAGE_SIZE at base\n");
addr = base_addr + page_size;
size = 3 * page_size;
@@ -76,7 +77,8 @@ int main(void)
dump_maps();
ksft_exit_fail_msg("Error: first mmap() failed unexpectedly\n");
}
ksft_test_result_pass("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p);
ksft_print_msg("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p);
ksft_test_result_pass("mmap() 3*PAGE_SIZE at base+PAGE_SIZE\n");
/*
* Exact same mapping again:
@@ -93,7 +95,8 @@ int main(void)
dump_maps();
ksft_exit_fail_msg("Error:1: mmap() succeeded when it shouldn't have\n");
}
ksft_test_result_pass("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p);
ksft_print_msg("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p);
ksft_test_result_pass("mmap() 5*PAGE_SIZE at base\n");
/*
* Second mapping contained within first:
@@ -111,7 +114,8 @@ int main(void)
dump_maps();
ksft_exit_fail_msg("Error:2: mmap() succeeded when it shouldn't have\n");
}
ksft_test_result_pass("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p);
ksft_print_msg("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p);
ksft_test_result_pass("mmap() 2*PAGE_SIZE at base+PAGE_SIZE\n");
/*
* Overlap end of existing mapping:
@@ -128,7 +132,8 @@ int main(void)
dump_maps();
ksft_exit_fail_msg("Error:3: mmap() succeeded when it shouldn't have\n");
}
ksft_test_result_pass("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p);
ksft_print_msg("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p);
ksft_test_result_pass("mmap() 2*PAGE_SIZE at base+(3*PAGE_SIZE)\n");
/*
* Overlap start of existing mapping:
@@ -145,7 +150,8 @@ int main(void)
dump_maps();
ksft_exit_fail_msg("Error:4: mmap() succeeded when it shouldn't have\n");
}
ksft_test_result_pass("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p);
ksft_print_msg("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p);
ksft_test_result_pass("mmap() 2*PAGE_SIZE bytes at base\n");
/*
* Adjacent to start of existing mapping:
@@ -162,7 +168,8 @@ int main(void)
dump_maps();
ksft_exit_fail_msg("Error:5: mmap() failed when it shouldn't have\n");
}
ksft_test_result_pass("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p);
ksft_print_msg("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p);
ksft_test_result_pass("mmap() PAGE_SIZE at base\n");
/*
* Adjacent to end of existing mapping:
@@ -179,7 +186,8 @@ int main(void)
dump_maps();
ksft_exit_fail_msg("Error:6: mmap() failed when it shouldn't have\n");
}
ksft_test_result_pass("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p);
ksft_print_msg("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p);
ksft_test_result_pass("mmap() PAGE_SIZE at base+(4*PAGE_SIZE)\n");
addr = base_addr;
size = 5 * page_size;

View File

@@ -43,6 +43,8 @@ TEST_PROGS += srv6_hl2encap_red_l2vpn_test.sh
TEST_PROGS += srv6_end_next_csid_l3vpn_test.sh
TEST_PROGS += srv6_end_x_next_csid_l3vpn_test.sh
TEST_PROGS += srv6_end_flavors_test.sh
TEST_PROGS += srv6_end_dx4_netfilter_test.sh
TEST_PROGS += srv6_end_dx6_netfilter_test.sh
TEST_PROGS += vrf_strict_mode_test.sh
TEST_PROGS += arp_ndisc_evict_nocarrier.sh
TEST_PROGS += ndisc_unsolicited_na_test.sh

View File

@@ -101,3 +101,5 @@ CONFIG_NETFILTER_XT_MATCH_POLICY=m
CONFIG_CRYPTO_ARIA=y
CONFIG_XFRM_INTERFACE=m
CONFIG_XFRM_USER=m
CONFIG_IP_NF_MATCH_RPFILTER=m
CONFIG_IP6_NF_MATCH_RPFILTER=m

View File

@@ -2,3 +2,4 @@ CONFIG_IPV6=y
CONFIG_NET_SCH_NETEM=m
CONFIG_HSR=y
CONFIG_VETH=y
CONFIG_BRIDGE=y

View File

@@ -174,6 +174,8 @@ trap cleanup_all_ns EXIT
setup_hsr_interfaces 0
do_complete_ping_test
setup_ns ns1 ns2 ns3
setup_hsr_interfaces 1
do_complete_ping_test

View File

@@ -15,7 +15,7 @@ ksft_xfail=2
ksft_skip=4
# namespace list created by setup_ns
NS_LIST=""
NS_LIST=()
##############################################################################
# Helpers
@@ -27,6 +27,7 @@ __ksft_status_merge()
local -A weights
local weight=0
local i
for i in "$@"; do
weights[$i]=$((weight++))
done
@@ -67,9 +68,7 @@ loopy_wait()
while true
do
local out
out=$("$@")
local ret=$?
if ((!ret)); then
if out=$("$@"); then
echo -n "$out"
return 0
fi
@@ -139,6 +138,7 @@ cleanup_ns()
fi
for ns in "$@"; do
[ -z "${ns}" ] && continue
ip netns delete "${ns}" &> /dev/null
if ! busywait $BUSYWAIT_TIMEOUT ip netns list \| grep -vq "^$ns$" &> /dev/null; then
echo "Warn: Failed to remove namespace $ns"
@@ -152,7 +152,7 @@ cleanup_ns()
cleanup_all_ns()
{
cleanup_ns $NS_LIST
cleanup_ns "${NS_LIST[@]}"
}
# setup netns with given names as prefix. e.g
@@ -161,7 +161,7 @@ setup_ns()
{
local ns=""
local ns_name=""
local ns_list=""
local ns_list=()
local ns_exist=
for ns_name in "$@"; do
# Some test may setup/remove same netns multi times
@@ -177,13 +177,13 @@ setup_ns()
if ! ip netns add "$ns"; then
echo "Failed to create namespace $ns_name"
cleanup_ns "$ns_list"
cleanup_ns "${ns_list[@]}"
return $ksft_skip
fi
ip -n "$ns" link set lo up
! $ns_exist && ns_list="$ns_list $ns"
! $ns_exist && ns_list+=("$ns")
done
NS_LIST="$NS_LIST $ns_list"
NS_LIST+=("${ns_list[@]}")
}
tc_rule_stats_get()

View File

@@ -261,6 +261,8 @@ reset()
TEST_NAME="${1}"
MPTCP_LIB_SUBTEST_FLAKY=0 # reset if modified
if skip_test; then
MPTCP_LIB_TEST_COUNTER=$((MPTCP_LIB_TEST_COUNTER+1))
last_test_ignored=1
@@ -448,7 +450,9 @@ reset_with_tcp_filter()
# $1: err msg
fail_test()
{
ret=${KSFT_FAIL}
if ! mptcp_lib_subtest_is_flaky; then
ret=${KSFT_FAIL}
fi
if [ ${#} -gt 0 ]; then
print_fail "${@}"
@@ -2245,9 +2249,10 @@ remove_tests()
if reset "remove invalid addresses"; then
pm_nl_set_limits $ns1 3 3
pm_nl_add_endpoint $ns1 10.0.12.1 flags signal
# broadcast IP: no packet for this address will be received on ns1
pm_nl_add_endpoint $ns1 224.0.0.1 flags signal
pm_nl_add_endpoint $ns1 10.0.3.1 flags signal
pm_nl_add_endpoint $ns1 10.0.14.1 flags signal
pm_nl_set_limits $ns2 3 3
pm_nl_set_limits $ns2 2 2
addr_nr_ns1=-3 speed=10 \
run_tests $ns1 $ns2 10.0.1.1
chk_join_nr 1 1 1
@@ -3069,6 +3074,7 @@ fullmesh_tests()
fastclose_tests()
{
if reset_check_counter "fastclose test" "MPTcpExtMPFastcloseTx"; then
MPTCP_LIB_SUBTEST_FLAKY=1
test_linkfail=1024 fastclose=client \
run_tests $ns1 $ns2 10.0.1.1
chk_join_nr 0 0 0
@@ -3077,6 +3083,7 @@ fastclose_tests()
fi
if reset_check_counter "fastclose server test" "MPTcpExtMPFastcloseRx"; then
MPTCP_LIB_SUBTEST_FLAKY=1
test_linkfail=1024 fastclose=server \
run_tests $ns1 $ns2 10.0.1.1
chk_join_nr 0 0 0 0 0 0 1
@@ -3095,6 +3102,7 @@ fail_tests()
{
# single subflow
if reset_with_fail "Infinite map" 1; then
MPTCP_LIB_SUBTEST_FLAKY=1
test_linkfail=128 \
run_tests $ns1 $ns2 10.0.1.1
chk_join_nr 0 0 0 +1 +0 1 0 1 "$(pedit_action_pkts)"
@@ -3103,6 +3111,7 @@ fail_tests()
# multiple subflows
if reset_with_fail "MP_FAIL MP_RST" 2; then
MPTCP_LIB_SUBTEST_FLAKY=1
tc -n $ns2 qdisc add dev ns2eth1 root netem rate 1mbit delay 5ms
pm_nl_set_limits $ns1 0 1
pm_nl_set_limits $ns2 0 1

View File

@@ -21,6 +21,7 @@ declare -rx MPTCP_LIB_AF_INET6=10
MPTCP_LIB_SUBTESTS=()
MPTCP_LIB_SUBTESTS_DUPLICATED=0
MPTCP_LIB_SUBTEST_FLAKY=0
MPTCP_LIB_TEST_COUNTER=0
MPTCP_LIB_TEST_FORMAT="%02u %-50s"
MPTCP_LIB_IP_MPTCP=0
@@ -41,6 +42,16 @@ else
readonly MPTCP_LIB_COLOR_RESET=
fi
# SELFTESTS_MPTCP_LIB_OVERRIDE_FLAKY env var can be set not to ignore errors
# from subtests marked as flaky
mptcp_lib_override_flaky() {
[ "${SELFTESTS_MPTCP_LIB_OVERRIDE_FLAKY:-}" = 1 ]
}
mptcp_lib_subtest_is_flaky() {
[ "${MPTCP_LIB_SUBTEST_FLAKY}" = 1 ] && ! mptcp_lib_override_flaky
}
# $1: color, $2: text
mptcp_lib_print_color() {
echo -e "${MPTCP_LIB_START_PRINT:-}${*}${MPTCP_LIB_COLOR_RESET}"
@@ -72,7 +83,16 @@ mptcp_lib_pr_skip() {
}
mptcp_lib_pr_fail() {
mptcp_lib_print_err "[FAIL]${1:+ ${*}}"
local title cmt
if mptcp_lib_subtest_is_flaky; then
title="IGNO"
cmt=" (flaky)"
else
title="FAIL"
fi
mptcp_lib_print_err "[${title}]${cmt}${1:+ ${*}}"
}
mptcp_lib_pr_info() {
@@ -208,7 +228,13 @@ mptcp_lib_result_pass() {
# $1: test name
mptcp_lib_result_fail() {
__mptcp_lib_result_add "not ok" "${1}"
if mptcp_lib_subtest_is_flaky; then
# It might sound better to use 'not ok # TODO' or 'ok # SKIP',
# but some CIs don't understand 'TODO' and treat SKIP as errors.
__mptcp_lib_result_add "ok" "${1} # IGNORE Flaky"
else
__mptcp_lib_result_add "not ok" "${1}"
fi
}
# $1: test name

View File

@@ -244,7 +244,7 @@ run_test()
do_transfer $small $large $time
lret=$?
mptcp_lib_result_code "${lret}" "${msg}"
if [ $lret -ne 0 ]; then
if [ $lret -ne 0 ] && ! mptcp_lib_subtest_is_flaky; then
ret=$lret
[ $bail -eq 0 ] || exit $ret
fi
@@ -254,7 +254,7 @@ run_test()
do_transfer $large $small $time
lret=$?
mptcp_lib_result_code "${lret}" "${msg}"
if [ $lret -ne 0 ]; then
if [ $lret -ne 0 ] && ! mptcp_lib_subtest_is_flaky; then
ret=$lret
[ $bail -eq 0 ] || exit $ret
fi
@@ -290,7 +290,7 @@ run_test 10 10 0 0 "balanced bwidth"
run_test 10 10 1 25 "balanced bwidth with unbalanced delay"
# we still need some additional infrastructure to pass the following test-cases
run_test 10 3 0 0 "unbalanced bwidth"
MPTCP_LIB_SUBTEST_FLAKY=1 run_test 10 3 0 0 "unbalanced bwidth"
run_test 10 3 1 25 "unbalanced bwidth with unbalanced delay"
run_test 10 3 25 1 "unbalanced bwidth with opposed, unbalanced delay"

View File

@@ -160,10 +160,12 @@ make_connection()
local is_v6=$1
local app_port=$app4_port
local connect_addr="10.0.1.1"
local client_addr="10.0.1.2"
local listen_addr="0.0.0.0"
if [ "$is_v6" = "v6" ]
then
connect_addr="dead:beef:1::1"
client_addr="dead:beef:1::2"
listen_addr="::"
app_port=$app6_port
else
@@ -206,6 +208,7 @@ make_connection()
[ "$server_serverside" = 1 ]
then
test_pass
print_title "Connection info: ${client_addr}:${client_port} -> ${connect_addr}:${app_port}"
else
test_fail "Expected tokens (c:${client_token} - s:${server_token}) and server (c:${client_serverside} - s:${server_serverside})"
mptcp_lib_result_print_all_tap
@@ -297,7 +300,7 @@ test_announce()
ip netns exec "$ns2"\
./pm_nl_ctl ann 10.0.2.2 token "$client4_token" id $client_addr_id dev\
ns2eth1
print_test "ADD_ADDR id:${client_addr_id} 10.0.2.2 (ns2) => ns1, reuse port"
print_test "ADD_ADDR id:client 10.0.2.2 (ns2) => ns1, reuse port"
sleep 0.5
verify_announce_event $server_evts $ANNOUNCED $server4_token "10.0.2.2" $client_addr_id \
"$client4_port"
@@ -306,7 +309,7 @@ test_announce()
:>"$server_evts"
ip netns exec "$ns2" ./pm_nl_ctl ann\
dead:beef:2::2 token "$client6_token" id $client_addr_id dev ns2eth1
print_test "ADD_ADDR6 id:${client_addr_id} dead:beef:2::2 (ns2) => ns1, reuse port"
print_test "ADD_ADDR6 id:client dead:beef:2::2 (ns2) => ns1, reuse port"
sleep 0.5
verify_announce_event "$server_evts" "$ANNOUNCED" "$server6_token" "dead:beef:2::2"\
"$client_addr_id" "$client6_port" "v6"
@@ -316,7 +319,7 @@ test_announce()
client_addr_id=$((client_addr_id+1))
ip netns exec "$ns2" ./pm_nl_ctl ann 10.0.2.2 token "$client4_token" id\
$client_addr_id dev ns2eth1 port $new4_port
print_test "ADD_ADDR id:${client_addr_id} 10.0.2.2 (ns2) => ns1, new port"
print_test "ADD_ADDR id:client+1 10.0.2.2 (ns2) => ns1, new port"
sleep 0.5
verify_announce_event "$server_evts" "$ANNOUNCED" "$server4_token" "10.0.2.2"\
"$client_addr_id" "$new4_port"
@@ -327,7 +330,7 @@ test_announce()
# ADD_ADDR from the server to client machine reusing the subflow port
ip netns exec "$ns1" ./pm_nl_ctl ann 10.0.2.1 token "$server4_token" id\
$server_addr_id dev ns1eth2
print_test "ADD_ADDR id:${server_addr_id} 10.0.2.1 (ns1) => ns2, reuse port"
print_test "ADD_ADDR id:server 10.0.2.1 (ns1) => ns2, reuse port"
sleep 0.5
verify_announce_event "$client_evts" "$ANNOUNCED" "$client4_token" "10.0.2.1"\
"$server_addr_id" "$app4_port"
@@ -336,7 +339,7 @@ test_announce()
:>"$client_evts"
ip netns exec "$ns1" ./pm_nl_ctl ann dead:beef:2::1 token "$server6_token" id\
$server_addr_id dev ns1eth2
print_test "ADD_ADDR6 id:${server_addr_id} dead:beef:2::1 (ns1) => ns2, reuse port"
print_test "ADD_ADDR6 id:server dead:beef:2::1 (ns1) => ns2, reuse port"
sleep 0.5
verify_announce_event "$client_evts" "$ANNOUNCED" "$client6_token" "dead:beef:2::1"\
"$server_addr_id" "$app6_port" "v6"
@@ -346,7 +349,7 @@ test_announce()
server_addr_id=$((server_addr_id+1))
ip netns exec "$ns1" ./pm_nl_ctl ann 10.0.2.1 token "$server4_token" id\
$server_addr_id dev ns1eth2 port $new4_port
print_test "ADD_ADDR id:${server_addr_id} 10.0.2.1 (ns1) => ns2, new port"
print_test "ADD_ADDR id:server+1 10.0.2.1 (ns1) => ns2, new port"
sleep 0.5
verify_announce_event "$client_evts" "$ANNOUNCED" "$client4_token" "10.0.2.1"\
"$server_addr_id" "$new4_port"
@@ -380,7 +383,7 @@ test_remove()
local invalid_token=$(( client4_token - 1 ))
ip netns exec "$ns2" ./pm_nl_ctl rem token $invalid_token id\
$client_addr_id > /dev/null 2>&1
print_test "RM_ADDR id:${client_addr_id} ns2 => ns1, invalid token"
print_test "RM_ADDR id:client ns2 => ns1, invalid token"
local type
type=$(mptcp_lib_evts_get_info type "$server_evts")
if [ "$type" = "" ]
@@ -394,7 +397,7 @@ test_remove()
local invalid_id=$(( client_addr_id + 1 ))
ip netns exec "$ns2" ./pm_nl_ctl rem token "$client4_token" id\
$invalid_id > /dev/null 2>&1
print_test "RM_ADDR id:${invalid_id} ns2 => ns1, invalid id"
print_test "RM_ADDR id:client+1 ns2 => ns1, invalid id"
type=$(mptcp_lib_evts_get_info type "$server_evts")
if [ "$type" = "" ]
then
@@ -407,7 +410,7 @@ test_remove()
:>"$server_evts"
ip netns exec "$ns2" ./pm_nl_ctl rem token "$client4_token" id\
$client_addr_id
print_test "RM_ADDR id:${client_addr_id} ns2 => ns1"
print_test "RM_ADDR id:client ns2 => ns1"
sleep 0.5
verify_remove_event "$server_evts" "$REMOVED" "$server4_token" "$client_addr_id"
@@ -416,7 +419,7 @@ test_remove()
client_addr_id=$(( client_addr_id - 1 ))
ip netns exec "$ns2" ./pm_nl_ctl rem token "$client4_token" id\
$client_addr_id
print_test "RM_ADDR id:${client_addr_id} ns2 => ns1"
print_test "RM_ADDR id:client-1 ns2 => ns1"
sleep 0.5
verify_remove_event "$server_evts" "$REMOVED" "$server4_token" "$client_addr_id"
@@ -424,7 +427,7 @@ test_remove()
:>"$server_evts"
ip netns exec "$ns2" ./pm_nl_ctl rem token "$client6_token" id\
$client_addr_id
print_test "RM_ADDR6 id:${client_addr_id} ns2 => ns1"
print_test "RM_ADDR6 id:client-1 ns2 => ns1"
sleep 0.5
verify_remove_event "$server_evts" "$REMOVED" "$server6_token" "$client_addr_id"
@@ -434,7 +437,7 @@ test_remove()
# RM_ADDR from the server to client machine
ip netns exec "$ns1" ./pm_nl_ctl rem token "$server4_token" id\
$server_addr_id
print_test "RM_ADDR id:${server_addr_id} ns1 => ns2"
print_test "RM_ADDR id:server ns1 => ns2"
sleep 0.5
verify_remove_event "$client_evts" "$REMOVED" "$client4_token" "$server_addr_id"
@@ -443,7 +446,7 @@ test_remove()
server_addr_id=$(( server_addr_id - 1 ))
ip netns exec "$ns1" ./pm_nl_ctl rem token "$server4_token" id\
$server_addr_id
print_test "RM_ADDR id:${server_addr_id} ns1 => ns2"
print_test "RM_ADDR id:server-1 ns1 => ns2"
sleep 0.5
verify_remove_event "$client_evts" "$REMOVED" "$client4_token" "$server_addr_id"
@@ -451,7 +454,7 @@ test_remove()
:>"$client_evts"
ip netns exec "$ns1" ./pm_nl_ctl rem token "$server6_token" id\
$server_addr_id
print_test "RM_ADDR6 id:${server_addr_id} ns1 => ns2"
print_test "RM_ADDR6 id:server-1 ns1 => ns2"
sleep 0.5
verify_remove_event "$client_evts" "$REMOVED" "$client6_token" "$server_addr_id"
}
@@ -479,8 +482,14 @@ verify_subflow_events()
local locid
local remid
local info
local e_dport_txt
info="${e_saddr} (${e_from}) => ${e_daddr}:${e_dport} (${e_to})"
# only display the fixed ports
if [ "${e_dport}" -ge "${app4_port}" ] && [ "${e_dport}" -le "${app6_port}" ]; then
e_dport_txt=":${e_dport}"
fi
info="${e_saddr} (${e_from}) => ${e_daddr}${e_dport_txt} (${e_to})"
if [ "$e_type" = "$SUB_ESTABLISHED" ]
then
@@ -766,7 +775,7 @@ test_subflows_v4_v6_mix()
:>"$client_evts"
ip netns exec "$ns1" ./pm_nl_ctl ann 10.0.2.1 token "$server6_token" id\
$server_addr_id dev ns1eth2
print_test "ADD_ADDR4 id:${server_addr_id} 10.0.2.1 (ns1) => ns2, reuse port"
print_test "ADD_ADDR4 id:server 10.0.2.1 (ns1) => ns2, reuse port"
sleep 0.5
verify_announce_event "$client_evts" "$ANNOUNCED" "$client6_token" "10.0.2.1"\
"$server_addr_id" "$app6_port"
@@ -861,7 +870,7 @@ test_listener()
local listener_pid=$!
sleep 0.5
print_test "CREATE_LISTENER 10.0.2.2:$client4_port"
print_test "CREATE_LISTENER 10.0.2.2 (client port)"
verify_listener_events $client_evts $LISTENER_CREATED $AF_INET 10.0.2.2 $client4_port
# ADD_ADDR from client to server machine reusing the subflow port
@@ -878,13 +887,14 @@ test_listener()
mptcp_lib_kill_wait $listener_pid
sleep 0.5
print_test "CLOSE_LISTENER 10.0.2.2:$client4_port"
print_test "CLOSE_LISTENER 10.0.2.2 (client port)"
verify_listener_events $client_evts $LISTENER_CLOSED $AF_INET 10.0.2.2 $client4_port
}
print_title "Make connections"
make_connection
make_connection "v6"
print_title "Will be using address IDs ${client_addr_id} (client) and ${server_addr_id} (server)"
test_announce
test_remove

View File

@@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
#
# OVS kernel module self tests

View File

@@ -531,7 +531,7 @@ class ovsactions(nla):
for flat_act in parse_flat_map:
if parse_starts_block(actstr, flat_act[0], False):
actstr = actstr[len(flat_act[0]):]
self["attrs"].append([flat_act[1]])
self["attrs"].append([flat_act[1], True])
actstr = actstr[strspn(actstr, ", ") :]
parsed = True

View File

@@ -0,0 +1,335 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
#
# author: Jianguo Wu <wujianguo@chinatelecom.cn>
#
# Mostly copied from tools/testing/selftests/net/srv6_end_dt4_l3vpn_test.sh.
#
# This script is designed for testing the support of netfilter hooks for
# SRv6 End.DX4 behavior.
#
# Hereafter a network diagram is shown, where one tenants (named 100) offer
# IPv4 L3 VPN services allowing hosts to communicate with each other across
# an IPv6 network.
#
# Routers rt-1 and rt-2 implement IPv4 L3 VPN services leveraging the SRv6
# architecture. The key components for such VPNs are: a) SRv6 Encap behavior,
# b) SRv6 End.DX4 behavior.
#
# To explain how an IPv4 L3 VPN based on SRv6 works, let us briefly consider an
# example where, within the same domain of tenant 100, the host hs-1 pings
# the host hs-2.
#
# First of all, L2 reachability of the host hs-2 is taken into account by
# the router rt-1 which acts as an arp proxy.
#
# When the host hs-1 sends an IPv4 packet destined to hs-2, the router rt-1
# receives the packet on the internal veth-t100 interface, rt-1 contains the
# SRv6 Encap route for encapsulating the IPv4 packet in a IPv6 plus the Segment
# Routing Header (SRH) packet. This packet is sent through the (IPv6) core
# network up to the router rt-2 that receives it on veth0 interface.
#
# The rt-2 router uses the 'localsid' routing table to process incoming
# IPv6+SRH packets which belong to the VPN of the tenant 100. For each of these
# packets, the SRv6 End.DX4 behavior removes the outer IPv6+SRH headers and
# routs the packet to the specified nexthop. Afterwards, the packet is sent to
# the host hs-2 through the veth-t100 interface.
#
# The ping response follows the same processing but this time the role of rt-1
# and rt-2 are swapped.
#
# And when net.netfilter.nf_hooks_lwtunnel is set to 1 in rt-1 or rt-2, and a
# rpfilter iptables rule is added, SRv6 packets will go through netfilter PREROUTING
# hooks.
#
#
# +-------------------+ +-------------------+
# | | | |
# | hs-1 netns | | hs-2 netns |
# | | | |
# | +-------------+ | | +-------------+ |
# | | veth0 | | | | veth0 | |
# | | 10.0.0.1/24 | | | | 10.0.0.2/24 | |
# | +-------------+ | | +-------------+ |
# | . | | . |
# +-------------------+ +-------------------+
# . .
# . .
# . .
# +-----------------------------------+ +-----------------------------------+
# | . | | . |
# | +---------------+ | | +---------------- |
# | | veth-t100 | | | | veth-t100 | |
# | | 10.0.0.11/24 | +----------+ | | +----------+ | 10.0.0.22/24 | |
# | +-------+-------+ | route | | | | route | +-------+-------- |
# | | table | | | | table | |
# | +----------+ | | +----------+ |
# | +--------------+ | | +--------------+ |
# | | veth0 | | | | veth0 | |
# | | 2001:11::1/64 |.|...|.| 2001:11::2/64 | |
# | +--------------+ | | +--------------+ |
# | | | |
# | rt-1 netns | | rt-2 netns |
# | | | |
# +-----------------------------------+ +-----------------------------------+
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~
# | Network configuration |
# ~~~~~~~~~~~~~~~~~~~~~~~~~
#
# rt-1: localsid table
# +----------------------------------------------------------------+
# |SID |Action |
# +----------------------------------------------------------------+
# |fc00:21:100::6004|apply SRv6 End.DX4 nh4 10.0.0.1 dev veth-t100 |
# +----------------------------------------------------------------+
#
# rt-1: route table
# +---------------------------------------------------+
# |host |Action |
# +---------------------------------------------------+
# |10.0.0.2 |apply seg6 encap segs fc00:12:100::6004|
# +---------------------------------------------------+
# |10.0.0.0/24|forward to dev veth_t100 |
# +---------------------------------------------------+
#
#
# rt-2: localsid table
# +---------------------------------------------------------------+
# |SID |Action |
# +---------------------------------------------------------------+
# |fc00:12:100::6004|apply SRv6 End.DX4 nh4 10.0.0.2 dev veth-t100|
# +---------------------------------------------------------------+
#
# rt-2: route table
# +---------------------------------------------------+
# |host |Action |
# +---------------------------------------------------+
# |10.0.0.1 |apply seg6 encap segs fc00:21:100::6004|
# +---------------------------------------------------+
# |10.0.0.0/24|forward to dev veth_t100 |
# +---------------------------------------------------+
#
# Kselftest framework requirement - SKIP code is 4.
ksft_skip=4
readonly IPv6_RT_NETWORK=2001:11
readonly IPv4_HS_NETWORK=10.0.0
readonly SID_LOCATOR=fc00
PING_TIMEOUT_SEC=4
ret=0
PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no}
log_test()
{
local rc=$1
local expected=$2
local msg="$3"
if [ ${rc} -eq ${expected} ]; then
nsuccess=$((nsuccess+1))
printf "\n TEST: %-60s [ OK ]\n" "${msg}"
else
ret=1
nfail=$((nfail+1))
printf "\n TEST: %-60s [FAIL]\n" "${msg}"
if [ "${PAUSE_ON_FAIL}" = "yes" ]; then
echo
echo "hit enter to continue, 'q' to quit"
read a
[ "$a" = "q" ] && exit 1
fi
fi
}
print_log_test_results()
{
if [ "$TESTS" != "none" ]; then
printf "\nTests passed: %3d\n" ${nsuccess}
printf "Tests failed: %3d\n" ${nfail}
fi
}
log_section()
{
echo
echo "################################################################################"
echo "TEST SECTION: $*"
echo "################################################################################"
}
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
}
# Setup the basic networking for the routers
setup_rt_networking()
{
local rt=$1
local nsname=rt-${rt}
ip netns add ${nsname}
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 -netns ${nsname} addr add ${IPv6_RT_NETWORK}::${rt}/64 dev veth0 nodad
ip -netns ${nsname} link set veth0 up
ip -netns ${nsname} link set lo up
ip netns exec ${nsname} sysctl -wq net.ipv4.ip_forward=1
ip netns exec ${nsname} sysctl -wq net.ipv6.conf.all.forwarding=1
}
setup_rt_netfilter()
{
local rt=$1
local nsname=rt-${rt}
ip netns exec ${nsname} sysctl -wq net.netfilter.nf_hooks_lwtunnel=1
ip netns exec ${nsname} iptables -t raw -A PREROUTING -m rpfilter --invert -j DROP
}
setup_hs()
{
local hs=$1
local rt=$2
local tid=$3
local hsname=hs-${hs}
local rtname=rt-${rt}
local rtveth=veth-t${tid}
# set the networking for the host
ip netns add ${hsname}
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} link set veth0 up
ip -netns ${hsname} link set lo up
ip -netns ${rtname} addr add ${IPv4_HS_NETWORK}.${rt}${hs}/24 dev ${rtveth}
ip -netns ${rtname} link set ${rtveth} up
ip netns exec ${rtname} sysctl -wq net.ipv4.conf.${rtveth}.proxy_arp=1
}
setup_vpn_config()
{
local hssrc=$1
local rtsrc=$2
local hsdst=$3
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}
local vpn_sid=${SID_LOCATOR}:${hssrc}${hsdst}:${tid}::6004
# set the encap route for encapsulating packets which arrive from the
# host hssrc and destined to the access router rtsrc.
ip -netns ${rtsrc_name} -4 route add ${IPv4_HS_NETWORK}.${hsdst}/32 \
encap seg6 mode encap segs ${vpn_sid} dev veth0
ip -netns ${rtsrc_name} -6 route add ${vpn_sid}/128 \
via 2001:11::${rtdst} dev veth0
# set the decap route for decapsulating packets which arrive from
# the rtdst router and destined to the hsdst host.
ip -netns ${rtdst_name} -6 route add ${vpn_sid}/128 \
encap seg6local action End.DX4 nh4 ${IPv4_HS_NETWORK}.${hsdst} dev veth-t${tid}
}
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_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_hs 1 1 100
setup_hs 2 2 100
# setup the IPv4 L3 VPN which connects the host hs-1 and host hs-2.
setup_vpn_config 1 1 2 2 100 #args: src_host src_router dst_host dst_router tenant
setup_vpn_config 2 2 1 1 100
}
check_hs_connectivity()
{
local hssrc=$1
local hsdst=$2
local tid=$3
ip netns exec hs-${hssrc} ping -c 1 -W ${PING_TIMEOUT_SEC} \
${IPv4_HS_NETWORK}.${hsdst} >/dev/null 2>&1
}
check_and_log_hs_connectivity()
{
local hssrc=$1
local hsdst=$2
local tid=$3
check_hs_connectivity ${hssrc} ${hsdst} ${tid}
log_test $? 0 "Hosts connectivity: hs-${hssrc} -> hs-${hsdst} (tenant ${tid})"
}
host_tests()
{
log_section "SRv6 VPN connectivity test among hosts in the same tenant"
check_and_log_hs_connectivity 1 2 100
check_and_log_hs_connectivity 2 1 100
}
router_netfilter_tests()
{
log_section "SRv6 VPN connectivity test with netfilter enabled in routers"
setup_rt_netfilter 1
setup_rt_netfilter 2
check_and_log_hs_connectivity 1 2 100
check_and_log_hs_connectivity 2 1 100
}
if [ "$(id -u)" -ne 0 ];then
echo "SKIP: Need root privileges"
exit $ksft_skip
fi
if [ ! -x "$(command -v ip)" ]; then
echo "SKIP: Could not run test without ip tool"
exit $ksft_skip
fi
cleanup &>/dev/null
setup
host_tests
router_netfilter_tests
print_log_test_results
cleanup &>/dev/null
exit ${ret}

View File

@@ -0,0 +1,340 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
#
# author: Jianguo Wu <wujianguo@chinatelecom.cn>
#
# Mostly copied from tools/testing/selftests/net/srv6_end_dt6_l3vpn_test.sh.
#
# This script is designed for testing the support of netfilter hooks for
# SRv6 End.DX4 behavior.
#
# Hereafter a network diagram is shown, where one tenants (named 100) offer
# IPv6 L3 VPN services allowing hosts to communicate with each other across
# an IPv6 network.
#
# Routers rt-1 and rt-2 implement IPv6 L3 VPN services leveraging the SRv6
# architecture. The key components for such VPNs are: a) SRv6 Encap behavior,
# b) SRv6 End.DX4 behavior.
#
# To explain how an IPv6 L3 VPN based on SRv6 works, let us briefly consider an
# example where, within the same domain of tenant 100, the host hs-1 pings
# the host hs-2.
#
# First of all, L2 reachability of the host hs-2 is taken into account by
# the router rt-1 which acts as an arp proxy.
#
# When the host hs-1 sends an IPv6 packet destined to hs-2, the router rt-1
# receives the packet on the internal veth-t100 interface, rt-1 contains the
# SRv6 Encap route for encapsulating the IPv6 packet in a IPv6 plus the Segment
# Routing Header (SRH) packet. This packet is sent through the (IPv6) core
# network up to the router rt-2 that receives it on veth0 interface.
#
# The rt-2 router uses the 'localsid' routing table to process incoming
# IPv6+SRH packets which belong to the VPN of the tenant 100. For each of these
# packets, the SRv6 End.DX4 behavior removes the outer IPv6+SRH headers and
# routs the packet to the specified nexthop. Afterwards, the packet is sent to
# the host hs-2 through the veth-t100 interface.
#
# The ping response follows the same processing but this time the role of rt-1
# and rt-2 are swapped.
#
# And when net.netfilter.nf_hooks_lwtunnel is set to 1 in rt-1 or rt-2, and a
# rpfilter iptables rule is added, SRv6 packets will go through netfilter PREROUTING
# hooks.
#
#
# +-------------------+ +-------------------+
# | | | |
# | hs-1 netns | | hs-2 netns |
# | | | |
# | +-------------+ | | +-------------+ |
# | | veth0 | | | | veth0 | |
# | | cafe::1/64 | | | | cafe::2/64 | |
# | +-------------+ | | +-------------+ |
# | . | | . |
# +-------------------+ +-------------------+
# . .
# . .
# . .
# +-----------------------------------+ +-----------------------------------+
# | . | | . |
# | +---------------+ | | +---------------- |
# | | veth-t100 | | | | veth-t100 | |
# | | cafe::11/64 | +----------+ | | +----------+ | cafe::22/64 | |
# | +-------+-------+ | route | | | | route | +-------+-------- |
# | | table | | | | table | |
# | +----------+ | | +----------+ |
# | +--------------+ | | +--------------+ |
# | | veth0 | | | | veth0 | |
# | | 2001:11::1/64 |.|...|.| 2001:11::2/64 | |
# | +--------------+ | | +--------------+ |
# | | | |
# | rt-1 netns | | rt-2 netns |
# | | | |
# +-----------------------------------+ +-----------------------------------+
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~
# | Network configuration |
# ~~~~~~~~~~~~~~~~~~~~~~~~~
#
# rt-1: localsid table
# +----------------------------------------------------------------+
# |SID |Action |
# +----------------------------------------------------------------+
# |fc00:21:100::6004|apply SRv6 End.DX6 nh6 cafe::1 dev veth-t100 |
# +----------------------------------------------------------------+
#
# rt-1: route table
# +---------------------------------------------------+
# |host |Action |
# +---------------------------------------------------+
# |cafe::2 |apply seg6 encap segs fc00:12:100::6004|
# +---------------------------------------------------+
# |cafe::/64 |forward to dev veth_t100 |
# +---------------------------------------------------+
#
#
# rt-2: localsid table
# +---------------------------------------------------------------+
# |SID |Action |
# +---------------------------------------------------------------+
# |fc00:12:100::6004|apply SRv6 End.DX6 nh6 cafe::2 dev veth-t100 |
# +---------------------------------------------------------------+
#
# rt-2: route table
# +---------------------------------------------------+
# |host |Action |
# +---------------------------------------------------+
# |cafe::1 |apply seg6 encap segs fc00:21:100::6004|
# +---------------------------------------------------+
# |cafe::/64 |forward to dev veth_t100 |
# +---------------------------------------------------+
#
# Kselftest framework requirement - SKIP code is 4.
ksft_skip=4
readonly IPv6_RT_NETWORK=2001:11
readonly IPv6_HS_NETWORK=cafe
readonly SID_LOCATOR=fc00
PING_TIMEOUT_SEC=4
ret=0
PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no}
log_test()
{
local rc=$1
local expected=$2
local msg="$3"
if [ ${rc} -eq ${expected} ]; then
nsuccess=$((nsuccess+1))
printf "\n TEST: %-60s [ OK ]\n" "${msg}"
else
ret=1
nfail=$((nfail+1))
printf "\n TEST: %-60s [FAIL]\n" "${msg}"
if [ "${PAUSE_ON_FAIL}" = "yes" ]; then
echo
echo "hit enter to continue, 'q' to quit"
read a
[ "$a" = "q" ] && exit 1
fi
fi
}
print_log_test_results()
{
if [ "$TESTS" != "none" ]; then
printf "\nTests passed: %3d\n" ${nsuccess}
printf "Tests failed: %3d\n" ${nfail}
fi
}
log_section()
{
echo
echo "################################################################################"
echo "TEST SECTION: $*"
echo "################################################################################"
}
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
}
# Setup the basic networking for the routers
setup_rt_networking()
{
local rt=$1
local nsname=rt-${rt}
ip netns add ${nsname}
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 -netns ${nsname} addr add ${IPv6_RT_NETWORK}::${rt}/64 dev veth0 nodad
ip -netns ${nsname} link set veth0 up
ip -netns ${nsname} link set lo up
ip netns exec ${nsname} sysctl -wq net.ipv6.conf.all.forwarding=1
}
setup_rt_netfilter()
{
local rt=$1
local nsname=rt-${rt}
ip netns exec ${nsname} sysctl -wq net.netfilter.nf_hooks_lwtunnel=1
ip netns exec ${nsname} ip6tables -t raw -A PREROUTING -m rpfilter --invert -j DROP
}
setup_hs()
{
local hs=$1
local rt=$2
local tid=$3
local hsname=hs-${hs}
local rtname=rt-${rt}
local rtveth=veth-t${tid}
# set the networking for the host
ip netns add ${hsname}
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} link set veth0 up
ip -netns ${hsname} link set lo up
ip -netns ${rtname} addr add ${IPv6_HS_NETWORK}::${rt}${hs}/64 dev ${rtveth}
ip -netns ${rtname} link set ${rtveth} up
ip netns exec ${rtname} sysctl -wq net.ipv6.conf.all.accept_dad=0
ip netns exec ${rtname} sysctl -wq net.ipv6.conf.default.accept_dad=0
ip netns exec ${rtname} sysctl -wq net.ipv6.conf.${rtveth}.proxy_ndp=1
}
setup_vpn_config()
{
local hssrc=$1
local rtsrc=$2
local hsdst=$3
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}
local rtveth=veth-t${tid}
local vpn_sid=${SID_LOCATOR}:${hssrc}${hsdst}:${tid}::6004
ip -netns ${rtsrc_name} -6 neigh add proxy ${IPv6_HS_NETWORK}::${hsdst} dev ${rtveth}
# set the encap route for encapsulating packets which arrive from the
# host hssrc and destined to the access router rtsrc.
ip -netns ${rtsrc_name} -6 route add ${IPv6_HS_NETWORK}::${hsdst}/128 \
encap seg6 mode encap segs ${vpn_sid} dev veth0
ip -netns ${rtsrc_name} -6 route add ${vpn_sid}/128 \
via 2001:11::${rtdst} dev veth0
# set the decap route for decapsulating packets which arrive from
# the rtdst router and destined to the hsdst host.
ip -netns ${rtdst_name} -6 route add ${vpn_sid}/128 \
encap seg6local action End.DX6 nh6 ${IPv6_HS_NETWORK}::${hsdst} dev veth-t${tid}
}
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_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_hs 1 1 100
setup_hs 2 2 100
# setup the IPv4 L3 VPN which connects the host hs-1 and host hs-2.
setup_vpn_config 1 1 2 2 100 #args: src_host src_router dst_host dst_router tenant
setup_vpn_config 2 2 1 1 100
}
check_hs_connectivity()
{
local hssrc=$1
local hsdst=$2
local tid=$3
ip netns exec hs-${hssrc} ping -6 -c 1 -W ${PING_TIMEOUT_SEC} \
${IPv6_HS_NETWORK}::${hsdst} >/dev/null 2>&1
}
check_and_log_hs_connectivity()
{
local hssrc=$1
local hsdst=$2
local tid=$3
check_hs_connectivity ${hssrc} ${hsdst} ${tid}
log_test $? 0 "Hosts connectivity: hs-${hssrc} -> hs-${hsdst} (tenant ${tid})"
}
host_tests()
{
log_section "SRv6 VPN connectivity test among hosts in the same tenant"
check_and_log_hs_connectivity 1 2 100
check_and_log_hs_connectivity 2 1 100
}
router_netfilter_tests()
{
log_section "SRv6 VPN connectivity test with netfilter enabled in routers"
setup_rt_netfilter 1
setup_rt_netfilter 2
check_and_log_hs_connectivity 1 2 100
check_and_log_hs_connectivity 2 1 100
}
if [ "$(id -u)" -ne 0 ];then
echo "SKIP: Need root privileges"
exit $ksft_skip
fi
if [ ! -x "$(command -v ip)" ]; then
echo "SKIP: Could not run test without ip tool"
exit $ksft_skip
fi
cleanup &>/dev/null
setup
host_tests
router_netfilter_tests
print_log_test_results
cleanup &>/dev/null
exit ${ret}

View File

@@ -1,8 +1,18 @@
# SPDX-License-Identifier: GPL-2.0-or-later
CFLAGS += -Wall -O2 -g -fsanitize=address -fsanitize=undefined -static-libasan
CFLAGS += -Wall -O2 -g -fsanitize=address -fsanitize=undefined
TEST_GEN_PROGS := openat2_test resolve_test rename_attack_test
# gcc requires -static-libasan in order to ensure that Address Sanitizer's
# library is the first one loaded. However, clang already statically links the
# Address Sanitizer if -fsanitize is specified. Therefore, simply omit
# -static-libasan for clang builds.
ifeq ($(LLVM),)
CFLAGS += -static-libasan
endif
LOCAL_HDRS += helpers.h
include ../lib.mk
$(TEST_GEN_PROGS): helpers.c helpers.h
$(TEST_GEN_PROGS): helpers.c

View File

@@ -5,6 +5,7 @@
*/
#define _GNU_SOURCE
#define __SANE_USERSPACE_TYPES__ // Use ll64
#include <fcntl.h>
#include <sched.h>
#include <sys/stat.h>

View File

@@ -194,14 +194,14 @@ int main(int argc, char *argv[])
ksft_set_plan(7);
ksft_print_msg("Running on:\n");
ksft_print_msg("");
ksft_print_msg("%s", "");
system("uname -a");
ksft_print_msg("Current BPF sysctl settings:\n");
/* Avoid using "sysctl" which may not be installed. */
ksft_print_msg("");
ksft_print_msg("%s", "");
system("grep -H . /proc/sys/net/core/bpf_jit_enable");
ksft_print_msg("");
ksft_print_msg("%s", "");
system("grep -H . /proc/sys/net/core/bpf_jit_harden");
affinity();

View File

@@ -132,6 +132,50 @@
"echo \"1\" > /sys/bus/netdevsim/del_device"
]
},
{
"id": "6f62",
"name": "Add taprio Qdisc with too short interval",
"category": [
"qdisc",
"taprio"
],
"plugins": {
"requires": "nsPlugin"
},
"setup": [
"echo \"1 1 8\" > /sys/bus/netdevsim/new_device"
],
"cmdUnderTest": "$TC qdisc add dev $ETH root handle 1: taprio num_tc 2 queues 1@0 1@1 sched-entry S 01 300 sched-entry S 02 1700 clockid CLOCK_TAI",
"expExitCode": "2",
"verifyCmd": "$TC qdisc show dev $ETH",
"matchPattern": "qdisc taprio 1: root refcnt",
"matchCount": "0",
"teardown": [
"echo \"1\" > /sys/bus/netdevsim/del_device"
]
},
{
"id": "831f",
"name": "Add taprio Qdisc with too short cycle-time",
"category": [
"qdisc",
"taprio"
],
"plugins": {
"requires": "nsPlugin"
},
"setup": [
"echo \"1 1 8\" > /sys/bus/netdevsim/new_device"
],
"cmdUnderTest": "$TC qdisc add dev $ETH root handle 1: taprio num_tc 2 queues 1@0 1@1 sched-entry S 01 200000 sched-entry S 02 200000 cycle-time 100 clockid CLOCK_TAI",
"expExitCode": "2",
"verifyCmd": "$TC qdisc show dev $ETH",
"matchPattern": "qdisc taprio 1: root refcnt",
"matchCount": "0",
"teardown": [
"echo \"1\" > /sys/bus/netdevsim/del_device"
]
},
{
"id": "3e1e",
"name": "Add taprio Qdisc with an invalid cycle-time",