1 // SPDX-License-Identifier: GPL-2.0 2 #include <error.h> 3 #include <errno.h> 4 #include <getopt.h> 5 #include <stdio.h> 6 #include <stdlib.h> 7 #include <string.h> 8 #include <sys/stat.h> 9 #include <fcntl.h> 10 #include <unistd.h> 11 #include <bpf/bpf.h> 12 #include <bpf/libbpf.h> 13 14 const char *cfg_pin_path = "/sys/fs/bpf/flow_dissector"; 15 const char *cfg_map_name = "jmp_table"; 16 bool cfg_attach = true; 17 char *cfg_section_name; 18 char *cfg_path_name; 19 20 static void load_and_attach_program(void) 21 { 22 struct bpf_program *prog, *main_prog; 23 struct bpf_map *prog_array; 24 int i, fd, prog_fd, ret; 25 struct bpf_object *obj; 26 int prog_array_fd; 27 28 ret = bpf_prog_load(cfg_path_name, BPF_PROG_TYPE_FLOW_DISSECTOR, &obj, 29 &prog_fd); 30 if (ret) 31 error(1, 0, "bpf_prog_load %s", cfg_path_name); 32 33 main_prog = bpf_object__find_program_by_title(obj, cfg_section_name); 34 if (!main_prog) 35 error(1, 0, "bpf_object__find_program_by_title %s", 36 cfg_section_name); 37 38 prog_fd = bpf_program__fd(main_prog); 39 if (prog_fd < 0) 40 error(1, 0, "bpf_program__fd"); 41 42 prog_array = bpf_object__find_map_by_name(obj, cfg_map_name); 43 if (!prog_array) 44 error(1, 0, "bpf_object__find_map_by_name %s", cfg_map_name); 45 46 prog_array_fd = bpf_map__fd(prog_array); 47 if (prog_array_fd < 0) 48 error(1, 0, "bpf_map__fd %s", cfg_map_name); 49 50 i = 0; 51 bpf_object__for_each_program(prog, obj) { 52 fd = bpf_program__fd(prog); 53 if (fd < 0) 54 error(1, 0, "bpf_program__fd"); 55 56 if (fd != prog_fd) { 57 printf("%d: %s\n", i, bpf_program__title(prog, false)); 58 bpf_map_update_elem(prog_array_fd, &i, &fd, BPF_ANY); 59 ++i; 60 } 61 } 62 63 ret = bpf_prog_attach(prog_fd, 0 /* Ignore */, BPF_FLOW_DISSECTOR, 0); 64 if (ret) 65 error(1, 0, "bpf_prog_attach %s", cfg_path_name); 66 67 ret = bpf_object__pin(obj, cfg_pin_path); 68 if (ret) 69 error(1, 0, "bpf_object__pin %s", cfg_pin_path); 70 71 } 72 73 static void detach_program(void) 74 { 75 char command[64]; 76 int ret; 77 78 ret = bpf_prog_detach(0, BPF_FLOW_DISSECTOR); 79 if (ret) 80 error(1, 0, "bpf_prog_detach"); 81 82 /* To unpin, it is necessary and sufficient to just remove this dir */ 83 sprintf(command, "rm -r %s", cfg_pin_path); 84 ret = system(command); 85 if (ret) 86 error(1, errno, command); 87 } 88 89 static void parse_opts(int argc, char **argv) 90 { 91 bool attach = false; 92 bool detach = false; 93 int c; 94 95 while ((c = getopt(argc, argv, "adp:s:")) != -1) { 96 switch (c) { 97 case 'a': 98 if (detach) 99 error(1, 0, "attach/detach are exclusive"); 100 attach = true; 101 break; 102 case 'd': 103 if (attach) 104 error(1, 0, "attach/detach are exclusive"); 105 detach = true; 106 break; 107 case 'p': 108 if (cfg_path_name) 109 error(1, 0, "only one prog name can be given"); 110 111 cfg_path_name = optarg; 112 break; 113 case 's': 114 if (cfg_section_name) 115 error(1, 0, "only one section can be given"); 116 117 cfg_section_name = optarg; 118 break; 119 } 120 } 121 122 if (detach) 123 cfg_attach = false; 124 125 if (cfg_attach && !cfg_path_name) 126 error(1, 0, "must provide a path to the BPF program"); 127 128 if (cfg_attach && !cfg_section_name) 129 error(1, 0, "must provide a section name"); 130 } 131 132 int main(int argc, char **argv) 133 { 134 parse_opts(argc, argv); 135 if (cfg_attach) 136 load_and_attach_program(); 137 else 138 detach_program(); 139 return 0; 140 } 141