linux/samples/bpf/xdp_redirect_map_user.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/* Copyright (c) 2017 Covalent IO, Inc. http://covalent.io
   3 */
   4static const char *__doc__ =
   5"XDP redirect tool, using BPF_MAP_TYPE_DEVMAP\n"
   6"Usage: xdp_redirect_map <IFINDEX|IFNAME>_IN <IFINDEX|IFNAME>_OUT\n";
   7
   8#include <linux/bpf.h>
   9#include <linux/if_link.h>
  10#include <assert.h>
  11#include <errno.h>
  12#include <signal.h>
  13#include <stdio.h>
  14#include <stdlib.h>
  15#include <stdbool.h>
  16#include <string.h>
  17#include <net/if.h>
  18#include <unistd.h>
  19#include <libgen.h>
  20#include <getopt.h>
  21#include <bpf/bpf.h>
  22#include <bpf/libbpf.h>
  23#include "bpf_util.h"
  24#include "xdp_sample_user.h"
  25#include "xdp_redirect_map.skel.h"
  26
  27static int mask = SAMPLE_RX_CNT | SAMPLE_REDIRECT_ERR_MAP_CNT |
  28                  SAMPLE_EXCEPTION_CNT | SAMPLE_DEVMAP_XMIT_CNT_MULTI;
  29
  30DEFINE_SAMPLE_INIT(xdp_redirect_map);
  31
  32static const struct option long_options[] = {
  33        { "help", no_argument, NULL, 'h' },
  34        { "skb-mode", no_argument, NULL, 'S' },
  35        { "force", no_argument, NULL, 'F' },
  36        { "load-egress", no_argument, NULL, 'X' },
  37        { "stats", no_argument, NULL, 's' },
  38        { "interval", required_argument, NULL, 'i' },
  39        { "verbose", no_argument, NULL, 'v' },
  40        {}
  41};
  42
  43int main(int argc, char **argv)
  44{
  45        struct bpf_devmap_val devmap_val = {};
  46        bool xdp_devmap_attached = false;
  47        struct xdp_redirect_map *skel;
  48        char str[2 * IF_NAMESIZE + 1];
  49        char ifname_out[IF_NAMESIZE];
  50        struct bpf_map *tx_port_map;
  51        char ifname_in[IF_NAMESIZE];
  52        int ifindex_in, ifindex_out;
  53        unsigned long interval = 2;
  54        int ret = EXIT_FAIL_OPTION;
  55        struct bpf_program *prog;
  56        bool generic = false;
  57        bool force = false;
  58        bool tried = false;
  59        bool error = true;
  60        int opt, key = 0;
  61
  62        while ((opt = getopt_long(argc, argv, "hSFXi:vs",
  63                                  long_options, NULL)) != -1) {
  64                switch (opt) {
  65                case 'S':
  66                        generic = true;
  67                        /* devmap_xmit tracepoint not available */
  68                        mask &= ~(SAMPLE_DEVMAP_XMIT_CNT |
  69                                  SAMPLE_DEVMAP_XMIT_CNT_MULTI);
  70                        break;
  71                case 'F':
  72                        force = true;
  73                        break;
  74                case 'X':
  75                        xdp_devmap_attached = true;
  76                        break;
  77                case 'i':
  78                        interval = strtoul(optarg, NULL, 0);
  79                        break;
  80                case 'v':
  81                        sample_switch_mode();
  82                        break;
  83                case 's':
  84                        mask |= SAMPLE_REDIRECT_MAP_CNT;
  85                        break;
  86                case 'h':
  87                        error = false;
  88                default:
  89                        sample_usage(argv, long_options, __doc__, mask, error);
  90                        return ret;
  91                }
  92        }
  93
  94        if (argc <= optind + 1) {
  95                sample_usage(argv, long_options, __doc__, mask, true);
  96                goto end;
  97        }
  98
  99        ifindex_in = if_nametoindex(argv[optind]);
 100        if (!ifindex_in)
 101                ifindex_in = strtoul(argv[optind], NULL, 0);
 102
 103        ifindex_out = if_nametoindex(argv[optind + 1]);
 104        if (!ifindex_out)
 105                ifindex_out = strtoul(argv[optind + 1], NULL, 0);
 106
 107        if (!ifindex_in || !ifindex_out) {
 108                fprintf(stderr, "Bad interface index or name\n");
 109                sample_usage(argv, long_options, __doc__, mask, true);
 110                goto end;
 111        }
 112
 113        skel = xdp_redirect_map__open();
 114        if (!skel) {
 115                fprintf(stderr, "Failed to xdp_redirect_map__open: %s\n",
 116                        strerror(errno));
 117                ret = EXIT_FAIL_BPF;
 118                goto end;
 119        }
 120
 121        ret = sample_init_pre_load(skel);
 122        if (ret < 0) {
 123                fprintf(stderr, "Failed to sample_init_pre_load: %s\n", strerror(-ret));
 124                ret = EXIT_FAIL_BPF;
 125                goto end_destroy;
 126        }
 127
 128        /* Load 2nd xdp prog on egress. */
 129        if (xdp_devmap_attached) {
 130                ret = get_mac_addr(ifindex_out, skel->rodata->tx_mac_addr);
 131                if (ret < 0) {
 132                        fprintf(stderr, "Failed to get interface %d mac address: %s\n",
 133                                ifindex_out, strerror(-ret));
 134                        ret = EXIT_FAIL;
 135                        goto end_destroy;
 136                }
 137        }
 138
 139        skel->rodata->from_match[0] = ifindex_in;
 140        skel->rodata->to_match[0] = ifindex_out;
 141
 142        ret = xdp_redirect_map__load(skel);
 143        if (ret < 0) {
 144                fprintf(stderr, "Failed to xdp_redirect_map__load: %s\n",
 145                        strerror(errno));
 146                ret = EXIT_FAIL_BPF;
 147                goto end_destroy;
 148        }
 149
 150        ret = sample_init(skel, mask);
 151        if (ret < 0) {
 152                fprintf(stderr, "Failed to initialize sample: %s\n", strerror(-ret));
 153                ret = EXIT_FAIL;
 154                goto end_destroy;
 155        }
 156
 157        prog = skel->progs.xdp_redirect_map_native;
 158        tx_port_map = skel->maps.tx_port_native;
 159restart:
 160        if (sample_install_xdp(prog, ifindex_in, generic, force) < 0) {
 161                /* First try with struct bpf_devmap_val as value for generic
 162                 * mode, then fallback to sizeof(int) for older kernels.
 163                 */
 164                fprintf(stderr,
 165                        "Trying fallback to sizeof(int) as value_size for devmap in generic mode\n");
 166                if (generic && !tried) {
 167                        prog = skel->progs.xdp_redirect_map_general;
 168                        tx_port_map = skel->maps.tx_port_general;
 169                        tried = true;
 170                        goto restart;
 171                }
 172                ret = EXIT_FAIL_XDP;
 173                goto end_destroy;
 174        }
 175
 176        /* Loading dummy XDP prog on out-device */
 177        sample_install_xdp(skel->progs.xdp_redirect_dummy_prog, ifindex_out, generic, force);
 178
 179        devmap_val.ifindex = ifindex_out;
 180        if (xdp_devmap_attached)
 181                devmap_val.bpf_prog.fd = bpf_program__fd(skel->progs.xdp_redirect_map_egress);
 182        ret = bpf_map_update_elem(bpf_map__fd(tx_port_map), &key, &devmap_val, 0);
 183        if (ret < 0) {
 184                fprintf(stderr, "Failed to update devmap value: %s\n",
 185                        strerror(errno));
 186                ret = EXIT_FAIL_BPF;
 187                goto end_destroy;
 188        }
 189
 190        ret = EXIT_FAIL;
 191        if (!if_indextoname(ifindex_in, ifname_in)) {
 192                fprintf(stderr, "Failed to if_indextoname for %d: %s\n", ifindex_in,
 193                        strerror(errno));
 194                goto end_destroy;
 195        }
 196
 197        if (!if_indextoname(ifindex_out, ifname_out)) {
 198                fprintf(stderr, "Failed to if_indextoname for %d: %s\n", ifindex_out,
 199                        strerror(errno));
 200                goto end_destroy;
 201        }
 202
 203        safe_strncpy(str, get_driver_name(ifindex_in), sizeof(str));
 204        printf("Redirecting from %s (ifindex %d; driver %s) to %s (ifindex %d; driver %s)\n",
 205               ifname_in, ifindex_in, str, ifname_out, ifindex_out, get_driver_name(ifindex_out));
 206        snprintf(str, sizeof(str), "%s->%s", ifname_in, ifname_out);
 207
 208        ret = sample_run(interval, NULL, NULL);
 209        if (ret < 0) {
 210                fprintf(stderr, "Failed during sample run: %s\n", strerror(-ret));
 211                ret = EXIT_FAIL;
 212                goto end_destroy;
 213        }
 214        ret = EXIT_OK;
 215end_destroy:
 216        xdp_redirect_map__destroy(skel);
 217end:
 218        sample_exit(ret);
 219}
 220