mirror of
https://github.com/revyos/thead-kernel.git
synced 2026-06-21 09:12:26 +02:00
@@ -10,20 +10,86 @@
|
||||
#include <net/bpf_sk_storage.h>
|
||||
#include <net/sock.h>
|
||||
#include <net/tcp.h>
|
||||
#include <net/net_namespace.h>
|
||||
#include <linux/error-injection.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/sock_diag.h>
|
||||
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include <trace/events/bpf_test_run.h>
|
||||
|
||||
struct bpf_test_timer {
|
||||
enum { NO_PREEMPT, NO_MIGRATE } mode;
|
||||
u32 i;
|
||||
u64 time_start, time_spent;
|
||||
};
|
||||
|
||||
static void bpf_test_timer_enter(struct bpf_test_timer *t)
|
||||
__acquires(rcu)
|
||||
{
|
||||
rcu_read_lock();
|
||||
if (t->mode == NO_PREEMPT)
|
||||
preempt_disable();
|
||||
else
|
||||
migrate_disable();
|
||||
|
||||
t->time_start = ktime_get_ns();
|
||||
}
|
||||
|
||||
static void bpf_test_timer_leave(struct bpf_test_timer *t)
|
||||
__releases(rcu)
|
||||
{
|
||||
t->time_start = 0;
|
||||
|
||||
if (t->mode == NO_PREEMPT)
|
||||
preempt_enable();
|
||||
else
|
||||
migrate_enable();
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static bool bpf_test_timer_continue(struct bpf_test_timer *t, u32 repeat, int *err, u32 *duration)
|
||||
__must_hold(rcu)
|
||||
{
|
||||
t->i++;
|
||||
if (t->i >= repeat) {
|
||||
/* We're done. */
|
||||
t->time_spent += ktime_get_ns() - t->time_start;
|
||||
do_div(t->time_spent, t->i);
|
||||
*duration = t->time_spent > U32_MAX ? U32_MAX : (u32)t->time_spent;
|
||||
*err = 0;
|
||||
goto reset;
|
||||
}
|
||||
|
||||
if (signal_pending(current)) {
|
||||
/* During iteration: we've been cancelled, abort. */
|
||||
*err = -EINTR;
|
||||
goto reset;
|
||||
}
|
||||
|
||||
if (need_resched()) {
|
||||
/* During iteration: we need to reschedule between runs. */
|
||||
t->time_spent += ktime_get_ns() - t->time_start;
|
||||
bpf_test_timer_leave(t);
|
||||
cond_resched();
|
||||
bpf_test_timer_enter(t);
|
||||
}
|
||||
|
||||
/* Do another round. */
|
||||
return true;
|
||||
|
||||
reset:
|
||||
t->i = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
static int bpf_test_run(struct bpf_prog *prog, void *ctx, u32 repeat,
|
||||
u32 *retval, u32 *time, bool xdp)
|
||||
{
|
||||
struct bpf_cgroup_storage *storage[MAX_BPF_CGROUP_STORAGE_TYPE] = { NULL };
|
||||
struct bpf_test_timer t = { NO_MIGRATE };
|
||||
enum bpf_cgroup_storage_type stype;
|
||||
u64 time_start, time_spent = 0;
|
||||
int ret = 0;
|
||||
u32 i;
|
||||
int ret;
|
||||
|
||||
for_each_cgroup_storage_type(stype) {
|
||||
storage[stype] = bpf_cgroup_storage_alloc(prog, stype);
|
||||
@@ -38,10 +104,8 @@ static int bpf_test_run(struct bpf_prog *prog, void *ctx, u32 repeat,
|
||||
if (!repeat)
|
||||
repeat = 1;
|
||||
|
||||
rcu_read_lock();
|
||||
migrate_disable();
|
||||
time_start = ktime_get_ns();
|
||||
for (i = 0; i < repeat; i++) {
|
||||
bpf_test_timer_enter(&t);
|
||||
do {
|
||||
ret = bpf_cgroup_storage_set(storage);
|
||||
if (ret)
|
||||
break;
|
||||
@@ -53,29 +117,8 @@ static int bpf_test_run(struct bpf_prog *prog, void *ctx, u32 repeat,
|
||||
|
||||
bpf_cgroup_storage_unset();
|
||||
|
||||
if (signal_pending(current)) {
|
||||
ret = -EINTR;
|
||||
break;
|
||||
}
|
||||
|
||||
if (need_resched()) {
|
||||
time_spent += ktime_get_ns() - time_start;
|
||||
migrate_enable();
|
||||
rcu_read_unlock();
|
||||
|
||||
cond_resched();
|
||||
|
||||
rcu_read_lock();
|
||||
migrate_disable();
|
||||
time_start = ktime_get_ns();
|
||||
}
|
||||
}
|
||||
time_spent += ktime_get_ns() - time_start;
|
||||
migrate_enable();
|
||||
rcu_read_unlock();
|
||||
|
||||
do_div(time_spent, repeat);
|
||||
*time = time_spent > U32_MAX ? U32_MAX : (u32)time_spent;
|
||||
} while (bpf_test_timer_continue(&t, repeat, &ret, time));
|
||||
bpf_test_timer_leave(&t);
|
||||
|
||||
for_each_cgroup_storage_type(stype)
|
||||
bpf_cgroup_storage_free(storage[stype]);
|
||||
@@ -688,18 +731,17 @@ int bpf_prog_test_run_flow_dissector(struct bpf_prog *prog,
|
||||
const union bpf_attr *kattr,
|
||||
union bpf_attr __user *uattr)
|
||||
{
|
||||
struct bpf_test_timer t = { NO_PREEMPT };
|
||||
u32 size = kattr->test.data_size_in;
|
||||
struct bpf_flow_dissector ctx = {};
|
||||
u32 repeat = kattr->test.repeat;
|
||||
struct bpf_flow_keys *user_ctx;
|
||||
struct bpf_flow_keys flow_keys;
|
||||
u64 time_start, time_spent = 0;
|
||||
const struct ethhdr *eth;
|
||||
unsigned int flags = 0;
|
||||
u32 retval, duration;
|
||||
void *data;
|
||||
int ret;
|
||||
u32 i;
|
||||
|
||||
if (prog->type != BPF_PROG_TYPE_FLOW_DISSECTOR)
|
||||
return -EINVAL;
|
||||
@@ -735,39 +777,15 @@ int bpf_prog_test_run_flow_dissector(struct bpf_prog *prog,
|
||||
ctx.data = data;
|
||||
ctx.data_end = (__u8 *)data + size;
|
||||
|
||||
rcu_read_lock();
|
||||
preempt_disable();
|
||||
time_start = ktime_get_ns();
|
||||
for (i = 0; i < repeat; i++) {
|
||||
retval = bpf_flow_dissect(prog, &ctx, eth->h_proto, ETH_HLEN,
|
||||
size, flags);
|
||||
bpf_test_timer_enter(&t);
|
||||
do {
|
||||
retval = bpf_flow_dissect(prog, &ctx, eth->h_proto, ETH_HLEN,
|
||||
size, flags);
|
||||
} while (bpf_test_timer_continue(&t, repeat, &ret, &duration));
|
||||
bpf_test_timer_leave(&t);
|
||||
|
||||
if (signal_pending(current)) {
|
||||
preempt_enable();
|
||||
rcu_read_unlock();
|
||||
|
||||
ret = -EINTR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (need_resched()) {
|
||||
time_spent += ktime_get_ns() - time_start;
|
||||
preempt_enable();
|
||||
rcu_read_unlock();
|
||||
|
||||
cond_resched();
|
||||
|
||||
rcu_read_lock();
|
||||
preempt_disable();
|
||||
time_start = ktime_get_ns();
|
||||
}
|
||||
}
|
||||
time_spent += ktime_get_ns() - time_start;
|
||||
preempt_enable();
|
||||
rcu_read_unlock();
|
||||
|
||||
do_div(time_spent, repeat);
|
||||
duration = time_spent > U32_MAX ? U32_MAX : (u32)time_spent;
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = bpf_test_finish(kattr, uattr, &flow_keys, sizeof(flow_keys),
|
||||
retval, duration);
|
||||
@@ -780,3 +798,106 @@ out:
|
||||
kfree(data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int bpf_prog_test_run_sk_lookup(struct bpf_prog *prog, const union bpf_attr *kattr,
|
||||
union bpf_attr __user *uattr)
|
||||
{
|
||||
struct bpf_test_timer t = { NO_PREEMPT };
|
||||
struct bpf_prog_array *progs = NULL;
|
||||
struct bpf_sk_lookup_kern ctx = {};
|
||||
u32 repeat = kattr->test.repeat;
|
||||
struct bpf_sk_lookup *user_ctx;
|
||||
u32 retval, duration;
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (prog->type != BPF_PROG_TYPE_SK_LOOKUP)
|
||||
return -EINVAL;
|
||||
|
||||
if (kattr->test.flags || kattr->test.cpu)
|
||||
return -EINVAL;
|
||||
|
||||
if (kattr->test.data_in || kattr->test.data_size_in || kattr->test.data_out ||
|
||||
kattr->test.data_size_out)
|
||||
return -EINVAL;
|
||||
|
||||
if (!repeat)
|
||||
repeat = 1;
|
||||
|
||||
user_ctx = bpf_ctx_init(kattr, sizeof(*user_ctx));
|
||||
if (IS_ERR(user_ctx))
|
||||
return PTR_ERR(user_ctx);
|
||||
|
||||
if (!user_ctx)
|
||||
return -EINVAL;
|
||||
|
||||
if (user_ctx->sk)
|
||||
goto out;
|
||||
|
||||
if (!range_is_zero(user_ctx, offsetofend(typeof(*user_ctx), local_port), sizeof(*user_ctx)))
|
||||
goto out;
|
||||
|
||||
if (user_ctx->local_port > U16_MAX || user_ctx->remote_port > U16_MAX) {
|
||||
ret = -ERANGE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ctx.family = (u16)user_ctx->family;
|
||||
ctx.protocol = (u16)user_ctx->protocol;
|
||||
ctx.dport = (u16)user_ctx->local_port;
|
||||
ctx.sport = (__force __be16)user_ctx->remote_port;
|
||||
|
||||
switch (ctx.family) {
|
||||
case AF_INET:
|
||||
ctx.v4.daddr = (__force __be32)user_ctx->local_ip4;
|
||||
ctx.v4.saddr = (__force __be32)user_ctx->remote_ip4;
|
||||
break;
|
||||
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
case AF_INET6:
|
||||
ctx.v6.daddr = (struct in6_addr *)user_ctx->local_ip6;
|
||||
ctx.v6.saddr = (struct in6_addr *)user_ctx->remote_ip6;
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
ret = -EAFNOSUPPORT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
progs = bpf_prog_array_alloc(1, GFP_KERNEL);
|
||||
if (!progs) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
progs->items[0].prog = prog;
|
||||
|
||||
bpf_test_timer_enter(&t);
|
||||
do {
|
||||
ctx.selected_sk = NULL;
|
||||
retval = BPF_PROG_SK_LOOKUP_RUN_ARRAY(progs, ctx, BPF_PROG_RUN);
|
||||
} while (bpf_test_timer_continue(&t, repeat, &ret, &duration));
|
||||
bpf_test_timer_leave(&t);
|
||||
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
user_ctx->cookie = 0;
|
||||
if (ctx.selected_sk) {
|
||||
if (ctx.selected_sk->sk_reuseport && !ctx.no_reuseport) {
|
||||
ret = -EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
user_ctx->cookie = sock_gen_cookie(ctx.selected_sk);
|
||||
}
|
||||
|
||||
ret = bpf_test_finish(kattr, uattr, NULL, 0, retval, duration);
|
||||
if (!ret)
|
||||
ret = bpf_ctx_finish(kattr, uattr, user_ctx, sizeof(*user_ctx));
|
||||
|
||||
out:
|
||||
bpf_prog_array_free(progs);
|
||||
kfree(user_ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -10295,6 +10295,7 @@ static u32 sk_lookup_convert_ctx_access(enum bpf_access_type type,
|
||||
}
|
||||
|
||||
const struct bpf_prog_ops sk_lookup_prog_ops = {
|
||||
.test_run = bpf_prog_test_run_sk_lookup,
|
||||
};
|
||||
|
||||
const struct bpf_verifier_ops sk_lookup_verifier_ops = {
|
||||
|
||||
Reference in New Issue
Block a user