master
c 1,856 lines 59.6 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "ebpf.h"
4 #include "ebpf_process.h"
5 #include "libbpf_api/ebpf_library.h"
6
7 /*****************************************************************
8 *
9 * GLOBAL VARIABLES
10 *
11 *****************************************************************/
12
13 static char *process_dimension_names[NETDATA_KEY_PUBLISH_PROCESS_END] = {"process", "task", "process", "thread"};
14 static char *process_id_names[NETDATA_KEY_PUBLISH_PROCESS_END] = {"do_exit", "release_task", "_do_fork", "sys_clone"};
15 static char *status[] = {"process", "zombie"};
16
17 netdata_ebpf_targets_t process_targets[] = {
18 {.name = "release_task", .mode = EBPF_LOAD_TRAMPOLINE},
19 {.name = "__x64_sys_clone", .mode = EBPF_LOAD_TRAMPOLINE},
20 {.name = "__x64_sys_clone3", .mode = EBPF_LOAD_TRAMPOLINE},
21 {.name = "_do_fork", .mode = EBPF_LOAD_TRAMPOLINE},
22 {.name = NULL, .mode = EBPF_LOAD_TRAMPOLINE}};
23
24 static ebpf_local_maps_t process_maps[] = {
25 {.name = "tbl_pid_stats",
26 .internal_input = ND_EBPF_DEFAULT_PID_SIZE,
27 .user_input = 0,
28 .type = NETDATA_EBPF_MAP_RESIZABLE | NETDATA_EBPF_MAP_PID,
29 .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
30 #ifdef LIBBPF_MAJOR_VERSION
31 .map_type = BPF_MAP_TYPE_PERCPU_HASH
32 #endif
33 },
34 {.name = "tbl_total_stats",
35 .internal_input = NETDATA_KEY_END_VECTOR,
36 .user_input = 0,
37 .type = NETDATA_EBPF_MAP_STATIC,
38 .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
39 #ifdef LIBBPF_MAJOR_VERSION
40 .map_type = BPF_MAP_TYPE_PERCPU_ARRAY
41 #endif
42 },
43 {.name = "process_ctrl",
44 .internal_input = NETDATA_CONTROLLER_END,
45 .user_input = 0,
46 .type = NETDATA_EBPF_MAP_CONTROLLER,
47 .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
48 #ifdef LIBBPF_MAJOR_VERSION
49 .map_type = BPF_MAP_TYPE_PERCPU_ARRAY
50 #endif
51 },
52 {.name = NULL,
53 .internal_input = 0,
54 .user_input = 0,
55 .type = NETDATA_EBPF_MAP_CONTROLLER,
56 .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
57 #ifdef LIBBPF_MAJOR_VERSION
58 .map_type = BPF_MAP_TYPE_PERCPU_ARRAY
59 #endif
60 }};
61
62 char *tracepoint_sched_type = "sched";
63 char *tracepoint_sched_process_exit = "sched_process_exit";
64 char *tracepoint_sched_process_exec = "sched_process_exec";
65 char *tracepoint_sched_process_fork = "sched_process_fork";
66 static int was_sched_process_exit_enabled = 0;
67 static int was_sched_process_exec_enabled = 0;
68 static int was_sched_process_fork_enabled = 0;
69
70 static netdata_idx_t *process_hash_values = NULL;
71 ebpf_process_stat_t *process_stat_vector = NULL;
72 static bool process_safe_clean = false;
73 static netdata_syscall_stat_t process_aggregated_data[NETDATA_KEY_PUBLISH_PROCESS_END];
74 static netdata_publish_syscall_t process_publish_aggregated[NETDATA_KEY_PUBLISH_PROCESS_END];
75
76 struct config process_config = APPCONFIG_INITIALIZER;
77
78 #ifdef LIBBPF_MAJOR_VERSION
79 /**
80 * Disable probe
81 *
82 * Disable all probes to use exclusively another method.
83 *
84 * @param obj is the main structure for bpf objects
85 */
86 static void ebpf_process_disable_probe(struct process_bpf *obj)
87 {
88 bpf_program__set_autoload(obj->progs.netdata_release_task_probe, false);
89 bpf_program__set_autoload(obj->progs.netdata_do_fork_probe, false);
90 bpf_program__set_autoload(obj->progs.netdata_kernel_clone_probe, false);
91 }
92
93 static void ebpf_disable_tracepoints(struct process_bpf *obj)
94 {
95 bpf_program__set_autoload(obj->progs.netdata_clone_exit, false);
96 bpf_program__set_autoload(obj->progs.netdata_clone3_exit, false);
97 bpf_program__set_autoload(obj->progs.netdata_fork_exit, false);
98 bpf_program__set_autoload(obj->progs.netdata_vfork_exit, false);
99 }
100
101 static void ebpf_set_trampoline_target(struct process_bpf *obj)
102 {
103 bpf_program__set_attach_target(
104 obj->progs.netdata_release_task_fentry, 0, process_targets[PROCESS_RELEASE_TASK_NAME].name);
105
106 bpf_program__set_attach_target(obj->progs.netdata_clone_fexit, 0, process_targets[PROCESS_SYS_CLONE].name);
107
108 bpf_program__set_attach_target(obj->progs.netdata_clone3_fexit, 0, process_targets[PROCESS_SYS_CLONE3].name);
109 }
110
111 /*
112 * Disable trampoline
113 *
114 * Disable all trampoline to use exclusively another method.
115 *
116 * @param obj is the main structure for bpf objects.
117 */
118 static void ebpf_disable_trampoline(struct process_bpf *obj)
119 {
120 bpf_program__set_autoload(obj->progs.netdata_release_task_fentry, false);
121 bpf_program__set_autoload(obj->progs.netdata_clone_fexit, false);
122 bpf_program__set_autoload(obj->progs.netdata_clone3_fexit, false);
123 }
124
125 static inline void ebpf_disable_clone3(struct process_bpf *obj)
126 {
127 bpf_program__set_autoload(obj->progs.netdata_clone3_exit, false);
128 bpf_program__set_autoload(obj->progs.netdata_clone3_fexit, false);
129 }
130
131 static inline void ebpf_adjust_process_fork(struct process_bpf *obj)
132 {
133 if (running_on_kernel <= NETDATA_EBPF_KERNEL_6_16) {
134 bpf_program__set_autoload(obj->progs.netdata_tracepoint_sched_process_fork, true);
135 bpf_program__set_autoload(obj->progs.netdata_tracepoint_sched_process_fork_v2, false);
136 } else {
137 bpf_program__set_autoload(obj->progs.netdata_tracepoint_sched_process_fork_v2, true);
138 bpf_program__set_autoload(obj->progs.netdata_tracepoint_sched_process_fork, false);
139 }
140 }
141
142 /**
143 * Mount Attach Probe
144 *
145 * Attach probes to target
146 *
147 * @param obj is the main structure for bpf objects.
148 *
149 * @return It returns 0 on success and -1 otherwise.
150 */
151 static inline int process_attach_kprobe_target(struct process_bpf *obj)
152 {
153 obj->links.netdata_release_task_probe = bpf_program__attach_kprobe(
154 obj->progs.netdata_release_task_probe, false, process_targets[PROCESS_RELEASE_TASK_NAME].name);
155 int ret = libbpf_get_error(obj->links.netdata_release_task_probe);
156 if (ret)
157 goto endakt;
158
159 if (running_on_kernel < NETDATA_EBPF_KERNEL_5_9_16) {
160 obj->links.netdata_do_fork_probe =
161 bpf_program__attach_kprobe(obj->progs.netdata_do_fork_probe, false, process_targets[PROCESS_SYS_FORK].name);
162 ret = libbpf_get_error(obj->links.netdata_do_fork_probe);
163 } else {
164 obj->links.netdata_kernel_clone_probe = bpf_program__attach_kprobe(
165 obj->progs.netdata_kernel_clone_probe, false, process_targets[PROCESS_KERNEL_CLONE].name);
166 ret = libbpf_get_error(obj->links.netdata_kernel_clone_probe);
167 }
168 endakt:
169 return ret;
170 }
171
172 /**
173 * Set hash tables
174 *
175 * Set the values for maps according the value given by kernel.
176 *
177 * @param obj is the main structure for bpf objects.
178 */
179 static void ebpf_process_set_hash_tables(struct process_bpf *obj)
180 {
181 process_maps[NETDATA_PROCESS_GLOBAL_TABLE].map_fd = bpf_map__fd(obj->maps.tbl_total_stats);
182 process_maps[NETDATA_PROCESS_PID_TABLE].map_fd = bpf_map__fd(obj->maps.tbl_pid_stats);
183 process_maps[NETDATA_PROCESS_CTRL_TABLE].map_fd = bpf_map__fd(obj->maps.process_ctrl);
184 }
185
186 /**
187 * Load and attach
188 *
189 * Load and attach the eBPF code in kernel.
190 *
191 * @param obj is the main structure for bpf objects.
192 * @param em structure with configuration
193 *
194 * @return it returns 0 on success and -1 otherwise
195 */
196 static inline int ebpf_process_load_and_attach(struct process_bpf *obj, ebpf_module_t *em)
197 {
198 netdata_ebpf_program_loaded_t mode = em->targets[PROCESS_RELEASE_TASK_NAME].mode;
199 if (mode == EBPF_LOAD_TRAMPOLINE) {
200 ebpf_process_disable_probe(obj);
201 ebpf_disable_tracepoints(obj);
202
203 ebpf_set_trampoline_target(obj);
204 } else if (mode == EBPF_LOAD_PROBE || mode == EBPF_LOAD_RETPROBE) {
205 ebpf_disable_tracepoints(obj);
206 ebpf_disable_trampoline(obj);
207
208 bpf_program__set_autoload(
209 (running_on_kernel <= NETDATA_EBPF_KERNEL_5_9_16) ? obj->progs.netdata_kernel_clone_probe :
210 obj->progs.netdata_do_fork_probe,
211 false);
212 } else { // Tracepoint
213 ebpf_process_disable_probe(obj);
214 ebpf_disable_trampoline(obj);
215 }
216
217 if (running_on_kernel < NETDATA_EBPF_KERNEL_5_3) {
218 ebpf_disable_clone3(obj);
219 }
220
221 ebpf_adjust_process_fork(obj);
222
223 int ret = process_bpf__load(obj);
224 if (ret) {
225 return ret;
226 }
227
228 ret = (mode == EBPF_LOAD_TRAMPOLINE) ? process_bpf__attach(obj) : process_attach_kprobe_target(obj);
229 if (!ret) {
230 ebpf_process_set_hash_tables(obj);
231
232 ebpf_update_controller(cachestat_maps[NETDATA_PROCESS_CTRL_TABLE].map_fd, em);
233 }
234
235 return ret;
236 }
237 #endif
238
239 /*
240 * Load BPF
241 *
242 * Load BPF files.
243 *
244 * @param em the structure with configuration
245 */
246 static int ebpf_process_load_bpf(ebpf_module_t *em)
247 {
248 #ifdef LIBBPF_MAJOR_VERSION
249 ebpf_define_map_type(process_maps, em->maps_per_core, running_on_kernel);
250 #endif
251
252 int ret = 0;
253 // ebpf_adjust_apps_cgroup(em, em->targets[NETDATA_KEY_CALLS_ADD_TO_PAGE_CACHE_LRU].mode);
254 if (em->load & EBPF_LOAD_LEGACY) {
255 em->probe_links = ebpf_load_program(ebpf_plugin_dir, em, running_on_kernel, isrh, &em->objects);
256 if (!em->probe_links) {
257 ret = -1;
258 }
259 }
260 #ifdef LIBBPF_MAJOR_VERSION
261 else {
262 process_bpf_obj = process_bpf__open();
263 if (!process_bpf_obj)
264 ret = -1;
265 else {
266 ret = ebpf_process_load_and_attach(process_bpf_obj, em);
267 if (ret) {
268 process_bpf__destroy(process_bpf_obj);
269 process_bpf_obj = NULL;
270 }
271 }
272 }
273 #endif
274
275 if (ret)
276 netdata_log_error("%s %s", EBPF_DEFAULT_ERROR_MSG, em->info.thread_name);
277
278 return ret;
279 }
280
281 /*****************************************************************
282 *
283 * PROCESS DATA AND SEND TO NETDATA
284 *
285 *****************************************************************/
286
287 /**
288 * Update publish structure before to send data to Netdata.
289 *
290 * @param publish the first output structure with independent dimensions
291 * @param pvc the second output structure with correlated dimensions
292 * @param input the structure with the input data.
293 */
294 static void ebpf_update_global_publish(
295 netdata_publish_syscall_t *publish,
296 netdata_publish_vfs_common_t *pvc,
297 netdata_syscall_stat_t *input)
298 {
299 netdata_publish_syscall_t *move = publish;
300 int selector = NETDATA_KEY_PUBLISH_PROCESS_EXIT;
301 while (move) {
302 move->ncall = (input->call > move->pcall) ? input->call - move->pcall : move->pcall - input->call;
303 move->nbyte = (input->bytes > move->pbyte) ? input->bytes - move->pbyte : move->pbyte - input->bytes;
304 move->nerr = (input->ecall > move->nerr) ? input->ecall - move->perr : move->perr - input->ecall;
305
306 move->pcall = input->call;
307 move->pbyte = input->bytes;
308 move->perr = input->ecall;
309
310 input = input->next;
311 move = move->next;
312 selector++;
313 }
314
315 pvc->running =
316 (long)publish[NETDATA_KEY_PUBLISH_PROCESS_FORK].ncall - (long)publish[NETDATA_KEY_PUBLISH_PROCESS_CLONE].ncall;
317 pvc->zombie = (long)publish[NETDATA_KEY_PUBLISH_PROCESS_EXIT].ncall -
318 (long)publish[NETDATA_KEY_PUBLISH_PROCESS_RELEASE_TASK].ncall;
319 }
320
321 /**
322 * Call the necessary functions to create a chart.
323 *
324 * @param family the chart family
325 * @param move the pointer with the values that will be published
326 */
327 static void write_status_chart(char *family, netdata_publish_vfs_common_t *pvc)
328 {
329 ebpf_write_begin_chart(family, NETDATA_PROCESS_STATUS_NAME, "");
330
331 write_chart_dimension(status[0], (long long)pvc->running);
332 write_chart_dimension(status[1], (long long)pvc->zombie);
333
334 ebpf_write_end_chart();
335 }
336
337 /**
338 * Send data to Netdata calling auxiliary functions.
339 *
340 * @param em the structure with thread information
341 */
342 static void ebpf_process_send_data(ebpf_module_t *em)
343 {
344 netdata_publish_vfs_common_t pvc;
345 ebpf_update_global_publish(process_publish_aggregated, &pvc, process_aggregated_data);
346
347 write_count_chart(
348 NETDATA_EXIT_SYSCALL,
349 NETDATA_EBPF_SYSTEM_GROUP,
350 &process_publish_aggregated[NETDATA_KEY_PUBLISH_PROCESS_EXIT],
351 2);
352 write_count_chart(
353 NETDATA_PROCESS_SYSCALL,
354 NETDATA_EBPF_SYSTEM_GROUP,
355 &process_publish_aggregated[NETDATA_KEY_PUBLISH_PROCESS_FORK],
356 2);
357
358 write_status_chart(NETDATA_EBPF_SYSTEM_GROUP, &pvc);
359 if (em->mode < MODE_ENTRY) {
360 write_err_chart(
361 NETDATA_PROCESS_ERROR_NAME,
362 NETDATA_EBPF_SYSTEM_GROUP,
363 &process_publish_aggregated[NETDATA_KEY_PUBLISH_PROCESS_FORK],
364 2);
365 }
366 }
367
368 /**
369 * Send data to Netdata calling auxiliary functions.
370 *
371 * @param root the target list.
372 */
373 void ebpf_process_send_apps_data(struct ebpf_target *root, ebpf_module_t *em)
374 {
375 struct ebpf_target *w;
376
377 for (w = root; w; w = w->next) {
378 if (ebpf_plugin_stop())
379 break;
380
381 if (unlikely(!(w->charts_created & (1 << EBPF_MODULE_PROCESS_IDX))))
382 continue;
383
384 ebpf_write_begin_chart(NETDATA_APP_FAMILY, w->clean_name, "_ebpf_process_start");
385 write_chart_dimension("calls", w->process.create_process);
386 ebpf_write_end_chart();
387
388 ebpf_write_begin_chart(NETDATA_APP_FAMILY, w->clean_name, "_ebpf_thread_start");
389 write_chart_dimension("calls", w->process.create_thread);
390 ebpf_write_end_chart();
391
392 ebpf_write_begin_chart(NETDATA_APP_FAMILY, w->clean_name, "_ebpf_task_exit");
393 write_chart_dimension("calls", w->process.exit_call);
394 ebpf_write_end_chart();
395
396 ebpf_write_begin_chart(NETDATA_APP_FAMILY, w->clean_name, "_ebpf_task_released");
397 write_chart_dimension("calls", w->process.release_call);
398 ebpf_write_end_chart();
399
400 if (em->mode < MODE_ENTRY) {
401 ebpf_write_begin_chart(NETDATA_APP_FAMILY, w->clean_name, "_ebpf_task_error");
402 write_chart_dimension("calls", w->process.task_err);
403 ebpf_write_end_chart();
404 }
405 }
406 }
407
408 /*****************************************************************
409 *
410 * READ INFORMATION FROM KERNEL RING
411 *
412 *****************************************************************/
413
414 /**
415 * Read the hash table and store data to allocated vectors.
416 *
417 * @param maps_per_core do I need to read all cores?
418 */
419 static void ebpf_read_process_hash_global_tables(netdata_idx_t *stats, int maps_per_core)
420 {
421 netdata_idx_t res[NETDATA_KEY_END_VECTOR];
422 ebpf_read_global_table_stats(
423 res,
424 process_hash_values,
425 process_maps[NETDATA_PROCESS_GLOBAL_TABLE].map_fd,
426 maps_per_core,
427 0,
428 NETDATA_KEY_END_VECTOR);
429
430 ebpf_read_global_table_stats(
431 stats,
432 process_hash_values,
433 process_maps[NETDATA_PROCESS_CTRL_TABLE].map_fd,
434 maps_per_core,
435 NETDATA_CONTROLLER_PID_TABLE_ADD,
436 NETDATA_CONTROLLER_END);
437
438 process_aggregated_data[NETDATA_KEY_PUBLISH_PROCESS_EXIT].call = res[NETDATA_KEY_CALLS_DO_EXIT];
439 process_aggregated_data[NETDATA_KEY_PUBLISH_PROCESS_RELEASE_TASK].call = res[NETDATA_KEY_CALLS_RELEASE_TASK];
440 process_aggregated_data[NETDATA_KEY_PUBLISH_PROCESS_FORK].call = res[NETDATA_KEY_CALLS_DO_FORK];
441 process_aggregated_data[NETDATA_KEY_PUBLISH_PROCESS_CLONE].call = res[NETDATA_KEY_CALLS_SYS_CLONE];
442
443 process_aggregated_data[NETDATA_KEY_PUBLISH_PROCESS_FORK].ecall = res[NETDATA_KEY_ERROR_DO_FORK];
444 process_aggregated_data[NETDATA_KEY_PUBLISH_PROCESS_CLONE].ecall = res[NETDATA_KEY_ERROR_SYS_CLONE];
445 }
446
447 /**
448 * Update cgroup
449 *
450 * Update cgroup data based in PID running.
451 *
452 * @param maps_per_core do I need to read all cores?
453 */
454 static void ebpf_update_process_cgroup()
455 {
456 ebpf_cgroup_target_t *ect;
457 netdata_mutex_lock(&mutex_cgroup_shm);
458 for (ect = ebpf_cgroup_pids; ect; ect = ect->next) {
459 if (ebpf_plugin_stop())
460 break;
461
462 struct pid_on_target2 *pids;
463 for (pids = ect->pids; pids; pids = pids->next) {
464 uint32_t pid = pids->pid;
465 ebpf_publish_process_t *out = &pids->ps;
466 netdata_ebpf_pid_stats_t *local_pid = netdata_ebpf_lookup_shm_pointer_unsafe(pid);
467 if (!local_pid || !(local_pid->threads & (1U << (NETDATA_EBPF_PIDS_PROCESS_IDX << 1))))
468 continue;
469
470 ebpf_publish_process_t *in = &local_pid->process;
471
472 memcpy(out, in, sizeof(ebpf_publish_process_t));
473 }
474 }
475 netdata_mutex_unlock(&mutex_cgroup_shm);
476 }
477
478 /*****************************************************************
479 *
480 * FUNCTIONS TO CREATE CHARTS
481 *
482 *****************************************************************/
483
484 /**
485 * Create process status chart
486 *
487 * @param family the chart family
488 * @param name the chart name
489 * @param axis the axis label
490 * @param web the group name used to attach the chart on dashboard
491 * @param order the order number of the specified chart
492 * @param update_every value to overwrite the update frequency set by the server.
493 */
494 static void
495 ebpf_process_status_chart(char *family, char *name, char *axis, char *web, char *algorithm, int order, int update_every)
496 {
497 printf(
498 "CHART %s.%s '' 'Process not closed' '%s' '%s' 'system.process_status' line %d %d '' 'ebpf.plugin' 'process'\n",
499 family,
500 name,
501 axis,
502 web,
503 order,
504 update_every);
505
506 printf("DIMENSION %s '' %s 1 1\n", status[0], algorithm);
507 printf("DIMENSION %s '' %s 1 1\n", status[1], algorithm);
508 }
509
510 /**
511 * Create global charts
512 *
513 * Call ebpf_create_chart to create the charts for the collector.
514 *
515 * @param em a pointer to the structure with the default values.
516 */
517 static void ebpf_create_global_charts(ebpf_module_t *em)
518 {
519 ebpf_create_chart(
520 NETDATA_EBPF_SYSTEM_GROUP,
521 NETDATA_PROCESS_SYSCALL,
522 "Start process",
523 EBPF_COMMON_UNITS_CALLS_PER_SEC,
524 NETDATA_PROCESS_GROUP,
525 "system.process_thread",
526 NETDATA_EBPF_CHART_TYPE_LINE,
527 21002,
528 ebpf_create_global_dimension,
529 &process_publish_aggregated[NETDATA_KEY_PUBLISH_PROCESS_FORK],
530 2,
531 em->update_every,
532 NETDATA_EBPF_MODULE_NAME_PROCESS);
533
534 ebpf_create_chart(
535 NETDATA_EBPF_SYSTEM_GROUP,
536 NETDATA_EXIT_SYSCALL,
537 "Exit process",
538 EBPF_COMMON_UNITS_CALLS_PER_SEC,
539 NETDATA_PROCESS_GROUP,
540 "system.exit",
541 NETDATA_EBPF_CHART_TYPE_LINE,
542 21003,
543 ebpf_create_global_dimension,
544 &process_publish_aggregated[NETDATA_KEY_PUBLISH_PROCESS_EXIT],
545 2,
546 em->update_every,
547 NETDATA_EBPF_MODULE_NAME_PROCESS);
548
549 ebpf_process_status_chart(
550 NETDATA_EBPF_SYSTEM_GROUP,
551 NETDATA_PROCESS_STATUS_NAME,
552 EBPF_COMMON_UNITS_CALLS,
553 NETDATA_PROCESS_GROUP,
554 ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX],
555 21004,
556 em->update_every);
557
558 if (em->mode < MODE_ENTRY) {
559 ebpf_create_chart(
560 NETDATA_EBPF_SYSTEM_GROUP,
561 NETDATA_PROCESS_ERROR_NAME,
562 "Fails to create process",
563 EBPF_COMMON_UNITS_CALLS_PER_SEC,
564 NETDATA_PROCESS_GROUP,
565 "system.task_error",
566 NETDATA_EBPF_CHART_TYPE_LINE,
567 21005,
568 ebpf_create_global_dimension,
569 &process_publish_aggregated[NETDATA_KEY_PUBLISH_PROCESS_FORK],
570 2,
571 em->update_every,
572 NETDATA_EBPF_MODULE_NAME_PROCESS);
573 }
574
575 fflush(stdout);
576 }
577
578 /**
579 * Create process apps charts
580 *
581 * Call ebpf_create_chart to create the charts on apps submenu.
582 *
583 * @param em a pointer to the structure with the default values.
584 * @param ptr a pointer for the targets.
585 */
586 void ebpf_process_create_apps_charts(struct ebpf_module *em, void *ptr)
587 {
588 struct ebpf_target *root = ptr;
589 struct ebpf_target *w;
590 int update_every = em->update_every;
591 for (w = root; w; w = w->next) {
592 if (ebpf_plugin_stop())
593 break;
594
595 if (unlikely(!w->exposed))
596 continue;
597
598 ebpf_write_chart_cmd(
599 NETDATA_APP_FAMILY,
600 w->clean_name,
601 "_ebpf_process_start",
602 "Process started.",
603 EBPF_COMMON_UNITS_CALLS_PER_SEC,
604 NETDATA_PROCESS_GROUP,
605 NETDATA_EBPF_CHART_TYPE_STACKED,
606 "app.ebpf_process_start",
607 20161,
608 update_every,
609 NETDATA_EBPF_MODULE_NAME_PROCESS);
610 ebpf_create_chart_labels("app_group", w->name, RRDLABEL_SRC_AUTO);
611 ebpf_commit_label();
612 fprintf(stdout, "DIMENSION calls '' %s 1 1\n", ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX]);
613
614 ebpf_write_chart_cmd(
615 NETDATA_APP_FAMILY,
616 w->clean_name,
617 "_ebpf_thread_start",
618 "Threads started.",
619 EBPF_COMMON_UNITS_CALLS_PER_SEC,
620 NETDATA_PROCESS_GROUP,
621 NETDATA_EBPF_CHART_TYPE_STACKED,
622 "app.ebpf_thread_start",
623 20162,
624 update_every,
625 NETDATA_EBPF_MODULE_NAME_PROCESS);
626 ebpf_create_chart_labels("app_group", w->name, RRDLABEL_SRC_AUTO);
627 ebpf_commit_label();
628 fprintf(stdout, "DIMENSION calls '' %s 1 1\n", ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX]);
629
630 ebpf_write_chart_cmd(
631 NETDATA_APP_FAMILY,
632 w->clean_name,
633 "_ebpf_task_exit",
634 "Tasks starts exit process.",
635 EBPF_COMMON_UNITS_CALLS_PER_SEC,
636 NETDATA_PROCESS_GROUP,
637 NETDATA_EBPF_CHART_TYPE_STACKED,
638 "app.ebpf_task_exit",
639 20163,
640 update_every,
641 NETDATA_EBPF_MODULE_NAME_PROCESS);
642 ebpf_create_chart_labels("app_group", w->name, RRDLABEL_SRC_AUTO);
643 ebpf_commit_label();
644 fprintf(stdout, "DIMENSION calls '' %s 1 1\n", ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX]);
645
646 ebpf_write_chart_cmd(
647 NETDATA_APP_FAMILY,
648 w->clean_name,
649 "_ebpf_task_released",
650 "Tasks released.",
651 EBPF_COMMON_UNITS_CALLS_PER_SEC,
652 NETDATA_PROCESS_GROUP,
653 NETDATA_EBPF_CHART_TYPE_STACKED,
654 "app.ebpf_task_released",
655 20164,
656 update_every,
657 NETDATA_EBPF_MODULE_NAME_PROCESS);
658 ebpf_create_chart_labels("app_group", w->name, RRDLABEL_SRC_AUTO);
659 ebpf_commit_label();
660 fprintf(stdout, "DIMENSION calls '' %s 1 1\n", ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX]);
661
662 if (em->mode < MODE_ENTRY) {
663 ebpf_write_chart_cmd(
664 NETDATA_APP_FAMILY,
665 w->clean_name,
666 "_ebpf_task_error",
667 "Errors to create process or threads.",
668 EBPF_COMMON_UNITS_CALLS_PER_SEC,
669 NETDATA_PROCESS_GROUP,
670 NETDATA_EBPF_CHART_TYPE_STACKED,
671 "app.ebpf_task_error",
672 20165,
673 update_every,
674 NETDATA_EBPF_MODULE_NAME_PROCESS);
675 ebpf_create_chart_labels("app_group", w->name, RRDLABEL_SRC_AUTO);
676 ebpf_commit_label();
677 fprintf(stdout, "DIMENSION calls '' %s 1 1\n", ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX]);
678 }
679 w->charts_created |= 1 << EBPF_MODULE_PROCESS_IDX;
680 }
681
682 em->apps_charts |= NETDATA_EBPF_APPS_FLAG_CHART_CREATED;
683 }
684
685 /*****************************************************************
686 *
687 * FUNCTIONS TO CLOSE THE THREAD
688 *
689 *****************************************************************/
690
691 static void ebpf_obsolete_specific_process_charts(char *type, ebpf_module_t *em);
692
693 /**
694 * Obsolete services
695 *
696 * Obsolete all service charts created
697 *
698 * @param em a pointer to `struct ebpf_module`
699 */
700 static void ebpf_obsolete_process_services(ebpf_module_t *em, char *id)
701 {
702 ebpf_write_chart_obsolete(
703 id,
704 NETDATA_SYSCALL_APPS_TASK_PROCESS,
705 "",
706 "Process started",
707 EBPF_COMMON_UNITS_CALLS_PER_SEC,
708 NETDATA_APPS_PROCESS_GROUP,
709 NETDATA_EBPF_CHART_TYPE_STACKED,
710 NETDATA_SYSTEMD_PROCESS_CREATE_CONTEXT,
711 20065,
712 em->update_every);
713
714 ebpf_write_chart_obsolete(
715 id,
716 NETDATA_SYSCALL_APPS_TASK_THREAD,
717 "",
718 "Threads started",
719 EBPF_COMMON_UNITS_CALLS_PER_SEC,
720 NETDATA_APPS_PROCESS_GROUP,
721 NETDATA_EBPF_CHART_TYPE_STACKED,
722 NETDATA_SYSTEMD_THREAD_CREATE_CONTEXT,
723 20066,
724 em->update_every);
725
726 ebpf_write_chart_obsolete(
727 id,
728 NETDATA_SYSCALL_APPS_TASK_CLOSE,
729 "",
730 "Tasks starts exit process.",
731 EBPF_COMMON_UNITS_CALLS_PER_SEC,
732 NETDATA_APPS_PROCESS_GROUP,
733 NETDATA_EBPF_CHART_TYPE_STACKED,
734 NETDATA_SYSTEMD_PROCESS_EXIT_CONTEXT,
735 20067,
736 em->update_every);
737
738 ebpf_write_chart_obsolete(
739 id,
740 NETDATA_SYSCALL_APPS_TASK_EXIT,
741 "",
742 "Tasks closed",
743 EBPF_COMMON_UNITS_CALLS_PER_SEC,
744 NETDATA_APPS_PROCESS_GROUP,
745 NETDATA_EBPF_CHART_TYPE_STACKED,
746 NETDATA_SYSTEMD_PROCESS_CLOSE_CONTEXT,
747 20068,
748 em->update_every);
749
750 if (em->mode < MODE_ENTRY) {
751 ebpf_write_chart_obsolete(
752 id,
753 NETDATA_SYSCALL_APPS_TASK_ERROR,
754 "",
755 "Errors to create process or threads.",
756 EBPF_COMMON_UNITS_CALLS_PER_SEC,
757 NETDATA_APPS_PROCESS_GROUP,
758 NETDATA_EBPF_CHART_TYPE_STACKED,
759 NETDATA_SYSTEMD_PROCESS_ERROR_CONTEXT,
760 20069,
761 em->update_every);
762 }
763 }
764
765 /**
766 * Obsolete cgroup chart
767 *
768 * Send obsolete for all charts created before to close.
769 *
770 * @param em a pointer to `struct ebpf_module`
771 */
772 static inline void ebpf_obsolete_process_cgroup_charts(ebpf_module_t *em)
773 {
774 netdata_mutex_lock(&mutex_cgroup_shm);
775
776 ebpf_cgroup_target_t *ect;
777 for (ect = ebpf_cgroup_pids; ect; ect = ect->next) {
778 if (ect->systemd) {
779 ebpf_obsolete_process_services(em, ect->name);
780
781 continue;
782 }
783
784 ebpf_obsolete_specific_process_charts(ect->name, em);
785 }
786 netdata_mutex_unlock(&mutex_cgroup_shm);
787 }
788
789 /**
790 * Obsolette apps charts
791 *
792 * Obsolete apps charts.
793 *
794 * @param em a pointer to the structure with the default values.
795 */
796 void ebpf_obsolete_process_apps_charts(struct ebpf_module *em)
797 {
798 struct ebpf_target *w;
799 int update_every = em->update_every;
800 for (w = apps_groups_root_target; w; w = w->next) {
801 if (unlikely(!(w->charts_created & (1 << EBPF_MODULE_PROCESS_IDX))))
802 continue;
803
804 ebpf_write_chart_obsolete(
805 NETDATA_APP_FAMILY,
806 w->clean_name,
807 "_ebpf_process_start",
808 "Process started.",
809 EBPF_COMMON_UNITS_CALLS_PER_SEC,
810 NETDATA_PROCESS_GROUP,
811 NETDATA_EBPF_CHART_TYPE_STACKED,
812 "app.ebpf_process_start",
813 20161,
814 update_every);
815
816 ebpf_write_chart_obsolete(
817 NETDATA_APP_FAMILY,
818 w->clean_name,
819 "_ebpf_thread_start",
820 "Threads started.",
821 EBPF_COMMON_UNITS_CALLS_PER_SEC,
822 NETDATA_PROCESS_GROUP,
823 NETDATA_EBPF_CHART_TYPE_STACKED,
824 "app.ebpf_thread_start",
825 20162,
826 update_every);
827
828 ebpf_write_chart_obsolete(
829 NETDATA_APP_FAMILY,
830 w->clean_name,
831 "_ebpf_task_exit",
832 "Tasks starts exit process.",
833 EBPF_COMMON_UNITS_CALLS_PER_SEC,
834 NETDATA_PROCESS_GROUP,
835 NETDATA_EBPF_CHART_TYPE_STACKED,
836 "app.ebpf_task_exit",
837 20163,
838 update_every);
839
840 ebpf_write_chart_obsolete(
841 NETDATA_APP_FAMILY,
842 w->clean_name,
843 "_ebpf_task_released",
844 "Tasks released.",
845 EBPF_COMMON_UNITS_CALLS_PER_SEC,
846 NETDATA_PROCESS_GROUP,
847 NETDATA_EBPF_CHART_TYPE_STACKED,
848 "app.ebpf_task_released",
849 20164,
850 update_every);
851
852 if (em->mode < MODE_ENTRY) {
853 ebpf_write_chart_obsolete(
854 NETDATA_APP_FAMILY,
855 w->clean_name,
856 "_ebpf_task_error",
857 "Errors to create process or threads.",
858 EBPF_COMMON_UNITS_CALLS_PER_SEC,
859 NETDATA_PROCESS_GROUP,
860 NETDATA_EBPF_CHART_TYPE_STACKED,
861 "app.ebpf_task_error",
862 20165,
863 update_every);
864 }
865
866 w->charts_created &= ~(1 << EBPF_MODULE_PROCESS_IDX);
867 }
868 }
869
870 /**
871 * Obsolete global
872 *
873 * Obsolete global charts created by thread.
874 *
875 * @param em a pointer to `struct ebpf_module`
876 */
877 static void ebpf_obsolete_process_global(ebpf_module_t *em)
878 {
879 ebpf_write_chart_obsolete(
880 NETDATA_EBPF_SYSTEM_GROUP,
881 NETDATA_PROCESS_SYSCALL,
882 "",
883 "Start process",
884 EBPF_COMMON_UNITS_CALLS_PER_SEC,
885 NETDATA_PROCESS_GROUP,
886 NETDATA_EBPF_CHART_TYPE_LINE,
887 "system.process_thread",
888 21002,
889 em->update_every);
890
891 ebpf_write_chart_obsolete(
892 NETDATA_EBPF_SYSTEM_GROUP,
893 NETDATA_EXIT_SYSCALL,
894 "",
895 "Exit process",
896 EBPF_COMMON_UNITS_CALLS_PER_SEC,
897 NETDATA_PROCESS_GROUP,
898 NETDATA_EBPF_CHART_TYPE_LINE,
899 "system.exit",
900 21003,
901 em->update_every);
902
903 ebpf_write_chart_obsolete(
904 NETDATA_EBPF_SYSTEM_GROUP,
905 NETDATA_PROCESS_STATUS_NAME,
906 "",
907 "Process not closed",
908 EBPF_COMMON_UNITS_CALLS,
909 NETDATA_PROCESS_GROUP,
910 NETDATA_EBPF_CHART_TYPE_LINE,
911 "system.process_status",
912 21004,
913 em->update_every);
914
915 if (em->mode < MODE_ENTRY) {
916 ebpf_write_chart_obsolete(
917 NETDATA_EBPF_SYSTEM_GROUP,
918 NETDATA_PROCESS_ERROR_NAME,
919 "",
920 "Fails to create process",
921 EBPF_COMMON_UNITS_CALLS_PER_SEC,
922 NETDATA_PROCESS_GROUP,
923 NETDATA_EBPF_CHART_TYPE_LINE,
924 "system.task_error",
925 21005,
926 em->update_every);
927 }
928 }
929
930 /**
931 * Process disable tracepoints
932 *
933 * Disable tracepoints when the plugin was responsible to enable it.
934 */
935 static void ebpf_process_disable_tracepoints()
936 {
937 char *default_message = "Cannot disable the tracepoint";
938 if (!was_sched_process_exit_enabled) {
939 if (ebpf_disable_tracing_values(tracepoint_sched_type, tracepoint_sched_process_exit))
940 netdata_log_error("%s %s/%s.", default_message, tracepoint_sched_type, tracepoint_sched_process_exit);
941 }
942
943 if (!was_sched_process_exec_enabled) {
944 if (ebpf_disable_tracing_values(tracepoint_sched_type, tracepoint_sched_process_exec))
945 netdata_log_error("%s %s/%s.", default_message, tracepoint_sched_type, tracepoint_sched_process_exec);
946 }
947
948 if (!was_sched_process_fork_enabled) {
949 if (ebpf_disable_tracing_values(tracepoint_sched_type, tracepoint_sched_process_fork))
950 netdata_log_error("%s %s/%s.", default_message, tracepoint_sched_type, tracepoint_sched_process_fork);
951 }
952 }
953
954 static void ebpf_process_exit(void *pptr)
955 {
956 ebpf_set_pid_map_fd(NETDATA_EBPF_PIDS_PROCESS_IDX, -1);
957 ebpf_module_t *em = CLEANUP_FUNCTION_GET_PTR(pptr);
958 if (!em)
959 return;
960
961 if (!process_safe_clean) {
962 netdata_mutex_lock(&ebpf_exit_cleanup);
963 ebpf_module_enabled_set(em, NETDATA_THREAD_EBPF_STOPPED);
964 netdata_mutex_unlock(&ebpf_exit_cleanup);
965 return;
966 }
967
968 netdata_mutex_lock(&lock);
969 collect_pids &= ~(1 << EBPF_MODULE_PROCESS_IDX);
970 netdata_mutex_unlock(&lock);
971
972 // Drop this module's bits from the shared PID pool so its slots don't
973 // stay pinned if the plugin keeps running after the module stops.
974 if (integration_shm && ebpf_shm_sem_wait_or_stop(shm_mutex_ebpf_integration)) {
975 netdata_ebpf_sweep_shm_for_module_unsafe(NETDATA_EBPF_PIDS_PROCESS_IDX);
976 sem_post(shm_mutex_ebpf_integration);
977 }
978
979 if (ebpf_module_enabled_get(em) == NETDATA_THREAD_EBPF_FUNCTION_RUNNING && !ebpf_plugin_stop()) {
980 netdata_mutex_lock(&lock);
981 if (em->cgroup_charts) {
982 ebpf_obsolete_process_cgroup_charts(em);
983 fflush(stdout);
984 }
985
986 if (em->apps_charts & NETDATA_EBPF_APPS_FLAG_CHART_CREATED) {
987 ebpf_obsolete_process_apps_charts(em);
988 }
989
990 ebpf_obsolete_process_global(em);
991
992 fflush(stdout);
993 netdata_mutex_unlock(&lock);
994 }
995
996 freez(process_hash_values);
997 freez(process_stat_vector);
998
999 ebpf_process_disable_tracepoints();
1000
1001 if (!ebpf_plugin_stop() && em->functions.bpf_unload)
1002 em->functions.bpf_unload(em);
1003
1004 netdata_mutex_lock(&ebpf_exit_cleanup);
1005 process_pid_fd = -1;
1006 ebpf_module_enabled_set(em, NETDATA_THREAD_EBPF_STOPPED);
1007 netdata_mutex_unlock(&ebpf_exit_cleanup);
1008 }
1009
1010 /*****************************************************************
1011 *
1012 * FUNCTIONS WITH THE MAIN LOOP
1013 *
1014 *****************************************************************/
1015
1016 /**
1017 * Sum PIDs
1018 *
1019 * Sum values for all targets.
1020 *
1021 * @param ps structure used to store data
1022 * @param pids input data
1023 */
1024 static void ebpf_process_sum_cgroup_pids(ebpf_publish_process_t *ps, struct pid_on_target2 *pids)
1025 {
1026 ebpf_publish_process_t accumulator;
1027 memset(&accumulator, 0, sizeof(accumulator));
1028
1029 while (pids) {
1030 ebpf_publish_process_t *pps = &pids->ps;
1031
1032 accumulator.exit_call += pps->exit_call;
1033 accumulator.release_call += pps->release_call;
1034 accumulator.create_process += pps->create_process;
1035 accumulator.create_thread += pps->create_thread;
1036
1037 accumulator.task_err += pps->task_err;
1038
1039 pids = pids->next;
1040 }
1041
1042 ps->exit_call = (accumulator.exit_call >= ps->exit_call) ? accumulator.exit_call : ps->exit_call;
1043 ps->release_call = (accumulator.release_call >= ps->release_call) ? accumulator.release_call : ps->release_call;
1044 ps->create_process =
1045 (accumulator.create_process >= ps->create_process) ? accumulator.create_process : ps->create_process;
1046 ps->create_thread =
1047 (accumulator.create_thread >= ps->create_thread) ? accumulator.create_thread : ps->create_thread;
1048
1049 ps->task_err = (accumulator.task_err >= ps->task_err) ? accumulator.task_err : ps->task_err;
1050 }
1051
1052 /*
1053 * Send Specific Process data
1054 *
1055 * Send data for specific cgroup/apps.
1056 *
1057 * @param type chart type
1058 * @param values structure with values that will be sent to netdata
1059 * @param em the structure with thread information
1060 */
1061 static void ebpf_send_specific_process_data(char *type, ebpf_publish_process_t *values, ebpf_module_t *em)
1062 {
1063 ebpf_write_begin_chart(type, NETDATA_SYSCALL_APPS_TASK_PROCESS, "");
1064 write_chart_dimension(
1065 process_publish_aggregated[NETDATA_KEY_PUBLISH_PROCESS_FORK].name, (long long)values->create_process);
1066 ebpf_write_end_chart();
1067
1068 ebpf_write_begin_chart(type, NETDATA_SYSCALL_APPS_TASK_THREAD, "");
1069 write_chart_dimension(
1070 process_publish_aggregated[NETDATA_KEY_PUBLISH_PROCESS_CLONE].name, (long long)values->create_thread);
1071 ebpf_write_end_chart();
1072
1073 ebpf_write_begin_chart(type, NETDATA_SYSCALL_APPS_TASK_EXIT, "");
1074 write_chart_dimension(
1075 process_publish_aggregated[NETDATA_KEY_PUBLISH_PROCESS_EXIT].name, (long long)values->release_call);
1076 ebpf_write_end_chart();
1077
1078 ebpf_write_begin_chart(type, NETDATA_SYSCALL_APPS_TASK_CLOSE, "");
1079 write_chart_dimension(
1080 process_publish_aggregated[NETDATA_KEY_PUBLISH_PROCESS_RELEASE_TASK].name, (long long)values->release_call);
1081 ebpf_write_end_chart();
1082
1083 if (em->mode < MODE_ENTRY) {
1084 ebpf_write_begin_chart(type, NETDATA_SYSCALL_APPS_TASK_ERROR, "");
1085 write_chart_dimension(
1086 process_publish_aggregated[NETDATA_KEY_PUBLISH_PROCESS_EXIT].name, (long long)values->task_err);
1087 ebpf_write_end_chart();
1088 }
1089 }
1090
1091 /**
1092 * Create specific process charts
1093 *
1094 * Create charts for cgroup/application
1095 *
1096 * @param type the chart type.
1097 * @param em the structure with thread information
1098 */
1099 static void ebpf_create_specific_process_charts(char *type, ebpf_module_t *em)
1100 {
1101 char *label = (!strncmp(type, "cgroup_", 7)) ? &type[7] : type;
1102 ebpf_create_chart(
1103 type,
1104 NETDATA_SYSCALL_APPS_TASK_PROCESS,
1105 "Process started",
1106 EBPF_COMMON_UNITS_CALLS_PER_SEC,
1107 NETDATA_PROCESS_GROUP,
1108 NETDATA_CGROUP_PROCESS_CREATE_CONTEXT,
1109 NETDATA_EBPF_CHART_TYPE_LINE,
1110 NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5000,
1111 ebpf_create_global_dimension,
1112 &process_publish_aggregated[NETDATA_KEY_PUBLISH_PROCESS_FORK],
1113 1,
1114 em->update_every,
1115 NETDATA_EBPF_MODULE_NAME_PROCESS);
1116 ebpf_create_chart_labels("cgroup_name", label, RRDLABEL_SRC_AUTO);
1117 ebpf_commit_label();
1118
1119 ebpf_create_chart(
1120 type,
1121 NETDATA_SYSCALL_APPS_TASK_THREAD,
1122 "Threads started",
1123 EBPF_COMMON_UNITS_CALLS_PER_SEC,
1124 NETDATA_PROCESS_GROUP,
1125 NETDATA_CGROUP_THREAD_CREATE_CONTEXT,
1126 NETDATA_EBPF_CHART_TYPE_LINE,
1127 NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5001,
1128 ebpf_create_global_dimension,
1129 &process_publish_aggregated[NETDATA_KEY_PUBLISH_PROCESS_CLONE],
1130 1,
1131 em->update_every,
1132 NETDATA_EBPF_MODULE_NAME_PROCESS);
1133 ebpf_create_chart_labels("cgroup_name", label, RRDLABEL_SRC_AUTO);
1134 ebpf_commit_label();
1135
1136 ebpf_create_chart(
1137 type,
1138 NETDATA_SYSCALL_APPS_TASK_EXIT,
1139 "Tasks starts exit process.",
1140 EBPF_COMMON_UNITS_CALLS_PER_SEC,
1141 NETDATA_PROCESS_GROUP,
1142 NETDATA_CGROUP_PROCESS_EXIT_CONTEXT,
1143 NETDATA_EBPF_CHART_TYPE_LINE,
1144 NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5002,
1145 ebpf_create_global_dimension,
1146 &process_publish_aggregated[NETDATA_KEY_PUBLISH_PROCESS_EXIT],
1147 1,
1148 em->update_every,
1149 NETDATA_EBPF_MODULE_NAME_PROCESS);
1150 ebpf_create_chart_labels("cgroup_name", label, RRDLABEL_SRC_AUTO);
1151 ebpf_commit_label();
1152
1153 ebpf_create_chart(
1154 type,
1155 NETDATA_SYSCALL_APPS_TASK_CLOSE,
1156 "Tasks closed",
1157 EBPF_COMMON_UNITS_CALLS_PER_SEC,
1158 NETDATA_PROCESS_GROUP,
1159 NETDATA_CGROUP_PROCESS_CLOSE_CONTEXT,
1160 NETDATA_EBPF_CHART_TYPE_LINE,
1161 NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5003,
1162 ebpf_create_global_dimension,
1163 &process_publish_aggregated[NETDATA_KEY_PUBLISH_PROCESS_RELEASE_TASK],
1164 1,
1165 em->update_every,
1166 NETDATA_EBPF_MODULE_NAME_PROCESS);
1167 ebpf_create_chart_labels("cgroup_name", label, RRDLABEL_SRC_AUTO);
1168 ebpf_commit_label();
1169
1170 if (em->mode < MODE_ENTRY) {
1171 ebpf_create_chart(
1172 type,
1173 NETDATA_SYSCALL_APPS_TASK_ERROR,
1174 "Errors to create process or threads.",
1175 EBPF_COMMON_UNITS_CALLS_PER_SEC,
1176 NETDATA_PROCESS_GROUP,
1177 NETDATA_CGROUP_PROCESS_ERROR_CONTEXT,
1178 NETDATA_EBPF_CHART_TYPE_LINE,
1179 NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5004,
1180 ebpf_create_global_dimension,
1181 &process_publish_aggregated[NETDATA_KEY_PUBLISH_PROCESS_EXIT],
1182 1,
1183 em->update_every,
1184 NETDATA_EBPF_MODULE_NAME_PROCESS);
1185 ebpf_create_chart_labels("cgroup_name", label, RRDLABEL_SRC_AUTO);
1186 ebpf_commit_label();
1187 }
1188 }
1189
1190 /**
1191 * Obsolete specific process charts
1192 *
1193 * Obsolete charts for cgroup/application
1194 *
1195 * @param type the chart type.
1196 * @param em the structure with thread information
1197 */
1198 static void ebpf_obsolete_specific_process_charts(char *type, ebpf_module_t *em)
1199 {
1200 ebpf_write_chart_obsolete(
1201 type,
1202 NETDATA_SYSCALL_APPS_TASK_PROCESS,
1203 "",
1204 "Process started",
1205 EBPF_COMMON_UNITS_CALLS_PER_SEC,
1206 NETDATA_PROCESS_GROUP,
1207 NETDATA_EBPF_CHART_TYPE_LINE,
1208 NETDATA_CGROUP_PROCESS_CREATE_CONTEXT,
1209 NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5000,
1210 em->update_every);
1211
1212 ebpf_write_chart_obsolete(
1213 type,
1214 NETDATA_SYSCALL_APPS_TASK_THREAD,
1215 "",
1216 "Threads started",
1217 EBPF_COMMON_UNITS_CALLS_PER_SEC,
1218 NETDATA_PROCESS_GROUP,
1219 NETDATA_EBPF_CHART_TYPE_LINE,
1220 NETDATA_CGROUP_THREAD_CREATE_CONTEXT,
1221 NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5001,
1222 em->update_every);
1223
1224 ebpf_write_chart_obsolete(
1225 type,
1226 NETDATA_SYSCALL_APPS_TASK_EXIT,
1227 "",
1228 "Tasks starts exit process.",
1229 EBPF_COMMON_UNITS_CALLS_PER_SEC,
1230 NETDATA_PROCESS_GROUP,
1231 NETDATA_EBPF_CHART_TYPE_LINE,
1232 NETDATA_CGROUP_PROCESS_EXIT_CONTEXT,
1233 NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5002,
1234 em->update_every);
1235
1236 ebpf_write_chart_obsolete(
1237 type,
1238 NETDATA_SYSCALL_APPS_TASK_CLOSE,
1239 "",
1240 "Tasks closed",
1241 EBPF_COMMON_UNITS_CALLS_PER_SEC,
1242 NETDATA_PROCESS_GROUP,
1243 NETDATA_EBPF_CHART_TYPE_LINE,
1244 NETDATA_CGROUP_PROCESS_CLOSE_CONTEXT,
1245 NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5003,
1246 em->update_every);
1247
1248 if (em->mode < MODE_ENTRY) {
1249 ebpf_write_chart_obsolete(
1250 type,
1251 NETDATA_SYSCALL_APPS_TASK_ERROR,
1252 "",
1253 "Errors to create process or threads.",
1254 EBPF_COMMON_UNITS_CALLS_PER_SEC,
1255 NETDATA_PROCESS_GROUP,
1256 NETDATA_EBPF_CHART_TYPE_LINE,
1257 NETDATA_CGROUP_PROCESS_ERROR_CONTEXT,
1258 NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5004,
1259 em->update_every);
1260 }
1261 }
1262
1263 /**
1264 * Create Systemd process Charts
1265 *
1266 * Create charts when systemd is enabled
1267 *
1268 * @param em the structure with thread information
1269 **/
1270 static void ebpf_create_systemd_process_charts(ebpf_module_t *em)
1271 {
1272 static ebpf_systemd_args_t data_process = {
1273 .title = "Process started",
1274 .units = EBPF_COMMON_UNITS_CALLS_PER_SEC,
1275 .family = NETDATA_APPS_PROCESS_GROUP,
1276 .charttype = NETDATA_EBPF_CHART_TYPE_STACKED,
1277 .order = 20065,
1278 .algorithm = EBPF_CHART_ALGORITHM_INCREMENTAL,
1279 .context = NETDATA_SYSTEMD_PROCESS_CREATE_CONTEXT,
1280 .module = NETDATA_EBPF_MODULE_NAME_PROCESS,
1281 .update_every = 0,
1282 .suffix = NETDATA_SYSCALL_APPS_TASK_PROCESS,
1283 .dimension = "calls"};
1284
1285 static ebpf_systemd_args_t data_thread = {
1286 .title = "Threads started",
1287 .units = EBPF_COMMON_UNITS_CALLS_PER_SEC,
1288 .family = NETDATA_APPS_PROCESS_GROUP,
1289 .charttype = NETDATA_EBPF_CHART_TYPE_STACKED,
1290 .order = 20066,
1291 .algorithm = EBPF_CHART_ALGORITHM_INCREMENTAL,
1292 .context = NETDATA_SYSTEMD_THREAD_CREATE_CONTEXT,
1293 .module = NETDATA_EBPF_MODULE_NAME_PROCESS,
1294 .update_every = 0,
1295 .suffix = NETDATA_SYSCALL_APPS_TASK_THREAD,
1296 .dimension = "calls"};
1297
1298 static ebpf_systemd_args_t task_exit = {
1299 .title = "Tasks starts exit process.",
1300 .units = EBPF_COMMON_UNITS_CALLS_PER_SEC,
1301 .family = NETDATA_APPS_PROCESS_GROUP,
1302 .charttype = NETDATA_EBPF_CHART_TYPE_STACKED,
1303 .order = 20067,
1304 .algorithm = EBPF_CHART_ALGORITHM_INCREMENTAL,
1305 .context = NETDATA_SYSTEMD_PROCESS_EXIT_CONTEXT,
1306 .module = NETDATA_EBPF_MODULE_NAME_PROCESS,
1307 .update_every = 0,
1308 .suffix = NETDATA_SYSCALL_APPS_TASK_CLOSE,
1309 .dimension = "calls"};
1310
1311 static ebpf_systemd_args_t task_closed = {
1312 .title = "Tasks closed",
1313 .units = EBPF_COMMON_UNITS_CALLS_PER_SEC,
1314 .family = NETDATA_APPS_PROCESS_GROUP,
1315 .charttype = NETDATA_EBPF_CHART_TYPE_STACKED,
1316 .order = 20068,
1317 .algorithm = EBPF_CHART_ALGORITHM_INCREMENTAL,
1318 .context = NETDATA_SYSTEMD_PROCESS_CLOSE_CONTEXT,
1319 .module = NETDATA_EBPF_MODULE_NAME_PROCESS,
1320 .update_every = 0,
1321 .suffix = NETDATA_SYSCALL_APPS_TASK_EXIT,
1322 .dimension = "calls"};
1323
1324 static ebpf_systemd_args_t task_error = {
1325 .title = "Errors to create process or threads.",
1326 .units = EBPF_COMMON_UNITS_CALLS_PER_SEC,
1327 .family = NETDATA_APPS_PROCESS_GROUP,
1328 .charttype = NETDATA_EBPF_CHART_TYPE_STACKED,
1329 .order = 20069,
1330 .algorithm = EBPF_CHART_ALGORITHM_INCREMENTAL,
1331 .context = NETDATA_SYSTEMD_PROCESS_ERROR_CONTEXT,
1332 .module = NETDATA_EBPF_MODULE_NAME_PROCESS,
1333 .update_every = 0,
1334 .suffix = NETDATA_SYSCALL_APPS_TASK_ERROR,
1335 .dimension = "calls"};
1336
1337 ebpf_cgroup_target_t *w;
1338 netdata_run_mode_t mode = em->mode;
1339 if (!task_exit.update_every)
1340 data_process.update_every = data_thread.update_every = task_exit.update_every = task_closed.update_every =
1341 task_error.update_every = em->update_every;
1342
1343 for (w = ebpf_cgroup_pids; w; w = w->next) {
1344 if (ebpf_plugin_stop())
1345 break;
1346
1347 if (unlikely(!w->systemd || w->flags & NETDATA_EBPF_SERVICES_HAS_PROCESS_CHART))
1348 continue;
1349
1350 data_process.id = data_thread.id = task_exit.id = task_closed.id = task_error.id = w->name;
1351 ebpf_create_charts_on_systemd(&data_process);
1352
1353 ebpf_create_charts_on_systemd(&data_thread);
1354
1355 ebpf_create_charts_on_systemd(&task_exit);
1356
1357 ebpf_create_charts_on_systemd(&task_closed);
1358 if (mode < MODE_ENTRY) {
1359 ebpf_create_charts_on_systemd(&task_error);
1360 }
1361 w->flags |= NETDATA_EBPF_SERVICES_HAS_PROCESS_CHART;
1362 }
1363 }
1364
1365 /**
1366 * Send Systemd charts
1367 *
1368 * Send collected data to Netdata.
1369 *
1370 * @param em the structure with thread information
1371 */
1372 static void ebpf_send_systemd_process_charts(ebpf_module_t *em)
1373 {
1374 ebpf_cgroup_target_t *ect;
1375 for (ect = ebpf_cgroup_pids; ect; ect = ect->next) {
1376 if (ebpf_plugin_stop())
1377 break;
1378
1379 if (unlikely(!(ect->flags & NETDATA_EBPF_SERVICES_HAS_PROCESS_CHART))) {
1380 continue;
1381 }
1382
1383 ebpf_write_begin_chart(ect->name, NETDATA_SYSCALL_APPS_TASK_PROCESS, "");
1384 write_chart_dimension("calls", ect->publish_systemd_ps.create_process);
1385 ebpf_write_end_chart();
1386
1387 ebpf_write_begin_chart(ect->name, NETDATA_SYSCALL_APPS_TASK_THREAD, "");
1388 write_chart_dimension("calls", ect->publish_systemd_ps.create_thread);
1389 ebpf_write_end_chart();
1390
1391 ebpf_write_begin_chart(ect->name, NETDATA_SYSCALL_APPS_TASK_EXIT, "");
1392 write_chart_dimension("calls", ect->publish_systemd_ps.exit_call);
1393 ebpf_write_end_chart();
1394
1395 ebpf_write_begin_chart(ect->name, NETDATA_SYSCALL_APPS_TASK_CLOSE, "");
1396 write_chart_dimension("calls", ect->publish_systemd_ps.release_call);
1397 ebpf_write_end_chart();
1398
1399 if (em->mode < MODE_ENTRY) {
1400 ebpf_write_begin_chart(ect->name, NETDATA_SYSCALL_APPS_TASK_ERROR, "");
1401 write_chart_dimension("calls", ect->publish_systemd_ps.task_err);
1402 ebpf_write_end_chart();
1403 }
1404 }
1405 }
1406
1407 /**
1408 * Send data to Netdata calling auxiliary functions.
1409 *
1410 * @param em the structure with thread information
1411 */
1412 static void ebpf_process_send_cgroup_data(ebpf_module_t *em)
1413 {
1414 netdata_mutex_lock(&mutex_cgroup_shm);
1415 ebpf_cgroup_target_t *ect;
1416 for (ect = ebpf_cgroup_pids; ect; ect = ect->next) {
1417 ebpf_process_sum_cgroup_pids(&ect->publish_systemd_ps, ect->pids);
1418 }
1419
1420 if (ebpf_plugin_stop()) {
1421 netdata_mutex_unlock(&mutex_cgroup_shm);
1422 return;
1423 }
1424
1425 if (ebpf_cgroup_systemd_enabled_get()) {
1426 if (ebpf_send_cgroup_chart_get()) {
1427 ebpf_create_systemd_process_charts(em);
1428 }
1429
1430 ebpf_send_systemd_process_charts(em);
1431 }
1432
1433 for (ect = ebpf_cgroup_pids; ect; ect = ect->next) {
1434 if (ebpf_plugin_stop())
1435 break;
1436
1437 if (ect->systemd)
1438 continue;
1439
1440 if (!(ect->flags & NETDATA_EBPF_CGROUP_HAS_PROCESS_CHART) && ect->updated) {
1441 ebpf_create_specific_process_charts(ect->name, em);
1442 ect->flags |= NETDATA_EBPF_CGROUP_HAS_PROCESS_CHART;
1443 }
1444
1445 if (ect->flags & NETDATA_EBPF_CGROUP_HAS_PROCESS_CHART) {
1446 if (ect->updated) {
1447 ebpf_send_specific_process_data(ect->name, &ect->publish_systemd_ps, em);
1448 } else {
1449 ebpf_obsolete_specific_process_charts(ect->name, em);
1450 ect->flags &= ~NETDATA_EBPF_CGROUP_HAS_PROCESS_CHART;
1451 }
1452 }
1453 }
1454
1455 netdata_mutex_unlock(&mutex_cgroup_shm);
1456 }
1457
1458 /**
1459 * Update Cgroup algorithm
1460 *
1461 * Change algorithm from absolute to incremental
1462 */
1463 void ebpf_process_update_cgroup_algorithm()
1464 {
1465 int i;
1466 for (i = 0; i < NETDATA_KEY_PUBLISH_PROCESS_END; i++) {
1467 netdata_publish_syscall_t *ptr = &process_publish_aggregated[i];
1468 ptr->algorithm = ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX];
1469 }
1470 }
1471
1472 /**
1473 * Process Accumulator
1474 *
1475 * Sum all values read from kernel and store in the first address.
1476 *
1477 * @param out the vector with read values.
1478 * @param maps_per_core do I need to read all cores?
1479 */
1480 void ebpf_process_apps_accumulator(ebpf_process_stat_t *out, int maps_per_core)
1481 {
1482 int i, end = (maps_per_core) ? ebpf_nprocs : 1;
1483 ebpf_process_stat_t *total = &out[0];
1484 uint64_t ct = total->ct;
1485 for (i = 1; i < end; i++) {
1486 if (ebpf_plugin_stop())
1487 break;
1488
1489 ebpf_process_stat_t *w = &out[i];
1490 total->exit_call += w->exit_call;
1491 total->task_err += w->task_err;
1492 total->create_thread += w->create_thread;
1493 total->create_process += w->create_process;
1494 total->release_call += w->release_call;
1495
1496 if (w->ct > ct)
1497 ct = w->ct;
1498 }
1499 total->ct = ct;
1500 }
1501
1502 /**
1503 * Sum values for pid
1504 *
1505 * @param structure to store result.
1506 * @param root the structure with all available PIDs
1507 */
1508 void ebpf_process_sum_values_for_pids(ebpf_process_stat_t *process, struct ebpf_pid_on_target *root)
1509 {
1510 memset(process, 0, sizeof(ebpf_process_stat_t));
1511 for (; root; root = root->next) {
1512 if (ebpf_plugin_stop())
1513 break;
1514
1515 uint32_t pid = root->pid;
1516 netdata_ebpf_pid_stats_t *local_pid = netdata_ebpf_lookup_shm_pointer_unsafe(pid);
1517 if (!local_pid || !(local_pid->threads & (1U << (NETDATA_EBPF_PIDS_PROCESS_IDX << 1))))
1518 continue;
1519
1520 ebpf_publish_process_t *in = &local_pid->process;
1521
1522 process->task_err += in->task_err;
1523 process->release_call += in->release_call;
1524 process->exit_call += in->exit_call;
1525 process->create_thread += in->create_thread;
1526 process->create_process += in->create_process;
1527 }
1528 }
1529
1530 /**
1531 * Collect data for all process
1532 *
1533 * Read data from hash table and store it in appropriate vectors.
1534 * It also creates the link between targets and PIDs.
1535 *
1536 * @param tbl_pid_stats_fd The mapped file descriptor for the hash table.
1537 * @param maps_per_core do I have hash maps per core?
1538 */
1539 void collect_data_for_all_processes(int tbl_pid_stats_fd, int maps_per_core)
1540 {
1541 if (tbl_pid_stats_fd == -1)
1542 return;
1543
1544 ebpf_set_pid_map_fd(NETDATA_EBPF_PIDS_PROCESS_IDX, tbl_pid_stats_fd);
1545 size_t length = sizeof(ebpf_process_stat_t);
1546 if (maps_per_core)
1547 length *= ebpf_nprocs;
1548
1549 if (tbl_pid_stats_fd != -1) {
1550 uint32_t key = 0, next_key = 0;
1551 while (bpf_map_get_next_key(tbl_pid_stats_fd, &key, &next_key) == 0) {
1552 if (ebpf_plugin_stop())
1553 break;
1554
1555 if (bpf_map_lookup_elem(tbl_pid_stats_fd, &key, process_stat_vector)) {
1556 goto end_process_loop;
1557 }
1558
1559 ebpf_process_apps_accumulator(process_stat_vector, maps_per_core);
1560
1561 netdata_ebpf_pid_stats_t *local_pid =
1562 netdata_ebpf_get_shm_pointer_unsafe(key, NETDATA_EBPF_PIDS_PROCESS_IDX);
1563 if (!local_pid)
1564 goto end_process_loop;
1565
1566 ebpf_publish_process_t *w = &local_pid->process;
1567
1568 if (!w->ct || w->ct != process_stat_vector[0].ct) {
1569 w->ct = process_stat_vector[0].ct;
1570 w->create_thread = process_stat_vector[0].create_thread;
1571 w->exit_call = process_stat_vector[0].exit_call;
1572 w->create_process = process_stat_vector[0].create_process;
1573 w->release_call = process_stat_vector[0].release_call;
1574 w->task_err = process_stat_vector[0].task_err;
1575 } else {
1576 if (kill((pid_t)key, 0) == -1 && errno == ESRCH) {
1577 if (netdata_ebpf_reset_shm_pointer_unsafe(tbl_pid_stats_fd, key, NETDATA_EBPF_PIDS_PROCESS_IDX))
1578 memset(w, 0, sizeof(*w));
1579 }
1580 }
1581
1582 end_process_loop:
1583 memset(process_stat_vector, 0, length);
1584 key = next_key;
1585 }
1586 }
1587
1588 struct ebpf_target *w;
1589 for (w = apps_groups_root_target; w; w = w->next) {
1590 if (ebpf_plugin_stop())
1591 break;
1592
1593 if (unlikely(!(w->processes)))
1594 continue;
1595
1596 ebpf_process_sum_values_for_pids(&w->process, w->root_pid);
1597 }
1598 }
1599
1600 /**
1601 * Main loop for this collector.
1602 *
1603 * @param em the structure with thread information
1604 */
1605 static void process_collector(ebpf_module_t *em)
1606 {
1607 int publish_global = em->global_charts;
1608 int cgroups = em->cgroup_charts;
1609 netdata_mutex_lock(&ebpf_exit_cleanup);
1610 process_pid_fd = process_maps[NETDATA_PROCESS_PID_TABLE].map_fd;
1611 netdata_mutex_unlock(&ebpf_exit_cleanup);
1612 if (cgroups)
1613 ebpf_process_update_cgroup_algorithm();
1614
1615 int update_every = em->update_every;
1616 int counter = update_every - 1;
1617 int maps_per_core = em->maps_per_core;
1618 uint32_t running_time = 0;
1619 uint32_t lifetime = em->lifetime;
1620 netdata_idx_t *stats = em->hash_table_stats;
1621 memset(stats, 0, sizeof(netdata_idx_t) * NETDATA_EBPF_GLOBAL_TABLE_STATUS_END);
1622 heartbeat_t hb;
1623 heartbeat_init(&hb, USEC_PER_SEC);
1624 int process_maps_per_core = ebpf_modules[EBPF_MODULE_PROCESS_IDX].maps_per_core;
1625 while (!ebpf_plugin_stop() && running_time < lifetime) {
1626 if (ebpf_plugin_stop())
1627 break;
1628
1629 heartbeat_next(&hb);
1630
1631 if (ebpf_plugin_stop())
1632 break;
1633
1634 if (++counter == update_every) {
1635 counter = 0;
1636
1637 ebpf_read_process_hash_global_tables(stats, maps_per_core);
1638
1639 netdata_apps_integration_flags_t apps_enabled = em->apps_charts;
1640
1641 if (ebpf_all_pids_count > 0) {
1642 if (!ebpf_shm_sem_wait_or_stop(shm_mutex_ebpf_integration)) {
1643 if (errno != ECANCELED)
1644 netdata_log_error("PROCESS: Failed to wait on semaphore.");
1645 break;
1646 }
1647 netdata_mutex_lock(&collect_data_mutex);
1648 collect_data_for_all_processes(process_pid_fd, process_maps_per_core);
1649
1650 if (cgroups && ebpf_cgroup_integration_active_get()) {
1651 ebpf_update_process_cgroup();
1652 }
1653 netdata_mutex_unlock(&collect_data_mutex);
1654 if (sem_post(shm_mutex_ebpf_integration)) {
1655 netdata_log_error("PROCESS: Failed to post semaphore.");
1656 break;
1657 }
1658 }
1659
1660 // Avoid acquiring lock for data-send when shutdown is in progress;
1661 // the main thread may be holding lock for apps-parsing at this point,
1662 // which would delay this thread's join and compound the shutdown time.
1663 if (ebpf_plugin_stop())
1664 break;
1665
1666 netdata_mutex_lock(&lock);
1667
1668 if (publish_global) {
1669 ebpf_process_send_data(em);
1670 }
1671
1672 netdata_mutex_lock(&collect_data_mutex);
1673 if (apps_enabled & NETDATA_EBPF_APPS_FLAG_CHART_CREATED) {
1674 ebpf_process_send_apps_data(apps_groups_root_target, em);
1675 }
1676
1677 if (cgroups && ebpf_cgroup_integration_active_get()) {
1678 if (!ebpf_plugin_stop())
1679 ebpf_process_send_cgroup_data(em);
1680 }
1681
1682 netdata_mutex_unlock(&collect_data_mutex);
1683 netdata_mutex_unlock(&lock);
1684
1685 fflush(stdout);
1686
1687 if (ebpf_plugin_stop())
1688 break;
1689
1690 netdata_mutex_lock(&ebpf_exit_cleanup);
1691 running_time += update_every;
1692 em->running_time = running_time;
1693 netdata_mutex_unlock(&ebpf_exit_cleanup);
1694 }
1695 }
1696 }
1697
1698 /*****************************************************************
1699 *
1700 * FUNCTIONS TO START THREAD
1701 *
1702 *****************************************************************/
1703
1704 /**
1705 * Allocate vectors used with this thread.
1706 * We are not testing the return, because callocz does this and shutdown the software
1707 * case it was not possible to allocate.
1708 *
1709 * @param length is the length for the vectors used inside the collector.
1710 */
1711 static void ebpf_process_allocate_global_vectors(size_t length)
1712 {
1713 memset(process_aggregated_data, 0, length * sizeof(netdata_syscall_stat_t));
1714 memset(process_publish_aggregated, 0, length * sizeof(netdata_publish_syscall_t));
1715 process_hash_values = callocz(ebpf_nprocs, sizeof(netdata_idx_t));
1716 process_stat_vector = callocz(ebpf_nprocs, sizeof(ebpf_process_stat_t));
1717 }
1718
1719 static void change_syscalls()
1720 {
1721 static char *lfork = "do_fork";
1722 process_id_names[NETDATA_KEY_PUBLISH_PROCESS_FORK] = lfork;
1723 }
1724
1725 /**
1726 * Set local variables
1727 *
1728 */
1729 static void set_local_pointers()
1730 {
1731 if (isrh >= NETDATA_MINIMUM_RH_VERSION && isrh < NETDATA_RH_8)
1732 change_syscalls();
1733 }
1734
1735 /*****************************************************************
1736 *
1737 * EBPF PROCESS THREAD
1738 *
1739 *****************************************************************/
1740
1741 /**
1742 * Enable a single tracepoint
1743 *
1744 * Enable a tracepoint and store whether it was already enabled.
1745 *
1746 * @param event the tracepoint event name
1747 * @param was_enabled pointer to store the previous state
1748 *
1749 * @return 0 on success, -1 on error
1750 */
1751 static int ebpf_enable_single_tracepoint(const char *event, int *was_enabled)
1752 {
1753 int enabled = ebpf_is_tracepoint_enabled(tracepoint_sched_type, event);
1754 if (enabled == -1)
1755 return -1;
1756 if (!enabled) {
1757 if (ebpf_enable_tracing_values(tracepoint_sched_type, event))
1758 return -1;
1759 }
1760 *was_enabled = enabled;
1761 return 0;
1762 }
1763
1764 /**
1765 * Enable tracepoints
1766 *
1767 * Enable necessary tracepoints for thread.
1768 *
1769 * @return It returns 0 on success and -1 otherwise
1770 */
1771 static int ebpf_process_enable_tracepoints()
1772 {
1773 if (ebpf_enable_single_tracepoint(tracepoint_sched_process_exit, &was_sched_process_exit_enabled))
1774 return -1;
1775
1776 if (ebpf_enable_single_tracepoint(tracepoint_sched_process_exec, &was_sched_process_exec_enabled))
1777 return -1;
1778
1779 if (ebpf_enable_single_tracepoint(tracepoint_sched_process_fork, &was_sched_process_fork_enabled))
1780 return -1;
1781
1782 return 0;
1783 }
1784
1785 /**
1786 * Process thread
1787 *
1788 * Thread used to generate process charts.
1789 *
1790 * @param ptr a pointer to `struct ebpf_module`
1791 *
1792 * @return It always return NULL
1793 */
1794 void ebpf_process_thread(void *ptr)
1795 {
1796 ebpf_module_t *em = (ebpf_module_t *)ptr;
1797
1798 process_safe_clean = false;
1799
1800 CLEANUP_FUNCTION_REGISTER(ebpf_process_exit) cleanup_ptr = em;
1801
1802 if (!ebpf_module_thread_has_valid_state(em)) {
1803 em->global_charts = em->apps_charts = em->cgroup_charts = NETDATA_THREAD_EBPF_STOPPING;
1804 ebpf_module_enabled_set(em, NETDATA_THREAD_EBPF_STOPPING);
1805 netdata_mutex_lock(&ebpf_exit_cleanup);
1806 ebpf_update_disabled_plugin_stats(em);
1807 netdata_mutex_unlock(&ebpf_exit_cleanup);
1808 return;
1809 }
1810
1811 em->maps = process_maps;
1812
1813 netdata_mutex_lock(&ebpf_exit_cleanup);
1814 if (ebpf_process_enable_tracepoints()) {
1815 em->global_charts = em->apps_charts = em->cgroup_charts = NETDATA_THREAD_EBPF_STOPPING;
1816 ebpf_module_enabled_set(em, NETDATA_THREAD_EBPF_STOPPING);
1817 }
1818 netdata_mutex_unlock(&ebpf_exit_cleanup);
1819
1820 ebpf_process_allocate_global_vectors(NETDATA_KEY_PUBLISH_PROCESS_END);
1821 netdata_mutex_lock(&lock);
1822 ebpf_update_pid_table(&process_maps[0], em);
1823
1824 set_local_pointers();
1825 if (ebpf_process_load_bpf(em)) {
1826 em->global_charts = em->apps_charts = em->cgroup_charts = NETDATA_THREAD_EBPF_STOPPING;
1827 ebpf_module_enabled_set(em, NETDATA_THREAD_EBPF_STOPPING);
1828 } else {
1829 ebpf_mark_program_loaded();
1830 }
1831
1832 int algorithms[NETDATA_KEY_PUBLISH_PROCESS_END] = {
1833 NETDATA_EBPF_ABSOLUTE_IDX, NETDATA_EBPF_ABSOLUTE_IDX, NETDATA_EBPF_ABSOLUTE_IDX, NETDATA_EBPF_ABSOLUTE_IDX};
1834
1835 ebpf_global_labels(
1836 process_aggregated_data,
1837 process_publish_aggregated,
1838 process_dimension_names,
1839 process_id_names,
1840 algorithms,
1841 NETDATA_KEY_PUBLISH_PROCESS_END);
1842
1843 ebpf_create_global_charts(em);
1844
1845 ebpf_update_stats(&plugin_statistics, em);
1846 ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps, EBPF_ACTION_STAT_ADD);
1847
1848 netdata_mutex_unlock(&lock);
1849
1850 process_safe_clean = true;
1851 process_collector(em);
1852
1853 netdata_mutex_lock(&ebpf_exit_cleanup);
1854 ebpf_update_disabled_plugin_stats(em);
1855 netdata_mutex_unlock(&ebpf_exit_cleanup);
1856 }