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 "flow_dissector_load.h"
15
16const char *cfg_pin_path = "/sys/fs/bpf/flow_dissector";
17const char *cfg_map_name = "jmp_table";
18bool cfg_attach = true;
19char *cfg_prog_name;
20char *cfg_path_name;
21
22static void load_and_attach_program(void)
23{
24	int prog_fd, ret;
25	struct bpf_object *obj;
26
27	/* Use libbpf 1.0 API mode */
28	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
29
30	ret = bpf_flow_load(&obj, cfg_path_name, cfg_prog_name,
31			    cfg_map_name, NULL, &prog_fd, NULL);
32	if (ret)
33		error(1, 0, "bpf_flow_load %s", cfg_path_name);
34
35	ret = bpf_prog_attach(prog_fd, 0 /* Ignore */, BPF_FLOW_DISSECTOR, 0);
36	if (ret)
37		error(1, 0, "bpf_prog_attach %s", cfg_path_name);
38
39	ret = bpf_object__pin(obj, cfg_pin_path);
40	if (ret)
41		error(1, 0, "bpf_object__pin %s", cfg_pin_path);
42}
43
44static void detach_program(void)
45{
46	char command[64];
47	int ret;
48
49	ret = bpf_prog_detach(0, BPF_FLOW_DISSECTOR);
50	if (ret)
51		error(1, 0, "bpf_prog_detach");
52
53	/* To unpin, it is necessary and sufficient to just remove this dir */
54	sprintf(command, "rm -r %s", cfg_pin_path);
55	ret = system(command);
56	if (ret)
57		error(1, errno, "%s", command);
58}
59
60static void parse_opts(int argc, char **argv)
61{
62	bool attach = false;
63	bool detach = false;
64	int c;
65
66	while ((c = getopt(argc, argv, "adp:s:")) != -1) {
67		switch (c) {
68		case 'a':
69			if (detach)
70				error(1, 0, "attach/detach are exclusive");
71			attach = true;
72			break;
73		case 'd':
74			if (attach)
75				error(1, 0, "attach/detach are exclusive");
76			detach = true;
77			break;
78		case 'p':
79			if (cfg_path_name)
80				error(1, 0, "only one path can be given");
81
82			cfg_path_name = optarg;
83			break;
84		case 's':
85			if (cfg_prog_name)
86				error(1, 0, "only one prog can be given");
87
88			cfg_prog_name = optarg;
89			break;
90		}
91	}
92
93	if (detach)
94		cfg_attach = false;
95
96	if (cfg_attach && !cfg_path_name)
97		error(1, 0, "must provide a path to the BPF program");
98
99	if (cfg_attach && !cfg_prog_name)
100		error(1, 0, "must provide a section name");
101}
102
103int main(int argc, char **argv)
104{
105	parse_opts(argc, argv);
106	if (cfg_attach)
107		load_and_attach_program();
108	else
109		detach_program();
110	return 0;
111}
112