.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* Copyright (C) 2017 Cavium, Inc. |
---|
2 | | - * |
---|
3 | | - * This program is free software; you can redistribute it and/or modify it |
---|
4 | | - * under the terms of version 2 of the GNU General Public License |
---|
5 | | - * as published by the Free Software Foundation. |
---|
6 | 3 | */ |
---|
7 | 4 | #include <linux/bpf.h> |
---|
8 | 5 | #include <linux/netlink.h> |
---|
.. | .. |
---|
15 | 12 | #include <string.h> |
---|
16 | 13 | #include <sys/socket.h> |
---|
17 | 14 | #include <unistd.h> |
---|
18 | | -#include "bpf_load.h" |
---|
19 | 15 | #include <bpf/bpf.h> |
---|
20 | 16 | #include <arpa/inet.h> |
---|
21 | 17 | #include <fcntl.h> |
---|
.. | .. |
---|
25 | 21 | #include <sys/ioctl.h> |
---|
26 | 22 | #include <sys/syscall.h> |
---|
27 | 23 | #include "bpf_util.h" |
---|
| 24 | +#include <bpf/libbpf.h> |
---|
| 25 | +#include <sys/resource.h> |
---|
| 26 | +#include <libgen.h> |
---|
28 | 27 | |
---|
29 | | -int sock, sock_arp, flags = 0; |
---|
| 28 | +int sock, sock_arp, flags = XDP_FLAGS_UPDATE_IF_NOEXIST; |
---|
30 | 29 | static int total_ifindex; |
---|
31 | | -int *ifindex_list; |
---|
| 30 | +static int *ifindex_list; |
---|
| 31 | +static __u32 *prog_id_list; |
---|
32 | 32 | char buf[8192]; |
---|
| 33 | +static int lpm_map_fd; |
---|
| 34 | +static int rxcnt_map_fd; |
---|
| 35 | +static int arp_table_map_fd; |
---|
| 36 | +static int exact_match_map_fd; |
---|
| 37 | +static int tx_port_map_fd; |
---|
33 | 38 | |
---|
34 | 39 | static int get_route_table(int rtm_family); |
---|
35 | 40 | static void int_exit(int sig) |
---|
36 | 41 | { |
---|
| 42 | + __u32 prog_id = 0; |
---|
37 | 43 | int i = 0; |
---|
38 | 44 | |
---|
39 | | - for (i = 0; i < total_ifindex; i++) |
---|
40 | | - bpf_set_link_xdp_fd(ifindex_list[i], -1, flags); |
---|
| 45 | + for (i = 0; i < total_ifindex; i++) { |
---|
| 46 | + if (bpf_get_link_xdp_id(ifindex_list[i], &prog_id, flags)) { |
---|
| 47 | + printf("bpf_get_link_xdp_id on iface %d failed\n", |
---|
| 48 | + ifindex_list[i]); |
---|
| 49 | + exit(1); |
---|
| 50 | + } |
---|
| 51 | + if (prog_id_list[i] == prog_id) |
---|
| 52 | + bpf_set_link_xdp_fd(ifindex_list[i], -1, flags); |
---|
| 53 | + else if (!prog_id) |
---|
| 54 | + printf("couldn't find a prog id on iface %d\n", |
---|
| 55 | + ifindex_list[i]); |
---|
| 56 | + else |
---|
| 57 | + printf("program on iface %d changed, not removing\n", |
---|
| 58 | + ifindex_list[i]); |
---|
| 59 | + prog_id = 0; |
---|
| 60 | + } |
---|
41 | 61 | exit(0); |
---|
42 | 62 | } |
---|
43 | 63 | |
---|
44 | 64 | static void close_and_exit(int sig) |
---|
45 | 65 | { |
---|
46 | | - int i = 0; |
---|
47 | | - |
---|
48 | 66 | close(sock); |
---|
49 | 67 | close(sock_arp); |
---|
50 | 68 | |
---|
51 | | - for (i = 0; i < total_ifindex; i++) |
---|
52 | | - bpf_set_link_xdp_fd(ifindex_list[i], -1, flags); |
---|
53 | | - exit(0); |
---|
| 69 | + int_exit(0); |
---|
54 | 70 | } |
---|
55 | 71 | |
---|
56 | 72 | /* Get the mac address of the interface given interface name */ |
---|
.. | .. |
---|
179 | 195 | route.iface_name = alloca(sizeof(char *) * IFNAMSIZ); |
---|
180 | 196 | route.iface_name = if_indextoname(route.iface, route.iface_name); |
---|
181 | 197 | route.mac = getmac(route.iface_name); |
---|
182 | | - if (route.mac == -1) { |
---|
183 | | - int i = 0; |
---|
184 | | - |
---|
185 | | - for (i = 0; i < total_ifindex; i++) |
---|
186 | | - bpf_set_link_xdp_fd(ifindex_list[i], -1, flags); |
---|
187 | | - exit(0); |
---|
188 | | - } |
---|
189 | | - assert(bpf_map_update_elem(map_fd[4], &route.iface, &route.iface, 0) == 0); |
---|
| 198 | + if (route.mac == -1) |
---|
| 199 | + int_exit(0); |
---|
| 200 | + assert(bpf_map_update_elem(tx_port_map_fd, |
---|
| 201 | + &route.iface, &route.iface, 0) == 0); |
---|
190 | 202 | if (rtm_family == AF_INET) { |
---|
191 | 203 | struct trie_value { |
---|
192 | 204 | __u8 prefix[4]; |
---|
.. | .. |
---|
207 | 219 | direct_entry.arp.dst = 0; |
---|
208 | 220 | if (route.dst_len == 32) { |
---|
209 | 221 | if (nh->nlmsg_type == RTM_DELROUTE) { |
---|
210 | | - assert(bpf_map_delete_elem(map_fd[3], &route.dst) == 0); |
---|
| 222 | + assert(bpf_map_delete_elem(exact_match_map_fd, |
---|
| 223 | + &route.dst) == 0); |
---|
211 | 224 | } else { |
---|
212 | | - if (bpf_map_lookup_elem(map_fd[2], &route.dst, &direct_entry.arp.mac) == 0) |
---|
| 225 | + if (bpf_map_lookup_elem(arp_table_map_fd, |
---|
| 226 | + &route.dst, |
---|
| 227 | + &direct_entry.arp.mac) == 0) |
---|
213 | 228 | direct_entry.arp.dst = route.dst; |
---|
214 | | - assert(bpf_map_update_elem(map_fd[3], &route.dst, &direct_entry, 0) == 0); |
---|
| 229 | + assert(bpf_map_update_elem(exact_match_map_fd, |
---|
| 230 | + &route.dst, |
---|
| 231 | + &direct_entry, 0) == 0); |
---|
215 | 232 | } |
---|
216 | 233 | } |
---|
217 | 234 | for (i = 0; i < 4; i++) |
---|
.. | .. |
---|
225 | 242 | route.gw, route.dst_len, |
---|
226 | 243 | route.metric, |
---|
227 | 244 | route.iface_name); |
---|
228 | | - if (bpf_map_lookup_elem(map_fd[0], prefix_key, |
---|
| 245 | + if (bpf_map_lookup_elem(lpm_map_fd, prefix_key, |
---|
229 | 246 | prefix_value) < 0) { |
---|
230 | 247 | for (i = 0; i < 4; i++) |
---|
231 | 248 | prefix_value->prefix[i] = prefix_key->data[i]; |
---|
.. | .. |
---|
234 | 251 | prefix_value->gw = route.gw; |
---|
235 | 252 | prefix_value->metric = route.metric; |
---|
236 | 253 | |
---|
237 | | - assert(bpf_map_update_elem(map_fd[0], |
---|
| 254 | + assert(bpf_map_update_elem(lpm_map_fd, |
---|
238 | 255 | prefix_key, |
---|
239 | 256 | prefix_value, 0 |
---|
240 | 257 | ) == 0); |
---|
.. | .. |
---|
247 | 264 | prefix_key->data[2], |
---|
248 | 265 | prefix_key->data[3], |
---|
249 | 266 | prefix_key->prefixlen); |
---|
250 | | - assert(bpf_map_delete_elem(map_fd[0], |
---|
| 267 | + assert(bpf_map_delete_elem(lpm_map_fd, |
---|
251 | 268 | prefix_key |
---|
252 | 269 | ) == 0); |
---|
253 | 270 | /* Rereading the route table to check if |
---|
.. | .. |
---|
275 | 292 | prefix_value->ifindex = route.iface; |
---|
276 | 293 | prefix_value->gw = route.gw; |
---|
277 | 294 | prefix_value->metric = route.metric; |
---|
278 | | - assert(bpf_map_update_elem( |
---|
279 | | - map_fd[0], |
---|
| 295 | + assert(bpf_map_update_elem(lpm_map_fd, |
---|
280 | 296 | prefix_key, |
---|
281 | 297 | prefix_value, |
---|
282 | 298 | 0) == 0); |
---|
.. | .. |
---|
401 | 417 | arp_entry.mac = atol(mac); |
---|
402 | 418 | printf("%x\t\t%llx\n", arp_entry.dst, arp_entry.mac); |
---|
403 | 419 | if (ndm_family == AF_INET) { |
---|
404 | | - if (bpf_map_lookup_elem(map_fd[3], &arp_entry.dst, |
---|
| 420 | + if (bpf_map_lookup_elem(exact_match_map_fd, |
---|
| 421 | + &arp_entry.dst, |
---|
405 | 422 | &direct_entry) == 0) { |
---|
406 | 423 | if (nh->nlmsg_type == RTM_DELNEIGH) { |
---|
407 | 424 | direct_entry.arp.dst = 0; |
---|
.. | .. |
---|
410 | 427 | direct_entry.arp.dst = arp_entry.dst; |
---|
411 | 428 | direct_entry.arp.mac = arp_entry.mac; |
---|
412 | 429 | } |
---|
413 | | - assert(bpf_map_update_elem(map_fd[3], |
---|
| 430 | + assert(bpf_map_update_elem(exact_match_map_fd, |
---|
414 | 431 | &arp_entry.dst, |
---|
415 | 432 | &direct_entry, 0 |
---|
416 | 433 | ) == 0); |
---|
417 | 434 | memset(&direct_entry, 0, sizeof(direct_entry)); |
---|
418 | 435 | } |
---|
419 | 436 | if (nh->nlmsg_type == RTM_DELNEIGH) { |
---|
420 | | - assert(bpf_map_delete_elem(map_fd[2], &arp_entry.dst) == 0); |
---|
| 437 | + assert(bpf_map_delete_elem(arp_table_map_fd, |
---|
| 438 | + &arp_entry.dst) == 0); |
---|
421 | 439 | } else if (nh->nlmsg_type == RTM_NEWNEIGH) { |
---|
422 | | - assert(bpf_map_update_elem(map_fd[2], |
---|
| 440 | + assert(bpf_map_update_elem(arp_table_map_fd, |
---|
423 | 441 | &arp_entry.dst, |
---|
424 | 442 | &arp_entry.mac, 0 |
---|
425 | 443 | ) == 0); |
---|
.. | .. |
---|
553 | 571 | for (key = 0; key < nr_keys; key++) { |
---|
554 | 572 | __u64 sum = 0; |
---|
555 | 573 | |
---|
556 | | - assert(bpf_map_lookup_elem(map_fd[1], &key, values) == 0); |
---|
| 574 | + assert(bpf_map_lookup_elem(rxcnt_map_fd, |
---|
| 575 | + &key, values) == 0); |
---|
557 | 576 | for (i = 0; i < nr_cpus; i++) |
---|
558 | 577 | sum += (values[i] - prev[key][i]); |
---|
559 | 578 | if (sum) |
---|
.. | .. |
---|
594 | 613 | return ret; |
---|
595 | 614 | } |
---|
596 | 615 | |
---|
| 616 | +static void usage(const char *prog) |
---|
| 617 | +{ |
---|
| 618 | + fprintf(stderr, |
---|
| 619 | + "%s: %s [OPTS] interface name list\n\n" |
---|
| 620 | + "OPTS:\n" |
---|
| 621 | + " -S use skb-mode\n" |
---|
| 622 | + " -F force loading prog\n", |
---|
| 623 | + __func__, prog); |
---|
| 624 | +} |
---|
| 625 | + |
---|
597 | 626 | int main(int ac, char **argv) |
---|
598 | 627 | { |
---|
| 628 | + struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY}; |
---|
| 629 | + struct bpf_prog_load_attr prog_load_attr = { |
---|
| 630 | + .prog_type = BPF_PROG_TYPE_XDP, |
---|
| 631 | + }; |
---|
| 632 | + struct bpf_prog_info info = {}; |
---|
| 633 | + __u32 info_len = sizeof(info); |
---|
| 634 | + const char *optstr = "SF"; |
---|
| 635 | + struct bpf_object *obj; |
---|
599 | 636 | char filename[256]; |
---|
600 | 637 | char **ifname_list; |
---|
601 | | - int i = 1; |
---|
| 638 | + int prog_fd, opt; |
---|
| 639 | + int err, i = 1; |
---|
602 | 640 | |
---|
603 | 641 | snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]); |
---|
604 | | - if (ac < 2) { |
---|
605 | | - printf("usage: %s [-S] Interface name list\n", argv[0]); |
---|
| 642 | + prog_load_attr.file = filename; |
---|
| 643 | + |
---|
| 644 | + total_ifindex = ac - 1; |
---|
| 645 | + ifname_list = (argv + 1); |
---|
| 646 | + |
---|
| 647 | + while ((opt = getopt(ac, argv, optstr)) != -1) { |
---|
| 648 | + switch (opt) { |
---|
| 649 | + case 'S': |
---|
| 650 | + flags |= XDP_FLAGS_SKB_MODE; |
---|
| 651 | + total_ifindex--; |
---|
| 652 | + ifname_list++; |
---|
| 653 | + break; |
---|
| 654 | + case 'F': |
---|
| 655 | + flags &= ~XDP_FLAGS_UPDATE_IF_NOEXIST; |
---|
| 656 | + total_ifindex--; |
---|
| 657 | + ifname_list++; |
---|
| 658 | + break; |
---|
| 659 | + default: |
---|
| 660 | + usage(basename(argv[0])); |
---|
| 661 | + return 1; |
---|
| 662 | + } |
---|
| 663 | + } |
---|
| 664 | + |
---|
| 665 | + if (!(flags & XDP_FLAGS_SKB_MODE)) |
---|
| 666 | + flags |= XDP_FLAGS_DRV_MODE; |
---|
| 667 | + |
---|
| 668 | + if (optind == ac) { |
---|
| 669 | + usage(basename(argv[0])); |
---|
606 | 670 | return 1; |
---|
607 | 671 | } |
---|
608 | | - if (!strcmp(argv[1], "-S")) { |
---|
609 | | - flags = XDP_FLAGS_SKB_MODE; |
---|
610 | | - total_ifindex = ac - 2; |
---|
611 | | - ifname_list = (argv + 2); |
---|
612 | | - } else { |
---|
613 | | - flags = 0; |
---|
614 | | - total_ifindex = ac - 1; |
---|
615 | | - ifname_list = (argv + 1); |
---|
616 | | - } |
---|
617 | | - if (load_bpf_file(filename)) { |
---|
618 | | - printf("%s", bpf_log_buf); |
---|
| 672 | + |
---|
| 673 | + if (setrlimit(RLIMIT_MEMLOCK, &r)) { |
---|
| 674 | + perror("setrlimit(RLIMIT_MEMLOCK)"); |
---|
619 | 675 | return 1; |
---|
620 | 676 | } |
---|
| 677 | + |
---|
| 678 | + if (bpf_prog_load_xattr(&prog_load_attr, &obj, &prog_fd)) |
---|
| 679 | + return 1; |
---|
| 680 | + |
---|
621 | 681 | printf("\n**************loading bpf file*********************\n\n\n"); |
---|
622 | | - if (!prog_fd[0]) { |
---|
623 | | - printf("load_bpf_file: %s\n", strerror(errno)); |
---|
| 682 | + if (!prog_fd) { |
---|
| 683 | + printf("bpf_prog_load_xattr: %s\n", strerror(errno)); |
---|
624 | 684 | return 1; |
---|
625 | 685 | } |
---|
626 | | - ifindex_list = (int *)malloc(total_ifindex * sizeof(int *)); |
---|
| 686 | + |
---|
| 687 | + lpm_map_fd = bpf_object__find_map_fd_by_name(obj, "lpm_map"); |
---|
| 688 | + rxcnt_map_fd = bpf_object__find_map_fd_by_name(obj, "rxcnt"); |
---|
| 689 | + arp_table_map_fd = bpf_object__find_map_fd_by_name(obj, "arp_table"); |
---|
| 690 | + exact_match_map_fd = bpf_object__find_map_fd_by_name(obj, |
---|
| 691 | + "exact_match"); |
---|
| 692 | + tx_port_map_fd = bpf_object__find_map_fd_by_name(obj, "tx_port"); |
---|
| 693 | + if (lpm_map_fd < 0 || rxcnt_map_fd < 0 || arp_table_map_fd < 0 || |
---|
| 694 | + exact_match_map_fd < 0 || tx_port_map_fd < 0) { |
---|
| 695 | + printf("bpf_object__find_map_fd_by_name failed\n"); |
---|
| 696 | + return 1; |
---|
| 697 | + } |
---|
| 698 | + |
---|
| 699 | + ifindex_list = (int *)calloc(total_ifindex, sizeof(int *)); |
---|
627 | 700 | for (i = 0; i < total_ifindex; i++) { |
---|
628 | 701 | ifindex_list[i] = if_nametoindex(ifname_list[i]); |
---|
629 | 702 | if (!ifindex_list[i]) { |
---|
.. | .. |
---|
632 | 705 | return 1; |
---|
633 | 706 | } |
---|
634 | 707 | } |
---|
| 708 | + prog_id_list = (__u32 *)calloc(total_ifindex, sizeof(__u32 *)); |
---|
635 | 709 | for (i = 0; i < total_ifindex; i++) { |
---|
636 | | - if (bpf_set_link_xdp_fd(ifindex_list[i], prog_fd[0], flags) < 0) { |
---|
| 710 | + if (bpf_set_link_xdp_fd(ifindex_list[i], prog_fd, flags) < 0) { |
---|
637 | 711 | printf("link set xdp fd failed\n"); |
---|
638 | 712 | int recovery_index = i; |
---|
639 | 713 | |
---|
.. | .. |
---|
642 | 716 | |
---|
643 | 717 | return 1; |
---|
644 | 718 | } |
---|
| 719 | + err = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len); |
---|
| 720 | + if (err) { |
---|
| 721 | + printf("can't get prog info - %s\n", strerror(errno)); |
---|
| 722 | + return err; |
---|
| 723 | + } |
---|
| 724 | + prog_id_list[i] = info.id; |
---|
| 725 | + memset(&info, 0, sizeof(info)); |
---|
645 | 726 | printf("Attached to %d\n", ifindex_list[i]); |
---|
646 | 727 | } |
---|
647 | 728 | signal(SIGINT, int_exit); |
---|