Skip to content

enable BPF_PROG_TEST_RUN for raw_tp #96

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
sudo: required
language: bash
dist: bionic
services:
- docker

env:
global:
- PROJECT_NAME='libbpf'
- AUTHOR_EMAIL="$(git log -1 --pretty=\"%aE\")"
- REPO_ROOT="$TRAVIS_BUILD_DIR"
- CI_ROOT="$REPO_ROOT/travis-ci"
- VMTEST_ROOT="$CI_ROOT/vmtest"

addons:
apt:
packages:
- qemu-kvm
- zstd
- binutils-dev
- elfutils
- libcap-dev
- libelf-dev
- libdw-dev
- python3-docutils

jobs:
include:
- stage: Builds & Tests
name: Kernel LATEST + selftests
language: bash
env: KERNEL=LATEST
script: $CI_ROOT/vmtest/run_vmtest.sh || travis_terminate 1
3 changes: 3 additions & 0 deletions include/linux/bpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -1381,6 +1381,9 @@ int bpf_prog_test_run_tracing(struct bpf_prog *prog,
int bpf_prog_test_run_flow_dissector(struct bpf_prog *prog,
const union bpf_attr *kattr,
union bpf_attr __user *uattr);
int bpf_prog_test_run_raw_tp(struct bpf_prog *prog,
const union bpf_attr *kattr,
union bpf_attr __user *uattr);
bool btf_ctx_access(int off, int size, enum bpf_access_type type,
const struct bpf_prog *prog,
struct bpf_insn_access_aux *info);
Expand Down
5 changes: 5 additions & 0 deletions include/uapi/linux/bpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,11 @@ union bpf_attr {
*/
__aligned_u64 ctx_in;
__aligned_u64 ctx_out;
__u32 cpu_plus; /* run this program on cpu
* (cpu_plus - 1).
* If cpu_plus == 0, run on
* current cpu.
*/
} test;

struct { /* anonymous struct used by BPF_*_GET_*_ID */
Expand Down
2 changes: 1 addition & 1 deletion kernel/bpf/syscall.c
Original file line number Diff line number Diff line change
Expand Up @@ -2975,7 +2975,7 @@ static int bpf_prog_query(const union bpf_attr *attr,
}
}

#define BPF_PROG_TEST_RUN_LAST_FIELD test.ctx_out
#define BPF_PROG_TEST_RUN_LAST_FIELD test.cpu_plus

static int bpf_prog_test_run(const union bpf_attr *attr,
union bpf_attr __user *uattr)
Expand Down
1 change: 1 addition & 0 deletions kernel/trace/bpf_trace.c
Original file line number Diff line number Diff line change
Expand Up @@ -1678,6 +1678,7 @@ const struct bpf_verifier_ops raw_tracepoint_verifier_ops = {
};

const struct bpf_prog_ops raw_tracepoint_prog_ops = {
.test_run = bpf_prog_test_run_raw_tp,
};

const struct bpf_verifier_ops tracing_verifier_ops = {
Expand Down
88 changes: 88 additions & 0 deletions net/bpf/test_run.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <net/sock.h>
#include <net/tcp.h>
#include <linux/error-injection.h>
#include <linux/smp.h>

#define CREATE_TRACE_POINTS
#include <trace/events/bpf_test_run.h>
Expand Down Expand Up @@ -204,6 +205,9 @@ int bpf_prog_test_run_tracing(struct bpf_prog *prog,
int b = 2, err = -EFAULT;
u32 retval = 0;

if (kattr->test.cpu_plus)
return -EINVAL;

switch (prog->expected_attach_type) {
case BPF_TRACE_FENTRY:
case BPF_TRACE_FEXIT:
Expand Down Expand Up @@ -236,6 +240,84 @@ int bpf_prog_test_run_tracing(struct bpf_prog *prog,
return err;
}

struct bpf_raw_tp_test_run_info {
struct bpf_prog *prog;
void *ctx;
u32 retval;
};

static void
__bpf_prog_test_run_raw_tp(void *data)
{
struct bpf_raw_tp_test_run_info *info = data;

rcu_read_lock();
migrate_disable();
info->retval = BPF_PROG_RUN(info->prog, info->ctx);
migrate_enable();
rcu_read_unlock();
}

int bpf_prog_test_run_raw_tp(struct bpf_prog *prog,
const union bpf_attr *kattr,
union bpf_attr __user *uattr)
{
void __user *ctx_in = u64_to_user_ptr(kattr->test.ctx_in);
__u32 ctx_size_in = kattr->test.ctx_size_in;
struct bpf_raw_tp_test_run_info info;
int cpu, err = 0;

/* doesn't support data_in/out, ctx_out, duration, or repeat */
if (kattr->test.data_in || kattr->test.data_out ||
kattr->test.ctx_out || kattr->test.duration ||
kattr->test.repeat)
return -EINVAL;

if (ctx_size_in < prog->aux->max_ctx_offset)
return -EINVAL;

if (ctx_size_in) {
info.ctx = kzalloc(ctx_size_in, GFP_USER);
if (!info.ctx)
return -ENOMEM;
if (copy_from_user(info.ctx, ctx_in, ctx_size_in)) {
err = -EFAULT;
goto out;
}
} else {
info.ctx = NULL;
}

info.prog = prog;
cpu = kattr->test.cpu_plus - 1;

if (!kattr->test.cpu_plus || cpu == smp_processor_id()) {
__bpf_prog_test_run_raw_tp(&info);
} else {
/* smp_call_function_single() also checks cpu_online()
* after csd_lock(). However, since cpu_plus is from user
* space, let's do an extra quick check to filter out
* invalid value before smp_call_function_single().
*/
if (!cpu_online(cpu)) {
err = -ENXIO;
goto out;
}

err = smp_call_function_single(cpu, __bpf_prog_test_run_raw_tp,
&info, 1);
if (err)
goto out;
}

if (copy_to_user(&uattr->test.retval, &info.retval, sizeof(u32)))
err = -EFAULT;

out:
kfree(info.ctx);
return err;
}

static void *bpf_ctx_init(const union bpf_attr *kattr, u32 max_size)
{
void __user *data_in = u64_to_user_ptr(kattr->test.ctx_in);
Expand Down Expand Up @@ -410,6 +492,9 @@ int bpf_prog_test_run_skb(struct bpf_prog *prog, const union bpf_attr *kattr,
void *data;
int ret;

if (kattr->test.cpu_plus)
return -EINVAL;

data = bpf_test_init(kattr, size, NET_SKB_PAD + NET_IP_ALIGN,
SKB_DATA_ALIGN(sizeof(struct skb_shared_info)));
if (IS_ERR(data))
Expand Down Expand Up @@ -607,6 +692,9 @@ int bpf_prog_test_run_flow_dissector(struct bpf_prog *prog,
if (prog->type != BPF_PROG_TYPE_FLOW_DISSECTOR)
return -EINVAL;

if (kattr->test.cpu_plus)
return -EINVAL;

if (size < ETH_HLEN)
return -EINVAL;

Expand Down
5 changes: 5 additions & 0 deletions tools/include/uapi/linux/bpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,11 @@ union bpf_attr {
*/
__aligned_u64 ctx_in;
__aligned_u64 ctx_out;
__u32 cpu_plus; /* run this program on cpu
* (cpu_plus - 1).
* If cpu_plus == 0, run on
* current cpu.
*/
} test;

struct { /* anonymous struct used by BPF_*_GET_*_ID */
Expand Down
13 changes: 12 additions & 1 deletion tools/lib/bpf/bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -684,7 +684,8 @@ int bpf_prog_test_run(int prog_fd, int repeat, void *data, __u32 size,
return ret;
}

int bpf_prog_test_run_xattr(struct bpf_prog_test_run_attr *test_attr)
int bpf_prog_test_run_xattr_opts(struct bpf_prog_test_run_attr *test_attr,
const struct bpf_prog_test_run_opts *opts)
{
union bpf_attr attr;
int ret;
Expand All @@ -693,6 +694,11 @@ int bpf_prog_test_run_xattr(struct bpf_prog_test_run_attr *test_attr)
return -EINVAL;

memset(&attr, 0, sizeof(attr));
if (opts) {
if (!OPTS_VALID(opts, bpf_prog_test_run_opts))
return -EINVAL;
attr.test.cpu_plus = opts->cpu_plus;
}
attr.test.prog_fd = test_attr->prog_fd;
attr.test.data_in = ptr_to_u64(test_attr->data_in);
attr.test.data_out = ptr_to_u64(test_attr->data_out);
Expand All @@ -712,6 +718,11 @@ int bpf_prog_test_run_xattr(struct bpf_prog_test_run_attr *test_attr)
return ret;
}

int bpf_prog_test_run_xattr(struct bpf_prog_test_run_attr *test_attr)
{
return bpf_prog_test_run_xattr_opts(test_attr, NULL);
}

static int bpf_obj_get_next_id(__u32 start_id, __u32 *next_id, int cmd)
{
union bpf_attr attr;
Expand Down
11 changes: 11 additions & 0 deletions tools/lib/bpf/bpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,17 @@ struct bpf_prog_bind_opts {

LIBBPF_API int bpf_prog_bind_map(int prog_fd, int map_fd,
const struct bpf_prog_bind_opts *opts);

struct bpf_prog_test_run_opts {
size_t sz; /* size of this struct for forward/backward compatibility */
__u32 cpu_plus;
};
#define bpf_prog_test_run_opts__last_field cpu_plus

LIBBPF_API
int bpf_prog_test_run_xattr_opts(struct bpf_prog_test_run_attr *test_attr,
const struct bpf_prog_test_run_opts *opts);

#ifdef __cplusplus
} /* extern "C" */
#endif
Expand Down
1 change: 1 addition & 0 deletions tools/lib/bpf/libbpf.map
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,7 @@ LIBBPF_0.1.0 {
LIBBPF_0.2.0 {
global:
bpf_prog_bind_map;
bpf_prog_test_run_xattr_opts;
bpf_program__section_name;
perf_buffer__buffer_cnt;
perf_buffer__buffer_fd;
Expand Down
75 changes: 75 additions & 0 deletions tools/testing/selftests/bpf/prog_tests/raw_tp_test_run.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2019 Facebook */
#include <test_progs.h>
#include "bpf/libbpf_internal.h"
#include "test_raw_tp_test_run.skel.h"

static int duration;

void test_raw_tp_test_run(void)
{
struct bpf_prog_test_run_attr test_attr = {};
__u64 args[2] = {0x1234ULL, 0x5678ULL};
int comm_fd = -1, err, nr_online, i;
int expected_retval = 0x1234 + 0x5678;
struct test_raw_tp_test_run *skel;
char buf[] = "new_name";
bool *online = NULL;

err = parse_cpu_mask_file("/sys/devices/system/cpu/online", &online,
&nr_online);
if (CHECK(err, "parse_cpu_mask_file", "err %d\n", err))
return;

skel = test_raw_tp_test_run__open_and_load();
if (CHECK(!skel, "skel_open", "failed to open skeleton\n")) {
free(online);
return;
}
err = test_raw_tp_test_run__attach(skel);
if (CHECK(err, "skel_attach", "skeleton attach failed: %d\n", err))
goto cleanup;

comm_fd = open("/proc/self/comm", O_WRONLY|O_TRUNC);
if (CHECK(comm_fd < 0, "open /proc/self/comm", "err %d\n", errno))
goto cleanup;

err = write(comm_fd, buf, sizeof(buf));
CHECK(err < 0, "task rename", "err %d", errno);

CHECK(skel->bss->count == 0, "check_count", "didn't increase\n");
CHECK(skel->data->on_cpu != 0xffffffff, "check_on_cpu", "got wrong value\n");

test_attr.prog_fd = bpf_program__fd(skel->progs.rename);
test_attr.ctx_in = args;
test_attr.ctx_size_in = sizeof(__u64);

err = bpf_prog_test_run_xattr(&test_attr);
CHECK(err == 0, "test_run", "should fail for too small ctx\n");

test_attr.ctx_size_in = sizeof(args);
err = bpf_prog_test_run_xattr(&test_attr);
CHECK(err < 0, "test_run", "err %d\n", errno);
CHECK(test_attr.retval != expected_retval, "check_retval",
"expect 0x%x, got 0x%x\n", expected_retval, test_attr.retval);

for (i = 0; i < nr_online; i++)
if (online[i]) {
DECLARE_LIBBPF_OPTS(bpf_prog_test_run_opts, opts,
.cpu_plus = i + 1,
);

test_attr.retval = 0;
err = bpf_prog_test_run_xattr_opts(&test_attr, &opts);
CHECK(err < 0, "test_run_with_opts", "err %d\n", errno);
CHECK(skel->data->on_cpu != i, "check_on_cpu",
"got wrong value\n");
CHECK(test_attr.retval != expected_retval,
"check_retval", "expect 0x%x, got 0x%x\n",
expected_retval, test_attr.retval);
}
cleanup:
close(comm_fd);
test_raw_tp_test_run__destroy(skel);
free(online);
}
25 changes: 25 additions & 0 deletions tools/testing/selftests/bpf/progs/test_raw_tp_test_run.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2020 Facebook */

#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_endian.h>
#include <bpf/bpf_tracing.h>

__u32 count = 0;
__u32 on_cpu = 0xffffffff;

SEC("raw_tp/task_rename")
int BPF_PROG(rename, struct task_struct *task, char *comm)
{

count++;
if ((__u64) task == 0x1234ULL && (__u64) comm == 0x5678ULL) {
on_cpu = bpf_get_smp_processor_id();
return (int)task + (int)comm;
}

return 0;
}

char _license[] SEC("license") = "GPL";
Loading