]> git.feebdaed.xyz Git - 0xmirror/xdp-tools.git/commitdiff
libxdp: add selftest for dispatcher v2 compatibility
authorJalal Mostafa <jalal.a.mostapha@gmail.com>
Fri, 12 Sep 2025 13:30:15 +0000 (15:30 +0200)
committerToke Høiland-Jørgensen <toke@toke.dk>
Tue, 16 Dec 2025 22:15:38 +0000 (23:15 +0100)
Signed-off-by: Jalal Mostafa <jalal.a.mostapha@gmail.com>
lib/libxdp/tests/Makefile
lib/libxdp/tests/test_dispatcher_versions.c
lib/libxdp/tests/xdp_dispatcher.h [new file with mode: 0644]
lib/libxdp/tests/xdp_dispatcher_v1.c
lib/libxdp/tests/xdp_dispatcher_v1.h [deleted file]
lib/libxdp/tests/xdp_dispatcher_v2.c [new file with mode: 0644]

index 94c90c1b600b9078457cbd077f527c94e91f6709..bb2300b4f4a0d3891ca8a3e61e984eb2cc3fcd84 100644 (file)
@@ -2,11 +2,11 @@
 
 USER_TARGETS := test_xsk_refcnt test_xdp_frags test_link_detach test_xsk_umem_flags test_xdp_devbound
 STATIC_LINK_TARGETS := check_kern_compat test_dispatcher_versions
-BPF_TARGETS := xdp_dispatcher_v1 xdp_pass
+BPF_TARGETS := xdp_dispatcher_v1 xdp_dispatcher_v2 xdp_pass
 USER_LIBS := -lpthread
 USER_EXTRA_C := test_utils.c
 
-EXTRA_DEPS += xdp_dispatcher_v1.h
+EXTRA_DEPS += xdp_dispatcher.h
 EXTRA_USER_DEPS += test_utils.h $(USER_EXTRA_C)
 
 TEST_FILE := ./test-libxdp.sh
index 45564416e3f9d77e214eeba5093d8d4ae617438d..afb76db88110d0b5924070aa51529224c533d2b7 100644 (file)
@@ -15,7 +15,7 @@
 
 #include "test_utils.h"
 #include "../libxdp_internal.h"
-#include "xdp_dispatcher_v1.h"
+#include "xdp_dispatcher.h"
 
 #include <xdp/libxdp.h>
 #include <bpf/libbpf.h>
 
 #define PROG_RUN_PRIO 42
 #define PROG_CHAIN_CALL_ACTIONS (1 << XDP_DROP)
+#define DISPATCHER_V1_FILE "xdp_dispatcher_v1.o"
+#define DISPATCHER_V2_FILE "xdp_dispatcher_v2.o"
+
+static void print_test_result(const char *func, int ret)
+{
+       fflush(stderr);
+       fprintf(stderr, "%s:\t%s\n", func, ret ? "FAILED" : "PASSED");
+       fflush(stdout);
+}
 
 int get_prog_id(int prog_fd)
 {
@@ -43,21 +52,38 @@ int get_prog_id(int prog_fd)
        return info.id;
 }
 
-int load_dispatcher_v1(int ifindex)
+static char* get_dispatcher_file(unsigned int dispatcher_version)
+{
+       switch (dispatcher_version) {
+       case XDP_DISPATCHER_VERSION_V1:
+               return DISPATCHER_V1_FILE;
+
+       case XDP_DISPATCHER_VERSION_V2:
+               return DISPATCHER_V2_FILE;
+
+       default:
+               break;
+       }
+       return NULL;
+}
+
+int load_dispatcher(int ifindex, unsigned int dispatcher_version)
 {
-       struct xdp_dispatcher_config_v1 dispatcher_config = {};
+       struct xdp_dispatcher_config_v1 dispatcher_config_v1 = {};
+       struct xdp_dispatcher_config_v2 dispatcher_config_v2 = {};
+       char *dispatcher_file = get_dispatcher_file(dispatcher_version);
        struct bpf_object *obj_dispatcher, *obj_prog = NULL;
        DECLARE_LIBBPF_OPTS(bpf_link_create_opts, opts);
        struct bpf_program *dispatcher_prog, *xdp_prog;
-       int ret, btf_id, lfd = -1, dispatcher_id;
+       int ret = 0, btf_id, lfd = -1, dispatcher_id;
        char pin_path[PATH_MAX], buf[PATH_MAX];
        const char *attach_func = "prog0";
        struct bpf_map *map;
 
-       if (!ifindex)
+       if (!ifindex || !dispatcher_file)
                return -ENOENT;
 
-       obj_dispatcher = open_bpf_file("xdp_dispatcher_v1.o", NULL);
+       obj_dispatcher = open_bpf_file(dispatcher_file, NULL);
        if (IS_ERR_OR_NULL(obj_dispatcher))
                return -errno;
 
@@ -76,22 +102,38 @@ int load_dispatcher_v1(int ifindex)
        }
 
        dispatcher_prog = bpf_object__find_program_by_name(obj_dispatcher,
-                                                         "xdp_dispatcher");
+                                                          "xdp_dispatcher");
        if (!dispatcher_prog) {
                ret = -errno;
                goto out;
        }
 
