]>
Commit | Line | Data |
---|---|---|
7f904d7e TG |
1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* Copyright(c) 2017 Jesper Dangaard Brouer, Red Hat, Inc. | |
fad3917e JDB |
3 | */ |
4 | static const char *__doc__ = | |
e531a220 KKD |
5 | "XDP CPU redirect tool, using BPF_MAP_TYPE_CPUMAP\n" |
6 | "Usage: xdp_redirect_cpu -d <IFINDEX|IFNAME> -c 0 ... -c N\n" | |
7 | "Valid specification for CPUMAP BPF program:\n" | |
8 | " --mprog-name/-e pass (use built-in XDP_PASS program)\n" | |
9 | " --mprog-name/-e drop (use built-in XDP_DROP program)\n" | |
10 | " --redirect-device/-r <ifindex|ifname> (use built-in DEVMAP redirect program)\n" | |
11 | " Custom CPUMAP BPF program:\n" | |
12 | " --mprog-filename/-f <filename> --mprog-name/-e <program>\n" | |
13 | " Optionally, also pass --redirect-map/-m and --redirect-device/-r together\n" | |
14 | " to configure DEVMAP in BPF object <filename>\n"; | |
fad3917e JDB |
15 | |
16 | #include <errno.h> | |
17 | #include <signal.h> | |
18 | #include <stdio.h> | |
19 | #include <stdlib.h> | |
20 | #include <stdbool.h> | |
21 | #include <string.h> | |
22 | #include <unistd.h> | |
23 | #include <locale.h> | |
24 | #include <sys/resource.h> | |
6a098154 | 25 | #include <sys/sysinfo.h> |
fad3917e JDB |
26 | #include <getopt.h> |
27 | #include <net/if.h> | |
28 | #include <time.h> | |
f9e6bfdb | 29 | #include <linux/limits.h> |
fad3917e JDB |
30 | #include <arpa/inet.h> |
31 | #include <linux/if_link.h> | |
2bf3e2ef | 32 | #include <bpf/bpf.h> |
7cf245a3 | 33 | #include <bpf/libbpf.h> |
fad3917e | 34 | #include "bpf_util.h" |
e531a220 KKD |
35 | #include "xdp_sample_user.h" |
36 | #include "xdp_redirect_cpu.skel.h" | |
fad3917e | 37 | |
e531a220 KKD |
38 | static int map_fd; |
39 | static int avail_fd; | |
40 | static int count_fd; | |
151936bf | 41 | |
e531a220 KKD |
42 | static int mask = SAMPLE_RX_CNT | SAMPLE_REDIRECT_ERR_MAP_CNT | |
43 | SAMPLE_CPUMAP_ENQUEUE_CNT | SAMPLE_CPUMAP_KTHREAD_CNT | | |
44 | SAMPLE_EXCEPTION_CNT; | |
fad3917e | 45 | |
e531a220 | 46 | DEFINE_SAMPLE_INIT(xdp_redirect_cpu); |
fad3917e JDB |
47 | |
48 | static const struct option long_options[] = { | |
e531a220 KKD |
49 | { "help", no_argument, NULL, 'h' }, |
50 | { "dev", required_argument, NULL, 'd' }, | |
51 | { "skb-mode", no_argument, NULL, 'S' }, | |
52 | { "progname", required_argument, NULL, 'p' }, | |
53 | { "qsize", required_argument, NULL, 'q' }, | |
54 | { "cpu", required_argument, NULL, 'c' }, | |
55 | { "stress-mode", no_argument, NULL, 'x' }, | |
56 | { "force", no_argument, NULL, 'F' }, | |
57 | { "interval", required_argument, NULL, 'i' }, | |
58 | { "verbose", no_argument, NULL, 'v' }, | |
59 | { "stats", no_argument, NULL, 's' }, | |
60 | { "mprog-name", required_argument, NULL, 'e' }, | |
61 | { "mprog-filename", required_argument, NULL, 'f' }, | |
62 | { "redirect-device", required_argument, NULL, 'r' }, | |
63 | { "redirect-map", required_argument, NULL, 'm' }, | |
64 | {} | |
fad3917e JDB |
65 | }; |
66 | ||
bbaf6029 MF |
67 | static void print_avail_progs(struct bpf_object *obj) |
68 | { | |
69 | struct bpf_program *pos; | |
70 | ||
e531a220 | 71 | printf(" Programs to be used for -p/--progname:\n"); |
bbaf6029 | 72 | bpf_object__for_each_program(pos, obj) { |
e531a220 KKD |
73 | if (bpf_program__is_xdp(pos)) { |
74 | if (!strncmp(bpf_program__name(pos), "xdp_prognum", | |
75 | sizeof("xdp_prognum") - 1)) | |
76 | printf(" %s\n", bpf_program__name(pos)); | |
fad3917e | 77 | } |
fad3917e | 78 | } |
fad3917e JDB |
79 | } |
80 | ||
e531a220 KKD |
81 | static void usage(char *argv[], const struct option *long_options, |
82 | const char *doc, int mask, bool error, struct bpf_object *obj) | |
fad3917e | 83 | { |
e531a220 KKD |
84 | sample_usage(argv, long_options, doc, mask, error); |
85 | print_avail_progs(obj); | |
fad3917e JDB |
86 | } |
87 | ||
ce4dade7 | 88 | static int create_cpu_entry(__u32 cpu, struct bpf_cpumap_val *value, |
fad3917e JDB |
89 | __u32 avail_idx, bool new) |
90 | { | |
91 | __u32 curr_cpus_count = 0; | |
92 | __u32 key = 0; | |
93 | int ret; | |
94 | ||
95 | /* Add a CPU entry to cpumap, as this allocate a cpu entry in | |
96 | * the kernel for the cpu. | |
97 | */ | |
e531a220 KKD |
98 | ret = bpf_map_update_elem(map_fd, &cpu, value, 0); |
99 | if (ret < 0) { | |
100 | fprintf(stderr, "Create CPU entry failed: %s\n", strerror(errno)); | |
101 | return ret; | |
fad3917e JDB |
102 | } |
103 | ||
104 | /* Inform bpf_prog's that a new CPU is available to select | |
105 | * from via some control maps. | |
106 | */ | |
e531a220 KKD |
107 | ret = bpf_map_update_elem(avail_fd, &avail_idx, &cpu, 0); |
108 | if (ret < 0) { | |
109 | fprintf(stderr, "Add to avail CPUs failed: %s\n", strerror(errno)); | |
110 | return ret; | |
fad3917e JDB |
111 | } |
112 | ||
113 | /* When not replacing/updating existing entry, bump the count */ | |
e531a220 KKD |
114 | ret = bpf_map_lookup_elem(count_fd, &key, &curr_cpus_count); |
115 | if (ret < 0) { | |
116 | fprintf(stderr, "Failed reading curr cpus_count: %s\n", | |
117 | strerror(errno)); | |
118 | return ret; | |
fad3917e JDB |
119 | } |
120 | if (new) { | |
121 | curr_cpus_count++; | |
e531a220 | 122 | ret = bpf_map_update_elem(count_fd, &key, |
bbaf6029 | 123 | &curr_cpus_count, 0); |
e531a220 KKD |
124 | if (ret < 0) { |
125 | fprintf(stderr, "Failed write curr cpus_count: %s\n", | |
126 | strerror(errno)); | |
127 | return ret; | |
fad3917e JDB |
128 | } |
129 | } | |
e531a220 KKD |
130 | |
131 | printf("%s CPU: %u as idx: %u qsize: %d cpumap_prog_fd: %d (cpus_count: %u)\n", | |
132 | new ? "Add new" : "Replace", cpu, avail_idx, | |
ce4dade7 | 133 | value->qsize, value->bpf_prog.fd, curr_cpus_count); |
fad3917e JDB |
134 | |
135 | return 0; | |
136 | } | |
137 | ||
138 | /* CPUs are zero-indexed. Thus, add a special sentinel default value | |
139 | * in map cpus_available to mark CPU index'es not configured | |
140 | */ | |
e531a220 | 141 | static int mark_cpus_unavailable(void) |
fad3917e | 142 | { |
e531a220 | 143 | int ret, i, n_cpus = libbpf_num_possible_cpus(); |
48b2e71c | 144 | __u32 invalid_cpu = n_cpus; |
fad3917e | 145 | |
6a098154 | 146 | for (i = 0; i < n_cpus; i++) { |
e531a220 | 147 | ret = bpf_map_update_elem(avail_fd, &i, |
bbaf6029 | 148 | &invalid_cpu, 0); |
e531a220 KKD |
149 | if (ret < 0) { |
150 | fprintf(stderr, "Failed marking CPU unavailable: %s\n", | |
151 | strerror(errno)); | |
152 | return ret; | |
fad3917e JDB |
153 | } |
154 | } | |
e531a220 KKD |
155 | |
156 | return 0; | |
fad3917e JDB |
157 | } |
158 | ||
159 | /* Stress cpumap management code by concurrently changing underlying cpumap */ | |
e531a220 | 160 | static void stress_cpumap(void *ctx) |
fad3917e | 161 | { |
e531a220 KKD |
162 | struct bpf_cpumap_val *value = ctx; |
163 | ||
fad3917e JDB |
164 | /* Changing qsize will cause kernel to free and alloc a new |
165 | * bpf_cpu_map_entry, with an associated/complicated tear-down | |
166 | * procedure. | |
167 | */ | |
ce4dade7 LB |
168 | value->qsize = 1024; |
169 | create_cpu_entry(1, value, 0, false); | |
170 | value->qsize = 8; | |
171 | create_cpu_entry(1, value, 0, false); | |
172 | value->qsize = 16000; | |
173 | create_cpu_entry(1, value, 0, false); | |
fad3917e JDB |
174 | } |
175 | ||
e531a220 KKD |
176 | static int set_cpumap_prog(struct xdp_redirect_cpu *skel, |
177 | const char *redir_interface, const char *redir_map, | |
178 | const char *mprog_filename, const char *mprog_name) | |
f9e6bfdb | 179 | { |
e531a220 KKD |
180 | if (mprog_filename) { |
181 | struct bpf_program *prog; | |
182 | struct bpf_object *obj; | |
183 | int ret; | |
184 | ||
185 | if (!mprog_name) { | |
186 | fprintf(stderr, "BPF program not specified for file %s\n", | |
187 | mprog_filename); | |
188 | goto end; | |
189 | } | |
190 | if ((redir_interface && !redir_map) || (!redir_interface && redir_map)) { | |
191 | fprintf(stderr, "--redirect-%s specified but --redirect-%s not specified\n", | |
192 | redir_interface ? "device" : "map", redir_interface ? "map" : "device"); | |
193 | goto end; | |
151936bf | 194 | } |
bbaf6029 | 195 | |
e531a220 KKD |
196 | /* Custom BPF program */ |
197 | obj = bpf_object__open_file(mprog_filename, NULL); | |
198 | if (!obj) { | |
199 | ret = -errno; | |
200 | fprintf(stderr, "Failed to bpf_prog_load_xattr: %s\n", | |
201 | strerror(errno)); | |
202 | return ret; | |
203 | } | |
ce4dade7 | 204 | |
e531a220 KKD |
205 | ret = bpf_object__load(obj); |
206 | if (ret < 0) { | |
207 | ret = -errno; | |
208 | fprintf(stderr, "Failed to bpf_object__load: %s\n", | |
209 | strerror(errno)); | |
210 | return ret; | |
211 | } | |
ce4dade7 | 212 | |
e531a220 KKD |
213 | if (redir_map) { |
214 | int err, redir_map_fd, ifindex_out, key = 0; | |
ce4dade7 | 215 | |
e531a220 KKD |
216 | redir_map_fd = bpf_object__find_map_fd_by_name(obj, redir_map); |
217 | if (redir_map_fd < 0) { | |
218 | fprintf(stderr, "Failed to bpf_object__find_map_fd_by_name: %s\n", | |
219 | strerror(errno)); | |
220 | return redir_map_fd; | |
221 | } | |
ce4dade7 | 222 | |
e531a220 KKD |
223 | ifindex_out = if_nametoindex(redir_interface); |
224 | if (!ifindex_out) | |
225 | ifindex_out = strtoul(redir_interface, NULL, 0); | |
226 | if (!ifindex_out) { | |
227 | fprintf(stderr, "Bad interface name or index\n"); | |
228 | return -EINVAL; | |
229 | } | |
ce4dade7 | 230 | |
e531a220 KKD |
231 | err = bpf_map_update_elem(redir_map_fd, &key, &ifindex_out, 0); |
232 | if (err < 0) | |
233 | return err; | |
234 | } | |
ce4dade7 | 235 | |
e531a220 KKD |
236 | prog = bpf_object__find_program_by_name(obj, mprog_name); |
237 | if (!prog) { | |
238 | ret = -errno; | |
239 | fprintf(stderr, "Failed to bpf_object__find_program_by_name: %s\n", | |
240 | strerror(errno)); | |
241 | return ret; | |
242 | } | |
ce4dade7 | 243 | |
e531a220 KKD |
244 | return bpf_program__fd(prog); |
245 | } else { | |
246 | if (mprog_name) { | |
247 | if (redir_interface || redir_map) { | |
248 | fprintf(stderr, "Need to specify --mprog-filename/-f\n"); | |
249 | goto end; | |
250 | } | |
251 | if (!strcmp(mprog_name, "pass") || !strcmp(mprog_name, "drop")) { | |
252 | /* Use built-in pass/drop programs */ | |
253 | return *mprog_name == 'p' ? bpf_program__fd(skel->progs.xdp_redirect_cpu_pass) | |
254 | : bpf_program__fd(skel->progs.xdp_redirect_cpu_drop); | |
255 | } else { | |
256 | fprintf(stderr, "Unknown name \"%s\" for built-in BPF program\n", | |
257 | mprog_name); | |
258 | goto end; | |
259 | } | |
260 | } else { | |
261 | if (redir_map) { | |
262 | fprintf(stderr, "Need to specify --mprog-filename, --mprog-name and" | |
263 | " --redirect-device with --redirect-map\n"); | |
264 | goto end; | |
265 | } | |
266 | if (redir_interface) { | |
267 | /* Use built-in devmap redirect */ | |
268 | struct bpf_devmap_val val = {}; | |
269 | int ifindex_out, err; | |
270 | __u32 key = 0; | |
271 | ||
272 | if (!redir_interface) | |
273 | return 0; | |
274 | ||
275 | ifindex_out = if_nametoindex(redir_interface); | |
276 | if (!ifindex_out) | |
277 | ifindex_out = strtoul(redir_interface, NULL, 0); | |
278 | if (!ifindex_out) { | |
279 | fprintf(stderr, "Bad interface name or index\n"); | |
280 | return -EINVAL; | |
281 | } | |
282 | ||
283 | if (get_mac_addr(ifindex_out, skel->bss->tx_mac_addr) < 0) { | |
284 | printf("Get interface %d mac failed\n", ifindex_out); | |
285 | return -EINVAL; | |
286 | } | |
287 | ||
288 | val.ifindex = ifindex_out; | |
289 | val.bpf_prog.fd = bpf_program__fd(skel->progs.xdp_redirect_egress_prog); | |
290 | err = bpf_map_update_elem(bpf_map__fd(skel->maps.tx_port), &key, &val, 0); | |
291 | if (err < 0) | |
292 | return -errno; | |
293 | ||
294 | return bpf_program__fd(skel->progs.xdp_redirect_cpu_devmap); | |
295 | } | |
296 | } | |
ce4dade7 LB |
297 | } |
298 | ||
e531a220 KKD |
299 | /* Disabled */ |
300 | return 0; | |
301 | end: | |
302 | fprintf(stderr, "Invalid options for CPUMAP BPF program\n"); | |
303 | return -EINVAL; | |
ce4dade7 LB |
304 | } |
305 | ||
fad3917e JDB |
306 | int main(int argc, char **argv) |
307 | { | |
e531a220 KKD |
308 | const char *redir_interface = NULL, *redir_map = NULL; |
309 | const char *mprog_filename = NULL, *mprog_name = NULL; | |
310 | struct xdp_redirect_cpu *skel; | |
311 | struct bpf_map_info info = {}; | |
312 | char ifname_buf[IF_NAMESIZE]; | |
ce4dade7 | 313 | struct bpf_cpumap_val value; |
e531a220 KKD |
314 | __u32 infosz = sizeof(info); |
315 | int ret = EXIT_FAIL_OPTION; | |
316 | unsigned long interval = 2; | |
fad3917e | 317 | bool stress_mode = false; |
bbaf6029 | 318 | struct bpf_program *prog; |
e531a220 KKD |
319 | const char *prog_name; |
320 | bool generic = false; | |
321 | bool force = false; | |
fad3917e | 322 | int added_cpus = 0; |
e531a220 | 323 | bool error = true; |
fad3917e | 324 | int longindex = 0; |
fad3917e | 325 | int add_cpu = -1; |
e531a220 KKD |
326 | int ifindex = -1; |
327 | int *cpu, i, opt; | |
fad3917e | 328 | __u32 qsize; |
e531a220 | 329 | int n_cpus; |
fad3917e | 330 | |
e531a220 | 331 | n_cpus = libbpf_num_possible_cpus(); |
6a098154 | 332 | |
eff94154 JDB |
333 | /* Notice: Choosing the queue size is very important when CPU is |
334 | * configured with power-saving states. | |
335 | * | |
336 | * If deepest state take 133 usec to wakeup from (133/10^6). When link | |
337 | * speed is 10Gbit/s ((10*10^9/8) in bytes/sec). How many bytes can | |
338 | * arrive with in 133 usec at this speed: (10*10^9/8)*(133/10^6) = | |
339 | * 166250 bytes. With MTU size packets this is 110 packets, and with | |
340 | * minimum Ethernet (MAC-preamble + intergap) 84 bytes is 1979 packets. | |
341 | * | |
342 | * Setting default cpumap queue to 2048 as worst-case (small packet) | |
343 | * should be +64 packet due kthread wakeup call (due to xdp_do_flush) | |
344 | * worst-case is 2043 packets. | |
345 | * | |
346 | * Sysadm can configured system to avoid deep-sleep via: | |
347 | * tuned-adm profile network-latency | |
fad3917e | 348 | */ |
eff94154 | 349 | qsize = 2048; |
fad3917e | 350 | |
e531a220 KKD |
351 | skel = xdp_redirect_cpu__open(); |
352 | if (!skel) { | |
353 | fprintf(stderr, "Failed to xdp_redirect_cpu__open: %s\n", | |
bbaf6029 | 354 | strerror(errno)); |
e531a220 KKD |
355 | ret = EXIT_FAIL_BPF; |
356 | goto end; | |
357 | } | |
358 | ||
359 | ret = sample_init_pre_load(skel); | |
360 | if (ret < 0) { | |
361 | fprintf(stderr, "Failed to sample_init_pre_load: %s\n", strerror(-ret)); | |
362 | ret = EXIT_FAIL_BPF; | |
363 | goto end_destroy; | |
bbaf6029 | 364 | } |
151936bf | 365 | |
e531a220 KKD |
366 | if (bpf_map__set_max_entries(skel->maps.cpu_map, n_cpus) < 0) { |
367 | fprintf(stderr, "Failed to set max entries for cpu_map map: %s", | |
368 | strerror(errno)); | |
369 | ret = EXIT_FAIL_BPF; | |
370 | goto end_destroy; | |
151936bf DL |
371 | } |
372 | ||
e531a220 KKD |
373 | if (bpf_map__set_max_entries(skel->maps.cpus_available, n_cpus) < 0) { |
374 | fprintf(stderr, "Failed to set max entries for cpus_available map: %s", | |
375 | strerror(errno)); | |
376 | ret = EXIT_FAIL_BPF; | |
377 | goto end_destroy; | |
fad3917e | 378 | } |
fad3917e | 379 | |
e531a220 | 380 | cpu = calloc(n_cpus, sizeof(int)); |
a4e76f1b | 381 | if (!cpu) { |
e531a220 KKD |
382 | fprintf(stderr, "Failed to allocate cpu array\n"); |
383 | goto end_destroy; | |
a4e76f1b | 384 | } |
a4e76f1b | 385 | |
e531a220 KKD |
386 | prog = skel->progs.xdp_prognum5_lb_hash_ip_pairs; |
387 | while ((opt = getopt_long(argc, argv, "d:si:Sxp:f:e:r:m:c:q:Fvh", | |
fad3917e JDB |
388 | long_options, &longindex)) != -1) { |
389 | switch (opt) { | |
390 | case 'd': | |
391 | if (strlen(optarg) >= IF_NAMESIZE) { | |
e531a220 KKD |
392 | fprintf(stderr, "-d/--dev name too long\n"); |
393 | goto end_cpu; | |
fad3917e | 394 | } |
8312b914 DY |
395 | safe_strncpy(ifname_buf, optarg, strlen(ifname_buf)); |
396 | ifindex = if_nametoindex(ifname_buf); | |
e531a220 KKD |
397 | if (!ifindex) |
398 | ifindex = strtoul(optarg, NULL, 0); | |
399 | if (!ifindex) { | |
400 | fprintf(stderr, "Bad interface index or name (%d): %s\n", | |
fad3917e | 401 | errno, strerror(errno)); |
e531a220 KKD |
402 | usage(argv, long_options, __doc__, mask, true, skel->obj); |
403 | goto end_cpu; | |
fad3917e JDB |
404 | } |
405 | break; | |
406 | case 's': | |
e531a220 KKD |
407 | mask |= SAMPLE_REDIRECT_MAP_CNT; |
408 | break; | |
409 | case 'i': | |
410 | interval = strtoul(optarg, NULL, 0); | |
fad3917e JDB |
411 | break; |
412 | case 'S': | |
e531a220 | 413 | generic = true; |
fad3917e | 414 | break; |
fad3917e JDB |
415 | case 'x': |
416 | stress_mode = true; | |
417 | break; | |
fad3917e JDB |
418 | case 'p': |
419 | /* Selecting eBPF prog to load */ | |
bbaf6029 | 420 | prog_name = optarg; |
e531a220 KKD |
421 | prog = bpf_object__find_program_by_name(skel->obj, |
422 | prog_name); | |
423 | if (!prog) { | |
424 | fprintf(stderr, | |
425 | "Failed to find program %s specified by" | |
426 | " option -p/--progname\n", | |
427 | prog_name); | |
428 | print_avail_progs(skel->obj); | |
429 | goto end_cpu; | |
430 | } | |
ce4dade7 LB |
431 | break; |
432 | case 'f': | |
433 | mprog_filename = optarg; | |
434 | break; | |
435 | case 'e': | |
436 | mprog_name = optarg; | |
437 | break; | |
438 | case 'r': | |
439 | redir_interface = optarg; | |
e531a220 | 440 | mask |= SAMPLE_DEVMAP_XMIT_CNT_MULTI; |
ce4dade7 LB |
441 | break; |
442 | case 'm': | |
443 | redir_map = optarg; | |
444 | break; | |
fad3917e JDB |
445 | case 'c': |
446 | /* Add multiple CPUs */ | |
447 | add_cpu = strtoul(optarg, NULL, 0); | |
6a098154 | 448 | if (add_cpu >= n_cpus) { |
fad3917e | 449 | fprintf(stderr, |
48b2e71c | 450 | "--cpu nr too large for cpumap err (%d):%s\n", |
fad3917e | 451 | errno, strerror(errno)); |
48b2e71c | 452 | usage(argv, long_options, __doc__, mask, true, skel->obj); |
e531a220 | 453 | goto end_cpu; |
fad3917e | 454 | } |
a4e76f1b | 455 | cpu[added_cpus++] = add_cpu; |
fad3917e JDB |
456 | break; |
457 | case 'q': | |
e531a220 | 458 | qsize = strtoul(optarg, NULL, 0); |
fad3917e | 459 | break; |
743e568c | 460 | case 'F': |
e531a220 KKD |
461 | force = true; |
462 | break; | |
463 | case 'v': | |
464 | sample_switch_mode(); | |
743e568c | 465 | break; |
fad3917e | 466 | case 'h': |
e531a220 | 467 | error = false; |
fad3917e | 468 | default: |
e531a220 KKD |
469 | usage(argv, long_options, __doc__, mask, error, skel->obj); |
470 | goto end_cpu; | |
fad3917e JDB |
471 | } |
472 | } | |
d50ecc46 | 473 | |
e531a220 | 474 | ret = EXIT_FAIL_OPTION; |
fad3917e | 475 | if (ifindex == -1) { |
e531a220 KKD |
476 | fprintf(stderr, "Required option --dev missing\n"); |
477 | usage(argv, long_options, __doc__, mask, true, skel->obj); | |
478 | goto end_cpu; | |
fad3917e | 479 | } |
e531a220 | 480 | |
fad3917e | 481 | if (add_cpu == -1) { |
e531a220 KKD |
482 | fprintf(stderr, "Required option --cpu missing\n" |
483 | "Specify multiple --cpu option to add more\n"); | |
484 | usage(argv, long_options, __doc__, mask, true, skel->obj); | |
485 | goto end_cpu; | |
fad3917e JDB |
486 | } |
487 | ||
e531a220 KKD |
488 | skel->rodata->from_match[0] = ifindex; |
489 | if (redir_interface) | |
490 | skel->rodata->to_match[0] = if_nametoindex(redir_interface); | |
491 | ||
492 | ret = xdp_redirect_cpu__load(skel); | |
493 | if (ret < 0) { | |
494 | fprintf(stderr, "Failed to xdp_redirect_cpu__load: %s\n", | |
495 | strerror(errno)); | |
496 | goto end_cpu; | |
ce4dade7 | 497 | } |
ce4dade7 | 498 | |
e531a220 KKD |
499 | ret = bpf_obj_get_info_by_fd(bpf_map__fd(skel->maps.cpu_map), &info, &infosz); |
500 | if (ret < 0) { | |
501 | fprintf(stderr, "Failed bpf_obj_get_info_by_fd for cpumap: %s\n", | |
502 | strerror(errno)); | |
503 | goto end_cpu; | |
504 | } | |
a4e76f1b | 505 | |
e531a220 | 506 | skel->bss->cpumap_map_id = info.id; |
fad3917e | 507 | |
e531a220 KKD |
508 | map_fd = bpf_map__fd(skel->maps.cpu_map); |
509 | avail_fd = bpf_map__fd(skel->maps.cpus_available); | |
510 | count_fd = bpf_map__fd(skel->maps.cpus_count); | |
511 | ||
512 | ret = mark_cpus_unavailable(); | |
513 | if (ret < 0) { | |
514 | fprintf(stderr, "Unable to mark CPUs as unavailable\n"); | |
515 | goto end_cpu; | |
bbaf6029 MF |
516 | } |
517 | ||
e531a220 KKD |
518 | ret = sample_init(skel, mask); |
519 | if (ret < 0) { | |
520 | fprintf(stderr, "Failed to initialize sample: %s\n", strerror(-ret)); | |
521 | ret = EXIT_FAIL; | |
522 | goto end_cpu; | |
bbaf6029 MF |
523 | } |
524 | ||
e531a220 KKD |
525 | value.bpf_prog.fd = set_cpumap_prog(skel, redir_interface, redir_map, |
526 | mprog_filename, mprog_name); | |
527 | if (value.bpf_prog.fd < 0) { | |
528 | fprintf(stderr, "Failed to set CPUMAP BPF program: %s\n", | |
529 | strerror(-value.bpf_prog.fd)); | |
530 | usage(argv, long_options, __doc__, mask, true, skel->obj); | |
531 | ret = EXIT_FAIL_BPF; | |
532 | goto end_cpu; | |
fad3917e | 533 | } |
e531a220 | 534 | value.qsize = qsize; |
fad3917e | 535 | |
e531a220 KKD |
536 | for (i = 0; i < added_cpus; i++) { |
537 | if (create_cpu_entry(cpu[i], &value, i, true) < 0) { | |
538 | fprintf(stderr, "Cannot proceed, exiting\n"); | |
539 | usage(argv, long_options, __doc__, mask, true, skel->obj); | |
540 | goto end_cpu; | |
541 | } | |
3b7a8ec2 | 542 | } |
3b7a8ec2 | 543 | |
e531a220 KKD |
544 | ret = EXIT_FAIL_XDP; |
545 | if (sample_install_xdp(prog, ifindex, generic, force) < 0) | |
546 | goto end_cpu; | |
151936bf | 547 | |
e531a220 KKD |
548 | ret = sample_run(interval, stress_mode ? stress_cpumap : NULL, &value); |
549 | if (ret < 0) { | |
550 | fprintf(stderr, "Failed during sample run: %s\n", strerror(-ret)); | |
551 | ret = EXIT_FAIL; | |
552 | goto end_cpu; | |
553 | } | |
554 | ret = EXIT_OK; | |
555 | end_cpu: | |
a4e76f1b | 556 | free(cpu); |
e531a220 KKD |
557 | end_destroy: |
558 | xdp_redirect_cpu__destroy(skel); | |
559 | end: | |
560 | sample_exit(ret); | |
fad3917e | 561 | } |