github.com/datadog/cilium@v1.6.12/bpf/lib/tailcall.h (about) 1 #ifndef TAILCALL_H 2 #define TAILCALL_H 3 4 #include "config.h" 5 6 #define __eval(x, ...) x ## __VA_ARGS__ 7 8 #define __and_00 0 9 #define __and_01 0 10 #define __and_10 0 11 #define __and_11 1 12 #define __and_0(y) __eval(__and_0, y) 13 #define __and_1(y) __eval(__and_1, y) 14 #define __and(x, y) __eval(__and_, x)(y) 15 16 #define __or_00 0 17 #define __or_01 1 18 #define __or_10 1 19 #define __or_11 1 20 #define __or_0(y) __eval(__or_0, y) 21 #define __or_1(y) __eval(__or_1, y) 22 #define __or(x, y) __eval(__or_, x)(y) 23 24 /* declare_tailcall_if() and invoke_tailcall_if() is a pair 25 * of helpers which based on COND either selects to emit a 26 * tail call for the underlying function when true or emits 27 * it as inlined when false. COND can be selected by one or 28 * multiple compile time flags. 29 * 30 * Usage example: 31 * 32 * 1) Declaration: 33 * 34 * declare_tailcall_if(__and(is_defined(ENABLE_IPV4), is_defined(ENABLE_IPV6)), 35 * CILIUM_CALL_FOO) 36 * int foo_fn(struct __sk_buff *skb) 37 * { 38 * [...] 39 * } 40 * 41 * 2) Call-site: 42 * 43 * [...] 44 * invoke_tailcall_if(__and(is_defined(ENABLE_IPV4), is_defined(ENABLE_IPV6)), 45 * CILIUM_CALL_FOO, foo_fn); 46 * [...] 47 * 48 * 3) Compilation result: 49 * 50 * When compiled with -DENABLE_IPV4 and -DENABLE_IPV6 both 51 * set, then above emits a tail call as follows: 52 * 53 * __attribute__((section("2" "/" "10"), used)) 54 * int foo_fn(struct __sk_buff *skb) 55 * { 56 * [...] 57 * } 58 * 59 * [...] 60 * do { ep_tail_call(skb, 10); ret = -140; } while (0); 61 * [...] 62 * 63 * The fall-through side sets DROP_MISSED_TAIL_CALL as ret. 64 * 65 * When only one of them is set in the above example or none 66 * of them, then the code emission looks like: 67 * 68 * static __inline __attribute__ ((__always_inline__)) 69 * int foo_fn(struct __sk_buff *skb) 70 * { 71 * [...] 72 * } 73 * 74 * [...] 75 * return foo_fn(skb); 76 * [...] 77 * 78 * Selectors can be single is_defined(), or multiple ones 79 * combined with __and() or __or() macros. COND must be 80 * the same expression for declare_tailcall_if() and the 81 * invoke_tailcall_if() part. 82 */ 83 #define __declare_tailcall_if_0(NAME) \ 84 static __always_inline 85 #define __declare_tailcall_if_1(NAME) \ 86 __section_tail(CILIUM_MAP_CALLS, NAME) 87 #define declare_tailcall_if(COND, NAME) \ 88 __eval(__declare_tailcall_if_, COND)(NAME) 89 90 #define __invoke_tailcall_if_0(NAME, FUNC) \ 91 return FUNC(skb) 92 #define __invoke_tailcall_if_1(NAME, FUNC) \ 93 do { \ 94 ep_tail_call(skb, NAME); \ 95 ret = DROP_MISSED_TAIL_CALL; \ 96 } while (0) 97 #define invoke_tailcall_if(COND, NAME, FUNC) \ 98 __eval(__invoke_tailcall_if_, COND)(NAME, FUNC) 99 100 #endif /* TAILCALL_H */