diff options
Diffstat (limited to 'src/xdp/utils/xdp_loader.c')
-rw-r--r-- | src/xdp/utils/xdp_loader.c | 165 |
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; +} |