Thread (35 messages) 35 messages, 9 authors, 2021-06-02

Re: [RFC PATCH bpf-next] bpf: Introduce bpf_timer

flat view

From: Andrii Nakryiko <hidden>
Date: 2021-05-24 19:13:30
Also in: bpf

On Mon, May 24, 2021 at 7:56 AM Alexei Starovoitov
[off-list ref] wrote:
On Mon, May 24, 2021 at 4:50 AM Lorenz Bauer [off-list ref] wrote:
quoted
On Thu, 20 May 2021 at 19:55, Alexei Starovoitov
[off-list ref] wrote:
quoted
From: Alexei Starovoitov <ast@kernel.org>

Introduce 'struct bpf_timer' that can be embedded in most BPF map types
and helpers to operate on it:
long bpf_timer_init(struct bpf_timer *timer, void *callback, int flags)
long bpf_timer_mod(struct bpf_timer *timer, u64 msecs)
long bpf_timer_del(struct bpf_timer *timer)
I like invoking the callback with a pointer to the map element it was
defined in, since it solves lifetime of the context and user space
introspection of the same. I'm not so sure about being able to put it
into all different kinds of maps, is that really going to be used?
Certainly. At least in array and hash maps.
The global data is an array.
A single global timer is a simple and easy to use pattern.
quoted
It would be useful if Cong Wang could describe their use case, it's
kind of hard to tell what the end goal is. Should user space be able
to create and arm timers? Or just BPF? In the other thread it seems
like a primitive for waiting on a timer is proposed. Why? It also begs
the question how we would wait on multiple timers.
In the proposed api the same callback can be invoked for multiple timers.
The user space can create/destroy timers via prog_run cmd.
It will also destroy timers by map_delete_elem cmd.
quoted
quoted
+ *
+ * long bpf_timer_init(struct bpf_timer *timer, void *callback, int flags)
In your selftest the callback has a type (int)(*callback)(struct
bpf_map *map, int *key, struct map_elem *val).
Correct. I'll update the comment.
quoted
quoted
+ *     Description
+ *             Initialize the timer to call given static function.
+ *     Return
+ *             zero
+ *
+ * long bpf_timer_mod(struct bpf_timer *timer, u64 msecs)
+ *     Description
+ *             Set the timer expiration N msecs from the current time.
+ *     Return
+ *             zero
+ *
+ * long bpf_timer_del(struct bpf_timer *timer)
+ *     Description
+ *             Deactivate the timer.
+ *     Return
+ *             zero
  */
 #define __BPF_FUNC_MAPPER(FN)          \
        FN(unspec),                     \
@@ -4932,6 +4950,9 @@ union bpf_attr {
        FN(sys_bpf),                    \
        FN(btf_find_by_name_kind),      \
        FN(sys_close),                  \
+       FN(timer_init),                 \
+       FN(timer_mod),                  \
+       FN(timer_del),                  \
        /* */
How can user space force stopping of timers (required IMO)?
We can add new commands, of course, but I don't think it's
necessary, since test_run can be used to achieve the same
and map_delete_elem will stop them too.
I second the use of BPF_PROG_TEST_RUN (a.k.a. BPF_PROG_RUN now) to
"mirror" such APIs to user-space. We have so much BPF-side
functionality and APIs that reflecting all of that with special
user-space-facing BPF commands is becoming quite impractical. E.g., a
long time ago there was a proposal to add commands to push data to BPF
ringbuf from user-space for all kinds of testing scenarios. We never
did that because no one bothered enough, but now I'd advocate that a
small custom BPF program that is single-shot through BPF_PROG_RUN is a
better way to do this. Similarly for timers and whatever other
functionality. By doing everything from BPF program we also side-step
potential subtle differences in semantics between BPF-side and
user-space-side.

We just need to remember to enable all such functionality to
BPF_PROG_TYPE_SYSCALL as it's sleepable and always runs from user
context, so is most powerful in terms of what's safe to do through
such program type. And, of course, ideally for other types of programs
where it makes sense.

quoted
quoted
 /* integer value in 'imm' field of BPF_CALL instruction selects which helper
@@ -6038,6 +6059,10 @@ struct bpf_spin_lock {
        __u32   val;
 };

+struct bpf_timer {
+       __u64 opaque;
+};
+
This might be clear already, but we won't be able to modify the size
of bpf_timer later since it would break uapi, right?
Correct. The internal implementation can change. The 'opaque'
is just the pointer to the internal struct.
When do you think we'd need to change this uapi struct?
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help