diff options
Diffstat (limited to 'src/xdp/utils')
-rw-r--r-- | src/xdp/utils/Makefile | 11 | ||||
-rw-r--r-- | src/xdp/utils/xdp_loader.c | 165 | ||||
-rw-r--r-- | src/xdp/utils/xdp_stats.c | 298 |
3 files changed, 0 insertions, 474 deletions
diff --git a/src/xdp/utils/Makefile b/src/xdp/utils/Makefile deleted file mode 100644 index 42d6e63e3..000000000 --- a/src/xdp/utils/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) - -USER_TARGETS := xdp_stats xdp_loader - -LIBBPF_DIR = ../libbpf/src/ -COMMON_DIR = ../common/ - -# Extend with another COMMON_OBJS -COMMON_OBJS += $(COMMON_DIR)/common_libbpf.o - -include $(COMMON_DIR)/common.mk diff --git a/src/xdp/utils/xdp_loader.c b/src/xdp/utils/xdp_loader.c deleted file mode 100644 index d3b05d0c0..000000000 --- a/src/xdp/utils/xdp_loader.c +++ /dev/null @@ -1,165 +0,0 @@ -/* 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; -} diff --git a/src/xdp/utils/xdp_stats.c b/src/xdp/utils/xdp_stats.c deleted file mode 100644 index f9fa7438f..000000000 --- a/src/xdp/utils/xdp_stats.c +++ /dev/null @@ -1,298 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -static const char *__doc__ = "XDP stats program\n" - " - Finding xdp_stats_map via --dev name info\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> -/* Lesson#1: this prog does not need to #include <bpf/libbpf.h> as it only uses - * the simple bpf-syscall wrappers, defined in libbpf #include<bpf/bpf.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/xdp_stats_kern_user.h" - -#include "../include/bpf_util.h" /* bpf_num_possible_cpus */ - -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}, - - {{"quiet", no_argument, NULL, 'q' }, - "Quiet mode (no output)"}, - - {{0, 0, NULL, 0 }} -}; - -#define NANOSEC_PER_SEC 1000000000 /* 10^9 */ -static __u64 gettime(void) -{ - struct timespec t; - int res; - - res = clock_gettime(CLOCK_MONOTONIC, &t); - if (res < 0) { - fprintf(stderr, "Error with gettimeofday! (%i)\n", res); - exit(EXIT_FAIL); - } - return (__u64) t.tv_sec * NANOSEC_PER_SEC + t.tv_nsec; -} - -struct record { - __u64 timestamp; - struct datarec total; /* defined in common_kern_user.h */ -}; - -struct stats_record { - struct record stats[XDP_ACTION_MAX]; -}; - -static double calc_period(struct record *r, struct record *p) -{ - double period_ = 0; - __u64 period = 0; - - period = r->timestamp - p->timestamp; - if (period > 0) - period_ = ((double) period / NANOSEC_PER_SEC); - - return period_; -} - -static void stats_print_header() -{ - /* Print stats "header" */ - printf("%-12s\n", "XDP-action"); -} - -static void stats_print(struct stats_record *stats_rec, - struct stats_record *stats_prev) -{ - struct record *rec, *prev; - __u64 packets, bytes; - double period; - double pps; /* packets per sec */ - double bps; /* bits per sec */ - int i; - - stats_print_header(); /* Print stats "header" */ - - /* Print for each XDP actions stats */ - for (i = 0; i < XDP_ACTION_MAX; i++) - { - char *fmt = "%-12s %'11lld pkts (%'10.0f pps)" - " %'11lld Kbytes (%'6.0f Mbits/s)" - " period:%f\n"; - const char *action = action2str(i); - - rec = &stats_rec->stats[i]; - prev = &stats_prev->stats[i]; - - period = calc_period(rec, prev); - if (period == 0) - return; - - packets = rec->total.rx_packets - prev->total.rx_packets; - pps = packets / period; - - bytes = rec->total.rx_bytes - prev->total.rx_bytes; - bps = (bytes * 8)/ period / 1000000; - - printf(fmt, action, rec->total.rx_packets, pps, - rec->total.rx_bytes / 1000 , bps, - period); - } - printf("\n"); -} - - -/* BPF_MAP_TYPE_ARRAY */ -void map_get_value_array(int fd, __u32 key, struct datarec *value) -{ - if ((bpf_map_lookup_elem(fd, &key, value)) != 0) { - fprintf(stderr, - "ERR: bpf_map_lookup_elem failed key:0x%X\n", key); - } -} - -/* BPF_MAP_TYPE_PERCPU_ARRAY */ -void map_get_value_percpu_array(int fd, __u32 key, struct datarec *value) -{ - /* For percpu maps, userspace gets a value per possible CPU */ - unsigned int nr_cpus = bpf_num_possible_cpus(); - struct datarec values[nr_cpus]; - __u64 sum_bytes = 0; - __u64 sum_pkts = 0; - int i; - - if ((bpf_map_lookup_elem(fd, &key, values)) != 0) { - fprintf(stderr, - "ERR: bpf_map_lookup_elem failed key:0x%X\n", key); - return; - } - - /* Sum values from each CPU */ - for (i = 0; i < nr_cpus; i++) { - sum_pkts += values[i].rx_packets; - sum_bytes += values[i].rx_bytes; - } - value->rx_packets = sum_pkts; - value->rx_bytes = sum_bytes; -} - -static bool map_collect(int fd, __u32 map_type, __u32 key, struct record *rec) -{ - struct datarec value; - - /* Get time as close as possible to reading map contents */ - rec->timestamp = gettime(); - - switch (map_type) { - case BPF_MAP_TYPE_ARRAY: - map_get_value_array(fd, key, &value); - break; - case BPF_MAP_TYPE_PERCPU_ARRAY: - map_get_value_percpu_array(fd, key, &value); - break; - default: - fprintf(stderr, "ERR: Unknown map_type(%u) cannot handle\n", - map_type); - return false; - break; - } - - rec->total.rx_packets = value.rx_packets; - rec->total.rx_bytes = value.rx_bytes; - return true; -} - -static void stats_collect(int map_fd, __u32 map_type, - struct stats_record *stats_rec) -{ - /* Collect all XDP actions stats */ - __u32 key; - - for (key = 0; key < XDP_ACTION_MAX; key++) { - map_collect(map_fd, map_type, key, &stats_rec->stats[key]); - } -} - -static int stats_poll(const char *pin_dir, int map_fd, __u32 id, - __u32 map_type, int interval) -{ - struct bpf_map_info info = {}; - struct stats_record prev, record = { 0 }; - int counter = 0; - - /* Trick to pretty printf with thousands separators use %' */ - setlocale(LC_NUMERIC, "en_US"); - - /* Get initial reading quickly */ - stats_collect(map_fd, map_type, &record); - usleep(1000000/4); - - while (1) { - prev = record; /* struct copy */ - - map_fd = open_bpf_map_file(pin_dir, "xdp_stats_map", &info); - if (map_fd < 0) { - return EXIT_FAIL_BPF; - } else if (id != info.id) { - printf("BPF map xdp_stats_map changed its ID, restarting\n"); - return 0; - } - - stats_collect(map_fd, map_type, &record); - stats_print(&record, &prev); - sleep(interval); - counter++; - if (counter > 1) { - return 0; - } - } - - return 0; -} - -#ifndef PATH_MAX -#define PATH_MAX 4096 -#endif - -const char *pin_basedir = "/sys/fs/bpf"; - -int main(int argc, char **argv) -{ - const struct bpf_map_info map_expect = { - .key_size = sizeof(__u32), - .value_size = sizeof(struct datarec), - .max_entries = XDP_ACTION_MAX, - }; - struct bpf_map_info info = { 0 }; - char pin_dir[PATH_MAX]; - int stats_map_fd; - int interval = 2; - int len, err; - - struct config cfg = { - .ifindex = -1, - .do_unload = false, - }; - - /* 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; - } - - /* Use the --dev name as subdir for finding pinned maps */ - len = snprintf(pin_dir, PATH_MAX, "%s/%s", pin_basedir, cfg.ifname); - if (len < 0) { - fprintf(stderr, "ERR: creating pin dirname\n"); - return EXIT_FAIL_OPTION; - } - - stats_map_fd = open_bpf_map_file(pin_dir, "xdp_stats_map", &info); - if (stats_map_fd < 0) { - return EXIT_FAIL_BPF; - } - - /* check map info, e.g. datarec is expected size */ - err = check_map_fd_info(&info, &map_expect); - if (err) { - fprintf(stderr, "ERR: map via FD not compatible\n"); - return err; - } - if (verbose) { - printf("\nCollecting stats from BPF map\n"); - printf(" - BPF map (bpf_map_type:%d) id:%d name:%s" - " key_size:%d value_size:%d max_entries:%d\n", - info.type, info.id, info.name, - info.key_size, info.value_size, info.max_entries - ); - } - - err = stats_poll(pin_dir, stats_map_fd, info.id, info.type, interval); - if (err < 0) - return err; - - return EXIT_OK; -} |