]>
Commit | Line | Data |
---|---|---|
e48cfe4b | 1 | // SPDX-License-Identifier: GPL-2.0 |
594a116b KKD |
2 | static const char *__doc__ = |
3 | "XDP multi redirect tool, using BPF_MAP_TYPE_DEVMAP and BPF_F_BROADCAST flag for bpf_redirect_map\n" | |
4 | "Usage: xdp_redirect_map_multi <IFINDEX|IFNAME> <IFINDEX|IFNAME> ... <IFINDEX|IFNAME>\n"; | |
5 | ||
e48cfe4b HL |
6 | #include <linux/bpf.h> |
7 | #include <linux/if_link.h> | |
8 | #include <assert.h> | |
594a116b | 9 | #include <getopt.h> |
e48cfe4b HL |
10 | #include <errno.h> |
11 | #include <signal.h> | |
12 | #include <stdio.h> | |
13 | #include <stdlib.h> | |
14 | #include <string.h> | |
15 | #include <net/if.h> | |
16 | #include <unistd.h> | |
17 | #include <libgen.h> | |
18 | #include <sys/resource.h> | |
19 | #include <sys/ioctl.h> | |
20 | #include <sys/types.h> | |
21 | #include <sys/socket.h> | |
22 | #include <netinet/in.h> | |
594a116b | 23 | #include <linux/if_ether.h> |
e48cfe4b HL |
24 | #include <bpf/bpf.h> |
25 | #include <bpf/libbpf.h> | |
594a116b KKD |
26 | #include "bpf_util.h" |
27 | #include "xdp_sample_user.h" | |
28 | #include "xdp_redirect_map_multi.skel.h" | |
e48cfe4b HL |
29 | |
30 | #define MAX_IFACE_NUM 32 | |
e48cfe4b | 31 | static int ifaces[MAX_IFACE_NUM] = {}; |
e48cfe4b | 32 | |
594a116b KKD |
33 | static int mask = SAMPLE_RX_CNT | SAMPLE_REDIRECT_ERR_MAP_CNT | |
34 | SAMPLE_EXCEPTION_CNT | SAMPLE_DEVMAP_XMIT_CNT | | |
35 | SAMPLE_DEVMAP_XMIT_CNT_MULTI | SAMPLE_SKIP_HEADING; | |
e48cfe4b | 36 | |
594a116b | 37 | DEFINE_SAMPLE_INIT(xdp_redirect_map_multi); |
e48cfe4b | 38 | |
594a116b KKD |
39 | static const struct option long_options[] = { |
40 | { "help", no_argument, NULL, 'h' }, | |
41 | { "skb-mode", no_argument, NULL, 'S' }, | |
42 | { "force", no_argument, NULL, 'F' }, | |
43 | { "load-egress", no_argument, NULL, 'X' }, | |
44 | { "stats", no_argument, NULL, 's' }, | |
45 | { "interval", required_argument, NULL, 'i' }, | |
46 | { "verbose", no_argument, NULL, 'v' }, | |
47 | {} | |
48 | }; | |
e48cfe4b | 49 | |
594a116b | 50 | static int update_mac_map(struct bpf_map *map) |
e48cfe4b | 51 | { |
594a116b | 52 | int mac_map_fd = bpf_map__fd(map); |
e48cfe4b HL |
53 | unsigned char mac_addr[6]; |
54 | unsigned int ifindex; | |
594a116b | 55 | int i, ret = -1; |
e48cfe4b HL |
56 | |
57 | for (i = 0; ifaces[i] > 0; i++) { | |
58 | ifindex = ifaces[i]; | |
59 | ||
60 | ret = get_mac_addr(ifindex, mac_addr); | |
61 | if (ret < 0) { | |
594a116b KKD |
62 | fprintf(stderr, "get interface %d mac failed\n", |
63 | ifindex); | |
e48cfe4b HL |
64 | return ret; |
65 | } | |
66 | ||
67 | ret = bpf_map_update_elem(mac_map_fd, &ifindex, mac_addr, 0); | |
594a116b KKD |
68 | if (ret < 0) { |
69 | fprintf(stderr, "Failed to update mac address for ifindex %d\n", | |
70 | ifindex); | |
e48cfe4b HL |
71 | return ret; |
72 | } | |
73 | } | |
74 | ||
75 | return 0; | |
76 | } | |
77 | ||
e48cfe4b HL |
78 | int main(int argc, char **argv) |
79 | { | |
594a116b KKD |
80 | struct bpf_devmap_val devmap_val = {}; |
81 | struct xdp_redirect_map_multi *skel; | |
82 | struct bpf_program *ingress_prog; | |
83 | bool xdp_devmap_attached = false; | |
84 | struct bpf_map *forward_map; | |
85 | int ret = EXIT_FAIL_OPTION; | |
86 | unsigned long interval = 2; | |
e48cfe4b | 87 | char ifname[IF_NAMESIZE]; |
e48cfe4b | 88 | unsigned int ifindex; |
594a116b KKD |
89 | bool generic = false; |
90 | bool force = false; | |
91 | bool tried = false; | |
92 | bool error = true; | |
93 | int i, opt; | |
94 | ||
95 | while ((opt = getopt_long(argc, argv, "hSFXi:vs", | |
96 | long_options, NULL)) != -1) { | |
e48cfe4b HL |
97 | switch (opt) { |
98 | case 'S': | |
594a116b KKD |
99 | generic = true; |
100 | /* devmap_xmit tracepoint not available */ | |
101 | mask &= ~(SAMPLE_DEVMAP_XMIT_CNT | | |
102 | SAMPLE_DEVMAP_XMIT_CNT_MULTI); | |
e48cfe4b HL |
103 | break; |
104 | case 'F': | |
594a116b | 105 | force = true; |
e48cfe4b HL |
106 | break; |
107 | case 'X': | |
594a116b KKD |
108 | xdp_devmap_attached = true; |
109 | break; | |
110 | case 'i': | |
111 | interval = strtoul(optarg, NULL, 0); | |
112 | break; | |
113 | case 'v': | |
114 | sample_switch_mode(); | |
e48cfe4b | 115 | break; |
594a116b KKD |
116 | case 's': |
117 | mask |= SAMPLE_REDIRECT_MAP_CNT; | |
118 | break; | |
119 | case 'h': | |
120 | error = false; | |
e48cfe4b | 121 | default: |
594a116b KKD |
122 | sample_usage(argv, long_options, __doc__, mask, error); |
123 | return ret; | |
e48cfe4b HL |
124 | } |
125 | } | |
126 | ||
594a116b KKD |
127 | if (argc <= optind + 1) { |
128 | sample_usage(argv, long_options, __doc__, mask, error); | |
129 | return ret; | |
e48cfe4b HL |
130 | } |
131 | ||
594a116b KKD |
132 | skel = xdp_redirect_map_multi__open(); |
133 | if (!skel) { | |
134 | fprintf(stderr, "Failed to xdp_redirect_map_multi__open: %s\n", | |
135 | strerror(errno)); | |
136 | ret = EXIT_FAIL_BPF; | |
137 | goto end; | |
e48cfe4b HL |
138 | } |
139 | ||
594a116b KKD |
140 | ret = sample_init_pre_load(skel); |
141 | if (ret < 0) { | |
142 | fprintf(stderr, "Failed to sample_init_pre_load: %s\n", strerror(-ret)); | |
143 | ret = EXIT_FAIL_BPF; | |
144 | goto end_destroy; | |
145 | } | |
146 | ||
147 | ret = EXIT_FAIL_OPTION; | |
e48cfe4b HL |
148 | for (i = 0; i < MAX_IFACE_NUM && argv[optind + i]; i++) { |
149 | ifaces[i] = if_nametoindex(argv[optind + i]); | |
150 | if (!ifaces[i]) | |
151 | ifaces[i] = strtoul(argv[optind + i], NULL, 0); | |
152 | if (!if_indextoname(ifaces[i], ifname)) { | |
594a116b KKD |
153 | fprintf(stderr, "Bad interface index or name\n"); |
154 | sample_usage(argv, long_options, __doc__, mask, true); | |
155 | goto end_destroy; | |
e48cfe4b HL |
156 | } |
157 | ||
594a116b KKD |
158 | skel->rodata->from_match[i] = ifaces[i]; |
159 | skel->rodata->to_match[i] = ifaces[i]; | |
e48cfe4b HL |
160 | } |
161 | ||
594a116b KKD |
162 | ret = xdp_redirect_map_multi__load(skel); |
163 | if (ret < 0) { | |
164 | fprintf(stderr, "Failed to xdp_redirect_map_multi__load: %s\n", | |
165 | strerror(errno)); | |
166 | ret = EXIT_FAIL_BPF; | |
167 | goto end_destroy; | |
e48cfe4b HL |
168 | } |
169 | ||
594a116b | 170 | if (xdp_devmap_attached) { |
e48cfe4b | 171 | /* Update mac_map with all egress interfaces' mac addr */ |
594a116b KKD |
172 | if (update_mac_map(skel->maps.mac_map) < 0) { |
173 | fprintf(stderr, "Updating mac address failed\n"); | |
174 | ret = EXIT_FAIL; | |
175 | goto end_destroy; | |
e48cfe4b | 176 | } |
594a116b | 177 | } |
e48cfe4b | 178 | |
594a116b KKD |
179 | ret = sample_init(skel, mask); |
180 | if (ret < 0) { | |
181 | fprintf(stderr, "Failed to initialize sample: %s\n", strerror(-ret)); | |
182 | ret = EXIT_FAIL; | |
183 | goto end_destroy; | |
e48cfe4b HL |
184 | } |
185 | ||
594a116b KKD |
186 | ingress_prog = skel->progs.xdp_redirect_map_native; |
187 | forward_map = skel->maps.forward_map_native; | |
e48cfe4b | 188 | |
e48cfe4b HL |
189 | for (i = 0; ifaces[i] > 0; i++) { |
190 | ifindex = ifaces[i]; | |
191 | ||
594a116b KKD |
192 | ret = EXIT_FAIL_XDP; |
193 | restart: | |
e48cfe4b | 194 | /* bind prog_fd to each interface */ |
594a116b KKD |
195 | if (sample_install_xdp(ingress_prog, ifindex, generic, force) < 0) { |
196 | if (generic && !tried) { | |
197 | fprintf(stderr, | |
198 | "Trying fallback to sizeof(int) as value_size for devmap in generic mode\n"); | |
199 | ingress_prog = skel->progs.xdp_redirect_map_general; | |
200 | forward_map = skel->maps.forward_map_general; | |
201 | tried = true; | |
202 | goto restart; | |
203 | } | |
204 | goto end_destroy; | |
e48cfe4b HL |
205 | } |
206 | ||
207 | /* Add all the interfaces to forward group and attach | |
594a116b | 208 | * egress devmap program if exist |
e48cfe4b HL |
209 | */ |
210 | devmap_val.ifindex = ifindex; | |
594a116b KKD |
211 | if (xdp_devmap_attached) |
212 | devmap_val.bpf_prog.fd = bpf_program__fd(skel->progs.xdp_devmap_prog); | |
213 | ret = bpf_map_update_elem(bpf_map__fd(forward_map), &ifindex, &devmap_val, 0); | |
214 | if (ret < 0) { | |
215 | fprintf(stderr, "Failed to update devmap value: %s\n", | |
216 | strerror(errno)); | |
217 | ret = EXIT_FAIL_BPF; | |
218 | goto end_destroy; | |
e48cfe4b HL |
219 | } |
220 | } | |
221 | ||
594a116b KKD |
222 | ret = sample_run(interval, NULL, NULL); |
223 | if (ret < 0) { | |
224 | fprintf(stderr, "Failed during sample run: %s\n", strerror(-ret)); | |
225 | ret = EXIT_FAIL; | |
226 | goto end_destroy; | |
227 | } | |
228 | ret = EXIT_OK; | |
229 | end_destroy: | |
230 | xdp_redirect_map_multi__destroy(skel); | |
231 | end: | |
232 | sample_exit(ret); | |
e48cfe4b | 233 | } |