1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 2 3 /** 4 * ibumad BPF sample user side 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of version 2 of the GNU General Public 8 * License as published by the Free Software Foundation. 9 * 10 * Copyright(c) 2018 Ira Weiny, Intel Corporation 11 */ 12 13 #include <linux/bpf.h> 14 #include <signal.h> 15 #include <stdio.h> 16 #include <stdlib.h> 17 #include <string.h> 18 #include <unistd.h> 19 #include <sys/types.h> 20 #include <limits.h> 21 22 #include <sys/resource.h> 23 #include <getopt.h> 24 #include <net/if.h> 25 26 #include <bpf/bpf.h> 27 #include "bpf_util.h" 28 #include <bpf/libbpf.h> 29 30 static struct bpf_link *tp_links[3]; 31 static struct bpf_object *obj; 32 static int map_fd[2]; 33 static int tp_cnt; 34 35 static void dump_counts(int fd) 36 { 37 __u32 key; 38 __u64 value; 39 40 for (key = 0; key < 256; key++) { 41 if (bpf_map_lookup_elem(fd, &key, &value)) { 42 printf("failed to read key %u\n", key); 43 continue; 44 } 45 if (value) 46 printf("0x%02x : %llu\n", key, value); 47 } 48 } 49 50 static void dump_all_counts(void) 51 { 52 printf("Read 'Class : count'\n"); 53 dump_counts(map_fd[0]); 54 printf("Write 'Class : count'\n"); 55 dump_counts(map_fd[1]); 56 } 57 58 static void dump_exit(int sig) 59 { 60 dump_all_counts(); 61 /* Detach tracepoints */ 62 while (tp_cnt) 63 bpf_link__destroy(tp_links[--tp_cnt]); 64 65 bpf_object__close(obj); 66 exit(0); 67 } 68 69 static const struct option long_options[] = { 70 {"help", no_argument, NULL, 'h'}, 71 {"delay", required_argument, NULL, 'd'}, 72 }; 73 74 static void usage(char *cmd) 75 { 76 printf("eBPF test program to count packets from various IP addresses\n" 77 "Usage: %s <options>\n" 78 " --help, -h this menu\n" 79 " --delay, -d <delay> wait <delay> sec between prints [1 - 1000000]\n" 80 , cmd 81 ); 82 } 83 84 int main(int argc, char **argv) 85 { 86 struct bpf_program *prog; 87 unsigned long delay = 5; 88 char filename[256]; 89 int longindex = 0; 90 int opt, err = -1; 91 92 while ((opt = getopt_long(argc, argv, "hd:rSw", 93 long_options, &longindex)) != -1) { 94 switch (opt) { 95 case 'd': 96 delay = strtoul(optarg, NULL, 0); 97 if (delay == ULONG_MAX || delay < 0 || 98 delay > 1000000) { 99 fprintf(stderr, "ERROR: invalid delay : %s\n", 100 optarg); 101 usage(argv[0]); 102 return 1; 103 } 104 break; 105 default: 106 case 'h': 107 usage(argv[0]); 108 return 1; 109 } 110 } 111 112 /* Do one final dump when exiting */ 113 signal(SIGINT, dump_exit); 114 signal(SIGTERM, dump_exit); 115 116 snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]); 117 obj = bpf_object__open_file(filename, NULL); 118 if (libbpf_get_error(obj)) { 119 fprintf(stderr, "ERROR: opening BPF object file failed\n"); 120 return err; 121 } 122 123 /* load BPF program */ 124 if (bpf_object__load(obj)) { 125 fprintf(stderr, "ERROR: loading BPF object file failed\n"); 126 goto cleanup; 127 } 128 129 map_fd[0] = bpf_object__find_map_fd_by_name(obj, "read_count"); 130 map_fd[1] = bpf_object__find_map_fd_by_name(obj, "write_count"); 131 if (map_fd[0] < 0 || map_fd[1] < 0) { 132 fprintf(stderr, "ERROR: finding a map in obj file failed\n"); 133 goto cleanup; 134 } 135 136 bpf_object__for_each_program(prog, obj) { 137 tp_links[tp_cnt] = bpf_program__attach(prog); 138 if (libbpf_get_error(tp_links[tp_cnt])) { 139 fprintf(stderr, "ERROR: bpf_program__attach failed\n"); 140 tp_links[tp_cnt] = NULL; 141 goto cleanup; 142 } 143 tp_cnt++; 144 } 145 146 while (1) { 147 sleep(delay); 148 dump_all_counts(); 149 } 150 err = 0; 151 152 cleanup: 153 /* Detach tracepoints */ 154 while (tp_cnt) 155 bpf_link__destroy(tp_links[--tp_cnt]); 156 157 bpf_object__close(obj); 158 return err; 159 } 160