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