master
c 2,474 lines 79.8 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include <sys/time.h>
4 #include <sys/resource.h>
5 #include <ifaddrs.h>
6 #include <errno.h>
7 #include <stdint.h>
8
9 #include "ebpf.h"
10 #include "ebpf_socket.h"
11 #include "ebpf_unittest.h"
12 #include "libbpf_api/ebpf_library.h"
13 #include "libnetdata/libjudy/judy-malloc.h"
14
15 /*****************************************************************
16 *
17 * GLOBAL VARIABLES
18 *
19 *****************************************************************/
20
21 char *ebpf_plugin_dir = PLUGINS_DIR;
22 static char *ebpf_configured_log_dir = LOG_DIR;
23
24 char *ebpf_algorithms[] = {EBPF_CHART_ALGORITHM_ABSOLUTE, EBPF_CHART_ALGORITHM_INCREMENTAL};
25 struct config collector_config = APPCONFIG_INITIALIZER;
26
27 int running_on_kernel = 0;
28 int ebpf_nprocs;
29 int isrh = 0;
30 int main_thread_id = 0;
31 int process_pid_fd = -1;
32 uint64_t collect_pids = 0;
33 uint32_t integration_with_collectors = NETDATA_EBPF_INTEGRATION_DISABLED;
34 ND_THREAD *socket_ipc = NULL;
35 static size_t global_iterations_counter = 1;
36 bool publish_internal_metrics = true;
37 bool ebpf_program_loaded_any = false;
38
39 netdata_mutex_t lock;
40 netdata_mutex_t ebpf_exit_cleanup;
41 netdata_mutex_t collect_data_mutex;
42
43 struct netdata_static_thread cgroup_integration_thread = {
44 .name = "EBPF CGROUP INT",
45 .config_section = NULL,
46 .config_name = NULL,
47 .env_name = NULL,
48 .enabled = 1,
49 .thread = NULL,
50 .init_routine = NULL,
51 .start_routine = NULL};
52
53 static void ebpf_socket_unload_bpf(ebpf_module_t *em);
54
55 ebpf_module_t ebpf_modules[] = {
56 {.info =
57 {.thread_name = "process", .config_name = "process", .thread_description = NETDATA_EBPF_MODULE_PROCESS_DESC},
58 .functions =
59 {.start_routine = ebpf_process_thread,
60 .apps_routine = ebpf_process_create_apps_charts,
61 .fnct_routine = NULL,
62 .bpf_unload = ebpf_unload_legacy_bpf},
63 .enabled = NETDATA_THREAD_EBPF_NOT_RUNNING,
64 .update_every = EBPF_DEFAULT_UPDATE_EVERY,
65 .global_charts = 1,
66 .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
67 .apps_level = NETDATA_APPS_LEVEL_REAL_PARENT,
68 .cgroup_charts = CONFIG_BOOLEAN_NO,
69 .mode = MODE_ENTRY,
70 .optional = 0,
71 .maps = NULL,
72 .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE,
73 .names = NULL,
74 .cfg = &process_config,
75 .config_file = NETDATA_PROCESS_CONFIG_FILE,
76 .kernels =
77 NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_10 | NETDATA_V5_14,
78 .load = EBPF_LOAD_LEGACY,
79 .targets = process_targets,
80 .probe_links = NULL,
81 .objects = NULL,
82 .thread = NULL,
83 .maps_per_core = CONFIG_BOOLEAN_YES,
84 .lifetime = EBPF_DEFAULT_LIFETIME,
85 .running_time = 0},
86 {.info = {.thread_name = "socket", .config_name = "socket", .thread_description = NETDATA_EBPF_SOCKET_MODULE_DESC},
87 .functions =
88 {.start_routine = ebpf_socket_thread,
89 .apps_routine = ebpf_socket_create_apps_charts,
90 .fnct_routine = ebpf_socket_read_open_connections,
91 .bpf_unload = ebpf_socket_unload_bpf,
92 .fcnt_name = EBPF_FUNCTION_SOCKET,
93 .fcnt_desc = EBPF_PLUGIN_SOCKET_FUNCTION_DESCRIPTION,
94 .fcnt_thread_chart_name = NULL,
95 .fcnt_thread_lifetime_name = NULL},
96 .enabled = NETDATA_THREAD_EBPF_NOT_RUNNING,
97 .update_every = EBPF_DEFAULT_UPDATE_EVERY,
98 .global_charts = 1,
99 .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
100 .apps_level = NETDATA_APPS_LEVEL_REAL_PARENT,
101 .cgroup_charts = CONFIG_BOOLEAN_NO,
102 .mode = MODE_ENTRY,
103 .optional = 0,
104 .maps = NULL,
105 .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE,
106 .names = NULL,
107 .cfg = &socket_config,
108 .config_file = NETDATA_NETWORK_CONFIG_FILE,
109 .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14,
110 .load = EBPF_LOAD_LEGACY,
111 .targets = socket_targets,
112 .probe_links = NULL,
113 .objects = NULL,
114 .thread = NULL,
115 .maps_per_core = CONFIG_BOOLEAN_YES,
116 .lifetime = EBPF_DEFAULT_LIFETIME,
117 .running_time = 0},
118 {.info =
119 {.thread_name = "cachestat",
120 .config_name = "cachestat",
121 .thread_description = NETDATA_EBPF_CACHESTAT_MODULE_DESC},
122 .functions =
123 {.start_routine = ebpf_cachestat_thread,
124 .apps_routine = ebpf_cachestat_create_apps_charts,
125 .fnct_routine = NULL,
126 .bpf_unload = ebpf_cachestat_unload_bpf},
127 .enabled = NETDATA_THREAD_EBPF_NOT_RUNNING,
128 .update_every = EBPF_DEFAULT_UPDATE_EVERY,
129 .global_charts = 1,
130 .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
131 .apps_level = NETDATA_APPS_LEVEL_REAL_PARENT,
132 .cgroup_charts = CONFIG_BOOLEAN_NO,
133 .mode = MODE_ENTRY,
134 .optional = 0,
135 .maps = cachestat_maps,
136 .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE,
137 .names = NULL,
138 .cfg = &cachestat_config,
139 .config_file = NETDATA_CACHESTAT_CONFIG_FILE,
140 .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14 |
141 NETDATA_V5_15 | NETDATA_V5_16,
142 .load = EBPF_LOAD_LEGACY,
143 .targets = cachestat_targets,
144 .probe_links = NULL,
145 .objects = NULL,
146 .thread = NULL,
147 .maps_per_core = CONFIG_BOOLEAN_YES,
148 .lifetime = EBPF_DEFAULT_LIFETIME,
149 .running_time = 0},
150 {.info = {.thread_name = "sync", .config_name = "sync", .thread_description = NETDATA_EBPF_SYNC_MODULE_DESC},
151 .functions =
152 {.start_routine = ebpf_sync_thread,
153 .apps_routine = NULL,
154 .fnct_routine = NULL,
155 .bpf_unload = ebpf_sync_unload_bpf},
156 .enabled = NETDATA_THREAD_EBPF_NOT_RUNNING,
157 .maps = NULL,
158 .update_every = EBPF_DEFAULT_UPDATE_EVERY,
159 .global_charts = 1,
160 .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
161 .apps_level = NETDATA_APPS_NOT_SET,
162 .cgroup_charts = CONFIG_BOOLEAN_NO,
163 .mode = MODE_ENTRY,
164 .optional = 0,
165 .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE,
166 .names = NULL,
167 .cfg = &sync_config,
168 .config_file = NETDATA_SYNC_CONFIG_FILE,
169 // All syscalls have the same kernels
170 .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14,
171 .load = EBPF_LOAD_LEGACY,
172 .targets = sync_targets,
173 .probe_links = NULL,
174 .objects = NULL,
175 .thread = NULL,
176 .maps_per_core = CONFIG_BOOLEAN_YES,
177 .lifetime = EBPF_DEFAULT_LIFETIME,
178 .running_time = 0},
179 {.info = {.thread_name = "dc", .config_name = "dc", .thread_description = NETDATA_EBPF_DC_MODULE_DESC},
180 .functions =
181 {.start_routine = ebpf_dcstat_thread,
182 .apps_routine = ebpf_dcstat_create_apps_charts,
183 .fnct_routine = NULL,
184 .bpf_unload = ebpf_dcstat_unload_bpf},
185 .enabled = NETDATA_THREAD_EBPF_NOT_RUNNING,
186 .update_every = EBPF_DEFAULT_UPDATE_EVERY,
187 .global_charts = 1,
188 .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
189 .apps_level = NETDATA_APPS_LEVEL_REAL_PARENT,
190 .cgroup_charts = CONFIG_BOOLEAN_NO,
191 .mode = MODE_ENTRY,
192 .optional = 0,
193 .maps = dcstat_maps,
194 .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE,
195 .names = NULL,
196 .cfg = &dcstat_config,
197 .config_file = NETDATA_DIRECTORY_DCSTAT_CONFIG_FILE,
198 .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14,
199 .load = EBPF_LOAD_LEGACY,
200 .targets = dc_targets,
201 .probe_links = NULL,
202 .objects = NULL,
203 .thread = NULL,
204 .maps_per_core = CONFIG_BOOLEAN_YES,
205 .lifetime = EBPF_DEFAULT_LIFETIME,
206 .running_time = 0},
207 {.info = {.thread_name = "swap", .config_name = "swap", .thread_description = NETDATA_EBPF_SWAP_MODULE_DESC},
208 .functions =
209 {.start_routine = ebpf_swap_thread,
210 .apps_routine = ebpf_swap_create_apps_charts,
211 .fnct_routine = NULL,
212 .bpf_unload = ebpf_swap_unload_bpf},
213 .enabled = NETDATA_THREAD_EBPF_NOT_RUNNING,
214 .update_every = EBPF_DEFAULT_UPDATE_EVERY,
215 .global_charts = 1,
216 .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
217 .apps_level = NETDATA_APPS_LEVEL_REAL_PARENT,
218 .cgroup_charts = CONFIG_BOOLEAN_NO,
219 .mode = MODE_ENTRY,
220 .optional = 0,
221 .maps = NULL,
222 .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE,
223 .names = NULL,
224 .cfg = &swap_config,
225 .config_file = NETDATA_DIRECTORY_SWAP_CONFIG_FILE,
226 .kernels =
227 NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14 | NETDATA_V6_8,
228 .load = EBPF_LOAD_LEGACY,
229 .targets = swap_targets,
230 .probe_links = NULL,
231 .objects = NULL,
232 .thread = NULL,
233 .maps_per_core = CONFIG_BOOLEAN_YES,
234 .lifetime = EBPF_DEFAULT_LIFETIME,
235 .running_time = 0},
236 {.info = {.thread_name = "vfs", .config_name = "vfs", .thread_description = NETDATA_EBPF_VFS_MODULE_DESC},
237 .functions =
238 {.start_routine = ebpf_vfs_thread,
239 .apps_routine = ebpf_vfs_create_apps_charts,
240 .fnct_routine = NULL,
241 .bpf_unload = ebpf_vfs_unload_bpf},
242 .enabled = NETDATA_THREAD_EBPF_NOT_RUNNING,
243 .update_every = EBPF_DEFAULT_UPDATE_EVERY,
244 .global_charts = 1,
245 .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
246 .apps_level = NETDATA_APPS_LEVEL_REAL_PARENT,
247 .cgroup_charts = CONFIG_BOOLEAN_NO,
248 .mode = MODE_ENTRY,
249 .optional = 0,
250 .maps = NULL,
251 .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE,
252 .names = NULL,
253 .cfg = &vfs_config,
254 .config_file = NETDATA_DIRECTORY_VFS_CONFIG_FILE,
255 .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14,
256 .load = EBPF_LOAD_LEGACY,
257 .targets = vfs_targets,
258 .probe_links = NULL,
259 .objects = NULL,
260 .thread = NULL,
261 .maps_per_core = CONFIG_BOOLEAN_YES,
262 .lifetime = EBPF_DEFAULT_LIFETIME,
263 .running_time = 0},
264 {.info =
265 {.thread_name = "filesystem", .config_name = "filesystem", .thread_description = NETDATA_EBPF_FS_MODULE_DESC},
266 .functions =
267 {.start_routine = ebpf_filesystem_thread,
268 .apps_routine = NULL,
269 .fnct_routine = NULL,
270 .bpf_unload = ebpf_filesystem_unload_bpf},
271 .enabled = NETDATA_THREAD_EBPF_NOT_RUNNING,
272 .update_every = EBPF_DEFAULT_UPDATE_EVERY,
273 .global_charts = 1,
274 .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
275 .apps_level = NETDATA_APPS_NOT_SET,
276 .cgroup_charts = CONFIG_BOOLEAN_NO,
277 .mode = MODE_ENTRY,
278 .optional = 0,
279 .maps = NULL,
280 .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE,
281 .names = NULL,
282 .cfg = &fs_config,
283 .config_file = NETDATA_FILESYSTEM_CONFIG_FILE,
284 //We are setting kernels as zero, because we load eBPF programs according the kernel running.
285 .kernels = 0,
286 .load = EBPF_LOAD_LEGACY,
287 .targets = NULL,
288 .probe_links = NULL,
289 .objects = NULL,
290 .thread = NULL,
291 .maps_per_core = CONFIG_BOOLEAN_YES,
292 .lifetime = EBPF_DEFAULT_LIFETIME,
293 .running_time = 0},
294 {.info = {.thread_name = "disk", .config_name = "disk", .thread_description = NETDATA_EBPF_DISK_MODULE_DESC},
295 .functions =
296 {.start_routine = ebpf_disk_thread,
297 .apps_routine = NULL,
298 .fnct_routine = NULL,
299 .bpf_unload = ebpf_unload_legacy_bpf},
300 .enabled = NETDATA_THREAD_EBPF_NOT_RUNNING,
301 .update_every = EBPF_DEFAULT_UPDATE_EVERY,
302 .global_charts = 1,
303 .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
304 .apps_level = NETDATA_APPS_NOT_SET,
305 .cgroup_charts = CONFIG_BOOLEAN_NO,
306 .mode = MODE_ENTRY,
307 .optional = 0,
308 .maps = NULL,
309 .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE,
310 .names = NULL,
311 .cfg = &disk_config,
312 .config_file = NETDATA_DISK_CONFIG_FILE,
313 .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14,
314 .load = EBPF_LOAD_LEGACY,
315 .targets = NULL,
316 .probe_links = NULL,
317 .objects = NULL,
318 .thread = NULL,
319 .maps_per_core = CONFIG_BOOLEAN_YES,
320 .lifetime = EBPF_DEFAULT_LIFETIME,
321 .running_time = 0},
322 {.info = {.thread_name = "mount", .config_name = "mount", .thread_description = NETDATA_EBPF_MOUNT_MODULE_DESC},
323 .functions =
324 {.start_routine = ebpf_mount_thread,
325 .apps_routine = NULL,
326 .fnct_routine = NULL,
327 .bpf_unload = ebpf_mount_unload_bpf},
328 .enabled = NETDATA_THREAD_EBPF_NOT_RUNNING,
329 .update_every = EBPF_DEFAULT_UPDATE_EVERY,
330 .global_charts = 1,
331 .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
332 .apps_level = NETDATA_APPS_NOT_SET,
333 .cgroup_charts = CONFIG_BOOLEAN_NO,
334 .mode = MODE_ENTRY,
335 .optional = 0,
336 .maps = NULL,
337 .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE,
338 .names = NULL,
339 .cfg = &mount_config,
340 .config_file = NETDATA_MOUNT_CONFIG_FILE,
341 .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14,
342 .load = EBPF_LOAD_LEGACY,
343 .targets = mount_targets,
344 .probe_links = NULL,
345 .objects = NULL,
346 .thread = NULL,
347 .maps_per_core = CONFIG_BOOLEAN_YES,
348 .lifetime = EBPF_DEFAULT_LIFETIME,
349 .running_time = 0},
350 {.info = {.thread_name = "fd", .config_name = "fd", .thread_description = NETDATA_EBPF_FD_MODULE_DESC},
351 .functions =
352 {.start_routine = ebpf_fd_thread,
353 .apps_routine = ebpf_fd_create_apps_charts,
354 .fnct_routine = NULL,
355 .bpf_unload = ebpf_fd_unload_bpf},
356 .enabled = NETDATA_THREAD_EBPF_NOT_RUNNING,
357 .update_every = EBPF_DEFAULT_UPDATE_EVERY,
358 .global_charts = 1,
359 .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
360 .apps_level = NETDATA_APPS_LEVEL_REAL_PARENT,
361 .cgroup_charts = CONFIG_BOOLEAN_NO,
362 .mode = MODE_ENTRY,
363 .optional = 0,
364 .maps = NULL,
365 .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE,
366 .names = NULL,
367 .cfg = &fd_config,
368 .config_file = NETDATA_FD_CONFIG_FILE,
369 .kernels =
370 NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_11 | NETDATA_V5_14,
371 .load = EBPF_LOAD_LEGACY,
372 .targets = fd_targets,
373 .probe_links = NULL,
374 .objects = NULL,
375 .thread = NULL,
376 .maps_per_core = CONFIG_BOOLEAN_YES,
377 .lifetime = EBPF_DEFAULT_LIFETIME,
378 .running_time = 0},
379 {.info =
380 {.thread_name = "hardirq", .config_name = "hardirq", .thread_description = NETDATA_EBPF_HARDIRQ_MODULE_DESC},
381 .functions = {.start_routine = ebpf_hardirq_thread, .apps_routine = NULL, .fnct_routine = NULL},
382 .enabled = NETDATA_THREAD_EBPF_NOT_RUNNING,
383 .update_every = EBPF_DEFAULT_UPDATE_EVERY,
384 .global_charts = 1,
385 .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
386 .apps_level = NETDATA_APPS_NOT_SET,
387 .cgroup_charts = CONFIG_BOOLEAN_NO,
388 .mode = MODE_ENTRY,
389 .optional = 0,
390 .maps = NULL,
391 .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE,
392 .names = NULL,
393 .cfg = &hardirq_config,
394 .config_file = NETDATA_HARDIRQ_CONFIG_FILE,
395 .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14,
396 .load = EBPF_LOAD_LEGACY,
397 .targets = NULL,
398 .probe_links = NULL,
399 .objects = NULL,
400 .thread = NULL,
401 .maps_per_core = CONFIG_BOOLEAN_YES,
402 .lifetime = EBPF_DEFAULT_LIFETIME,
403 .running_time = 0},
404 {.info =
405 {.thread_name = "softirq", .config_name = "softirq", .thread_description = NETDATA_EBPF_SOFTIRQ_MODULE_DESC},
406 .functions =
407 {.start_routine = ebpf_softirq_thread,
408 .apps_routine = NULL,
409 .fnct_routine = NULL,
410 .bpf_unload = ebpf_unload_legacy_bpf},
411 .enabled = NETDATA_THREAD_EBPF_NOT_RUNNING,
412 .update_every = EBPF_DEFAULT_UPDATE_EVERY,
413 .global_charts = 1,
414 .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
415 .apps_level = NETDATA_APPS_NOT_SET,
416 .cgroup_charts = CONFIG_BOOLEAN_NO,
417 .mode = MODE_ENTRY,
418 .optional = 0,
419 .maps = NULL,
420 .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE,
421 .names = NULL,
422 .cfg = &softirq_config,
423 .config_file = NETDATA_SOFTIRQ_CONFIG_FILE,
424 .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14,
425 .load = EBPF_LOAD_LEGACY,
426 .targets = NULL,
427 .probe_links = NULL,
428 .objects = NULL,
429 .thread = NULL,
430 .maps_per_core = CONFIG_BOOLEAN_YES,
431 .lifetime = EBPF_DEFAULT_LIFETIME,
432 .running_time = 0},
433 {.info =
434 {.thread_name = "oomkill", .config_name = "oomkill", .thread_description = NETDATA_EBPF_OOMKILL_MODULE_DESC},
435 .functions =
436 {.start_routine = ebpf_oomkill_thread,
437 .apps_routine = ebpf_oomkill_create_apps_charts,
438 .fnct_routine = NULL,
439 .bpf_unload = ebpf_unload_legacy_bpf},
440 .enabled = NETDATA_THREAD_EBPF_NOT_RUNNING,
441 .update_every = EBPF_DEFAULT_UPDATE_EVERY,
442 .global_charts = 1,
443 .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
444 .apps_level = NETDATA_APPS_LEVEL_REAL_PARENT,
445 .cgroup_charts = CONFIG_BOOLEAN_NO,
446 .mode = MODE_ENTRY,
447 .optional = 0,
448 .maps = NULL,
449 .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE,
450 .names = NULL,
451 .cfg = &oomkill_config,
452 .config_file = NETDATA_OOMKILL_CONFIG_FILE,
453 .kernels = NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14,
454 .load = EBPF_LOAD_LEGACY,
455 .targets = NULL,
456 .probe_links = NULL,
457 .objects = NULL,
458 .thread = NULL,
459 .maps_per_core = CONFIG_BOOLEAN_YES,
460 .lifetime = EBPF_DEFAULT_LIFETIME,
461 .running_time = 0},
462 {.info = {.thread_name = "shm", .config_name = "shm", .thread_description = NETDATA_EBPF_SHM_MODULE_DESC},
463 .functions =
464 {.start_routine = ebpf_shm_thread,
465 .apps_routine = ebpf_shm_create_apps_charts,
466 .fnct_routine = NULL,
467 .bpf_unload = ebpf_shm_unload_bpf},
468 .enabled = NETDATA_THREAD_EBPF_NOT_RUNNING,
469 .update_every = EBPF_DEFAULT_UPDATE_EVERY,
470 .global_charts = 1,
471 .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
472 .apps_level = NETDATA_APPS_LEVEL_REAL_PARENT,
473 .cgroup_charts = CONFIG_BOOLEAN_NO,
474 .mode = MODE_ENTRY,
475 .optional = 0,
476 .maps = NULL,
477 .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE,
478 .names = NULL,
479 .cfg = &shm_config,
480 .config_file = NETDATA_DIRECTORY_SHM_CONFIG_FILE,
481 .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14,
482 .load = EBPF_LOAD_LEGACY,
483 .targets = shm_targets,
484 .probe_links = NULL,
485 .objects = NULL,
486 .thread = NULL,
487 .maps_per_core = CONFIG_BOOLEAN_YES,
488 .lifetime = EBPF_DEFAULT_LIFETIME,
489 .running_time = 0},
490 {.info = {.thread_name = "mdflush", .config_name = "mdflush", .thread_description = NETDATA_EBPF_MD_MODULE_DESC},
491 .functions =
492 {.start_routine = ebpf_mdflush_thread,
493 .apps_routine = NULL,
494 .fnct_routine = NULL,
495 .bpf_unload = ebpf_unload_legacy_bpf},
496 .enabled = NETDATA_THREAD_EBPF_NOT_RUNNING,
497 .update_every = EBPF_DEFAULT_UPDATE_EVERY,
498 .global_charts = 1,
499 .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
500 .apps_level = NETDATA_APPS_NOT_SET,
501 .cgroup_charts = CONFIG_BOOLEAN_NO,
502 .mode = MODE_ENTRY,
503 .optional = 0,
504 .maps = NULL,
505 .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE,
506 .names = NULL,
507 .cfg = &mdflush_config,
508 .config_file = NETDATA_DIRECTORY_MDFLUSH_CONFIG_FILE,
509 .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14,
510 .load = EBPF_LOAD_LEGACY,
511 .targets = mdflush_targets,
512 .probe_links = NULL,
513 .objects = NULL,
514 .thread = NULL,
515 .maps_per_core = CONFIG_BOOLEAN_YES,
516 .lifetime = EBPF_DEFAULT_LIFETIME,
517 .running_time = 0},
518 {.info =
519 {.thread_name = "functions",
520 .config_name = "functions",
521 .thread_description = NETDATA_EBPF_FUNCTIONS_MODULE_DESC},
522 .functions = {.start_routine = ebpf_function_thread, .apps_routine = NULL, .fnct_routine = NULL},
523 .enabled = NETDATA_THREAD_EBPF_RUNNING,
524 .update_every = EBPF_DEFAULT_UPDATE_EVERY,
525 .global_charts = 1,
526 .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
527 .apps_level = NETDATA_APPS_NOT_SET,
528 .cgroup_charts = CONFIG_BOOLEAN_NO,
529 .mode = MODE_ENTRY,
530 .optional = 0,
531 .maps = NULL,
532 .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE,
533 .names = NULL,
534 .cfg = NULL,
535 .config_file = NETDATA_DIRECTORY_FUNCTIONS_CONFIG_FILE,
536 .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14,
537 .load = EBPF_LOAD_LEGACY,
538 .targets = NULL,
539 .probe_links = NULL,
540 .objects = NULL,
541 .thread = NULL,
542 .maps_per_core = CONFIG_BOOLEAN_YES,
543 .lifetime = EBPF_DEFAULT_LIFETIME,
544 .running_time = 0},
545 {.info = {.thread_name = NULL, .config_name = NULL},
546 .functions = {.start_routine = NULL, .apps_routine = NULL, .fnct_routine = NULL},
547 .enabled = NETDATA_THREAD_EBPF_NOT_RUNNING,
548 .update_every = EBPF_DEFAULT_UPDATE_EVERY,
549 .global_charts = 0,
550 .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
551 .apps_level = NETDATA_APPS_NOT_SET,
552 .cgroup_charts = CONFIG_BOOLEAN_NO,
553 .mode = MODE_ENTRY,
554 .optional = 0,
555 .maps = NULL,
556 .pid_map_size = 0,
557 .names = NULL,
558 .cfg = NULL,
559 .kernels = 0,
560 .load = EBPF_LOAD_LEGACY,
561 .targets = NULL,
562 .probe_links = NULL,
563 .objects = NULL,
564 .thread = NULL,
565 .maps_per_core = CONFIG_BOOLEAN_YES},
566 };
567
568 struct netdata_static_thread ebpf_threads[] = {
569 {.name = "EBPF PROCESS",
570 .config_section = NULL,
571 .config_name = NULL,
572 .env_name = NULL,
573 .enabled = 1,
574 .thread = NULL,
575 .init_routine = NULL,
576 .start_routine = NULL},
577 {.name = "EBPF SOCKET",
578 .config_section = NULL,
579 .config_name = NULL,
580 .env_name = NULL,
581 .enabled = 1,
582 .thread = NULL,
583 .init_routine = NULL,
584 .start_routine = NULL},
585 {.name = "EBPF CACHESTAT",
586 .config_section = NULL,
587 .config_name = NULL,
588 .env_name = NULL,
589 .enabled = 1,
590 .thread = NULL,
591 .init_routine = NULL,
592 .start_routine = NULL},
593 {.name = "EBPF SYNC",
594 .config_section = NULL,
595 .config_name = NULL,
596 .env_name = NULL,
597 .enabled = 1,
598 .thread = NULL,
599 .init_routine = NULL,
600 .start_routine = NULL},
601 {.name = "EBPF DCSTAT",
602 .config_section = NULL,
603 .config_name = NULL,
604 .env_name = NULL,
605 .enabled = 1,
606 .thread = NULL,
607 .init_routine = NULL,
608 .start_routine = NULL},
609 {.name = "EBPF SWAP",
610 .config_section = NULL,
611 .config_name = NULL,
612 .env_name = NULL,
613 .enabled = 1,
614 .thread = NULL,
615 .init_routine = NULL,
616 .start_routine = NULL},
617 {.name = "EBPF VFS",
618 .config_section = NULL,
619 .config_name = NULL,
620 .env_name = NULL,
621 .enabled = 1,
622 .thread = NULL,
623 .init_routine = NULL,
624 .start_routine = NULL},
625 {.name = "EBPF FILESYSTEM",
626 .config_section = NULL,
627 .config_name = NULL,
628 .env_name = NULL,
629 .enabled = 1,
630 .thread = NULL,
631 .init_routine = NULL,
632 .start_routine = NULL},
633 {.name = "EBPF DISK",
634 .config_section = NULL,
635 .config_name = NULL,
636 .env_name = NULL,
637 .enabled = 1,
638 .thread = NULL,
639 .init_routine = NULL,
640 .start_routine = NULL},
641 {.name = "EBPF MOUNT",
642 .config_section = NULL,
643 .config_name = NULL,
644 .env_name = NULL,
645 .enabled = 1,
646 .thread = NULL,
647 .init_routine = NULL,
648 .start_routine = NULL},
649 {.name = "EBPF FD",
650 .config_section = NULL,
651 .config_name = NULL,
652 .env_name = NULL,
653 .enabled = 1,
654 .thread = NULL,
655 .init_routine = NULL,
656 .start_routine = NULL},
657 {.name = "EBPF HARDIRQ",
658 .config_section = NULL,
659 .config_name = NULL,
660 .env_name = NULL,
661 .enabled = 1,
662 .thread = NULL,
663 .init_routine = NULL,
664 .start_routine = NULL},
665 {.name = "EBPF SOFTIRQ",
666 .config_section = NULL,
667 .config_name = NULL,
668 .env_name = NULL,
669 .enabled = 1,
670 .thread = NULL,
671 .init_routine = NULL,
672 .start_routine = NULL},
673 {.name = "EBPF OOMKILL",
674 .config_section = NULL,
675 .config_name = NULL,
676 .env_name = NULL,
677 .enabled = 1,
678 .thread = NULL,
679 .init_routine = NULL,
680 .start_routine = NULL},
681 {.name = "EBPF SHM",
682 .config_section = NULL,
683 .config_name = NULL,
684 .env_name = NULL,
685 .enabled = 1,
686 .thread = NULL,
687 .init_routine = NULL,
688 .start_routine = NULL},
689 {.name = "EBPF MDFLUSH",
690 .config_section = NULL,
691 .config_name = NULL,
692 .env_name = NULL,
693 .enabled = 1,
694 .thread = NULL,
695 .init_routine = NULL,
696 .start_routine = NULL},
697 {.name = "EBPF FUNCTIONS",
698 .config_section = NULL,
699 .config_name = NULL,
700 .env_name = NULL,
701 #ifdef NETDATA_DEV_MODE
702 .enabled = 1,
703 #else
704 .enabled = 0,
705 #endif
706 .thread = NULL,
707 .init_routine = NULL,
708 .start_routine = NULL},
709 {.name = NULL,
710 .config_section = NULL,
711 .config_name = NULL,
712 .env_name = NULL,
713 .enabled = 0,
714 .thread = NULL,
715 .init_routine = NULL,
716 .start_routine = NULL},
717 };
718
719 ebpf_filesystem_partitions_t localfs[] = {
720 {.filesystem = "ext4",
721 .optional_filesystem = NULL,
722 .family = "ext4",
723 .objects = NULL,
724 .probe_links = NULL,
725 .flags = NETDATA_FILESYSTEM_FLAG_NO_PARTITION,
726 .enabled = CONFIG_BOOLEAN_YES,
727 .addresses = {.function = NULL, .addr = 0},
728 .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4,
729 .fs_maps = NULL,
730 .fs_obj = NULL,
731 .functions = {"ext4_file_read_iter", "ext4_file_write_iter", "ext4_file_open", "ext4_sync_file", NULL}},
732 {.filesystem = "xfs",
733 .optional_filesystem = NULL,
734 .family = "xfs",
735 .objects = NULL,
736 .probe_links = NULL,
737 .flags = NETDATA_FILESYSTEM_FLAG_NO_PARTITION,
738 .enabled = CONFIG_BOOLEAN_YES,
739 .addresses = {.function = NULL, .addr = 0},
740 .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4,
741 .fs_maps = NULL,
742 .fs_obj = NULL,
743 .functions = {"xfs_file_read_iter", "xfs_file_write_iter", "xfs_file_open", "xfs_file_fsync", NULL}},
744 {.filesystem = "nfs",
745 .optional_filesystem = "nfs4",
746 .family = "nfs",
747 .objects = NULL,
748 .probe_links = NULL,
749 .flags = NETDATA_FILESYSTEM_ATTR_CHARTS,
750 .enabled = CONFIG_BOOLEAN_YES,
751 .addresses = {.function = NULL, .addr = 0},
752 .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4,
753 .fs_maps = NULL,
754 .fs_obj = NULL,
755 .functions =
756 {"nfs_file_read",
757 "nfs_file_write",
758 "nfs_open",
759 "nfs_getattr",
760 NULL}}, // "nfs4_file_open" - not present on all kernels
761 {.filesystem = "zfs",
762 .optional_filesystem = NULL,
763 .family = "zfs",
764 .objects = NULL,
765 .probe_links = NULL,
766 .flags = NETDATA_FILESYSTEM_FLAG_NO_PARTITION,
767 .enabled = CONFIG_BOOLEAN_YES,
768 .addresses = {.function = NULL, .addr = 0},
769 .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4,
770 .fs_maps = NULL,
771 .fs_obj = NULL,
772 .functions = {"zpl_iter_read", "zpl_iter_write", "zpl_open", "zpl_fsync", NULL}},
773 {.filesystem = "btrfs",
774 .optional_filesystem = NULL,
775 .family = "btrfs",
776 .objects = NULL,
777 .probe_links = NULL,
778 .flags = NETDATA_FILESYSTEM_FILL_ADDRESS_TABLE,
779 .enabled = CONFIG_BOOLEAN_YES,
780 .addresses = {.function = "btrfs_file_operations", .addr = 0},
781 .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_10,
782 .fs_maps = NULL,
783 .fs_obj = NULL,
784 .functions = {"btrfs_file_read_iter", "btrfs_file_write_iter", "btrfs_file_open", "btrfs_sync_file", NULL}},
785 {.filesystem = NULL,
786 .optional_filesystem = NULL,
787 .family = NULL,
788 .objects = NULL,
789 .probe_links = NULL,
790 .flags = NETDATA_FILESYSTEM_FLAG_NO_PARTITION,
791 .enabled = CONFIG_BOOLEAN_YES,
792 .addresses = {.function = NULL, .addr = 0},
793 .kernels = 0,
794 .fs_maps = NULL,
795 .fs_obj = NULL}};
796
797 ebpf_sync_syscalls_t local_syscalls[] = {
798 {.syscall = NETDATA_SYSCALLS_SYNC,
799 .enabled = CONFIG_BOOLEAN_YES,
800 .objects = NULL,
801 .probe_links = NULL,
802 #ifdef LIBBPF_MAJOR_VERSION
803 .sync_obj = NULL,
804 #endif
805 .sync_maps = NULL},
806 {.syscall = NETDATA_SYSCALLS_SYNCFS,
807 .enabled = CONFIG_BOOLEAN_YES,
808 .objects = NULL,
809 .probe_links = NULL,
810 #ifdef LIBBPF_MAJOR_VERSION
811 .sync_obj = NULL,
812 #endif
813 .sync_maps = NULL},
814 {.syscall = NETDATA_SYSCALLS_MSYNC,
815 .enabled = CONFIG_BOOLEAN_YES,
816 .objects = NULL,
817 .probe_links = NULL,
818 #ifdef LIBBPF_MAJOR_VERSION
819 .sync_obj = NULL,
820 #endif
821 .sync_maps = NULL},
822 {.syscall = NETDATA_SYSCALLS_FSYNC,
823 .enabled = CONFIG_BOOLEAN_YES,
824 .objects = NULL,
825 .probe_links = NULL,
826 #ifdef LIBBPF_MAJOR_VERSION
827 .sync_obj = NULL,
828 #endif
829 .sync_maps = NULL},
830 {.syscall = NETDATA_SYSCALLS_FDATASYNC,
831 .enabled = CONFIG_BOOLEAN_YES,
832 .objects = NULL,
833 .probe_links = NULL,
834 #ifdef LIBBPF_MAJOR_VERSION
835 .sync_obj = NULL,
836 #endif
837 .sync_maps = NULL},
838 {.syscall = NETDATA_SYSCALLS_SYNC_FILE_RANGE,
839 .enabled = CONFIG_BOOLEAN_YES,
840 .objects = NULL,
841 .probe_links = NULL,
842 #ifdef LIBBPF_MAJOR_VERSION
843 .sync_obj = NULL,
844 #endif
845 .sync_maps = NULL},
846 {.syscall = NULL,
847 .enabled = CONFIG_BOOLEAN_NO,
848 .objects = NULL,
849 .probe_links = NULL,
850 #ifdef LIBBPF_MAJOR_VERSION
851 .sync_obj = NULL,
852 #endif
853 .sync_maps = NULL}};
854
855 // cgroup integration via netipc
856 _Atomic int ebpf_cgroup_systemd_enabled = 0;
857 _Atomic int ebpf_cgroup_integration_active = 0;
858 netdata_mutex_t mutex_cgroup_shm;
859
860 //Network viewer
861 ebpf_network_viewer_options_t network_viewer_opt;
862
863 // Statistic
864 ebpf_plugin_stats_t plugin_statistics = {
865 .core = 0,
866 .legacy = 0,
867 .running = 0,
868 .threads = 0,
869 .tracepoints = 0,
870 .probes = 0,
871 .retprobes = 0,
872 .trampolines = 0,
873 .memlock_kern = 0,
874 .hash_tables = 0};
875 netdata_ebpf_judy_pid_t ebpf_judy_pid = {.pid_table = NULL, .index = {.JudyLArray = NULL}};
876 bool ebpf_plugin_exit = false;
877 volatile sig_atomic_t ebpf_stop_signal = 0;
878 static bool ebpf_pre_exit_check_done = false;
879
880 #ifdef LIBBPF_MAJOR_VERSION
881 struct btf *default_btf = NULL;
882 struct cachestat_bpf *cachestat_bpf_obj = NULL;
883 struct dc_bpf *dc_bpf_obj = NULL;
884 struct disk_bpf *disk_bpf_obj = NULL;
885 struct fd_bpf *fd_bpf_obj = NULL;
886 struct hardirq_bpf *hardirq_bpf_obj = NULL;
887 struct mdflush_bpf *mdflush_bpf_obj = NULL;
888 struct mount_bpf *mount_bpf_obj = NULL;
889 struct shm_bpf *shm_bpf_obj = NULL;
890 struct socket_bpf *socket_bpf_obj = NULL;
891 struct swap_bpf *swap_bpf_obj = NULL;
892 struct vfs_bpf *vfs_bpf_obj = NULL;
893 struct process_bpf *process_bpf_obj = NULL;
894 #else
895 void *default_btf = NULL;
896 #endif
897 const char *btf_path = NULL;
898
899 /*****************************************************************
900 *
901 * FUNCTIONS USED TO MANIPULATE JUDY ARRAY
902 *
903 *****************************************************************/
904
905 /**
906 * Hashtable insert unsafe
907 *
908 * Find or create a value associated to the index
909 *
910 * @return The lsocket = 0 when new item added to the array otherwise the existing item value is returned in *lsocket
911 * we return a pointer to a pointer, so that the caller can put anything needed at the value of the index.
912 * The pointer to pointer we return has to be used before any other operation that may change the index (insert/delete).
913 *
914 */
915 void **ebpf_judy_insert_unsafe(PPvoid_t arr, Word_t key)
916 {
917 JError_t J_Error;
918 Pvoid_t *idx = JudyLIns(arr, key, &J_Error);
919 if (unlikely(idx == PJERR)) {
920 netdata_log_error(
921 "Cannot add PID to JudyL, JU_ERRNO_* == %u, ID == %d", JU_ERRNO(&J_Error), JU_ERRID(&J_Error));
922 }
923
924 return idx;
925 }
926
927 /**
928 * Get PID from judy
929 *
930 * Get a pointer for the `pid` from judy_array;
931 *
932 * @param judy_array a judy array where PID is the primary key
933 * @param pid pid stored.
934 */
935 netdata_ebpf_judy_pid_stats_t *ebpf_get_pid_from_judy_unsafe(PPvoid_t judy_array, uint32_t pid)
936 {
937 netdata_ebpf_judy_pid_stats_t **pid_pptr =
938 (netdata_ebpf_judy_pid_stats_t **)ebpf_judy_insert_unsafe(judy_array, pid);
939 netdata_ebpf_judy_pid_stats_t *pid_ptr = *pid_pptr;
940 if (likely(*pid_pptr == NULL)) {
941 *pid_pptr = aral_mallocz(ebpf_judy_pid.pid_table);
942 if (unlikely(*pid_pptr == NULL)) {
943 netdata_log_error("Cannot allocate memory for PID %u", pid);
944 return NULL;
945 }
946
947 pid_ptr = *pid_pptr;
948
949 pid_ptr->cmdline = NULL;
950 pid_ptr->socket_stats.JudyLArray = NULL;
951 rw_spinlock_init(&pid_ptr->socket_stats.rw_spinlock);
952 }
953
954 return pid_ptr;
955 }
956
957 /*****************************************************************
958 *
959 * FUNCTIONS USED TO ALLOCATE APPS/CGROUP MEMORIES (ARAL)
960 *
961 *****************************************************************/
962
963 /**
964 * Allocate PID ARAL
965 *
966 * Allocate memory using ARAL functions to speed up processing.
967 *
968 * @param name the internal name used for allocated region.
969 * @param size size of each element inside allocated space
970 *
971 * @return It returns the address on success and NULL otherwise.
972 */
973 ARAL *ebpf_allocate_pid_aral(char *name, size_t size)
974 {
975 static size_t max_elements = NETDATA_EBPF_ALLOC_MAX_PID;
976 if (max_elements < NETDATA_EBPF_ALLOC_MIN_ELEMENTS) {
977 netdata_log_error(
978 "Number of elements given is too small, adjusting it for %d", NETDATA_EBPF_ALLOC_MIN_ELEMENTS);
979 max_elements = NETDATA_EBPF_ALLOC_MIN_ELEMENTS;
980 }
981
982 return aral_create(name, size, 0, 0, NULL, NULL, NULL, false, false, false);
983 }
984
985 /*****************************************************************
986 *
987 * FUNCTIONS USED TO CLEAN MEMORY AND OPERATE SYSTEM FILES
988 *
989 *****************************************************************/
990
991 /**
992 * Wait to avoid possible coredumps while process is closing.
993 */
994 static inline void ebpf_check_before2go()
995 {
996 usec_t max = 200 * USEC_PER_MS, step = 50 * USEC_PER_MS;
997 int j;
998 while (max) {
999 max -= step;
1000 sleep_usec(step);
1001 int active_count = 0;
1002 netdata_mutex_lock(&ebpf_exit_cleanup);
1003 for (j = 0; ebpf_modules[j].info.thread_name != NULL; j++) {
1004 if (ebpf_module_enabled_get(&ebpf_modules[j]) < NETDATA_THREAD_EBPF_STOPPING)
1005 active_count++;
1006 }
1007 netdata_mutex_unlock(&ebpf_exit_cleanup);
1008 if (!active_count)
1009 return;
1010 }
1011
1012 netdata_log_error("eBPF cannot unload all threads on time, but it will go away");
1013 }
1014
1015 /**
1016 * Close the collector gracefully
1017 */
1018 static void ebpf_cleanup(void)
1019 {
1020 #ifdef LIBBPF_MAJOR_VERSION
1021 netdata_mutex_lock(&ebpf_exit_cleanup);
1022 if (default_btf) {
1023 btf__free(default_btf);
1024 default_btf = NULL;
1025 }
1026 netdata_mutex_unlock(&ebpf_exit_cleanup);
1027 #endif
1028
1029 char filename[FILENAME_MAX + 1];
1030 ebpf_pid_file(filename, FILENAME_MAX);
1031 if (unlink(filename) == -1 && errno != ENOENT)
1032 netdata_log_error("Cannot remove PID file %s: %s", filename, strerror(errno));
1033
1034 #ifdef NETDATA_INTERNAL_CHECKS
1035 netdata_log_error("Good bye world! I was PID %d", main_thread_id);
1036 #endif
1037 fprintf(stdout, "EXIT\n");
1038 fflush(stdout);
1039
1040 if (!ebpf_pre_exit_check_done) {
1041 ebpf_check_before2go();
1042 ebpf_pre_exit_check_done = true;
1043 }
1044 ebpf_cgroup_cache_cleanup();
1045 netdata_integration_cleanup_shm();
1046 }
1047
1048 static void ebpf_exit(int exit_code)
1049 {
1050 ebpf_cleanup();
1051 exit(exit_code);
1052 }
1053
1054 /**
1055 * Unload legacy code
1056 *
1057 * @param objects objects loaded from eBPF programs
1058 * @param probe_links links from loader
1059 */
1060 void ebpf_unload_legacy_code(struct bpf_object *objects, struct bpf_link **probe_links)
1061 {
1062 if (!probe_links || !objects)
1063 return;
1064
1065 if ((uintptr_t)objects < 4096 || (uintptr_t)objects == (uintptr_t)-1) {
1066 freez(probe_links);
1067 return;
1068 }
1069
1070 struct bpf_program *prog;
1071 size_t j = 0;
1072 bpf_object__for_each_program(prog, objects)
1073 {
1074 bpf_link__destroy(probe_links[j]);
1075 j++;
1076 }
1077 freez(probe_links);
1078
1079 bpf_object__close(objects);
1080 }
1081
1082 void ebpf_unload_legacy_bpf(ebpf_module_t *em)
1083 {
1084 if ((em->load & EBPF_LOAD_LEGACY) && em->probe_links) {
1085 ebpf_unload_legacy_code(em->objects, em->probe_links);
1086 em->objects = NULL;
1087 em->probe_links = NULL;
1088 }
1089 }
1090
1091 static void ebpf_socket_unload_bpf(ebpf_module_t *em)
1092 {
1093 ebpf_unload_legacy_bpf(em);
1094
1095 #ifdef LIBBPF_MAJOR_VERSION
1096 if (socket_bpf_obj) {
1097 socket_bpf__destroy(socket_bpf_obj);
1098 socket_bpf_obj = NULL;
1099 }
1100 #endif
1101 }
1102
1103 /**
1104 * Read Local Ports
1105 *
1106 * Parse /proc/net/{tcp,udp} and get the ports Linux is listening.
1107 *
1108 * @param filename the proc file to parse.
1109 * @param proto is the magic number associated to the protocol file we are reading.
1110 */
1111 void ebpf_stop_threads(int sig)
1112 {
1113 static int only_one = 0;
1114 usec_t stop_started_ut = now_monotonic_usec();
1115 pid_t current_tid = gettid_cached();
1116
1117 // Child thread should be closed by itself.
1118 netdata_mutex_lock(&ebpf_exit_cleanup);
1119 if (main_thread_id != gettid_cached() || only_one) {
1120 netdata_mutex_unlock(&ebpf_exit_cleanup);
1121 return;
1122 }
1123 only_one = 1;
1124
1125 netdata_log_info(
1126 "EBPF SHUTDOWN: stop requested (signal=%d, main_tid=%d, current_tid=%d).", sig, main_thread_id, current_tid);
1127 __atomic_store_n(&ebpf_plugin_exit, true, __ATOMIC_RELEASE);
1128
1129 int i;
1130 for (i = 0; ebpf_modules[i].info.thread_name != NULL; i++) {
1131 enum ebpf_threads_status enabled = ebpf_module_enabled_get(&ebpf_modules[i]);
1132
1133 if (enabled < NETDATA_THREAD_EBPF_STOPPING && ebpf_modules[i].thread &&
1134 ebpf_modules[i].thread->thread) {
1135 nd_thread_signal_cancel(ebpf_modules[i].thread->thread);
1136 #ifdef NETDATA_DEV_MODE
1137 netdata_log_info("Sending cancel for thread %s", ebpf_modules[i].info.thread_name);
1138 #endif
1139 }
1140 }
1141 netdata_mutex_unlock(&ebpf_exit_cleanup);
1142
1143 for (i = 0; ebpf_modules[i].info.thread_name != NULL; i++) {
1144 enum ebpf_threads_status enabled = ebpf_module_enabled_get(&ebpf_modules[i]);
1145
1146 if (enabled < NETDATA_THREAD_EBPF_STOPPED && ebpf_threads[i].thread) {
1147 netdata_log_info(
1148 "EBPF SHUTDOWN: about to join module[%d]='%s' (state=%u).",
1149 i,
1150 ebpf_modules[i].info.thread_name,
1151 enabled);
1152 usec_t join_started_ut = now_monotonic_usec();
1153 nd_thread_join(ebpf_threads[i].thread);
1154 usec_t join_duration_ut = now_monotonic_usec() - join_started_ut;
1155 netdata_log_info(
1156 "EBPF SHUTDOWN: joined '%s' in %llums.",
1157 ebpf_modules[i].info.thread_name,
1158 (unsigned long long)(join_duration_ut / USEC_PER_MS));
1159 }
1160 }
1161
1162 netdata_mutex_lock(&mutex_cgroup_shm);
1163 nd_thread_signal_cancel(cgroup_integration_thread.thread);
1164 #ifdef NETDATA_DEV_MODE
1165 netdata_log_info("Sending cancel for thread %s", cgroup_integration_thread.name);
1166 #endif
1167 netdata_mutex_unlock(&mutex_cgroup_shm);
1168
1169 // Join the cgroup integration thread before cleanup tears down the netipc cache it reads.
1170 if (cgroup_integration_thread.thread) {
1171 nd_thread_join(cgroup_integration_thread.thread);
1172 cgroup_integration_thread.thread = NULL;
1173 }
1174
1175 usec_t before_checks_ut = now_monotonic_usec();
1176 if (!ebpf_pre_exit_check_done) {
1177 ebpf_check_before2go();
1178 ebpf_pre_exit_check_done = true;
1179 }
1180 usec_t checks_duration_ut = now_monotonic_usec() - before_checks_ut;
1181 netdata_log_info(
1182 "EBPF SHUTDOWN: post-cancel checks finished in %llums.",
1183 (unsigned long long)(checks_duration_ut / USEC_PER_MS));
1184
1185 // BPF unload is handled by each module's exit function (in parallel with thread shutdown).
1186 // During forced shutdown, the kernel cleans up BPF programs automatically on process exit.
1187 // Sequential unload here would add several seconds of delay with no benefit.
1188
1189 usec_t total_duration_ut = now_monotonic_usec() - stop_started_ut;
1190 netdata_log_info(
1191 "EBPF SHUTDOWN: total stop duration %llums.", (unsigned long long)(total_duration_ut / USEC_PER_MS));
1192
1193 ebpf_cleanup();
1194 }
1195
1196 /**
1197 * Start Pthread Variable
1198 *
1199 * This function starts all
1200 */
1201 static void ebpf_mutex_initialize()
1202 {
1203 netdata_mutex_init(&lock);
1204 netdata_mutex_init(&ebpf_exit_cleanup);
1205 netdata_mutex_init(&collect_data_mutex);
1206 netdata_mutex_init(&mutex_cgroup_shm);
1207 rw_spinlock_init(&ebpf_judy_pid.index.rw_spinlock);
1208 }
1209
1210 /**
1211 * Allocate the vectors used for all threads.
1212 */
1213 static void ebpf_allocate_common_vectors()
1214 {
1215 ebpf_judy_pid.pid_table =
1216 ebpf_allocate_pid_aral(NETDATA_EBPF_PID_SOCKET_ARAL_TABLE_NAME, sizeof(netdata_ebpf_judy_pid_stats_t));
1217 ebpf_aral_init();
1218 }
1219
1220 /**
1221 * Set global variables reading environment variables
1222 */
1223 static void ebpf_set_global_variables()
1224 {
1225 // Get environment variables
1226 ebpf_plugin_dir = getenv("NETDATA_PLUGINS_DIR");
1227 if (!ebpf_plugin_dir)
1228 ebpf_plugin_dir = PLUGINS_DIR;
1229
1230 ebpf_user_config_dir = getenv("NETDATA_USER_CONFIG_DIR");
1231 if (!ebpf_user_config_dir)
1232 ebpf_user_config_dir = CONFIG_DIR;
1233
1234 ebpf_stock_config_dir = getenv("NETDATA_STOCK_CONFIG_DIR");
1235 if (!ebpf_stock_config_dir)
1236 ebpf_stock_config_dir = LIBCONFIG_DIR;
1237
1238 ebpf_configured_log_dir = getenv("NETDATA_LOG_DIR");
1239 if (!ebpf_configured_log_dir)
1240 ebpf_configured_log_dir = LOG_DIR;
1241
1242 ebpf_nprocs = (int)sysconf(_SC_NPROCESSORS_ONLN);
1243 if (ebpf_nprocs < 0) {
1244 ebpf_nprocs = NETDATA_MAX_PROCESSOR;
1245 netdata_log_error("Cannot identify number of process, using default value %d", ebpf_nprocs);
1246 }
1247
1248 isrh = get_redhat_release();
1249 pid_max = os_get_system_pid_max();
1250 running_on_kernel = ebpf_get_kernel_version();
1251 ebpf_reset_pid_map_fds();
1252 }
1253
1254 /**
1255 * Parse arguments given from user.
1256 *
1257 * @param argc the number of arguments
1258 * @param argv the pointer to the arguments
1259 */
1260 static void ebpf_parse_args(int argc, char **argv)
1261 {
1262 int disable_cgroups = 1;
1263 int freq = 0;
1264 int option_index = 0;
1265 uint64_t select_threads = 0;
1266 static struct option long_options[] = {
1267 {"process", no_argument, 0, 0},
1268 {"net", no_argument, 0, 0},
1269 {"cachestat", no_argument, 0, 0},
1270 {"sync", no_argument, 0, 0},
1271 {"dcstat", no_argument, 0, 0},
1272 {"swap", no_argument, 0, 0},
1273 {"vfs", no_argument, 0, 0},
1274 {"filesystem", no_argument, 0, 0},
1275 {"disk", no_argument, 0, 0},
1276 {"mount", no_argument, 0, 0},
1277 {"filedescriptor", no_argument, 0, 0},
1278 {"hardirq", no_argument, 0, 0},
1279 {"softirq", no_argument, 0, 0},
1280 {"oomkill", no_argument, 0, 0},
1281 {"shm", no_argument, 0, 0},
1282 {"mdflush", no_argument, 0, 0},
1283 /* INSERT NEW THREADS BEFORE THIS COMMENT TO KEEP COMPATIBILITY WITH enum ebpf_module_indexes */
1284 {"all", no_argument, 0, 0},
1285 {"version", no_argument, 0, 0},
1286 {"help", no_argument, 0, 0},
1287 {"global", no_argument, 0, 0},
1288 {"return", no_argument, 0, 0},
1289 {"legacy", no_argument, 0, 0},
1290 {"core", no_argument, 0, 0},
1291 {"unittest", no_argument, 0, 0},
1292 {0, 0, 0, 0}};
1293
1294 memset(&network_viewer_opt, 0, sizeof(network_viewer_opt));
1295 rw_spinlock_init(&network_viewer_opt.rw_spinlock);
1296
1297 if (argc > 1) {
1298 int n = (int)str2l(argv[1]);
1299 if (n > 0) {
1300 freq = n;
1301 }
1302 }
1303
1304 if (!freq)
1305 freq = EBPF_DEFAULT_UPDATE_EVERY;
1306
1307 if (ebpf_load_collector_config(ebpf_user_config_dir, &disable_cgroups, freq)) {
1308 netdata_log_info(
1309 "Does not have a configuration file inside `%s/ebpf.d.conf. It will try to load stock file.",
1310 ebpf_user_config_dir);
1311 if (ebpf_load_collector_config(ebpf_stock_config_dir, &disable_cgroups, freq)) {
1312 netdata_log_info("Does not have a stock file. It is starting with default options.");
1313 }
1314 }
1315
1316 ebpf_load_thread_config();
1317
1318 while (1) {
1319 int c = getopt_long_only(argc, argv, "", long_options, &option_index);
1320 if (c == -1)
1321 break;
1322
1323 switch (option_index) {
1324 case EBPF_MODULE_PROCESS_IDX: {
1325 select_threads |= 1 << EBPF_MODULE_PROCESS_IDX;
1326 #ifdef NETDATA_INTERNAL_CHECKS
1327 netdata_log_info(
1328 "EBPF enabling \"PROCESS\" charts, because it was started with the option \"[-]-process\".");
1329 #endif
1330 break;
1331 }
1332 case EBPF_MODULE_SOCKET_IDX: {
1333 select_threads |= 1 << EBPF_MODULE_SOCKET_IDX;
1334 #ifdef NETDATA_INTERNAL_CHECKS
1335 netdata_log_info("EBPF enabling \"NET\" charts, because it was started with the option \"[-]-net\".");
1336 #endif
1337 break;
1338 }
1339 case EBPF_MODULE_CACHESTAT_IDX: {
1340 select_threads |= 1 << EBPF_MODULE_CACHESTAT_IDX;
1341 #ifdef NETDATA_INTERNAL_CHECKS
1342 netdata_log_info(
1343 "EBPF enabling \"CACHESTAT\" charts, because it was started with the option \"[-]-cachestat\".");
1344 #endif
1345 break;
1346 }
1347 case EBPF_MODULE_SYNC_IDX: {
1348 select_threads |= 1 << EBPF_MODULE_SYNC_IDX;
1349 #ifdef NETDATA_INTERNAL_CHECKS
1350 netdata_log_info("EBPF enabling \"SYNC\" chart, because it was started with the option \"[-]-sync\".");
1351 #endif
1352 break;
1353 }
1354 case EBPF_MODULE_DCSTAT_IDX: {
1355 select_threads |= 1 << EBPF_MODULE_DCSTAT_IDX;
1356 #ifdef NETDATA_INTERNAL_CHECKS
1357 netdata_log_info(
1358 "EBPF enabling \"DCSTAT\" charts, because it was started with the option \"[-]-dcstat\".");
1359 #endif
1360 break;
1361 }
1362 case EBPF_MODULE_SWAP_IDX: {
1363 select_threads |= 1 << EBPF_MODULE_SWAP_IDX;
1364 #ifdef NETDATA_INTERNAL_CHECKS
1365 netdata_log_info("EBPF enabling \"SWAP\" chart, because it was started with the option \"[-]-swap\".");
1366 #endif
1367 break;
1368 }
1369 case EBPF_MODULE_VFS_IDX: {
1370 select_threads |= 1 << EBPF_MODULE_VFS_IDX;
1371 #ifdef NETDATA_INTERNAL_CHECKS
1372 netdata_log_info("EBPF enabling \"VFS\" chart, because it was started with the option \"[-]-vfs\".");
1373 #endif
1374 break;
1375 }
1376 case EBPF_MODULE_FILESYSTEM_IDX: {
1377 select_threads |= 1 << EBPF_MODULE_FILESYSTEM_IDX;
1378 #ifdef NETDATA_INTERNAL_CHECKS
1379 netdata_log_info(
1380 "EBPF enabling \"FILESYSTEM\" chart, because it was started with the option \"[-]-filesystem\".");
1381 #endif
1382 break;
1383 }
1384 case EBPF_MODULE_DISK_IDX: {
1385 select_threads |= 1 << EBPF_MODULE_DISK_IDX;
1386 #ifdef NETDATA_INTERNAL_CHECKS
1387 netdata_log_info("EBPF enabling \"DISK\" chart, because it was started with the option \"[-]-disk\".");
1388 #endif
1389 break;
1390 }
1391 case EBPF_MODULE_MOUNT_IDX: {
1392 select_threads |= 1 << EBPF_MODULE_MOUNT_IDX;
1393 #ifdef NETDATA_INTERNAL_CHECKS
1394 netdata_log_info(
1395 "EBPF enabling \"MOUNT\" chart, because it was started with the option \"[-]-mount\".");
1396 #endif
1397 break;
1398 }
1399 case EBPF_MODULE_FD_IDX: {
1400 select_threads |= 1 << EBPF_MODULE_FD_IDX;
1401 #ifdef NETDATA_INTERNAL_CHECKS
1402 netdata_log_info(
1403 "EBPF enabling \"FILEDESCRIPTOR\" chart, because it was started with the option \"[-]-filedescriptor\".");
1404 #endif
1405 break;
1406 }
1407 case EBPF_MODULE_HARDIRQ_IDX: {
1408 select_threads |= 1 << EBPF_MODULE_HARDIRQ_IDX;
1409 #ifdef NETDATA_INTERNAL_CHECKS
1410 netdata_log_info(
1411 "EBPF enabling \"HARDIRQ\" chart, because it was started with the option \"[-]-hardirq\".");
1412 #endif
1413 break;
1414 }
1415 case EBPF_MODULE_SOFTIRQ_IDX: {
1416 select_threads |= 1 << EBPF_MODULE_SOFTIRQ_IDX;
1417 #ifdef NETDATA_INTERNAL_CHECKS
1418 netdata_log_info(
1419 "EBPF enabling \"SOFTIRQ\" chart, because it was started with the option \"[-]-softirq\".");
1420 #endif
1421 break;
1422 }
1423 case EBPF_MODULE_OOMKILL_IDX: {
1424 select_threads |= 1 << EBPF_MODULE_OOMKILL_IDX;
1425 #ifdef NETDATA_INTERNAL_CHECKS
1426 netdata_log_info(
1427 "EBPF enabling \"OOMKILL\" chart, because it was started with the option \"[-]-oomkill\".");
1428 #endif
1429 break;
1430 }
1431 case EBPF_MODULE_SHM_IDX: {
1432 select_threads |= 1 << EBPF_MODULE_SHM_IDX;
1433 #ifdef NETDATA_INTERNAL_CHECKS
1434 netdata_log_info("EBPF enabling \"SHM\" chart, because it was started with the option \"[-]-shm\".");
1435 #endif
1436 break;
1437 }
1438 case EBPF_MODULE_MDFLUSH_IDX: {
1439 select_threads |= 1 << EBPF_MODULE_MDFLUSH_IDX;
1440 #ifdef NETDATA_INTERNAL_CHECKS
1441 netdata_log_info(
1442 "EBPF enabling \"MDFLUSH\" chart, because it was started with the option \"[-]-mdflush\".");
1443 #endif
1444 break;
1445 }
1446 case EBPF_OPTION_ALL_CHARTS: {
1447 ebpf_set_apps_mode(NETDATA_EBPF_APPS_FLAG_YES);
1448 disable_cgroups = 0;
1449 #ifdef NETDATA_INTERNAL_CHECKS
1450 netdata_log_info(
1451 "EBPF running with all chart groups, because it was started with the option \"[-]-all\".");
1452 #endif
1453 break;
1454 }
1455 case EBPF_OPTION_VERSION: {
1456 printf("ebpf.plugin %s\n", NETDATA_VERSION);
1457 exit(0);
1458 }
1459 case EBPF_OPTION_HELP: {
1460 ebpf_print_help();
1461 exit(0);
1462 }
1463 case EBPF_OPTION_GLOBAL_CHART: {
1464 disable_cgroups = 1;
1465 #ifdef NETDATA_INTERNAL_CHECKS
1466 netdata_log_info(
1467 "EBPF running with global chart group, because it was started with the option \"[-]-global\".");
1468 #endif
1469 break;
1470 }
1471 case EBPF_OPTION_RETURN_MODE: {
1472 ebpf_set_thread_mode(MODE_RETURN);
1473 #ifdef NETDATA_INTERNAL_CHECKS
1474 netdata_log_info(
1475 "EBPF running in \"RETURN\" mode, because it was started with the option \"[-]-return\".");
1476 #endif
1477 break;
1478 }
1479 case EBPF_OPTION_LEGACY: {
1480 ebpf_set_load_mode(EBPF_LOAD_LEGACY, EBPF_LOADED_FROM_USER);
1481 #ifdef NETDATA_INTERNAL_CHECKS
1482 netdata_log_info(
1483 "EBPF running with \"LEGACY\" code, because it was started with the option \"[-]-legacy\".");
1484 #endif
1485 break;
1486 }
1487 case EBPF_OPTION_CORE: {
1488 ebpf_set_load_mode(EBPF_LOAD_CORE, EBPF_LOADED_FROM_USER);
1489 #ifdef NETDATA_INTERNAL_CHECKS
1490 netdata_log_info(
1491 "EBPF running with \"CO-RE\" code, because it was started with the option \"[-]-core\".");
1492 #endif
1493 break;
1494 }
1495 case EBPF_OPTION_UNITTEST: {
1496 // if we cannot run until the end, we will cancel the unittest
1497 int exit_code = ECANCELED;
1498 if (ebpf_can_plugin_load_code(running_on_kernel, NETDATA_EBPF_PLUGIN_NAME))
1499 goto unittest;
1500
1501 if (ebpf_adjust_memory_limit())
1502 goto unittest;
1503
1504 // Load binary in entry mode
1505 ebpf_ut_initialize_structure(MODE_ENTRY);
1506 if (ebpf_ut_load_real_binary())
1507 goto unittest;
1508
1509 ebpf_ut_cleanup_memory();
1510
1511 // Do not load a binary in entry mode
1512 ebpf_ut_initialize_structure(MODE_ENTRY);
1513 if (ebpf_ut_load_fake_binary())
1514 goto unittest;
1515
1516 ebpf_ut_cleanup_memory();
1517
1518 exit_code = 0;
1519 unittest:
1520 exit(exit_code);
1521 }
1522 default: {
1523 break;
1524 }
1525 }
1526 }
1527
1528 if (disable_cgroups) {
1529 ebpf_disable_cgroups();
1530 }
1531
1532 if (select_threads) {
1533 disable_all_global_charts();
1534 uint64_t idx;
1535 for (idx = 0; idx < EBPF_OPTION_ALL_CHARTS; idx++) {
1536 if (select_threads & 1 << idx)
1537 ebpf_enable_specific_chart(&ebpf_modules[idx], disable_cgroups);
1538 }
1539 }
1540
1541 // Load apps_groups.conf
1542 if (ebpf_read_apps_groups_conf(
1543 &apps_groups_default_target, &apps_groups_root_target, ebpf_user_config_dir, "groups")) {
1544 netdata_log_info(
1545 "Cannot read process groups configuration file '%s/apps_groups.conf'. Will try '%s/apps_groups.conf'",
1546 ebpf_user_config_dir,
1547 ebpf_stock_config_dir);
1548 if (ebpf_read_apps_groups_conf(
1549 &apps_groups_default_target, &apps_groups_root_target, ebpf_stock_config_dir, "groups")) {
1550 netdata_log_error(
1551 "Cannot read process groups '%s/apps_groups.conf'. There are no internal defaults. Failing.",
1552 ebpf_stock_config_dir);
1553 ebpf_exit(1);
1554 }
1555 } else
1556 netdata_log_info("Loaded config file '%s/apps_groups.conf'", ebpf_user_config_dir);
1557 }
1558
1559 /*****************************************************************
1560 *
1561 * Collector charts
1562 *
1563 *****************************************************************/
1564
1565 static char *load_event_stat[NETDATA_EBPF_LOAD_STAT_END] = {"legacy", "co-re"};
1566 static char *memlock_stat = "memory_locked";
1567 static char *hash_table_stat = "hash_table";
1568 static char *hash_table_core[NETDATA_EBPF_LOAD_STAT_END] = {"per_core", "unique"};
1569
1570 /**
1571 * Send Hash Table PID data
1572 *
1573 * Send all information associated with a specific pid table.
1574 *
1575 * @param chart chart id
1576 * @param idx index position in hash_table_stats
1577 */
1578 static inline void ebpf_send_hash_table_pid_data(char *chart, uint32_t idx)
1579 {
1580 int i;
1581 ebpf_write_begin_chart(NETDATA_MONITORING_FAMILY, chart, "");
1582 for (i = 0; i < EBPF_MODULE_FUNCTION_IDX; i++) {
1583 ebpf_module_t *wem = &ebpf_modules[i];
1584 if (wem->functions.apps_routine)
1585 write_chart_dimension(
1586 (char *)wem->info.thread_name,
1587 (ebpf_module_enabled_get(wem) < NETDATA_THREAD_EBPF_STOPPING) ? wem->hash_table_stats[idx] : 0);
1588 }
1589 ebpf_write_end_chart();
1590 }
1591
1592 /**
1593 * Send Global Hash Table data
1594 *
1595 * Send all information associated with a specific pid table.
1596 *
1597 */
1598 static inline void ebpf_send_global_hash_table_data()
1599 {
1600 int i;
1601 ebpf_write_begin_chart(NETDATA_MONITORING_FAMILY, NETDATA_EBPF_HASH_TABLES_GLOBAL_ELEMENTS, "");
1602 for (i = 0; i < EBPF_MODULE_FUNCTION_IDX; i++) {
1603 ebpf_module_t *wem = &ebpf_modules[i];
1604 write_chart_dimension(
1605 (char *)wem->info.thread_name,
1606 (ebpf_module_enabled_get(wem) < NETDATA_THREAD_EBPF_STOPPING) ? NETDATA_CONTROLLER_END : 0);
1607 }
1608 ebpf_write_end_chart();
1609 }
1610
1611 /**
1612 * Send Statistic Data
1613 *
1614 * Send statistic information to netdata.
1615 */
1616 void ebpf_send_statistic_data()
1617 {
1618 if (!publish_internal_metrics)
1619 return;
1620
1621 ebpf_write_begin_chart(NETDATA_MONITORING_FAMILY, NETDATA_EBPF_THREADS, "");
1622 int i;
1623 for (i = 0; i < EBPF_MODULE_FUNCTION_IDX; i++) {
1624 ebpf_module_t *wem = &ebpf_modules[i];
1625 if (wem->functions.fnct_routine)
1626 continue;
1627
1628 write_chart_dimension(
1629 (char *)wem->info.thread_name, (ebpf_module_enabled_get(wem) < NETDATA_THREAD_EBPF_STOPPING) ? 1 : 0);
1630 }
1631 ebpf_write_end_chart();
1632
1633 ebpf_write_begin_chart(NETDATA_MONITORING_FAMILY, "monitoring_pid", "");
1634 write_chart_dimension("user", ebpf_all_pids_count);
1635 write_chart_dimension("kernel", ebpf_hash_table_pids_count);
1636 ebpf_write_end_chart();
1637
1638 ebpf_write_begin_chart(NETDATA_MONITORING_FAMILY, NETDATA_EBPF_LIFE_TIME, "");
1639 for (i = 0; i < EBPF_MODULE_FUNCTION_IDX; i++) {
1640 ebpf_module_t *wem = &ebpf_modules[i];
1641 // Threads like VFS is slow to load and this can create an invalid number, this is the motive
1642 // we are also testing wem->lifetime value.
1643 if (wem->functions.fnct_routine)
1644 continue;
1645
1646 write_chart_dimension(
1647 (char *)wem->info.thread_name,
1648 (wem->lifetime && ebpf_module_enabled_get(wem) < NETDATA_THREAD_EBPF_STOPPING) ?
1649 (long long)(wem->lifetime - wem->running_time) :
1650 0);
1651 }
1652 ebpf_write_end_chart();
1653
1654 ebpf_write_begin_chart(NETDATA_MONITORING_FAMILY, NETDATA_EBPF_LOAD_METHOD, "");
1655 write_chart_dimension(load_event_stat[NETDATA_EBPF_LOAD_STAT_LEGACY], (long long)plugin_statistics.legacy);
1656 write_chart_dimension(load_event_stat[NETDATA_EBPF_LOAD_STAT_CORE], (long long)plugin_statistics.core);
1657 ebpf_write_end_chart();
1658
1659 ebpf_write_begin_chart(NETDATA_MONITORING_FAMILY, NETDATA_EBPF_KERNEL_MEMORY, "");
1660 write_chart_dimension(memlock_stat, (long long)plugin_statistics.memlock_kern);
1661 ebpf_write_end_chart();
1662
1663 ebpf_user_mem_stat_t ipc_data;
1664 netdata_integration_current_ipc_data(&ipc_data);
1665 NETDATA_DOUBLE ipc_value = 0.0;
1666 if (ipc_data.total > 0)
1667 ipc_value = ((NETDATA_DOUBLE)ipc_data.current / (NETDATA_DOUBLE)ipc_data.total) * 100.0;
1668 ebpf_write_begin_chart(NETDATA_MONITORING_FAMILY, NETDATA_EBPF_IPC_USAGE, "");
1669 write_chart_dimension("positions", (long long)ipc_value);
1670 ebpf_write_end_chart();
1671
1672 ebpf_write_begin_chart(NETDATA_MONITORING_FAMILY, NETDATA_EBPF_HASH_TABLES_LOADED, "");
1673 write_chart_dimension(hash_table_stat, (long long)plugin_statistics.hash_tables);
1674 ebpf_write_end_chart();
1675
1676 ebpf_write_begin_chart(NETDATA_MONITORING_FAMILY, NETDATA_EBPF_HASH_TABLES_PER_CORE, "");
1677 write_chart_dimension(hash_table_core[NETDATA_EBPF_THREAD_PER_CORE], (long long)plugin_statistics.hash_percpu);
1678 write_chart_dimension(hash_table_core[NETDATA_EBPF_THREAD_UNIQUE], (long long)plugin_statistics.hash_unique);
1679 ebpf_write_end_chart();
1680
1681 ebpf_send_global_hash_table_data();
1682
1683 ebpf_send_hash_table_pid_data(
1684 NETDATA_EBPF_HASH_TABLES_INSERT_PID_ELEMENTS, NETDATA_EBPF_GLOBAL_TABLE_PID_TABLE_ADD);
1685 ebpf_send_hash_table_pid_data(
1686 NETDATA_EBPF_HASH_TABLES_REMOVE_PID_ELEMENTS, NETDATA_EBPF_GLOBAL_TABLE_PID_TABLE_DEL);
1687
1688 for (i = 0; i < EBPF_MODULE_FUNCTION_IDX; i++) {
1689 ebpf_module_t *wem = &ebpf_modules[i];
1690 if (!wem->functions.fnct_routine || !wem->functions.fcnt_thread_chart_name ||
1691 !wem->functions.fcnt_thread_lifetime_name)
1692 continue;
1693
1694 ebpf_write_begin_chart(NETDATA_MONITORING_FAMILY, wem->functions.fcnt_thread_chart_name, "");
1695 write_chart_dimension(
1696 (char *)wem->info.thread_name, (ebpf_module_enabled_get(wem) < NETDATA_THREAD_EBPF_STOPPING) ? 1 : 0);
1697 ebpf_write_end_chart();
1698
1699 ebpf_write_begin_chart(NETDATA_MONITORING_FAMILY, wem->functions.fcnt_thread_lifetime_name, "");
1700 write_chart_dimension(
1701 (char *)wem->info.thread_name,
1702 (wem->lifetime && ebpf_module_enabled_get(wem) < NETDATA_THREAD_EBPF_STOPPING) ?
1703 (long long)(wem->lifetime - wem->running_time) :
1704 0);
1705 ebpf_write_end_chart();
1706 }
1707 }
1708
1709 /**
1710 * Update Internal Metric variable
1711 *
1712 * By default eBPF.plugin sends internal metrics for netdata, but user can
1713 * disable this.
1714 *
1715 * The function updates the variable used to send charts.
1716 */
1717 static void update_internal_metric_variable()
1718 {
1719 const char *s = getenv("NETDATA_INTERNALS_MONITORING");
1720 if (s && *s && strcmp(s, "NO") == 0)
1721 publish_internal_metrics = false;
1722 }
1723
1724 /**
1725 * Create PIDS Chart
1726 *
1727 * Write to standard output current values for PIDSs charts.
1728 *
1729 * @param order order to display chart
1730 * @param update_every time used to update charts
1731 */
1732 static void ebpf_create_pids_chart(int order, int update_every)
1733 {
1734 ebpf_write_chart_cmd(
1735 NETDATA_MONITORING_FAMILY,
1736 "monitoring_pid",
1737 "",
1738 "Total number of monitored PIDs",
1739 "pids",
1740 NETDATA_EBPF_FAMILY,
1741 NETDATA_EBPF_CHART_TYPE_LINE,
1742 "netdata.ebpf_pids",
1743 order,
1744 update_every,
1745 "main");
1746
1747 ebpf_write_global_dimension("user", "user", ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
1748
1749 ebpf_write_global_dimension("kernel", "kernel", ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
1750 }
1751
1752 /**
1753 * Create Thread Chart
1754 *
1755 * Write to standard output current values for threads charts.
1756 *
1757 * @param name is the chart name
1758 * @param title chart title.
1759 * @param units chart units
1760 * @param order is the chart order
1761 * @param update_every time used to update charts
1762 * @param module a module to create a specific chart.
1763 */
1764 static void
1765 ebpf_create_thread_chart(char *name, char *title, char *units, int order, int update_every, ebpf_module_t *module)
1766 {
1767 // common call for specific and all charts.
1768 ebpf_write_chart_cmd(
1769 NETDATA_MONITORING_FAMILY,
1770 name,
1771 "",
1772 title,
1773 units,
1774 NETDATA_EBPF_FAMILY,
1775 NETDATA_EBPF_CHART_TYPE_LINE,
1776 NULL,
1777 order,
1778 update_every,
1779 "main");
1780
1781 if (module) {
1782 ebpf_write_global_dimension(
1783 (char *)module->info.thread_name,
1784 (char *)module->info.thread_name,
1785 ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
1786 return;
1787 }
1788
1789 int i;
1790 for (i = 0; i < EBPF_MODULE_FUNCTION_IDX; i++) {
1791 ebpf_module_t *em = &ebpf_modules[i];
1792 if (em->functions.fnct_routine)
1793 continue;
1794
1795 ebpf_write_global_dimension(
1796 (char *)em->info.thread_name, (char *)em->info.thread_name, ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
1797 }
1798 }
1799
1800 /**
1801 * Create chart for Load Thread
1802 *
1803 * Write to standard output current values for load mode.
1804 *
1805 * @param update_every time used to update charts
1806 */
1807 static inline void ebpf_create_statistic_ipc_usage(int update_every)
1808 {
1809 ebpf_write_chart_cmd(
1810 NETDATA_MONITORING_FAMILY,
1811 NETDATA_EBPF_IPC_USAGE,
1812 "",
1813 "IPC used array positions.",
1814 "%",
1815 NETDATA_EBPF_FAMILY,
1816 NETDATA_EBPF_CHART_TYPE_LINE,
1817 NULL,
1818 NETDATA_EBPF_ORDER_PIDS_IPC,
1819 update_every,
1820 NETDATA_EBPF_MODULE_NAME_PROCESS);
1821
1822 ebpf_write_global_dimension("positions", "positions", ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
1823 }
1824
1825 /**
1826 * Create chart for Load Thread
1827 *
1828 * Write to standard output current values for load mode.
1829 *
1830 * @param update_every time used to update charts
1831 */
1832 static inline void ebpf_create_statistic_load_chart(int update_every)
1833 {
1834 ebpf_write_chart_cmd(
1835 NETDATA_MONITORING_FAMILY,
1836 NETDATA_EBPF_LOAD_METHOD,
1837 "",
1838 "Load info.",
1839 "methods",
1840 NETDATA_EBPF_FAMILY,
1841 NETDATA_EBPF_CHART_TYPE_LINE,
1842 NULL,
1843 NETDATA_EBPF_ORDER_STAT_LOAD_METHOD,
1844 update_every,
1845 NETDATA_EBPF_MODULE_NAME_PROCESS);
1846
1847 ebpf_write_global_dimension(
1848 load_event_stat[NETDATA_EBPF_LOAD_STAT_LEGACY],
1849 load_event_stat[NETDATA_EBPF_LOAD_STAT_LEGACY],
1850 ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
1851
1852 ebpf_write_global_dimension(
1853 load_event_stat[NETDATA_EBPF_LOAD_STAT_CORE],
1854 load_event_stat[NETDATA_EBPF_LOAD_STAT_CORE],
1855 ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
1856 }
1857
1858 /**
1859 * Create chart for Kernel Memory
1860 *
1861 * Write to standard output current values for allocated memory.
1862 *
1863 * @param update_every time used to update charts
1864 */
1865 static inline void ebpf_create_statistic_kernel_memory(int update_every)
1866 {
1867 ebpf_write_chart_cmd(
1868 NETDATA_MONITORING_FAMILY,
1869 NETDATA_EBPF_KERNEL_MEMORY,
1870 "",
1871 "Memory allocated for hash tables.",
1872 "bytes",
1873 NETDATA_EBPF_FAMILY,
1874 NETDATA_EBPF_CHART_TYPE_LINE,
1875 NULL,
1876 NETDATA_EBPF_ORDER_STAT_KERNEL_MEMORY,
1877 update_every,
1878 NETDATA_EBPF_MODULE_NAME_PROCESS);
1879
1880 ebpf_write_global_dimension(memlock_stat, memlock_stat, ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
1881 }
1882
1883 /**
1884 * Create chart Hash Table
1885 *
1886 * Write to standard output number of hash tables used with this software.
1887 *
1888 * @param update_every time used to update charts
1889 */
1890 static inline void ebpf_create_statistic_hash_tables(int update_every)
1891 {
1892 ebpf_write_chart_cmd(
1893 NETDATA_MONITORING_FAMILY,
1894 NETDATA_EBPF_HASH_TABLES_LOADED,
1895 "",
1896 "Number of hash tables loaded.",
1897 "hash tables",
1898 NETDATA_EBPF_FAMILY,
1899 NETDATA_EBPF_CHART_TYPE_LINE,
1900 NULL,
1901 NETDATA_EBPF_ORDER_STAT_HASH_TABLES,
1902 update_every,
1903 NETDATA_EBPF_MODULE_NAME_PROCESS);
1904
1905 ebpf_write_global_dimension(hash_table_stat, hash_table_stat, ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
1906 }
1907
1908 /**
1909 * Create chart for percpu stats
1910 *
1911 * Write to standard output current values for threads.
1912 *
1913 * @param update_every time used to update charts
1914 */
1915 static inline void ebpf_create_statistic_hash_per_core(int update_every)
1916 {
1917 ebpf_write_chart_cmd(
1918 NETDATA_MONITORING_FAMILY,
1919 NETDATA_EBPF_HASH_TABLES_PER_CORE,
1920 "",
1921 "How threads are loading hash/array tables.",
1922 "threads",
1923 NETDATA_EBPF_FAMILY,
1924 NETDATA_EBPF_CHART_TYPE_LINE,
1925 NULL,
1926 NETDATA_EBPF_ORDER_STAT_HASH_CORE,
1927 update_every,
1928 NETDATA_EBPF_MODULE_NAME_PROCESS);
1929
1930 ebpf_write_global_dimension(
1931 hash_table_core[NETDATA_EBPF_THREAD_PER_CORE],
1932 hash_table_core[NETDATA_EBPF_THREAD_PER_CORE],
1933 ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
1934
1935 ebpf_write_global_dimension(
1936 hash_table_core[NETDATA_EBPF_THREAD_UNIQUE],
1937 hash_table_core[NETDATA_EBPF_THREAD_UNIQUE],
1938 ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
1939 }
1940
1941 /**
1942 * Hash table global elements
1943 *
1944 * Write to standard output current values inside global tables.
1945 *
1946 * @param update_every time used to update charts
1947 */
1948 static void ebpf_create_statistic_hash_global_elements(int update_every)
1949 {
1950 ebpf_write_chart_cmd(
1951 NETDATA_MONITORING_FAMILY,
1952 NETDATA_EBPF_HASH_TABLES_GLOBAL_ELEMENTS,
1953 "",
1954 "Controllers inside global table",
1955 "rows",
1956 NETDATA_EBPF_FAMILY,
1957 NETDATA_EBPF_CHART_TYPE_LINE,
1958 NULL,
1959 NETDATA_EBPF_ORDER_STAT_HASH_GLOBAL_TABLE_TOTAL,
1960 update_every,
1961 NETDATA_EBPF_MODULE_NAME_PROCESS);
1962
1963 int i;
1964 for (i = 0; i < EBPF_MODULE_FUNCTION_IDX; i++) {
1965 ebpf_write_global_dimension(
1966 (char *)ebpf_modules[i].info.thread_name,
1967 (char *)ebpf_modules[i].info.thread_name,
1968 ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
1969 }
1970 }
1971
1972 /**
1973 * Hash table global elements
1974 *
1975 * Write to standard output current values inside global tables.
1976 *
1977 * @param update_every time used to update charts
1978 * @param id chart id
1979 * @param title chart title
1980 * @param order ordder chart will be shown on dashboard.
1981 */
1982 static void ebpf_create_statistic_hash_pid_table(int update_every, char *id, char *title, int order)
1983 {
1984 ebpf_write_chart_cmd(
1985 NETDATA_MONITORING_FAMILY,
1986 id,
1987 "",
1988 title,
1989 "rows",
1990 NETDATA_EBPF_FAMILY,
1991 NETDATA_EBPF_CHART_TYPE_LINE,
1992 NULL,
1993 order,
1994 update_every,
1995 NETDATA_EBPF_MODULE_NAME_PROCESS);
1996
1997 int i;
1998 for (i = 0; i < EBPF_MODULE_FUNCTION_IDX; i++) {
1999 ebpf_module_t *wem = &ebpf_modules[i];
2000 if (wem->functions.apps_routine)
2001 ebpf_write_global_dimension(
2002 (char *)wem->info.thread_name,
2003 (char *)wem->info.thread_name,
2004 ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX]);
2005 }
2006 }
2007
2008 /**
2009 * Create Statistics Charts
2010 *
2011 * Create charts that will show statistics related to eBPF plugin.
2012 *
2013 * @param update_every time used to update charts
2014 */
2015 static void ebpf_create_statistic_charts(int update_every)
2016 {
2017 static char create_charts = 1;
2018 update_internal_metric_variable();
2019 if (!publish_internal_metrics)
2020 return;
2021
2022 if (!create_charts)
2023 return;
2024
2025 create_charts = 0;
2026
2027 ebpf_create_thread_chart(
2028 NETDATA_EBPF_THREADS, "Threads running.", "boolean", NETDATA_EBPF_ORDER_STAT_THREADS, update_every, NULL);
2029
2030 ebpf_create_pids_chart(NETDATA_EBPF_ORDER_PIDS, update_every);
2031
2032 ebpf_create_thread_chart(
2033 NETDATA_EBPF_LIFE_TIME,
2034 "Time remaining for thread.",
2035 "seconds",
2036 NETDATA_EBPF_ORDER_STAT_LIFE_TIME,
2037 update_every,
2038 NULL);
2039
2040 int i, j;
2041 char name[256];
2042 for (i = 0, j = NETDATA_EBPF_ORDER_FUNCTION_PER_THREAD; i < EBPF_MODULE_FUNCTION_IDX; i++) {
2043 ebpf_module_t *em = &ebpf_modules[i];
2044 if (!em->functions.fnct_routine)
2045 continue;
2046
2047 em->functions.order_thread_chart = j;
2048 snprintfz(name, sizeof(name) - 1, "%s_%s", NETDATA_EBPF_THREADS, em->info.thread_name);
2049 em->functions.fcnt_thread_chart_name = strdupz(name);
2050 ebpf_create_thread_chart(name, "Threads running.", "boolean", j++, update_every, em);
2051
2052 em->functions.order_thread_lifetime = j;
2053 snprintfz(name, sizeof(name) - 1, "%s_%s", NETDATA_EBPF_LIFE_TIME, em->info.thread_name);
2054 em->functions.fcnt_thread_lifetime_name = strdupz(name);
2055 ebpf_create_thread_chart(name, "Time remaining for thread.", "seconds", j++, update_every, em);
2056 }
2057
2058 ebpf_create_statistic_ipc_usage(update_every);
2059
2060 ebpf_create_statistic_load_chart(update_every);
2061
2062 ebpf_create_statistic_kernel_memory(update_every);
2063
2064 ebpf_create_statistic_hash_tables(update_every);
2065
2066 ebpf_create_statistic_hash_per_core(update_every);
2067
2068 ebpf_create_statistic_hash_global_elements(update_every);
2069
2070 ebpf_create_statistic_hash_pid_table(
2071 update_every,
2072 NETDATA_EBPF_HASH_TABLES_INSERT_PID_ELEMENTS,
2073 "Elements inserted into PID table",
2074 NETDATA_EBPF_ORDER_STAT_HASH_PID_TABLE_ADDED);
2075
2076 ebpf_create_statistic_hash_pid_table(
2077 update_every,
2078 NETDATA_EBPF_HASH_TABLES_REMOVE_PID_ELEMENTS,
2079 "Elements removed from PID table",
2080 NETDATA_EBPF_ORDER_STAT_HASH_PID_TABLE_REMOVED);
2081
2082 fflush(stdout);
2083 }
2084
2085 /*****************************************************************
2086 *
2087 * COLLECTOR ENTRY POINT
2088 *
2089 *****************************************************************/
2090
2091 /**
2092 * Update PID file
2093 *
2094 * Update the content of PID file
2095 *
2096 * @param filename is the full name of the file.
2097 * @param pid that identifies the process
2098 */
2099 static void ebpf_update_pid_file(char *filename, pid_t pid)
2100 {
2101 FILE *fp = fopen(filename, "w");
2102 if (!fp)
2103 return;
2104
2105 fprintf(fp, "%d", pid);
2106 fclose(fp);
2107 }
2108
2109 /**
2110 * Get Process Name
2111 *
2112 * Get process name from /proc/PID/status
2113 *
2114 * @param pid that identifies the process
2115 */
2116 static char *ebpf_get_process_name(pid_t pid)
2117 {
2118 char *name = NULL;
2119 char filename[FILENAME_MAX + 1];
2120 snprintfz(filename, sizeof(filename) - 1, "/proc/%d/status", pid);
2121
2122 procfile *ff = procfile_open(filename, " \t", PROCFILE_FLAG_DEFAULT);
2123 if (unlikely(!ff)) {
2124 netdata_log_error("Cannot open %s", filename);
2125 return name;
2126 }
2127
2128 ff = procfile_readall(ff);
2129 if (unlikely(!ff)) {
2130 procfile_close(ff);
2131 return name;
2132 }
2133
2134 unsigned long i, lines = procfile_lines(ff);
2135 for (i = 0; i < lines; i++) {
2136 char *cmp = procfile_lineword(ff, i, 0);
2137 if (!strcmp(cmp, "Name:")) {
2138 name = strdupz(procfile_lineword(ff, i, 1));
2139 break;
2140 }
2141 }
2142
2143 procfile_close(ff);
2144
2145 return name;
2146 }
2147
2148 /**
2149 * Read Previous PID
2150 *
2151 * @param filename is the full name of the file.
2152 *
2153 * @return It returns the PID used during previous execution on success or 0 otherwise
2154 */
2155 static pid_t ebpf_read_previous_pid(char *filename)
2156 {
2157 FILE *fp = fopen(filename, "r");
2158 if (!fp)
2159 return 0;
2160
2161 char buffer[64];
2162 size_t length = fread(buffer, sizeof(*buffer), 63, fp);
2163 pid_t old_pid = 0;
2164 if (length) {
2165 if (length > 63)
2166 length = 63;
2167
2168 buffer[length] = '\0';
2169 old_pid = (pid_t)str2uint32_t(buffer, NULL);
2170 }
2171 fclose(fp);
2172
2173 return old_pid;
2174 }
2175
2176 /**
2177 * Validate Data Sharing Selection
2178 *
2179 * Validate user input avoid sigsegv
2180 */
2181 void ebpf_validate_data_sharing_selection()
2182 {
2183 uint32_t enabled = CONFIG_BOOLEAN_NO;
2184 for (uint32_t i = 0; ebpf_modules[i].info.thread_name != NULL; i++) {
2185 if (ebpf_modules[i].apps_charts || ebpf_modules[i].cgroup_charts) {
2186 enabled = CONFIG_BOOLEAN_YES;
2187 break;
2188 }
2189 }
2190
2191 if (enabled && integration_with_collectors != NETDATA_EBPF_INTEGRATION_SHM) {
2192 integration_with_collectors = NETDATA_EBPF_INTEGRATION_SHM;
2193 }
2194 }
2195
2196 /**
2197 * Initialize Data Sharing
2198 *
2199 * Start sharing according to user configuration.
2200 */
2201 static void ebpf_initialize_data_sharing()
2202 {
2203 ebpf_validate_data_sharing_selection();
2204
2205 // Initialize
2206 switch (integration_with_collectors) {
2207 case NETDATA_EBPF_INTEGRATION_SOCKET: {
2208 socket_ipc =
2209 nd_thread_create("ebpf_socket_ipc", NETDATA_THREAD_OPTION_DEFAULT, ebpf_socket_thread_ipc, NULL);
2210 break;
2211 }
2212 case NETDATA_EBPF_INTEGRATION_SHM:
2213 // All pid_map_size have the same value
2214 if (netdata_integration_initialize_shm(ebpf_modules[EBPF_MODULE_PROCESS_IDX].pid_map_size)) {
2215 ebpf_set_apps_mode(NETDATA_EBPF_APPS_FLAG_NO);
2216 ebpf_disable_cgroups();
2217 }
2218 break;
2219 case NETDATA_EBPF_INTEGRATION_DISABLED:
2220 default:
2221 break;
2222 }
2223 }
2224
2225 /**
2226 * Kill previous process
2227 *
2228 * Kill previous process whether it was not closed.
2229 *
2230 * @param filename is the full name of the file.
2231 * @param pid that identifies the process
2232 */
2233 static void ebpf_kill_previous_process(char *filename, pid_t pid)
2234 {
2235 pid_t old_pid = ebpf_read_previous_pid(filename);
2236 if (!old_pid)
2237 return;
2238
2239 char *prev_name = ebpf_get_process_name(old_pid);
2240 if (!prev_name)
2241 return;
2242
2243 char *current_name = ebpf_get_process_name(pid);
2244 if (current_name && !strcmp(prev_name, current_name))
2245 kill(old_pid, SIGKILL);
2246
2247 freez(prev_name);
2248 freez(current_name);
2249
2250 // wait few microseconds before start new plugin
2251 sleep_usec(USEC_PER_MS * 300);
2252 }
2253
2254 /**
2255 * PID file
2256 *
2257 * Write the filename for PID inside the given vector.
2258 *
2259 * @param filename vector where we will store the name.
2260 * @param length number of bytes available in filename vector
2261 */
2262 void ebpf_pid_file(char *filename, size_t length)
2263 {
2264 snprintfz(filename, length - 1, "%s/var/run/ebpf.pid", netdata_configured_host_prefix);
2265 }
2266
2267 /**
2268 * Manage PID
2269 *
2270 * This function kills another instance of eBPF whether it is necessary and update the file content.
2271 *
2272 * @param pid that identifies the process
2273 */
2274 static void ebpf_manage_pid(pid_t pid)
2275 {
2276 char filename[FILENAME_MAX + 1];
2277 ebpf_pid_file(filename, FILENAME_MAX);
2278
2279 ebpf_kill_previous_process(filename, pid);
2280 ebpf_update_pid_file(filename, pid);
2281 }
2282
2283 /**
2284 * Set start routine
2285 *
2286 * Set static routine before threads to be created.
2287 */
2288 static void ebpf_set_static_routine()
2289 {
2290 int i;
2291 for (i = 0; ebpf_modules[i].info.thread_name != NULL; i++) {
2292 ebpf_threads[i].start_routine = ebpf_modules[i].functions.start_routine;
2293 }
2294 }
2295
2296 static void ebpf_signal_stop_handler(int sig)
2297 {
2298 // Async-signal-safe stop request: actual shutdown is handled by main thread flow.
2299 if (!ebpf_stop_signal)
2300 ebpf_stop_signal = (sig > 0) ? sig : 1;
2301 }
2302
2303 static bool ebpf_all_enabled_threads_stopped(void)
2304 {
2305 bool any_enabled = false;
2306
2307 for (size_t i = 0; ebpf_threads[i].name != NULL; i++) {
2308 if (!ebpf_threads[i].enabled)
2309 continue;
2310
2311 any_enabled = true;
2312
2313 if (!ebpf_threads[i].thread)
2314 continue;
2315
2316 if (ebpf_module_enabled_get(&ebpf_modules[i]) < NETDATA_THREAD_EBPF_STOPPING)
2317 return false;
2318 }
2319
2320 return any_enabled;
2321 }
2322
2323 /**
2324 * Entry point
2325 *
2326 * @param argc the number of arguments
2327 * @param argv the pointer to the arguments
2328 *
2329 * @return it returns 0 on success and another integer otherwise
2330 */
2331 int main(int argc, char **argv)
2332 {
2333 // Reduce memory footprint:
2334 // - Single malloc arena avoids fragmentation across 24+ threads
2335 // - Allocations >1MB use mmap so they're returned to OS on free,
2336 // preventing 30MB+ of brk heap holes from libbpf's temp buffers
2337 // - THP disabled prevents 2MB huge page waste in sparse allocations
2338 #if defined(HAVE_C_MALLOPT)
2339 mallopt(M_ARENA_MAX, 1);
2340 mallopt(M_MMAP_THRESHOLD, 1024 * 1024);
2341 #endif
2342 #if defined(HAVE_SYS_PRCTL_H) && defined(PR_SET_THP_DISABLE)
2343 prctl(PR_SET_THP_DISABLE, 1, 0, 0, 0);
2344 #endif
2345
2346 nd_log_initialize_for_external_plugins(NETDATA_EBPF_PLUGIN_NAME);
2347 netdata_threads_init_for_external_plugins(0);
2348
2349 libjudy_malloc_init();
2350
2351 ebpf_set_global_variables();
2352 if (ebpf_can_plugin_load_code(running_on_kernel, NETDATA_EBPF_PLUGIN_NAME))
2353 return 2;
2354
2355 if (ebpf_adjust_memory_limit())
2356 return 3;
2357
2358 main_thread_id = gettid_cached();
2359
2360 ebpf_parse_args(argc, argv);
2361 ebpf_manage_pid(getpid());
2362
2363 signal(SIGINT, ebpf_signal_stop_handler);
2364 signal(SIGQUIT, ebpf_signal_stop_handler);
2365 signal(SIGTERM, ebpf_signal_stop_handler);
2366 signal(SIGPIPE, ebpf_signal_stop_handler);
2367
2368 ebpf_mutex_initialize();
2369
2370 netdata_configured_host_prefix = getenv("NETDATA_HOST_PREFIX");
2371 if (verify_netdata_host_prefix(true) == -1)
2372 ebpf_exit(1);
2373
2374 ebpf_allocate_common_vectors();
2375
2376 #ifdef LIBBPF_MAJOR_VERSION
2377 libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
2378
2379 #ifndef NETDATA_INTERNAL_CHECKS
2380 libbpf_set_print(netdata_silent_libbpf_vfprintf);
2381 #endif
2382 #endif
2383
2384 ebpf_read_local_addresses_unsafe();
2385 read_local_ports("/proc/net/tcp", IPPROTO_TCP);
2386 read_local_ports("/proc/net/tcp6", IPPROTO_TCP);
2387 read_local_ports("/proc/net/udp", IPPROTO_UDP);
2388 read_local_ports("/proc/net/udp6", IPPROTO_UDP);
2389
2390 ebpf_set_static_routine();
2391
2392 cgroup_integration_thread.start_routine = ebpf_cgroup_integration;
2393
2394 cgroup_integration_thread.thread =
2395 nd_thread_create(cgroup_integration_thread.name, NETDATA_THREAD_OPTION_DEFAULT, ebpf_cgroup_integration, NULL);
2396
2397 ebpf_initialize_data_sharing();
2398
2399 uint32_t i;
2400 for (i = 0; ebpf_threads[i].name != NULL; i++) {
2401 struct netdata_static_thread *st = &ebpf_threads[i];
2402
2403 ebpf_module_t *em = &ebpf_modules[i];
2404 em->thread = st;
2405 em->thread_id = i;
2406 if (ebpf_module_enabled_get(em) != NETDATA_THREAD_EBPF_NOT_RUNNING) {
2407 ebpf_module_enabled_set(em, NETDATA_THREAD_EBPF_RUNNING);
2408 em->lifetime = EBPF_NON_FUNCTION_LIFE_TIME;
2409
2410 if (em->functions.apps_routine && (em->apps_charts || em->cgroup_charts)) {
2411 collect_pids |= 1 << i;
2412 }
2413 st->thread = nd_thread_create(st->name, NETDATA_THREAD_OPTION_DEFAULT, st->start_routine, em);
2414 } else {
2415 st->enabled = 0;
2416 em->lifetime = EBPF_DEFAULT_LIFETIME;
2417 }
2418 }
2419
2420 // BPF loading allocated ~50MB then freed most of it.
2421 // glibc keeps freed pages in its free list; trim returns them to the OS.
2422 #if defined(HAVE_C_MALLOC_TRIM)
2423 malloc_trim(0);
2424 #endif
2425
2426 heartbeat_t hb;
2427 heartbeat_init(&hb, USEC_PER_SEC);
2428 int update_apps_every = (int)EBPF_CFG_UPDATE_APPS_EVERY_DEFAULT;
2429 int update_apps_list = update_apps_every - 1;
2430 int exit_code = 0;
2431 //Plugin will be killed when it receives a signal
2432 for (; !ebpf_plugin_stop(); global_iterations_counter++) {
2433 (void)heartbeat_next(&hb);
2434
2435 // Skip all work (including expensive apps-parsing) if shutdown was requested
2436 // while we were sleeping. Without this check the main thread runs
2437 // ebpf_parse_proc_files()+ebpf_create_apps_charts() while holding lock +
2438 // collect_data_mutex, blocking module threads from exiting and doubling
2439 // shutdown time when fd/process/socket/vfs modules are enabled.
2440 if (ebpf_plugin_stop())
2441 break;
2442
2443 if (!ebpf_program_loaded() && ebpf_all_enabled_threads_stopped()) {
2444 netdata_log_error("EBPF: failed to load any eBPF program, shutting down.");
2445 exit_code = 1;
2446 break;
2447 }
2448
2449 if (global_iterations_counter % EBPF_DEFAULT_UPDATE_EVERY == 0) {
2450 netdata_mutex_lock(&lock);
2451 ebpf_create_statistic_charts(EBPF_DEFAULT_UPDATE_EVERY);
2452
2453 ebpf_send_statistic_data();
2454 fflush(stdout);
2455 netdata_mutex_unlock(&lock);
2456 }
2457
2458 if (++update_apps_list == update_apps_every) {
2459 update_apps_list = 0;
2460 netdata_mutex_lock(&lock);
2461 if (collect_pids) {
2462 netdata_mutex_lock(&collect_data_mutex);
2463 ebpf_parse_proc_files();
2464 ebpf_create_apps_charts(apps_groups_root_target);
2465 netdata_mutex_unlock(&collect_data_mutex);
2466 }
2467 netdata_mutex_unlock(&lock);
2468 }
2469 }
2470
2471 ebpf_stop_threads((int)ebpf_stop_signal);
2472
2473 return exit_code;
2474 }