18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* Copyright (c) 2016 PLUMgrid 38c2ecf20Sopenharmony_ci */ 48c2ecf20Sopenharmony_ci#include <linux/bpf.h> 58c2ecf20Sopenharmony_ci#include <linux/if_link.h> 68c2ecf20Sopenharmony_ci#include <assert.h> 78c2ecf20Sopenharmony_ci#include <errno.h> 88c2ecf20Sopenharmony_ci#include <signal.h> 98c2ecf20Sopenharmony_ci#include <stdio.h> 108c2ecf20Sopenharmony_ci#include <stdlib.h> 118c2ecf20Sopenharmony_ci#include <string.h> 128c2ecf20Sopenharmony_ci#include <unistd.h> 138c2ecf20Sopenharmony_ci#include <libgen.h> 148c2ecf20Sopenharmony_ci#include <sys/resource.h> 158c2ecf20Sopenharmony_ci#include <net/if.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include "bpf_util.h" 188c2ecf20Sopenharmony_ci#include <bpf/bpf.h> 198c2ecf20Sopenharmony_ci#include <bpf/libbpf.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistatic int ifindex; 228c2ecf20Sopenharmony_cistatic __u32 xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST; 238c2ecf20Sopenharmony_cistatic __u32 prog_id; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic void int_exit(int sig) 268c2ecf20Sopenharmony_ci{ 278c2ecf20Sopenharmony_ci __u32 curr_prog_id = 0; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci if (bpf_get_link_xdp_id(ifindex, &curr_prog_id, xdp_flags)) { 308c2ecf20Sopenharmony_ci printf("bpf_get_link_xdp_id failed\n"); 318c2ecf20Sopenharmony_ci exit(1); 328c2ecf20Sopenharmony_ci } 338c2ecf20Sopenharmony_ci if (prog_id == curr_prog_id) 348c2ecf20Sopenharmony_ci bpf_set_link_xdp_fd(ifindex, -1, xdp_flags); 358c2ecf20Sopenharmony_ci else if (!curr_prog_id) 368c2ecf20Sopenharmony_ci printf("couldn't find a prog id on a given interface\n"); 378c2ecf20Sopenharmony_ci else 388c2ecf20Sopenharmony_ci printf("program on interface changed, not removing\n"); 398c2ecf20Sopenharmony_ci exit(0); 408c2ecf20Sopenharmony_ci} 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* simple per-protocol drop counter 438c2ecf20Sopenharmony_ci */ 448c2ecf20Sopenharmony_cistatic void poll_stats(int map_fd, int interval) 458c2ecf20Sopenharmony_ci{ 468c2ecf20Sopenharmony_ci unsigned int nr_cpus = bpf_num_possible_cpus(); 478c2ecf20Sopenharmony_ci __u64 values[nr_cpus], prev[UINT8_MAX] = { 0 }; 488c2ecf20Sopenharmony_ci int i; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci while (1) { 518c2ecf20Sopenharmony_ci __u32 key = UINT32_MAX; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci sleep(interval); 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci while (bpf_map_get_next_key(map_fd, &key, &key) != -1) { 568c2ecf20Sopenharmony_ci __u64 sum = 0; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci assert(bpf_map_lookup_elem(map_fd, &key, values) == 0); 598c2ecf20Sopenharmony_ci for (i = 0; i < nr_cpus; i++) 608c2ecf20Sopenharmony_ci sum += values[i]; 618c2ecf20Sopenharmony_ci if (sum > prev[key]) 628c2ecf20Sopenharmony_ci printf("proto %u: %10llu pkt/s\n", 638c2ecf20Sopenharmony_ci key, (sum - prev[key]) / interval); 648c2ecf20Sopenharmony_ci prev[key] = sum; 658c2ecf20Sopenharmony_ci } 668c2ecf20Sopenharmony_ci } 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic void usage(const char *prog) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci fprintf(stderr, 728c2ecf20Sopenharmony_ci "usage: %s [OPTS] IFACE\n\n" 738c2ecf20Sopenharmony_ci "OPTS:\n" 748c2ecf20Sopenharmony_ci " -S use skb-mode\n" 758c2ecf20Sopenharmony_ci " -N enforce native mode\n" 768c2ecf20Sopenharmony_ci " -F force loading prog\n", 778c2ecf20Sopenharmony_ci prog); 788c2ecf20Sopenharmony_ci} 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ciint main(int argc, char **argv) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY}; 838c2ecf20Sopenharmony_ci struct bpf_prog_load_attr prog_load_attr = { 848c2ecf20Sopenharmony_ci .prog_type = BPF_PROG_TYPE_XDP, 858c2ecf20Sopenharmony_ci }; 868c2ecf20Sopenharmony_ci struct bpf_prog_info info = {}; 878c2ecf20Sopenharmony_ci __u32 info_len = sizeof(info); 888c2ecf20Sopenharmony_ci const char *optstr = "FSN"; 898c2ecf20Sopenharmony_ci int prog_fd, map_fd, opt; 908c2ecf20Sopenharmony_ci struct bpf_object *obj; 918c2ecf20Sopenharmony_ci struct bpf_map *map; 928c2ecf20Sopenharmony_ci char filename[256]; 938c2ecf20Sopenharmony_ci int err; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci while ((opt = getopt(argc, argv, optstr)) != -1) { 968c2ecf20Sopenharmony_ci switch (opt) { 978c2ecf20Sopenharmony_ci case 'S': 988c2ecf20Sopenharmony_ci xdp_flags |= XDP_FLAGS_SKB_MODE; 998c2ecf20Sopenharmony_ci break; 1008c2ecf20Sopenharmony_ci case 'N': 1018c2ecf20Sopenharmony_ci /* default, set below */ 1028c2ecf20Sopenharmony_ci break; 1038c2ecf20Sopenharmony_ci case 'F': 1048c2ecf20Sopenharmony_ci xdp_flags &= ~XDP_FLAGS_UPDATE_IF_NOEXIST; 1058c2ecf20Sopenharmony_ci break; 1068c2ecf20Sopenharmony_ci default: 1078c2ecf20Sopenharmony_ci usage(basename(argv[0])); 1088c2ecf20Sopenharmony_ci return 1; 1098c2ecf20Sopenharmony_ci } 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci if (!(xdp_flags & XDP_FLAGS_SKB_MODE)) 1138c2ecf20Sopenharmony_ci xdp_flags |= XDP_FLAGS_DRV_MODE; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci if (optind == argc) { 1168c2ecf20Sopenharmony_ci usage(basename(argv[0])); 1178c2ecf20Sopenharmony_ci return 1; 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci if (setrlimit(RLIMIT_MEMLOCK, &r)) { 1218c2ecf20Sopenharmony_ci perror("setrlimit(RLIMIT_MEMLOCK)"); 1228c2ecf20Sopenharmony_ci return 1; 1238c2ecf20Sopenharmony_ci } 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci ifindex = if_nametoindex(argv[optind]); 1268c2ecf20Sopenharmony_ci if (!ifindex) { 1278c2ecf20Sopenharmony_ci perror("if_nametoindex"); 1288c2ecf20Sopenharmony_ci return 1; 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]); 1328c2ecf20Sopenharmony_ci prog_load_attr.file = filename; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci if (bpf_prog_load_xattr(&prog_load_attr, &obj, &prog_fd)) 1358c2ecf20Sopenharmony_ci return 1; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci map = bpf_map__next(NULL, obj); 1388c2ecf20Sopenharmony_ci if (!map) { 1398c2ecf20Sopenharmony_ci printf("finding a map in obj file failed\n"); 1408c2ecf20Sopenharmony_ci return 1; 1418c2ecf20Sopenharmony_ci } 1428c2ecf20Sopenharmony_ci map_fd = bpf_map__fd(map); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci if (!prog_fd) { 1458c2ecf20Sopenharmony_ci printf("bpf_prog_load_xattr: %s\n", strerror(errno)); 1468c2ecf20Sopenharmony_ci return 1; 1478c2ecf20Sopenharmony_ci } 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci signal(SIGINT, int_exit); 1508c2ecf20Sopenharmony_ci signal(SIGTERM, int_exit); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci if (bpf_set_link_xdp_fd(ifindex, prog_fd, xdp_flags) < 0) { 1538c2ecf20Sopenharmony_ci printf("link set xdp fd failed\n"); 1548c2ecf20Sopenharmony_ci return 1; 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci err = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len); 1588c2ecf20Sopenharmony_ci if (err) { 1598c2ecf20Sopenharmony_ci printf("can't get prog info - %s\n", strerror(errno)); 1608c2ecf20Sopenharmony_ci return err; 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci prog_id = info.id; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci poll_stats(map_fd, 2); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci return 0; 1678c2ecf20Sopenharmony_ci} 168