xref: /linux/tools/testing/selftests/bpf/progs/timer.c (revision 0d7ae06860753bb30b3731302b994da071120d00)
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