summaryrefslogtreecommitdiffstats
path: root/lib/libxdp/xdp-dispatcher.c.in
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libxdp/xdp-dispatcher.c.in')
-rw-r--r--lib/libxdp/xdp-dispatcher.c.in82
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);