Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /* Copyright (c) 2017 Covalent IO, Inc. http://covalent.io
0003  */
0004 static const char *__doc__ =
0005 "XDP redirect tool, using BPF_MAP_TYPE_DEVMAP\n"
0006 "Usage: xdp_redirect_map <IFINDEX|IFNAME>_IN <IFINDEX|IFNAME>_OUT\n";
0007 
0008 #include <linux/bpf.h>
0009 #include <linux/if_link.h>
0010 #include <assert.h>
0011 #include <errno.h>
0012 #include <signal.h>
0013 #include <stdio.h>
0014 #include <stdlib.h>
0015 #include <stdbool.h>
0016 #include <string.h>
0017 #include <net/if.h>
0018 #include <unistd.h>
0019 #include <libgen.h>
0020 #include <getopt.h>
0021 #include <bpf/bpf.h>
0022 #include <bpf/libbpf.h>
0023 #include "bpf_util.h"
0024 #include "xdp_sample_user.h"
0025 #include "xdp_redirect_map.skel.h"
0026 
0027 static int mask = SAMPLE_RX_CNT | SAMPLE_REDIRECT_ERR_MAP_CNT |
0028           SAMPLE_EXCEPTION_CNT | SAMPLE_DEVMAP_XMIT_CNT_MULTI;
0029 
0030 DEFINE_SAMPLE_INIT(xdp_redirect_map);
0031 
0032 static const struct option long_options[] = {
0033     { "help", no_argument, NULL, 'h' },
0034     { "skb-mode", no_argument, NULL, 'S' },
0035     { "force", no_argument, NULL, 'F' },
0036     { "load-egress", no_argument, NULL, 'X' },
0037     { "stats", no_argument, NULL, 's' },
0038     { "interval", required_argument, NULL, 'i' },
0039     { "verbose", no_argument, NULL, 'v' },
0040     {}
0041 };
0042 
0043 static int verbose = 0;
0044 
0045 int main(int argc, char **argv)
0046 {
0047     struct bpf_devmap_val devmap_val = {};
0048     bool xdp_devmap_attached = false;
0049     struct xdp_redirect_map *skel;
0050     char str[2 * IF_NAMESIZE + 1];
0051     char ifname_out[IF_NAMESIZE];
0052     struct bpf_map *tx_port_map;
0053     char ifname_in[IF_NAMESIZE];
0054     int ifindex_in, ifindex_out;
0055     unsigned long interval = 2;
0056     int ret = EXIT_FAIL_OPTION;
0057     struct bpf_program *prog;
0058     bool generic = false;
0059     bool force = false;
0060     bool tried = false;
0061     bool error = true;
0062     int opt, key = 0;
0063 
0064     while ((opt = getopt_long(argc, argv, "hSFXi:vs",
0065                   long_options, NULL)) != -1) {
0066         switch (opt) {
0067         case 'S':
0068             generic = true;
0069             /* devmap_xmit tracepoint not available */
0070             mask &= ~(SAMPLE_DEVMAP_XMIT_CNT |
0071                   SAMPLE_DEVMAP_XMIT_CNT_MULTI);
0072             break;
0073         case 'F':
0074             force = true;
0075             break;
0076         case 'X':
0077             xdp_devmap_attached = true;
0078             break;
0079         case 'i':
0080             interval = strtoul(optarg, NULL, 0);
0081             break;
0082         case 'v':
0083             sample_switch_mode();
0084             verbose = 1;
0085             break;
0086         case 's':
0087             mask |= SAMPLE_REDIRECT_MAP_CNT;
0088             break;
0089         case 'h':
0090             error = false;
0091         default:
0092             sample_usage(argv, long_options, __doc__, mask, error);
0093             return ret;
0094         }
0095     }
0096 
0097     if (argc <= optind + 1) {
0098         sample_usage(argv, long_options, __doc__, mask, true);
0099         goto end;
0100     }
0101 
0102     ifindex_in = if_nametoindex(argv[optind]);
0103     if (!ifindex_in)
0104         ifindex_in = strtoul(argv[optind], NULL, 0);
0105 
0106     ifindex_out = if_nametoindex(argv[optind + 1]);
0107     if (!ifindex_out)
0108         ifindex_out = strtoul(argv[optind + 1], NULL, 0);
0109 
0110     if (!ifindex_in || !ifindex_out) {
0111         fprintf(stderr, "Bad interface index or name\n");
0112         sample_usage(argv, long_options, __doc__, mask, true);
0113         goto end;
0114     }
0115 
0116     skel = xdp_redirect_map__open();
0117     if (!skel) {
0118         fprintf(stderr, "Failed to xdp_redirect_map__open: %s\n",
0119             strerror(errno));
0120         ret = EXIT_FAIL_BPF;
0121         goto end;
0122     }
0123 
0124     ret = sample_init_pre_load(skel);
0125     if (ret < 0) {
0126         fprintf(stderr, "Failed to sample_init_pre_load: %s\n", strerror(-ret));
0127         ret = EXIT_FAIL_BPF;
0128         goto end_destroy;
0129     }
0130 
0131     /* Load 2nd xdp prog on egress. */
0132     if (xdp_devmap_attached) {
0133         ret = get_mac_addr(ifindex_out, skel->rodata->tx_mac_addr);
0134         if (ret < 0) {
0135             fprintf(stderr, "Failed to get interface %d mac address: %s\n",
0136                 ifindex_out, strerror(-ret));
0137             ret = EXIT_FAIL;
0138             goto end_destroy;
0139         }
0140         if (verbose)
0141             printf("Egress ifindex:%d using src MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
0142                    ifindex_out,
0143                    skel->rodata->tx_mac_addr[0], skel->rodata->tx_mac_addr[1],
0144                    skel->rodata->tx_mac_addr[2], skel->rodata->tx_mac_addr[3],
0145                    skel->rodata->tx_mac_addr[4], skel->rodata->tx_mac_addr[5]);
0146     }
0147 
0148     skel->rodata->from_match[0] = ifindex_in;
0149     skel->rodata->to_match[0] = ifindex_out;
0150 
0151     ret = xdp_redirect_map__load(skel);
0152     if (ret < 0) {
0153         fprintf(stderr, "Failed to xdp_redirect_map__load: %s\n",
0154             strerror(errno));
0155         ret = EXIT_FAIL_BPF;
0156         goto end_destroy;
0157     }
0158 
0159     ret = sample_init(skel, mask);
0160     if (ret < 0) {
0161         fprintf(stderr, "Failed to initialize sample: %s\n", strerror(-ret));
0162         ret = EXIT_FAIL;
0163         goto end_destroy;
0164     }
0165 
0166     prog = skel->progs.xdp_redirect_map_native;
0167     tx_port_map = skel->maps.tx_port_native;
0168 restart:
0169     if (sample_install_xdp(prog, ifindex_in, generic, force) < 0) {
0170         /* First try with struct bpf_devmap_val as value for generic
0171          * mode, then fallback to sizeof(int) for older kernels.
0172          */
0173         fprintf(stderr,
0174             "Trying fallback to sizeof(int) as value_size for devmap in generic mode\n");
0175         if (generic && !tried) {
0176             prog = skel->progs.xdp_redirect_map_general;
0177             tx_port_map = skel->maps.tx_port_general;
0178             tried = true;
0179             goto restart;
0180         }
0181         ret = EXIT_FAIL_XDP;
0182         goto end_destroy;
0183     }
0184 
0185     /* Loading dummy XDP prog on out-device */
0186     sample_install_xdp(skel->progs.xdp_redirect_dummy_prog, ifindex_out, generic, force);
0187 
0188     devmap_val.ifindex = ifindex_out;
0189     if (xdp_devmap_attached)
0190         devmap_val.bpf_prog.fd = bpf_program__fd(skel->progs.xdp_redirect_map_egress);
0191     ret = bpf_map_update_elem(bpf_map__fd(tx_port_map), &key, &devmap_val, 0);
0192     if (ret < 0) {
0193         fprintf(stderr, "Failed to update devmap value: %s\n",
0194             strerror(errno));
0195         ret = EXIT_FAIL_BPF;
0196         goto end_destroy;
0197     }
0198 
0199     ret = EXIT_FAIL;
0200     if (!if_indextoname(ifindex_in, ifname_in)) {
0201         fprintf(stderr, "Failed to if_indextoname for %d: %s\n", ifindex_in,
0202             strerror(errno));
0203         goto end_destroy;
0204     }
0205 
0206     if (!if_indextoname(ifindex_out, ifname_out)) {
0207         fprintf(stderr, "Failed to if_indextoname for %d: %s\n", ifindex_out,
0208             strerror(errno));
0209         goto end_destroy;
0210     }
0211 
0212     safe_strncpy(str, get_driver_name(ifindex_in), sizeof(str));
0213     printf("Redirecting from %s (ifindex %d; driver %s) to %s (ifindex %d; driver %s)\n",
0214            ifname_in, ifindex_in, str, ifname_out, ifindex_out, get_driver_name(ifindex_out));
0215     snprintf(str, sizeof(str), "%s->%s", ifname_in, ifname_out);
0216 
0217     ret = sample_run(interval, NULL, NULL);
0218     if (ret < 0) {
0219         fprintf(stderr, "Failed during sample run: %s\n", strerror(-ret));
0220         ret = EXIT_FAIL;
0221         goto end_destroy;
0222     }
0223     ret = EXIT_OK;
0224 end_destroy:
0225     xdp_redirect_map__destroy(skel);
0226 end:
0227     sample_exit(ret);
0228 }