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