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> 53540f7c6SAlexei Starovoitov #include <errno.h> 63540f7c6SAlexei Starovoitov #include <bpf/bpf_helpers.h> 73540f7c6SAlexei Starovoitov #include "bpf_tcp_helpers.h" 83540f7c6SAlexei Starovoitov 93540f7c6SAlexei Starovoitov char _license[] SEC("license") = "GPL"; 103540f7c6SAlexei Starovoitov struct hmap_elem { 113540f7c6SAlexei Starovoitov int counter; 123540f7c6SAlexei Starovoitov struct bpf_timer timer; 133540f7c6SAlexei Starovoitov struct bpf_spin_lock lock; /* unused */ 143540f7c6SAlexei Starovoitov }; 153540f7c6SAlexei Starovoitov 163540f7c6SAlexei Starovoitov struct { 173540f7c6SAlexei Starovoitov __uint(type, BPF_MAP_TYPE_HASH); 183540f7c6SAlexei Starovoitov __uint(max_entries, 1000); 193540f7c6SAlexei Starovoitov __type(key, int); 203540f7c6SAlexei Starovoitov __type(value, struct hmap_elem); 213540f7c6SAlexei Starovoitov } hmap SEC(".maps"); 223540f7c6SAlexei Starovoitov 233540f7c6SAlexei Starovoitov struct { 243540f7c6SAlexei Starovoitov __uint(type, BPF_MAP_TYPE_HASH); 253540f7c6SAlexei Starovoitov __uint(map_flags, BPF_F_NO_PREALLOC); 263540f7c6SAlexei Starovoitov __uint(max_entries, 1000); 273540f7c6SAlexei Starovoitov __type(key, int); 283540f7c6SAlexei Starovoitov __type(value, struct hmap_elem); 293540f7c6SAlexei Starovoitov } hmap_malloc SEC(".maps"); 303540f7c6SAlexei Starovoitov 313540f7c6SAlexei Starovoitov struct elem { 323540f7c6SAlexei Starovoitov struct bpf_timer t; 333540f7c6SAlexei Starovoitov }; 343540f7c6SAlexei Starovoitov 353540f7c6SAlexei Starovoitov struct { 363540f7c6SAlexei Starovoitov __uint(type, BPF_MAP_TYPE_ARRAY); 373540f7c6SAlexei Starovoitov __uint(max_entries, 2); 383540f7c6SAlexei Starovoitov __type(key, int); 393540f7c6SAlexei Starovoitov __type(value, struct elem); 403540f7c6SAlexei Starovoitov } array SEC(".maps"); 413540f7c6SAlexei Starovoitov 423540f7c6SAlexei Starovoitov struct { 433540f7c6SAlexei Starovoitov __uint(type, BPF_MAP_TYPE_LRU_HASH); 443540f7c6SAlexei Starovoitov __uint(max_entries, 4); 453540f7c6SAlexei Starovoitov __type(key, int); 463540f7c6SAlexei Starovoitov __type(value, struct elem); 473540f7c6SAlexei Starovoitov } lru SEC(".maps"); 483540f7c6SAlexei Starovoitov 49944459e8STero Kristo struct { 50944459e8STero Kristo __uint(type, BPF_MAP_TYPE_ARRAY); 51944459e8STero Kristo __uint(max_entries, 1); 52944459e8STero Kristo __type(key, int); 53944459e8STero Kristo __type(value, struct elem); 54*0d7ae068SDavid Vernet } abs_timer SEC(".maps"), soft_timer_pinned SEC(".maps"), abs_timer_pinned SEC(".maps"); 55944459e8STero Kristo 563540f7c6SAlexei Starovoitov __u64 bss_data; 57944459e8STero Kristo __u64 abs_data; 583540f7c6SAlexei Starovoitov __u64 err; 593540f7c6SAlexei Starovoitov __u64 ok; 603540f7c6SAlexei Starovoitov __u64 callback_check = 52; 613540f7c6SAlexei Starovoitov __u64 callback2_check = 52; 62*0d7ae068SDavid Vernet __u64 pinned_callback_check; 63*0d7ae068SDavid Vernet __s32 pinned_cpu; 643540f7c6SAlexei Starovoitov 653540f7c6SAlexei Starovoitov #define ARRAY 1 663540f7c6SAlexei Starovoitov #define HTAB 2 673540f7c6SAlexei Starovoitov #define HTAB_MALLOC 3 683540f7c6SAlexei Starovoitov #define LRU 4 693540f7c6SAlexei Starovoitov 703540f7c6SAlexei Starovoitov /* callback for array and lru timers */ 713540f7c6SAlexei Starovoitov static int timer_cb1(void *map, int *key, struct bpf_timer *timer) 723540f7c6SAlexei Starovoitov { 733540f7c6SAlexei Starovoitov /* increment bss variable twice. 743540f7c6SAlexei Starovoitov * Once via array timer callback and once via lru timer callback 753540f7c6SAlexei Starovoitov */ 763540f7c6SAlexei Starovoitov bss_data += 5; 773540f7c6SAlexei Starovoitov 783540f7c6SAlexei Starovoitov /* *key == 0 - the callback was called for array timer. 793540f7c6SAlexei Starovoitov * *key == 4 - the callback was called from lru timer. 803540f7c6SAlexei Starovoitov */ 813540f7c6SAlexei Starovoitov if (*key == ARRAY) { 823540f7c6SAlexei Starovoitov struct bpf_timer *lru_timer; 833540f7c6SAlexei Starovoitov int lru_key = LRU; 843540f7c6SAlexei Starovoitov 853540f7c6SAlexei Starovoitov /* rearm array timer to be called again in ~35 seconds */ 863540f7c6SAlexei Starovoitov if (bpf_timer_start(timer, 1ull << 35, 0) != 0) 873540f7c6SAlexei Starovoitov err |= 1; 883540f7c6SAlexei Starovoitov 893540f7c6SAlexei Starovoitov lru_timer = bpf_map_lookup_elem(&lru, &lru_key); 903540f7c6SAlexei Starovoitov if (!lru_timer) 913540f7c6SAlexei Starovoitov return 0; 923540f7c6SAlexei Starovoitov bpf_timer_set_callback(lru_timer, timer_cb1); 933540f7c6SAlexei Starovoitov if (bpf_timer_start(lru_timer, 0, 0) != 0) 943540f7c6SAlexei Starovoitov err |= 2; 953540f7c6SAlexei Starovoitov } else if (*key == LRU) { 963540f7c6SAlexei Starovoitov int lru_key, i; 973540f7c6SAlexei Starovoitov 983540f7c6SAlexei Starovoitov for (i = LRU + 1; 993540f7c6SAlexei Starovoitov i <= 100 /* for current LRU eviction algorithm this number 1003540f7c6SAlexei Starovoitov * should be larger than ~ lru->max_entries * 2 1013540f7c6SAlexei Starovoitov */; 1023540f7c6SAlexei Starovoitov i++) { 1033540f7c6SAlexei Starovoitov struct elem init = {}; 1043540f7c6SAlexei Starovoitov 1053540f7c6SAlexei Starovoitov /* lru_key cannot be used as loop induction variable 1063540f7c6SAlexei Starovoitov * otherwise the loop will be unbounded. 1073540f7c6SAlexei Starovoitov */ 1083540f7c6SAlexei Starovoitov lru_key = i; 1093540f7c6SAlexei Starovoitov 1103540f7c6SAlexei Starovoitov /* add more elements into lru map to push out current 1113540f7c6SAlexei Starovoitov * element and force deletion of this timer 1123540f7c6SAlexei Starovoitov */ 1133540f7c6SAlexei Starovoitov bpf_map_update_elem(map, &lru_key, &init, 0); 1143540f7c6SAlexei Starovoitov /* look it up to bump it into active list */ 1153540f7c6SAlexei Starovoitov bpf_map_lookup_elem(map, &lru_key); 1163540f7c6SAlexei Starovoitov 1173540f7c6SAlexei Starovoitov /* keep adding until *key changes underneath, 1183540f7c6SAlexei Starovoitov * which means that key/timer memory was reused 1193540f7c6SAlexei Starovoitov */ 1203540f7c6SAlexei Starovoitov if (*key != LRU) 1213540f7c6SAlexei Starovoitov break; 1223540f7c6SAlexei Starovoitov } 1233540f7c6SAlexei Starovoitov 1243540f7c6SAlexei Starovoitov /* check that the timer was removed */ 1253540f7c6SAlexei Starovoitov if (bpf_timer_cancel(timer) != -EINVAL) 1263540f7c6SAlexei Starovoitov err |= 4; 1273540f7c6SAlexei Starovoitov ok |= 1; 1283540f7c6SAlexei Starovoitov } 1293540f7c6SAlexei Starovoitov return 0; 1303540f7c6SAlexei Starovoitov } 1313540f7c6SAlexei Starovoitov 1323540f7c6SAlexei Starovoitov SEC("fentry/bpf_fentry_test1") 133a7c2ca3aSYonghong Song int BPF_PROG2(test1, int, a) 1343540f7c6SAlexei Starovoitov { 1353540f7c6SAlexei Starovoitov struct bpf_timer *arr_timer, *lru_timer; 1363540f7c6SAlexei Starovoitov struct elem init = {}; 1373540f7c6SAlexei Starovoitov int lru_key = LRU; 1383540f7c6SAlexei Starovoitov int array_key = ARRAY; 1393540f7c6SAlexei Starovoitov 1403540f7c6SAlexei Starovoitov arr_timer = bpf_map_lookup_elem(&array, &array_key); 1413540f7c6SAlexei Starovoitov if (!arr_timer) 1423540f7c6SAlexei Starovoitov return 0; 1433540f7c6SAlexei Starovoitov bpf_timer_init(arr_timer, &array, CLOCK_MONOTONIC); 1443540f7c6SAlexei Starovoitov 1453540f7c6SAlexei Starovoitov bpf_map_update_elem(&lru, &lru_key, &init, 0); 1463540f7c6SAlexei Starovoitov lru_timer = bpf_map_lookup_elem(&lru, &lru_key); 1473540f7c6SAlexei Starovoitov if (!lru_timer) 1483540f7c6SAlexei Starovoitov return 0; 1493540f7c6SAlexei Starovoitov bpf_timer_init(lru_timer, &lru, CLOCK_MONOTONIC); 1503540f7c6SAlexei Starovoitov 1513540f7c6SAlexei Starovoitov bpf_timer_set_callback(arr_timer, timer_cb1); 1523540f7c6SAlexei Starovoitov bpf_timer_start(arr_timer, 0 /* call timer_cb1 asap */, 0); 1533540f7c6SAlexei Starovoitov 1543540f7c6SAlexei Starovoitov /* init more timers to check that array destruction 1553540f7c6SAlexei Starovoitov * doesn't leak timer memory. 1563540f7c6SAlexei Starovoitov */ 1573540f7c6SAlexei Starovoitov array_key = 0; 1583540f7c6SAlexei Starovoitov arr_timer = bpf_map_lookup_elem(&array, &array_key); 1593540f7c6SAlexei Starovoitov if (!arr_timer) 1603540f7c6SAlexei Starovoitov return 0; 1613540f7c6SAlexei Starovoitov bpf_timer_init(arr_timer, &array, CLOCK_MONOTONIC); 1623540f7c6SAlexei Starovoitov return 0; 1633540f7c6SAlexei Starovoitov } 1643540f7c6SAlexei Starovoitov 1653540f7c6SAlexei Starovoitov /* callback for prealloc and non-prealloca hashtab timers */ 1663540f7c6SAlexei Starovoitov static int timer_cb2(void *map, int *key, struct hmap_elem *val) 1673540f7c6SAlexei Starovoitov { 1683540f7c6SAlexei Starovoitov if (*key == HTAB) 1693540f7c6SAlexei Starovoitov callback_check--; 1703540f7c6SAlexei Starovoitov else 1713540f7c6SAlexei Starovoitov callback2_check--; 1723540f7c6SAlexei Starovoitov if (val->counter > 0 && --val->counter) { 1733540f7c6SAlexei Starovoitov /* re-arm the timer again to execute after 1 usec */ 1743540f7c6SAlexei Starovoitov bpf_timer_start(&val->timer, 1000, 0); 1753540f7c6SAlexei Starovoitov } else if (*key == HTAB) { 1763540f7c6SAlexei Starovoitov struct bpf_timer *arr_timer; 1773540f7c6SAlexei Starovoitov int array_key = ARRAY; 1783540f7c6SAlexei Starovoitov 1793540f7c6SAlexei Starovoitov /* cancel arr_timer otherwise bpf_fentry_test1 prog 1803540f7c6SAlexei Starovoitov * will stay alive forever. 1813540f7c6SAlexei Starovoitov */ 1823540f7c6SAlexei Starovoitov arr_timer = bpf_map_lookup_elem(&array, &array_key); 1833540f7c6SAlexei Starovoitov if (!arr_timer) 1843540f7c6SAlexei Starovoitov return 0; 1853540f7c6SAlexei Starovoitov if (bpf_timer_cancel(arr_timer) != 1) 1863540f7c6SAlexei Starovoitov /* bpf_timer_cancel should return 1 to indicate 1873540f7c6SAlexei Starovoitov * that arr_timer was active at this time 1883540f7c6SAlexei Starovoitov */ 1893540f7c6SAlexei Starovoitov err |= 8; 1903540f7c6SAlexei Starovoitov 1913540f7c6SAlexei Starovoitov /* try to cancel ourself. It shouldn't deadlock. */ 1923540f7c6SAlexei Starovoitov if (bpf_timer_cancel(&val->timer) != -EDEADLK) 1933540f7c6SAlexei Starovoitov err |= 16; 1943540f7c6SAlexei Starovoitov 1953540f7c6SAlexei Starovoitov /* delete this key and this timer anyway. 1963540f7c6SAlexei Starovoitov * It shouldn't deadlock either. 1973540f7c6SAlexei Starovoitov */ 1983540f7c6SAlexei Starovoitov bpf_map_delete_elem(map, key); 1993540f7c6SAlexei Starovoitov 2003540f7c6SAlexei Starovoitov /* in preallocated hashmap both 'key' and 'val' could have been 2013540f7c6SAlexei Starovoitov * reused to store another map element (like in LRU above), 2023540f7c6SAlexei Starovoitov * but in controlled test environment the below test works. 2033540f7c6SAlexei Starovoitov * It's not a use-after-free. The memory is owned by the map. 2043540f7c6SAlexei Starovoitov */ 2053540f7c6SAlexei Starovoitov if (bpf_timer_start(&val->timer, 1000, 0) != -EINVAL) 2063540f7c6SAlexei Starovoitov err |= 32; 2073540f7c6SAlexei Starovoitov ok |= 2; 2083540f7c6SAlexei Starovoitov } else { 2093540f7c6SAlexei Starovoitov if (*key != HTAB_MALLOC) 2103540f7c6SAlexei Starovoitov err |= 64; 2113540f7c6SAlexei Starovoitov 2123540f7c6SAlexei Starovoitov /* try to cancel ourself. It shouldn't deadlock. */ 2133540f7c6SAlexei Starovoitov if (bpf_timer_cancel(&val->timer) != -EDEADLK) 2143540f7c6SAlexei Starovoitov err |= 128; 2153540f7c6SAlexei Starovoitov 2163540f7c6SAlexei Starovoitov /* delete this key and this timer anyway. 2173540f7c6SAlexei Starovoitov * It shouldn't deadlock either. 2183540f7c6SAlexei Starovoitov */ 2193540f7c6SAlexei Starovoitov bpf_map_delete_elem(map, key); 2203540f7c6SAlexei Starovoitov 2213540f7c6SAlexei Starovoitov ok |= 4; 2223540f7c6SAlexei Starovoitov } 2233540f7c6SAlexei Starovoitov return 0; 2243540f7c6SAlexei Starovoitov } 2253540f7c6SAlexei Starovoitov 2263540f7c6SAlexei Starovoitov int bpf_timer_test(void) 2273540f7c6SAlexei Starovoitov { 2283540f7c6SAlexei Starovoitov struct hmap_elem *val; 2293540f7c6SAlexei Starovoitov int key = HTAB, key_malloc = HTAB_MALLOC; 2303540f7c6SAlexei Starovoitov 2313540f7c6SAlexei Starovoitov val = bpf_map_lookup_elem(&hmap, &key); 2323540f7c6SAlexei Starovoitov if (val) { 2333540f7c6SAlexei Starovoitov if (bpf_timer_init(&val->timer, &hmap, CLOCK_BOOTTIME) != 0) 2343540f7c6SAlexei Starovoitov err |= 512; 2353540f7c6SAlexei Starovoitov bpf_timer_set_callback(&val->timer, timer_cb2); 2363540f7c6SAlexei Starovoitov bpf_timer_start(&val->timer, 1000, 0); 2373540f7c6SAlexei Starovoitov } 2383540f7c6SAlexei Starovoitov val = bpf_map_lookup_elem(&hmap_malloc, &key_malloc); 2393540f7c6SAlexei Starovoitov if (val) { 2403540f7c6SAlexei Starovoitov if (bpf_timer_init(&val->timer, &hmap_malloc, CLOCK_BOOTTIME) != 0) 2413540f7c6SAlexei Starovoitov err |= 1024; 2423540f7c6SAlexei Starovoitov bpf_timer_set_callback(&val->timer, timer_cb2); 2433540f7c6SAlexei Starovoitov bpf_timer_start(&val->timer, 1000, 0); 2443540f7c6SAlexei Starovoitov } 2453540f7c6SAlexei Starovoitov return 0; 2463540f7c6SAlexei Starovoitov } 2473540f7c6SAlexei Starovoitov 2483540f7c6SAlexei Starovoitov SEC("fentry/bpf_fentry_test2") 249a7c2ca3aSYonghong Song int BPF_PROG2(test2, int, a, int, b) 2503540f7c6SAlexei Starovoitov { 2513540f7c6SAlexei Starovoitov struct hmap_elem init = {}, *val; 2523540f7c6SAlexei Starovoitov int key = HTAB, key_malloc = HTAB_MALLOC; 2533540f7c6SAlexei Starovoitov 2543540f7c6SAlexei Starovoitov init.counter = 10; /* number of times to trigger timer_cb2 */ 2553540f7c6SAlexei Starovoitov bpf_map_update_elem(&hmap, &key, &init, 0); 2563540f7c6SAlexei Starovoitov val = bpf_map_lookup_elem(&hmap, &key); 2573540f7c6SAlexei Starovoitov if (val) 2583540f7c6SAlexei Starovoitov bpf_timer_init(&val->timer, &hmap, CLOCK_BOOTTIME); 2593540f7c6SAlexei Starovoitov /* update the same key to free the timer */ 2603540f7c6SAlexei Starovoitov bpf_map_update_elem(&hmap, &key, &init, 0); 2613540f7c6SAlexei Starovoitov 2623540f7c6SAlexei Starovoitov bpf_map_update_elem(&hmap_malloc, &key_malloc, &init, 0); 2633540f7c6SAlexei Starovoitov val = bpf_map_lookup_elem(&hmap_malloc, &key_malloc); 2643540f7c6SAlexei Starovoitov if (val) 2653540f7c6SAlexei Starovoitov bpf_timer_init(&val->timer, &hmap_malloc, CLOCK_BOOTTIME); 2663540f7c6SAlexei Starovoitov /* update the same key to free the timer */ 2673540f7c6SAlexei Starovoitov bpf_map_update_elem(&hmap_malloc, &key_malloc, &init, 0); 2683540f7c6SAlexei Starovoitov 2693540f7c6SAlexei Starovoitov /* init more timers to check that htab operations 2703540f7c6SAlexei Starovoitov * don't leak timer memory. 2713540f7c6SAlexei Starovoitov */ 2723540f7c6SAlexei Starovoitov key = 0; 2733540f7c6SAlexei Starovoitov bpf_map_update_elem(&hmap, &key, &init, 0); 2743540f7c6SAlexei Starovoitov val = bpf_map_lookup_elem(&hmap, &key); 2753540f7c6SAlexei Starovoitov if (val) 2763540f7c6SAlexei Starovoitov bpf_timer_init(&val->timer, &hmap, CLOCK_BOOTTIME); 2773540f7c6SAlexei Starovoitov bpf_map_delete_elem(&hmap, &key); 2783540f7c6SAlexei Starovoitov bpf_map_update_elem(&hmap, &key, &init, 0); 2793540f7c6SAlexei Starovoitov val = bpf_map_lookup_elem(&hmap, &key); 2803540f7c6SAlexei Starovoitov if (val) 2813540f7c6SAlexei Starovoitov bpf_timer_init(&val->timer, &hmap, CLOCK_BOOTTIME); 2823540f7c6SAlexei Starovoitov 2833540f7c6SAlexei Starovoitov /* and with non-prealloc htab */ 2843540f7c6SAlexei Starovoitov key_malloc = 0; 2853540f7c6SAlexei Starovoitov bpf_map_update_elem(&hmap_malloc, &key_malloc, &init, 0); 2863540f7c6SAlexei Starovoitov val = bpf_map_lookup_elem(&hmap_malloc, &key_malloc); 2873540f7c6SAlexei Starovoitov if (val) 2883540f7c6SAlexei Starovoitov bpf_timer_init(&val->timer, &hmap_malloc, CLOCK_BOOTTIME); 2893540f7c6SAlexei Starovoitov bpf_map_delete_elem(&hmap_malloc, &key_malloc); 2903540f7c6SAlexei Starovoitov bpf_map_update_elem(&hmap_malloc, &key_malloc, &init, 0); 2913540f7c6SAlexei Starovoitov val = bpf_map_lookup_elem(&hmap_malloc, &key_malloc); 2923540f7c6SAlexei Starovoitov if (val) 2933540f7c6SAlexei Starovoitov bpf_timer_init(&val->timer, &hmap_malloc, CLOCK_BOOTTIME); 2943540f7c6SAlexei Starovoitov 2953540f7c6SAlexei Starovoitov return bpf_timer_test(); 2963540f7c6SAlexei Starovoitov } 297944459e8STero Kristo 298944459e8STero Kristo /* callback for absolute timer */ 299944459e8STero Kristo static int timer_cb3(void *map, int *key, struct bpf_timer *timer) 300944459e8STero Kristo { 301944459e8STero Kristo abs_data += 6; 302944459e8STero Kristo 303944459e8STero Kristo if (abs_data < 12) { 304944459e8STero Kristo bpf_timer_start(timer, bpf_ktime_get_boot_ns() + 1000, 305944459e8STero Kristo BPF_F_TIMER_ABS); 306944459e8STero Kristo } else { 307944459e8STero Kristo /* Re-arm timer ~35 seconds in future */ 308944459e8STero Kristo bpf_timer_start(timer, bpf_ktime_get_boot_ns() + (1ull << 35), 309944459e8STero Kristo BPF_F_TIMER_ABS); 310944459e8STero Kristo } 311944459e8STero Kristo 312944459e8STero Kristo return 0; 313944459e8STero Kristo } 314944459e8STero Kristo 315944459e8STero Kristo SEC("fentry/bpf_fentry_test3") 316944459e8STero Kristo int BPF_PROG2(test3, int, a) 317944459e8STero Kristo { 318944459e8STero Kristo int key = 0; 319944459e8STero Kristo struct bpf_timer *timer; 320944459e8STero Kristo 321944459e8STero Kristo bpf_printk("test3"); 322944459e8STero Kristo 323944459e8STero Kristo timer = bpf_map_lookup_elem(&abs_timer, &key); 324944459e8STero Kristo if (timer) { 325944459e8STero Kristo if (bpf_timer_init(timer, &abs_timer, CLOCK_BOOTTIME) != 0) 326944459e8STero Kristo err |= 2048; 327944459e8STero Kristo bpf_timer_set_callback(timer, timer_cb3); 328944459e8STero Kristo bpf_timer_start(timer, bpf_ktime_get_boot_ns() + 1000, 329944459e8STero Kristo BPF_F_TIMER_ABS); 330944459e8STero Kristo } 331944459e8STero Kristo 332944459e8STero Kristo return 0; 333944459e8STero Kristo } 334*0d7ae068SDavid Vernet 335*0d7ae068SDavid Vernet /* callback for pinned timer */ 336*0d7ae068SDavid Vernet static int timer_cb_pinned(void *map, int *key, struct bpf_timer *timer) 337*0d7ae068SDavid Vernet { 338*0d7ae068SDavid Vernet __s32 cpu = bpf_get_smp_processor_id(); 339*0d7ae068SDavid Vernet 340*0d7ae068SDavid Vernet if (cpu != pinned_cpu) 341*0d7ae068SDavid Vernet err |= 16384; 342*0d7ae068SDavid Vernet 343*0d7ae068SDavid Vernet pinned_callback_check++; 344*0d7ae068SDavid Vernet return 0; 345*0d7ae068SDavid Vernet } 346*0d7ae068SDavid Vernet 347*0d7ae068SDavid Vernet static void test_pinned_timer(bool soft) 348*0d7ae068SDavid Vernet { 349*0d7ae068SDavid Vernet int key = 0; 350*0d7ae068SDavid Vernet void *map; 351*0d7ae068SDavid Vernet struct bpf_timer *timer; 352*0d7ae068SDavid Vernet __u64 flags = BPF_F_TIMER_CPU_PIN; 353*0d7ae068SDavid Vernet __u64 start_time; 354*0d7ae068SDavid Vernet 355*0d7ae068SDavid Vernet if (soft) { 356*0d7ae068SDavid Vernet map = &soft_timer_pinned; 357*0d7ae068SDavid Vernet start_time = 0; 358*0d7ae068SDavid Vernet } else { 359*0d7ae068SDavid Vernet map = &abs_timer_pinned; 360*0d7ae068SDavid Vernet start_time = bpf_ktime_get_boot_ns(); 361*0d7ae068SDavid Vernet flags |= BPF_F_TIMER_ABS; 362*0d7ae068SDavid Vernet } 363*0d7ae068SDavid Vernet 364*0d7ae068SDavid Vernet timer = bpf_map_lookup_elem(map, &key); 365*0d7ae068SDavid Vernet if (timer) { 366*0d7ae068SDavid Vernet if (bpf_timer_init(timer, map, CLOCK_BOOTTIME) != 0) 367*0d7ae068SDavid Vernet err |= 4096; 368*0d7ae068SDavid Vernet bpf_timer_set_callback(timer, timer_cb_pinned); 369*0d7ae068SDavid Vernet pinned_cpu = bpf_get_smp_processor_id(); 370*0d7ae068SDavid Vernet bpf_timer_start(timer, start_time + 1000, flags); 371*0d7ae068SDavid Vernet } else { 372*0d7ae068SDavid Vernet err |= 8192; 373*0d7ae068SDavid Vernet } 374*0d7ae068SDavid Vernet } 375*0d7ae068SDavid Vernet 376*0d7ae068SDavid Vernet SEC("fentry/bpf_fentry_test4") 377*0d7ae068SDavid Vernet int BPF_PROG2(test4, int, a) 378*0d7ae068SDavid Vernet { 379*0d7ae068SDavid Vernet bpf_printk("test4"); 380*0d7ae068SDavid Vernet test_pinned_timer(true); 381*0d7ae068SDavid Vernet 382*0d7ae068SDavid Vernet return 0; 383*0d7ae068SDavid Vernet } 384*0d7ae068SDavid Vernet 385*0d7ae068SDavid Vernet SEC("fentry/bpf_fentry_test5") 386*0d7ae068SDavid Vernet int BPF_PROG2(test5, int, a) 387*0d7ae068SDavid Vernet { 388*0d7ae068SDavid Vernet bpf_printk("test5"); 389*0d7ae068SDavid Vernet test_pinned_timer(false); 390*0d7ae068SDavid Vernet 391*0d7ae068SDavid Vernet return 0; 392*0d7ae068SDavid Vernet } 393