17c2aad20Sopenharmony_ci/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
27c2aad20Sopenharmony_ci#ifndef __BPF_HELPERS__
37c2aad20Sopenharmony_ci#define __BPF_HELPERS__
47c2aad20Sopenharmony_ci
57c2aad20Sopenharmony_ci/*
67c2aad20Sopenharmony_ci * Note that bpf programs need to include either
77c2aad20Sopenharmony_ci * vmlinux.h (auto-generated from BTF) or linux/types.h
87c2aad20Sopenharmony_ci * in advance since bpf_helper_defs.h uses such types
97c2aad20Sopenharmony_ci * as __u64.
107c2aad20Sopenharmony_ci */
117c2aad20Sopenharmony_ci#include "bpf_helper_defs.h"
127c2aad20Sopenharmony_ci
137c2aad20Sopenharmony_ci#define __uint(name, val) int (*name)[val]
147c2aad20Sopenharmony_ci#define __type(name, val) typeof(val) *name
157c2aad20Sopenharmony_ci#define __array(name, val) typeof(val) *name[]
167c2aad20Sopenharmony_ci
177c2aad20Sopenharmony_ci/*
187c2aad20Sopenharmony_ci * Helper macro to place programs, maps, license in
197c2aad20Sopenharmony_ci * different sections in elf_bpf file. Section names
207c2aad20Sopenharmony_ci * are interpreted by libbpf depending on the context (BPF programs, BPF maps,
217c2aad20Sopenharmony_ci * extern variables, etc).
227c2aad20Sopenharmony_ci * To allow use of SEC() with externs (e.g., for extern .maps declarations),
237c2aad20Sopenharmony_ci * make sure __attribute__((unused)) doesn't trigger compilation warning.
247c2aad20Sopenharmony_ci */
257c2aad20Sopenharmony_ci#if __GNUC__ && !__clang__
267c2aad20Sopenharmony_ci
277c2aad20Sopenharmony_ci/*
287c2aad20Sopenharmony_ci * Pragma macros are broken on GCC
297c2aad20Sopenharmony_ci * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55578
307c2aad20Sopenharmony_ci * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90400
317c2aad20Sopenharmony_ci */
327c2aad20Sopenharmony_ci#define SEC(name) __attribute__((section(name), used))
337c2aad20Sopenharmony_ci
347c2aad20Sopenharmony_ci#else
357c2aad20Sopenharmony_ci
367c2aad20Sopenharmony_ci#define SEC(name) \
377c2aad20Sopenharmony_ci	_Pragma("GCC diagnostic push")					    \
387c2aad20Sopenharmony_ci	_Pragma("GCC diagnostic ignored \"-Wignored-attributes\"")	    \
397c2aad20Sopenharmony_ci	__attribute__((section(name), used))				    \
407c2aad20Sopenharmony_ci	_Pragma("GCC diagnostic pop")					    \
417c2aad20Sopenharmony_ci
427c2aad20Sopenharmony_ci#endif
437c2aad20Sopenharmony_ci
447c2aad20Sopenharmony_ci/* Avoid 'linux/stddef.h' definition of '__always_inline'. */
457c2aad20Sopenharmony_ci#undef __always_inline
467c2aad20Sopenharmony_ci#define __always_inline inline __attribute__((always_inline))
477c2aad20Sopenharmony_ci
487c2aad20Sopenharmony_ci#ifndef __noinline
497c2aad20Sopenharmony_ci#define __noinline __attribute__((noinline))
507c2aad20Sopenharmony_ci#endif
517c2aad20Sopenharmony_ci#ifndef __weak
527c2aad20Sopenharmony_ci#define __weak __attribute__((weak))
537c2aad20Sopenharmony_ci#endif
547c2aad20Sopenharmony_ci
557c2aad20Sopenharmony_ci/*
567c2aad20Sopenharmony_ci * Use __hidden attribute to mark a non-static BPF subprogram effectively
577c2aad20Sopenharmony_ci * static for BPF verifier's verification algorithm purposes, allowing more
587c2aad20Sopenharmony_ci * extensive and permissive BPF verification process, taking into account
597c2aad20Sopenharmony_ci * subprogram's caller context.
607c2aad20Sopenharmony_ci */
617c2aad20Sopenharmony_ci#define __hidden __attribute__((visibility("hidden")))
627c2aad20Sopenharmony_ci
637c2aad20Sopenharmony_ci/* When utilizing vmlinux.h with BPF CO-RE, user BPF programs can't include
647c2aad20Sopenharmony_ci * any system-level headers (such as stddef.h, linux/version.h, etc), and
657c2aad20Sopenharmony_ci * commonly-used macros like NULL and KERNEL_VERSION aren't available through
667c2aad20Sopenharmony_ci * vmlinux.h. This just adds unnecessary hurdles and forces users to re-define
677c2aad20Sopenharmony_ci * them on their own. So as a convenience, provide such definitions here.
687c2aad20Sopenharmony_ci */
697c2aad20Sopenharmony_ci#ifndef NULL
707c2aad20Sopenharmony_ci#define NULL ((void *)0)
717c2aad20Sopenharmony_ci#endif
727c2aad20Sopenharmony_ci
737c2aad20Sopenharmony_ci#ifndef KERNEL_VERSION
747c2aad20Sopenharmony_ci#define KERNEL_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + ((c) > 255 ? 255 : (c)))
757c2aad20Sopenharmony_ci#endif
767c2aad20Sopenharmony_ci
777c2aad20Sopenharmony_ci/*
787c2aad20Sopenharmony_ci * Helper macros to manipulate data structures
797c2aad20Sopenharmony_ci */
807c2aad20Sopenharmony_ci
817c2aad20Sopenharmony_ci/* offsetof() definition that uses __builtin_offset() might not preserve field
827c2aad20Sopenharmony_ci * offset CO-RE relocation properly, so force-redefine offsetof() using
837c2aad20Sopenharmony_ci * old-school approach which works with CO-RE correctly
847c2aad20Sopenharmony_ci */
857c2aad20Sopenharmony_ci#undef offsetof
867c2aad20Sopenharmony_ci#define offsetof(type, member)	((unsigned long)&((type *)0)->member)
877c2aad20Sopenharmony_ci
887c2aad20Sopenharmony_ci/* redefined container_of() to ensure we use the above offsetof() macro */
897c2aad20Sopenharmony_ci#undef container_of
907c2aad20Sopenharmony_ci#define container_of(ptr, type, member)				\
917c2aad20Sopenharmony_ci	({							\
927c2aad20Sopenharmony_ci		void *__mptr = (void *)(ptr);			\
937c2aad20Sopenharmony_ci		((type *)(__mptr - offsetof(type, member)));	\
947c2aad20Sopenharmony_ci	})
957c2aad20Sopenharmony_ci
967c2aad20Sopenharmony_ci/*
977c2aad20Sopenharmony_ci * Compiler (optimization) barrier.
987c2aad20Sopenharmony_ci */
997c2aad20Sopenharmony_ci#ifndef barrier
1007c2aad20Sopenharmony_ci#define barrier() asm volatile("" ::: "memory")
1017c2aad20Sopenharmony_ci#endif
1027c2aad20Sopenharmony_ci
1037c2aad20Sopenharmony_ci/* Variable-specific compiler (optimization) barrier. It's a no-op which makes
1047c2aad20Sopenharmony_ci * compiler believe that there is some black box modification of a given
1057c2aad20Sopenharmony_ci * variable and thus prevents compiler from making extra assumption about its
1067c2aad20Sopenharmony_ci * value and potential simplifications and optimizations on this variable.
1077c2aad20Sopenharmony_ci *
1087c2aad20Sopenharmony_ci * E.g., compiler might often delay or even omit 32-bit to 64-bit casting of
1097c2aad20Sopenharmony_ci * a variable, making some code patterns unverifiable. Putting barrier_var()
1107c2aad20Sopenharmony_ci * in place will ensure that cast is performed before the barrier_var()
1117c2aad20Sopenharmony_ci * invocation, because compiler has to pessimistically assume that embedded
1127c2aad20Sopenharmony_ci * asm section might perform some extra operations on that variable.
1137c2aad20Sopenharmony_ci *
1147c2aad20Sopenharmony_ci * This is a variable-specific variant of more global barrier().
1157c2aad20Sopenharmony_ci */
1167c2aad20Sopenharmony_ci#ifndef barrier_var
1177c2aad20Sopenharmony_ci#define barrier_var(var) asm volatile("" : "+r"(var))
1187c2aad20Sopenharmony_ci#endif
1197c2aad20Sopenharmony_ci
1207c2aad20Sopenharmony_ci/*
1217c2aad20Sopenharmony_ci * Helper macro to throw a compilation error if __bpf_unreachable() gets
1227c2aad20Sopenharmony_ci * built into the resulting code. This works given BPF back end does not
1237c2aad20Sopenharmony_ci * implement __builtin_trap(). This is useful to assert that certain paths
1247c2aad20Sopenharmony_ci * of the program code are never used and hence eliminated by the compiler.
1257c2aad20Sopenharmony_ci *
1267c2aad20Sopenharmony_ci * For example, consider a switch statement that covers known cases used by
1277c2aad20Sopenharmony_ci * the program. __bpf_unreachable() can then reside in the default case. If
1287c2aad20Sopenharmony_ci * the program gets extended such that a case is not covered in the switch
1297c2aad20Sopenharmony_ci * statement, then it will throw a build error due to the default case not
1307c2aad20Sopenharmony_ci * being compiled out.
1317c2aad20Sopenharmony_ci */
1327c2aad20Sopenharmony_ci#ifndef __bpf_unreachable
1337c2aad20Sopenharmony_ci# define __bpf_unreachable()	__builtin_trap()
1347c2aad20Sopenharmony_ci#endif
1357c2aad20Sopenharmony_ci
1367c2aad20Sopenharmony_ci/*
1377c2aad20Sopenharmony_ci * Helper function to perform a tail call with a constant/immediate map slot.
1387c2aad20Sopenharmony_ci */
1397c2aad20Sopenharmony_ci#if __clang_major__ >= 8 && defined(__bpf__)
1407c2aad20Sopenharmony_cistatic __always_inline void
1417c2aad20Sopenharmony_cibpf_tail_call_static(void *ctx, const void *map, const __u32 slot)
1427c2aad20Sopenharmony_ci{
1437c2aad20Sopenharmony_ci	if (!__builtin_constant_p(slot))
1447c2aad20Sopenharmony_ci		__bpf_unreachable();
1457c2aad20Sopenharmony_ci
1467c2aad20Sopenharmony_ci	/*
1477c2aad20Sopenharmony_ci	 * Provide a hard guarantee that LLVM won't optimize setting r2 (map
1487c2aad20Sopenharmony_ci	 * pointer) and r3 (constant map index) from _different paths_ ending
1497c2aad20Sopenharmony_ci	 * up at the _same_ call insn as otherwise we won't be able to use the
1507c2aad20Sopenharmony_ci	 * jmpq/nopl retpoline-free patching by the x86-64 JIT in the kernel
1517c2aad20Sopenharmony_ci	 * given they mismatch. See also d2e4c1e6c294 ("bpf: Constant map key
1527c2aad20Sopenharmony_ci	 * tracking for prog array pokes") for details on verifier tracking.
1537c2aad20Sopenharmony_ci	 *
1547c2aad20Sopenharmony_ci	 * Note on clobber list: we need to stay in-line with BPF calling
1557c2aad20Sopenharmony_ci	 * convention, so even if we don't end up using r0, r4, r5, we need
1567c2aad20Sopenharmony_ci	 * to mark them as clobber so that LLVM doesn't end up using them
1577c2aad20Sopenharmony_ci	 * before / after the call.
1587c2aad20Sopenharmony_ci	 */
1597c2aad20Sopenharmony_ci	asm volatile("r1 = %[ctx]\n\t"
1607c2aad20Sopenharmony_ci		     "r2 = %[map]\n\t"
1617c2aad20Sopenharmony_ci		     "r3 = %[slot]\n\t"
1627c2aad20Sopenharmony_ci		     "call 12"
1637c2aad20Sopenharmony_ci		     :: [ctx]"r"(ctx), [map]"r"(map), [slot]"i"(slot)
1647c2aad20Sopenharmony_ci		     : "r0", "r1", "r2", "r3", "r4", "r5");
1657c2aad20Sopenharmony_ci}
1667c2aad20Sopenharmony_ci#endif
1677c2aad20Sopenharmony_ci
1687c2aad20Sopenharmony_cienum libbpf_pin_type {
1697c2aad20Sopenharmony_ci	LIBBPF_PIN_NONE,
1707c2aad20Sopenharmony_ci	/* PIN_BY_NAME: pin maps by name (in /sys/fs/bpf by default) */
1717c2aad20Sopenharmony_ci	LIBBPF_PIN_BY_NAME,
1727c2aad20Sopenharmony_ci};
1737c2aad20Sopenharmony_ci
1747c2aad20Sopenharmony_cienum libbpf_tristate {
1757c2aad20Sopenharmony_ci	TRI_NO = 0,
1767c2aad20Sopenharmony_ci	TRI_YES = 1,
1777c2aad20Sopenharmony_ci	TRI_MODULE = 2,
1787c2aad20Sopenharmony_ci};
1797c2aad20Sopenharmony_ci
1807c2aad20Sopenharmony_ci#define __kconfig __attribute__((section(".kconfig")))
1817c2aad20Sopenharmony_ci#define __ksym __attribute__((section(".ksyms")))
1827c2aad20Sopenharmony_ci#define __kptr_untrusted __attribute__((btf_type_tag("kptr_untrusted")))
1837c2aad20Sopenharmony_ci#define __kptr __attribute__((btf_type_tag("kptr")))
1847c2aad20Sopenharmony_ci#define __percpu_kptr __attribute__((btf_type_tag("percpu_kptr")))
1857c2aad20Sopenharmony_ci
1867c2aad20Sopenharmony_ci#define bpf_ksym_exists(sym) ({									\
1877c2aad20Sopenharmony_ci	_Static_assert(!__builtin_constant_p(!!sym), #sym " should be marked as __weak");	\
1887c2aad20Sopenharmony_ci	!!sym;											\
1897c2aad20Sopenharmony_ci})
1907c2aad20Sopenharmony_ci
1917c2aad20Sopenharmony_ci#ifndef ___bpf_concat
1927c2aad20Sopenharmony_ci#define ___bpf_concat(a, b) a ## b
1937c2aad20Sopenharmony_ci#endif
1947c2aad20Sopenharmony_ci#ifndef ___bpf_apply
1957c2aad20Sopenharmony_ci#define ___bpf_apply(fn, n) ___bpf_concat(fn, n)
1967c2aad20Sopenharmony_ci#endif
1977c2aad20Sopenharmony_ci#ifndef ___bpf_nth
1987c2aad20Sopenharmony_ci#define ___bpf_nth(_, _1, _2, _3, _4, _5, _6, _7, _8, _9, _a, _b, _c, N, ...) N
1997c2aad20Sopenharmony_ci#endif
2007c2aad20Sopenharmony_ci#ifndef ___bpf_narg
2017c2aad20Sopenharmony_ci#define ___bpf_narg(...) \
2027c2aad20Sopenharmony_ci	___bpf_nth(_, ##__VA_ARGS__, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
2037c2aad20Sopenharmony_ci#endif
2047c2aad20Sopenharmony_ci
2057c2aad20Sopenharmony_ci#define ___bpf_fill0(arr, p, x) do {} while (0)
2067c2aad20Sopenharmony_ci#define ___bpf_fill1(arr, p, x) arr[p] = x
2077c2aad20Sopenharmony_ci#define ___bpf_fill2(arr, p, x, args...) arr[p] = x; ___bpf_fill1(arr, p + 1, args)
2087c2aad20Sopenharmony_ci#define ___bpf_fill3(arr, p, x, args...) arr[p] = x; ___bpf_fill2(arr, p + 1, args)
2097c2aad20Sopenharmony_ci#define ___bpf_fill4(arr, p, x, args...) arr[p] = x; ___bpf_fill3(arr, p + 1, args)
2107c2aad20Sopenharmony_ci#define ___bpf_fill5(arr, p, x, args...) arr[p] = x; ___bpf_fill4(arr, p + 1, args)
2117c2aad20Sopenharmony_ci#define ___bpf_fill6(arr, p, x, args...) arr[p] = x; ___bpf_fill5(arr, p + 1, args)
2127c2aad20Sopenharmony_ci#define ___bpf_fill7(arr, p, x, args...) arr[p] = x; ___bpf_fill6(arr, p + 1, args)
2137c2aad20Sopenharmony_ci#define ___bpf_fill8(arr, p, x, args...) arr[p] = x; ___bpf_fill7(arr, p + 1, args)
2147c2aad20Sopenharmony_ci#define ___bpf_fill9(arr, p, x, args...) arr[p] = x; ___bpf_fill8(arr, p + 1, args)
2157c2aad20Sopenharmony_ci#define ___bpf_fill10(arr, p, x, args...) arr[p] = x; ___bpf_fill9(arr, p + 1, args)
2167c2aad20Sopenharmony_ci#define ___bpf_fill11(arr, p, x, args...) arr[p] = x; ___bpf_fill10(arr, p + 1, args)
2177c2aad20Sopenharmony_ci#define ___bpf_fill12(arr, p, x, args...) arr[p] = x; ___bpf_fill11(arr, p + 1, args)
2187c2aad20Sopenharmony_ci#define ___bpf_fill(arr, args...) \
2197c2aad20Sopenharmony_ci	___bpf_apply(___bpf_fill, ___bpf_narg(args))(arr, 0, args)
2207c2aad20Sopenharmony_ci
2217c2aad20Sopenharmony_ci/*
2227c2aad20Sopenharmony_ci * BPF_SEQ_PRINTF to wrap bpf_seq_printf to-be-printed values
2237c2aad20Sopenharmony_ci * in a structure.
2247c2aad20Sopenharmony_ci */
2257c2aad20Sopenharmony_ci#define BPF_SEQ_PRINTF(seq, fmt, args...)			\
2267c2aad20Sopenharmony_ci({								\
2277c2aad20Sopenharmony_ci	static const char ___fmt[] = fmt;			\
2287c2aad20Sopenharmony_ci	unsigned long long ___param[___bpf_narg(args)];		\
2297c2aad20Sopenharmony_ci								\
2307c2aad20Sopenharmony_ci	_Pragma("GCC diagnostic push")				\
2317c2aad20Sopenharmony_ci	_Pragma("GCC diagnostic ignored \"-Wint-conversion\"")	\
2327c2aad20Sopenharmony_ci	___bpf_fill(___param, args);				\
2337c2aad20Sopenharmony_ci	_Pragma("GCC diagnostic pop")				\
2347c2aad20Sopenharmony_ci								\
2357c2aad20Sopenharmony_ci	bpf_seq_printf(seq, ___fmt, sizeof(___fmt),		\
2367c2aad20Sopenharmony_ci		       ___param, sizeof(___param));		\
2377c2aad20Sopenharmony_ci})
2387c2aad20Sopenharmony_ci
2397c2aad20Sopenharmony_ci/*
2407c2aad20Sopenharmony_ci * BPF_SNPRINTF wraps the bpf_snprintf helper with variadic arguments instead of
2417c2aad20Sopenharmony_ci * an array of u64.
2427c2aad20Sopenharmony_ci */
2437c2aad20Sopenharmony_ci#define BPF_SNPRINTF(out, out_size, fmt, args...)		\
2447c2aad20Sopenharmony_ci({								\
2457c2aad20Sopenharmony_ci	static const char ___fmt[] = fmt;			\
2467c2aad20Sopenharmony_ci	unsigned long long ___param[___bpf_narg(args)];		\
2477c2aad20Sopenharmony_ci								\
2487c2aad20Sopenharmony_ci	_Pragma("GCC diagnostic push")				\
2497c2aad20Sopenharmony_ci	_Pragma("GCC diagnostic ignored \"-Wint-conversion\"")	\
2507c2aad20Sopenharmony_ci	___bpf_fill(___param, args);				\
2517c2aad20Sopenharmony_ci	_Pragma("GCC diagnostic pop")				\
2527c2aad20Sopenharmony_ci								\
2537c2aad20Sopenharmony_ci	bpf_snprintf(out, out_size, ___fmt,			\
2547c2aad20Sopenharmony_ci		     ___param, sizeof(___param));		\
2557c2aad20Sopenharmony_ci})
2567c2aad20Sopenharmony_ci
2577c2aad20Sopenharmony_ci#ifdef BPF_NO_GLOBAL_DATA
2587c2aad20Sopenharmony_ci#define BPF_PRINTK_FMT_MOD
2597c2aad20Sopenharmony_ci#else
2607c2aad20Sopenharmony_ci#define BPF_PRINTK_FMT_MOD static const
2617c2aad20Sopenharmony_ci#endif
2627c2aad20Sopenharmony_ci
2637c2aad20Sopenharmony_ci#define __bpf_printk(fmt, ...)				\
2647c2aad20Sopenharmony_ci({							\
2657c2aad20Sopenharmony_ci	BPF_PRINTK_FMT_MOD char ____fmt[] = fmt;	\
2667c2aad20Sopenharmony_ci	bpf_trace_printk(____fmt, sizeof(____fmt),	\
2677c2aad20Sopenharmony_ci			 ##__VA_ARGS__);		\
2687c2aad20Sopenharmony_ci})
2697c2aad20Sopenharmony_ci
2707c2aad20Sopenharmony_ci/*
2717c2aad20Sopenharmony_ci * __bpf_vprintk wraps the bpf_trace_vprintk helper with variadic arguments
2727c2aad20Sopenharmony_ci * instead of an array of u64.
2737c2aad20Sopenharmony_ci */
2747c2aad20Sopenharmony_ci#define __bpf_vprintk(fmt, args...)				\
2757c2aad20Sopenharmony_ci({								\
2767c2aad20Sopenharmony_ci	static const char ___fmt[] = fmt;			\
2777c2aad20Sopenharmony_ci	unsigned long long ___param[___bpf_narg(args)];		\
2787c2aad20Sopenharmony_ci								\
2797c2aad20Sopenharmony_ci	_Pragma("GCC diagnostic push")				\
2807c2aad20Sopenharmony_ci	_Pragma("GCC diagnostic ignored \"-Wint-conversion\"")	\
2817c2aad20Sopenharmony_ci	___bpf_fill(___param, args);				\
2827c2aad20Sopenharmony_ci	_Pragma("GCC diagnostic pop")				\
2837c2aad20Sopenharmony_ci								\
2847c2aad20Sopenharmony_ci	bpf_trace_vprintk(___fmt, sizeof(___fmt),		\
2857c2aad20Sopenharmony_ci			  ___param, sizeof(___param));		\
2867c2aad20Sopenharmony_ci})
2877c2aad20Sopenharmony_ci
2887c2aad20Sopenharmony_ci/* Use __bpf_printk when bpf_printk call has 3 or fewer fmt args
2897c2aad20Sopenharmony_ci * Otherwise use __bpf_vprintk
2907c2aad20Sopenharmony_ci */
2917c2aad20Sopenharmony_ci#define ___bpf_pick_printk(...) \
2927c2aad20Sopenharmony_ci	___bpf_nth(_, ##__VA_ARGS__, __bpf_vprintk, __bpf_vprintk, __bpf_vprintk,	\
2937c2aad20Sopenharmony_ci		   __bpf_vprintk, __bpf_vprintk, __bpf_vprintk, __bpf_vprintk,		\
2947c2aad20Sopenharmony_ci		   __bpf_vprintk, __bpf_vprintk, __bpf_printk /*3*/, __bpf_printk /*2*/,\
2957c2aad20Sopenharmony_ci		   __bpf_printk /*1*/, __bpf_printk /*0*/)
2967c2aad20Sopenharmony_ci
2977c2aad20Sopenharmony_ci/* Helper macro to print out debug messages */
2987c2aad20Sopenharmony_ci#define bpf_printk(fmt, args...) ___bpf_pick_printk(args)(fmt, ##args)
2997c2aad20Sopenharmony_ci
3007c2aad20Sopenharmony_cistruct bpf_iter_num;
3017c2aad20Sopenharmony_ci
3027c2aad20Sopenharmony_ciextern int bpf_iter_num_new(struct bpf_iter_num *it, int start, int end) __weak __ksym;
3037c2aad20Sopenharmony_ciextern int *bpf_iter_num_next(struct bpf_iter_num *it) __weak __ksym;
3047c2aad20Sopenharmony_ciextern void bpf_iter_num_destroy(struct bpf_iter_num *it) __weak __ksym;
3057c2aad20Sopenharmony_ci
3067c2aad20Sopenharmony_ci#ifndef bpf_for_each
3077c2aad20Sopenharmony_ci/* bpf_for_each(iter_type, cur_elem, args...) provides generic construct for
3087c2aad20Sopenharmony_ci * using BPF open-coded iterators without having to write mundane explicit
3097c2aad20Sopenharmony_ci * low-level loop logic. Instead, it provides for()-like generic construct
3107c2aad20Sopenharmony_ci * that can be used pretty naturally. E.g., for some hypothetical cgroup
3117c2aad20Sopenharmony_ci * iterator, you'd write:
3127c2aad20Sopenharmony_ci *
3137c2aad20Sopenharmony_ci * struct cgroup *cg, *parent_cg = <...>;
3147c2aad20Sopenharmony_ci *
3157c2aad20Sopenharmony_ci * bpf_for_each(cgroup, cg, parent_cg, CG_ITER_CHILDREN) {
3167c2aad20Sopenharmony_ci *     bpf_printk("Child cgroup id = %d", cg->cgroup_id);
3177c2aad20Sopenharmony_ci *     if (cg->cgroup_id == 123)
3187c2aad20Sopenharmony_ci *         break;
3197c2aad20Sopenharmony_ci * }
3207c2aad20Sopenharmony_ci *
3217c2aad20Sopenharmony_ci * I.e., it looks almost like high-level for each loop in other languages,
3227c2aad20Sopenharmony_ci * supports continue/break, and is verifiable by BPF verifier.
3237c2aad20Sopenharmony_ci *
3247c2aad20Sopenharmony_ci * For iterating integers, the difference betwen bpf_for_each(num, i, N, M)
3257c2aad20Sopenharmony_ci * and bpf_for(i, N, M) is in that bpf_for() provides additional proof to
3267c2aad20Sopenharmony_ci * verifier that i is in [N, M) range, and in bpf_for_each() case i is `int
3277c2aad20Sopenharmony_ci * *`, not just `int`. So for integers bpf_for() is more convenient.
3287c2aad20Sopenharmony_ci *
3297c2aad20Sopenharmony_ci * Note: this macro relies on C99 feature of allowing to declare variables
3307c2aad20Sopenharmony_ci * inside for() loop, bound to for() loop lifetime. It also utilizes GCC
3317c2aad20Sopenharmony_ci * extension: __attribute__((cleanup(<func>))), supported by both GCC and
3327c2aad20Sopenharmony_ci * Clang.
3337c2aad20Sopenharmony_ci */
3347c2aad20Sopenharmony_ci#define bpf_for_each(type, cur, args...) for (							\
3357c2aad20Sopenharmony_ci	/* initialize and define destructor */							\
3367c2aad20Sopenharmony_ci	struct bpf_iter_##type ___it __attribute__((aligned(8), /* enforce, just in case */,	\
3377c2aad20Sopenharmony_ci						    cleanup(bpf_iter_##type##_destroy))),	\
3387c2aad20Sopenharmony_ci	/* ___p pointer is just to call bpf_iter_##type##_new() *once* to init ___it */		\
3397c2aad20Sopenharmony_ci			       *___p __attribute__((unused)) = (				\
3407c2aad20Sopenharmony_ci					bpf_iter_##type##_new(&___it, ##args),			\
3417c2aad20Sopenharmony_ci	/* this is a workaround for Clang bug: it currently doesn't emit BTF */			\
3427c2aad20Sopenharmony_ci	/* for bpf_iter_##type##_destroy() when used from cleanup() attribute */		\
3437c2aad20Sopenharmony_ci					(void)bpf_iter_##type##_destroy, (void *)0);		\
3447c2aad20Sopenharmony_ci	/* iteration and termination check */							\
3457c2aad20Sopenharmony_ci	(((cur) = bpf_iter_##type##_next(&___it)));						\
3467c2aad20Sopenharmony_ci)
3477c2aad20Sopenharmony_ci#endif /* bpf_for_each */
3487c2aad20Sopenharmony_ci
3497c2aad20Sopenharmony_ci#ifndef bpf_for
3507c2aad20Sopenharmony_ci/* bpf_for(i, start, end) implements a for()-like looping construct that sets
3517c2aad20Sopenharmony_ci * provided integer variable *i* to values starting from *start* through,
3527c2aad20Sopenharmony_ci * but not including, *end*. It also proves to BPF verifier that *i* belongs
3537c2aad20Sopenharmony_ci * to range [start, end), so this can be used for accessing arrays without
3547c2aad20Sopenharmony_ci * extra checks.
3557c2aad20Sopenharmony_ci *
3567c2aad20Sopenharmony_ci * Note: *start* and *end* are assumed to be expressions with no side effects
3577c2aad20Sopenharmony_ci * and whose values do not change throughout bpf_for() loop execution. They do
3587c2aad20Sopenharmony_ci * not have to be statically known or constant, though.
3597c2aad20Sopenharmony_ci *
3607c2aad20Sopenharmony_ci * Note: similarly to bpf_for_each(), it relies on C99 feature of declaring for()
3617c2aad20Sopenharmony_ci * loop bound variables and cleanup attribute, supported by GCC and Clang.
3627c2aad20Sopenharmony_ci */
3637c2aad20Sopenharmony_ci#define bpf_for(i, start, end) for (								\
3647c2aad20Sopenharmony_ci	/* initialize and define destructor */							\
3657c2aad20Sopenharmony_ci	struct bpf_iter_num ___it __attribute__((aligned(8), /* enforce, just in case */	\
3667c2aad20Sopenharmony_ci						 cleanup(bpf_iter_num_destroy))),		\
3677c2aad20Sopenharmony_ci	/* ___p pointer is necessary to call bpf_iter_num_new() *once* to init ___it */		\
3687c2aad20Sopenharmony_ci			    *___p __attribute__((unused)) = (					\
3697c2aad20Sopenharmony_ci				bpf_iter_num_new(&___it, (start), (end)),			\
3707c2aad20Sopenharmony_ci	/* this is a workaround for Clang bug: it currently doesn't emit BTF */			\
3717c2aad20Sopenharmony_ci	/* for bpf_iter_num_destroy() when used from cleanup() attribute */			\
3727c2aad20Sopenharmony_ci				(void)bpf_iter_num_destroy, (void *)0);				\
3737c2aad20Sopenharmony_ci	({											\
3747c2aad20Sopenharmony_ci		/* iteration step */								\
3757c2aad20Sopenharmony_ci		int *___t = bpf_iter_num_next(&___it);						\
3767c2aad20Sopenharmony_ci		/* termination and bounds check */						\
3777c2aad20Sopenharmony_ci		(___t && ((i) = *___t, (i) >= (start) && (i) < (end)));				\
3787c2aad20Sopenharmony_ci	});											\
3797c2aad20Sopenharmony_ci)
3807c2aad20Sopenharmony_ci#endif /* bpf_for */
3817c2aad20Sopenharmony_ci
3827c2aad20Sopenharmony_ci#ifndef bpf_repeat
3837c2aad20Sopenharmony_ci/* bpf_repeat(N) performs N iterations without exposing iteration number
3847c2aad20Sopenharmony_ci *
3857c2aad20Sopenharmony_ci * Note: similarly to bpf_for_each(), it relies on C99 feature of declaring for()
3867c2aad20Sopenharmony_ci * loop bound variables and cleanup attribute, supported by GCC and Clang.
3877c2aad20Sopenharmony_ci */
3887c2aad20Sopenharmony_ci#define bpf_repeat(N) for (									\
3897c2aad20Sopenharmony_ci	/* initialize and define destructor */							\
3907c2aad20Sopenharmony_ci	struct bpf_iter_num ___it __attribute__((aligned(8), /* enforce, just in case */	\
3917c2aad20Sopenharmony_ci						 cleanup(bpf_iter_num_destroy))),		\
3927c2aad20Sopenharmony_ci	/* ___p pointer is necessary to call bpf_iter_num_new() *once* to init ___it */		\
3937c2aad20Sopenharmony_ci			    *___p __attribute__((unused)) = (					\
3947c2aad20Sopenharmony_ci				bpf_iter_num_new(&___it, 0, (N)),				\
3957c2aad20Sopenharmony_ci	/* this is a workaround for Clang bug: it currently doesn't emit BTF */			\
3967c2aad20Sopenharmony_ci	/* for bpf_iter_num_destroy() when used from cleanup() attribute */			\
3977c2aad20Sopenharmony_ci				(void)bpf_iter_num_destroy, (void *)0);				\
3987c2aad20Sopenharmony_ci	bpf_iter_num_next(&___it);								\
3997c2aad20Sopenharmony_ci	/* nothing here  */									\
4007c2aad20Sopenharmony_ci)
4017c2aad20Sopenharmony_ci#endif /* bpf_repeat */
4027c2aad20Sopenharmony_ci
4037c2aad20Sopenharmony_ci#endif
404