Merge git://github.com/Paragon-Software-Group/linux-ntfs3
[linux-2.6-microblaze.git] / samples / bpf / xdp_redirect_user.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Copyright (c) 2016 John Fastabend <john.r.fastabend@intel.com>
3  */
4 static 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
28 static int mask = SAMPLE_RX_CNT | SAMPLE_REDIRECT_ERR_CNT |
29                   SAMPLE_EXCEPTION_CNT | SAMPLE_DEVMAP_XMIT_CNT_MULTI;
30
31 DEFINE_SAMPLE_INIT(xdp_redirect);
32
33 static 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
43 int 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;
169 end_destroy:
170         xdp_redirect__destroy(skel);
171 end:
172         sample_exit(ret);
173 }