Skip to content
Permalink
Browse files
bpf: introduce bpf timer
Signed-off-by: Cong Wang <cong.wang@bytedance.com>
  • Loading branch information
Cong Wang committed Mar 17, 2021
1 parent 56901d4 commit 78245045626bf039d5e1ccc3a2f2f8b3a7079e8e
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 3 deletions.
@@ -1900,6 +1900,10 @@ extern const struct bpf_func_proto bpf_get_socket_ptr_cookie_proto;
extern const struct bpf_func_proto bpf_task_storage_get_proto;
extern const struct bpf_func_proto bpf_task_storage_delete_proto;
extern const struct bpf_func_proto bpf_for_each_map_elem_proto;
extern const struct bpf_func_proto bpf_timer_create_proto;
extern const struct bpf_func_proto bpf_timer_gettime_proto;
extern const struct bpf_func_proto bpf_timer_settime_proto;
extern const struct bpf_func_proto bpf_timer_delete_proto;

const struct bpf_func_proto *bpf_tracing_func_proto(
enum bpf_func_id func_id, const struct bpf_prog *prog);
@@ -4827,6 +4827,10 @@ union bpf_attr {
FN(sock_from_file), \
FN(check_mtu), \
FN(for_each_map_elem), \
FN(timer_create), \
FN(timer_settime), \
FN(timer_gettime), \
FN(timer_delete), \
/* */

/* integer value in 'imm' field of BPF_CALL instruction selects which helper
@@ -662,6 +662,122 @@ const struct bpf_func_proto bpf_this_cpu_ptr_proto = {
.arg1_type = ARG_PTR_TO_PERCPU_BTF_ID,
};

struct bpf_timer_list {
struct timer_list timer;
void *callback;
void *arg;
struct rcu_head rcu;
};

static DEFINE_IDR(bpf_timer_idr);
static DEFINE_SPINLOCK(idr_lock);

static void bpf_timer_callback(struct timer_list *t)
{
struct bpf_timer_list *bt = from_timer(bt, t, timer);

rcu_read_lock();
BPF_CAST_CALL(bt->callback)((u64)(long)bt->ctx, 0, 0, 0, 0);
rcu_read_unlock();
}

notrace BPF_CALL_4(bpf_timer_create, void *, callback_fn, void *, callback_arg,
u32, flags)
{
struct bpf_timer_list *t;
unsigned long irq_flags;
int ret;

t = kmalloc(sizeof(*t), GFP_ATOMIC);
if (!t)
return -ENOMEM;
timer_setup(&t->timer, bpf_timer_callback, flags); // XXX: translate flags
t->callback = callback_fn;
t->arg = callback_arg;

spin_lock_irqsave(&idr_lock, irq_flags);
ret = idr_alloc_cyclic(&timer_idr, t, 0, INT_MAX, GFP_ATOMIC);
spin_unlock_irqrestore(&idr_lock, irq_flags);
if (ret < 0)
kfree(t);
return ret;
}

const struct bpf_func_proto bpf_timer_create_proto = {
.func = bpf_timer_create,
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_FUNC,
.arg2_type = ARG_PTR_TO_MEM_OR_NULL,
.arg3_type = ARG_ANYTHING,
};

notrace BPF_CALL_2(bpf_timer_gettime, s32, timer_id, u64 *, expires)
{
struct bpf_timer_list *t;
int ret = 0;

rcu_read_lock();
t = idr_find(&bpf_timer_idr, timer_id);
if (t)
*expires = t->timer.expires;
else
ret = -ENOENT;
rcu_read_unlock();
return ret;
}

const struct bpf_func_proto bpf_timer_gettime_proto = {
.func = bpf_timer_gettime,
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_ANYTHING,
.arg1_type = ARG_PTR_TO_LONG,
};

notrace BPF_CALL_2(bpf_timer_settime, s32, timer_id, u64, expires)
{
struct bpf_timer_list *t;
int ret = -ENOENT;

rcu_read_lock();
t = idr_find(&bpf_timer_idr, timer_id);
if (t)
ret = mod_timer(&t->timer, expires);
rcu_read_unlock();
return ret;
}

const struct bpf_func_proto bpf_timer_settime_proto = {
.func = bpf_timer_settime,
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_ANYTHING,
.arg2_type = ARG_ANYTHING,
};

notrace BPF_CALL_1(bpf_timer_delete, s32, timer_id)
{
struct bpf_timer_list *t;
int ret;

spin_lock_irqsave(&idr_lock, irq_flags);
t = idr_remove(&bpf_timer_idr, timer_id);
spin_unlock_irqrestore(&idr_lock, irq_flags);
if (!t)
return -ENOENT;
ret = del_timer_sync(&t->timer);
kfree_rcu(t, rcu);
return ret;
}

const struct bpf_func_proto bpf_timer_delete_proto = {
.func = bpf_timer_delete,
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_ANYTHING,
};

const struct bpf_func_proto bpf_get_current_task_proto __weak;
const struct bpf_func_proto bpf_probe_read_user_proto __weak;
const struct bpf_func_proto bpf_probe_read_user_str_proto __weak;
@@ -728,6 +844,14 @@ bpf_base_func_proto(enum bpf_func_id func_id)
return &bpf_per_cpu_ptr_proto;
case BPF_FUNC_this_cpu_ptr:
return &bpf_this_cpu_ptr_proto;
case BPF_FUNC_timer_create:
return &bpf_timer_create_proto;
case BPF_FUNC_timer_gettime:
return &bpf_timer_gettime_proto;
case BPF_FUNC_timer_settime:
return &bpf_timer_settime_proto;
case BPF_FUNC_timer_delete:
return &bpf_timer_delete_proto;
default:
break;
}
@@ -489,7 +489,8 @@ static bool is_release_function(enum bpf_func_id func_id)
{
return func_id == BPF_FUNC_sk_release ||
func_id == BPF_FUNC_ringbuf_submit ||
func_id == BPF_FUNC_ringbuf_discard;
func_id == BPF_FUNC_ringbuf_discard ||
func_id == BPF_FUNC_timer_delete;
}

static bool may_be_acquire_function(enum bpf_func_id func_id)
@@ -498,7 +499,8 @@ static bool may_be_acquire_function(enum bpf_func_id func_id)
func_id == BPF_FUNC_sk_lookup_udp ||
func_id == BPF_FUNC_skc_lookup_tcp ||
func_id == BPF_FUNC_map_lookup_elem ||
func_id == BPF_FUNC_ringbuf_reserve;
func_id == BPF_FUNC_ringbuf_reserve ||
func_id == BPF_FUNC_timer_create;
}

static bool is_acquire_function(enum bpf_func_id func_id,
@@ -509,7 +511,8 @@ static bool is_acquire_function(enum bpf_func_id func_id,
if (func_id == BPF_FUNC_sk_lookup_tcp ||
func_id == BPF_FUNC_sk_lookup_udp ||
func_id == BPF_FUNC_skc_lookup_tcp ||
func_id == BPF_FUNC_ringbuf_reserve)
func_id == BPF_FUNC_ringbuf_reserve ||
func_id == BPF_FUNC_timer_create)
return true;

if (func_id == BPF_FUNC_map_lookup_elem &&

0 comments on commit 7824504

Please sign in to comment.