]>
Commit | Line | Data |
---|---|---|
5b497af4 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
9d6e0052 | 2 | /* Copyright (c) 2017 Covalent IO, Inc. http://covalent.io |
9d6e0052 | 3 | */ |
bbe65865 KKD |
4 | static 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 | ||
9d6e0052 | 8 | #include <linux/bpf.h> |
24251c26 | 9 | #include <linux/if_link.h> |
9d6e0052 JF |
10 | #include <assert.h> |
11 | #include <errno.h> | |
12 | #include <signal.h> | |
13 | #include <stdio.h> | |
14 | #include <stdlib.h> | |
306da4e6 | 15 | #include <stdbool.h> |
9d6e0052 | 16 | #include <string.h> |
9e859e8f | 17 | #include <net/if.h> |
9d6e0052 | 18 | #include <unistd.h> |
24251c26 | 19 | #include <libgen.h> |
bbe65865 | 20 | #include <getopt.h> |
2bf3e2ef | 21 | #include <bpf/bpf.h> |
7cf245a3 | 22 | #include <bpf/libbpf.h> |
bbe65865 KKD |
23 | #include "bpf_util.h" |
24 | #include "xdp_sample_user.h" | |
25 | #include "xdp_redirect_map.skel.h" | |
9d6e0052 | 26 | |
bbe65865 KKD |
27 | static int mask = SAMPLE_RX_CNT | SAMPLE_REDIRECT_ERR_MAP_CNT | |
28 | SAMPLE_EXCEPTION_CNT | SAMPLE_DEVMAP_XMIT_CNT_MULTI; | |
6e66fbb1 | 29 | |
bbe65865 | 30 | DEFINE_SAMPLE_INIT(xdp_redirect_map); |
6e66fbb1 | 31 | |
bbe65865 KKD |
32 | static 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 | }; | |
9d6e0052 | 42 | |
24251c26 AG |
43 | int main(int argc, char **argv) |
44 | { | |
bbe65865 KKD |
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) { | |
24251c26 AG |
64 | switch (opt) { |
65 | case 'S': | |
bbe65865 KKD |
66 | generic = true; |
67 | /* devmap_xmit tracepoint not available */ | |
68 | mask &= ~(SAMPLE_DEVMAP_XMIT_CNT | | |
69 | SAMPLE_DEVMAP_XMIT_CNT_MULTI); | |
24251c26 | 70 | break; |
743e568c | 71 | case 'F': |
bbe65865 | 72 | force = true; |
743e568c | 73 | break; |
6e66fbb1 HL |
74 | case 'X': |
75 | xdp_devmap_attached = true; | |
76 | break; | |
bbe65865 KKD |
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; | |
24251c26 | 88 | default: |
bbe65865 KKD |
89 | sample_usage(argv, long_options, __doc__, mask, error); |
90 | return ret; | |
24251c26 AG |
91 | } |
92 | } | |
93 | ||
bbe65865 KKD |
94 | if (argc <= optind + 1) { |
95 | sample_usage(argv, long_options, __doc__, mask, true); | |
96 | goto end; | |
9d6e0052 JF |
97 | } |
98 | ||
9e859e8f DL |
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 | ||
bbe65865 KKD |
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; | |
9d6e0052 JF |
111 | } |
112 | ||
bbe65865 KKD |
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; | |
9d6e0052 JF |
119 | } |
120 | ||
bbe65865 KKD |
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; | |
3b7a8ec2 | 126 | } |
3b7a8ec2 | 127 | |
6e66fbb1 HL |
128 | /* Load 2nd xdp prog on egress. */ |
129 | if (xdp_devmap_attached) { | |
bbe65865 KKD |
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; | |
6e66fbb1 | 136 | } |
bbe65865 | 137 | } |
6e66fbb1 | 138 | |
bbe65865 KKD |
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; | |
159 | restart: | |
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; | |
6e66fbb1 | 171 | } |
bbe65865 KKD |
172 | ret = EXIT_FAIL_XDP; |
173 | goto end_destroy; | |
6e66fbb1 HL |
174 | } |
175 | ||
bbe65865 KKD |
176 | /* Loading dummy XDP prog on out-device */ |
177 | sample_install_xdp(skel->progs.xdp_redirect_dummy_prog, ifindex_out, generic, force); | |
306da4e6 | 178 | |
6e66fbb1 | 179 | devmap_val.ifindex = ifindex_out; |
bbe65865 KKD |
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; | |
215 | end_destroy: | |
216 | xdp_redirect_map__destroy(skel); | |
217 | end: | |
218 | sample_exit(ret); | |
9d6e0052 | 219 | } |