diff options
Diffstat (limited to 'src/xdp/xdp_prog_user.c')
-rw-r--r-- | src/xdp/xdp_prog_user.c | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/src/xdp/xdp_prog_user.c b/src/xdp/xdp_prog_user.c new file mode 100644 index 000000000..c47d2977d --- /dev/null +++ b/src/xdp/xdp_prog_user.c @@ -0,0 +1,182 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +static const char *__doc__ = "XDP redirect helper\n" + " - Allows to populate/query tx_port and redirect_params maps\n"; + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <getopt.h> +#include <stdbool.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_ether.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" + +#include "common/xdp_stats_kern_user.h" + +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}, + + {{"redirect-dev", required_argument, NULL, 'r' }, + "Redirect to device <ifname>", "<ifname>", true}, + + {{"src-mac", required_argument, NULL, 'L' }, + "Source MAC address of <dev>", "<mac>", true }, + + {{"dest-mac", required_argument, NULL, 'R' }, + "Destination MAC address of <redirect-dev>", "<mac>", true }, + + {{"quiet", no_argument, NULL, 'q' }, + "Quiet mode (no output)"}, + + {{0, 0, NULL, 0 }, NULL, false} +}; + +static int parse_u8(char *str, unsigned char *x) +{ + unsigned long z; + + z = strtoul(str, 0, 16); + if (z > 0xff) + return -1; + + if (x) + *x = z; + + return 0; +} + +static int parse_mac(char *str, unsigned char mac[ETH_ALEN]) +{ + if (parse_u8(str, &mac[0]) < 0) + return -1; + if (parse_u8(str + 3, &mac[1]) < 0) + return -1; + if (parse_u8(str + 6, &mac[2]) < 0) + return -1; + if (parse_u8(str + 9, &mac[3]) < 0) + return -1; + if (parse_u8(str + 12, &mac[4]) < 0) + return -1; + if (parse_u8(str + 15, &mac[5]) < 0) + return -1; + + return 0; +} + +static int write_iface_params(int map_fd, unsigned char *src, unsigned char *dest) +{ + if (bpf_map_update_elem(map_fd, src, dest, 0) < 0) { + fprintf(stderr, + "WARN: Failed to update bpf map file: err(%d):%s\n", + errno, strerror(errno)); + return -1; + } + + printf("forward: %02x:%02x:%02x:%02x:%02x:%02x -> %02x:%02x:%02x:%02x:%02x:%02x\n", + src[0], src[1], src[2], src[3], src[4], src[5], + dest[0], dest[1], dest[2], dest[3], dest[4], dest[5] + ); + + return 0; +} + +#ifndef PATH_MAX +#define PATH_MAX 4096 +#endif + +const char *pin_basedir = "/sys/fs/bpf"; + +int main(int argc, char **argv) +{ + int i; + int len; + int map_fd; + bool redirect_map; + char pin_dir[PATH_MAX]; + unsigned char src[ETH_ALEN]; + unsigned char dest[ETH_ALEN]; + + struct config cfg = { + .ifindex = -1, + .redirect_ifindex = -1, + }; + + /* Cmdline options can change progsec */ + parse_cmdline_args(argc, argv, long_options, &cfg, __doc__); + + redirect_map = (cfg.ifindex > 0) && (cfg.redirect_ifindex > 0); + + if (cfg.redirect_ifindex > 0 && cfg.ifindex == -1) { + fprintf(stderr, "ERR: required option --dev missing\n\n"); + usage(argv[0], __doc__, long_options, (argc == 1)); + return EXIT_FAIL_OPTION; + } + + 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; + } + + if (parse_mac(cfg.src_mac, src) < 0) { + fprintf(stderr, "ERR: can't parse mac address %s\n", cfg.src_mac); + return EXIT_FAIL_OPTION; + } + + if (parse_mac(cfg.dest_mac, dest) < 0) { + fprintf(stderr, "ERR: can't parse mac address %s\n", cfg.dest_mac); + return EXIT_FAIL_OPTION; + } + + /* Open the tx_port map corresponding to the cfg.ifname interface */ + map_fd = open_bpf_map_file(pin_dir, "tx_port", NULL); + if (map_fd < 0) { + return EXIT_FAIL_BPF; + } + + printf("map dir: %s\n", pin_dir); + + if (redirect_map) { + /* setup a virtual port for the static redirect */ + i = 0; + bpf_map_update_elem(map_fd, &i, &cfg.redirect_ifindex, 0); + printf("redirect from ifnum=%d to ifnum=%d\n", cfg.ifindex, cfg.redirect_ifindex); + + /* Open the redirect_params map */ + map_fd = open_bpf_map_file(pin_dir, "redirect_params", NULL); + if (map_fd < 0) { + return EXIT_FAIL_BPF; + } + + /* Setup the mapping containing MAC addresses */ + if (write_iface_params(map_fd, src, dest) < 0) { + fprintf(stderr, "can't write iface params\n"); + return 1; + } + } else { + /* setup 1-1 mapping for the dynamic router */ + for (i = 1; i < 256; ++i) + bpf_map_update_elem(map_fd, &i, &i, 0); + } + + return EXIT_OK; +} |