linux/samples/bpf/xdp_redirect_user.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/* Copyright (c) 2016 John Fastabend <john.r.fastabend@intel.com>
   3 */
   4static const char *__doc__ =
   5"XDP redirect tool, using bpf_redirect helper\n"
   6"Usage: xdp_redirect <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 <sys/resource.h>
  22#include <bpf/bpf.h>
  23#include <bpf/libbpf.h>
  24#include "bpf_util.h"
  25#include "xdp_sample_user.h"
  26#include "xdp_redirect.skel.h"
  27
  28static int mask = SAMPLE_RX_CNT | SAMPLE_REDIRECT_ERR_CNT |
  29                  SAMPLE_EXCEPTION_CNT | SAMPLE_DEVMAP_XMIT_CNT_MULTI;
  30
  31DEFINE_SAMPLE_INIT(xdp_redirect);
  32
  33static const struct option long_options[] = {
  34        {"help",        no_argument,            NULL, 'h' },
  35        {"skb-mode",    no_argument,            NULL, 'S' },
  36        {"force",       no_argument,            NULL, 'F' },
  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        int ifindex_in, ifindex_out, opt;
  46        char str[2 * IF_NAMESIZE + 1];
  47        char ifname_out[IF_NAMESIZE];
  48        char ifname_in[IF_NAMESIZE];
  49        int ret = EXIT_FAIL_OPTION;
  50        unsigned long interval = 2;
  51        struct xdp_redirect *skel;
  52        bool generic = false;
  53        bool force = false;
  54        bool error = true;
  55
  56        while ((opt = getopt_long(argc, argv, "hSFi:vs",
  57                                  long_options, NULL)) != -1) {
  58                switch (opt) {
  59                case 'S':
  60                        generic = true;
  61                        mask &= ~(SAMPLE_DEVMAP_XMIT_CNT |
  62                                  SAMPLE_DEVMAP_XMIT_CNT_MULTI);
  63                        break;
  64                case 'F':
  65                        force = true;
  66                        break;
  67                case 'i':
  68                        interval = strtoul(optarg, NULL, 0);
  69                        break;
  70                case 'v':
  71                        sample_switch_mode();
  72                        break;
  73                case 's':
  74                        mask |= SAMPLE_REDIRECT_CNT;
  75                        break;
  76                case 'h':
  77                        error = false;
  78                default:
  79                        sample_usage(argv, long_options, __doc__, mask, error);
  80                        return ret;
  81                }
  82        }
  83
  84        if (argc <= optind + 1) {
  85                sample_usage(argv, long_options, __doc__, mask, true);
  86                return ret;
  87        }
  88
  89        ifindex_in = if_nametoindex(argv[optind]);
  90        if (!ifindex_in)
  91                ifindex_in = strtoul(argv[optind], NULL, 0);
  92
  93        ifindex_out = if_nametoindex(argv[optind + 1]);
  94        if (!ifindex_out)
  95                ifindex_out = strtoul(argv[optind + 1], NULL, 0);
  96
  97        if (!ifindex_in || !ifindex_out) {
  98                fprintf(stderr, "Bad interface index or name\n");
  99                sample_usage(argv, long_options, __doc__, mask, true);
 100                goto end;
 101        }
 102
 103        skel = xdp_redirect__open();
 104        if (!skel) {
 105                fprintf(stderr, "Failed to xdp_redirect__open: %s\n", strerror(errno));
 106                ret = EXIT_FAIL_BPF;
 107                goto end;
 108        }
 109
 110        ret = sample_init_pre_load(skel);
 111        if (ret < 0) {
 112                fprintf(stderr, "Failed to sample_init_pre_load: %s\n", strerror(-ret));
 113                ret = EXIT_FAIL_BPF;
 114                goto end_destroy;
 115        }
 116
 117        skel->rodata->from_match[0] = ifindex_in;
 118        skel->rodata->to_match[0] = ifindex_out;
 119        skel->rodata->ifindex_out = ifindex_out;
 120
 121        ret = xdp_redirect__load(skel);
 122        if (ret < 0) {
 123                fprintf(stderr, "Failed to xdp_redirect__load: %s\n", strerror(errno));
 124                ret = EXIT_FAIL_BPF;
 125                goto end_destroy;
 126        }
 127
 128        ret = sample_init(skel, mask);
 129        if (ret < 0) {
 130                fprintf(stderr, "Failed to initialize sample: %s\n", strerror(-ret));
 131                ret = EXIT_FAIL;
 132                goto end_destroy;
 133        }
 134
 135        ret = EXIT_FAIL_XDP;
 136        if (sample_install_xdp(skel->progs.xdp_redirect_prog, ifindex_in,
 137                               generic, force) < 0)
 138                goto end_destroy;
 139
 140        /* Loading dummy XDP prog on out-device */
 141        sample_install_xdp(skel->progs.xdp_redirect_dummy_prog, ifindex_out,
 142                           generic, force);
 143
 144        ret = EXIT_FAIL;
 145        if (!if_indextoname(ifindex_in, ifname_in)) {
 146                fprintf(stderr, "Failed to if_indextoname for %d: %s\n", ifindex_in,
 147                        strerror(errno));
 148                goto end_destroy;
 149        }
 150
 151        if (!if_indextoname(ifindex_out, ifname_out)) {
 152                fprintf(stderr, "Failed to if_indextoname for %d: %s\n", ifindex_out,
 153                        strerror(errno));
 154                goto end_destroy;
 155        }
 156
 157        safe_strncpy(str, get_driver_name(ifindex_in), sizeof(str));
 158        printf("Redirecting from %s (ifindex %d; driver %s) to %s (ifindex %d; driver %s)\n",
 159               ifname_in, ifindex_in, str, ifname_out, ifindex_out, get_driver_name(ifindex_out));
 160        snprintf(str, sizeof(str), "%s->%s", ifname_in, ifname_out);
 161
 162        ret = sample_run(interval, NULL, NULL);
 163        if (ret < 0) {
 164                fprintf(stderr, "Failed during sample run: %s\n", strerror(-ret));
 165                ret = EXIT_FAIL;
 166                goto end_destroy;
 167        }
 168        ret = EXIT_OK;
 169end_destroy:
 170        xdp_redirect__destroy(skel);
 171end:
 172        sample_exit(ret);
 173}
 174