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