diff options
Diffstat (limited to 'lib/libxdp/xdp-dispatcher.c.in')
-rw-r--r-- | lib/libxdp/xdp-dispatcher.c.in | 82 |
1 files changed, 82 insertions, 0 deletions
diff --git a/lib/libxdp/xdp-dispatcher.c.in b/lib/libxdp/xdp-dispatcher.c.in new file mode 100644 index 0000000..6214d78 --- /dev/null +++ b/lib/libxdp/xdp-dispatcher.c.in @@ -0,0 +1,82 @@ +/* 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 <linux/bpf.h> +#include <bpf/bpf_helpers.h> +#include <bpf/bpf_endian.h> + +#include <xdp/prog_dispatcher.h> + +/* 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); |