-       dispatcher_config.num_progs_enabled = 1;
-       dispatcher_config.chain_call_actions[0] = PROG_CHAIN_CALL_ACTIONS;
-       dispatcher_config.run_prios[0] = PROG_RUN_PRIO;
+       switch (dispatcher_version) {
+       case XDP_DISPATCHER_VERSION_V1:
+               dispatcher_config_v1.num_progs_enabled = 1;
+               dispatcher_config_v1.chain_call_actions[0] = PROG_CHAIN_CALL_ACTIONS;
+               dispatcher_config_v1.run_prios[0] = PROG_RUN_PRIO;
+
+               ret = bpf_map__set_initial_value(map, &dispatcher_config_v1,
+                                                sizeof(dispatcher_config_v1));
+               break;
+
+       case XDP_DISPATCHER_VERSION_V2:
+               dispatcher_config_v2.magic = XDP_DISPATCHER_MAGIC;
+               dispatcher_config_v2.num_progs_enabled = 1;
+               dispatcher_config_v2.chain_call_actions[0] = PROG_CHAIN_CALL_ACTIONS;
+               dispatcher_config_v2.run_prios[0] = PROG_RUN_PRIO;
+               dispatcher_config_v2.is_xdp_frags = 0;
+               dispatcher_config_v2.program_flags[0] = 0;
+               dispatcher_config_v2.dispatcher_version = XDP_DISPATCHER_VERSION_V2;
+
+               ret = bpf_map__set_initial_value(map, &dispatcher_config_v2,
+                                                sizeof(dispatcher_config_v2));
+       }
 
-       ret = bpf_map__set_initial_value(map, &dispatcher_config,
-                                        sizeof(dispatcher_config));
        if (ret)
                goto out;
 
-
        ret = bpf_object__load(obj_dispatcher);
        if (ret)
                goto out;
@@ -190,14 +232,14 @@ err_unpin:
        goto out;
 }
 
-int check_old_dispatcher(int ifindex)
+int check_old_dispatcher(int ifindex, unsigned int dispatcher_version)
 {
        struct xdp_multiprog *mp = NULL;
        struct xdp_program *xdp_prog;
        char buf[100];
        int ret;
 
-       ret = load_dispatcher_v1(ifindex);
+       ret = load_dispatcher(ifindex, dispatcher_version);
        if (ret)
                goto out;
 
@@ -279,6 +321,20 @@ static void usage(char *progname)
        exit(EXIT_FAILURE);
 }
 
+int check_old_dispatcher_v1(int ifindex)
+{
+       int ret = check_old_dispatcher(ifindex, XDP_DISPATCHER_VERSION_V1);
+       print_test_result(__func__, ret);
+       return ret;
+}
+
+int check_old_dispatcher_v2(int ifindex)
+{
+       int ret = check_old_dispatcher(ifindex, XDP_DISPATCHER_VERSION_V2);
+       print_test_result(__func__, ret);
+       return ret;
+}
+
 int main(int argc, char **argv)
 {
        int ifindex, ret;
@@ -297,7 +353,8 @@ int main(int argc, char **argv)
 
        ifindex = if_nametoindex(argv[1]);
 
-       ret = check_old_dispatcher(ifindex);
+       ret = check_old_dispatcher_v1(ifindex);
+       ret = check_old_dispatcher_v2(ifindex) || ret;
 
        return ret;
 }
