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 */