summaryrefslogtreecommitdiff
path: root/src/xdp/utils/xdp_loader.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/xdp/utils/xdp_loader.c')
-rw-r--r--src/xdp/utils/xdp_loader.c165
1 files changed, 165 insertions, 0 deletions
diff --git a/src/xdp/utils/xdp_loader.c b/src/xdp/utils/xdp_loader.c
new file mode 100644
index 000000000..d3b05d0c0
--- /dev/null
+++ b/src/xdp/utils/xdp_loader.c
@@ -0,0 +1,165 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+static const char *__doc__ = "XDP loader\n"
+ " - Allows selecting BPF section --progsec name to XDP-attach to --dev\n";
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <getopt.h>
+
+#include <locale.h>
+#include <unistd.h>
+#include <time.h>
+
+#include <bpf/bpf.h>
+#include <bpf/libbpf.h>
+
+#include <net/if.h>
+#include <linux/if_link.h> /* depend on kernel-headers installed */
+
+#include "../common/common_params.h"
+#include "../common/common_user_bpf_xdp.h"
+#include "../common/common_libbpf.h"
+
+static const char *default_filename = "xdp_prog_kern.o";
+
+static const struct option_wrapper long_options[] = {
+
+ {{"help", no_argument, NULL, 'h' },
+ "Show help", false},
+
+ {{"dev", required_argument, NULL, 'd' },
+ "Operate on device <ifname>", "<ifname>", true},
+
+ {{"skb-mode", no_argument, NULL, 'S' },
+ "Install XDP program in SKB (AKA generic) mode"},
+
+ {{"native-mode", no_argument, NULL, 'N' },
+ "Install XDP program in native mode"},
+
+ {{"auto-mode", no_argument, NULL, 'A' },
+ "Auto-detect SKB or native mode"},
+
+ {{"force", no_argument, NULL, 'F' },
+ "Force install, replacing existing program on interface"},
+
+ {{"unload", no_argument, NULL, 'U' },
+ "Unload XDP program instead of loading"},
+
+ {{"reuse-maps", no_argument, NULL, 'M' },
+ "Reuse pinned maps"},
+
+ {{"quiet", no_argument, NULL, 'q' },
+ "Quiet mode (no output)"},
+
+ {{"filename", required_argument, NULL, 1 },
+ "Load program from <file>", "<file>"},
+
+ {{"progsec", required_argument, NULL, 2 },
+ "Load program in <section> of the ELF file", "<section>"},
+
+ {{0, 0, NULL, 0 }, NULL, false}
+};
+
+#ifndef PATH_MAX
+#define PATH_MAX 4096
+#endif
+
+const char *pin_basedir = "/sys/fs/bpf";
+const char *map_name = "xdp_stats_map";
+
+/* Pinning maps under /sys/fs/bpf in subdir */
+int pin_maps_in_bpf_object(struct bpf_object *bpf_obj, struct config *cfg)
+{
+ char map_filename[PATH_MAX];
+ int err, len;
+
+ len = snprintf(map_filename, PATH_MAX, "%s/%s/%s",
+ pin_basedir, cfg->ifname, map_name);
+ if (len < 0) {
+ fprintf(stderr, "ERR: creating map_name\n");
+ return EXIT_FAIL_OPTION;
+ }
+
+ /* Existing/previous XDP prog might not have cleaned up */
+ if (access(map_filename, F_OK ) != -1 ) {
+ if (verbose)
+ printf(" - Unpinning (remove) prev maps in %s/\n",
+ cfg->pin_dir);
+
+ /* Basically calls unlink(3) on map_filename */
+ err = bpf_object__unpin_maps(bpf_obj, cfg->pin_dir);
+ if (err) {
+ fprintf(stderr, "ERR: UNpinning maps in %s\n", cfg->pin_dir);
+ return EXIT_FAIL_BPF;
+ }
+ }
+ if (verbose)
+ printf(" - Pinning maps in %s/\n", cfg->pin_dir);
+
+ /* This will pin all maps in our bpf_object */
+ err = bpf_object__pin_maps(bpf_obj, cfg->pin_dir);
+ if (err)
+ return EXIT_FAIL_BPF;
+
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ struct bpf_object *bpf_obj;
+ int err, len;
+
+ struct config cfg = {
+ .xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST | XDP_FLAGS_DRV_MODE,
+ .ifindex = -1,
+ .do_unload = false,
+ };
+ /* Set default BPF-ELF object file and BPF program name */
+ strncpy(cfg.filename, default_filename, sizeof(cfg.filename));
+ /* Cmdline options can change progsec */
+ parse_cmdline_args(argc, argv, long_options, &cfg, __doc__);
+
+ /* Required option */
+ if (cfg.ifindex == -1) {
+ fprintf(stderr, "ERR: required option --dev missing\n\n");
+ usage(argv[0], __doc__, long_options, (argc == 1));
+ return EXIT_FAIL_OPTION;
+ }
+ if (cfg.do_unload) {
+ if (!cfg.reuse_maps) {
+ /* TODO: Miss unpin of maps on unload */
+ }
+ return xdp_link_detach(cfg.ifindex, cfg.xdp_flags, 0);
+ }
+
+ len = snprintf(cfg.pin_dir, PATH_MAX, "%s/%s", pin_basedir, cfg.ifname);
+ if (len < 0) {
+ fprintf(stderr, "ERR: creating pin dirname\n");
+ return EXIT_FAIL_OPTION;
+ }
+
+
+ bpf_obj = load_bpf_and_xdp_attach(&cfg);
+ if (!bpf_obj)
+ return EXIT_FAIL_BPF;
+
+ if (verbose) {
+ printf("Success: Loaded BPF-object(%s) and used section(%s)\n",
+ cfg.filename, cfg.progsec);
+ printf(" - XDP prog attached on device:%s(ifindex:%d)\n",
+ cfg.ifname, cfg.ifindex);
+ }
+
+ /* Use the --dev name as subdir for exporting/pinning maps */
+ if (!cfg.reuse_maps) {
+ err = pin_maps_in_bpf_object(bpf_obj, &cfg);
+ if (err) {
+ fprintf(stderr, "ERR: pinning maps\n");
+ return err;
+ }
+ }
+
+ return EXIT_OK;
+}