master
c 1,740 lines 49.4 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include <sys/types.h>
4 #include <sys/stat.h>
5 #include <fcntl.h>
6 #include <dlfcn.h>
7 #include <sys/utsname.h>
8
9 #include "../ebpf.h"
10 #include "libnetdata/libnetdata.h"
11
12 char *ebpf_user_config_dir = CONFIG_DIR;
13 char *ebpf_stock_config_dir = LIBCONFIG_DIR;
14
15 /*
16 static int clean_kprobe_event(FILE *out, char *filename, char *father_pid, netdata_ebpf_events_t *ptr)
17 {
18 int fd = open(filename, O_WRONLY | O_APPEND, 0);
19 if (fd < 0) {
20 if (out) {
21 fprintf(out, "Cannot open %s : %s\n", filename, strerror(errno));
22 }
23 return 1;
24 }
25
26 char cmd[1024];
27 int length = snprintf(cmd, 1023, "-:kprobes/%c_netdata_%s_%s", ptr->type, ptr->name, father_pid);
28 int ret = 0;
29 if (length > 0) {
30 ssize_t written = write(fd, cmd, strlen(cmd));
31 if (written < 0) {
32 if (out) {
33 fprintf(
34 out, "Cannot remove the event (%d, %d) '%s' from %s : %s\n", getppid(), getpid(), cmd, filename,
35 strerror((int)errno));
36 }
37 ret = 1;
38 }
39 }
40
41 close(fd);
42
43 return ret;
44 }
45
46 int clean_kprobe_events(FILE *out, int pid, netdata_ebpf_events_t *ptr)
47 {
48 char filename[FILENAME_MAX + 1];
49 snprintf(filename, FILENAME_MAX, "%s%s", NETDATA_DEBUGFS, "kprobe_events");
50
51 char removeme[16];
52 snprintf(removeme, 15, "%d", pid);
53
54 int i;
55 for (i = 0; ptr[i].name; i++) {
56 if (clean_kprobe_event(out, filename, removeme, &ptr[i])) {
57 break;
58 }
59 }
60
61 return 0;
62 }
63 */
64
65 //----------------------------------------------------------------------------------------------------------------------
66
67 /**
68 * Get Kernel version
69 *
70 * Get the current kernel from /proc and returns an integer value representing it
71 *
72 * @return it returns a value representing the kernel version.
73 */
74 int ebpf_get_kernel_version()
75 {
76 char major[16], minor[16], patch[16];
77 char ver[VERSION_STRING_LEN];
78 char *version = ver;
79
80 int fd = open("/proc/sys/kernel/osrelease", O_RDONLY | O_CLOEXEC);
81 if (fd < 0)
82 return -1;
83
84 ssize_t len = read(fd, ver, sizeof(ver) - 1);
85 if (len < 0) {
86 close(fd);
87 return -1;
88 }
89
90 ver[len] = '\0';
91 close(fd);
92
93 char *move = major;
94 while (*version && *version != '.')
95 *move++ = *version++;
96 *move = '\0';
97
98 version++;
99 move = minor;
100 while (*version && *version != '.')
101 *move++ = *version++;
102 *move = '\0';
103
104 if (*version)
105 version++;
106 else
107 return -1;
108
109 move = patch;
110 while (*version && *version != '\n' && *version != '-')
111 *move++ = *version++;
112 *move = '\0';
113
114 // This new rule is fixing kernel version according the formula:
115 // KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + ((c) > 255 ? 255 : (c)))
116 // that was extracted from /usr/include/linux/version.h
117 long major_val = str2l(major);
118 long minor_val = str2l(minor);
119 if (major_val < 0 || minor_val < 0)
120 return -1;
121
122 int ipatch = (int)str2l(patch);
123 if (ipatch < 0)
124 return -1;
125
126 if (ipatch > 255)
127 ipatch = 255;
128
129 return ((int)(major_val * 65536) + (int)(minor_val * 256) + ipatch);
130 }
131
132 /**
133 * Get RH release
134 *
135 * Read Red Hat release from /etc/redhat-release
136 *
137 * @return It returns RH release on success and -1 otherwise
138 */
139 int get_redhat_release()
140 {
141 char buffer[VERSION_STRING_LEN + 1];
142 int major, minor;
143 FILE *fp = fopen("/etc/redhat-release", "r");
144
145 if (fp) {
146 major = 0;
147 minor = -1;
148 size_t length = fread(buffer, sizeof(char), VERSION_STRING_LEN, fp);
149 if (length > 4) {
150 buffer[length] = '\0';
151 char *end = strchr(buffer, '.');
152 char *start;
153 if (end) {
154 *end = '\0';
155
156 if (end > buffer) {
157 start = end - 1;
158
159 major = strtol(start, NULL, 10);
160 start = ++end;
161
162 char *minor_end = strchr(start, ' ');
163 if (minor_end) {
164 *minor_end = '\0';
165 minor = strtol(start, NULL, 10);
166 } else {
167 minor = -1;
168 }
169 }
170 }
171 }
172
173 fclose(fp);
174 return ((major * 256) + minor);
175 } else {
176 return -1;
177 }
178 }
179
180 /**
181 * Check if the kernel is in a list of rejected ones
182 *
183 * @return Returns 1 if the kernel is rejected, 0 otherwise.
184 */
185 static int kernel_is_rejected()
186 {
187 // Get kernel version from system
188 char version_string[VERSION_STRING_LEN + 1];
189 int version_string_len = 0;
190
191 if (read_txt_file("/proc/version_signature", version_string, sizeof(version_string))) {
192 if (read_txt_file("/proc/version", version_string, sizeof(version_string))) {
193 struct utsname uname_buf;
194 if (uname(&uname_buf)) {
195 collector_info("Cannot check kernel version");
196 return 0;
197 }
198 version_string_len =
199 snprintfz(version_string, VERSION_STRING_LEN, "%s %s", uname_buf.release, uname_buf.version);
200 }
201 }
202
203 if (!version_string_len)
204 version_string_len = strlen(version_string);
205
206 // Open a file with a list of rejected kernels
207 char *config_dir = getenv("NETDATA_USER_CONFIG_DIR");
208 if (config_dir == NULL) {
209 config_dir = CONFIG_DIR;
210 }
211
212 char filename[FILENAME_MAX + 1];
213 snprintfz(filename, FILENAME_MAX, "%s/ebpf.d/%s", config_dir, EBPF_KERNEL_REJECT_LIST_FILE);
214 FILE *kernel_reject_list = fopen(filename, "r");
215
216 if (!kernel_reject_list) {
217 // Keep this to have compatibility with old versions
218 snprintfz(filename, FILENAME_MAX, "%s/%s", config_dir, EBPF_KERNEL_REJECT_LIST_FILE);
219 kernel_reject_list = fopen(filename, "r");
220
221 if (!kernel_reject_list) {
222 config_dir = getenv("NETDATA_STOCK_CONFIG_DIR");
223 if (config_dir == NULL) {
224 config_dir = LIBCONFIG_DIR;
225 }
226
227 snprintfz(filename, FILENAME_MAX, "%s/ebpf.d/%s", config_dir, EBPF_KERNEL_REJECT_LIST_FILE);
228 kernel_reject_list = fopen(filename, "r");
229
230 if (!kernel_reject_list)
231 return 0;
232 }
233 }
234
235 // Find if the kernel is in the reject list
236 char *reject_string = NULL;
237 size_t buf_len = 0;
238 ssize_t reject_string_len;
239 while ((reject_string_len = getline(&reject_string, &buf_len, kernel_reject_list)) > 0) {
240 if (reject_string_len > 1) {
241 reject_string_len--;
242 if (version_string_len >= reject_string_len) {
243 if (!strncmp(version_string, reject_string, reject_string_len)) {
244 collector_info("A buggy kernel is detected");
245 fclose(kernel_reject_list);
246 freez(reject_string);
247 return 1;
248 }
249 }
250 }
251 }
252
253 fclose(kernel_reject_list);
254 freez(reject_string);
255
256 return 0;
257 }
258
259 /**
260 * Check Kernel Version
261 *
262 * Test kernel version
263 *
264 * @param version current kernel version
265 *
266 * @return It returns 1 when kernel is supported and 0 otherwise
267 */
268 int ebpf_check_kernel_version(int version)
269 {
270 if (kernel_is_rejected())
271 return 0;
272
273 // Kernel 4.11.0 or RH > 7.5
274 return (version >= NETDATA_MINIMUM_EBPF_KERNEL || get_redhat_release() >= NETDATA_MINIMUM_RH_VERSION);
275 }
276
277 /**
278 * Am I running as Root
279 *
280 * Verify the user that is running the collector.
281 *
282 * @return It returns 1 for root and 0 otherwise.
283 */
284 int is_ebpf_plugin_running_as_root()
285 {
286 uid_t uid = getuid(), euid = geteuid();
287
288 if (uid == 0 || euid == 0) {
289 return 1;
290 }
291
292 return 0;
293 }
294
295 /**
296 * Can the plugin run eBPF code
297 *
298 * This function checks kernel version and permissions.
299 *
300 * @param kver the kernel version
301 * @param name the plugin name.
302 *
303 * @return It returns 0 on success and -1 otherwise
304 */
305 int ebpf_can_plugin_load_code(int kver, char *plugin_name)
306 {
307 if (!ebpf_check_kernel_version(kver)) {
308 netdata_log_error("The current collector cannot run on this kernel.");
309 return -1;
310 }
311
312 if (!is_ebpf_plugin_running_as_root()) {
313 netdata_log_error(
314 "%s should either run as root (now running with uid %u, euid %u) or have special capabilities.",
315 plugin_name,
316 (unsigned int)getuid(),
317 (unsigned int)geteuid());
318 return -1;
319 }
320
321 return 0;
322 }
323
324 /**
325 * Adjust memory
326 *
327 * Adjust memory values to load eBPF programs.
328 *
329 * @return It returns 0 on success and -1 otherwise
330 */
331 int ebpf_adjust_memory_limit()
332 {
333 struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY};
334 if (setrlimit(RLIMIT_MEMLOCK, &r)) {
335 netdata_log_error("Setrlimit(RLIMIT_MEMLOCK)");
336 return -1;
337 }
338
339 return 0;
340 }
341
342 //----------------------------------------------------------------------------------------------------------------------
343
344 /**
345 * Kernel Name
346 *
347 * Select kernel name used by eBPF programs
348 *
349 * Netdata delivers for users eBPF programs with specific suffixes that represent the kernels they were
350 * compiled, when we load the eBPF program, the suffix must be the nereast possible of the kernel running.
351 *
352 * @param selector select the kernel version.
353 *
354 * @return It returns the string to load kernel.
355 */
356 static char *ebpf_select_kernel_name(uint32_t selector)
357 {
358 static char *kernel_names[] = {
359 NETDATA_IDX_STR_V3_10,
360 NETDATA_IDX_STR_V4_14,
361 NETDATA_IDX_STR_V4_16,
362 NETDATA_IDX_STR_V4_18,
363 NETDATA_IDX_STR_V5_4,
364 NETDATA_IDX_STR_V5_10,
365 NETDATA_IDX_STR_V5_11,
366 NETDATA_IDX_STR_V5_14,
367 NETDATA_IDX_STR_V5_15,
368 NETDATA_IDX_STR_V5_16,
369 NETDATA_IDX_STR_V6_8};
370
371 return kernel_names[selector];
372 }
373
374 /**
375 * Select Max Index
376 *
377 * Select last index that will be tested on host.
378 *
379 * @param is_rhf is Red Hat fammily?
380 * @param kver the kernel version
381 *
382 * @return it returns the index to access kernel string.
383 */
384 static int ebpf_select_max_index(int is_rhf, uint32_t kver)
385 {
386 if (is_rhf > 0) { // Is Red Hat family
387 if (kver >= NETDATA_EBPF_KERNEL_5_14)
388 return NETDATA_IDX_V5_14;
389 else if (kver >= NETDATA_EBPF_KERNEL_5_4 && kver < NETDATA_EBPF_KERNEL_5_5) // For Oracle Linux
390 return NETDATA_IDX_V5_4;
391 else if (kver >= NETDATA_EBPF_KERNEL_4_11)
392 return NETDATA_IDX_V4_18;
393 } else { // Kernels from kernel.org
394 if (kver >= NETDATA_EBPF_KERNEL_6_8)
395 return NETDATA_IDX_V6_8;
396 else if (kver >= NETDATA_EBPF_KERNEL_5_16)
397 return NETDATA_IDX_V5_16;
398 else if (kver >= NETDATA_EBPF_KERNEL_5_15)
399 return NETDATA_IDX_V5_15;
400 else if (kver >= NETDATA_EBPF_KERNEL_5_11)
401 return NETDATA_IDX_V5_11;
402 else if (kver >= NETDATA_EBPF_KERNEL_5_10)
403 return NETDATA_IDX_V5_10;
404 else if (kver >= NETDATA_EBPF_KERNEL_4_17)
405 return NETDATA_IDX_V5_4;
406 else if (kver >= NETDATA_EBPF_KERNEL_4_15)
407 return NETDATA_IDX_V4_16;
408 else if (kver >= NETDATA_EBPF_KERNEL_4_11)
409 return NETDATA_IDX_V4_14;
410 }
411
412 return NETDATA_IDX_V3_10;
413 }
414
415 /**
416 * Select Index
417 *
418 * Select index to load data.
419 *
420 * @param kernels is the variable with kernel versions.
421 * @param is_rhf is Red Hat fammily?
422 * param kver the kernel version
423 */
424 static uint32_t ebpf_select_index(uint32_t kernels, int is_rhf, uint32_t kver)
425 {
426 uint32_t start = ebpf_select_max_index(is_rhf, kver);
427 uint32_t idx;
428
429 if (is_rhf == -1)
430 kernels &= ~NETDATA_V5_14;
431
432 for (idx = start; idx; idx--) {
433 if (kernels & 1 << idx)
434 break;
435 }
436
437 return idx;
438 }
439
440 /**
441 * Mount Name
442 *
443 * Mount name of eBPF program to be loaded.
444 *
445 * Netdata eBPF programs has the following format:
446 *
447 * Tnetdata_ebpf_N.V.o
448 *
449 * where:
450 * T - Is the eBPF type. When starts with 'p', this means we are only adding probes,
451 * and when they start with 'r' we are using retprobes.
452 * N - The eBPF program name.
453 * V - The kernel version in string format.
454 *
455 * @param out the vector where the name will be stored
456 * @param len the size of the out vector.
457 * @param path where the binaries are stored
458 * @param kver the kernel version
459 * @param name the eBPF program name.
460 * @param is_return is return or entry ?
461 */
462 static void
463 ebpf_mount_name(char *out, size_t len, char *path, uint32_t kver, const char *name, int is_return, int is_rhf)
464 {
465 char *version = ebpf_select_kernel_name(kver);
466 snprintfz(
467 out,
468 len,
469 "%s/ebpf.d/%cnetdata_ebpf_%s.%s%s.o",
470 path,
471 (is_return) ? 'r' : 'p',
472 name,
473 version,
474 (is_rhf != -1) ? ".rhf" : "");
475 }
476
477 //----------------------------------------------------------------------------------------------------------------------
478
479 /**
480 * Statistics from targets
481 *
482 * Count the information from targets.
483 *
484 * @param report the output structure
485 * @param targets vector with information about the eBPF plugin.
486 * @param value factor used to update calculation
487 */
488 static void ebpf_stats_targets(ebpf_plugin_stats_t *report, netdata_ebpf_targets_t *targets, int value)
489 {
490 if (!targets) {
491 report->probes = report->tracepoints = report->trampolines = 0;
492 return;
493 }
494
495 int i = 0;
496 while (targets[i].name) {
497 switch (targets[i].mode) {
498 case EBPF_LOAD_PROBE: {
499 report->probes += value;
500 break;
501 }
502 case EBPF_LOAD_RETPROBE: {
503 report->retprobes += value;
504 break;
505 }
506 case EBPF_LOAD_TRACEPOINT: {
507 report->tracepoints += value;
508 break;
509 }
510 case EBPF_LOAD_TRAMPOLINE: {
511 report->trampolines += value;
512 break;
513 }
514 }
515
516 i++;
517 }
518 }
519
520 /**
521 * Update General stats
522 *
523 * Update eBPF plugin statistics that has relationship with the thread.
524 *
525 * This function must be called with mutex associated to charts is locked.
526 *
527 * @param report the output structure
528 * @param em the structure with information about how the module/thread is working.
529 */
530 void ebpf_update_stats(ebpf_plugin_stats_t *report, ebpf_module_t *em)
531 {
532 int value;
533
534 // It is not necessary to report more information.
535 if (ebpf_module_enabled_get(em) > NETDATA_THREAD_EBPF_FUNCTION_RUNNING)
536 value = -1;
537 else
538 value = 1;
539
540 report->threads += value;
541 report->running += value;
542
543 // In theory the `else if` is useless, because when this function is called, the module should not stay in
544 // EBPF_LOAD_PLAY_DICE. We have this additional condition to detect errors from developers.
545 if (em->load & EBPF_LOAD_LEGACY)
546 report->legacy += value;
547 else if (em->load & EBPF_LOAD_CORE)
548 report->core += value;
549
550 if (em->maps_per_core)
551 report->hash_percpu += value;
552 else
553 report->hash_unique += value;
554
555 ebpf_stats_targets(report, em->targets, value);
556 }
557
558 /**
559 * Update Kernel memory with memory
560 *
561 * This algorithm is an adaptation of https://elixir.bootlin.com/linux/v6.1.14/source/tools/bpf/bpftool/common.c#L402
562 * to get 'memlock' data and update report.
563 *
564 * @param report the output structure
565 * @param map pointer to a map.
566 * @param action What action will be done with this map.
567 */
568 void ebpf_update_kernel_memory(ebpf_plugin_stats_t *report, ebpf_local_maps_t *map, ebpf_stats_action_t action)
569 {
570 char filename[FILENAME_MAX + 1];
571 snprintfz(filename, FILENAME_MAX, "/proc/self/fdinfo/%d", map->map_fd);
572 procfile *ff = procfile_open(filename, " \t", PROCFILE_FLAG_DEFAULT);
573 if (unlikely(!ff)) {
574 netdata_log_error("Cannot open %s", filename);
575 return;
576 }
577
578 ff = procfile_readall(ff);
579 if (unlikely(!ff))
580 return;
581
582 unsigned long j, lines = procfile_lines(ff);
583 char *memlock = "memlock";
584 for (j = 0; j < lines; j++) {
585 char *cmp = procfile_lineword(ff, j, 0);
586 if (!strncmp(memlock, cmp, 7)) {
587 uint64_t memsize = (uint64_t)str2l(procfile_lineword(ff, j, 1));
588 switch (action) {
589 case EBPF_ACTION_STAT_ADD: {
590 report->memlock_kern += memsize;
591 report->hash_tables += 1;
592 #ifdef NETDATA_DEV_MODE
593 collector_info(
594 "Hash table %u: %s (FD = %d) is consuming %lu bytes totalizing %lu bytes",
595 report->hash_tables,
596 map->name,
597 map->map_fd,
598 memsize,
599 report->memlock_kern);
600 #endif
601 break;
602 }
603 case EBPF_ACTION_STAT_REMOVE: {
604 report->memlock_kern -= memsize;
605 report->hash_tables -= 1;
606 #ifdef NETDATA_DEV_MODE
607 collector_info(
608 "Hash table %s (FD = %d) was removed releasing %lu bytes, now we have %u tables loaded totalizing %lu bytes.",
609 map->name,
610 map->map_fd,
611 memsize,
612 report->hash_tables,
613 report->memlock_kern);
614 #endif
615 break;
616 }
617 default: {
618 break;
619 }
620 }
621 break;
622 }
623 }
624
625 procfile_close(ff);
626 }
627
628 /**
629 * Update Kernel memory with memory
630 *
631 * This algorithm is an adaptation of https://elixir.bootlin.com/linux/v6.1.14/source/tools/bpf/bpftool/common.c#L402
632 * to get 'memlock' data and update report.
633 *
634 * @param report the output structure
635 * @param map pointer to a map. Last map must fish with name = NULL
636 * @param action should plugin add or remove values from amount.
637 */
638 void ebpf_update_kernel_memory_with_vector(
639 ebpf_plugin_stats_t *report,
640 ebpf_local_maps_t *maps,
641 ebpf_stats_action_t action)
642 {
643 if (!maps)
644 return;
645
646 ebpf_local_maps_t *map;
647 int i = 0;
648 for (map = &maps[i]; maps[i].name; i++, map = &maps[i]) {
649 int fd = map->map_fd;
650 if (fd == ND_EBPF_MAP_FD_NOT_INITIALIZED)
651 continue;
652
653 ebpf_update_kernel_memory(report, map, action);
654 }
655 }
656
657 //----------------------------------------------------------------------------------------------------------------------
658
659 void ebpf_update_pid_table(ebpf_local_maps_t *pid, ebpf_module_t *em)
660 {
661 pid->user_input = em->pid_map_size;
662 }
663
664 /**
665 * Update map size
666 *
667 * Update map size with information read from configuration files.
668 *
669 * @param map the structure with file descriptor to update.
670 * @param lmap the structure with information from configuration files.
671 * @param em the structure with information about how the module/thread is working.
672 * @param map_name the name of the file used to log.
673 */
674 void ebpf_update_map_size(
675 struct bpf_map *map,
676 ebpf_local_maps_t *lmap,
677 ebpf_module_t *em,
678 const char *map_name __maybe_unused)
679 {
680 uint32_t define_size = 0;
681 uint32_t apps_type = NETDATA_EBPF_MAP_PID | NETDATA_EBPF_MAP_RESIZABLE;
682 if (lmap->user_input && lmap->user_input != lmap->internal_input) {
683 define_size = lmap->internal_input;
684 #ifdef NETDATA_INTERNAL_CHECKS
685 collector_info("Changing map %s from size %u to %u ", map_name, lmap->internal_input, lmap->user_input);
686 #endif
687 } else if (((lmap->type & apps_type) == apps_type) && (!em->apps_charts) && (!em->cgroup_charts)) {
688 lmap->user_input = ND_EBPF_DEFAULT_MIN_PID;
689 } else if (((em->apps_charts) || (em->cgroup_charts)) && (em->apps_level != NETDATA_APPS_NOT_SET)) {
690 switch (em->apps_level) {
691 case NETDATA_APPS_LEVEL_ALL: {
692 define_size = lmap->user_input;
693 break;
694 }
695 case NETDATA_APPS_LEVEL_PARENT: {
696 define_size = ND_EBPF_DEFAULT_PID_SIZE / 2;
697 break;
698 }
699 case NETDATA_APPS_LEVEL_REAL_PARENT:
700 default: {
701 define_size = ND_EBPF_DEFAULT_PID_SIZE / 3;
702 }
703 }
704 }
705
706 if (!define_size)
707 return;
708
709 #ifdef LIBBPF_MAJOR_VERSION
710 bpf_map__set_max_entries(map, define_size);
711 #else
712 bpf_map__resize(map, define_size);
713 #endif
714 }
715
716 #ifdef LIBBPF_MAJOR_VERSION
717 /**
718 * Update map type
719 *
720 * Update map type with information given.
721 *
722 * @param map the map we want to modify
723 * @param w a structure with user input
724 */
725 void ebpf_update_map_type(struct bpf_map *map, ebpf_local_maps_t *w)
726 {
727 if (bpf_map__set_type(map, w->map_type)) {
728 netdata_log_error("Cannot modify map type for %s", w->name);
729 }
730 }
731
732 /**
733 * Define map type
734 *
735 * This PR defines the type used by hash tables according user input.
736 *
737 * @param maps the list of maps used with a hash table.
738 * @param maps_per_core define if map type according user specification.
739 * @param kver kernel version host is running.
740 */
741 void ebpf_define_map_type(ebpf_local_maps_t *maps, int maps_per_core, int kver)
742 {
743 if (!maps)
744 return;
745
746 // Before kernel 4.06 there was not percpu hash tables
747 if (kver < NETDATA_EBPF_KERNEL_4_06)
748 maps_per_core = CONFIG_BOOLEAN_NO;
749
750 int i = 0;
751 while (maps[i].name) {
752 ebpf_local_maps_t *map = &maps[i];
753 // maps_per_core is a boolean value in configuration files.
754 if (maps_per_core) {
755 if (map->map_type == BPF_MAP_TYPE_HASH)
756 map->map_type = BPF_MAP_TYPE_PERCPU_HASH;
757 else if (map->map_type == BPF_MAP_TYPE_ARRAY)
758 map->map_type = BPF_MAP_TYPE_PERCPU_ARRAY;
759 } else {
760 if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH)
761 map->map_type = BPF_MAP_TYPE_HASH;
762 else if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY)
763 map->map_type = BPF_MAP_TYPE_ARRAY;
764 }
765
766 i++;
767 }
768 }
769 #endif
770
771 /**
772 * Update Legacy map
773 *
774 * Update map for eBPF legacy code.
775 *
776 * @param program the structure with values read from binary.
777 * @param em the structure with information about how the module/thread is working.
778 */
779 static void ebpf_update_legacy_map(struct bpf_object *program, ebpf_module_t *em)
780 {
781 struct bpf_map *map;
782 ebpf_local_maps_t *maps = em->maps;
783 if (!maps)
784 return;
785
786 bpf_map__for_each(map, program)
787 {
788 const char *map_name = bpf_map__name(map);
789 int i = 0;
790 while (maps[i].name) {
791 ebpf_local_maps_t *w = &maps[i];
792
793 if (!strcmp(w->name, map_name)) {
794 // Modify size
795 if (w->type & NETDATA_EBPF_MAP_RESIZABLE) {
796 ebpf_update_map_size(map, w, em, map_name);
797 }
798
799 #ifdef LIBBPF_MAJOR_VERSION
800 ebpf_update_map_type(map, w);
801 #endif
802 }
803
804 i++;
805 }
806 }
807 }
808
809 size_t ebpf_count_programs(struct bpf_object *obj)
810 {
811 size_t tot = 0;
812 struct bpf_program *prog;
813 bpf_object__for_each_program(prog, obj)
814 {
815 tot++;
816 }
817
818 return tot;
819 }
820
821 static ebpf_specify_name_t *ebpf_find_names(ebpf_specify_name_t *names, const char *prog_name)
822 {
823 size_t i = 0;
824 while (names[i].program_name) {
825 if (!strcmp(prog_name, names[i].program_name))
826 return &names[i];
827
828 i++;
829 }
830
831 return NULL;
832 }
833
834 static struct bpf_link **ebpf_attach_programs(struct bpf_object *obj, size_t length, ebpf_specify_name_t *names)
835 {
836 struct bpf_link **links = callocz(length, sizeof(struct bpf_link *));
837 size_t i = 0;
838 struct bpf_program *prog;
839 ebpf_specify_name_t *w;
840 bpf_object__for_each_program(prog, obj)
841 {
842 if (names) {
843 const char *name = bpf_program__name(prog);
844 w = ebpf_find_names(names, name);
845 } else
846 w = NULL;
847
848 if (w) {
849 enum bpf_prog_type type = bpf_program__get_type(prog);
850 if (type == BPF_PROG_TYPE_KPROBE)
851 links[i] = bpf_program__attach_kprobe(prog, w->retprobe, w->optional);
852 } else
853 links[i] = bpf_program__attach(prog);
854
855 if (libbpf_get_error(links[i])) {
856 links[i] = NULL;
857 }
858
859 i++;
860 }
861
862 return links;
863 }
864
865 static void ebpf_update_maps(ebpf_module_t *em, struct bpf_object *obj)
866 {
867 if (!em->maps)
868 return;
869
870 ebpf_local_maps_t *maps = em->maps;
871 struct bpf_map *map;
872 bpf_map__for_each(map, obj)
873 {
874 int fd = bpf_map__fd(map);
875 if (maps) {
876 const char *map_name = bpf_map__name(map);
877 int j = 0;
878 while (maps[j].name) {
879 ebpf_local_maps_t *w = &maps[j];
880 if (w->map_fd == ND_EBPF_MAP_FD_NOT_INITIALIZED && !strcmp(map_name, w->name))
881 w->map_fd = fd;
882
883 j++;
884 }
885 }
886 }
887 }
888
889 /**
890 * Update Controller
891 *
892 * Update controller value with user input.
893 *
894 * @param fd the table file descriptor
895 * @param em structure with information about eBPF program we will load.
896 */
897 void ebpf_update_controller(int fd, ebpf_module_t *em)
898 {
899 uint32_t values[NETDATA_CONTROLLER_END] = {
900 (em->apps_charts & NETDATA_EBPF_APPS_FLAG_YES) | em->cgroup_charts, em->apps_level, 0, 0, 0, 0};
901 uint32_t key;
902 uint32_t end = NETDATA_CONTROLLER_PID_TABLE_ADD;
903
904 for (key = NETDATA_CONTROLLER_APPS_ENABLED; key < end; key++) {
905 int ret = bpf_map_update_elem(fd, &key, &values[key], BPF_ANY);
906 if (ret)
907 netdata_log_error("Add key(%u) for controller table failed.", key);
908 }
909 }
910
911 /**
912 * Update Legacy controller
913 *
914 * Update legacy controller table when eBPF program has it.
915 *
916 * @param em structure with information about eBPF program we will load.
917 * @param obj bpf object with tables.
918 */
919 static void ebpf_update_legacy_controller(ebpf_module_t *em, struct bpf_object *obj)
920 {
921 ebpf_local_maps_t *maps = em->maps;
922 if (!maps)
923 return;
924
925 struct bpf_map *map;
926 bpf_map__for_each(map, obj)
927 {
928 size_t i = 0;
929 while (maps[i].name) {
930 ebpf_local_maps_t *w = &maps[i];
931 if (w->map_fd != ND_EBPF_MAP_FD_NOT_INITIALIZED && (w->type & NETDATA_EBPF_MAP_CONTROLLER)) {
932 w->type &= ~NETDATA_EBPF_MAP_CONTROLLER;
933 w->type |= NETDATA_EBPF_MAP_CONTROLLER_UPDATED;
934
935 ebpf_update_controller(w->map_fd, em);
936 }
937 i++;
938 }
939 }
940 }
941
942 /**
943 * Load Program
944 *
945 * Load eBPF program into kernel
946 *
947 * @param plugins_dir directory where binary are stored
948 * @param em structure with information about eBPF program we will load.
949 * @param kver the kernel version according /usr/include/linux/version.h
950 * @param is_rhf is a kernel from Red Hat Family?
951 * @param obj structure where we will store object loaded.
952 *
953 * @return it returns a link for each target we associated an eBPF program.
954 */
955 struct bpf_link **ebpf_load_program(char *plugins_dir, ebpf_module_t *em, int kver, int is_rhf, struct bpf_object **obj)
956 {
957 char lpath[4096];
958
959 uint32_t idx = ebpf_select_index(em->kernels, is_rhf, kver);
960
961 ebpf_mount_name(lpath, 4095, plugins_dir, idx, em->info.thread_name, em->mode, is_rhf);
962
963 // When this function is called ebpf.plugin is using legacy code, so we should reset the variable
964 em->load &= ~NETDATA_EBPF_LOAD_METHODS;
965 em->load |= EBPF_LOAD_LEGACY;
966
967 *obj = bpf_object__open_file(lpath, NULL);
968 if (!*obj) {
969 *obj = NULL;
970 return NULL;
971 }
972
973 if (libbpf_get_error(*obj)) {
974 bpf_object__close(*obj);
975 *obj = NULL;
976 return NULL;
977 }
978
979 ebpf_update_legacy_map(*obj, em);
980
981 if (bpf_object__load(*obj)) {
982 netdata_log_error("ERROR: loading BPF object file failed %s\n", lpath);
983 bpf_object__close(*obj);
984 *obj = NULL;
985 return NULL;
986 }
987
988 ebpf_update_maps(em, *obj);
989 ebpf_update_legacy_controller(em, *obj);
990
991 size_t count_programs = ebpf_count_programs(*obj);
992
993 #ifdef NETDATA_INTERNAL_CHECKS
994 collector_info("eBPF program %s loaded with success!", lpath);
995 #endif
996
997 return ebpf_attach_programs(*obj, count_programs, em->names);
998 }
999
1000 char *ebpf_find_symbol(char *search)
1001 {
1002 char filename[FILENAME_MAX + 1];
1003 char *ret = NULL;
1004 snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, NETDATA_KALLSYMS);
1005 procfile *ff = procfile_open(filename, " \t", PROCFILE_FLAG_DEFAULT);
1006 if (unlikely(!ff)) {
1007 netdata_log_error("Cannot open %s%s", netdata_configured_host_prefix, NETDATA_KALLSYMS);
1008 return ret;
1009 }
1010
1011 ff = procfile_readall(ff);
1012 if (unlikely(!ff))
1013 return ret;
1014
1015 unsigned long i, lines = procfile_lines(ff);
1016 size_t length = strlen(search);
1017 for (i = 0; i < lines; i++) {
1018 char *cmp = procfile_lineword(ff, i, 2);
1019 if (!strncmp(search, cmp, length)) {
1020 ret = strdupz(cmp);
1021 break;
1022 }
1023 }
1024
1025 procfile_close(ff);
1026
1027 return ret;
1028 }
1029
1030 void ebpf_update_names(ebpf_specify_name_t *opt, ebpf_module_t *em)
1031 {
1032 int mode = em->mode;
1033 em->names = opt;
1034
1035 size_t i = 0;
1036 while (opt[i].program_name) {
1037 opt[i].retprobe = (mode == MODE_RETURN);
1038 opt[i].optional = ebpf_find_symbol(opt[i].function_to_attach);
1039
1040 i++;
1041 }
1042 }
1043
1044 //----------------------------------------------------------------------------------------------------------------------
1045
1046 void ebpf_mount_config_name(char *filename, size_t length, char *path, const char *config)
1047 {
1048 snprintf(filename, length, "%s/ebpf.d/%s", path, config);
1049 }
1050
1051 int ebpf_load_config(struct config *config, char *filename)
1052 {
1053 return inicfg_load(config, filename, 0, NULL);
1054 }
1055
1056 static netdata_run_mode_t ebpf_select_mode(const char *mode)
1057 {
1058 if (!strcasecmp(mode, EBPF_CFG_LOAD_MODE_RETURN))
1059 return MODE_RETURN;
1060 else if (!strcasecmp(mode, "dev"))
1061 return MODE_DEVMODE;
1062
1063 return MODE_ENTRY;
1064 }
1065
1066 static void ebpf_select_mode_string(char *output, size_t len, netdata_run_mode_t sel)
1067 {
1068 if (sel == MODE_RETURN)
1069 strncpyz(output, EBPF_CFG_LOAD_MODE_RETURN, len);
1070 else
1071 strncpyz(output, EBPF_CFG_LOAD_MODE_DEFAULT, len);
1072 }
1073
1074 /**
1075 * Convert string to load mode
1076 *
1077 * Convert the string given as argument to value present in enum.
1078 *
1079 * @param str value read from configuration file.
1080 *
1081 * @return It returns the value to be used.
1082 */
1083 netdata_ebpf_load_mode_t epbf_convert_string_to_load_mode(const char *str)
1084 {
1085 if (!strcasecmp(str, EBPF_CFG_CORE_PROGRAM))
1086 return EBPF_LOAD_CORE;
1087 else if (!strcasecmp(str, EBPF_CFG_LEGACY_PROGRAM))
1088 return EBPF_LOAD_LEGACY;
1089
1090 return EBPF_LOAD_PLAY_DICE;
1091 }
1092
1093 /**
1094 * Convert load mode to string
1095 *
1096 * @param mode value that will select the string
1097 *
1098 * @return It returns the string associated to mode.
1099 */
1100 static char *ebpf_convert_load_mode_to_string(netdata_ebpf_load_mode_t mode)
1101 {
1102 if (mode & EBPF_LOAD_CORE)
1103 return EBPF_CFG_CORE_PROGRAM;
1104 else if (mode & EBPF_LOAD_LEGACY)
1105 return EBPF_CFG_LEGACY_PROGRAM;
1106
1107 return EBPF_CFG_DEFAULT_PROGRAM;
1108 }
1109
1110 /**
1111 * Convert collect pid to string
1112 *
1113 * @param level value that will select the string
1114 *
1115 * @return It returns the string associated to level.
1116 */
1117 static char *ebpf_convert_collect_pid_to_string(netdata_apps_level_t level)
1118 {
1119 if (level == NETDATA_APPS_LEVEL_REAL_PARENT)
1120 return EBPF_CFG_PID_REAL_PARENT;
1121 else if (level == NETDATA_APPS_LEVEL_PARENT)
1122 return EBPF_CFG_PID_PARENT;
1123 else if (level == NETDATA_APPS_LEVEL_ALL)
1124 return EBPF_CFG_PID_ALL;
1125
1126 return EBPF_CFG_PID_INTERNAL_USAGE;
1127 }
1128
1129 /**
1130 * Convert string to apps level
1131 *
1132 * @param str the argument read from config files
1133 *
1134 * @return it returns the level associated to the string or default when it is a wrong value
1135 */
1136 netdata_apps_level_t ebpf_convert_string_to_apps_level(const char *str)
1137 {
1138 if (!strcasecmp(str, EBPF_CFG_PID_REAL_PARENT))
1139 return NETDATA_APPS_LEVEL_REAL_PARENT;
1140 else if (!strcasecmp(str, EBPF_CFG_PID_PARENT))
1141 return NETDATA_APPS_LEVEL_PARENT;
1142 else if (!strcasecmp(str, EBPF_CFG_PID_ALL))
1143 return NETDATA_APPS_LEVEL_ALL;
1144
1145 return NETDATA_APPS_NOT_SET;
1146 }
1147
1148 /**
1149 * CO-RE type
1150 *
1151 * Select the preferential type of CO-RE
1152 *
1153 * @param str value read from configuration file.
1154 * @param lmode load mode used by collector.
1155 */
1156 netdata_ebpf_program_loaded_t ebpf_convert_core_type(const char *str, netdata_run_mode_t lmode)
1157 {
1158 if (!strcasecmp(str, EBPF_CFG_ATTACH_TRACEPOINT))
1159 return EBPF_LOAD_TRACEPOINT;
1160 else if (!strcasecmp(str, EBPF_CFG_ATTACH_PROBE)) {
1161 return (lmode == MODE_ENTRY) ? EBPF_LOAD_PROBE : EBPF_LOAD_RETPROBE;
1162 }
1163
1164 return EBPF_LOAD_TRAMPOLINE;
1165 }
1166
1167 #ifdef LIBBPF_MAJOR_VERSION
1168 /**
1169 * Adjust Thread Load
1170 *
1171 * Adjust thread configuration according specified load.
1172 *
1173 * @param mod the main structure that will be adjusted.
1174 * @param file the btf file used with thread.
1175 */
1176 void ebpf_adjust_thread_load(ebpf_module_t *mod, struct btf *file)
1177 {
1178 if (!file) {
1179 mod->load &= ~EBPF_LOAD_CORE;
1180 mod->load |= EBPF_LOAD_LEGACY;
1181 } else if (mod->load == EBPF_LOAD_PLAY_DICE && file) {
1182 mod->load &= ~EBPF_LOAD_LEGACY;
1183 mod->load |= EBPF_LOAD_CORE;
1184 }
1185 }
1186
1187 /**
1188 * Parse BTF file
1189 *
1190 * Parse a specific BTF file present on filesystem
1191 *
1192 * @param filename the file that will be parsed.
1193 *
1194 * @return It returns a pointer for the file on success and NULL otherwise.
1195 */
1196 struct btf *ebpf_parse_btf_file(const char *filename)
1197 {
1198 struct btf *bf = btf__parse(filename, NULL);
1199 if (libbpf_get_error(bf)) {
1200 fprintf(stderr, "Cannot parse btf file");
1201 btf__free(bf);
1202 return NULL;
1203 }
1204
1205 return bf;
1206 }
1207
1208 /**
1209 * Load default btf file
1210 *
1211 * Load the default BTF file on environment.
1212 *
1213 * @param path is the fullpath
1214 * @param filename is the file inside BTF path.
1215 */
1216 struct btf *ebpf_load_btf_file(const char *path, const char *filename)
1217 {
1218 char fullpath[PATH_MAX + 1];
1219 snprintfz(fullpath, PATH_MAX, "%s/%s", path, filename);
1220 struct btf *ret = ebpf_parse_btf_file(fullpath);
1221 if (!ret)
1222 collector_info(
1223 "Your environment does not have BTF file %s/%s. The plugin will work with 'legacy' code.", path, filename);
1224
1225 return ret;
1226 }
1227
1228 /**
1229 * Find BTF attach type
1230 *
1231 * Search type fr current btf file.
1232 *
1233 * @param file is the structure for the btf file already parsed.
1234 */
1235 static inline const struct btf_type *ebpf_find_btf_attach_type(struct btf *file)
1236 {
1237 int id = btf__find_by_name_kind(file, "bpf_attach_type", BTF_KIND_ENUM);
1238 if (id < 0) {
1239 fprintf(stderr, "Cannot find 'bpf_attach_type'");
1240
1241 return NULL;
1242 }
1243
1244 return btf__type_by_id(file, id);
1245 }
1246
1247 /**
1248 * Is function inside BTF
1249 *
1250 * Look for a specific function inside the given BTF file.
1251 *
1252 * @param file is the structure for the btf file already parsed.
1253 * @param function is the function that we want to find.
1254 */
1255 int ebpf_is_function_inside_btf(struct btf *file, char *function)
1256 {
1257 const struct btf_type *type = ebpf_find_btf_attach_type(file);
1258 if (!type)
1259 return -1;
1260
1261 const struct btf_enum *e = btf_enum(type);
1262 int i, id;
1263 for (id = -1, i = 0; i < btf_vlen(type); i++, e++) {
1264 if (!strcmp(btf__name_by_offset(file, e->name_off), "BPF_TRACE_FENTRY")) {
1265 id = btf__find_by_name_kind(file, function, BTF_KIND_FUNC);
1266 break;
1267 }
1268 }
1269
1270 return (id > 0) ? 1 : 0;
1271 }
1272 #endif
1273
1274 /**
1275 * Update target with configuration
1276 *
1277 * Update target load mode with value.
1278 *
1279 * @param em the module structure
1280 * @param value value used to update.
1281 */
1282 static void ebpf_update_target_with_conf(ebpf_module_t *em, netdata_ebpf_program_loaded_t value)
1283 {
1284 netdata_ebpf_targets_t *targets = em->targets;
1285 if (!targets) {
1286 return;
1287 }
1288
1289 int i = 0;
1290 while (targets[i].name) {
1291 targets[i].mode = value;
1292 i++;
1293 }
1294 }
1295
1296 /**
1297 * Select Load Mode
1298 *
1299 * Select the load mode according the given inputs.
1300 *
1301 * @param btf_file a pointer to the loaded btf file.
1302 * @parma load current value.
1303 * @param btf_file a pointer to the loaded btf file.
1304 * @param is_rhf is Red Hat family?
1305 *
1306 * @return it returns the new load mode.
1307 */
1308 static netdata_ebpf_load_mode_t ebpf_select_load_mode(
1309 struct btf *btf_file __maybe_unused,
1310 netdata_ebpf_load_mode_t load,
1311 int kver __maybe_unused,
1312 int is_rh __maybe_unused)
1313 {
1314 #ifdef LIBBPF_MAJOR_VERSION
1315 if ((load & EBPF_LOAD_CORE) || (load & EBPF_LOAD_PLAY_DICE)) {
1316 // Quick fix for Oracle linux 8.x
1317 load = (!btf_file || (is_rh && (kver >= NETDATA_EBPF_KERNEL_5_4 && kver < NETDATA_EBPF_KERNEL_5_5))) ?
1318 EBPF_LOAD_LEGACY :
1319 EBPF_LOAD_CORE;
1320 }
1321 #else
1322 load = EBPF_LOAD_LEGACY;
1323 #endif
1324
1325 return load;
1326 }
1327
1328 /**
1329 * Update Module using config
1330 *
1331 * Update configuration for a specific thread.
1332 *
1333 * @param modules structure that will be updated
1334 * @param origin specify the configuration file loaded
1335 * @param btf_file a pointer to the loaded btf file.
1336 * @param is_rhf is Red Hat family?
1337 */
1338 void ebpf_update_module_using_config(
1339 ebpf_module_t *modules,
1340 netdata_ebpf_load_mode_t origin,
1341 struct btf *btf_file,
1342 int kver,
1343 int is_rh)
1344 {
1345 char default_value[EBPF_MAX_MODE_LENGTH + 1];
1346 ebpf_select_mode_string(default_value, EBPF_MAX_MODE_LENGTH, modules->mode);
1347 const char *load_mode = inicfg_get(modules->cfg, EBPF_GLOBAL_SECTION, EBPF_CFG_LOAD_MODE, default_value);
1348 modules->mode = ebpf_select_mode(load_mode);
1349
1350 modules->update_every =
1351 (int)inicfg_get_number(modules->cfg, EBPF_GLOBAL_SECTION, EBPF_CFG_UPDATE_EVERY, modules->update_every);
1352
1353 modules->apps_charts = inicfg_get_boolean(
1354 modules->cfg,
1355 EBPF_GLOBAL_SECTION,
1356 EBPF_CFG_APPLICATION,
1357 (int)(modules->apps_charts & NETDATA_EBPF_APPS_FLAG_YES));
1358
1359 modules->cgroup_charts =
1360 inicfg_get_boolean(modules->cfg, EBPF_GLOBAL_SECTION, EBPF_CFG_CGROUP, modules->cgroup_charts);
1361
1362 modules->pid_map_size =
1363 (uint32_t)inicfg_get_number(modules->cfg, EBPF_GLOBAL_SECTION, EBPF_CFG_PID_SIZE, modules->pid_map_size);
1364
1365 modules->lifetime =
1366 (uint32_t)inicfg_get_number(modules->cfg, EBPF_GLOBAL_SECTION, EBPF_CFG_LIFETIME, EBPF_DEFAULT_LIFETIME);
1367
1368 char *value = ebpf_convert_load_mode_to_string(modules->load & NETDATA_EBPF_LOAD_METHODS);
1369 const char *type_format = inicfg_get(modules->cfg, EBPF_GLOBAL_SECTION, EBPF_CFG_TYPE_FORMAT, value);
1370 netdata_ebpf_load_mode_t load = epbf_convert_string_to_load_mode(type_format);
1371 load = ebpf_select_load_mode(btf_file, load, kver, is_rh);
1372 modules->load = origin | load;
1373
1374 const char *core_attach =
1375 inicfg_get(modules->cfg, EBPF_GLOBAL_SECTION, EBPF_CFG_CORE_ATTACH, EBPF_CFG_ATTACH_TRAMPOLINE);
1376 netdata_ebpf_program_loaded_t fill_lm = ebpf_convert_core_type(core_attach, modules->mode);
1377 ebpf_update_target_with_conf(modules, fill_lm);
1378
1379 value = ebpf_convert_collect_pid_to_string(modules->apps_level);
1380 const char *collect_pid = inicfg_get(modules->cfg, EBPF_GLOBAL_SECTION, EBPF_CFG_COLLECT_PID, value);
1381 modules->apps_level = ebpf_convert_string_to_apps_level(collect_pid);
1382
1383 modules->maps_per_core =
1384 inicfg_get_boolean(modules->cfg, EBPF_GLOBAL_SECTION, EBPF_CFG_MAPS_PER_CORE, modules->maps_per_core);
1385 if (kver < NETDATA_EBPF_KERNEL_4_06)
1386 modules->maps_per_core = CONFIG_BOOLEAN_NO;
1387
1388 #ifdef NETDATA_DEV_MODE
1389 collector_info(
1390 "The thread %s was configured with: mode = %s; update every = %d; apps = %s; cgroup = %s; ebpf type format = %s; ebpf co-re tracing = %s; collect pid = %s; maps per core = %s, lifetime=%u",
1391 modules->info.thread_name,
1392 load_mode,
1393 modules->update_every,
1394 (modules->apps_charts) ? "enabled" : "disabled",
1395 (modules->cgroup_charts) ? "enabled" : "disabled",
1396 type_format,
1397 core_attach,
1398 collect_pid,
1399 (modules->maps_per_core) ? "enabled" : "disabled",
1400 modules->lifetime);
1401 #endif
1402 }
1403
1404 /**
1405 * Update module
1406 *
1407 * When this function is called, it will load the configuration file and after this
1408 * it updates the global information of ebpf_module.
1409 * If the module has specific configuration, this function will load it, but it will not
1410 * update the variables.
1411 *
1412 * @param em the module structure
1413 * @param btf_file a pointer to the loaded btf file.
1414 * @param is_rhf is Red Hat family?
1415 * @param kver the kernel version
1416 */
1417 void ebpf_update_module(ebpf_module_t *em, struct btf *btf_file, int kver, int is_rh)
1418 {
1419 char filename[FILENAME_MAX + 1];
1420 netdata_ebpf_load_mode_t origin;
1421
1422 ebpf_mount_config_name(filename, FILENAME_MAX, ebpf_user_config_dir, em->config_file);
1423 if (!ebpf_load_config(em->cfg, filename)) {
1424 ebpf_mount_config_name(filename, FILENAME_MAX, ebpf_stock_config_dir, em->config_file);
1425 if (!ebpf_load_config(em->cfg, filename)) {
1426 netdata_log_error("Cannot load the ebpf configuration file %s", em->config_file);
1427 return;
1428 }
1429 // If user defined data globally, we will have here EBPF_LOADED_FROM_USER, we need to consider this, to avoid
1430 // forcing users to configure thread by thread.
1431 origin =
1432 (!(em->load & NETDATA_EBPF_LOAD_SOURCE)) ? EBPF_LOADED_FROM_STOCK : em->load & NETDATA_EBPF_LOAD_SOURCE;
1433 } else
1434 origin = EBPF_LOADED_FROM_USER;
1435
1436 ebpf_update_module_using_config(em, origin, btf_file, kver, is_rh);
1437 }
1438
1439 /**
1440 * Adjust Apps Cgroup
1441 *
1442 * Apps and cgroup has internal cleanup that needs attaching tracers to release_task, to avoid overload the function
1443 * we will enable this integration by default, if and only if, we are running with trampolines.
1444 *
1445 * @param em a pointer to the main thread structure.
1446 * @param mode is the mode used with different
1447 */
1448 void ebpf_adjust_apps_cgroup(ebpf_module_t *em, netdata_ebpf_program_loaded_t mode)
1449 {
1450 if ((em->load & EBPF_LOADED_FROM_STOCK) && (em->apps_charts || em->cgroup_charts) && mode != EBPF_LOAD_TRAMPOLINE) {
1451 em->apps_charts = NETDATA_EBPF_APPS_FLAG_NO;
1452 em->cgroup_charts = 0;
1453 }
1454 }
1455
1456 //----------------------------------------------------------------------------------------------------------------------
1457
1458 /**
1459 * Load Address
1460 *
1461 * Helper used to get address from /proc/kallsym
1462 *
1463 * @param fa address structure
1464 * @param fd file descriptor loaded inside kernel. If a negative value is given
1465 * the function will load address and it won't update hash table.
1466 */
1467 void ebpf_load_addresses(ebpf_addresses_t *fa, int fd)
1468 {
1469 if (fa->addr)
1470 return;
1471
1472 procfile *ff = procfile_open("/proc/kallsyms", " \t:", PROCFILE_FLAG_DEFAULT);
1473 if (!ff)
1474 return;
1475
1476 ff = procfile_readall(ff);
1477 if (!ff)
1478 return;
1479
1480 fa->hash = simple_hash(fa->function);
1481
1482 size_t lines = procfile_lines(ff), l;
1483 for (l = 0; l < lines; l++) {
1484 char *fcnt = procfile_lineword(ff, l, 2);
1485 uint32_t hash = simple_hash(fcnt);
1486 if (fa->hash == hash && !strcmp(fcnt, fa->function)) {
1487 char *type = procfile_lineword(ff, l, 1);
1488 fa->type = type[0];
1489 // Only text symbols (T=global, t=static, W=weak global, w=weak local) are probeable
1490 if (fa->type != 'T' && fa->type != 't' && fa->type != 'W' && fa->type != 'w')
1491 continue;
1492 if (fd > 0) {
1493 char addr[128];
1494 snprintf(addr, 127, "0x%s", procfile_lineword(ff, l, 0));
1495 fa->addr = (unsigned long)strtoul(addr, NULL, 16);
1496 uint32_t key = 0;
1497 bpf_map_update_elem(fd, &key, &fa->addr, BPF_ANY);
1498 } else
1499 fa->addr = 1;
1500 break;
1501 }
1502 }
1503
1504 procfile_close(ff);
1505 }
1506
1507 //----------------------------------------------------------------------------------------------------------------------
1508
1509 /**
1510 * Fill Algorithms
1511 *
1512 * Set one unique dimension for all vector position.
1513 *
1514 * @param algorithms the output vector
1515 * @param length number of elements of algorithms vector
1516 * @param algorithm algorithm used on charts.
1517 */
1518 void ebpf_fill_algorithms(int *algorithms, size_t length, int algorithm)
1519 {
1520 size_t i;
1521 for (i = 0; i < length; i++) {
1522 algorithms[i] = algorithm;
1523 }
1524 }
1525
1526 /**
1527 * Fill Histogram dimension
1528 *
1529 * Fill the histogram dimension with the specified ranges
1530 */
1531 char **ebpf_fill_histogram_dimension(size_t maximum)
1532 {
1533 char *dimensions[] = {"us", "ms", "s"};
1534 int previous_dim = 0, current_dim = 0;
1535 uint32_t previous_level = 1000, current_level = 1000;
1536 uint32_t previous_divisor = 1, current_divisor = 1;
1537 uint32_t current = 1, previous = 0;
1538 uint32_t selector;
1539 char **out = callocz(maximum, sizeof(char *));
1540 char range[128];
1541 size_t end = maximum - 1;
1542 for (selector = 0; selector < end; selector++) {
1543 snprintf(
1544 range,
1545 127,
1546 "%u%s->%u%s",
1547 previous / previous_divisor,
1548 dimensions[previous_dim],
1549 current / current_divisor,
1550 dimensions[current_dim]);
1551 out[selector] = strdupz(range);
1552 previous = current;
1553 current <<= 1;
1554
1555 if (previous_dim != 2 && previous > previous_level) {
1556 previous_dim++;
1557
1558 previous_divisor *= 1000;
1559 previous_level *= 1000;
1560 }
1561
1562 if (current_dim != 2 && current > current_level) {
1563 current_dim++;
1564
1565 current_divisor *= 1000;
1566 current_level *= 1000;
1567 }
1568 }
1569 snprintf(range, 127, "%u%s->+Inf", previous / previous_divisor, dimensions[previous_dim]);
1570 out[selector] = strdupz(range);
1571
1572 return out;
1573 }
1574
1575 /**
1576 * Histogram dimension cleanup
1577 *
1578 * Cleanup dimensions allocated with function ebpf_fill_histogram_dimension
1579 *
1580 * @param ptr
1581 * @param length
1582 */
1583 void ebpf_histogram_dimension_cleanup(char **ptr, size_t length)
1584 {
1585 size_t i;
1586 for (i = 0; i < length; i++) {
1587 freez(ptr[i]);
1588 }
1589 freez(ptr);
1590 }
1591
1592 //----------------------------------------------------------------------------------------------------------------------
1593
1594 /**
1595 * Open tracepoint path
1596 *
1597 * @param filename pointer to store the path
1598 * @param length file length
1599 * @param subsys is the name of your subsystem.
1600 * @param eventname is the name of the event to trace.
1601 * @param flags flags used with syscall open
1602 *
1603 * @return it returns a positive value on success and a negative otherwise.
1604 */
1605 static inline int
1606 ebpf_open_tracepoint_path(char *filename, size_t length, const char *subsys, const char *eventname, int flags)
1607 {
1608 snprintfz(filename, length, "%s/events/%s/%s/enable", NETDATA_DEBUGFS, subsys, eventname);
1609 return open(filename, flags | O_CLOEXEC, 0);
1610 }
1611
1612 /**
1613 * Is tracepoint enabled
1614 *
1615 * Check whether the tracepoint is enabled.
1616 *
1617 * @param subsys is the name of your subsystem.
1618 * @param eventname is the name of the event to trace.
1619 *
1620 * @return it returns 1 when it is enabled, 0 when it is disabled and -1 on error.
1621 */
1622 int ebpf_is_tracepoint_enabled(const char *subsys, const char *eventname)
1623 {
1624 char text[FILENAME_MAX + 1];
1625 int fd = ebpf_open_tracepoint_path(text, FILENAME_MAX, subsys, eventname, O_RDONLY);
1626 if (fd < 0) {
1627 return -1;
1628 }
1629
1630 ssize_t length = read(fd, text, 1);
1631 if (length != 1) {
1632 close(fd);
1633 return -1;
1634 }
1635 close(fd);
1636
1637 return (text[0] == '1') ? CONFIG_BOOLEAN_YES : CONFIG_BOOLEAN_NO;
1638 }
1639
1640 /**
1641 * Change Tracing values
1642 *
1643 * Change value for specific tracepoint enabling or disabling it according value given.
1644 *
1645 * @param subsys is the name of your subsystem.
1646 * @param eventname is the name of the event to trace.
1647 * @param value a value to enable (1) or disable (0) a tracepoint.
1648 *
1649 * @return It returns 0 on success and -1 otherwise
1650 */
1651 static int ebpf_change_tracing_values(const char *subsys, const char *eventname, const char *value)
1652 {
1653 if (strcmp("0", value) && strcmp("1", value)) {
1654 netdata_log_error("Invalid value given to either enable or disable a tracepoint.");
1655 return -1;
1656 }
1657
1658 char filename[1024];
1659 int fd = ebpf_open_tracepoint_path(filename, 1023, subsys, eventname, O_WRONLY);
1660 if (fd < 0) {
1661 return -1;
1662 }
1663
1664 ssize_t written = write(fd, value, strlen(value));
1665 if (written < 0) {
1666 close(fd);
1667 return -1;
1668 }
1669
1670 close(fd);
1671 return 0;
1672 }
1673
1674 /**
1675 * Enable tracing values
1676 *
1677 * Enable a tracepoint on a system
1678 *
1679 * @param subsys is the name of your subsystem.
1680 * @param eventname is the name of the event to trace.
1681 *
1682 * @return It returns 0 on success and -1 otherwise
1683 */
1684 int ebpf_enable_tracing_values(const char *subsys, const char *eventname)
1685 {
1686 return ebpf_change_tracing_values(subsys, eventname, "1");
1687 }
1688
1689 /**
1690 * Disable tracing values
1691 *
1692 * Disable tracing points enabled by collector
1693 *
1694 * @param subsys is the name of your subsystem.
1695 * @param eventname is the name of the event to trace.
1696 *
1697 * @return It returns 0 on success and -1 otherwise
1698 */
1699 int ebpf_disable_tracing_values(const char *subsys, const char *eventname)
1700 {
1701 return ebpf_change_tracing_values(subsys, eventname, "0");
1702 }
1703
1704 /**
1705 * Select PC prefix
1706 *
1707 * Identify the prefix to run on PC architecture.
1708 *
1709 * @return It returns 32 or 64 according to host arch.
1710 */
1711 static uint32_t ebpf_select_pc_prefix()
1712 {
1713 #if SIZE_OF_VOID_P == 4
1714 return 32;
1715 #else
1716 return 64;
1717 #endif
1718 }
1719
1720 /**
1721 * Select Host Prefix
1722 *
1723 * Select prefix to syscall when host is running a kernel newer than 4.17.0
1724 *
1725 * @param output the vector to store data.
1726 * @param length length of output vector.
1727 * @param syscall the syscall that prefix will be attached;
1728 * @param kver the current kernel version in format MAJOR*65536 + MINOR*256 + PATCH
1729 */
1730 void ebpf_select_host_prefix(char *output, size_t length, char *syscall, int kver)
1731 {
1732 if (kver < NETDATA_EBPF_KERNEL_4_17)
1733 snprintfz(output, length, "sys_%s", syscall);
1734 else {
1735 uint32_t arch = ebpf_select_pc_prefix();
1736 // Prefix selected according https://www.kernel.org/doc/html/latest/process/adding-syscalls.html
1737 char *prefix = (arch == 32) ? "__ia32" : "__x64";
1738 snprintfz(output, length, "%s_sys_%s", prefix, syscall);
1739 }
1740 }