| .. | .. |
|---|
| 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); |
|---|