diff --git a/advanced03-AF_XDP/af_xdp_user.c b/advanced03-AF_XDP/af_xdp_user.c index 5d3274db..6082e8a8 100644 --- a/advanced03-AF_XDP/af_xdp_user.c +++ b/advanced03-AF_XDP/af_xdp_user.c @@ -39,7 +39,6 @@ static struct xdp_program *prog; int xsk_map_fd; bool custom_xsk = false; struct config cfg = { - .xdp_flags = XDP_FLAGS_DRV_MODE, .ifindex = -1, }; @@ -565,7 +564,7 @@ int main(int argc, char **argv) return err; } - err = xdp_program__attach(prog, cfg.ifindex, cfg.xdp_flags, 0); + err = xdp_program__attach(prog, cfg.ifindex, cfg.attach_mode, 0); if (err) { libxdp_strerror(err, errmsg, sizeof(errmsg)); fprintf(stderr, "Couldn't attach XDP program on iface '%s' : %s (%d)\n", diff --git a/basic-solutions/xdp_loader.c b/basic-solutions/xdp_loader.c index 574fa2cf..04edd840 100644 --- a/basic-solutions/xdp_loader.c +++ b/basic-solutions/xdp_loader.c @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 */ static const char *__doc__ = "XDP loader\n" - " - Allows selecting BPF section --progname name to XDP-attach to --dev\n"; + " - Allows selecting BPF program --progname name to XDP-attach to --dev\n"; #include #include @@ -77,7 +77,7 @@ int pin_maps_in_bpf_object(struct bpf_object *bpf_obj, struct config *cfg) int err, len; len = snprintf(map_filename, PATH_MAX, "%s/%s/%s", - pin_basedir, cfg->ifname, map_name); + cfg->pin_dir, cfg->ifname, map_name); if (len < 0) { fprintf(stderr, "ERR: creating map_name\n"); return EXIT_FAIL_OPTION; @@ -101,8 +101,10 @@ int pin_maps_in_bpf_object(struct bpf_object *bpf_obj, struct config *cfg) /* This will pin all maps in our bpf_object */ err = bpf_object__pin_maps(bpf_obj, cfg->pin_dir); - if (err) + if (err) { + fprintf(stderr, "ERR: Pinning maps in %s\n", cfg->pin_dir); return EXIT_FAIL_BPF; + } return 0; } @@ -113,9 +115,9 @@ int main(int argc, char **argv) int err, len; struct config cfg = { - .xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST | XDP_FLAGS_DRV_MODE, - .ifindex = -1, - .do_unload = false, + .attach_mode = XDP_MODE_NATIVE, + .ifindex = -1, + .do_unload = false, }; /* Set default BPF-ELF object file and BPF program name */ strncpy(cfg.filename, default_filename, sizeof(cfg.filename)); @@ -135,7 +137,8 @@ int main(int argc, char **argv) /* return xdp_link_detach(cfg.ifindex, cfg.xdp_flags, 0); */ } - len = snprintf(cfg.pin_dir, PATH_MAX, "%s/%s", pin_basedir, cfg.ifname); + /* Initialize the pin_dir configuration */ + len = snprintf(cfg.pin_dir, 512, "%s/%s", pin_basedir, cfg.ifname); if (len < 0) { fprintf(stderr, "ERR: creating pin dirname\n"); return EXIT_FAIL_OPTION; @@ -147,7 +150,7 @@ int main(int argc, char **argv) return EXIT_FAIL_BPF; if (verbose) { - printf("Success: Loaded BPF-object(%s) and used section(%s)\n", + printf("Success: Loaded BPF-object(%s) and used program(%s)\n", cfg.filename, cfg.progname); printf(" - XDP prog attached on device:%s(ifindex:%d)\n", cfg.ifname, cfg.ifindex); diff --git a/basic02-prog-by-name/Makefile b/basic02-prog-by-name/Makefile index ac56eadf..4f15b00d 100644 --- a/basic02-prog-by-name/Makefile +++ b/basic02-prog-by-name/Makefile @@ -4,6 +4,7 @@ XDP_TARGETS := xdp_prog_kern USER_TARGETS := xdp_loader COMMON_DIR = ../common +COMMON_OBJS += $(COMMON_DIR)/common_user_bpf_xdp.o include $(COMMON_DIR)/common.mk diff --git a/basic02-prog-by-name/xdp_loader.c b/basic02-prog-by-name/xdp_loader.c index 00e8585b..2904b016 100644 --- a/basic02-prog-by-name/xdp_loader.c +++ b/basic02-prog-by-name/xdp_loader.c @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 */ static const char *__doc__ = "XDP loader\n" " - Specify BPF-object --filename to load \n" - " - and select BPF section --progname name to XDP-attach to --dev\n"; + " - and select BPF program --progname name to XDP-attach to --dev\n"; #include #include @@ -17,6 +17,7 @@ static const char *__doc__ = "XDP loader\n" #include /* depend on kernel-headers installed */ #include "../common/common_params.h" +#include "../common/common_user_bpf_xdp.h" static const char *default_filename = "xdp_prog_kern.o"; static const char *default_progname = "xdp_pass_func"; @@ -37,14 +38,14 @@ static const struct option_wrapper long_options[] = { {{"auto-mode", no_argument, NULL, 'A' }, "Auto-detect SKB or native mode"}, - {{"offload-mode",no_argument, NULL, 3 }, + {{"offload-mode",no_argument, NULL, 3 }, "Hardware offload XDP program to NIC"}, - {{"force", no_argument, NULL, 'F' }, - "Force install, replacing existing program on interface"}, + {{"unload", required_argument, NULL, 'U' }, + "Unload XDP program instead of loading", ""}, - {{"unload", no_argument, NULL, 'U' }, - "Unload XDP program instead of loading"}, + {{"unload-all", no_argument, NULL, 4 }, + "Unload all XDP programs on device"}, {{"quiet", no_argument, NULL, 'q' }, "Quiet mode (no output)"}, @@ -58,61 +59,6 @@ static const struct option_wrapper long_options[] = { {{0, 0, NULL, 0 }, NULL, false} }; -/* Lesson#1: More advanced load_bpf_object_file and bpf_object */ - - -/* Lesson#2: This is a central piece of this lesson: - * - Notice how BPF-ELF obj can have several programs - * - Find by program name via: xdp_program__create - */ -struct xdp_program *__load_bpf_and_xdp_attach(struct config *cfg) -{ - /* In next assignment this will be moved into ../common/ */ - int prog_fd = -1; - int err; - - DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts); - DECLARE_LIBXDP_OPTS(xdp_program_opts, xdp_opts, 0); - - xdp_opts.open_filename = cfg->filename; - xdp_opts.prog_name = cfg->progname; - xdp_opts.opts = &opts; - - /* If flags indicate hardware offload, supply ifindex */ - /* if (cfg->xdp_flags & XDP_FLAGS_HW_MODE) */ - /* offload_ifindex = cfg->ifindex; */ - - struct xdp_program *prog = xdp_program__create(&xdp_opts); - err = libxdp_get_error(prog); - if (err) { - char errmsg[1024]; - libxdp_strerror(err, errmsg, sizeof(errmsg)); - fprintf(stderr, "ERR: loading program: %s\n", errmsg); - exit(EXIT_FAIL_BPF); - } - - /* At this point: All XDP/BPF programs from the cfg->filename have been - * loaded into the kernel, and evaluated by the verifier. Only one of - * these gets attached to XDP hook, the others will get freed once this - * process exit. - */ - - /* At this point: BPF-progs are (only) loaded by the kernel, and prog_fd - * is our select file-descriptor handle. Next step is attaching this FD - * to a kernel hook point, in this case XDP net_device link-level hook. - */ - err = xdp_program__attach(prog, cfg->ifindex, XDP_MODE_SKB, 0); - if (err) - exit(err); - - prog_fd = xdp_program__fd(prog); - if (prog_fd < 0) { - fprintf(stderr, "ERR: xdp_program__fd failed: %s\n", strerror(errno)); - exit(EXIT_FAIL_BPF); - } - - return prog; -} static void list_avail_progs(struct bpf_object *obj) { @@ -122,20 +68,26 @@ static void list_avail_progs(struct bpf_object *obj) bpf_object__name(obj)); bpf_object__for_each_program(pos, obj) { - printf("*** %s\n", bpf_program__name(pos)); - printf("*** %d\n", bpf_program__type(pos)); if (bpf_program__type(pos) == BPF_PROG_TYPE_XDP) printf(" %s\n", bpf_program__name(pos)); } } +/* Lesson#1: This is a central piece of this lesson: + * - Notice how BPF-ELF obj can have several programs + * - Find by program name via: xdp_program__create + */ int main(int argc, char **argv) { struct config cfg = { - .xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST | XDP_FLAGS_DRV_MODE, - .ifindex = -1, - .do_unload = false, + .attach_mode = XDP_MODE_NATIVE, + .ifindex = -1, + .do_unload = false, }; + struct bpf_object *obj; + char errmsg[1024]; + int err; + /* Set default BPF-ELF object file and BPF program name */ strncpy(cfg.filename, default_filename, sizeof(cfg.filename)); strncpy(cfg.progname, default_progname, sizeof(cfg.progname)); @@ -148,22 +100,64 @@ int main(int argc, char **argv) usage(argv[0], __doc__, long_options, (argc == 1)); return EXIT_FAIL_OPTION; } - /* if (cfg.do_unload) */ - /* return xdp_link_detach(cfg.ifindex, cfg.xdp_flags, 0); */ - - struct xdp_program *prog = __load_bpf_and_xdp_attach(&cfg); - if (!prog) - return EXIT_FAIL_BPF; + /* Unload a program by prog_id, or + * unload all programs on net device + */ + if (cfg.do_unload || cfg.unload_all) { + err = do_unload(&cfg); + if (err) { + libxdp_strerror(err, errmsg, sizeof(errmsg)); + fprintf(stderr, "Couldn't unload XDP program %s: %s\n", + cfg.progname, errmsg); + return err; + } + + printf("Success: Unloading XDP prog name: %s\n", cfg.progname); + return EXIT_OK; + } + /* Open a BPF object file */ + DECLARE_LIBBPF_OPTS(bpf_object_open_opts, bpf_opts); + obj = bpf_object__open_file(cfg.filename, &bpf_opts); + err = libbpf_get_error(obj); + if (err) { + libxdp_strerror(err, errmsg, sizeof(errmsg)); + fprintf(stderr, "Couldn't open BPF object file %s: %s\n", + cfg.filename, errmsg); + return err; + } + + /* List available programs */ if (verbose) - list_avail_progs(xdp_program__bpf_obj(prog)); + list_avail_progs(obj); + + DECLARE_LIBXDP_OPTS(xdp_program_opts, xdp_opts, + .obj = obj, + .prog_name = cfg.progname); + struct xdp_program *prog = xdp_program__create(&xdp_opts); + err = libxdp_get_error(prog); + if (err) { + libxdp_strerror(err, errmsg, sizeof(errmsg)); + fprintf(stderr, "ERR: loading program %s: %s\n", cfg.progname, errmsg); + exit(EXIT_FAIL_BPF); + } + + /* At this point: BPF-progs are (only) loaded by the kernel, and prog + * is our selected program handle. Next step is attaching this prog + * to a kernel hook point, in this case XDP net_device link-level hook. + */ + err = xdp_program__attach(prog, cfg.ifindex, cfg.attach_mode, 0); + if (err) { + perror("xdp_program__attach"); + exit(err); + } if (verbose) { - printf("Success: Loaded BPF-object(%s) and used section(%s)\n", + printf("Success: Loaded BPF-object(%s) and used program(%s)\n", cfg.filename, cfg.progname); - printf(" - XDP prog attached on device:%s(ifindex:%d)\n", - cfg.ifname, cfg.ifindex); + printf(" - XDP prog id:%d attached on device:%s(ifindex:%d)\n", + xdp_program__id(prog), cfg.ifname, cfg.ifindex); } - /* Other BPF section programs will get freed on exit */ + /* Other BPF programs from ELF file will get freed on exit */ return EXIT_OK; } diff --git a/basic03-map-counter/xdp_load_and_stats.c b/basic03-map-counter/xdp_load_and_stats.c index d20c8302..bc7ab181 100644 --- a/basic03-map-counter/xdp_load_and_stats.c +++ b/basic03-map-counter/xdp_load_and_stats.c @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 */ static const char *__doc__ = "XDP loader and stats program\n" - " - Allows selecting BPF section --progname name to XDP-attach to --dev\n"; + " - Allows selecting BPF --progname name to XDP-attach to --dev\n"; #include #include @@ -42,11 +42,11 @@ static const struct option_wrapper long_options[] = { {{"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", required_argument, NULL, 'U' }, + "Unload XDP program instead of loading", ""}, - {{"unload", no_argument, NULL, 'U' }, - "Unload XDP program instead of loading"}, + {{"unload-all", no_argument, NULL, 4 }, + "Unload all XDP programs on device"}, {{"quiet", no_argument, NULL, 'q' }, "Quiet mode (no output)"}, @@ -274,10 +274,10 @@ int main(int argc, char **argv) struct xdp_program *program; int stats_map_fd; int interval = 2; + char errmsg[1024]; int err; struct config cfg = { - .xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST | XDP_FLAGS_DRV_MODE, .ifindex = -1, .do_unload = false, }; @@ -293,8 +293,22 @@ int main(int argc, char **argv) usage(argv[0], __doc__, long_options, (argc == 1)); return EXIT_FAIL_OPTION; } - /* if (cfg.do_unload) */ - /* return xdp_link_detach(cfg.ifindex, cfg.xdp_flags, 0); */ + + /* Unload a program by prog_id, or + * unload all programs on net device + */ + if (cfg.do_unload || cfg.unload_all) { + err = do_unload(&cfg); + if (err) { + libxdp_strerror(err, errmsg, sizeof(errmsg)); + fprintf(stderr, "Couldn't unload XDP program %d: %s\n", + cfg.prog_id, errmsg); + return err; + } + + printf("Success: Unloading XDP prog name: %s\n", cfg.progname); + return EXIT_OK; + } program = load_bpf_and_xdp_attach(&cfg); if (!program) @@ -303,8 +317,8 @@ int main(int argc, char **argv) if (verbose) { printf("Success: Loaded BPF-object(%s) and used section(%s)\n", cfg.filename, cfg.progname); - printf(" - XDP prog attached on device:%s(ifindex:%d)\n", - cfg.ifname, cfg.ifindex); + printf(" - XDP prog id:%d attached on device:%s(ifindex:%d)\n", + xdp_program__id(program), cfg.ifname, cfg.ifindex); } /* Lesson#3: Locate map file descriptor */ diff --git a/basic04-pinning-maps/xdp_loader.c b/basic04-pinning-maps/xdp_loader.c index 96e124aa..457afbc5 100644 --- a/basic04-pinning-maps/xdp_loader.c +++ b/basic04-pinning-maps/xdp_loader.c @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 */ static const char *__doc__ = "XDP loader\n" - " - Allows selecting BPF section --progname name to XDP-attach to --dev\n"; + " - Allows selecting BPF program --progname name to XDP-attach to --dev\n"; #include #include @@ -118,9 +118,9 @@ int main(int argc, char **argv) int err; struct config cfg = { - .xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST | XDP_FLAGS_DRV_MODE, - .ifindex = -1, - .do_unload = false, + .attach_mode = XDP_MODE_NATIVE, + .ifindex = -1, + .do_unload = false, }; /* Set default BPF-ELF object file and BPF program name */ strncpy(cfg.filename, default_filename, sizeof(cfg.filename)); @@ -143,7 +143,7 @@ int main(int argc, char **argv) return EXIT_FAIL_BPF; if (verbose) { - printf("Success: Loaded BPF-object(%s) and used section(%s)\n", + printf("Success: Loaded BPF-object(%s) and used program(%s)\n", cfg.filename, cfg.progname); printf(" - XDP prog attached on device:%s(ifindex:%d)\n", cfg.ifname, cfg.ifindex); diff --git a/common/common_params.c b/common/common_params.c index 32cedc62..53a90c30 100644 --- a/common/common_params.c +++ b/common/common_params.c @@ -139,9 +139,6 @@ void parse_cmdline_args(int argc, char **argv, case 3: /* --offload-mode */ cfg->attach_mode = XDP_MODE_HW; break; - case 'F': - cfg->xdp_flags &= ~XDP_FLAGS_UPDATE_IF_NOEXIST; - break; case 'M': cfg->reuse_maps = true; break; diff --git a/common/common_user_bpf_xdp.c b/common/common_user_bpf_xdp.c index 9831c57a..85ef31f8 100644 --- a/common/common_user_bpf_xdp.c +++ b/common/common_user_bpf_xdp.c @@ -118,7 +118,7 @@ struct xdp_program *load_bpf_and_xdp_attach(struct config *cfg) * is our select file-descriptor handle. Next step is attaching this FD * to a kernel hook point, in this case XDP net_device link-level hook. */ - err = xdp_program__attach(prog, cfg->ifindex, XDP_MODE_SKB, 0); + err = xdp_program__attach(prog, cfg->ifindex, cfg->attach_mode, 0); if (err) exit(err); diff --git a/tracing04-xdp-tcpdump/xdp_sample_pkts_user.c b/tracing04-xdp-tcpdump/xdp_sample_pkts_user.c index 2c3ce045..bf2a5398 100644 --- a/tracing04-xdp-tcpdump/xdp_sample_pkts_user.c +++ b/tracing04-xdp-tcpdump/xdp_sample_pkts_user.c @@ -41,7 +41,6 @@ static pcap_t* pd; static pcap_dumper_t* pdumper; static unsigned int pcap_pkts; static struct config cfg = { - .xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST | XDP_FLAGS_DRV_MODE, .ifindex = -1, }; static struct xdp_program *prog; @@ -169,7 +168,7 @@ int main(int argc, char **argv) fprintf(stderr, "ERR: loading program: %s\n", errmsg); return err; } - err = xdp_program__attach(prog, cfg.ifindex, cfg.xdp_flags, 0); + err = xdp_program__attach(prog, cfg.ifindex, cfg.attach_mode, 0); if (err) { libxdp_strerror(err, errmsg, sizeof(errmsg)); fprintf(stderr, "Couldn't attach XDP program on iface '%s' : %s (%d)\n", @@ -215,6 +214,6 @@ int main(int argc, char **argv) return 0; out: - xdp_program__detach(prog, cfg.ifindex, cfg.xdp_flags, 0); + xdp_program__detach(prog, cfg.ifindex, cfg.attach_mode, 0); return -1; }