Merge git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf
Alexei Starovoitov says: ==================== pull-request: bpf 2020-06-12 The following pull-request contains BPF updates for your *net* tree. We've added 26 non-merge commits during the last 10 day(s) which contain a total of 27 files changed, 348 insertions(+), 93 deletions(-). The main changes are: 1) sock_hash accounting fix, from Andrey. 2) libbpf fix and probe_mem sanitizing, from Andrii. 3) sock_hash fixes, from Jakub. 4) devmap_val fix, from Jesper. 5) load_bytes_relative fix, from YiFei. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
@@ -230,6 +230,13 @@ void test_cgroup_attach_multi(void)
|
||||
"prog_replace", "errno=%d\n", errno))
|
||||
goto err;
|
||||
|
||||
/* replace program with itself */
|
||||
attach_opts.replace_prog_fd = allow_prog[6];
|
||||
if (CHECK(bpf_prog_attach_xattr(allow_prog[6], cg1,
|
||||
BPF_CGROUP_INET_EGRESS, &attach_opts),
|
||||
"prog_replace", "errno=%d\n", errno))
|
||||
goto err;
|
||||
|
||||
value = 0;
|
||||
CHECK_FAIL(bpf_map_update_elem(map_fd, &key, &value, 0));
|
||||
CHECK_FAIL(system(PING_CMD));
|
||||
|
71
tools/testing/selftests/bpf/prog_tests/load_bytes_relative.c
Normal file
71
tools/testing/selftests/bpf/prog_tests/load_bytes_relative.c
Normal file
@@ -0,0 +1,71 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
/*
|
||||
* Copyright 2020 Google LLC.
|
||||
*/
|
||||
|
||||
#include <test_progs.h>
|
||||
#include <network_helpers.h>
|
||||
|
||||
void test_load_bytes_relative(void)
|
||||
{
|
||||
int server_fd, cgroup_fd, prog_fd, map_fd, client_fd;
|
||||
int err;
|
||||
struct bpf_object *obj;
|
||||
struct bpf_program *prog;
|
||||
struct bpf_map *test_result;
|
||||
__u32 duration = 0;
|
||||
|
||||
__u32 map_key = 0;
|
||||
__u32 map_value = 0;
|
||||
|
||||
cgroup_fd = test__join_cgroup("/load_bytes_relative");
|
||||
if (CHECK_FAIL(cgroup_fd < 0))
|
||||
return;
|
||||
|
||||
server_fd = start_server(AF_INET, SOCK_STREAM);
|
||||
if (CHECK_FAIL(server_fd < 0))
|
||||
goto close_cgroup_fd;
|
||||
|
||||
err = bpf_prog_load("./load_bytes_relative.o", BPF_PROG_TYPE_CGROUP_SKB,
|
||||
&obj, &prog_fd);
|
||||
if (CHECK_FAIL(err))
|
||||
goto close_server_fd;
|
||||
|
||||
test_result = bpf_object__find_map_by_name(obj, "test_result");
|
||||
if (CHECK_FAIL(!test_result))
|
||||
goto close_bpf_object;
|
||||
|
||||
map_fd = bpf_map__fd(test_result);
|
||||
if (map_fd < 0)
|
||||
goto close_bpf_object;
|
||||
|
||||
prog = bpf_object__find_program_by_name(obj, "load_bytes_relative");
|
||||
if (CHECK_FAIL(!prog))
|
||||
goto close_bpf_object;
|
||||
|
||||
err = bpf_prog_attach(prog_fd, cgroup_fd, BPF_CGROUP_INET_EGRESS,
|
||||
BPF_F_ALLOW_MULTI);
|
||||
if (CHECK_FAIL(err))
|
||||
goto close_bpf_object;
|
||||
|
||||
client_fd = connect_to_fd(AF_INET, SOCK_STREAM, server_fd);
|
||||
if (CHECK_FAIL(client_fd < 0))
|
||||
goto close_bpf_object;
|
||||
close(client_fd);
|
||||
|
||||
err = bpf_map_lookup_elem(map_fd, &map_key, &map_value);
|
||||
if (CHECK_FAIL(err))
|
||||
goto close_bpf_object;
|
||||
|
||||
CHECK(map_value != 1, "bpf", "bpf program returned failure");
|
||||
|
||||
close_bpf_object:
|
||||
bpf_object__close(obj);
|
||||
|
||||
close_server_fd:
|
||||
close(server_fd);
|
||||
|
||||
close_cgroup_fd:
|
||||
close(cgroup_fd);
|
||||
}
|
@@ -25,13 +25,23 @@ struct sample {
|
||||
char comm[16];
|
||||
};
|
||||
|
||||
static volatile int sample_cnt;
|
||||
static int sample_cnt;
|
||||
|
||||
static void atomic_inc(int *cnt)
|
||||
{
|
||||
__atomic_add_fetch(cnt, 1, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
|
||||
static int atomic_xchg(int *cnt, int val)
|
||||
{
|
||||
return __atomic_exchange_n(cnt, val, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
|
||||
static int process_sample(void *ctx, void *data, size_t len)
|
||||
{
|
||||
struct sample *s = data;
|
||||
|
||||
sample_cnt++;
|
||||
atomic_inc(&sample_cnt);
|
||||
|
||||
switch (s->seq) {
|
||||
case 0:
|
||||
@@ -76,7 +86,7 @@ void test_ringbuf(void)
|
||||
const size_t rec_sz = BPF_RINGBUF_HDR_SZ + sizeof(struct sample);
|
||||
pthread_t thread;
|
||||
long bg_ret = -1;
|
||||
int err;
|
||||
int err, cnt;
|
||||
|
||||
skel = test_ringbuf__open_and_load();
|
||||
if (CHECK(!skel, "skel_open_load", "skeleton open&load failed\n"))
|
||||
@@ -116,11 +126,15 @@ void test_ringbuf(void)
|
||||
/* -EDONE is used as an indicator that we are done */
|
||||
if (CHECK(err != -EDONE, "err_done", "done err: %d\n", err))
|
||||
goto cleanup;
|
||||
cnt = atomic_xchg(&sample_cnt, 0);
|
||||
CHECK(cnt != 2, "cnt", "exp %d samples, got %d\n", 2, cnt);
|
||||
|
||||
/* we expect extra polling to return nothing */
|
||||
err = ring_buffer__poll(ringbuf, 0);
|
||||
if (CHECK(err != 0, "extra_samples", "poll result: %d\n", err))
|
||||
goto cleanup;
|
||||
cnt = atomic_xchg(&sample_cnt, 0);
|
||||
CHECK(cnt != 0, "cnt", "exp %d samples, got %d\n", 0, cnt);
|
||||
|
||||
CHECK(skel->bss->dropped != 0, "err_dropped", "exp %ld, got %ld\n",
|
||||
0L, skel->bss->dropped);
|
||||
@@ -136,6 +150,8 @@ void test_ringbuf(void)
|
||||
3L * rec_sz, skel->bss->cons_pos);
|
||||
err = ring_buffer__poll(ringbuf, -1);
|
||||
CHECK(err <= 0, "poll_err", "err %d\n", err);
|
||||
cnt = atomic_xchg(&sample_cnt, 0);
|
||||
CHECK(cnt != 2, "cnt", "exp %d samples, got %d\n", 2, cnt);
|
||||
|
||||
/* start poll in background w/ long timeout */
|
||||
err = pthread_create(&thread, NULL, poll_thread, (void *)(long)10000);
|
||||
@@ -164,6 +180,8 @@ void test_ringbuf(void)
|
||||
2L, skel->bss->total);
|
||||
CHECK(skel->bss->discarded != 1, "err_discarded", "exp %ld, got %ld\n",
|
||||
1L, skel->bss->discarded);
|
||||
cnt = atomic_xchg(&sample_cnt, 0);
|
||||
CHECK(cnt != 0, "cnt", "exp %d samples, got %d\n", 0, cnt);
|
||||
|
||||
/* clear flags to return to "adaptive" notification mode */
|
||||
skel->bss->flags = 0;
|
||||
@@ -178,10 +196,20 @@ void test_ringbuf(void)
|
||||
if (CHECK(err != EBUSY, "try_join", "err %d\n", err))
|
||||
goto cleanup;
|
||||
|
||||
/* still no samples, because consumer is behind */
|
||||
cnt = atomic_xchg(&sample_cnt, 0);
|
||||
CHECK(cnt != 0, "cnt", "exp %d samples, got %d\n", 0, cnt);
|
||||
|
||||
skel->bss->dropped = 0;
|
||||
skel->bss->total = 0;
|
||||
skel->bss->discarded = 0;
|
||||
|
||||
skel->bss->value = 333;
|
||||
syscall(__NR_getpgid);
|
||||
/* now force notifications */
|
||||
skel->bss->flags = BPF_RB_FORCE_WAKEUP;
|
||||
sample_cnt = 0;
|
||||
trigger_samples();
|
||||
skel->bss->value = 777;
|
||||
syscall(__NR_getpgid);
|
||||
|
||||
/* now we should get a pending notification */
|
||||
usleep(50000);
|
||||
@@ -193,8 +221,8 @@ void test_ringbuf(void)
|
||||
goto cleanup;
|
||||
|
||||
/* 3 rounds, 2 samples each */
|
||||
CHECK(sample_cnt != 6, "wrong_sample_cnt",
|
||||
"expected to see %d samples, got %d\n", 6, sample_cnt);
|
||||
cnt = atomic_xchg(&sample_cnt, 0);
|
||||
CHECK(cnt != 6, "cnt", "exp %d samples, got %d\n", 6, cnt);
|
||||
|
||||
/* BPF side did everything right */
|
||||
CHECK(skel->bss->dropped != 0, "err_dropped", "exp %ld, got %ld\n",
|
||||
|
@@ -15,6 +15,8 @@ void test_skeleton(void)
|
||||
int duration = 0, err;
|
||||
struct test_skeleton* skel;
|
||||
struct test_skeleton__bss *bss;
|
||||
struct test_skeleton__data *data;
|
||||
struct test_skeleton__rodata *rodata;
|
||||
struct test_skeleton__kconfig *kcfg;
|
||||
|
||||
skel = test_skeleton__open();
|
||||
@@ -24,13 +26,45 @@ void test_skeleton(void)
|
||||
if (CHECK(skel->kconfig, "skel_kconfig", "kconfig is mmaped()!\n"))
|
||||
goto cleanup;
|
||||
|
||||
bss = skel->bss;
|
||||
data = skel->data;
|
||||
rodata = skel->rodata;
|
||||
|
||||
/* validate values are pre-initialized correctly */
|
||||
CHECK(data->in1 != -1, "in1", "got %d != exp %d\n", data->in1, -1);
|
||||
CHECK(data->out1 != -1, "out1", "got %d != exp %d\n", data->out1, -1);
|
||||
CHECK(data->in2 != -1, "in2", "got %lld != exp %lld\n", data->in2, -1LL);
|
||||
CHECK(data->out2 != -1, "out2", "got %lld != exp %lld\n", data->out2, -1LL);
|
||||
|
||||
CHECK(bss->in3 != 0, "in3", "got %d != exp %d\n", bss->in3, 0);
|
||||
CHECK(bss->out3 != 0, "out3", "got %d != exp %d\n", bss->out3, 0);
|
||||
CHECK(bss->in4 != 0, "in4", "got %lld != exp %lld\n", bss->in4, 0LL);
|
||||
CHECK(bss->out4 != 0, "out4", "got %lld != exp %lld\n", bss->out4, 0LL);
|
||||
|
||||
CHECK(rodata->in6 != 0, "in6", "got %d != exp %d\n", rodata->in6, 0);
|
||||
CHECK(bss->out6 != 0, "out6", "got %d != exp %d\n", bss->out6, 0);
|
||||
|
||||
/* validate we can pre-setup global variables, even in .bss */
|
||||
data->in1 = 10;
|
||||
data->in2 = 11;
|
||||
bss->in3 = 12;
|
||||
bss->in4 = 13;
|
||||
rodata->in6 = 14;
|
||||
|
||||
err = test_skeleton__load(skel);
|
||||
if (CHECK(err, "skel_load", "failed to load skeleton: %d\n", err))
|
||||
goto cleanup;
|
||||
|
||||
bss = skel->bss;
|
||||
bss->in1 = 1;
|
||||
bss->in2 = 2;
|
||||
/* validate pre-setup values are still there */
|
||||
CHECK(data->in1 != 10, "in1", "got %d != exp %d\n", data->in1, 10);
|
||||
CHECK(data->in2 != 11, "in2", "got %lld != exp %lld\n", data->in2, 11LL);
|
||||
CHECK(bss->in3 != 12, "in3", "got %d != exp %d\n", bss->in3, 12);
|
||||
CHECK(bss->in4 != 13, "in4", "got %lld != exp %lld\n", bss->in4, 13LL);
|
||||
CHECK(rodata->in6 != 14, "in6", "got %d != exp %d\n", rodata->in6, 14);
|
||||
|
||||
/* now set new values and attach to get them into outX variables */
|
||||
data->in1 = 1;
|
||||
data->in2 = 2;
|
||||
bss->in3 = 3;
|
||||
bss->in4 = 4;
|
||||
bss->in5.a = 5;
|
||||
@@ -44,14 +78,15 @@ void test_skeleton(void)
|
||||
/* trigger tracepoint */
|
||||
usleep(1);
|
||||
|
||||
CHECK(bss->out1 != 1, "res1", "got %d != exp %d\n", bss->out1, 1);
|
||||
CHECK(bss->out2 != 2, "res2", "got %lld != exp %d\n", bss->out2, 2);
|
||||
CHECK(data->out1 != 1, "res1", "got %d != exp %d\n", data->out1, 1);
|
||||
CHECK(data->out2 != 2, "res2", "got %lld != exp %d\n", data->out2, 2);
|
||||
CHECK(bss->out3 != 3, "res3", "got %d != exp %d\n", (int)bss->out3, 3);
|
||||
CHECK(bss->out4 != 4, "res4", "got %lld != exp %d\n", bss->out4, 4);
|
||||
CHECK(bss->handler_out5.a != 5, "res5", "got %d != exp %d\n",
|
||||
bss->handler_out5.a, 5);
|
||||
CHECK(bss->handler_out5.b != 6, "res6", "got %lld != exp %d\n",
|
||||
bss->handler_out5.b, 6);
|
||||
CHECK(bss->out6 != 14, "res7", "got %d != exp %d\n", bss->out6, 14);
|
||||
|
||||
CHECK(bss->bpf_syscall != kcfg->CONFIG_BPF_SYSCALL, "ext1",
|
||||
"got %d != exp %d\n", bss->bpf_syscall, kcfg->CONFIG_BPF_SYSCALL);
|
||||
|
@@ -8,14 +8,6 @@
|
||||
|
||||
#define IFINDEX_LO 1
|
||||
|
||||
struct bpf_devmap_val {
|
||||
u32 ifindex; /* device index */
|
||||
union {
|
||||
int fd; /* prog fd on map write */
|
||||
u32 id; /* prog id on map read */
|
||||
} bpf_prog;
|
||||
};
|
||||
|
||||
void test_xdp_with_devmap_helpers(void)
|
||||
{
|
||||
struct test_xdp_with_devmap_helpers *skel;
|
||||
|
48
tools/testing/selftests/bpf/progs/load_bytes_relative.c
Normal file
48
tools/testing/selftests/bpf/progs/load_bytes_relative.c
Normal file
@@ -0,0 +1,48 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
/*
|
||||
* Copyright 2020 Google LLC.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <linux/bpf.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/ip.h>
|
||||
#include <bpf/bpf_helpers.h>
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_ARRAY);
|
||||
__uint(max_entries, 1);
|
||||
__type(key, __u32);
|
||||
__type(value, __u32);
|
||||
} test_result SEC(".maps");
|
||||
|
||||
SEC("cgroup_skb/egress")
|
||||
int load_bytes_relative(struct __sk_buff *skb)
|
||||
{
|
||||
struct ethhdr eth;
|
||||
struct iphdr iph;
|
||||
|
||||
__u32 map_key = 0;
|
||||
__u32 test_passed = 0;
|
||||
|
||||
/* MAC header is not set by the time cgroup_skb/egress triggers */
|
||||
if (bpf_skb_load_bytes_relative(skb, 0, ð, sizeof(eth),
|
||||
BPF_HDR_START_MAC) != -EFAULT)
|
||||
goto fail;
|
||||
|
||||
if (bpf_skb_load_bytes_relative(skb, 0, &iph, sizeof(iph),
|
||||
BPF_HDR_START_NET))
|
||||
goto fail;
|
||||
|
||||
if (bpf_skb_load_bytes_relative(skb, 0xffff, &iph, sizeof(iph),
|
||||
BPF_HDR_START_NET) != -EFAULT)
|
||||
goto fail;
|
||||
|
||||
test_passed = 1;
|
||||
|
||||
fail:
|
||||
bpf_map_update_elem(&test_result, &map_key, &test_passed, BPF_ANY);
|
||||
|
||||
return 1;
|
||||
}
|
@@ -10,16 +10,26 @@ struct s {
|
||||
long long b;
|
||||
} __attribute__((packed));
|
||||
|
||||
int in1 = 0;
|
||||
long long in2 = 0;
|
||||
/* .data section */
|
||||
int in1 = -1;
|
||||
long long in2 = -1;
|
||||
|
||||
/* .bss section */
|
||||
char in3 = '\0';
|
||||
long long in4 __attribute__((aligned(64))) = 0;
|
||||
struct s in5 = {};
|
||||
|
||||
long long out2 = 0;
|
||||
/* .rodata section */
|
||||
const volatile int in6 = 0;
|
||||
|
||||
/* .data section */
|
||||
int out1 = -1;
|
||||
long long out2 = -1;
|
||||
|
||||
/* .bss section */
|
||||
char out3 = 0;
|
||||
long long out4 = 0;
|
||||
int out1 = 0;
|
||||
int out6 = 0;
|
||||
|
||||
extern bool CONFIG_BPF_SYSCALL __kconfig;
|
||||
extern int LINUX_KERNEL_VERSION __kconfig;
|
||||
@@ -36,6 +46,7 @@ int handler(const void *ctx)
|
||||
out3 = in3;
|
||||
out4 = in4;
|
||||
out5 = in5;
|
||||
out6 = in6;
|
||||
|
||||
bpf_syscall = CONFIG_BPF_SYSCALL;
|
||||
kern_ver = LINUX_KERNEL_VERSION;
|
||||
|
@@ -2,7 +2,7 @@
|
||||
/* fails to load without expected_attach_type = BPF_XDP_DEVMAP
|
||||
* because of access to egress_ifindex
|
||||
*/
|
||||
#include "vmlinux.h"
|
||||
#include <linux/bpf.h>
|
||||
#include <bpf/bpf_helpers.h>
|
||||
|
||||
SEC("xdp_dm_log")
|
||||
|
@@ -1,6 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#include "vmlinux.h"
|
||||
#include <linux/bpf.h>
|
||||
#include <bpf/bpf_helpers.h>
|
||||
|
||||
struct {
|
||||
|
Reference in New Issue
Block a user