1*dbf6806dSKumar Kartikeya Dwivedi // SPDX-License-Identifier: GPL-2.0
2*dbf6806dSKumar Kartikeya Dwivedi
3*dbf6806dSKumar Kartikeya Dwivedi #include <vmlinux.h>
4*dbf6806dSKumar Kartikeya Dwivedi #include <errno.h>
5*dbf6806dSKumar Kartikeya Dwivedi #include <bpf/bpf_helpers.h>
6*dbf6806dSKumar Kartikeya Dwivedi
7*dbf6806dSKumar Kartikeya Dwivedi #define CLOCK_MONOTONIC 1
8*dbf6806dSKumar Kartikeya Dwivedi #define TIMER_NSEC (60ULL * 1000 * 1000 * 1000)
9*dbf6806dSKumar Kartikeya Dwivedi
10*dbf6806dSKumar Kartikeya Dwivedi struct timer_value {
11*dbf6806dSKumar Kartikeya Dwivedi struct bpf_timer timer;
12*dbf6806dSKumar Kartikeya Dwivedi u64 data;
13*dbf6806dSKumar Kartikeya Dwivedi };
14*dbf6806dSKumar Kartikeya Dwivedi
15*dbf6806dSKumar Kartikeya Dwivedi struct {
16*dbf6806dSKumar Kartikeya Dwivedi __uint(type, BPF_MAP_TYPE_RHASH);
17*dbf6806dSKumar Kartikeya Dwivedi __uint(map_flags, BPF_F_NO_PREALLOC);
18*dbf6806dSKumar Kartikeya Dwivedi __uint(max_entries, 1);
19*dbf6806dSKumar Kartikeya Dwivedi __type(key, u64);
20*dbf6806dSKumar Kartikeya Dwivedi __type(value, struct timer_value);
21*dbf6806dSKumar Kartikeya Dwivedi } timer_map SEC(".maps");
22*dbf6806dSKumar Kartikeya Dwivedi
23*dbf6806dSKumar Kartikeya Dwivedi u64 armed;
24*dbf6806dSKumar Kartikeya Dwivedi u64 cancelled;
25*dbf6806dSKumar Kartikeya Dwivedi long timer_init_err;
26*dbf6806dSKumar Kartikeya Dwivedi long timer_set_callback_err;
27*dbf6806dSKumar Kartikeya Dwivedi long timer_start_err;
28*dbf6806dSKumar Kartikeya Dwivedi long timer_cancel_err;
29*dbf6806dSKumar Kartikeya Dwivedi
timer_cb(void * map,u64 * key,struct timer_value * value)30*dbf6806dSKumar Kartikeya Dwivedi static int timer_cb(void *map, u64 *key, struct timer_value *value)
31*dbf6806dSKumar Kartikeya Dwivedi {
32*dbf6806dSKumar Kartikeya Dwivedi return 0;
33*dbf6806dSKumar Kartikeya Dwivedi }
34*dbf6806dSKumar Kartikeya Dwivedi
arm_timer_cb(struct bpf_map * map,u64 * key,struct timer_value * value,void * ctx)35*dbf6806dSKumar Kartikeya Dwivedi static long arm_timer_cb(struct bpf_map *map, u64 *key,
36*dbf6806dSKumar Kartikeya Dwivedi struct timer_value *value, void *ctx)
37*dbf6806dSKumar Kartikeya Dwivedi {
38*dbf6806dSKumar Kartikeya Dwivedi u64 key_copy = *key;
39*dbf6806dSKumar Kartikeya Dwivedi long err;
40*dbf6806dSKumar Kartikeya Dwivedi
41*dbf6806dSKumar Kartikeya Dwivedi err = bpf_map_delete_elem(map, &key_copy);
42*dbf6806dSKumar Kartikeya Dwivedi if (err)
43*dbf6806dSKumar Kartikeya Dwivedi return 1;
44*dbf6806dSKumar Kartikeya Dwivedi
45*dbf6806dSKumar Kartikeya Dwivedi err = bpf_timer_init(&value->timer, map, CLOCK_MONOTONIC);
46*dbf6806dSKumar Kartikeya Dwivedi if (err) {
47*dbf6806dSKumar Kartikeya Dwivedi timer_init_err = err;
48*dbf6806dSKumar Kartikeya Dwivedi return 1;
49*dbf6806dSKumar Kartikeya Dwivedi }
50*dbf6806dSKumar Kartikeya Dwivedi
51*dbf6806dSKumar Kartikeya Dwivedi err = bpf_timer_set_callback(&value->timer, timer_cb);
52*dbf6806dSKumar Kartikeya Dwivedi if (err) {
53*dbf6806dSKumar Kartikeya Dwivedi timer_set_callback_err = err;
54*dbf6806dSKumar Kartikeya Dwivedi return 1;
55*dbf6806dSKumar Kartikeya Dwivedi }
56*dbf6806dSKumar Kartikeya Dwivedi
57*dbf6806dSKumar Kartikeya Dwivedi err = bpf_timer_start(&value->timer, TIMER_NSEC, BPF_F_TIMER_CPU_PIN);
58*dbf6806dSKumar Kartikeya Dwivedi if (err) {
59*dbf6806dSKumar Kartikeya Dwivedi timer_start_err = err;
60*dbf6806dSKumar Kartikeya Dwivedi return 1;
61*dbf6806dSKumar Kartikeya Dwivedi }
62*dbf6806dSKumar Kartikeya Dwivedi
63*dbf6806dSKumar Kartikeya Dwivedi __sync_fetch_and_add(&armed, 1);
64*dbf6806dSKumar Kartikeya Dwivedi return 1;
65*dbf6806dSKumar Kartikeya Dwivedi }
66*dbf6806dSKumar Kartikeya Dwivedi
cancel_timer_cb(struct bpf_map * map,u64 * key,struct timer_value * value,void * ctx)67*dbf6806dSKumar Kartikeya Dwivedi static long cancel_timer_cb(struct bpf_map *map, u64 *key,
68*dbf6806dSKumar Kartikeya Dwivedi struct timer_value *value, void *ctx)
69*dbf6806dSKumar Kartikeya Dwivedi {
70*dbf6806dSKumar Kartikeya Dwivedi long err;
71*dbf6806dSKumar Kartikeya Dwivedi
72*dbf6806dSKumar Kartikeya Dwivedi err = bpf_timer_cancel(&value->timer);
73*dbf6806dSKumar Kartikeya Dwivedi if (err == -EINVAL)
74*dbf6806dSKumar Kartikeya Dwivedi return 1;
75*dbf6806dSKumar Kartikeya Dwivedi if (err < 0) {
76*dbf6806dSKumar Kartikeya Dwivedi timer_cancel_err = err;
77*dbf6806dSKumar Kartikeya Dwivedi return 1;
78*dbf6806dSKumar Kartikeya Dwivedi }
79*dbf6806dSKumar Kartikeya Dwivedi
80*dbf6806dSKumar Kartikeya Dwivedi __sync_fetch_and_add(&cancelled, 1);
81*dbf6806dSKumar Kartikeya Dwivedi return 1;
82*dbf6806dSKumar Kartikeya Dwivedi }
83*dbf6806dSKumar Kartikeya Dwivedi
84*dbf6806dSKumar Kartikeya Dwivedi SEC("syscall")
arm_deleted_timer(void * ctx)85*dbf6806dSKumar Kartikeya Dwivedi int arm_deleted_timer(void *ctx)
86*dbf6806dSKumar Kartikeya Dwivedi {
87*dbf6806dSKumar Kartikeya Dwivedi bpf_for_each_map_elem(&timer_map, arm_timer_cb, NULL, 0);
88*dbf6806dSKumar Kartikeya Dwivedi return 0;
89*dbf6806dSKumar Kartikeya Dwivedi }
90*dbf6806dSKumar Kartikeya Dwivedi
91*dbf6806dSKumar Kartikeya Dwivedi SEC("syscall")
cancel_recycled_timer(void * ctx)92*dbf6806dSKumar Kartikeya Dwivedi int cancel_recycled_timer(void *ctx)
93*dbf6806dSKumar Kartikeya Dwivedi {
94*dbf6806dSKumar Kartikeya Dwivedi bpf_for_each_map_elem(&timer_map, cancel_timer_cb, NULL, 0);
95*dbf6806dSKumar Kartikeya Dwivedi return 0;
96*dbf6806dSKumar Kartikeya Dwivedi }
97*dbf6806dSKumar Kartikeya Dwivedi
98*dbf6806dSKumar Kartikeya Dwivedi char _license[] SEC("license") = "GPL";
99