/* SPDX-License-Identifier: GPL-2.0 */ divert(-1) #forloop definition taken from example in the M4 manual define(`forloop', `pushdef(`$1', `$2')_forloop($@)popdef(`$1')') define(`_forloop',`$4`'ifelse($1, decr(`$3'), `', `define(`$1', incr($1))$0($@)')') define(`NUM_PROGS',ifdef(`MAX_DISPATCHER_ACTIONS', MAX_DISPATCHER_ACTIONS, `10')) divert(0)dnl #include #include #include #include /* While 'const volatile' sounds a little like an oxymoron, there's reason * behind the madness: * * - const places the data in rodata, where libbpf will mark it as read-only and * frozen on program load, letting the kernel do dead code elimination based * on the values. * * - volatile prevents the compiler from optimising away the checks based on the * compile-time value of the variables, which is important since we will be * changing the values before loading the program into the kernel. */ static volatile const struct xdp_dispatcher_config conf = {}; /* The volatile return value prevents the compiler from assuming it knows the * return value and optimising based on that. */ forloop(`i', `0', NUM_PROGS, `__attribute__ ((noinline)) int format(`prog%d', i)(struct xdp_md *ctx) { volatile int ret = XDP_DISPATCHER_RETVAL; if (!ctx) return XDP_ABORTED; return ret; } ') __attribute__ ((noinline)) int compat_test(struct xdp_md *ctx) { volatile int ret = XDP_DISPATCHER_RETVAL; if (!ctx) return XDP_ABORTED; return ret; } SEC("xdp") int xdp_dispatcher(struct xdp_md *ctx) { __u8 num_progs_enabled = conf.num_progs_enabled; int ret; forloop(`i', `0', NUM_PROGS, ` if (num_progs_enabled < incr(i)) goto out; ret = format(`prog%d', i)(ctx); if (!((1U << ret) & conf.chain_call_actions[i])) return ret; ') /* keep a reference to the compat_test() function so we can use it * as an freplace target in xdp_multiprog__check_compat() in libxdp */ if (num_progs_enabled < incr(NUM_PROGS)) goto out; ret = compat_test(ctx); out: return XDP_PASS; } SEC("xdp") int xdp_pass(struct xdp_md *ctx) { return XDP_PASS; } char _license[] SEC("license") = "GPL"; __uint(dispatcher_version, XDP_DISPATCHER_VERSION) SEC(XDP_METADATA_SECTION);