xref: /aosp_15_r20/external/bcc/libbpf-tools/tcpsynbl.c (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
1 // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
2 // Copyright (c) 2021 Yaqi Chen
3 //
4 // Based on tcpsynbl(8) from BCC by Brendan Gregg.
5 // 19-Dec-2021   Yaqi Chen   Created this.
6 #include <argp.h>
7 #include <stdio.h>
8 #include <signal.h>
9 #include <unistd.h>
10 #include <time.h>
11 #include <bpf/libbpf.h>
12 #include <bpf/bpf.h>
13 #include "tcpsynbl.h"
14 #include "tcpsynbl.skel.h"
15 #include "btf_helpers.h"
16 #include "trace_helpers.h"
17 
18 static struct env {
19 	bool ipv4;
20 	bool ipv6;
21 	time_t interval;
22 	int times;
23 	bool timestamp;
24 	bool verbose;
25 } env = {
26 	.interval = 99999999,
27 	.times = 99999999,
28 };
29 
30 static volatile sig_atomic_t exiting = 0;
31 
32 const char *argp_program_version = "tcpsynbl 0.1";
33 const char *argp_program_bug_address =
34 	"https://github.com/iovisor/bcc/tree/master/libbpf-tools";
35 const char argp_program_doc[] =
36 "Summarize TCP SYN backlog as a histogram.\n"
37 "\n"
38 "USAGE: tcpsynbl [--help] [-T] [-4] [-6] [interval] [count]\n"
39 "\n"
40 "EXAMPLES:\n"
41 "    tcpsynbl              # summarize TCP SYN backlog as a histogram\n"
42 "    tcpsynbl 1 10         # print 1 second summaries, 10 times\n"
43 "    tcpsynbl -T 1         # 1s summaries with timestamps\n"
44 "    tcpsynbl -4           # trace IPv4 family only\n"
45 "    tcpsynbl -6           # trace IPv6 family only\n";
46 
47 
48 static const struct argp_option opts[] = {
49 	{ "timestamp", 'T', NULL, 0, "Include timestamp on output" },
50 	{ "ipv4", '4', NULL, 0, "Trace IPv4 family only" },
51 	{ "ipv6", '6', NULL, 0, "Trace IPv6 family only" },
52 	{ "verbose", 'v', NULL, 0, "Verbose debug output" },
53 	{ NULL, 'h', NULL, OPTION_HIDDEN, "Show the full help" },
54 	{},
55 };
56 
57 
parse_arg(int key,char * arg,struct argp_state * state)58 static error_t parse_arg(int key, char *arg, struct argp_state *state)
59 {
60 	static int pos_args;
61 
62 	switch (key) {
63 	case 'h':
64 		argp_state_help(state, stderr, ARGP_HELP_STD_HELP);
65 		break;
66 	case 'v':
67 		env.verbose = true;
68 		break;
69 	case 'T':
70 		env.timestamp = true;
71 		break;
72 	case '4':
73 		env.ipv4 = true;
74 		break;
75 	case '6':
76 		env.ipv6 = true;
77 		break;
78 	case ARGP_KEY_ARG:
79 		errno = 0;
80 		if (pos_args == 0) {
81 			env.interval = strtol(arg, NULL, 10);
82 			if (errno) {
83 				fprintf(stderr, "invalid internal\n");
84 				argp_usage(state);
85 			}
86 		} else if (pos_args == 1) {
87 			env.times = strtol(arg, NULL, 10);
88 			if (errno) {
89 				fprintf(stderr, "invalid times\n");
90 				argp_usage(state);
91 			}
92 		} else {
93 			fprintf(stderr,
94 				"unrecognized positional argument: %s\n", arg);
95 			argp_usage(state);
96 		}
97 		pos_args++;
98 		break;
99 	default:
100 		return ARGP_ERR_UNKNOWN;
101 	}
102 	return 0;
103 }
104 
libbpf_print_fn(enum libbpf_print_level level,const char * format,va_list args)105 static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args)
106 {
107 	if (level == LIBBPF_DEBUG && !env.verbose)
108 		return 0;
109 	return vfprintf(stderr, format, args);
110 }
111 
sig_handler(int sig)112 static void sig_handler(int sig)
113 {
114 	exiting = true;
115 }
116 
disable_all_progs(struct tcpsynbl_bpf * obj)117 static void disable_all_progs(struct tcpsynbl_bpf *obj)
118 {
119 	bpf_program__set_autoload(obj->progs.tcp_v4_syn_recv_kprobe, false);
120 	bpf_program__set_autoload(obj->progs.tcp_v6_syn_recv_kprobe, false);
121 	bpf_program__set_autoload(obj->progs.tcp_v4_syn_recv, false);
122 	bpf_program__set_autoload(obj->progs.tcp_v6_syn_recv, false);
123 }
124 
set_autoload_prog(struct tcpsynbl_bpf * obj,int version)125 static void set_autoload_prog(struct tcpsynbl_bpf *obj, int version)
126 {
127 	if (version == 4) {
128 		if (fentry_can_attach("tcp_v4_syn_recv_sock", NULL))
129 			bpf_program__set_autoload(obj->progs.tcp_v4_syn_recv, true);
130 		else
131 			bpf_program__set_autoload(obj->progs.tcp_v4_syn_recv_kprobe, true);
132 	}
133 
134 	if (version == 6){
135 		if (fentry_can_attach("tcp_v6_syn_recv_sock", NULL))
136 			bpf_program__set_autoload(obj->progs.tcp_v6_syn_recv, true);
137 		else
138 			bpf_program__set_autoload(obj->progs.tcp_v6_syn_recv_kprobe, true);
139 	}
140 }
141 
print_log2_hists(int fd)142 static int print_log2_hists(int fd)
143 {
144 	__u64 lookup_key = -1, next_key;
145 	struct hist hist;
146 	int err;
147 
148 	while (!bpf_map_get_next_key(fd, &lookup_key, &next_key)) {
149 		err = bpf_map_lookup_elem(fd, &next_key, &hist);
150 		if (err < 0) {
151 			fprintf(stderr, "failed to lookup hist: %d\n", err);
152 			return -1;
153 		}
154 		printf("backlog_max = %lld\n", next_key);
155 		print_log2_hist(hist.slots, MAX_SLOTS, "backlog");
156 		lookup_key = next_key;
157 	}
158 
159 	lookup_key = -1;
160 	while (!bpf_map_get_next_key(fd, &lookup_key, &next_key)) {
161 		err = bpf_map_delete_elem(fd, &next_key);
162 		if (err < 0) {
163 			fprintf(stderr, "failed to cleanup hist : %d\n", err);
164 			return -1;
165 		}
166 		lookup_key = next_key;
167 	}
168 
169 	return 0;
170 }
171 
main(int argc,char ** argv)172 int main(int argc, char **argv)
173 {
174 	LIBBPF_OPTS(bpf_object_open_opts, open_opts);
175 	static const struct argp argp = {
176 		.options = opts,
177 		.parser = parse_arg,
178 		.doc = argp_program_doc
179 	};
180 
181 	struct tcpsynbl_bpf *obj;
182 	struct tm *tm;
183 	char ts[32];
184 	time_t t;
185 	int err, map_fd;
186 
187 	err = argp_parse(&argp, argc, argv, 0, NULL, NULL);
188 	if (err)
189 		return err;
190 
191 	libbpf_set_print(libbpf_print_fn);
192 
193 	err = ensure_core_btf(&open_opts);
194 	if (err) {
195 		fprintf(stderr, "failed to fetch necessary BTF for CO-RE: %s\n", strerror(-err));
196 		return 1;
197 	}
198 
199 	obj = tcpsynbl_bpf__open_opts(&open_opts);
200 	if (!obj) {
201 		fprintf(stderr, "failed to open BPF object\n");
202 		return 1;
203 	}
204 
205 	disable_all_progs(obj);
206 
207 	if (env.ipv4) {
208 		set_autoload_prog(obj, 4);
209 	} else if (env.ipv6) {
210 		set_autoload_prog(obj, 6);
211 	} else {
212 		set_autoload_prog(obj, 4);
213 		set_autoload_prog(obj, 6);
214 	}
215 
216 	err = tcpsynbl_bpf__load(obj);
217 	if (err) {
218 		fprintf(stderr, "failed to load BPF object: %d\n", err);
219 		goto cleanup;
220 	}
221 
222 	err = tcpsynbl_bpf__attach(obj);
223 	if (err) {
224 		fprintf(stderr, "failed to attach BPF programs\n");
225 		goto cleanup;
226 	}
227 
228 	map_fd= bpf_map__fd(obj->maps.hists);
229 
230 	signal(SIGINT, sig_handler);
231 
232 	printf("Tracing SYN backlog size. Ctrl-C to end.\n");
233 
234 	/* main: poll */
235 	while (1) {
236 		sleep(env.interval);
237 		printf("\n");
238 
239 		if (env.timestamp) {
240 			time(&t);
241 			tm = localtime(&t);
242 			strftime(ts, sizeof(ts), "%H:%M:%S", tm);
243 			printf("%-8s\n", ts);
244 		}
245 
246 		err = print_log2_hists(map_fd);
247 		if (err)
248 			break;
249 
250 		if (exiting || --env.times == 0)
251 			break;
252 	}
253 
254 cleanup:
255 	tcpsynbl_bpf__destroy(obj);
256 	cleanup_core_btf(&open_opts);
257 
258 	return err != 0;
259 }
260