0001
0002
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
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 }