Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /* Copyright (c) 2016 John Fastabend <john.r.fastabend@intel.com>
0003  */
0004 static const char *__doc__ =
0005 "XDP redirect tool, using bpf_redirect helper\n"
0006 "Usage: xdp_redirect <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.skel.h"
0026 
0027 static int mask = SAMPLE_RX_CNT | SAMPLE_REDIRECT_ERR_CNT |
0028           SAMPLE_EXCEPTION_CNT | SAMPLE_DEVMAP_XMIT_CNT_MULTI;
0029 
0030 DEFINE_SAMPLE_INIT(xdp_redirect);
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     {"stats",   no_argument,        NULL, 's' },
0037     {"interval",    required_argument,  NULL, 'i' },
0038     {"verbose", no_argument,        NULL, 'v' },
0039     {}
0040 };
0041 
0042 int main(int argc, char **argv)
0043 {
0044     int ifindex_in, ifindex_out, opt;
0045     char str[2 * IF_NAMESIZE + 1];
0046     char ifname_out[IF_NAMESIZE];
0047     char ifname_in[IF_NAMESIZE];
0048     int ret = EXIT_FAIL_OPTION;
0049     unsigned long interval = 2;
0050     struct xdp_redirect *skel;
0051     bool generic = false;
0052     bool force = false;
0053     bool error = true;
0054 
0055     while ((opt = getopt_long(argc, argv, "hSFi:vs",
0056                   long_options, NULL)) != -1) {
0057         switch (opt) {
0058         case 'S':
0059             generic = true;
0060             mask &= ~(SAMPLE_DEVMAP_XMIT_CNT |
0061                   SAMPLE_DEVMAP_XMIT_CNT_MULTI);
0062             break;
0063         case 'F':
0064             force = true;
0065             break;
0066         case 'i':
0067             interval = strtoul(optarg, NULL, 0);
0068             break;
0069         case 'v':
0070             sample_switch_mode();
0071             break;
0072         case 's':
0073             mask |= SAMPLE_REDIRECT_CNT;
0074             break;
0075         case 'h':
0076             error = false;
0077         default:
0078             sample_usage(argv, long_options, __doc__, mask, error);
0079             return ret;
0080         }
0081     }
0082 
0083     if (argc <= optind + 1) {
0084         sample_usage(argv, long_options, __doc__, mask, true);
0085         return ret;
0086     }
0087 
0088     ifindex_in = if_nametoindex(argv[optind]);
0089     if (!ifindex_in)
0090         ifindex_in = strtoul(argv[optind], NULL, 0);
0091 
0092     ifindex_out = if_nametoindex(argv[optind + 1]);
0093     if (!ifindex_out)
0094         ifindex_out = strtoul(argv[optind + 1], NULL, 0);
0095 
0096     if (!ifindex_in || !ifindex_out) {
0097         fprintf(stderr, "Bad interface index or name\n");
0098         sample_usage(argv, long_options, __doc__, mask, true);
0099         goto end;
0100     }
0101 
0102     skel = xdp_redirect__open();
0103     if (!skel) {
0104         fprintf(stderr, "Failed to xdp_redirect__open: %s\n", strerror(errno));
0105         ret = EXIT_FAIL_BPF;
0106         goto end;
0107     }
0108 
0109     ret = sample_init_pre_load(skel);
0110     if (ret < 0) {
0111         fprintf(stderr, "Failed to sample_init_pre_load: %s\n", strerror(-ret));
0112         ret = EXIT_FAIL_BPF;
0113         goto end_destroy;
0114     }
0115 
0116     skel->rodata->from_match[0] = ifindex_in;
0117     skel->rodata->to_match[0] = ifindex_out;
0118     skel->rodata->ifindex_out = ifindex_out;
0119 
0120     ret = xdp_redirect__load(skel);
0121     if (ret < 0) {
0122         fprintf(stderr, "Failed to xdp_redirect__load: %s\n", strerror(errno));
0123         ret = EXIT_FAIL_BPF;
0124         goto end_destroy;
0125     }
0126 
0127     ret = sample_init(skel, mask);
0128     if (ret < 0) {
0129         fprintf(stderr, "Failed to initialize sample: %s\n", strerror(-ret));
0130         ret = EXIT_FAIL;
0131         goto end_destroy;
0132     }
0133 
0134     ret = EXIT_FAIL_XDP;
0135     if (sample_install_xdp(skel->progs.xdp_redirect_prog, ifindex_in,
0136                    generic, force) < 0)
0137         goto end_destroy;
0138 
0139     /* Loading dummy XDP prog on out-device */
0140     sample_install_xdp(skel->progs.xdp_redirect_dummy_prog, ifindex_out,
0141                generic, force);
0142 
0143     ret = EXIT_FAIL;
0144     if (!if_indextoname(ifindex_in, ifname_in)) {
0145         fprintf(stderr, "Failed to if_indextoname for %d: %s\n", ifindex_in,
0146             strerror(errno));
0147         goto end_destroy;
0148     }
0149 
0150     if (!if_indextoname(ifindex_out, ifname_out)) {
0151         fprintf(stderr, "Failed to if_indextoname for %d: %s\n", ifindex_out,
0152             strerror(errno));
0153         goto end_destroy;
0154     }
0155 
0156     safe_strncpy(str, get_driver_name(ifindex_in), sizeof(str));
0157     printf("Redirecting from %s (ifindex %d; driver %s) to %s (ifindex %d; driver %s)\n",
0158            ifname_in, ifindex_in, str, ifname_out, ifindex_out, get_driver_name(ifindex_out));
0159     snprintf(str, sizeof(str), "%s->%s", ifname_in, ifname_out);
0160 
0161     ret = sample_run(interval, NULL, NULL);
0162     if (ret < 0) {
0163         fprintf(stderr, "Failed during sample run: %s\n", strerror(-ret));
0164         ret = EXIT_FAIL;
0165         goto end_destroy;
0166     }
0167     ret = EXIT_OK;
0168 end_destroy:
0169     xdp_redirect__destroy(skel);
0170 end:
0171     sample_exit(ret);
0172 }