diff --git a/lib/libxdp/tests/xdp_dispatcher.h b/lib/libxdp/tests/xdp_dispatcher.h
new file mode 100644 (file)
index 0000000..adbe94e
--- /dev/null
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __XDP_DISPATCHER_H
+#define __XDP_DISPATCHER_H
+
+#ifndef MAX_DISPATCHER_ACTIONS
+#define MAX_DISPATCHER_ACTIONS 10
+#endif
+
+struct xdp_dispatcher_config_v1 {
+       __u8 num_progs_enabled;
+       __u32 chain_call_actions[MAX_DISPATCHER_ACTIONS];
+       __u32 run_prios[MAX_DISPATCHER_ACTIONS];
+};
+
+#define XDP_DISPATCHER_VERSION_V1 1
+
+struct xdp_dispatcher_config_v2 {
+       __u8 magic;                         /* Set to XDP_DISPATCHER_MAGIC */
+       __u8 dispatcher_version;            /* Set to XDP_DISPATCHER_VERSION */
+       __u8 num_progs_enabled;             /* Number of active program slots */
+       __u8 is_xdp_frags;                  /* Whether this dispatcher is loaded with XDP frags support */
+       __u32 chain_call_actions[MAX_DISPATCHER_ACTIONS];
+       __u32 run_prios[MAX_DISPATCHER_ACTIONS];
+       __u32 program_flags[MAX_DISPATCHER_ACTIONS];
+};
+
+#define XDP_DISPATCHER_MAGIC 236
+#define XDP_DISPATCHER_VERSION_V2 2
+
+#endif
index 2f1c7fba2a8748bc92a331fdd3fa54d7a80da4ea..bb08556f6da3cf1d723870581809cd80087ecb4d 100644 (file)
@@ -4,10 +4,9 @@
 #include <bpf/bpf_helpers.h>
 #include <bpf/bpf_endian.h>
 
-#include "xdp_dispatcher_v1.h"
+#include "xdp_dispatcher.h"
 
 #define XDP_METADATA_SECTION "xdp_metadata"
-#define XDP_DISPATCHER_VERSION_V1 1
 #define XDP_DISPATCHER_RETVAL 31
 
 
diff --git a/lib/libxdp/tests/xdp_dispatcher_v1.h b/lib/libxdp/tests/xdp_dispatcher_v1.h
deleted file mode 100644 (file)
index 55dac37..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-
-#ifndef __XDP_DISPATCHER_V1_H
-#define __XDP_DISPATCHER_V1_H
-
-#ifndef MAX_DISPATCHER_ACTIONS
-#define MAX_DISPATCHER_ACTIONS 10
-#endif
-
-struct xdp_dispatcher_config_v1 {
-       __u8 num_progs_enabled;
-       __u32 chain_call_actions[MAX_DISPATCHER_ACTIONS];
-       __u32 run_prios[MAX_DISPATCHER_ACTIONS];
-};
-
-#endif
diff --git a/lib/libxdp/tests/xdp_dispatcher_v2.c b/lib/libxdp/tests/xdp_dispatcher_v2.c
new file mode 100644 (file)
index 0000000..dbab72d
--- /dev/null
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#include <linux/bpf.h>
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_endian.h>
+
+#include "xdp_dispatcher.h"
+
+#define XDP_METADATA_SECTION "xdp_metadata"
+#define XDP_DISPATCHER_RETVAL 31
+
+
+static volatile const struct xdp_dispatcher_config_v2 conf = {};
+
+__attribute__ ((noinline))
+int prog0(struct xdp_md *ctx) {
+        volatile int ret = XDP_DISPATCHER_RETVAL;
+
+        if (!ctx)
+          return XDP_ABORTED;
+        return ret;
+}
+__attribute__ ((noinline))
+
+SEC("xdp")
+int xdp_dispatcher(struct xdp_md *ctx)
+{
+        __u8 num_progs_enabled = conf.num_progs_enabled;
+        int ret;
+
+        if (num_progs_enabled < 1)
+                goto out;
+        ret = prog0(ctx);
+        if (!((1U << ret) & conf.chain_call_actions[0]))
+                return ret;
+
+out:
+        return XDP_PASS;
+}
+
+char _license[] SEC("license") = "GPL";
+__uint(dispatcher_version, XDP_DISPATCHER_VERSION_V2) SEC(XDP_METADATA_SECTION);