13540f7c6SAlexei Starovoitov // SPDX-License-Identifier: GPL-2.0
23540f7c6SAlexei Starovoitov /* Copyright (c) 2021 Facebook */
33540f7c6SAlexei Starovoitov #include <linux/bpf.h>
43540f7c6SAlexei Starovoitov #include <time.h>
5*8e6d9ae2SMartin KaFai Lau #include <stdbool.h>
63540f7c6SAlexei Starovoitov #include <errno.h>
73540f7c6SAlexei Starovoitov #include <bpf/bpf_helpers.h>
8*8e6d9ae2SMartin KaFai Lau #include <bpf/bpf_tracing.h>
93540f7c6SAlexei Starovoitov
103540f7c6SAlexei Starovoitov char _license[] SEC("license") = "GPL";
113540f7c6SAlexei Starovoitov struct hmap_elem {
123540f7c6SAlexei Starovoitov int counter;
133540f7c6SAlexei Starovoitov struct bpf_timer timer;
143540f7c6SAlexei Starovoitov struct bpf_spin_lock lock; /* unused */
153540f7c6SAlexei Starovoitov };
163540f7c6SAlexei Starovoitov
173540f7c6SAlexei Starovoitov struct {
183540f7c6SAlexei Starovoitov __uint(type, BPF_MAP_TYPE_HASH);
193540f7c6SAlexei Starovoitov __uint(max_entries, 1000);
203540f7c6SAlexei Starovoitov __type(key, int);
213540f7c6SAlexei Starovoitov __type(value, struct hmap_elem);
223540f7c6SAlexei Starovoitov } hmap SEC(".maps");
233540f7c6SAlexei Starovoitov
243540f7c6SAlexei Starovoitov struct {
253540f7c6SAlexei Starovoitov __uint(type, BPF_MAP_TYPE_HASH);
263540f7c6SAlexei Starovoitov __uint(map_flags, BPF_F_NO_PREALLOC);
273540f7c6SAlexei Starovoitov __uint(max_entries, 1000);
283540f7c6SAlexei Starovoitov __type(key, int);
293540f7c6SAlexei Starovoitov __type(value, struct hmap_elem);
303540f7c6SAlexei Starovoitov } hmap_malloc SEC(".maps");
313540f7c6SAlexei Starovoitov
323540f7c6SAlexei Starovoitov struct elem {
333540f7c6SAlexei Starovoitov struct bpf_timer t;
343540f7c6SAlexei Starovoitov };
353540f7c6SAlexei Starovoitov
363540f7c6SAlexei Starovoitov struct {
373540f7c6SAlexei Starovoitov __uint(type, BPF_MAP_TYPE_ARRAY);
383540f7c6SAlexei Starovoitov __uint(max_entries, 2);
393540f7c6SAlexei Starovoitov __type(key, int);
403540f7c6SAlexei Starovoitov __type(value, struct elem);
413540f7c6SAlexei Starovoitov } array SEC(".maps");
423540f7c6SAlexei Starovoitov
433540f7c6SAlexei Starovoitov struct {
443540f7c6SAlexei Starovoitov __uint(type, BPF_MAP_TYPE_LRU_HASH);
453540f7c6SAlexei Starovoitov __uint(max_entries, 4);
463540f7c6SAlexei Starovoitov __type(key, int);
473540f7c6SAlexei Starovoitov __type(value, struct elem);
483540f7c6SAlexei Starovoitov } lru SEC(".maps");
493540f7c6SAlexei Starovoitov
50944459e8STero Kristo struct {
51944459e8STero Kristo __uint(type, BPF_MAP_TYPE_ARRAY);
52944459e8STero Kristo __uint(max_entries, 1);
53944459e8STero Kristo __type(key, int);
54944459e8STero Kristo __type(value, struct elem);
553f00e4a9SMartin KaFai Lau } abs_timer SEC(".maps"), soft_timer_pinned SEC(".maps"), abs_timer_pinned SEC(".maps"),
563f00e4a9SMartin KaFai Lau race_array SEC(".maps");
57944459e8STero Kristo
583540f7c6SAlexei Starovoitov __u64 bss_data;
59944459e8STero Kristo __u64 abs_data;
603540f7c6SAlexei Starovoitov __u64 err;
613540f7c6SAlexei Starovoitov __u64 ok;
623540f7c6SAlexei Starovoitov __u64 callback_check = 52;
633540f7c6SAlexei Starovoitov __u64 callback2_check = 52;
640d7ae068SDavid Vernet __u64 pinned_callback_check;
650d7ae068SDavid Vernet __s32 pinned_cpu;
663540f7c6SAlexei Starovoitov
673540f7c6SAlexei Starovoitov #define ARRAY 1
683540f7c6SAlexei Starovoitov #define HTAB 2
693540f7c6SAlexei Starovoitov #define HTAB_MALLOC 3
703540f7c6SAlexei Starovoitov #define LRU 4
713540f7c6SAlexei Starovoitov
723540f7c6SAlexei Starovoitov /* callback for array and lru timers */
timer_cb1(void * map,int * key,struct bpf_timer * timer)733540f7c6SAlexei Starovoitov static int timer_cb1(void *map, int *key, struct bpf_timer *timer)
743540f7c6SAlexei Starovoitov {
753540f7c6SAlexei Starovoitov /* increment bss variable twice.
763540f7c6SAlexei Starovoitov * Once via array timer callback and once via lru timer callback
773540f7c6SAlexei Starovoitov */
783540f7c6SAlexei Starovoitov bss_data += 5;
793540f7c6SAlexei Starovoitov
803540f7c6SAlexei Starovoitov /* *key == 0 - the callback was called for array timer.
813540f7c6SAlexei Starovoitov * *key == 4 - the callback was called from lru timer.
823540f7c6SAlexei Starovoitov */
833540f7c6SAlexei Starovoitov if (*key == ARRAY) {
843540f7c6SAlexei Starovoitov struct bpf_timer *lru_timer;
853540f7c6SAlexei Starovoitov int lru_key = LRU;
863540f7c6SAlexei Starovoitov
873540f7c6SAlexei Starovoitov /* rearm array timer to be called again in ~35 seconds */
883540f7c6SAlexei Starovoitov if (bpf_timer_start(timer, 1ull << 35, 0) != 0)
893540f7c6SAlexei Starovoitov err |= 1;
903540f7c6SAlexei Starovoitov
913540f7c6SAlexei Starovoitov lru_timer = bpf_map_lookup_elem(&lru, &lru_key);
923540f7c6SAlexei Starovoitov if (!lru_timer)
933540f7c6SAlexei Starovoitov return 0;
943540f7c6SAlexei Starovoitov bpf_timer_set_callback(lru_timer, timer_cb1);
953540f7c6SAlexei Starovoitov if (bpf_timer_start(lru_timer, 0, 0) != 0)
963540f7c6SAlexei Starovoitov err |= 2;
973540f7c6SAlexei Starovoitov } else if (*key == LRU) {
983540f7c6SAlexei Starovoitov int lru_key, i;
993540f7c6SAlexei Starovoitov
1003540f7c6SAlexei Starovoitov for (i = LRU + 1;
1013540f7c6SAlexei Starovoitov i <= 100 /* for current LRU eviction algorithm this number
1023540f7c6SAlexei Starovoitov * should be larger than ~ lru->max_entries * 2
1033540f7c6SAlexei Starovoitov */;
1043540f7c6SAlexei Starovoitov i++) {
1053540f7c6SAlexei Starovoitov struct elem init = {};
1063540f7c6SAlexei Starovoitov
1073540f7c6SAlexei Starovoitov /* lru_key cannot be used as loop induction variable
1083540f7c6SAlexei Starovoitov * otherwise the loop will be unbounded.
1093540f7c6SAlexei Starovoitov */
1103540f7c6SAlexei Starovoitov lru_key = i;
1113540f7c6SAlexei Starovoitov
1123540f7c6SAlexei Starovoitov /* add more elements into lru map to push out current
1133540f7c6SAlexei Starovoitov * element and force deletion of this timer
1143540f7c6SAlexei Starovoitov */
1153540f7c6SAlexei Starovoitov bpf_map_update_elem(map, &lru_key, &init, 0);
1163540f7c6SAlexei Starovoitov /* look it up to bump it into active list */
1173540f7c6SAlexei Starovoitov bpf_map_lookup_elem(map, &lru_key);
1183540f7c6SAlexei Starovoitov
1193540f7c6SAlexei Starovoitov /* keep adding until *key changes underneath,
1203540f7c6SAlexei Starovoitov * which means that key/timer memory was reused
1213540f7c6SAlexei Starovoitov */
1223540f7c6SAlexei Starovoitov if (*key != LRU)
1233540f7c6SAlexei Starovoitov break;
1243540f7c6SAlexei Starovoitov }
1253540f7c6SAlexei Starovoitov
1263540f7c6SAlexei Starovoitov /* check that the timer was removed */
1273540f7c6SAlexei Starovoitov if (bpf_timer_cancel(timer) != -EINVAL)
1283540f7c6SAlexei Starovoitov err |= 4;
1293540f7c6SAlexei Starovoitov ok |= 1;
1303540f7c6SAlexei Starovoitov }
1313540f7c6SAlexei Starovoitov return 0;
1323540f7c6SAlexei Starovoitov }
1333540f7c6SAlexei Starovoitov
1343540f7c6SAlexei Starovoitov SEC("fentry/bpf_fentry_test1")
BPF_PROG2(test1,int,a)135a7c2ca3aSYonghong Song int BPF_PROG2(test1, int, a)
1363540f7c6SAlexei Starovoitov {
1373540f7c6SAlexei Starovoitov struct bpf_timer *arr_timer, *lru_timer;
1383540f7c6SAlexei Starovoitov struct elem init = {};
1393540f7c6SAlexei Starovoitov int lru_key = LRU;
1403540f7c6SAlexei Starovoitov int array_key = ARRAY;
1413540f7c6SAlexei Starovoitov
1423540f7c6SAlexei Starovoitov arr_timer = bpf_map_lookup_elem(&array, &array_key);
1433540f7c6SAlexei Starovoitov if (!arr_timer)
1443540f7c6SAlexei Starovoitov return 0;
1453540f7c6SAlexei Starovoitov bpf_timer_init(arr_timer, &array, CLOCK_MONOTONIC);
1463540f7c6SAlexei Starovoitov
1473540f7c6SAlexei Starovoitov bpf_map_update_elem(&lru, &lru_key, &init, 0);
1483540f7c6SAlexei Starovoitov lru_timer = bpf_map_lookup_elem(&lru, &lru_key);
1493540f7c6SAlexei Starovoitov if (!lru_timer)
1503540f7c6SAlexei Starovoitov return 0;
1513540f7c6SAlexei Starovoitov bpf_timer_init(lru_timer, &lru, CLOCK_MONOTONIC);
1523540f7c6SAlexei Starovoitov
1533540f7c6SAlexei Starovoitov bpf_timer_set_callback(arr_timer, timer_cb1);
1543540f7c6SAlexei Starovoitov bpf_timer_start(arr_timer, 0 /* call timer_cb1 asap */, 0);
1553540f7c6SAlexei Starovoitov
1563540f7c6SAlexei Starovoitov /* init more timers to check that array destruction
1573540f7c6SAlexei Starovoitov * doesn't leak timer memory.
1583540f7c6SAlexei Starovoitov */
1593540f7c6SAlexei Starovoitov array_key = 0;
1603540f7c6SAlexei Starovoitov arr_timer = bpf_map_lookup_elem(&array, &array_key);
1613540f7c6SAlexei Starovoitov if (!arr_timer)
1623540f7c6SAlexei Starovoitov return 0;
1633540f7c6SAlexei Starovoitov bpf_timer_init(arr_timer, &array, CLOCK_MONOTONIC);
1643540f7c6SAlexei Starovoitov return 0;
1653540f7c6SAlexei Starovoitov }
1663540f7c6SAlexei Starovoitov
1673540f7c6SAlexei Starovoitov /* callback for prealloc and non-prealloca hashtab timers */
timer_cb2(void * map,int * key,struct hmap_elem * val)1683540f7c6SAlexei Starovoitov static int timer_cb2(void *map, int *key, struct hmap_elem *val)
1693540f7c6SAlexei Starovoitov {
1703540f7c6SAlexei Starovoitov if (*key == HTAB)
1713540f7c6SAlexei Starovoitov callback_check--;
1723540f7c6SAlexei Starovoitov else
1733540f7c6SAlexei Starovoitov callback2_check--;
1743540f7c6SAlexei Starovoitov if (val->counter > 0 && --val->counter) {
1753540f7c6SAlexei Starovoitov /* re-arm the timer again to execute after 1 usec */
1763540f7c6SAlexei Starovoitov bpf_timer_start(&val->timer, 1000, 0);
1773540f7c6SAlexei Starovoitov } else if (*key == HTAB) {
1783540f7c6SAlexei Starovoitov struct bpf_timer *arr_timer;
1793540f7c6SAlexei Starovoitov int array_key = ARRAY;
1803540f7c6SAlexei Starovoitov
1813540f7c6SAlexei Starovoitov /* cancel arr_timer otherwise bpf_fentry_test1 prog
1823540f7c6SAlexei Starovoitov * will stay alive forever.
1833540f7c6SAlexei Starovoitov */
1843540f7c6SAlexei Starovoitov arr_timer = bpf_map_lookup_elem(&array, &array_key);
1853540f7c6SAlexei Starovoitov if (!arr_timer)
1863540f7c6SAlexei Starovoitov return 0;
1873540f7c6SAlexei Starovoitov if (bpf_timer_cancel(arr_timer) != 1)
1883540f7c6SAlexei Starovoitov /* bpf_timer_cancel should return 1 to indicate
1893540f7c6SAlexei Starovoitov * that arr_timer was active at this time
1903540f7c6SAlexei Starovoitov */
1913540f7c6SAlexei Starovoitov err |= 8;
1923540f7c6SAlexei Starovoitov
1933540f7c6SAlexei Starovoitov /* try to cancel ourself. It shouldn't deadlock. */
1943540f7c6SAlexei Starovoitov if (bpf_timer_cancel(&val->timer) != -EDEADLK)
1953540f7c6SAlexei Starovoitov err |= 16;
1963540f7c6SAlexei Starovoitov
1973540f7c6SAlexei Starovoitov /* delete this key and this timer anyway.
1983540f7c6SAlexei Starovoitov * It shouldn't deadlock either.
1993540f7c6SAlexei Starovoitov */
2003540f7c6SAlexei Starovoitov bpf_map_delete_elem(map, key);
2013540f7c6SAlexei Starovoitov
2023540f7c6SAlexei Starovoitov /* in preallocated hashmap both 'key' and 'val' could have been
2033540f7c6SAlexei Starovoitov * reused to store another map element (like in LRU above),
2043540f7c6SAlexei Starovoitov * but in controlled test environment the below test works.
2053540f7c6SAlexei Starovoitov * It's not a use-after-free. The memory is owned by the map.
2063540f7c6SAlexei Starovoitov */
2073540f7c6SAlexei Starovoitov if (bpf_timer_start(&val->timer, 1000, 0) != -EINVAL)
2083540f7c6SAlexei Starovoitov err |= 32;
2093540f7c6SAlexei Starovoitov ok |= 2;
2103540f7c6SAlexei Starovoitov } else {
2113540f7c6SAlexei Starovoitov if (*key != HTAB_MALLOC)
2123540f7c6SAlexei Starovoitov err |= 64;
2133540f7c6SAlexei Starovoitov
2143540f7c6SAlexei Starovoitov /* try to cancel ourself. It shouldn't deadlock. */
2153540f7c6SAlexei Starovoitov if (bpf_timer_cancel(&val->timer) != -EDEADLK)
2163540f7c6SAlexei Starovoitov err |= 128;
2173540f7c6SAlexei Starovoitov
2183540f7c6SAlexei Starovoitov /* delete this key and this timer anyway.
2193540f7c6SAlexei Starovoitov * It shouldn't deadlock either.
2203540f7c6SAlexei Starovoitov */
2213540f7c6SAlexei Starovoitov bpf_map_delete_elem(map, key);
2223540f7c6SAlexei Starovoitov
2233540f7c6SAlexei Starovoitov ok |= 4;
2243540f7c6SAlexei Starovoitov }
2253540f7c6SAlexei Starovoitov return 0;
2263540f7c6SAlexei Starovoitov }
2273540f7c6SAlexei Starovoitov
bpf_timer_test(void)2283540f7c6SAlexei Starovoitov int bpf_timer_test(void)
2293540f7c6SAlexei Starovoitov {
2303540f7c6SAlexei Starovoitov struct hmap_elem *val;
2313540f7c6SAlexei Starovoitov int key = HTAB, key_malloc = HTAB_MALLOC;
2323540f7c6SAlexei Starovoitov
2333540f7c6SAlexei Starovoitov val = bpf_map_lookup_elem(&hmap, &key);
2343540f7c6SAlexei Starovoitov if (val) {
2353540f7c6SAlexei Starovoitov if (bpf_timer_init(&val->timer, &hmap, CLOCK_BOOTTIME) != 0)
2363540f7c6SAlexei Starovoitov err |= 512;
2373540f7c6SAlexei Starovoitov bpf_timer_set_callback(&val->timer, timer_cb2);
2383540f7c6SAlexei Starovoitov bpf_timer_start(&val->timer, 1000, 0);
2393540f7c6SAlexei Starovoitov }
2403540f7c6SAlexei Starovoitov val = bpf_map_lookup_elem(&hmap_malloc, &key_malloc);
2413540f7c6SAlexei Starovoitov if (val) {
2423540f7c6SAlexei Starovoitov if (bpf_timer_init(&val->timer, &hmap_malloc, CLOCK_BOOTTIME) != 0)
2433540f7c6SAlexei Starovoitov err |= 1024;
2443540f7c6SAlexei Starovoitov bpf_timer_set_callback(&val->timer, timer_cb2);
2453540f7c6SAlexei Starovoitov bpf_timer_start(&val->timer, 1000, 0);
2463540f7c6SAlexei Starovoitov }
2473540f7c6SAlexei Starovoitov return 0;
2483540f7c6SAlexei Starovoitov }
2493540f7c6SAlexei Starovoitov
2503540f7c6SAlexei Starovoitov SEC("fentry/bpf_fentry_test2")
BPF_PROG2(test2,int,a,int,b)251a7c2ca3aSYonghong Song int BPF_PROG2(test2, int, a, int, b)
2523540f7c6SAlexei Starovoitov {
2533540f7c6SAlexei Starovoitov struct hmap_elem init = {}, *val;
2543540f7c6SAlexei Starovoitov int key = HTAB, key_malloc = HTAB_MALLOC;
2553540f7c6SAlexei Starovoitov
2563540f7c6SAlexei Starovoitov init.counter = 10; /* number of times to trigger timer_cb2 */
2573540f7c6SAlexei Starovoitov bpf_map_update_elem(&hmap, &key, &init, 0);
2583540f7c6SAlexei Starovoitov val = bpf_map_lookup_elem(&hmap, &key);
2593540f7c6SAlexei Starovoitov if (val)
2603540f7c6SAlexei Starovoitov bpf_timer_init(&val->timer, &hmap, CLOCK_BOOTTIME);
2613540f7c6SAlexei Starovoitov /* update the same key to free the timer */
2623540f7c6SAlexei Starovoitov bpf_map_update_elem(&hmap, &key, &init, 0);
2633540f7c6SAlexei Starovoitov
2643540f7c6SAlexei Starovoitov bpf_map_update_elem(&hmap_malloc, &key_malloc, &init, 0);
2653540f7c6SAlexei Starovoitov val = bpf_map_lookup_elem(&hmap_malloc, &key_malloc);
2663540f7c6SAlexei Starovoitov if (val)
2673540f7c6SAlexei Starovoitov bpf_timer_init(&val->timer, &hmap_malloc, CLOCK_BOOTTIME);
2683540f7c6SAlexei Starovoitov /* update the same key to free the timer */
2693540f7c6SAlexei Starovoitov bpf_map_update_elem(&hmap_malloc, &key_malloc, &init, 0);
2703540f7c6SAlexei Starovoitov
2713540f7c6SAlexei Starovoitov /* init more timers to check that htab operations
2723540f7c6SAlexei Starovoitov * don't leak timer memory.
2733540f7c6SAlexei Starovoitov */
2743540f7c6SAlexei Starovoitov key = 0;
2753540f7c6SAlexei Starovoitov bpf_map_update_elem(&hmap, &key, &init, 0);
2763540f7c6SAlexei Starovoitov val = bpf_map_lookup_elem(&hmap, &key);
2773540f7c6SAlexei Starovoitov if (val)
2783540f7c6SAlexei Starovoitov bpf_timer_init(&val->timer, &hmap, CLOCK_BOOTTIME);
2793540f7c6SAlexei Starovoitov bpf_map_delete_elem(&hmap, &key);
2803540f7c6SAlexei Starovoitov bpf_map_update_elem(&hmap, &key, &init, 0);
2813540f7c6SAlexei Starovoitov val = bpf_map_lookup_elem(&hmap, &key);
2823540f7c6SAlexei Starovoitov if (val)
2833540f7c6SAlexei Starovoitov bpf_timer_init(&val->timer, &hmap, CLOCK_BOOTTIME);
2843540f7c6SAlexei Starovoitov
2853540f7c6SAlexei Starovoitov /* and with non-prealloc htab */
2863540f7c6SAlexei Starovoitov key_malloc = 0;
2873540f7c6SAlexei Starovoitov bpf_map_update_elem(&hmap_malloc, &key_malloc, &init, 0);
2883540f7c6SAlexei Starovoitov val = bpf_map_lookup_elem(&hmap_malloc, &key_malloc);
2893540f7c6SAlexei Starovoitov if (val)
2903540f7c6SAlexei Starovoitov bpf_timer_init(&val->timer, &hmap_malloc, CLOCK_BOOTTIME);
2913540f7c6SAlexei Starovoitov bpf_map_delete_elem(&hmap_malloc, &key_malloc);
2923540f7c6SAlexei Starovoitov bpf_map_update_elem(&hmap_malloc, &key_malloc, &init, 0);
2933540f7c6SAlexei Starovoitov val = bpf_map_lookup_elem(&hmap_malloc, &key_malloc);
2943540f7c6SAlexei Starovoitov if (val)
2953540f7c6SAlexei Starovoitov bpf_timer_init(&val->timer, &hmap_malloc, CLOCK_BOOTTIME);
2963540f7c6SAlexei Starovoitov
2973540f7c6SAlexei Starovoitov return bpf_timer_test();
2983540f7c6SAlexei Starovoitov }
299944459e8STero Kristo
300944459e8STero Kristo /* callback for absolute timer */
timer_cb3(void * map,int * key,struct bpf_timer * timer)301944459e8STero Kristo static int timer_cb3(void *map, int *key, struct bpf_timer *timer)
302944459e8STero Kristo {
303944459e8STero Kristo abs_data += 6;
304944459e8STero Kristo
305944459e8STero Kristo if (abs_data < 12) {
306944459e8STero Kristo bpf_timer_start(timer, bpf_ktime_get_boot_ns() + 1000,
307944459e8STero Kristo BPF_F_TIMER_ABS);
308944459e8STero Kristo } else {
309944459e8STero Kristo /* Re-arm timer ~35 seconds in future */
310944459e8STero Kristo bpf_timer_start(timer, bpf_ktime_get_boot_ns() + (1ull << 35),
311944459e8STero Kristo BPF_F_TIMER_ABS);
312944459e8STero Kristo }
313944459e8STero Kristo
314944459e8STero Kristo return 0;
315944459e8STero Kristo }
316944459e8STero Kristo
317944459e8STero Kristo SEC("fentry/bpf_fentry_test3")
BPF_PROG2(test3,int,a)318944459e8STero Kristo int BPF_PROG2(test3, int, a)
319944459e8STero Kristo {
320944459e8STero Kristo int key = 0;
321944459e8STero Kristo struct bpf_timer *timer;
322944459e8STero Kristo
323944459e8STero Kristo bpf_printk("test3");
324944459e8STero Kristo
325944459e8STero Kristo timer = bpf_map_lookup_elem(&abs_timer, &key);
326944459e8STero Kristo if (timer) {
327944459e8STero Kristo if (bpf_timer_init(timer, &abs_timer, CLOCK_BOOTTIME) != 0)
328944459e8STero Kristo err |= 2048;
329944459e8STero Kristo bpf_timer_set_callback(timer, timer_cb3);
330944459e8STero Kristo bpf_timer_start(timer, bpf_ktime_get_boot_ns() + 1000,
331944459e8STero Kristo BPF_F_TIMER_ABS);
332944459e8STero Kristo }
333944459e8STero Kristo
334944459e8STero Kristo return 0;
335944459e8STero Kristo }
3360d7ae068SDavid Vernet
3370d7ae068SDavid Vernet /* callback for pinned timer */
timer_cb_pinned(void * map,int * key,struct bpf_timer * timer)3380d7ae068SDavid Vernet static int timer_cb_pinned(void *map, int *key, struct bpf_timer *timer)
3390d7ae068SDavid Vernet {
3400d7ae068SDavid Vernet __s32 cpu = bpf_get_smp_processor_id();
3410d7ae068SDavid Vernet
3420d7ae068SDavid Vernet if (cpu != pinned_cpu)
3430d7ae068SDavid Vernet err |= 16384;
3440d7ae068SDavid Vernet
3450d7ae068SDavid Vernet pinned_callback_check++;
3460d7ae068SDavid Vernet return 0;
3470d7ae068SDavid Vernet }
3480d7ae068SDavid Vernet
test_pinned_timer(bool soft)3490d7ae068SDavid Vernet static void test_pinned_timer(bool soft)
3500d7ae068SDavid Vernet {
3510d7ae068SDavid Vernet int key = 0;
3520d7ae068SDavid Vernet void *map;
3530d7ae068SDavid Vernet struct bpf_timer *timer;
3540d7ae068SDavid Vernet __u64 flags = BPF_F_TIMER_CPU_PIN;
3550d7ae068SDavid Vernet __u64 start_time;
3560d7ae068SDavid Vernet
3570d7ae068SDavid Vernet if (soft) {
3580d7ae068SDavid Vernet map = &soft_timer_pinned;
3590d7ae068SDavid Vernet start_time = 0;
3600d7ae068SDavid Vernet } else {
3610d7ae068SDavid Vernet map = &abs_timer_pinned;
3620d7ae068SDavid Vernet start_time = bpf_ktime_get_boot_ns();
3630d7ae068SDavid Vernet flags |= BPF_F_TIMER_ABS;
3640d7ae068SDavid Vernet }
3650d7ae068SDavid Vernet
3660d7ae068SDavid Vernet timer = bpf_map_lookup_elem(map, &key);
3670d7ae068SDavid Vernet if (timer) {
3680d7ae068SDavid Vernet if (bpf_timer_init(timer, map, CLOCK_BOOTTIME) != 0)
3690d7ae068SDavid Vernet err |= 4096;
3700d7ae068SDavid Vernet bpf_timer_set_callback(timer, timer_cb_pinned);
3710d7ae068SDavid Vernet pinned_cpu = bpf_get_smp_processor_id();
3720d7ae068SDavid Vernet bpf_timer_start(timer, start_time + 1000, flags);
3730d7ae068SDavid Vernet } else {
3740d7ae068SDavid Vernet err |= 8192;
3750d7ae068SDavid Vernet }
3760d7ae068SDavid Vernet }
3770d7ae068SDavid Vernet
3780d7ae068SDavid Vernet SEC("fentry/bpf_fentry_test4")
BPF_PROG2(test4,int,a)3790d7ae068SDavid Vernet int BPF_PROG2(test4, int, a)
3800d7ae068SDavid Vernet {
3810d7ae068SDavid Vernet bpf_printk("test4");
3820d7ae068SDavid Vernet test_pinned_timer(true);
3830d7ae068SDavid Vernet
3840d7ae068SDavid Vernet return 0;
3850d7ae068SDavid Vernet }
3860d7ae068SDavid Vernet
3870d7ae068SDavid Vernet SEC("fentry/bpf_fentry_test5")
BPF_PROG2(test5,int,a)3880d7ae068SDavid Vernet int BPF_PROG2(test5, int, a)
3890d7ae068SDavid Vernet {
3900d7ae068SDavid Vernet bpf_printk("test5");
3910d7ae068SDavid Vernet test_pinned_timer(false);
3920d7ae068SDavid Vernet
3930d7ae068SDavid Vernet return 0;
3940d7ae068SDavid Vernet }
3953f00e4a9SMartin KaFai Lau
race_timer_callback(void * race_array,int * race_key,struct bpf_timer * timer)3963f00e4a9SMartin KaFai Lau static int race_timer_callback(void *race_array, int *race_key, struct bpf_timer *timer)
3973f00e4a9SMartin KaFai Lau {
3983f00e4a9SMartin KaFai Lau bpf_timer_start(timer, 1000000, 0);
3993f00e4a9SMartin KaFai Lau return 0;
4003f00e4a9SMartin KaFai Lau }
4013f00e4a9SMartin KaFai Lau
4023f00e4a9SMartin KaFai Lau SEC("syscall")
race(void * ctx)4033f00e4a9SMartin KaFai Lau int race(void *ctx)
4043f00e4a9SMartin KaFai Lau {
4053f00e4a9SMartin KaFai Lau struct bpf_timer *timer;
4063f00e4a9SMartin KaFai Lau int err, race_key = 0;
4073f00e4a9SMartin KaFai Lau struct elem init;
4083f00e4a9SMartin KaFai Lau
4093f00e4a9SMartin KaFai Lau __builtin_memset(&init, 0, sizeof(struct elem));
4103f00e4a9SMartin KaFai Lau bpf_map_update_elem(&race_array, &race_key, &init, BPF_ANY);
4113f00e4a9SMartin KaFai Lau
4123f00e4a9SMartin KaFai Lau timer = bpf_map_lookup_elem(&race_array, &race_key);
4133f00e4a9SMartin KaFai Lau if (!timer)
4143f00e4a9SMartin KaFai Lau return 1;
4153f00e4a9SMartin KaFai Lau
4163f00e4a9SMartin KaFai Lau err = bpf_timer_init(timer, &race_array, CLOCK_MONOTONIC);
4173f00e4a9SMartin KaFai Lau if (err && err != -EBUSY)
4183f00e4a9SMartin KaFai Lau return 1;
4193f00e4a9SMartin KaFai Lau
4203f00e4a9SMartin KaFai Lau bpf_timer_set_callback(timer, race_timer_callback);
4213f00e4a9SMartin KaFai Lau bpf_timer_start(timer, 0, 0);
4223f00e4a9SMartin KaFai Lau bpf_timer_cancel(timer);
4233f00e4a9SMartin KaFai Lau
4243f00e4a9SMartin KaFai Lau return 0;
4253f00e4a9SMartin KaFai Lau }
426