~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/bpf/progs/timer.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 /* Copyright (c) 2021 Facebook */
  3 #include <linux/bpf.h>
  4 #include <time.h>
  5 #include <stdbool.h>
  6 #include <errno.h>
  7 #include <bpf/bpf_helpers.h>
  8 #include <bpf/bpf_tracing.h>
  9 
 10 char _license[] SEC("license") = "GPL";
 11 struct hmap_elem {
 12         int counter;
 13         struct bpf_timer timer;
 14         struct bpf_spin_lock lock; /* unused */
 15 };
 16 
 17 struct {
 18         __uint(type, BPF_MAP_TYPE_HASH);
 19         __uint(max_entries, 1000);
 20         __type(key, int);
 21         __type(value, struct hmap_elem);
 22 } hmap SEC(".maps");
 23 
 24 struct {
 25         __uint(type, BPF_MAP_TYPE_HASH);
 26         __uint(map_flags, BPF_F_NO_PREALLOC);
 27         __uint(max_entries, 1000);
 28         __type(key, int);
 29         __type(value, struct hmap_elem);
 30 } hmap_malloc SEC(".maps");
 31 
 32 struct elem {
 33         struct bpf_timer t;
 34 };
 35 
 36 struct {
 37         __uint(type, BPF_MAP_TYPE_ARRAY);
 38         __uint(max_entries, 2);
 39         __type(key, int);
 40         __type(value, struct elem);
 41 } array SEC(".maps");
 42 
 43 struct {
 44         __uint(type, BPF_MAP_TYPE_LRU_HASH);
 45         __uint(max_entries, 4);
 46         __type(key, int);
 47         __type(value, struct elem);
 48 } lru SEC(".maps");
 49 
 50 struct {
 51         __uint(type, BPF_MAP_TYPE_ARRAY);
 52         __uint(max_entries, 1);
 53         __type(key, int);
 54         __type(value, struct elem);
 55 } abs_timer SEC(".maps"), soft_timer_pinned SEC(".maps"), abs_timer_pinned SEC(".maps"),
 56         race_array SEC(".maps");
 57 
 58 __u64 bss_data;
 59 __u64 abs_data;
 60 __u64 err;
 61 __u64 ok;
 62 __u64 callback_check = 52;
 63 __u64 callback2_check = 52;
 64 __u64 pinned_callback_check;
 65 __s32 pinned_cpu;
 66 
 67 #define ARRAY 1
 68 #define HTAB 2
 69 #define HTAB_MALLOC 3
 70 #define LRU 4
 71 
 72 /* callback for array and lru timers */
 73 static int timer_cb1(void *map, int *key, struct bpf_timer *timer)
 74 {
 75         /* increment bss variable twice.
 76          * Once via array timer callback and once via lru timer callback
 77          */
 78         bss_data += 5;
 79 
 80         /* *key == 0 - the callback was called for array timer.
 81          * *key == 4 - the callback was called from lru timer.
 82          */
 83         if (*key == ARRAY) {
 84                 struct bpf_timer *lru_timer;
 85                 int lru_key = LRU;
 86 
 87                 /* rearm array timer to be called again in ~35 seconds */
 88                 if (bpf_timer_start(timer, 1ull << 35, 0) != 0)
 89                         err |= 1;
 90 
 91                 lru_timer = bpf_map_lookup_elem(&lru, &lru_key);
 92                 if (!lru_timer)
 93                         return 0;
 94                 bpf_timer_set_callback(lru_timer, timer_cb1);
 95                 if (bpf_timer_start(lru_timer, 0, 0) != 0)
 96                         err |= 2;
 97         } else if (*key == LRU) {
 98                 int lru_key, i;
 99 
100                 for (i = LRU + 1;
101                      i <= 100  /* for current LRU eviction algorithm this number
102                                 * should be larger than ~ lru->max_entries * 2
103                                 */;
104                      i++) {
105                         struct elem init = {};
106 
107                         /* lru_key cannot be used as loop induction variable
108                          * otherwise the loop will be unbounded.
109                          */
110                         lru_key = i;
111 
112                         /* add more elements into lru map to push out current
113                          * element and force deletion of this timer
114                          */
115                         bpf_map_update_elem(map, &lru_key, &init, 0);
116                         /* look it up to bump it into active list */
117                         bpf_map_lookup_elem(map, &lru_key);
118 
119                         /* keep adding until *key changes underneath,
120                          * which means that key/timer memory was reused
121                          */
122                         if (*key != LRU)
123                                 break;
124                 }
125 
126                 /* check that the timer was removed */
127                 if (bpf_timer_cancel(timer) != -EINVAL)
128                         err |= 4;
129                 ok |= 1;
130         }
131         return 0;
132 }
133 
134 SEC("fentry/bpf_fentry_test1")
135 int BPF_PROG2(test1, int, a)
136 {
137         struct bpf_timer *arr_timer, *lru_timer;
138         struct elem init = {};
139         int lru_key = LRU;
140         int array_key = ARRAY;
141 
142         arr_timer = bpf_map_lookup_elem(&array, &array_key);
143         if (!arr_timer)
144                 return 0;
145         bpf_timer_init(arr_timer, &array, CLOCK_MONOTONIC);
146 
147         bpf_map_update_elem(&lru, &lru_key, &init, 0);
148         lru_timer = bpf_map_lookup_elem(&lru, &lru_key);
149         if (!lru_timer)
150                 return 0;
151         bpf_timer_init(lru_timer, &lru, CLOCK_MONOTONIC);
152 
153         bpf_timer_set_callback(arr_timer, timer_cb1);
154         bpf_timer_start(arr_timer, 0 /* call timer_cb1 asap */, 0);
155 
156         /* init more timers to check that array destruction
157          * doesn't leak timer memory.
158          */
159         array_key = 0;
160         arr_timer = bpf_map_lookup_elem(&array, &array_key);
161         if (!arr_timer)
162                 return 0;
163         bpf_timer_init(arr_timer, &array, CLOCK_MONOTONIC);
164         return 0;
165 }
166 
167 /* callback for prealloc and non-prealloca hashtab timers */
168 static int timer_cb2(void *map, int *key, struct hmap_elem *val)
169 {
170         if (*key == HTAB)
171                 callback_check--;
172         else
173                 callback2_check--;
174         if (val->counter > 0 && --val->counter) {
175                 /* re-arm the timer again to execute after 1 usec */
176                 bpf_timer_start(&val->timer, 1000, 0);
177         } else if (*key == HTAB) {
178                 struct bpf_timer *arr_timer;
179                 int array_key = ARRAY;
180 
181                 /* cancel arr_timer otherwise bpf_fentry_test1 prog
182                  * will stay alive forever.
183                  */
184                 arr_timer = bpf_map_lookup_elem(&array, &array_key);
185                 if (!arr_timer)
186                         return 0;
187                 if (bpf_timer_cancel(arr_timer) != 1)
188                         /* bpf_timer_cancel should return 1 to indicate
189                          * that arr_timer was active at this time
190                          */
191                         err |= 8;
192 
193                 /* try to cancel ourself. It shouldn't deadlock. */
194                 if (bpf_timer_cancel(&val->timer) != -EDEADLK)
195                         err |= 16;
196 
197                 /* delete this key and this timer anyway.
198                  * It shouldn't deadlock either.
199                  */
200                 bpf_map_delete_elem(map, key);
201 
202                 /* in preallocated hashmap both 'key' and 'val' could have been
203                  * reused to store another map element (like in LRU above),
204                  * but in controlled test environment the below test works.
205                  * It's not a use-after-free. The memory is owned by the map.
206                  */
207                 if (bpf_timer_start(&val->timer, 1000, 0) != -EINVAL)
208                         err |= 32;
209                 ok |= 2;
210         } else {
211                 if (*key != HTAB_MALLOC)
212                         err |= 64;
213 
214                 /* try to cancel ourself. It shouldn't deadlock. */
215                 if (bpf_timer_cancel(&val->timer) != -EDEADLK)
216                         err |= 128;
217 
218                 /* delete this key and this timer anyway.
219                  * It shouldn't deadlock either.
220                  */
221                 bpf_map_delete_elem(map, key);
222 
223                 ok |= 4;
224         }
225         return 0;
226 }
227 
228 int bpf_timer_test(void)
229 {
230         struct hmap_elem *val;
231         int key = HTAB, key_malloc = HTAB_MALLOC;
232 
233         val = bpf_map_lookup_elem(&hmap, &key);
234         if (val) {
235                 if (bpf_timer_init(&val->timer, &hmap, CLOCK_BOOTTIME) != 0)
236                         err |= 512;
237                 bpf_timer_set_callback(&val->timer, timer_cb2);
238                 bpf_timer_start(&val->timer, 1000, 0);
239         }
240         val = bpf_map_lookup_elem(&hmap_malloc, &key_malloc);
241         if (val) {
242                 if (bpf_timer_init(&val->timer, &hmap_malloc, CLOCK_BOOTTIME) != 0)
243                         err |= 1024;
244                 bpf_timer_set_callback(&val->timer, timer_cb2);
245                 bpf_timer_start(&val->timer, 1000, 0);
246         }
247         return 0;
248 }
249 
250 SEC("fentry/bpf_fentry_test2")
251 int BPF_PROG2(test2, int, a, int, b)
252 {
253         struct hmap_elem init = {}, *val;
254         int key = HTAB, key_malloc = HTAB_MALLOC;
255 
256         init.counter = 10; /* number of times to trigger timer_cb2 */
257         bpf_map_update_elem(&hmap, &key, &init, 0);
258         val = bpf_map_lookup_elem(&hmap, &key);
259         if (val)
260                 bpf_timer_init(&val->timer, &hmap, CLOCK_BOOTTIME);
261         /* update the same key to free the timer */
262         bpf_map_update_elem(&hmap, &key, &init, 0);
263 
264         bpf_map_update_elem(&hmap_malloc, &key_malloc, &init, 0);
265         val = bpf_map_lookup_elem(&hmap_malloc, &key_malloc);
266         if (val)
267                 bpf_timer_init(&val->timer, &hmap_malloc, CLOCK_BOOTTIME);
268         /* update the same key to free the timer */
269         bpf_map_update_elem(&hmap_malloc, &key_malloc, &init, 0);
270 
271         /* init more timers to check that htab operations
272          * don't leak timer memory.
273          */
274         key = 0;
275         bpf_map_update_elem(&hmap, &key, &init, 0);
276         val = bpf_map_lookup_elem(&hmap, &key);
277         if (val)
278                 bpf_timer_init(&val->timer, &hmap, CLOCK_BOOTTIME);
279         bpf_map_delete_elem(&hmap, &key);
280         bpf_map_update_elem(&hmap, &key, &init, 0);
281         val = bpf_map_lookup_elem(&hmap, &key);
282         if (val)
283                 bpf_timer_init(&val->timer, &hmap, CLOCK_BOOTTIME);
284 
285         /* and with non-prealloc htab */
286         key_malloc = 0;
287         bpf_map_update_elem(&hmap_malloc, &key_malloc, &init, 0);
288         val = bpf_map_lookup_elem(&hmap_malloc, &key_malloc);
289         if (val)
290                 bpf_timer_init(&val->timer, &hmap_malloc, CLOCK_BOOTTIME);
291         bpf_map_delete_elem(&hmap_malloc, &key_malloc);
292         bpf_map_update_elem(&hmap_malloc, &key_malloc, &init, 0);
293         val = bpf_map_lookup_elem(&hmap_malloc, &key_malloc);
294         if (val)
295                 bpf_timer_init(&val->timer, &hmap_malloc, CLOCK_BOOTTIME);
296 
297         return bpf_timer_test();
298 }
299 
300 /* callback for absolute timer */
301 static int timer_cb3(void *map, int *key, struct bpf_timer *timer)
302 {
303         abs_data += 6;
304 
305         if (abs_data < 12) {
306                 bpf_timer_start(timer, bpf_ktime_get_boot_ns() + 1000,
307                                 BPF_F_TIMER_ABS);
308         } else {
309                 /* Re-arm timer ~35 seconds in future */
310                 bpf_timer_start(timer, bpf_ktime_get_boot_ns() + (1ull << 35),
311                                 BPF_F_TIMER_ABS);
312         }
313 
314         return 0;
315 }
316 
317 SEC("fentry/bpf_fentry_test3")
318 int BPF_PROG2(test3, int, a)
319 {
320         int key = 0;
321         struct bpf_timer *timer;
322 
323         bpf_printk("test3");
324 
325         timer = bpf_map_lookup_elem(&abs_timer, &key);
326         if (timer) {
327                 if (bpf_timer_init(timer, &abs_timer, CLOCK_BOOTTIME) != 0)
328                         err |= 2048;
329                 bpf_timer_set_callback(timer, timer_cb3);
330                 bpf_timer_start(timer, bpf_ktime_get_boot_ns() + 1000,
331                                 BPF_F_TIMER_ABS);
332         }
333 
334         return 0;
335 }
336 
337 /* callback for pinned timer */
338 static int timer_cb_pinned(void *map, int *key, struct bpf_timer *timer)
339 {
340         __s32 cpu = bpf_get_smp_processor_id();
341 
342         if (cpu != pinned_cpu)
343                 err |= 16384;
344 
345         pinned_callback_check++;
346         return 0;
347 }
348 
349 static void test_pinned_timer(bool soft)
350 {
351         int key = 0;
352         void *map;
353         struct bpf_timer *timer;
354         __u64 flags = BPF_F_TIMER_CPU_PIN;
355         __u64 start_time;
356 
357         if (soft) {
358                 map = &soft_timer_pinned;
359                 start_time = 0;
360         } else {
361                 map = &abs_timer_pinned;
362                 start_time = bpf_ktime_get_boot_ns();
363                 flags |= BPF_F_TIMER_ABS;
364         }
365 
366         timer = bpf_map_lookup_elem(map, &key);
367         if (timer) {
368                 if (bpf_timer_init(timer, map, CLOCK_BOOTTIME) != 0)
369                         err |= 4096;
370                 bpf_timer_set_callback(timer, timer_cb_pinned);
371                 pinned_cpu = bpf_get_smp_processor_id();
372                 bpf_timer_start(timer, start_time + 1000, flags);
373         } else {
374                 err |= 8192;
375         }
376 }
377 
378 SEC("fentry/bpf_fentry_test4")
379 int BPF_PROG2(test4, int, a)
380 {
381         bpf_printk("test4");
382         test_pinned_timer(true);
383 
384         return 0;
385 }
386 
387 SEC("fentry/bpf_fentry_test5")
388 int BPF_PROG2(test5, int, a)
389 {
390         bpf_printk("test5");
391         test_pinned_timer(false);
392 
393         return 0;
394 }
395 
396 static int race_timer_callback(void *race_array, int *race_key, struct bpf_timer *timer)
397 {
398         bpf_timer_start(timer, 1000000, 0);
399         return 0;
400 }
401 
402 SEC("syscall")
403 int race(void *ctx)
404 {
405         struct bpf_timer *timer;
406         int err, race_key = 0;
407         struct elem init;
408 
409         __builtin_memset(&init, 0, sizeof(struct elem));
410         bpf_map_update_elem(&race_array, &race_key, &init, BPF_ANY);
411 
412         timer = bpf_map_lookup_elem(&race_array, &race_key);
413         if (!timer)
414                 return 1;
415 
416         err = bpf_timer_init(timer, &race_array, CLOCK_MONOTONIC);
417         if (err && err != -EBUSY)
418                 return 1;
419 
420         bpf_timer_set_callback(timer, race_timer_callback);
421         bpf_timer_start(timer, 0, 0);
422         bpf_timer_cancel(timer);
423 
424         return 0;
425 }
426 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php