@cryptotaxi247 / netdata-1 / commits / 3e84239ff

Use the libbpf library for the eBPF plugin (#9490)

Vladimir Kobal committed Jul 16, 2020 at 15:10 UTC 3e84239ff64ececa6bd54bbddbc9e3d22542dfa9
21 files changed +1312 -1118
CMakeLists.txt
+30 -3
@@ -299,6 +299,30 @@ find_package(libmongoc-1.0)
299 # ${MONGOC_INCLUDE_DIRS}
300
301
302 +# -----------------------------------------------------------------------------
303 +# Detect libbpf
304 +IF(LINUX AND EXISTS "${CMAKE_SOURCE_DIR}/externaldeps/libbpf/libbpf.a")
305 + message(STATUS "libbpf library found")
306 + pkg_check_modules(ELF REQUIRED libelf)
307 + # later we use:
308 + # ${ELF_LIBRARIES}
309 + # ${ELF_CFLAGS_OTHER}
310 + # ${ELF_INCLUDE_DIRS}
311 + IF(ELF_LIBRARIES)
312 + list(APPEND NETDATA_COMMON_CFLAGS ${ELF_CFLAGS_OTHER})
313 + list(INSERT NETDATA_COMMON_LIBRARIES 0
314 + ${CMAKE_SOURCE_DIR}/externaldeps/libbpf/libbpf.a
315 + ${ELF_LIBRARIES})
316 + list(APPEND NETDATA_COMMON_INCLUDE_DIRS ${ELF_INCLUDE_DIRS})
317 + include_directories(BEFORE ${CMAKE_SOURCE_DIR}/externaldeps/libbpf/include)
318 + set(ENABLE_PLUGIN_EBPF True)
319 + ELSE(ELF_LIBRARIES)
320 + set(ENABLE_PLUGIN_EBPF False)
321 + message(STATUS "ebpf plugin: disabled (requires libelf)")
322 + ENDIF(ELF_LIBRARIES)
323 +ENDIF()
324 +
325 +
326 # -----------------------------------------------------------------------------
327 # netdata files
328
@@ -315,8 +339,6 @@ set(LIBNETDATA_FILES
339 libnetdata/clocks/clocks.h
340 libnetdata/dictionary/dictionary.c
341 libnetdata/dictionary/dictionary.h
318 - libnetdata/ebpf/ebpf.c
319 - libnetdata/ebpf/ebpf.h
342 libnetdata/eval/eval.c
343 libnetdata/eval/eval.h
344 libnetdata/inlined.h
@@ -357,6 +379,12 @@ set(LIBNETDATA_FILES
379 libnetdata/circular_buffer/circular_buffer.c
380 libnetdata/circular_buffer/circular_buffer.h)
381
382 +IF(ENABLE_PLUGIN_EBPF)
383 + list(APPEND LIBNETDATA_FILES
384 + libnetdata/ebpf/ebpf.c
385 + libnetdata/ebpf/ebpf.h)
386 +ENDIF()
387 +
388 add_library(libnetdata OBJECT ${LIBNETDATA_FILES})
389
390 set(APPS_PLUGIN_FILES
@@ -928,7 +956,6 @@ IF(LINUX)
956 SET(ENABLE_PLUGIN_APPS True)
957 SET(ENABLE_PLUGIN_PERF True)
958 SET(ENABLE_PLUGIN_SLABINFO True)
931 - SET(ENABLE_PLUGIN_EBPF True)
959
960 ELSEIF(FREEBSD)
961 add_executable(netdata config.h ${NETDATA_FILES} ${FREEBSD_PLUGIN_FILES})
Makefile.am
+11 -3
@@ -73,6 +73,8 @@ dist_noinst_DATA = \
73 packaging/bundle-dashboard.sh \
74 packaging/bundle-mosquitto.sh \
75 packaging/check-kernel-config.sh \
76 + packaging/libbpf.checksums \
77 + packaging/libbpf.version \
78 packaging/ebpf.checksums \
79 packaging/ebpf.version \
80 packaging/bundle-lws.sh \
@@ -124,6 +126,7 @@ AM_CFLAGS = \
126 $(OPTIONAL_IPMIMONITORING_CFLAGS) \
127 $(OPTIONAL_CUPS_CFLAGS) \
128 $(OPTIONAL_XENSTAT_CFLAGS) \
129 + $(OPTIONAL_BPF_CFLAGS) \
130 $(NULL)
131
132 sbin_PROGRAMS =
@@ -144,8 +147,6 @@ LIBNETDATA_FILES = \
147 libnetdata/clocks/clocks.h \
148 libnetdata/dictionary/dictionary.c \
149 libnetdata/dictionary/dictionary.h \
147 - libnetdata/ebpf/ebpf.c \
148 - libnetdata/ebpf/ebpf.h \
150 libnetdata/eval/eval.c \
151 libnetdata/eval/eval.h \
152 libnetdata/inlined.h \
@@ -185,6 +186,13 @@ LIBNETDATA_FILES = \
186 libnetdata/string/utf8.h \
187 $(NULL)
188
189 +if ENABLE_PLUGIN_EBPF
190 + LIBNETDATA_FILES += \
191 + libnetdata/ebpf/ebpf.c \
192 + libnetdata/ebpf/ebpf.h \
193 + $(NULL)
194 +endif
195 +
196 APPS_PLUGIN_FILES = \
197 collectors/apps.plugin/apps_plugin.c \
198 $(LIBNETDATA_FILES) \
@@ -665,6 +673,7 @@ endif
673
674 NETDATA_COMMON_LIBS = \
675 $(OPTIONAL_MATH_LIBS) \
676 + $(OPTIONAL_BPF_LIBS) \
677 $(OPTIONAL_ZLIB_LIBS) \
678 $(OPTIONAL_SSL_LIBS) \
679 $(OPTIONAL_UUID_LIBS) \
@@ -674,7 +683,6 @@ NETDATA_COMMON_LIBS = \
683 $(OPTIONAL_JUDY_LIBS) \
684 $(OPTIONAL_SSL_LIBS) \
685 $(OPTIONAL_JSONC_LIBS) \
677 - $(OPTIONAL_EBPF_LIBS) \
686 $(NULL)
687
688 if LINK_STATIC_JSONC
collectors/ebpf.plugin/ebpf.c
+138 -124
@@ -11,33 +11,35 @@
11 *
12 *****************************************************************/
13
14 -
14 // callback required by eval()
16 -int health_variable_lookup(const char *variable, uint32_t hash, struct rrdcalc *rc, calculated_number *result) {
17 - (void)variable;
18 - (void)hash;
19 - (void)rc;
20 - (void)result;
15 +int health_variable_lookup(const char *variable, uint32_t hash, struct rrdcalc *rc, calculated_number *result)
16 +{
17 + UNUSED(variable);
18 + UNUSED(hash);
19 + UNUSED(rc);
20 + UNUSED(result);
21 return 0;
22 };
23
24 -void send_statistics( const char *action, const char *action_result, const char *action_data) {
25 - (void) action;
26 - (void) action_result;
27 - (void) action_data;
24 +void send_statistics(const char *action, const char *action_result, const char *action_data)
25 +{
26 + UNUSED(action);
27 + UNUSED(action_result);
28 + UNUSED(action_data);
29 return;
30 }
31
32 // callbacks required by popen()
32 -void signals_block(void) {};
33 -void signals_unblock(void) {};
34 -void signals_reset(void) {};
33 +void signals_block(void){};
34 +void signals_unblock(void){};
35 +void signals_reset(void){};
36
37 // required by get_system_cpus()
38 char *netdata_configured_host_prefix = "";
39
40 // callback required by fatal()
40 -void netdata_cleanup_and_exit(int ret) {
41 +void netdata_cleanup_and_exit(int ret)
42 +{
43 exit(ret);
44 }
45
@@ -56,9 +58,11 @@ static char *ebpf_configured_log_dir = LOG_DIR;
58 int update_every = 1;
59 static int thread_finished = 0;
60 int close_ebpf_plugin = 0;
59 -struct config collector_config = { .first_section = NULL, .last_section = NULL, .mutex = NETDATA_MUTEX_INITIALIZER,
60 - .index = { .avl_tree = { .root = NULL, .compar = appconfig_section_compare },
61 - .rwlock = AVL_LOCK_INITIALIZER } };
61 +struct config collector_config = { .first_section = NULL,
62 + .last_section = NULL,
63 + .mutex = NETDATA_MUTEX_INITIALIZER,
64 + .index = { .avl_tree = { .root = NULL, .compar = appconfig_section_compare },
65 + .rwlock = AVL_LOCK_INITIALIZER } };
66
67 int running_on_kernel = 0;
68 char kernel_string[64];
@@ -106,7 +110,7 @@ ebpf_module_t ebpf_modules[] = {
110 .global_charts = 0, .apps_charts = 1, .mode = MODE_ENTRY, .probes = NULL },
111 };
112
109 -//Link with apps.plugin
113 +// Link with apps.plugin
114 pid_t *pid_index;
115 ebpf_process_stat_t *global_process_stat = NULL;
116
@@ -146,7 +150,7 @@ static void ebpf_exit(int sig)
150 {
151 close_ebpf_plugin = 1;
152
149 - //When both threads were not finished case I try to go in front this address, the collector will crash
153 + // When both threads were not finished case I try to go in front this address, the collector will crash
154 if (!thread_finished) {
155 return;
156 }
@@ -157,32 +161,32 @@ static void ebpf_exit(int sig)
161 freez(global_process_stat);
162
163 int ret = fork();
160 - if (ret < 0) //error
164 + if (ret < 0) // error
165 error("Cannot fork(), so I won't be able to clean %skprobe_events", NETDATA_DEBUGFS);
162 - else if (!ret) { //child
166 + else if (!ret) { // child
167 int i;
164 - for ( i=getdtablesize(); i>=0; --i)
168 + for (i = getdtablesize(); i >= 0; --i)
169 close(i);
170
167 - int fd = open("/dev/null",O_RDWR, 0);
171 + int fd = open("/dev/null", O_RDWR, 0);
172 if (fd != -1) {
169 - dup2 (fd, STDIN_FILENO);
170 - dup2 (fd, STDOUT_FILENO);
171 - dup2 (fd, STDERR_FILENO);
173 + dup2(fd, STDIN_FILENO);
174 + dup2(fd, STDOUT_FILENO);
175 + dup2(fd, STDERR_FILENO);
176 }
177
178 if (fd > 2)
175 - close (fd);
179 + close(fd);
180
181 int sid = setsid();
178 - if(sid >= 0) {
182 + if (sid >= 0) {
183 debug(D_EXIT, "Wait for father %d die", getpid());
184 sleep_usec(200000); //Sleep 200 miliseconds to father dies.
185 clean_loaded_events();
186 } else {
187 error("Cannot become session id leader, so I won't try to clean kprobe_events.\n");
188 }
185 - } else { //parent
189 + } else { // parent
190 exit(0);
191 }
192
@@ -195,7 +199,6 @@ static void ebpf_exit(int sig)
199 *
200 *****************************************************************/
201
198 -
202 /**
203 * Get a value from a structure.
204 *
@@ -205,10 +208,10 @@ static void ebpf_exit(int sig)
208 */
209 collected_number get_value_from_structure(char *basis, size_t offset)
210 {
208 - collected_number *value = (collected_number *)(basis + offset);
211 + collected_number *value = (collected_number *)(basis + offset);
212
210 - collected_number ret = (collected_number)llabs(*value);
211 - //this reset is necessary to avoid keep a constant value while processing is not executing a task
213 + collected_number ret = (collected_number)llabs(*value);
214 + // this reset is necessary to avoid keep a constant value while processing is not executing a task
215 *value = 0;
216
217 return ret;
@@ -222,9 +225,7 @@ collected_number get_value_from_structure(char *basis, size_t offset)
225 */
226 void write_begin_chart(char *family, char *name)
227 {
225 - printf( "BEGIN %s.%s\n"
226 - , family
227 - , name);
228 + printf("BEGIN %s.%s\n", family, name);
229 }
230
231 /**
@@ -244,7 +245,7 @@ inline void write_end_chart()
245 void write_chart_dimension(char *dim, long long value)
246 {
247 int ret = printf("SET %s = %lld\n", dim, value);
247 - (void)ret;
248 + UNUSED(ret);
249 }
250
251 /**
@@ -257,7 +258,8 @@ void write_chart_dimension(char *dim, long long value)
258 *
259 * @return It returns a variable tha maps the charts that did not have zero values.
260 */
260 -void write_count_chart(char *name, char *family, netdata_publish_syscall_t *move, uint32_t end) {
261 +void write_count_chart(char *name, char *family, netdata_publish_syscall_t *move, uint32_t end)
262 +{
263 write_begin_chart(family, name);
264
265 uint32_t i = 0;
@@ -279,7 +281,8 @@ void write_count_chart(char *name, char *family, netdata_publish_syscall_t *move
281 * @param move the pointer with the values that will be published
282 * @param end the number of values that will be written on standard output
283 */
282 -void write_err_chart(char *name, char *family, netdata_publish_syscall_t *move, int end) {
284 +void write_err_chart(char *name, char *family, netdata_publish_syscall_t *move, int end)
285 +{
286 write_begin_chart(family, name);
287
288 int i = 0;
@@ -293,7 +296,6 @@ void write_err_chart(char *name, char *family, netdata_publish_syscall_t *move,
296 write_end_chart();
297 }
298
296 -
299 /**
300 * Call the necessary functions to create a chart.
301 *
@@ -302,10 +304,11 @@ void write_err_chart(char *name, char *family, netdata_publish_syscall_t *move,
304 *
305 * @return It returns a variable tha maps the charts that did not have zero values.
306 */
305 -void write_io_chart(char *chart, char *family, char *dwrite, char *dread, netdata_publish_vfs_common_t *pvc) {
307 +void write_io_chart(char *chart, char *family, char *dwrite, char *dread, netdata_publish_vfs_common_t *pvc)
308 +{
309 write_begin_chart(family, chart);
310
308 - write_chart_dimension(dwrite, (long long) pvc->write);
311 + write_chart_dimension(dwrite, (long long)pvc->write);
312 write_chart_dimension(dread, (long long)pvc->read);
313
314 write_end_chart();
@@ -377,15 +380,15 @@ void ebpf_create_global_dimension(void *ptr, int end)
380 * @param move a pointer for a structure that has the dimensions
381 * @param end number of dimensions for the chart created
382 */
380 -void ebpf_create_chart(char *type
381 - , char *id
382 - , char *title
383 - , char *units
384 - , char *family
385 - , int order
386 - , void (*ncd)(void *, int)
387 - , void *move
388 - , int end)
383 +void ebpf_create_chart(char *type,
384 + char *id,
385 + char *title,
386 + char *units,
387 + char *family,
388 + int order,
389 + void (*ncd)(void *, int),
390 + void *move,
391 + int end)
392 {
393 ebpf_write_chart_cmd(type, id, title, units, family, "line", order);
394
@@ -407,8 +410,8 @@ void ebpf_create_charts_on_apps(char *id, char *title, char *units, char *family
410 struct target *w;
411 ebpf_write_chart_cmd(NETDATA_APPS_FAMILY, id, title, units, family, "stacked", order);
412
410 - for (w = root; w ; w = w->next) {
411 - if(unlikely(w->exposed))
413 + for (w = root; w; w = w->next) {
414 + if (unlikely(w->exposed))
415 fprintf(stdout, "DIMENSION %s '' absolute 1 1\n", w->name);
416 }
417 }
@@ -428,20 +431,21 @@ void ebpf_create_charts_on_apps(char *id, char *title, char *units, char *family
431 * @param name a pointer for the tensor with the name of the functions.
432 * @param end the number of elements in the previous 4 arguments.
433 */
431 -void ebpf_global_labels(netdata_syscall_stat_t *is, netdata_publish_syscall_t *pio, char **dim, char **name, int end) {
434 +void ebpf_global_labels(netdata_syscall_stat_t *is, netdata_publish_syscall_t *pio, char **dim, char **name, int end)
435 +{
436 int i;
437
438 netdata_syscall_stat_t *prev = NULL;
439 netdata_publish_syscall_t *publish_prev = NULL;
440 for (i = 0; i < end; i++) {
437 - if(prev) {
441 + if (prev) {
442 prev->next = &is[i];
443 }
444 prev = &is[i];
445
446 pio[i].dimension = dim[i];
447 pio[i].name = name[i];
444 - if(publish_prev) {
448 + if (publish_prev) {
449 publish_prev->next = &pio[i];
450 }
451 publish_prev = &pio[i];
@@ -453,9 +457,10 @@ void ebpf_global_labels(netdata_syscall_stat_t *is, netdata_publish_syscall_t *p
457 *
458 * @param lmode the mode that will be used for them.
459 */
456 -static inline void ebpf_set_thread_mode(netdata_run_mode_t lmode) {
457 - int i ;
458 - for (i = 0 ; ebpf_modules[i].thread_name ; i++ ) {
460 +static inline void ebpf_set_thread_mode(netdata_run_mode_t lmode)
461 +{
462 + int i;
463 + for (i = 0; ebpf_modules[i].thread_name; i++) {
464 ebpf_modules[i].mode = lmode;
465 }
466 }
@@ -466,7 +471,8 @@ static inline void ebpf_set_thread_mode(netdata_run_mode_t lmode) {
471 * @param em the structure that will be changed
472 * @param enable the status about the apps charts.
473 */
469 -static inline void ebpf_enable_specific_chart(struct ebpf_module *em, int enable) {
474 +static inline void ebpf_enable_specific_chart(struct ebpf_module *em, int enable)
475 +{
476 em->enabled = 1;
477 if (!enable) {
478 em->apps_charts = 1;
@@ -479,9 +485,10 @@ static inline void ebpf_enable_specific_chart(struct ebpf_module *em, int enabl
485 *
486 * @param apps what is the current status of apps
487 */
482 -static inline void ebpf_enable_all_charts(int apps) {
483 - int i ;
484 - for (i = 0 ; ebpf_modules[i].thread_name ; i++ ) {
488 +static inline void ebpf_enable_all_charts(int apps)
489 +{
490 + int i;
491 + for (i = 0; ebpf_modules[i].thread_name; i++) {
492 ebpf_enable_specific_chart(&ebpf_modules[i], apps);
493 }
494 }
@@ -492,9 +499,10 @@ static inline void ebpf_enable_all_charts(int apps) {
499 * @param idx the index of ebpf_modules that I am enabling
500 * @param disable_apps should I keep apps charts?
501 */
495 -static inline void ebpf_enable_chart(int idx, int disable_apps) {
496 - int i ;
497 - for (i = 0 ; ebpf_modules[i].thread_name ; i++ ) {
502 +static inline void ebpf_enable_chart(int idx, int disable_apps)
503 +{
504 + int i;
505 + for (i = 0; ebpf_modules[i].thread_name; i++) {
506 if (i == idx) {
507 ebpf_enable_specific_chart(&ebpf_modules[i], disable_apps);
508 break;
@@ -507,9 +515,10 @@ static inline void ebpf_enable_chart(int idx, int disable_apps) {
515 *
516 * Disable charts for apps loading only global charts.
517 */
510 -static inline void ebpf_disable_apps() {
511 - int i ;
512 - for (i = 0 ;ebpf_modules[i].thread_name ; i++ ) {
518 +static inline void ebpf_disable_apps()
519 +{
520 + int i;
521 + for (i = 0; ebpf_modules[i].thread_name; i++) {
522 ebpf_modules[i].apps_charts = 0;
523 }
524 }
@@ -517,7 +526,8 @@ static inline void ebpf_disable_apps() {
526 /**
527 * Print help on standard error for user knows how to use the collector.
528 */
520 -void ebpf_print_help() {
529 +void ebpf_print_help()
530 +{
531 const time_t t = time(NULL);
532 struct tm ct;
533 struct tm *test = localtime_r(&t, &ct);
@@ -553,10 +563,9 @@ void ebpf_print_help() {
563 " --process or -p Enable charts related to process run time.\n"
564 "\n"
565 " --return or -r Run the collector in return mode.\n"
556 - "\n"
557 - , VERSION
558 - , (year >= 116)?year + 1900: 2020
559 - );
566 + "\n",
567 + VERSION,
568 + (year >= 116) ? year + 1900 : 2020);
569 }
570
571 /*****************************************************************
@@ -591,18 +600,19 @@ int ebpf_start_pthread_variables()
600 */
601 static void ebpf_allocate_common_vectors()
602 {
594 - all_pids = callocz((size_t) pid_max, sizeof(struct pid_stat *));
603 + all_pids = callocz((size_t)pid_max, sizeof(struct pid_stat *));
604 pid_index = callocz((size_t)pid_max, sizeof(pid_t));
605 global_process_stat = callocz((size_t)ebpf_nprocs, sizeof(ebpf_process_stat_t));
606 }
607
608 /**
600 - * Fill the ebpf_functions structure with default values
609 + * Fill the ebpf_data structure with default values
610 *
611 * @param ef the pointer to set default values
612 */
604 -void fill_ebpf_functions(ebpf_functions_t *ef) {
605 - memset(ef, 0, sizeof(ebpf_functions_t));
613 +void fill_ebpf_data(ebpf_data_t *ef)
614 +{
615 + memset(ef, 0, sizeof(ebpf_data_t));
616 ef->kernel_string = kernel_string;
617 ef->running_on_kernel = running_on_kernel;
618 ef->map_fd = callocz(EBPF_MAX_MAPS, sizeof(int));
@@ -648,10 +658,11 @@ static inline int parse_disable_apps(char *ptr)
658 *
659 * @param disable_apps variable to store information related to apps.
660 */
651 -static void read_collector_values(int *disable_apps) {
661 +static void read_collector_values(int *disable_apps)
662 +{
663 // Read global section
664 char *value;
654 - if (appconfig_exists(&collector_config, EBPF_GLOBAL_SECTION, "load")) //Backward compatibility
665 + if (appconfig_exists(&collector_config, EBPF_GLOBAL_SECTION, "load")) // Backward compatibility
666 value = appconfig_get(&collector_config, EBPF_GLOBAL_SECTION, "load", "entry");
667 else
668 value = appconfig_get(&collector_config, EBPF_GLOBAL_SECTION, "ebpf load mode", "entry");
@@ -662,16 +673,14 @@ static void read_collector_values(int *disable_apps) {
673 *disable_apps = parse_disable_apps(value);
674
675 // Read ebpf programs section
665 - uint32_t enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION,
666 - ebpf_modules[0].config_name, 1);
676 + uint32_t enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, ebpf_modules[0].config_name, 1);
677 int started = 0;
678 if (enabled) {
679 ebpf_enable_chart(EBPF_MODULE_PROCESS_IDX, *disable_apps);
680 started++;
681 }
682
673 - enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION,
674 - ebpf_modules[1].config_name, 1);
683 + enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, ebpf_modules[1].config_name, 1);
684 if (enabled) {
685 ebpf_enable_chart(EBPF_MODULE_SOCKET_IDX, *disable_apps);
686 started++;
@@ -679,7 +688,6 @@ static void read_collector_values(int *disable_apps) {
688
689 if (!started)
690 ebpf_enable_all_charts(*disable_apps);
682 -
691 }
692
693 /**
@@ -690,10 +698,11 @@ static void read_collector_values(int *disable_apps) {
698 *
699 * @return 0 on success and -1 otherwise.
700 */
693 -static int load_collector_config(char *path, int *disable_apps) {
701 +static int load_collector_config(char *path, int *disable_apps)
702 +{
703 char lpath[4096];
704
696 - snprintf(lpath, 4095, "%s/%s", path, "ebpf.conf" );
705 + snprintf(lpath, 4095, "%s/%s", path, "ebpf.conf");
706
707 if (!appconfig_load(&collector_config, lpath, 0, NULL))
708 return -1;
@@ -706,22 +715,23 @@ static int load_collector_config(char *path, int *disable_apps) {
715 /**
716 * Set global variables reading environment variables
717 */
709 -void set_global_variables() {
710 - //Get environment variables
718 +void set_global_variables()
719 +{
720 + // Get environment variables
721 ebpf_plugin_dir = getenv("NETDATA_PLUGINS_DIR");
712 - if(!ebpf_plugin_dir)
722 + if (!ebpf_plugin_dir)
723 ebpf_plugin_dir = PLUGINS_DIR;
724
725 ebpf_user_config_dir = getenv("NETDATA_USER_CONFIG_DIR");
716 - if(!ebpf_user_config_dir)
726 + if (!ebpf_user_config_dir)
727 ebpf_user_config_dir = CONFIG_DIR;
728
729 ebpf_stock_config_dir = getenv("NETDATA_STOCK_CONFIG_DIR");
720 - if(!ebpf_stock_config_dir)
730 + if (!ebpf_stock_config_dir)
731 ebpf_stock_config_dir = LIBCONFIG_DIR;
732
733 ebpf_configured_log_dir = getenv("NETDATA_LOG_DIR");
724 - if(!ebpf_configured_log_dir)
734 + if (!ebpf_configured_log_dir)
735 ebpf_configured_log_dir = LOG_DIR;
736
737 ebpf_nprocs = (int)sysconf(_SC_NPROCESSORS_ONLN);
@@ -730,7 +740,7 @@ void set_global_variables() {
740 }
741
742 isrh = get_redhat_release();
733 - pid_max = get_system_pid_max();
743 + pid_max = get_system_pid_max();
744 }
745
746 /**
@@ -758,13 +768,13 @@ static void parse_args(int argc, char **argv)
768
769 if (argc > 1) {
770 int n = (int)str2l(argv[1]);
761 - if(n > 0) {
771 + if (n > 0) {
772 freq = n;
773 }
774 }
775
776 while (1) {
767 - int c = getopt_long(argc, argv, "hvganpr",long_options, &option_index);
777 + int c = getopt_long(argc, argv, "hvganpr", long_options, &option_index);
778 if (c == -1)
779 break;
780
@@ -781,7 +791,8 @@ static void parse_args(int argc, char **argv)
791 disable_apps = 1;
792 ebpf_disable_apps();
793 #ifdef NETDATA_INTERNAL_CHECKS
784 - info("EBPF running with global chart group, because it was started with the option \"--global\" or \"-g\".");
794 + info(
795 + "EBPF running with global chart group, because it was started with the option \"--global\" or \"-g\".");
796 #endif
797 break;
798 }
@@ -804,7 +815,8 @@ static void parse_args(int argc, char **argv)
815 enabled = 1;
816 ebpf_enable_chart(EBPF_MODULE_PROCESS_IDX, disable_apps);
817 #ifdef NETDATA_INTERNAL_CHECKS
807 - info("EBPF enabling \"PROCESS\" charts, because it was started with the option \"--process\" or \"-p\".");
818 + info(
819 + "EBPF enabling \"PROCESS\" charts, because it was started with the option \"--process\" or \"-p\".");
820 #endif
821 break;
822 }
@@ -826,8 +838,9 @@ static void parse_args(int argc, char **argv)
838 }
839
840 if (load_collector_config(ebpf_user_config_dir, &disable_apps)) {
829 - info("Does not have a configuration file inside `%s/ebpf.conf. It will try to load stock file.",
830 - ebpf_user_config_dir);
841 + info(
842 + "Does not have a configuration file inside `%s/ebpf.conf. It will try to load stock file.",
843 + ebpf_user_config_dir);
844 if (load_collector_config(ebpf_stock_config_dir, &disable_apps)) {
845 info("Does not have a stock file. It is starting with default options.");
846 } else {
@@ -847,15 +860,17 @@ static void parse_args(int argc, char **argv)
860 if (disable_apps)
861 return;
862
850 - //Load apps_groups.conf
851 - if (ebpf_read_apps_groups_conf(&apps_groups_default_target, &apps_groups_root_target,
852 - ebpf_user_config_dir, "groups") ) {
853 - info("Cannot read process groups configuration file '%s/apps_groups.conf'. Will try '%s/apps_groups.conf'",
854 - ebpf_user_config_dir, ebpf_stock_config_dir);
855 - if (ebpf_read_apps_groups_conf(&apps_groups_default_target, &apps_groups_root_target,
856 - ebpf_stock_config_dir, "groups") ) {
857 - error("Cannot read process groups '%s/apps_groups.conf'. There are no internal defaults. Failing.",
858 - ebpf_stock_config_dir);
863 + // Load apps_groups.conf
864 + if (ebpf_read_apps_groups_conf(
865 + &apps_groups_default_target, &apps_groups_root_target, ebpf_user_config_dir, "groups")) {
866 + info(
867 + "Cannot read process groups configuration file '%s/apps_groups.conf'. Will try '%s/apps_groups.conf'",
868 + ebpf_user_config_dir, ebpf_stock_config_dir);
869 + if (ebpf_read_apps_groups_conf(
870 + &apps_groups_default_target, &apps_groups_root_target, ebpf_stock_config_dir, "groups")) {
871 + error(
872 + "Cannot read process groups '%s/apps_groups.conf'. There are no internal defaults. Failing.",
873 + ebpf_stock_config_dir);
874 thread_finished++;
875 ebpf_exit(1);
876 }
@@ -863,7 +878,6 @@ static void parse_args(int argc, char **argv)
878 info("Loaded config file '%s/apps_groups.conf'", ebpf_user_config_dir);
879 }
880
866 -
881 /*****************************************************************
882 *
883 * COLLECTOR ENTRY POINT
@@ -883,30 +897,30 @@ int main(int argc, char **argv)
897 set_global_variables();
898 parse_args(argc, argv);
899
886 - running_on_kernel = get_kernel_version(kernel_string, 63);
887 - if(!has_condition_to_run(running_on_kernel)) {
900 + running_on_kernel = get_kernel_version(kernel_string, 63);
901 + if (!has_condition_to_run(running_on_kernel)) {
902 error("The current collector cannot run on this kernel.");
903 return 2;
904 }
905
892 - if(!am_i_running_as_root()) {
893 - error("ebpf.plugin should either run as root (now running with uid %u, euid %u) or have special capabilities..",
894 - (unsigned int)getuid(), (unsigned int)geteuid()
895 - );
906 + if (!am_i_running_as_root()) {
907 + error(
908 + "ebpf.plugin should either run as root (now running with uid %u, euid %u) or have special capabilities..",
909 + (unsigned int)getuid(), (unsigned int)geteuid());
910 return 3;
911 }
912
899 - //set name
913 + // set name
914 program_name = "ebpf.plugin";
915
902 - //disable syslog
916 + // disable syslog
917 error_log_syslog = 0;
918
919 // set errors flood protection to 100 logs per hour
920 error_log_errors_per_period = 100;
921 error_log_throttle_period = 3600;
922
909 - struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY};
923 + struct rlimit r = { RLIM_INFINITY, RLIM_INFINITY };
924 if (setrlimit(RLIMIT_MEMLOCK, &r)) {
925 error("Setrlimit(RLIMIT_MEMLOCK)");
926 return 4;
@@ -925,16 +939,16 @@ int main(int argc, char **argv)
939 ebpf_allocate_common_vectors();
940
941 struct netdata_static_thread ebpf_threads[] = {
928 - {"EBPF PROCESS", NULL, NULL, 1, NULL, NULL, ebpf_modules[0].start_routine},
929 - {"EBPF SOCKET", NULL, NULL, 1, NULL, NULL, ebpf_modules[1].start_routine},
930 - {NULL, NULL, NULL, 0, NULL, NULL, NULL}
942 + {"EBPF PROCESS", NULL, NULL, 1, NULL, NULL, ebpf_modules[0].start_routine},
943 + {"EBPF SOCKET" , NULL, NULL, 1, NULL, NULL, ebpf_modules[1].start_routine},
944 + {NULL , NULL, NULL, 0, NULL, NULL, NULL}
945 };
946
947 change_events();
948 clean_loaded_events();
949
950 int i;
937 - for (i = 0; ebpf_threads[i].name != NULL ; i++) {
951 + for (i = 0; ebpf_threads[i].name != NULL; i++) {
952 struct netdata_static_thread *st = &ebpf_threads[i];
953 st->thread = mallocz(sizeof(netdata_thread_t));
954
@@ -943,7 +957,7 @@ int main(int argc, char **argv)
957 netdata_thread_create(st->thread, st->name, NETDATA_THREAD_OPTION_JOINABLE, st->start_routine, em);
958 }
959
946 - for (i = 0; ebpf_threads[i].name != NULL ; i++) {
960 + for (i = 0; ebpf_threads[i].name != NULL; i++) {
961 struct netdata_static_thread *st = &ebpf_threads[i];
962 netdata_thread_join(*st->thread, NULL);
963 }
collectors/ebpf.plugin/ebpf.h
+95 -89
@@ -1,49 +1,48 @@
1 -#ifndef _NETDATA_VFS_EBPF_H_
2 -# define _NETDATA_VFS_EBPF_H_ 1
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2
4 -# include <stdint.h>
3 +#ifndef NETDATA_COLLECTOR_EBPF_H
4 +#define NETDATA_COLLECTOR_EBPF_H 1
5
6 #ifndef __FreeBSD__
7 -# include <linux/perf_event.h>
8 -# endif
9 -# include <stdint.h>
10 -# include <errno.h>
11 -# include <signal.h>
12 -# include <stdio.h>
13 -# include <stdint.h>
14 -# include <stdlib.h>
15 -# include <string.h>
16 -# include <unistd.h>
17 -# include <dlfcn.h>
18 -
19 -# include <fcntl.h>
20 -# include <ctype.h>
21 -# include <dirent.h>
22 -
23 -//From libnetdata.h
24 -# include "libnetdata/threads/threads.h"
25 -# include "libnetdata/locks/locks.h"
26 -# include "libnetdata/avl/avl.h"
27 -# include "libnetdata/clocks/clocks.h"
28 -# include "libnetdata/config/appconfig.h"
29 -# include "libnetdata/ebpf/ebpf.h"
30 -# include "libnetdata/procfile/procfile.h"
31 -# include "daemon/main.h"
32 -
33 -# include "ebpf_apps.h"
7 +#include <linux/perf_event.h>
8 +#endif
9 +#include <stdint.h>
10 +#include <errno.h>
11 +#include <signal.h>
12 +#include <stdio.h>
13 +#include <stdlib.h>
14 +#include <string.h>
15 +#include <unistd.h>
16 +#include <dlfcn.h>
17 +
18 +#include <fcntl.h>
19 +#include <ctype.h>
20 +#include <dirent.h>
21 +
22 +// From libnetdata.h
23 +#include "libnetdata/threads/threads.h"
24 +#include "libnetdata/locks/locks.h"
25 +#include "libnetdata/avl/avl.h"
26 +#include "libnetdata/clocks/clocks.h"
27 +#include "libnetdata/config/appconfig.h"
28 +#include "libnetdata/ebpf/ebpf.h"
29 +#include "libnetdata/procfile/procfile.h"
30 +#include "daemon/main.h"
31 +
32 +#include "ebpf_apps.h"
33
34 typedef enum {
36 - MODE_RETURN = 0, //This attaches kprobe when the function returns
37 - MODE_DEVMODE, //This stores log given description about the errors raised
38 - MODE_ENTRY //This attaches kprobe when the function is called
35 + MODE_RETURN = 0, // This attaches kprobe when the function returns
36 + MODE_DEVMODE, // This stores log given description about the errors raised
37 + MODE_ENTRY // This attaches kprobe when the function is called
38 } netdata_run_mode_t;
39
40 typedef struct netdata_syscall_stat {
42 - unsigned long bytes; //total number of bytes
43 - uint64_t call; //total number of calls
44 - uint64_t ecall; //number of calls that returned error
45 - struct netdata_syscall_stat *next; //Link list
46 -}netdata_syscall_stat_t;
41 + unsigned long bytes; // total number of bytes
42 + uint64_t call; // total number of calls
43 + uint64_t ecall; // number of calls that returned error
44 + struct netdata_syscall_stat *next; // Link list
45 +} netdata_syscall_stat_t;
46
47 typedef uint64_t netdata_idx_t;
48
@@ -57,7 +56,7 @@ typedef struct netdata_publish_syscall {
56 uint64_t nerr;
57 uint64_t perr;
58 struct netdata_publish_syscall *next;
60 -}netdata_publish_syscall_t;
59 +} netdata_publish_syscall_t;
60
61 typedef struct netdata_publish_vfs_common {
62 long write;
@@ -65,7 +64,7 @@ typedef struct netdata_publish_vfs_common {
64
65 long running;
66 long zombie;
68 -}netdata_publish_vfs_common_t;
67 +} netdata_publish_vfs_common_t;
68
69 typedef struct netdata_error_report {
70 char comm[16];
@@ -73,13 +72,13 @@ typedef struct netdata_error_report {
72
73 int type;
74 int err;
76 -}netdata_error_report_t;
75 +} netdata_error_report_t;
76
77 typedef struct ebpf_module {
78 const char *thread_name;
79 const char *config_name;
80 int enabled;
82 - void *(*start_routine) (void *);
81 + void *(*start_routine)(void *);
82 int update_time;
83 int global_charts;
84 int apps_charts;
@@ -93,38 +92,36 @@ extern ebpf_module_t ebpf_modules[];
92 #define EBPF_MODULE_SOCKET_IDX 1
93
94 // Copied from musl header
96 -//
95 #ifndef offsetof
98 -# if __GNUC__ > 3
99 -# define offsetof(type, member) __builtin_offsetof(type, member)
100 -# else
101 -# define offsetof(type, member) ((size_t)( (char *)&(((type *)0)->member) - (char *)0 ))
102 -# endif
96 +#if __GNUC__ > 3
97 +#define offsetof(type, member) __builtin_offsetof(type, member)
98 +#else
99 +#define offsetof(type, member) ((size_t)((char *)&(((type *)0)->member) - (char *)0))
100 +#endif
101 #endif
102
105 -//Chart defintions
106 -# define NETDATA_EBPF_FAMILY "ebpf"
107 -
108 -//Log file
109 -# define NETDATA_DEVELOPER_LOG_FILE "developer.log"
103 +// Chart defintions
104 +#define NETDATA_EBPF_FAMILY "ebpf"
105
111 -//Maximum number of processors monitored on perf events
112 -# define NETDATA_MAX_PROCESSOR 512
106 +// Log file
107 +#define NETDATA_DEVELOPER_LOG_FILE "developer.log"
108
114 -//Kernel versions calculated with the formula:
115 -// R = MAJOR*65536 + MINOR*256 + PATCH
116 -# define NETDATA_KERNEL_V5_3 328448
117 -# define NETDATA_KERNEL_V4_15 265984
109 +// Maximum number of processors monitored on perf events
110 +#define NETDATA_MAX_PROCESSOR 512
111
119 -# define EBPF_SYS_CLONE_IDX 11
120 -# define EBPF_MAX_MAPS 32
112 +// Kernel versions calculated with the formula:
113 +// R = MAJOR*65536 + MINOR*256 + PATCH
114 +#define NETDATA_KERNEL_V5_3 328448
115 +#define NETDATA_KERNEL_V4_15 265984
116
117 +#define EBPF_SYS_CLONE_IDX 11
118 +#define EBPF_MAX_MAPS 32
119
123 -//Threads
120 +// Threads
121 extern void *ebpf_process_thread(void *ptr);
122 extern void *ebpf_socket_thread(void *ptr);
123
127 -//Common variables
124 +// Common variables
125 extern pthread_mutex_t lock;
126 extern int close_ebpf_plugin;
127 extern int ebpf_nprocs;
@@ -137,29 +134,34 @@ extern netdata_ebpf_events_t socket_probes[];
134 extern pthread_mutex_t collect_data_mutex;
135 extern pthread_cond_t collect_data_cond_var;
136
140 -//Common functions
137 +// Common functions
138 extern void ebpf_global_labels(netdata_syscall_stat_t *is,
139 netdata_publish_syscall_t *pio,
140 char **dim,
141 char **name,
142 int end);
143
147 -extern void ebpf_write_chart_cmd(char *type, char *id, char *title, char *units, char *family,
148 - char *charttype, int order);
144 +extern void ebpf_write_chart_cmd(char *type,
145 + char *id,
146 + char *title,
147 + char *units,
148 + char *family,
149 + char *charttype,
150 + int order);
151
152 extern void ebpf_write_global_dimension(char *n, char *d);
153
154 extern void ebpf_create_global_dimension(void *ptr, int end);
155
154 -extern void ebpf_create_chart(char *type
155 - , char *id
156 - , char *title
157 - , char *units
158 - , char *family
159 - , int order
160 - , void (*ncd)(void *, int)
161 - , void *move
162 - , int end);
156 +extern void ebpf_create_chart(char *type,
157 + char *id,
158 + char *title,
159 + char *units,
160 + char *family,
161 + int order,
162 + void (*ncd)(void *, int),
163 + void *move,
164 + int end);
165
166 extern void write_begin_chart(char *family, char *name);
167
@@ -171,39 +173,43 @@ extern void write_err_chart(char *name, char *family, netdata_publish_syscall_t
173
174 extern void write_io_chart(char *chart, char *family, char *dwrite, char *dread, netdata_publish_vfs_common_t *pvc);
175
174 -extern void fill_ebpf_functions(ebpf_functions_t *ef);
176 +extern void fill_ebpf_data(ebpf_data_t *ef);
177
176 -extern void ebpf_create_charts_on_apps(char *name, char *title, char *units, char *family,
177 - int order, struct target *root);
178 +extern void ebpf_create_charts_on_apps(char *name,
179 + char *title,
180 + char *units,
181 + char *family,
182 + int order,
183 + struct target *root);
184
185 extern void write_end_chart();
186
181 -# define EBPF_GLOBAL_SECTION "global"
182 -# define EBPF_PROGRAMS_SECTION "ebpf programs"
187 +#define EBPF_GLOBAL_SECTION "global"
188 +#define EBPF_PROGRAMS_SECTION "ebpf programs"
189
184 -# define EBPF_COMMON_DIMENSION_CALL "Calls"
185 -# define EBPF_COMMON_DIMENSION_BYTESS "bytes/s"
186 -# define EBPF_COMMON_DIMENSION_DIFFERENCE "Difference"
190 +#define EBPF_COMMON_DIMENSION_CALL "Calls"
191 +#define EBPF_COMMON_DIMENSION_BYTESS "bytes/s"
192 +#define EBPF_COMMON_DIMENSION_DIFFERENCE "Difference"
193
188 -//Common variables
194 +// Common variables
195 extern char *ebpf_user_config_dir;
196 extern char *ebpf_stock_config_dir;
197 extern pid_t *pid_index;
198 extern int debug_enabled;
199
194 -//Socket functions and variables
195 -//Common functions
200 +// Socket functions and variables
201 +// Common functions
202 extern void ebpf_socket_create_apps_charts(ebpf_module_t *em, struct target *root);
203 extern collected_number get_value_from_structure(char *basis, size_t offset);
198 -extern struct pid_stat *root_of_pids;
204 +extern struct pid_stat *root_of_pids;
205 extern ebpf_process_stat_t *global_process_stat;
206 extern size_t all_pids_count;
207 extern int update_every;
208
203 -# define EBPF_MAX_SYNCHRONIZATION_TIME 300
209 +#define EBPF_MAX_SYNCHRONIZATION_TIME 300
210
211 //External functions
212 extern void change_socket_event();
213 extern void change_process_event();
214
209 -#endif
215 +#endif /* NETDATA_COLLECTOR_EBPF_H */
collectors/ebpf.plugin/ebpf_apps.c
+264 -397
@@ -1,6 +1,5 @@
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 -
3 #include "ebpf.h"
4 #include "ebpf_apps.h"
5
@@ -8,8 +7,7 @@
7 // internal flags
8 // handled in code (automatically set)
9
11 -static int
12 - proc_pid_cmdline_is_needed = 0; // 1 when we need to read /proc/cmdline
10 +static int proc_pid_cmdline_is_needed = 0; // 1 when we need to read /proc/cmdline
11
12 /*****************************************************************
13 *
@@ -27,12 +25,7 @@ static int
25 *
26 * @return It returns 0 when the data was copied and -1 otherwise
27 */
30 -#ifndef STATIC
31 -int ebpf_read_hash_table(void *ep, int fd, uint32_t pid,
32 - int (*bpf_map_lookup_elem)(int, const void *, void *))
33 -#else
34 -int ebpf_read_hash_table(void *ep, int fd, pid_t pid)
35 -#endif
28 +int ebpf_read_hash_table(void *ep, int fd, uint32_t pid)
29 {
30 if (!ep)
31 return -1;
@@ -55,21 +48,12 @@ int ebpf_read_hash_table(void *ep, int fd, pid_t pid)
48 *
49 * @return
50 */
58 -#ifndef STATIC
59 -size_t read_bandwidth_statistic_using_pid_on_target(ebpf_bandwidth_t **ep, int fd,
60 - ebpf_functions_t *ef, struct pid_on_target *pids)
61 -#else
62 -size_t read_bandwidth_statistic_using_pid_on_target(ebpf_bandwidth_t **ep, int fd,struct pid_on_target *pids)
63 -#endif
51 +size_t read_bandwidth_statistic_using_pid_on_target(ebpf_bandwidth_t **ep, int fd, struct pid_on_target *pids)
52 {
53 size_t count = 0;
66 - while(pids) {
54 + while (pids) {
55 uint32_t current_pid = pids->pid;
68 -#ifndef STATIC
69 - if (!ebpf_read_hash_table(ep[current_pid], fd, current_pid, ef->bpf_map_lookup_elem))
70 -#else
71 - if (!ebpf_read_hash_table(ep[current_pid], fd, current_pid))
72 -#endif
56 + if (!ebpf_read_hash_table(ep[current_pid], fd, current_pid))
57 count++;
58
59 pids = pids->next;
@@ -86,16 +70,10 @@ size_t read_bandwidth_statistic_using_pid_on_target(ebpf_bandwidth_t **ep, int f
70 * @param bpf_map_lookup_elem a pointer for the function to read the data
71 * @param bpf_map_get_next_key a pointer fo the function to read the index.
72 */
89 -#ifndef STATIC
90 -size_t read_bandwidth_statistic_using_hash_table(ebpf_bandwidth_t **out, int fd,
91 - int (*bpf_map_lookup_elem)(int, const void *, void *),
92 - int (*bpf_map_get_next_key)(int, const void *, void *))
93 -#else
73 size_t read_bandwidth_statistic_using_hash_table(ebpf_bandwidth_t **out, int fd)
95 -#endif
74 {
75 size_t count = 0;
98 - uint32_t key =0;
76 + uint32_t key = 0;
77 uint32_t next_key = 0;
78
79 while (bpf_map_get_next_key(fd, &key, &next_key) == 0) {
@@ -104,11 +82,7 @@ size_t read_bandwidth_statistic_using_hash_table(ebpf_bandwidth_t **out, int fd)
82 eps = callocz(1, sizeof(ebpf_process_stat_t));
83 out[next_key] = eps;
84 }
107 -#ifndef STATIC
108 - ebpf_read_hash_table(eps, fd, next_key, bpf_map_lookup_elem);
109 -#else
85 ebpf_read_hash_table(eps, fd, next_key);
111 -#endif
86 }
87
88 return count;
@@ -127,10 +101,11 @@ size_t read_bandwidth_statistic_using_hash_table(ebpf_bandwidth_t **out, int fd)
101 *
102 * @return It returns 1 for root and 0 otherwise.
103 */
130 -int am_i_running_as_root() {
104 +int am_i_running_as_root()
105 +{
106 uid_t uid = getuid(), euid = geteuid();
107
133 - if(uid == 0 || euid == 0) {
108 + if (uid == 0 || euid == 0) {
109 return 1;
110 }
111
@@ -144,67 +119,18 @@ int am_i_running_as_root() {
119 *
120 * @return it returns the number of structures that was reseted.
121 */
147 -size_t zero_all_targets(struct target *root) {
122 +size_t zero_all_targets(struct target *root)
123 +{
124 struct target *w;
125 size_t count = 0;
126
151 - for (w = root; w ; w = w->next) {
127 + for (w = root; w; w = w->next) {
128 count++;
129
154 - /* These variables are not necessary for eBPF collector
155 - w->minflt = 0;
156 - w->majflt = 0;
157 - w->utime = 0;
158 - w->stime = 0;
159 - w->gtime = 0;
160 - w->cminflt = 0;
161 - w->cmajflt = 0;
162 - w->cutime = 0;
163 - w->cstime = 0;
164 - w->cgtime = 0;
165 - w->num_threads = 0;
166 - // w->rss = 0;
167 - w->processes = 0;
168 -
169 - w->status_vmsize = 0;
170 - w->status_vmrss = 0;
171 - w->status_vmshared = 0;
172 - w->status_rssfile = 0;
173 - w->status_rssshmem = 0;
174 - w->status_vmswap = 0;
175 -
176 - w->io_logical_bytes_read = 0;
177 - w->io_logical_bytes_written = 0;
178 - // w->io_read_calls = 0;
179 - // w->io_write_calls = 0;
180 - w->io_storage_bytes_read = 0;
181 - w->io_storage_bytes_written = 0;
182 - // w->io_cancelled_write_bytes = 0;
183 -
184 - // zero file counters
185 - if(w->target_fds) {
186 - memset(w->target_fds, 0, sizeof(int) * w->target_fds_size);
187 - w->openfiles = 0;
188 - w->openpipes = 0;
189 - w->opensockets = 0;
190 - w->openinotifies = 0;
191 - w->openeventfds = 0;
192 - w->opentimerfds = 0;
193 - w->opensignalfds = 0;
194 - w->openeventpolls = 0;
195 - w->openother = 0;
196 - }
197 -
198 - w->collected_starttime = 0;
199 - w->uptime_min = 0;
200 - w->uptime_sum = 0;
201 - w->uptime_max = 0;
202 - */
203 -
204 - if(unlikely(w->root_pid)) {
130 + if (unlikely(w->root_pid)) {
131 struct pid_on_target *pid_on_target = w->root_pid;
132
207 - while(pid_on_target) {
133 + while (pid_on_target) {
134 struct pid_on_target *pid_on_target_to_free = pid_on_target;
135 pid_on_target = pid_on_target->next;
136 free(pid_on_target_to_free);
@@ -222,7 +148,8 @@ size_t zero_all_targets(struct target *root) {
148 *
149 * @param agrt the pointer to be cleaned.
150 */
225 -void clean_apps_groups_target(struct target *agrt) {
151 +void clean_apps_groups_target(struct target *agrt)
152 +{
153 struct target *current_target;
154 while (agrt) {
155 current_target = agrt;
@@ -242,50 +169,56 @@ void clean_apps_groups_target(struct target *agrt) {
169 *
170 * @return It returns the target on success and NULL otherwise
171 */
245 -struct target *get_apps_groups_target(struct target **agrt, const char *id,
246 - struct target *target, const char *name) {
247 - int tdebug = 0, thidden = target?target->hidden:0, ends_with = 0;
172 +struct target *get_apps_groups_target(struct target **agrt, const char *id, struct target *target, const char *name)
173 +{
174 + int tdebug = 0, thidden = target ? target->hidden : 0, ends_with = 0;
175 const char *nid = id;
176
177 // extract the options
251 - while(nid[0] == '-' || nid[0] == '+' || nid[0] == '*') {
252 - if(nid[0] == '-') thidden = 1;
253 - if(nid[0] == '+') tdebug = 1;
254 - if(nid[0] == '*') ends_with = 1;
178 + while (nid[0] == '-' || nid[0] == '+' || nid[0] == '*') {
179 + if (nid[0] == '-')
180 + thidden = 1;
181 + if (nid[0] == '+')
182 + tdebug = 1;
183 + if (nid[0] == '*')
184 + ends_with = 1;
185 nid++;
186 }
187 uint32_t hash = simple_hash(id);
188
189 // find if it already exists
190 struct target *w, *last = *agrt;
261 - for(w = *agrt ; w ; w = w->next) {
262 - if(w->idhash == hash && strncmp(nid, w->id, MAX_NAME) == 0)
191 + for (w = *agrt; w; w = w->next) {
192 + if (w->idhash == hash && strncmp(nid, w->id, MAX_NAME) == 0)
193 return w;
194
195 last = w;
196 }
197
198 // find an existing target
269 - if(unlikely(!target)) {
270 - while(*name == '-') {
271 - if(*name == '-') thidden = 1;
199 + if (unlikely(!target)) {
200 + while (*name == '-') {
201 + if (*name == '-')
202 + thidden = 1;
203 name++;
204 }
205
275 - for(target = *agrt ; target != NULL ; target = target->next) {
276 - if(!target->target && strcmp(name, target->name) == 0)
206 + for (target = *agrt; target != NULL; target = target->next) {
207 + if (!target->target && strcmp(name, target->name) == 0)
208 break;
209 }
210 }
211
281 - if(target && target->target)
282 - fatal("Internal Error: request to link process '%s' to target '%s' which is linked to target '%s'", id, target->id, target->target->id);
212 + if (target && target->target)
213 + fatal(
214 + "Internal Error: request to link process '%s' to target '%s' which is linked to target '%s'", id,
215 + target->id, target->target->id);
216
217 w = callocz(1, sizeof(struct target));
218 strncpyz(w->id, nid, MAX_NAME);
219 w->idhash = simple_hash(w->id);
220
288 - if(unlikely(!target))
221 + if (unlikely(!target))
222 // copy the name
223 strncpyz(w->name, name, MAX_NAME);
224 else
@@ -294,13 +227,13 @@ struct target *get_apps_groups_target(struct target **agrt, const char *id,
227
228 strncpyz(w->compare, nid, MAX_COMPARE_NAME);
229 size_t len = strlen(w->compare);
297 - if(w->compare[len - 1] == '*') {
230 + if (w->compare[len - 1] == '*') {
231 w->compare[len - 1] = '\0';
232 w->starts_with = 1;
233 }
234 w->ends_with = ends_with;
235
303 - if(w->starts_with && w->ends_with)
236 + if (w->starts_with && w->ends_with)
237 proc_pid_cmdline_is_needed = 1;
238
239 w->comparehash = simple_hash(w->compare);
@@ -310,14 +243,16 @@ struct target *get_apps_groups_target(struct target **agrt, const char *id,
243 #ifdef NETDATA_INTERNAL_CHECKS
244 w->debug_enabled = tdebug;
245 #else
313 - if(tdebug)
246 + if (tdebug)
247 fprintf(stderr, "apps.plugin has been compiled without debugging\n");
248 #endif
249 w->target = target;
250
251 // append it, to maintain the order in apps_groups.conf
319 - if(last) last->next = w;
320 - else *agrt = w;
252 + if (last)
253 + last->next = w;
254 + else
255 + *agrt = w;
256
257 return w;
258 }
@@ -331,8 +266,7 @@ struct target *get_apps_groups_target(struct target **agrt, const char *id,
266 *
267 * @return It returns 0 on succcess and -1 otherwise
268 */
334 -int ebpf_read_apps_groups_conf(struct target **agdt, struct target **agrt,
335 - const char *path, const char *file)
269 +int ebpf_read_apps_groups_conf(struct target **agdt, struct target **agrt, const char *path, const char *file)
270 {
271 char filename[FILENAME_MAX + 1];
272
@@ -341,34 +275,40 @@ int ebpf_read_apps_groups_conf(struct target **agdt, struct target **agrt,
275 // ----------------------------------------
276
277 procfile *ff = procfile_open(filename, " :\t", PROCFILE_FLAG_DEFAULT);
344 - if(!ff) return -1;
278 + if (!ff)
279 + return -1;
280
281 procfile_set_quotes(ff, "'\"");
282
283 ff = procfile_readall(ff);
349 - if(!ff)
284 + if (!ff)
285 return -1;
286
287 size_t line, lines = procfile_lines(ff);
288
354 - for (line = 0; line < lines ;line++) {
289 + for (line = 0; line < lines; line++) {
290 size_t word, words = procfile_linewords(ff, line);
356 - if(!words) continue;
291 + if (!words)
292 + continue;
293
294 char *name = procfile_lineword(ff, line, 0);
359 - if (!name || !*name) continue;
295 + if (!name || !*name)
296 + continue;
297
298 // find a possibly existing target
299 struct target *w = NULL;
300
301 // loop through all words, skipping the first one (the name)
365 - for (word = 0; word < words ;word++) {
302 + for (word = 0; word < words; word++) {
303 char *s = procfile_lineword(ff, line, word);
367 - if (!s || !*s) continue;
368 - if (*s == '#') break;
304 + if (!s || !*s)
305 + continue;
306 + if (*s == '#')
307 + break;
308
309 // is this the first word? skip it
371 - if (s == name) continue;
310 + if (s == name)
311 + continue;
312
313 // add this target
314 struct target *n = get_apps_groups_target(agrt, s, w, name);
@@ -379,15 +319,15 @@ int ebpf_read_apps_groups_conf(struct target **agdt, struct target **agrt,
319
320 // just some optimization
321 // to avoid searching for a target for each process
382 - if (!w) w = n->target?n->target:n;
322 + if (!w)
323 + w = n->target ? n->target : n;
324 }
325 }
326
327 procfile_close(ff);
328
388 - *agdt = get_apps_groups_target(agrt, "p+!o@w#e$i^r&7*5(-i)l-o_",
389 - NULL, "other"); // match nothing
390 - if(!*agdt)
329 + *agdt = get_apps_groups_target(agrt, "p+!o@w#e$i^r&7*5(-i)l-o_", NULL, "other"); // match nothing
330 + if (!*agdt)
331 fatal("Cannot create default target");
332
333 struct target *ptr = *agdt;
@@ -408,55 +348,58 @@ int ebpf_read_apps_groups_conf(struct target **agdt, struct target **agrt,
348 #define MAX_NAME 100
349 #define MAX_CMDLINE 16384
350
411 -struct pid_stat **all_pids = NULL; // to avoid allocations, we pre-allocate the
412 - // the entire pid space.
413 -struct pid_stat *root_of_pids = NULL; // global list of all processes running
351 +struct pid_stat **all_pids = NULL; // to avoid allocations, we pre-allocate the
352 + // the entire pid space.
353 +struct pid_stat *root_of_pids = NULL; // global list of all processes running
354
415 -size_t
416 - all_pids_count = 0; // the number of processes running
355 +size_t all_pids_count = 0; // the number of processes running
356
357 struct target
419 - *apps_groups_default_target = NULL, // the default target
420 - *apps_groups_root_target = NULL, // apps_groups.conf defined
421 - *users_root_target = NULL, // users
422 - *groups_root_target = NULL; // user groups
423 -
424 -size_t
425 - apps_groups_targets_count = 0; // # of apps_groups.conf targets
358 + *apps_groups_default_target = NULL, // the default target
359 + *apps_groups_root_target = NULL, // apps_groups.conf defined
360 + *users_root_target = NULL, // users
361 + *groups_root_target = NULL; // user groups
362
363 +size_t apps_groups_targets_count = 0; // # of apps_groups.conf targets
364
365 // ----------------------------------------------------------------------------
366 // internal counters
367
368 static size_t
432 - // global_iterations_counter = 1,
433 - calls_counter = 0,
434 - // file_counter = 0,
435 - // filenames_allocated_counter = 0,
436 - // inodes_changed_counter = 0,
437 - // links_changed_counter = 0,
438 - targets_assignment_counter = 0;
369 + // global_iterations_counter = 1,
370 + calls_counter = 0,
371 + // file_counter = 0,
372 + // filenames_allocated_counter = 0,
373 + // inodes_changed_counter = 0,
374 + // links_changed_counter = 0,
375 + targets_assignment_counter = 0;
376
377 // ----------------------------------------------------------------------------
378 // debugging
379
380 // log each problem once per process
381 // log flood protection flags (log_thrown)
445 -#define PID_LOG_IO 0x00000001
446 -#define PID_LOG_STATUS 0x00000002
382 +#define PID_LOG_IO 0x00000001
383 +#define PID_LOG_STATUS 0x00000002
384 #define PID_LOG_CMDLINE 0x00000004
448 -#define PID_LOG_FDS 0x00000008
449 -#define PID_LOG_STAT 0x00000010
385 +#define PID_LOG_FDS 0x00000008
386 +#define PID_LOG_STAT 0x00000010
387
388 int debug_enabled = 0;
389
390 #ifdef NETDATA_INTERNAL_CHECKS
391
455 -#define debug_log(fmt, args...) do { if(unlikely(debug_enabled)) debug_log_int(fmt, ##args); } while(0)
392 +#define debug_log(fmt, args...) \
393 + do { \
394 + if (unlikely(debug_enabled)) \
395 + debug_log_int(fmt, ##args); \
396 + } while (0)
397
398 #else
399
459 -static inline void debug_log_dummy(void) {}
400 +static inline void debug_log_dummy(void)
401 +{
402 +}
403 #define debug_log(fmt, args...) debug_log_dummy()
404
405 #endif
@@ -472,28 +415,37 @@ static inline void debug_log_dummy(void) {}
415 *
416 * @return It returns the status value.
417 */
475 -static inline int managed_log(struct pid_stat *p, uint32_t log, int status) {
476 - if(unlikely(!status)) {
418 +static inline int managed_log(struct pid_stat *p, uint32_t log, int status)
419 +{
420 + if (unlikely(!status)) {
421 // error("command failed log %u, errno %d", log, errno);
422
479 - if(unlikely(debug_enabled || errno != ENOENT)) {
480 - if(unlikely(debug_enabled || !(p->log_thrown & log))) {
423 + if (unlikely(debug_enabled || errno != ENOENT)) {
424 + if (unlikely(debug_enabled || !(p->log_thrown & log))) {
425 p->log_thrown |= log;
482 - switch(log) {
426 + switch (log) {
427 case PID_LOG_IO:
484 - error("Cannot process %s/proc/%d/io (command '%s')", netdata_configured_host_prefix, p->pid, p->comm);
428 + error(
429 + "Cannot process %s/proc/%d/io (command '%s')", netdata_configured_host_prefix, p->pid,
430 + p->comm);
431 break;
432
433 case PID_LOG_STATUS:
488 - error("Cannot process %s/proc/%d/status (command '%s')", netdata_configured_host_prefix, p->pid, p->comm);
434 + error(
435 + "Cannot process %s/proc/%d/status (command '%s')", netdata_configured_host_prefix, p->pid,
436 + p->comm);
437 break;
438
439 case PID_LOG_CMDLINE:
492 - error("Cannot process %s/proc/%d/cmdline (command '%s')", netdata_configured_host_prefix, p->pid, p->comm);
440 + error(
441 + "Cannot process %s/proc/%d/cmdline (command '%s')", netdata_configured_host_prefix, p->pid,
442 + p->comm);
443 break;
444
445 case PID_LOG_FDS:
496 - error("Cannot process entries in %s/proc/%d/fd (command '%s')", netdata_configured_host_prefix, p->pid, p->comm);
446 + error(
447 + "Cannot process entries in %s/proc/%d/fd (command '%s')", netdata_configured_host_prefix,
448 + p->pid, p->comm);
449 break;
450
451 case PID_LOG_STAT:
@@ -506,8 +458,7 @@ static inline int managed_log(struct pid_stat *p, uint32_t log, int status) {
458 }
459 }
460 errno = 0;
509 - }
510 - else if(unlikely(p->log_thrown & log)) {
461 + } else if (unlikely(p->log_thrown & log)) {
462 // error("unsetting log %u on pid %d", log, p->pid);
463 p->log_thrown &= ~log;
464 }
@@ -524,13 +475,14 @@ static inline int managed_log(struct pid_stat *p, uint32_t log, int status) {
475 *
476 * @return It returns the pid entry structure
477 */
527 -static inline struct pid_stat *get_pid_entry(pid_t pid) {
528 - if(unlikely(all_pids[pid]))
478 +static inline struct pid_stat *get_pid_entry(pid_t pid)
479 +{
480 + if (unlikely(all_pids[pid]))
481 return all_pids[pid];
482
483 struct pid_stat *p = callocz(1, sizeof(struct pid_stat));
484
533 - if(likely(root_of_pids))
485 + if (likely(root_of_pids))
486 root_of_pids->prev = p;
487
488 p->next = root_of_pids;
@@ -549,14 +501,15 @@ static inline struct pid_stat *get_pid_entry(pid_t pid) {
501 *
502 * @param p the pid_stat structure to assign for a target.
503 */
552 -static inline void assign_target_to_pid(struct pid_stat *p) {
504 +static inline void assign_target_to_pid(struct pid_stat *p)
505 +{
506 targets_assignment_counter++;
507
508 uint32_t hash = simple_hash(p->comm);
556 - size_t pclen = strlen(p->comm);
509 + size_t pclen = strlen(p->comm);
510
511 struct target *w;
559 - for(w = apps_groups_root_target; w ; w = w->next) {
512 + for (w = apps_groups_root_target; w; w = w->next) {
513 // if(debug_enabled || (p->target && p->target->debug_enabled)) debug_log_int("\t\tcomparing '%s' with '%s'", w->compare, p->comm);
514
515 // find it - 4 cases:
@@ -565,16 +518,17 @@ static inline void assign_target_to_pid(struct pid_stat *p) {
518 // 3. the target has the suffix
519 // 4. the target is something inside cmdline
520
568 - if(unlikely(( (!w->starts_with && !w->ends_with && w->comparehash == hash && !strcmp(w->compare, p->comm))
569 - || (w->starts_with && !w->ends_with && !strncmp(w->compare, p->comm, w->comparelen))
570 - || (!w->starts_with && w->ends_with && pclen >= w->comparelen && !strcmp(w->compare, &p->comm[pclen - w->comparelen]))
571 - || (proc_pid_cmdline_is_needed && w->starts_with && w->ends_with && p->cmdline && strstr(p->cmdline, w->compare))
572 - ))) {
573 -
574 - if(w->target) p->target = w->target;
575 - else p->target = w;
521 + if (unlikely(
522 + ((!w->starts_with && !w->ends_with && w->comparehash == hash && !strcmp(w->compare, p->comm)) ||
523 + (w->starts_with && !w->ends_with && !strncmp(w->compare, p->comm, w->comparelen)) ||
524 + (!w->starts_with && w->ends_with && pclen >= w->comparelen && !strcmp(w->compare, &p->comm[pclen - w->comparelen])) ||
525 + (proc_pid_cmdline_is_needed && w->starts_with && w->ends_with && p->cmdline && strstr(p->cmdline, w->compare))))) {
526 + if (w->target)
527 + p->target = w->target;
528 + else
529 + p->target = w;
530
577 - if(debug_enabled || (p->target && p->target->debug_enabled))
531 + if (debug_enabled || (p->target && p->target->debug_enabled))
532 debug_log_int("%s linked to target %s", p->comm, p->target->name);
533
534 break;
@@ -592,29 +546,34 @@ static inline void assign_target_to_pid(struct pid_stat *p) {
546 *
547 * @return It returns 1 on success and 0 otherwise.
548 */
595 -static inline int read_proc_pid_cmdline(struct pid_stat *p) {
549 +static inline int read_proc_pid_cmdline(struct pid_stat *p)
550 +{
551 static char cmdline[MAX_CMDLINE + 1];
552
598 - if(unlikely(!p->cmdline_filename)) {
553 + if (unlikely(!p->cmdline_filename)) {
554 char filename[FILENAME_MAX + 1];
555 snprintfz(filename, FILENAME_MAX, "%s/proc/%d/cmdline", netdata_configured_host_prefix, p->pid);
556 p->cmdline_filename = strdupz(filename);
557 }
558
559 int fd = open(p->cmdline_filename, procfile_open_flags, 0666);
605 - if(unlikely(fd == -1)) goto cleanup;
560 + if (unlikely(fd == -1))
561 + goto cleanup;
562
563 ssize_t i, bytes = read(fd, cmdline, MAX_CMDLINE);
564 close(fd);
565
610 - if(unlikely(bytes < 0)) goto cleanup;
566 + if (unlikely(bytes < 0))
567 + goto cleanup;
568
569 cmdline[bytes] = '\0';
613 - for(i = 0; i < bytes ; i++) {
614 - if(unlikely(!cmdline[i])) cmdline[i] = ' ';
570 + for (i = 0; i < bytes; i++) {
571 + if (unlikely(!cmdline[i]))
572 + cmdline[i] = ' ';
573 }
574
617 - if(p->cmdline) freez(p->cmdline);
575 + if (p->cmdline)
576 + freez(p->cmdline);
577 p->cmdline = strdupz(cmdline);
578
579 debug_log("Read file '%s' contents: %s", p->cmdline_filename, p->cmdline);
@@ -623,7 +582,8 @@ static inline int read_proc_pid_cmdline(struct pid_stat *p) {
582
583 cleanup:
584 // copy the command to the command line
626 - if(p->cmdline) freez(p->cmdline);
585 + if (p->cmdline)
586 + freez(p->cmdline);
587 p->cmdline = strdupz(p->comm);
588 return 0;
589 }
@@ -635,41 +595,45 @@ cleanup:
595 * @param p the pid stat structure to store the data.
596 * @param ptr an useless argument.
597 */
638 -static inline int read_proc_pid_stat(struct pid_stat *p, void *ptr) {
639 - (void)ptr;
598 +static inline int read_proc_pid_stat(struct pid_stat *p, void *ptr)
599 +{
600 + UNUSED(ptr);
601
602 static procfile *ff = NULL;
603
643 - if(unlikely(!p->stat_filename)) {
604 + if (unlikely(!p->stat_filename)) {
605 char filename[FILENAME_MAX + 1];
606 snprintfz(filename, FILENAME_MAX, "%s/proc/%d/stat", netdata_configured_host_prefix, p->pid);
607 p->stat_filename = strdupz(filename);
608 }
609
649 - int set_quotes = (!ff)?1:0;
610 + int set_quotes = (!ff) ? 1 : 0;
611
612 struct stat statbuf;
652 - if (stat(p->stat_filename, &statbuf)) return 0;
613 + if (stat(p->stat_filename, &statbuf))
614 + return 0;
615
616 ff = procfile_reopen(ff, p->stat_filename, NULL, PROCFILE_FLAG_NO_ERROR_ON_FILE_IO);
655 - if(unlikely(!ff)) return 0;
617 + if (unlikely(!ff))
618 + return 0;
619
657 - if(unlikely(set_quotes))
620 + if (unlikely(set_quotes))
621 procfile_set_open_close(ff, "(", ")");
622
623 ff = procfile_readall(ff);
661 - if(unlikely(!ff)) return 0;
624 + if (unlikely(!ff))
625 + return 0;
626
627 p->last_stat_collected_usec = p->stat_collected_usec;
628 p->stat_collected_usec = now_monotonic_usec();
629 calls_counter++;
630
667 - char *comm = procfile_lineword(ff, 0, 1);
668 - p->ppid = (int32_t)str2pid_t(procfile_lineword(ff, 0, 3));
631 + char *comm = procfile_lineword(ff, 0, 1);
632 + p->ppid = (int32_t)str2pid_t(procfile_lineword(ff, 0, 3));
633
670 - if(strcmp(p->comm, comm) != 0) {
671 - if(unlikely(debug_enabled)) {
672 - if(p->comm[0])
634 + if (strcmp(p->comm, comm) != 0) {
635 + if (unlikely(debug_enabled)) {
636 + if (p->comm[0])
637 debug_log("\tpid %d (%s) changed name to '%s'", p->pid, p->comm, comm);
638 else
639 debug_log("\tJust added %d (%s)", p->pid, comm);
@@ -678,13 +642,13 @@ static inline int read_proc_pid_stat(struct pid_stat *p, void *ptr) {
642 strncpyz(p->comm, comm, MAX_COMPARE_NAME);
643
644 // /proc/<pid>/cmdline
681 - if(likely(proc_pid_cmdline_is_needed))
645 + if (likely(proc_pid_cmdline_is_needed))
646 managed_log(p, PID_LOG_CMDLINE, read_proc_pid_cmdline(p));
647
648 assign_target_to_pid(p);
649 }
650
687 - if(unlikely(debug_enabled || (p->target && p->target->debug_enabled)))
651 + if (unlikely(debug_enabled || (p->target && p->target->debug_enabled)))
652 debug_log_int(
653 "READ PROC/PID/STAT: %s/proc/%d/stat, process: '%s' on target '%s' (dt=%llu)",
654 netdata_configured_host_prefix, p->pid, p->comm, (p->target) ? p->target->name : "UNSET",
@@ -701,32 +665,28 @@ static inline int read_proc_pid_stat(struct pid_stat *p, void *ptr) {
665 *
666 * @return It returns 1 on succcess and 0 otherwise
667 */
704 -static inline int collect_data_for_pid(pid_t pid, void *ptr) {
705 - if(unlikely(pid < 0 || pid > pid_max)) {
668 +static inline int collect_data_for_pid(pid_t pid, void *ptr)
669 +{
670 + if (unlikely(pid < 0 || pid > pid_max)) {
671 error("Invalid pid %d read (expected %d to %d). Ignoring process.", pid, 0, pid_max);
672 return 0;
673 }
674
675 struct pid_stat *p = get_pid_entry(pid);
711 - if(unlikely(!p || p->read)) return 0;
676 + if (unlikely(!p || p->read))
677 + return 0;
678 p->read = 1;
679
714 - if(unlikely(!managed_log(p, PID_LOG_STAT, read_proc_pid_stat(p, ptr))))
680 + if (unlikely(!managed_log(p, PID_LOG_STAT, read_proc_pid_stat(p, ptr))))
681 // there is no reason to proceed if we cannot get its status
682 return 0;
683
718 -
684 // check its parent pid
720 - if(unlikely(p->ppid < 0 || p->ppid > pid_max)) {
685 + if (unlikely(p->ppid < 0 || p->ppid > pid_max)) {
686 error("Pid %d (command '%s') states invalid parent pid %d. Using 0.", pid, p->comm, p->ppid);
687 p->ppid = 0;
688 }
689
725 - /*
726 - if(unlikely(debug_enabled && all_pids_count && p->ppid && all_pids[p->ppid] && !all_pids[p->ppid]->read))
727 - debug_log("Read process %d (%s) sortlisted %d, but its parent %d (%s) sortlisted %d, is not read", p->pid, p->comm, p->sortlist, all_pids[p->ppid]->pid, all_pids[p->ppid]->comm, all_pids[p->ppid]->sortlist);
728 - */
729 -
690 // mark it as updated
691 p->updated = 1;
692 p->keep = 0;
@@ -738,31 +698,34 @@ static inline int collect_data_for_pid(pid_t pid, void *ptr) {
698 /**
699 * Fill link list of parents with children PIDs
700 */
741 -static inline void link_all_processes_to_their_parents(void) {
701 +static inline void link_all_processes_to_their_parents(void)
702 +{
703 struct pid_stat *p, *pp;
704
705 // link all children to their parents
706 // and update children count on parents
746 - for(p = root_of_pids; p ; p = p->next) {
707 + for (p = root_of_pids; p; p = p->next) {
708 // for each process found
709
710 p->sortlist = 0;
711 p->parent = NULL;
712
752 - if(unlikely(!p->ppid)) {
713 + if (unlikely(!p->ppid)) {
714 p->parent = NULL;
715 continue;
716 }
717
718 pp = all_pids[p->ppid];
758 - if(likely(pp)) {
719 + if (likely(pp)) {
720 p->parent = pp;
721 pp->children_count++;
722
762 - if(unlikely(debug_enabled || (p->target && p->target->debug_enabled)))
763 - debug_log_int("child %d (%s, %s) on target '%s' has parent %d (%s, %s).", p->pid, p->comm, p->updated?"running":"exited", (p->target)?p->target->name:"UNSET", pp->pid, pp->comm, pp->updated?"running":"exited");
764 - }
765 - else {
723 + if (unlikely(debug_enabled || (p->target && p->target->debug_enabled)))
724 + debug_log_int(
725 + "child %d (%s, %s) on target '%s' has parent %d (%s, %s).", p->pid, p->comm,
726 + p->updated ? "running" : "exited", (p->target) ? p->target->name : "UNSET", pp->pid, pp->comm,
727 + pp->updated ? "running" : "exited");
728 + } else {
729 p->parent = NULL;
730 debug_log("pid %d %s states parent %d, but the later does not exist.", p->pid, p->comm, p->ppid);
731 }
@@ -772,26 +735,30 @@ static inline void link_all_processes_to_their_parents(void) {
735 /**
736 * Aggregate PIDs to targets.
737 */
775 -static void apply_apps_groups_targets_inheritance(void) {
738 +static void apply_apps_groups_targets_inheritance(void)
739 +{
740 struct pid_stat *p = NULL;
741
742 // children that do not have a target
743 // inherit their target from their parent
744 int found = 1, loops = 0;
781 - while(found) {
782 - if(unlikely(debug_enabled)) loops++;
745 + while (found) {
746 + if (unlikely(debug_enabled))
747 + loops++;
748 found = 0;
784 - for(p = root_of_pids; p ; p = p->next) {
749 + for (p = root_of_pids; p; p = p->next) {
750 // if this process does not have a target
751 // and it has a parent
752 // and its parent has a target
753 // then, set the parent's target to this process
789 - if(unlikely(!p->target && p->parent && p->parent->target)) {
754 + if (unlikely(!p->target && p->parent && p->parent->target)) {
755 p->target = p->parent->target;
756 found++;
757
793 - if(debug_enabled || (p->target && p->target->debug_enabled))
794 - debug_log_int("TARGET INHERITANCE: %s is inherited by %d (%s) from its parent %d (%s).", p->target->name, p->pid, p->comm, p->parent->pid, p->parent->comm);
758 + if (debug_enabled || (p->target && p->target->debug_enabled))
759 + debug_log_int(
760 + "TARGET INHERITANCE: %s is inherited by %d (%s) from its parent %d (%s).", p->target->name,
761 + p->pid, p->comm, p->parent->pid, p->parent->comm);
762 }
763 }
764 }
@@ -800,34 +767,37 @@ static void apply_apps_groups_targets_inheritance(void) {
767 // repeat, until nothing more can be done.
768 int sortlist = 1;
769 found = 1;
803 - while(found) {
804 - if(unlikely(debug_enabled)) loops++;
770 + while (found) {
771 + if (unlikely(debug_enabled))
772 + loops++;
773 found = 0;
774
807 - for(p = root_of_pids; p ; p = p->next) {
808 - if(unlikely(!p->sortlist && !p->children_count))
775 + for (p = root_of_pids; p; p = p->next) {
776 + if (unlikely(!p->sortlist && !p->children_count))
777 p->sortlist = sortlist++;
778
811 - if(unlikely(
812 - !p->children_count // if this process does not have any children
813 - && !p->merged // and is not already merged
814 - && p->parent // and has a parent
815 - && p->parent->children_count // and its parent has children
816 - // and the target of this process and its parent is the same,
817 - // or the parent does not have a target
818 - && (p->target == p->parent->target || !p->parent->target)
819 - && p->ppid != INIT_PID // and its parent is not init
820 - )) {
779 + if (unlikely(
780 + !p->children_count // if this process does not have any children
781 + && !p->merged // and is not already merged
782 + && p->parent // and has a parent
783 + && p->parent->children_count // and its parent has children
784 + // and the target of this process and its parent is the same,
785 + // or the parent does not have a target
786 + && (p->target == p->parent->target || !p->parent->target) &&
787 + p->ppid != INIT_PID // and its parent is not init
788 + )) {
789 // mark it as merged
790 p->parent->children_count--;
791 p->merged = 1;
792
793 // the parent inherits the child's target, if it does not have a target itself
826 - if(unlikely(p->target && !p->parent->target)) {
794 + if (unlikely(p->target && !p->parent->target)) {
795 p->parent->target = p->target;
796
829 - if(debug_enabled || (p->target && p->target->debug_enabled))
830 - debug_log_int("TARGET INHERITANCE: %s is inherited by %d (%s) from its child %d (%s).", p->target->name, p->parent->pid, p->parent->comm, p->pid, p->comm);
797 + if (debug_enabled || (p->target && p->target->debug_enabled))
798 + debug_log_int(
799 + "TARGET INHERITANCE: %s is inherited by %d (%s) from its child %d (%s).", p->target->name,
800 + p->parent->pid, p->parent->comm, p->pid, p->comm);
801 }
802
803 found++;
@@ -838,41 +808,45 @@ static void apply_apps_groups_targets_inheritance(void) {
808 }
809
810 // init goes always to default target
841 - if(all_pids[INIT_PID])
811 + if (all_pids[INIT_PID])
812 all_pids[INIT_PID]->target = apps_groups_default_target;
813
814 // pid 0 goes always to default target
845 - if(all_pids[0])
815 + if (all_pids[0])
816 all_pids[0]->target = apps_groups_default_target;
817
818 // give a default target on all top level processes
849 - if(unlikely(debug_enabled)) loops++;
850 - for(p = root_of_pids; p ; p = p->next) {
819 + if (unlikely(debug_enabled))
820 + loops++;
821 + for (p = root_of_pids; p; p = p->next) {
822 // if the process is not merged itself
823 // then is is a top level process
853 - if(unlikely(!p->merged && !p->target))
824 + if (unlikely(!p->merged && !p->target))
825 p->target = apps_groups_default_target;
826
827 // make sure all processes have a sortlist
857 - if(unlikely(!p->sortlist))
828 + if (unlikely(!p->sortlist))
829 p->sortlist = sortlist++;
830 }
831
861 - if(all_pids[1])
832 + if (all_pids[1])
833 all_pids[1]->sortlist = sortlist++;
834
835 // give a target to all merged child processes
836 found = 1;
866 - while(found) {
867 - if(unlikely(debug_enabled)) loops++;
837 + while (found) {
838 + if (unlikely(debug_enabled))
839 + loops++;
840 found = 0;
869 - for(p = root_of_pids; p ; p = p->next) {
870 - if(unlikely(!p->target && p->merged && p->parent && p->parent->target)) {
841 + for (p = root_of_pids; p; p = p->next) {
842 + if (unlikely(!p->target && p->merged && p->parent && p->parent->target)) {
843 p->target = p->parent->target;
844 found++;
845
874 - if(debug_enabled || (p->target && p->target->debug_enabled))
875 - debug_log_int("TARGET INHERITANCE: %s is inherited by %d (%s) from its parent %d (%s) at phase 2.", p->target->name, p->pid, p->comm, p->parent->pid, p->parent->comm);
846 + if (debug_enabled || (p->target && p->target->debug_enabled))
847 + debug_log_int(
848 + "TARGET INHERITANCE: %s is inherited by %d (%s) from its parent %d (%s) at phase 2.",
849 + p->target->name, p->pid, p->comm, p->parent->pid, p->parent->comm);
850 }
851 }
852 }
@@ -885,10 +859,11 @@ static void apply_apps_groups_targets_inheritance(void) {
859 *
860 * @param root the targets that will be updated.
861 */
888 -static inline void post_aggregate_targets(struct target *root) {
862 +static inline void post_aggregate_targets(struct target *root)
863 +{
864 struct target *w;
890 - for (w = root; w ; w = w->next) {
891 - if(w->collected_starttime) {
865 + for (w = root; w; w = w->next) {
866 + if (w->collected_starttime) {
867 if (!w->starttime || w->collected_starttime < w->starttime) {
868 w->starttime = w->collected_starttime;
869 }
@@ -903,21 +878,24 @@ static inline void post_aggregate_targets(struct target *root) {
878 *
879 * @param pid the PID that will be removed.
880 */
906 -static inline void del_pid_entry(pid_t pid) {
881 +static inline void del_pid_entry(pid_t pid)
882 +{
883 struct pid_stat *p = all_pids[pid];
884
909 - if(unlikely(!p)) {
885 + if (unlikely(!p)) {
886 error("attempted to free pid %d that is not allocated.", pid);
887 return;
888 }
889
890 debug_log("process %d %s exited, deleting it.", pid, p->comm);
891
916 - if(root_of_pids == p)
892 + if (root_of_pids == p)
893 root_of_pids = p->next;
894
919 - if(p->next) p->next->prev = p->prev;
920 - if(p->prev) p->prev->next = p->next;
895 + if (p->next)
896 + p->next->prev = p->prev;
897 + if (p->prev)
898 + p->prev->next = p->next;
899
900 freez(p->stat_filename);
901 freez(p->status_filename);
@@ -935,12 +913,13 @@ static inline void del_pid_entry(pid_t pid) {
913 *
914 * @param out is the structure where PIDs are stored.
915 */
938 -void cleanup_exited_pids(ebpf_process_stat_t **out) {
916 +void cleanup_exited_pids(ebpf_process_stat_t **out)
917 +{
918 struct pid_stat *p = NULL;
919
941 - for(p = root_of_pids; p ;) {
942 - if(!p->updated && (!p->keep || p->keeploops > 0)) {
943 - if(unlikely(debug_enabled && (p->keep || p->keeploops)))
920 + for (p = root_of_pids; p;) {
921 + if (!p->updated && (!p->keep || p->keeploops > 0)) {
922 + if (unlikely(debug_enabled && (p->keep || p->keeploops)))
923 debug_log(" > CLEANUP cannot keep exited process %d (%s) anymore - removing it.", p->pid, p->comm);
924
925 pid_t r = p->pid;
@@ -952,9 +931,9 @@ void cleanup_exited_pids(ebpf_process_stat_t **out) {
931 freez(w);
932 out[r] = NULL;
933 }
955 - }
956 - else {
957 - if(unlikely(p->keep)) p->keeploops++;
934 + } else {
935 + if (unlikely(p->keep))
936 + p->keeploops++;
937 p->keep = 0;
938 p = p->next;
939 }
@@ -972,20 +951,21 @@ static inline void read_proc_filesystem()
951
952 snprintfz(dirname, FILENAME_MAX, "%s/proc", netdata_configured_host_prefix);
953 DIR *dir = opendir(dirname);
975 - if(!dir) return;
954 + if (!dir)
955 + return;
956
957 struct dirent *de = NULL;
958
979 - while((de = readdir(dir))) {
959 + while ((de = readdir(dir))) {
960 char *endptr = de->d_name;
961
982 - if(unlikely(de->d_type != DT_DIR || de->d_name[0] < '0' || de->d_name[0] > '9'))
962 + if (unlikely(de->d_type != DT_DIR || de->d_name[0] < '0' || de->d_name[0] > '9'))
963 continue;
964
985 - pid_t pid = (pid_t) strtoul(de->d_name, &endptr, 10);
965 + pid_t pid = (pid_t)strtoul(de->d_name, &endptr, 10);
966
967 // make sure we read a valid number
988 - if(unlikely(endptr == de->d_name || *endptr != '\0'))
968 + if (unlikely(endptr == de->d_name || *endptr != '\0'))
969 continue;
970
971 collect_data_for_pid(pid, NULL);
@@ -1002,71 +982,23 @@ static inline void read_proc_filesystem()
982 */
983 static inline void aggregate_pid_on_target(struct target *w, struct pid_stat *p, struct target *o)
984 {
1005 - (void)o;
985 + UNUSED(o);
986
1007 - if(unlikely(!p->updated)) {
987 + if (unlikely(!p->updated)) {
988 // the process is not running
989 return;
990 }
991
1012 - if(unlikely(!w)) {
992 + if (unlikely(!w)) {
993 error("pid %d %s was left without a target!", p->pid, p->comm);
994 return;
995 }
996
1017 - /*
1018 - w->cutime += p->cutime;
1019 - w->cstime += p->cstime;
1020 - w->cgtime += p->cgtime;
1021 - w->cminflt += p->cminflt;
1022 - w->cmajflt += p->cmajflt;
1023 -
1024 - w->utime += p->utime;
1025 - w->stime += p->stime;
1026 - w->gtime += p->gtime;
1027 - w->minflt += p->minflt;
1028 - w->majflt += p->majflt;
1029 -
1030 - // w->rss += p->rss;
1031 -
1032 - w->status_vmsize += p->status_vmsize;
1033 - w->status_vmrss += p->status_vmrss;
1034 - w->status_vmshared += p->status_vmshared;
1035 - w->status_rssfile += p->status_rssfile;
1036 - w->status_rssshmem += p->status_rssshmem;
1037 - w->status_vmswap += p->status_vmswap;
1038 -
1039 - w->io_logical_bytes_read += p->io_logical_bytes_read;
1040 - w->io_logical_bytes_written += p->io_logical_bytes_written;
1041 - // w->io_read_calls += p->io_read_calls;
1042 - // w->io_write_calls += p->io_write_calls;
1043 - w->io_storage_bytes_read += p->io_storage_bytes_read;
1044 - w->io_storage_bytes_written += p->io_storage_bytes_written;
1045 - // w->io_cancelled_write_bytes += p->io_cancelled_write_bytes;
1046 - */
1047 -
997 w->processes++;
998 struct pid_on_target *pid_on_target = mallocz(sizeof(struct pid_on_target));
999 pid_on_target->pid = p->pid;
1000 pid_on_target->next = w->root_pid;
1001 w->root_pid = pid_on_target;
1053 - /*
1054 - w->num_threads += p->num_threads;
1055 -
1056 - if(!w->collected_starttime || p->collected_starttime < w->collected_starttime) w->collected_starttime = p->collected_starttime;
1057 - if(!w->uptime_min || p->uptime < w->uptime_min) w->uptime_min = p->uptime;
1058 - w->uptime_sum += p->uptime;
1059 - if(!w->uptime_max || w->uptime_max < p->uptime) w->uptime_max = p->uptime;
1060 -
1061 - if(unlikely(debug_enabled || w->debug_enabled)) {
1062 - //debug_log_int("aggregating '%s' pid %d on target '%s' utime=" KERNEL_UINT_FORMAT ", stime=" KERNEL_UINT_FORMAT ", gtime=" KERNEL_UINT_FORMAT ", cutime=" KERNEL_UINT_FORMAT ", cstime=" KERNEL_UINT_FORMAT ", cgtime=" KERNEL_UINT_FORMAT ", minflt=" KERNEL_UINT_FORMAT ", majflt=" KERNEL_UINT_FORMAT ", cminflt=" KERNEL_UINT_FORMAT ", cmajflt=" KERNEL_UINT_FORMAT "", p->comm, p->pid, w->name, p->utime, p->stime, p->gtime, p->cutime, p->cstime, p->cgtime, p->minflt, p->majflt, p->cminflt, p->cmajflt);
1063 -
1064 - struct pid_on_target *pid_on_target = mallocz(sizeof(struct pid_on_target));
1065 - pid_on_target->pid = p->pid;
1066 - pid_on_target->next = w->root_pid;
1067 - w->root_pid = pid_on_target;
1068 - }
1069 - */
1002 }
1003
1004 /**
@@ -1080,18 +1012,9 @@ static inline void aggregate_pid_on_target(struct target *w, struct pid_stat *p,
1012 * @param bpf_map_lookup_elem A pointer to the function that reads the data.
1013 * @param tbl_pid_stats_fd The mapped file descriptor for the hash table.
1014 */
1083 -#ifndef STATIC
1084 -void collect_data_for_all_processes(ebpf_process_stat_t **out,
1085 - pid_t *index,
1086 - int (*bpf_map_lookup_elem)(int, const void *, void *),
1087 - int tbl_pid_stats_fd)
1088 -#else
1089 -void collect_data_for_all_processes(ebpf_process_stat_t **out,
1090 - pid_t *index,
1091 - int tbl_pid_stats_fd)
1092 -#endif
1015 +void collect_data_for_all_processes(ebpf_process_stat_t **out, pid_t *index, int tbl_pid_stats_fd)
1016 {
1094 - struct pid_stat *pids = root_of_pids; // global list of all processes running
1017 + struct pid_stat *pids = root_of_pids; // global list of all processes running
1018 while (pids) {
1019 if (pids->updated_twice) {
1020 pids->read = 0; // mark it as not read, so that collect_data_for_pid() will read it
@@ -1111,8 +1034,8 @@ void collect_data_for_all_processes(ebpf_process_stat_t **out,
1034
1035 int counter = 0;
1036 uint32_t key;
1114 - pids = root_of_pids; // global list of all processes running
1115 - //while (bpf_map_get_next_key(tbl_pid_stats_fd, &key, &next_key) == 0) {
1037 + pids = root_of_pids; // global list of all processes running
1038 + // while (bpf_map_get_next_key(tbl_pid_stats_fd, &key, &next_key) == 0) {
1039 while (pids) {
1040 key = pids->pid;
1041 ebpf_process_stat_t *w = out[key];
@@ -1136,70 +1059,14 @@ void collect_data_for_all_processes(ebpf_process_stat_t **out,
1059
1060 apply_apps_groups_targets_inheritance();
1061
1139 - /* These lines are not necessary for ebpf plugin
1140 - zero_all_targets(users_root_target);
1141 - zero_all_targets(groups_root_target);
1142 - */
1143 -
1062 apps_groups_targets_count = zero_all_targets(apps_groups_root_target);
1063
1064 // this has to be done, before the cleanup
1065 struct pid_stat *p = NULL;
1148 - // struct target *w = NULL, *o = NULL;
1066
1067 // // concentrate everything on the targets
1151 - for(p = root_of_pids; p ; p = p->next) {
1152 -
1153 - // --------------------------------------------------------------------
1154 - // apps_groups target
1155 -
1068 + for (p = root_of_pids; p; p = p->next)
1069 aggregate_pid_on_target(p->target, p, NULL);
1070
1158 -
1159 - // // --------------------------------------------------------------------
1160 - // // user target
1161 -
1162 - // o = p->user_target;
1163 - // if(likely(p->user_target && p->user_target->uid == p->uid))
1164 - // w = p->user_target;
1165 - // else {
1166 - // if(unlikely(debug_enabled && p->user_target))
1167 - // debug_log("pid %d (%s) switched user from %u (%s) to %u.", p->pid, p->comm, p->user_target->uid, p->user_target->name, p->uid);
1168 -
1169 - // w = p->user_target = get_users_target(p->uid);
1170 - // }
1171 -
1172 - // aggregate_pid_on_target(w, p, o);
1173 -
1174 -
1175 - // // --------------------------------------------------------------------
1176 - // // user group target
1177 -
1178 - // o = p->group_target;
1179 - // if(likely(p->group_target && p->group_target->gid == p->gid))
1180 - // w = p->group_target;
1181 - // else {
1182 - // if(unlikely(debug_enabled && p->group_target))
1183 - // debug_log("pid %d (%s) switched group from %u (%s) to %u.", p->pid, p->comm, p->group_target->gid, p->group_target->name, p->gid);
1184 -
1185 - // w = p->group_target = get_groups_target(p->gid);
1186 - // }
1187 -
1188 - // aggregate_pid_on_target(w, p, o);
1189 -
1190 -
1191 - // // --------------------------------------------------------------------
1192 - // // aggregate all file descriptors
1193 -
1194 - // if(enable_file_charts)
1195 - // aggregate_pid_fds_on_targets(p);
1196 - }
1197 -
1071 post_aggregate_targets(apps_groups_root_target);
1199 - /* These lines are not necessary for ebpf plugin
1200 - post_aggregate_targets(users_root_target);
1201 - post_aggregate_targets(groups_root_target);
1202 - */
1203 -
1204 - //cleanup_exited_pids(out);
1072 }
collectors/ebpf.plugin/ebpf_apps.h
+57 -70
@@ -1,19 +1,21 @@
1 -#ifndef _NETDATA_EBPF_APPS_H
2 -# define _NETDATA_EBPF_APPS_H 1
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2
4 -# include "libnetdata/threads/threads.h"
5 -# include "libnetdata/locks/locks.h"
6 -# include "libnetdata/avl/avl.h"
7 -# include "libnetdata/clocks/clocks.h"
8 -# include "libnetdata/config/appconfig.h"
9 -# include "libnetdata/ebpf/ebpf.h"
3 +#ifndef NETDATA_EBPF_APPS_H
4 +#define NETDATA_EBPF_APPS_H 1
5
11 -# define NETDATA_APPS_FAMILY "apps"
12 -# define NETDATA_APPS_SYSCALL_GROUP "ebpf syscall"
13 -# define NETDATA_APPS_NET_GROUP "ebpf net"
6 +#include "libnetdata/threads/threads.h"
7 +#include "libnetdata/locks/locks.h"
8 +#include "libnetdata/avl/avl.h"
9 +#include "libnetdata/clocks/clocks.h"
10 +#include "libnetdata/config/appconfig.h"
11 +#include "libnetdata/ebpf/ebpf.h"
12
15 -# define MAX_COMPARE_NAME 100
16 -# define MAX_NAME 100
13 +#define NETDATA_APPS_FAMILY "apps"
14 +#define NETDATA_APPS_SYSCALL_GROUP "ebpf syscall"
15 +#define NETDATA_APPS_NET_GROUP "ebpf net"
16 +
17 +#define MAX_COMPARE_NAME 100
18 +#define MAX_NAME 100
19
20 // ----------------------------------------------------------------------------
21 // process_pid_stat
@@ -21,10 +23,10 @@
23 // Fields read from the kernel ring for a specific PID
24 //
25 typedef struct process_pid_stat {
24 - uint64_t pid_tgid; //Unique identifier
25 - uint32_t pid; //process id
26 + uint64_t pid_tgid; // Unique identifier
27 + uint32_t pid; // process id
28
27 - //Count number of calls done for specific function
29 + // Count number of calls done for specific function
30 uint32_t open_call;
31 uint32_t write_call;
32 uint32_t writev_call;
@@ -37,13 +39,13 @@ typedef struct process_pid_stat {
39 uint32_t clone_call;
40 uint32_t close_call;
41
40 - //Count number of bytes written or read
42 + // Count number of bytes written or read
43 uint64_t write_bytes;
44 uint64_t writev_bytes;
45 uint64_t readv_bytes;
46 uint64_t read_bytes;
47
46 - //Count number of errors for the specified function
48 + // Count number of errors for the specified function
49 uint32_t open_err;
50 uint32_t write_err;
51 uint32_t writev_err;
@@ -68,7 +70,6 @@ typedef struct socket_bandwidth {
70 unsigned char removed;
71 } socket_bandwidth_t;
72
71 -
73 // ----------------------------------------------------------------------------
74 // pid_stat
75 //
@@ -157,12 +158,12 @@ struct target {
158 int hidden; // if set, we set the hidden flag on the dimension
159 int debug_enabled;
160 int ends_with;
160 - int starts_with; // if set, the compare string matches only the
161 - // beginning of the command
161 + int starts_with; // if set, the compare string matches only the
162 + // beginning of the command
163
164 struct pid_on_target *root_pid; // list of aggregated pids for target debugging
165
165 - struct target *target; // the one that will be reported to netdata
166 + struct target *target; // the one that will be reported to netdata
167 struct target *next;
168 };
169
@@ -268,24 +269,24 @@ struct pid_stat {
269 // kernel_uint_t io_cancelled_write_bytes;
270 */
271
271 - struct pid_fd *fds; // array of fds it uses
272 - size_t fds_size; // the size of the fds array
272 + struct pid_fd *fds; // array of fds it uses
273 + size_t fds_size; // the size of the fds array
274
274 - int children_count; // number of processes directly referencing this
275 - unsigned char keep:1; // 1 when we need to keep this process in memory even after it exited
276 - int keeploops; // increases by 1 every time keep is 1 and updated 0
277 - unsigned char updated:1; // 1 when the process is currently running
278 - unsigned char updated_twice:1; // 1 when the process was running in the previous iteration
279 - unsigned char merged:1; // 1 when it has been merged to its parent
280 - unsigned char read:1; // 1 when we have already read this process for this iteration
275 + int children_count; // number of processes directly referencing this
276 + unsigned char keep : 1; // 1 when we need to keep this process in memory even after it exited
277 + int keeploops; // increases by 1 every time keep is 1 and updated 0
278 + unsigned char updated : 1; // 1 when the process is currently running
279 + unsigned char updated_twice : 1; // 1 when the process was running in the previous iteration
280 + unsigned char merged : 1; // 1 when it has been merged to its parent
281 + unsigned char read : 1; // 1 when we have already read this process for this iteration
282
282 - int sortlist; // higher numbers = top on the process tree
283 + int sortlist; // higher numbers = top on the process tree
284
285 // each process gets a unique number
286
286 - struct target *target; // app_groups.conf targets
287 - struct target *user_target; // uid based targets
288 - struct target *group_target; // gid based targets
287 + struct target *target; // app_groups.conf targets
288 + struct target *user_target; // uid based targets
289 + struct target *group_target; // gid based targets
290
291 usec_t stat_collected_usec;
292 usec_t last_stat_collected_usec;
@@ -295,7 +296,7 @@ struct pid_stat {
296
297 kernel_uint_t uptime;
298
298 - char *fds_dirname; // the full directory name in /proc/PID/fd
299 + char *fds_dirname; // the full directory name in /proc/PID/fd
300
301 char *stat_filename;
302 char *status_filename;
@@ -362,11 +363,11 @@ typedef struct ebpf_process_stat {
363 typedef struct ebpf_bandwidth {
364 uint32_t pid;
365
365 - uint64_t first; //First timestamp
366 - uint64_t ct; //Last timestamp
367 - uint64_t sent; //Bytes sent
368 - uint64_t received; //Bytes received
369 - unsigned char removed; //Remove the PID from table
366 + uint64_t first; //First timestamp
367 + uint64_t ct; //Last timestamp
368 + uint64_t sent; //Bytes sent
369 + uint64_t received; //Bytes received
370 + unsigned char removed; //Remove the PID from table
371 } ebpf_bandwidth_t;
372
373 /**
@@ -375,13 +376,14 @@ typedef struct ebpf_bandwidth {
376 * @param fmt the format to create the message.
377 * @param ... the arguments to fill the format.
378 */
378 -static inline void debug_log_int(const char *fmt, ... ) {
379 +static inline void debug_log_int(const char *fmt, ...)
380 +{
381 va_list args;
382
381 - fprintf( stderr, "apps.plugin: ");
382 - va_start( args, fmt );
383 - vfprintf( stderr, fmt, args );
384 - va_end( args );
383 + fprintf(stderr, "apps.plugin: ");
384 + va_start(args, fmt);
385 + vfprintf(stderr, fmt, args);
386 + va_end(args);
387
388 fputc('\n', stderr);
389 }
@@ -391,9 +393,10 @@ static inline void debug_log_int(const char *fmt, ... ) {
393 //
394 extern struct pid_stat **all_pids;
395
394 -
396 extern int ebpf_read_apps_groups_conf(struct target **apps_groups_default_target,
396 - struct target **apps_groups_root_target, const char *path, const char *file);
397 + struct target **apps_groups_root_target,
398 + const char *path,
399 + const char *file);
400
401 extern void clean_apps_groups_target(struct target *apps_groups_root_target);
402
@@ -403,30 +406,14 @@ extern int am_i_running_as_root();
406
407 extern void cleanup_exited_pids(ebpf_process_stat_t **out);
408
406 -#ifndef STATIC
407 -extern int ebpf_read_hash_table(void *ep, int fd, uint32_t pid,
408 - int (*bpf_map_lookup_elem)(int, const void *, void *));
409 +extern int ebpf_read_hash_table(void *ep, int fd, uint32_t pid);
410
410 -extern size_t read_processes_statistic_using_pid_on_target(ebpf_process_stat_t **ep, int fd, ebpf_functions_t *ef,
411 +extern size_t read_processes_statistic_using_pid_on_target(ebpf_process_stat_t **ep,
412 + int fd,
413 struct pid_on_target *pids);
414
413 -extern size_t read_bandwidth_statistic_using_pid_on_target(ebpf_bandwidth_t **ep, int fd,
414 - ebpf_functions_t *ef, struct pid_on_target *pids);
415 -
416 -extern void collect_data_for_all_processes(ebpf_process_stat_t **out,
417 - pid_t *index,
418 - int (*bpf_map_lookup_elem)(int, const void *, void *),
419 - int tbl_pid_stats_fd);
420 -
421 -#else
422 -extern int ebpf_read_hash_table(void *ep, int fd, pid_t pid);
415 +extern size_t read_bandwidth_statistic_using_pid_on_target(ebpf_bandwidth_t **ep, int fd, struct pid_on_target *pids);
416
424 -extern size_t read_processes_statistic_using_pid_on_target(ebpf_process_stat_t **ep, int fd,struct pid_on_target *pids);
417 +extern void collect_data_for_all_processes(ebpf_process_stat_t **out, pid_t *index, int tbl_pid_stats_fd);
418
426 -extern void collect_data_for_all_processes(ebpf_process_stat_t **out,
427 - pid_t *index,
428 - int tbl_pid_stats_fd);
429 -
430 -#endif
431 -
432 -#endif
419 +#endif /* NETDATA_EBPF_APPS_H */
collectors/ebpf.plugin/ebpf_process.c
+123 -138
@@ -11,17 +11,18 @@
11 *
12 *****************************************************************/
13
14 -static char *process_dimension_names[NETDATA_MAX_MONITOR_VECTOR] = { "open", "close", "delete", "read", "write",
15 - "process", "task", "process", "thread" };
16 -static char *process_id_names[NETDATA_MAX_MONITOR_VECTOR] = { "do_sys_open", "__close_fd", "vfs_unlink", "vfs_read", "vfs_write",
17 - "do_exit", "release_task", "_do_fork", "sys_clone" };
14 +static char *process_dimension_names[NETDATA_MAX_MONITOR_VECTOR] = { "open", "close", "delete", "read", "write",
15 + "process", "task", "process", "thread" };
16 +static char *process_id_names[NETDATA_MAX_MONITOR_VECTOR] = { "do_sys_open", "__close_fd", "vfs_unlink",
17 + "vfs_read", "vfs_write", "do_exit",
18 + "release_task", "_do_fork", "sys_clone" };
19 static char *status[] = { "process", "zombie" };
20
21 static netdata_idx_t *process_hash_values = NULL;
22 static netdata_syscall_stat_t *process_aggregated_data = NULL;
23 static netdata_publish_syscall_t *process_publish_aggregated = NULL;
24
24 -static ebpf_functions_t process_functions;
25 +static ebpf_data_t process_data;
26
27 static ebpf_process_stat_t **local_process_stats = NULL;
28 static ebpf_process_publish_apps_t **current_apps_data = NULL;
@@ -29,20 +30,7 @@ static ebpf_process_publish_apps_t **prev_apps_data = NULL;
30
31 int process_enabled = 0;
32
32 -#ifndef STATIC
33 -/**
34 - * Pointers used when collector is dynamically linked
35 - */
36 -
37 -//Libbpf (It is necessary to have at least kernel 4.10)
38 -static int (*bpf_map_lookup_elem)(int, const void *, void *) = NULL;
39 -static int (*bpf_map_delete_elem)(int fd, const void *key) = NULL;
40 -
33 static int *map_fd = NULL;
42 -/**
43 - * End of the pointers
44 - */
45 - #endif
34
35 /*****************************************************************
36 *
@@ -57,18 +45,17 @@ static int *map_fd = NULL;
45 * @param pvc the second output structure with correlated dimensions
46 * @param input the structure with the input data.
47 */
60 -static void ebpf_update_global_publish(netdata_publish_syscall_t *publish,
61 - netdata_publish_vfs_common_t *pvc,
62 - netdata_syscall_stat_t *input) {
63 -
48 +static void ebpf_update_global_publish(
49 + netdata_publish_syscall_t *publish, netdata_publish_vfs_common_t *pvc, netdata_syscall_stat_t *input)
50 +{
51 netdata_publish_syscall_t *move = publish;
65 - while(move) {
66 - if(input->call != move->pcall) {
52 + while (move) {
53 + if (input->call != move->pcall) {
54 //This condition happens to avoid initial values with dimensions higher than normal values.
68 - if(move->pcall) {
69 - move->ncall = (input->call > move->pcall)?input->call - move->pcall: move->pcall - input->call;
70 - move->nbyte = (input->bytes > move->pbyte)?input->bytes - move->pbyte: move->pbyte - input->bytes;
71 - move->nerr = (input->ecall > move->nerr)?input->ecall - move->perr: move->perr - input->ecall;
55 + if (move->pcall) {
56 + move->ncall = (input->call > move->pcall) ? input->call - move->pcall : move->pcall - input->call;
57 + move->nbyte = (input->bytes > move->pbyte) ? input->bytes - move->pbyte : move->pbyte - input->bytes;
58 + move->nerr = (input->ecall > move->nerr) ? input->ecall - move->perr : move->perr - input->ecall;
59 } else {
60 move->ncall = 0;
61 move->nbyte = 0;
@@ -103,8 +90,8 @@ static void ebpf_update_global_publish(netdata_publish_syscall_t *publish,
90 * @param prev Previous values read from memory.
91 * @param first was it allocated now?
92 */
106 -static void ebpf_process_update_apps_publish(ebpf_process_publish_apps_t *curr,
107 - ebpf_process_publish_apps_t *prev,int first)
93 +static void
94 +ebpf_process_update_apps_publish(ebpf_process_publish_apps_t *curr, ebpf_process_publish_apps_t *prev, int first)
95 {
96 if (first)
97 return;
@@ -116,7 +103,7 @@ static void ebpf_process_update_apps_publish(ebpf_process_publish_apps_t *curr,
103 curr->publish_write_bytes = curr->bytes_written - prev->bytes_written;
104 curr->publish_read_call = curr->call_read - prev->call_read;
105 curr->publish_read_bytes = curr->bytes_read - prev->bytes_read;
119 - curr->publish_process = curr->call_do_fork - prev->call_do_fork;
106 + curr->publish_process = curr->call_do_fork - prev->call_do_fork;
107 curr->publish_thread = curr->call_sys_clone - prev->call_sys_clone;
108 curr->publish_task = curr->call_release_task - prev->call_release_task;
109 curr->publish_open_error = curr->ecall_sys_open - prev->ecall_sys_open;
@@ -131,11 +118,12 @@ static void ebpf_process_update_apps_publish(ebpf_process_publish_apps_t *curr,
118 * @param family the chart family
119 * @param move the pointer with the values that will be published
120 */
134 -static void write_status_chart(char *family, netdata_publish_vfs_common_t *pvc) {
121 +static void write_status_chart(char *family, netdata_publish_vfs_common_t *pvc)
122 +{
123 write_begin_chart(family, NETDATA_PROCESS_STATUS_NAME);
124
137 - write_chart_dimension(status[0], (long long) pvc->running);
138 - write_chart_dimension(status[1], (long long) pvc->zombie);
125 + write_chart_dimension(status[0], (long long)pvc->running);
126 + write_chart_dimension(status[1], (long long)pvc->zombie);
127
128 write_end_chart();
129 }
@@ -145,46 +133,36 @@ static void write_status_chart(char *family, netdata_publish_vfs_common_t *pvc)
133 *
134 * @param em the structure with thread information
135 */
148 -static void ebpf_process_send_data(ebpf_module_t *em) {
136 +static void ebpf_process_send_data(ebpf_module_t *em)
137 +{
138 netdata_publish_vfs_common_t pvc;
139 ebpf_update_global_publish(process_publish_aggregated, &pvc, process_aggregated_data);
140
152 - write_count_chart(NETDATA_FILE_OPEN_CLOSE_COUNT, NETDATA_EBPF_FAMILY, process_publish_aggregated, 2);
141 + write_count_chart(
142 + NETDATA_FILE_OPEN_CLOSE_COUNT, NETDATA_EBPF_FAMILY, process_publish_aggregated, 2);
143
154 - write_count_chart(NETDATA_VFS_FILE_CLEAN_COUNT,
155 - NETDATA_EBPF_FAMILY,
156 - &process_publish_aggregated[NETDATA_DEL_START],
157 - 1);
144 + write_count_chart(
145 + NETDATA_VFS_FILE_CLEAN_COUNT, NETDATA_EBPF_FAMILY, &process_publish_aggregated[NETDATA_DEL_START], 1);
146
159 - write_count_chart(NETDATA_VFS_FILE_IO_COUNT,
160 - NETDATA_EBPF_FAMILY,
161 - &process_publish_aggregated[NETDATA_IN_START_BYTE],
162 - 2);
147 + write_count_chart(
148 + NETDATA_VFS_FILE_IO_COUNT, NETDATA_EBPF_FAMILY, &process_publish_aggregated[NETDATA_IN_START_BYTE], 2);
149
164 - write_count_chart(NETDATA_EXIT_SYSCALL,
165 - NETDATA_EBPF_FAMILY,
166 - &process_publish_aggregated[NETDATA_EXIT_START],
167 - 2);
168 - write_count_chart(NETDATA_PROCESS_SYSCALL,
169 - NETDATA_EBPF_FAMILY,
170 - &process_publish_aggregated[NETDATA_PROCESS_START],
171 - 2);
150 + write_count_chart(
151 + NETDATA_EXIT_SYSCALL, NETDATA_EBPF_FAMILY, &process_publish_aggregated[NETDATA_EXIT_START], 2);
152 + write_count_chart(
153 + NETDATA_PROCESS_SYSCALL, NETDATA_EBPF_FAMILY, &process_publish_aggregated[NETDATA_PROCESS_START], 2);
154
155 write_status_chart(NETDATA_EBPF_FAMILY, &pvc);
174 - if(em->mode < MODE_ENTRY) {
175 - write_err_chart(NETDATA_FILE_OPEN_ERR_COUNT, NETDATA_EBPF_FAMILY, process_publish_aggregated, 2);
176 - write_err_chart(NETDATA_VFS_FILE_ERR_COUNT,
177 - NETDATA_EBPF_FAMILY,
178 - &process_publish_aggregated[2],
179 - NETDATA_VFS_ERRORS);
180 - write_err_chart(NETDATA_PROCESS_ERROR_NAME,
181 - NETDATA_EBPF_FAMILY,
182 - &process_publish_aggregated[NETDATA_PROCESS_START],
183 - 2);
156 + if (em->mode < MODE_ENTRY) {
157 + write_err_chart(
158 + NETDATA_FILE_OPEN_ERR_COUNT, NETDATA_EBPF_FAMILY, process_publish_aggregated, 2);
159 + write_err_chart(
160 + NETDATA_VFS_FILE_ERR_COUNT, NETDATA_EBPF_FAMILY, &process_publish_aggregated[2], NETDATA_VFS_ERRORS);
161 + write_err_chart(
162 + NETDATA_PROCESS_ERROR_NAME, NETDATA_EBPF_FAMILY, &process_publish_aggregated[NETDATA_PROCESS_START], 2);
163 }
164
186 - write_io_chart(NETDATA_VFS_IO_FILE_BYTES, NETDATA_EBPF_FAMILY, process_id_names[3],
187 - process_id_names[4], &pvc);
165 + write_io_chart(NETDATA_VFS_IO_FILE_BYTES, NETDATA_EBPF_FAMILY, process_id_names[3], process_id_names[4], &pvc);
166 }
167
168 /**
@@ -219,7 +197,7 @@ long long ebpf_process_sum_values_for_pids(struct pid_on_target *root, size_t of
197 */
198 void ebpf_process_remove_pids()
199 {
222 - struct pid_stat *pids = root_of_pids;
200 + struct pid_stat *pids = root_of_pids;
201 int pid_fd = map_fd[0];
202 while (pids) {
203 uint32_t pid = pids->pid;
@@ -248,7 +226,7 @@ void ebpf_process_send_apps_data(ebpf_module_t *em, struct target *root)
226 collected_number value;
227
228 write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_SYSCALL_APPS_FILE_OPEN);
251 - for (w = root; w ; w = w->next) {
229 + for (w = root; w; w = w->next) {
230 if (unlikely(w->exposed && w->processes)) {
231 value = ebpf_process_sum_values_for_pids(w->root_pid, offsetof(ebpf_process_publish_apps_t, publish_open));
232 write_chart_dimension(w->name, value);
@@ -258,9 +236,10 @@ void ebpf_process_send_apps_data(ebpf_module_t *em, struct target *root)
236
237 if (em->mode < MODE_ENTRY) {
238 write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_SYSCALL_APPS_FILE_OPEN_ERROR);
261 - for (w = root; w ; w = w->next) {
239 + for (w = root; w; w = w->next) {
240 if (unlikely(w->exposed && w->processes)) {
263 - value = ebpf_process_sum_values_for_pids(w->root_pid, offsetof(ebpf_process_publish_apps_t, publish_open_error));
241 + value = ebpf_process_sum_values_for_pids(
242 + w->root_pid, offsetof(ebpf_process_publish_apps_t, publish_open_error));
243 write_chart_dimension(w->name, value);
244 }
245 }
@@ -268,9 +247,10 @@ void ebpf_process_send_apps_data(ebpf_module_t *em, struct target *root)
247 }
248
249 write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_SYSCALL_APPS_FILE_CLOSED);
271 - for (w = root; w ; w = w->next) {
250 + for (w = root; w; w = w->next) {
251 if (unlikely(w->exposed && w->processes)) {
273 - value = ebpf_process_sum_values_for_pids(w->root_pid, offsetof(ebpf_process_publish_apps_t, publish_closed));
252 + value =
253 + ebpf_process_sum_values_for_pids(w->root_pid, offsetof(ebpf_process_publish_apps_t, publish_closed));
254 write_chart_dimension(w->name, value);
255 }
256 }
@@ -278,9 +258,10 @@ void ebpf_process_send_apps_data(ebpf_module_t *em, struct target *root)
258
259 if (em->mode < MODE_ENTRY) {
260 write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_SYSCALL_APPS_FILE_CLOSE_ERROR);
281 - for (w = root; w ; w = w->next) {
261 + for (w = root; w; w = w->next) {
262 if (unlikely(w->exposed && w->processes)) {
283 - value = ebpf_process_sum_values_for_pids(w->root_pid, offsetof(ebpf_process_publish_apps_t, publish_close_error));
263 + value = ebpf_process_sum_values_for_pids(
264 + w->root_pid, offsetof(ebpf_process_publish_apps_t, publish_close_error));
265 write_chart_dimension(w->name, value);
266 }
267 }
@@ -288,18 +269,20 @@ void ebpf_process_send_apps_data(ebpf_module_t *em, struct target *root)
269 }
270
271 write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_SYSCALL_APPS_FILE_DELETED);
291 - for (w = root; w ; w = w->next) {
272 + for (w = root; w; w = w->next) {
273 if (unlikely(w->exposed && w->processes)) {
293 - value = ebpf_process_sum_values_for_pids(w->root_pid, offsetof(ebpf_process_publish_apps_t, publish_deleted));
274 + value =
275 + ebpf_process_sum_values_for_pids(w->root_pid, offsetof(ebpf_process_publish_apps_t, publish_deleted));
276 write_chart_dimension(w->name, value);
277 }
278 }
279 write_end_chart();
280
281 write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_SYSCALL_APPS_VFS_WRITE_CALLS);
300 - for (w = root; w ; w = w->next) {
282 + for (w = root; w; w = w->next) {
283 if (unlikely(w->exposed && w->processes)) {
302 - value = ebpf_process_sum_values_for_pids(w->root_pid, offsetof(ebpf_process_publish_apps_t, publish_write_call));
284 + value = ebpf_process_sum_values_for_pids(
285 + w->root_pid, offsetof(ebpf_process_publish_apps_t, publish_write_call));
286 write_chart_dimension(w->name, value);
287 }
288 }
@@ -307,9 +290,10 @@ void ebpf_process_send_apps_data(ebpf_module_t *em, struct target *root)
290
291 if (em->mode < MODE_ENTRY) {
292 write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_SYSCALL_APPS_VFS_WRITE_CALLS_ERROR);
310 - for (w = root; w ; w = w->next) {
293 + for (w = root; w; w = w->next) {
294 if (unlikely(w->exposed && w->processes)) {
312 - value = ebpf_process_sum_values_for_pids(w->root_pid, offsetof(ebpf_process_publish_apps_t, publish_write_error));
295 + value = ebpf_process_sum_values_for_pids(
296 + w->root_pid, offsetof(ebpf_process_publish_apps_t, publish_write_error));
297 write_chart_dimension(w->name, value);
298 }
299 }
@@ -317,9 +301,10 @@ void ebpf_process_send_apps_data(ebpf_module_t *em, struct target *root)
301 }
302
303 write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_SYSCALL_APPS_VFS_READ_CALLS);
320 - for (w = root; w ; w = w->next) {
304 + for (w = root; w; w = w->next) {
305 if (unlikely(w->exposed && w->processes)) {
322 - value = ebpf_process_sum_values_for_pids(w->root_pid, offsetof(ebpf_process_publish_apps_t, publish_read_call));
306 + value =
307 + ebpf_process_sum_values_for_pids(w->root_pid, offsetof(ebpf_process_publish_apps_t, publish_read_call));
308 write_chart_dimension(w->name, value);
309 }
310 }
@@ -327,9 +312,10 @@ void ebpf_process_send_apps_data(ebpf_module_t *em, struct target *root)
312
313 if (em->mode < MODE_ENTRY) {
314 write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_SYSCALL_APPS_VFS_READ_CALLS_ERROR);
330 - for (w = root; w ; w = w->next) {
315 + for (w = root; w; w = w->next) {
316 if (unlikely(w->exposed && w->processes)) {
332 - value = ebpf_process_sum_values_for_pids(w->root_pid, offsetof(ebpf_process_publish_apps_t, publish_read_error));
317 + value = ebpf_process_sum_values_for_pids(
318 + w->root_pid, offsetof(ebpf_process_publish_apps_t, publish_read_error));
319 write_chart_dimension(w->name, value);
320 }
321 }
@@ -337,43 +323,47 @@ void ebpf_process_send_apps_data(ebpf_module_t *em, struct target *root)
323 }
324
325 write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_SYSCALL_APPS_VFS_WRITE_BYTES);
340 - for (w = root; w ; w = w->next) {
326 + for (w = root; w; w = w->next) {
327 if (unlikely(w->exposed && w->processes)) {
342 - value = ebpf_process_sum_values_for_pids(w->root_pid, offsetof(ebpf_process_publish_apps_t, publish_write_bytes));
328 + value = ebpf_process_sum_values_for_pids(
329 + w->root_pid, offsetof(ebpf_process_publish_apps_t, publish_write_bytes));
330 write_chart_dimension(w->name, value);
331 }
332 }
333 write_end_chart();
334
335 write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_SYSCALL_APPS_VFS_READ_BYTES);
349 - for (w = root; w ; w = w->next) {
336 + for (w = root; w; w = w->next) {
337 if (unlikely(w->exposed && w->processes)) {
351 - value = ebpf_process_sum_values_for_pids(w->root_pid, offsetof(ebpf_process_publish_apps_t, publish_read_bytes));
338 + value = ebpf_process_sum_values_for_pids(
339 + w->root_pid, offsetof(ebpf_process_publish_apps_t, publish_read_bytes));
340 write_chart_dimension(w->name, value);
341 }
342 }
343 write_end_chart();
344
345 write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_SYSCALL_APPS_TASK_PROCESS);
358 - for (w = root; w ; w = w->next) {
346 + for (w = root; w; w = w->next) {
347 if (unlikely(w->exposed && w->processes)) {
360 - value = ebpf_process_sum_values_for_pids(w->root_pid, offsetof(ebpf_process_publish_apps_t, publish_process));
348 + value =
349 + ebpf_process_sum_values_for_pids(w->root_pid, offsetof(ebpf_process_publish_apps_t, publish_process));
350 write_chart_dimension(w->name, value);
351 }
352 }
353 write_end_chart();
354
355 write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_SYSCALL_APPS_TASK_THREAD);
367 - for (w = root; w ; w = w->next) {
356 + for (w = root; w; w = w->next) {
357 if (unlikely(w->exposed && w->processes)) {
369 - value = ebpf_process_sum_values_for_pids(w->root_pid, offsetof(ebpf_process_publish_apps_t, publish_thread));
358 + value =
359 + ebpf_process_sum_values_for_pids(w->root_pid, offsetof(ebpf_process_publish_apps_t, publish_thread));
360 write_chart_dimension(w->name, value);
361 }
362 }
363 write_end_chart();
364
365 write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_SYSCALL_APPS_TASK_CLOSE);
376 - for (w = root; w ; w = w->next) {
366 + for (w = root; w; w = w->next) {
367 if (unlikely(w->exposed && w->processes)) {
368 value = ebpf_process_sum_values_for_pids(w->root_pid, offsetof(ebpf_process_publish_apps_t, publish_task));
369 write_chart_dimension(w->name, value);
@@ -400,10 +390,10 @@ static void read_hash_global_tables()
390
391 netdata_idx_t *val = process_hash_values;
392 for (idx = 0; idx < NETDATA_GLOBAL_VECTOR; idx++) {
403 - if(!bpf_map_lookup_elem(map_fd[1], &idx, val)) {
393 + if (!bpf_map_lookup_elem(map_fd[1], &idx, val)) {
394 uint64_t total = 0;
395 int i;
406 - int end = (running_on_kernel < NETDATA_KERNEL_V4_15)?1:ebpf_nprocs;
396 + int end = (running_on_kernel < NETDATA_KERNEL_V4_15) ? 1 : ebpf_nprocs;
397 for (i = 0; i < end; i++)
398 total += val[i];
399
@@ -443,7 +433,7 @@ static void read_hash_global_tables()
433 static void ebpf_process_update_apps_data()
434 {
435 size_t i;
446 - for ( i = 0 ; i < all_pids_count; i++) {
436 + for (i = 0; i < all_pids_count; i++) {
437 uint32_t current_pid = pid_index[i];
438 ebpf_process_stat_t *ps = local_process_stats[current_pid];
439 if (!ps)
@@ -483,10 +473,8 @@ static void ebpf_process_update_apps_data()
473 cad->ecall_do_fork = ps->fork_err;
474 cad->ecall_sys_clone = ps->clone_err;
475
486 - cad->bytes_written = (uint64_t)ps->write_bytes +
487 - (uint64_t)ps->write_bytes;
488 - cad->bytes_read = (uint64_t)ps->read_bytes +
489 - (uint64_t)ps->readv_bytes;
476 + cad->bytes_written = (uint64_t)ps->write_bytes + (uint64_t)ps->write_bytes;
477 + cad->bytes_read = (uint64_t)ps->read_bytes + (uint64_t)ps->readv_bytes;
478
479 ebpf_process_update_apps_publish(cad, pad, lstatus);
480 }
@@ -507,7 +495,8 @@ static void ebpf_process_update_apps_data()
495 * @param web the group name used to attach the chart on dashaboard
496 * @param order the order number of the specified chart
497 */
510 -static void ebpf_create_io_chart(char *family, char *name, char *axis, char *web, int order) {
498 +static void ebpf_create_io_chart(char *family, char *name, char *axis, char *web, int order)
499 +{
500 printf("CHART %s.%s '' 'Bytes written and read' '%s' '%s' '' line %d %d\n",
501 family,
502 name,
@@ -529,7 +518,8 @@ static void ebpf_create_io_chart(char *family, char *name, char *axis, char *web
518 * @param web the group name used to attach the chart on dashaboard
519 * @param order the order number of the specified chart
520 */
532 -static void ebpf_process_status_chart(char *family, char *name, char *axis, char *web, int order) {
521 +static void ebpf_process_status_chart(char *family, char *name, char *axis, char *web, int order)
522 +{
523 printf("CHART %s.%s '' 'Process not closed' '%s' '%s' '' line %d %d ''\n",
524 family,
525 name,
@@ -648,7 +638,6 @@ static void ebpf_create_global_charts(ebpf_module_t *em)
638 &process_publish_aggregated[NETDATA_PROCESS_START],
639 2);
640 }
651 -
641 }
642
643 /**
@@ -781,15 +770,18 @@ static void ebpf_create_apps_charts(ebpf_module_t *em, struct target *root)
770 struct target *w;
771 int newly_added = 0;
772
784 - for(w = root ; w ; w = w->next) {
785 - if (w->target) continue;
773 + for (w = root; w; w = w->next) {
774 + if (w->target)
775 + continue;
776
787 - if(unlikely(w->processes && (debug_enabled || w->debug_enabled))) {
777 + if (unlikely(w->processes && (debug_enabled || w->debug_enabled))) {
778 struct pid_on_target *pid_on_target;
779
790 - fprintf(stderr, "ebpf.plugin: target '%s' has aggregated %u process%s:", w->name, w->processes, (w->processes == 1)?"":"es");
780 + fprintf(
781 + stderr, "ebpf.plugin: target '%s' has aggregated %u process%s:", w->name, w->processes,
782 + (w->processes == 1) ? "" : "es");
783
792 - for(pid_on_target = w->root_pid; pid_on_target; pid_on_target = pid_on_target->next) {
784 + for (pid_on_target = w->root_pid; pid_on_target; pid_on_target = pid_on_target->next) {
785 fprintf(stderr, " %d", pid_on_target->pid);
786 }
787
@@ -804,7 +796,8 @@ static void ebpf_create_apps_charts(ebpf_module_t *em, struct target *root)
796 }
797 }
798
807 - if (!newly_added) return;
799 + if (!newly_added)
800 + return;
801
802 if (ebpf_modules[EBPF_MODULE_PROCESS_IDX].apps_charts)
803 ebpf_process_create_apps_charts(em, root);
@@ -840,10 +833,7 @@ static void process_collector(usec_t step, ebpf_module_t *em)
833
834 pthread_mutex_lock(&collect_data_mutex);
835 cleanup_exited_pids(local_process_stats);
843 - collect_data_for_all_processes(local_process_stats,
844 - pid_index,
845 - process_functions.bpf_map_lookup_elem,
846 - pid_fd);
836 + collect_data_for_all_processes(local_process_stats, pid_index, pid_fd);
837
838 ebpf_create_apps_charts(em, apps_groups_root_target);
839
@@ -851,7 +841,7 @@ static void process_collector(usec_t step, ebpf_module_t *em)
841 pthread_mutex_unlock(&collect_data_mutex);
842
843 int publish_apps = 0;
854 - if (apps_enabled && all_pids_count > 0){
844 + if (apps_enabled && all_pids_count > 0) {
845 publish_apps = 1;
846 ebpf_process_update_apps_data();
847 }
@@ -891,11 +881,7 @@ static void ebpf_process_cleanup(void *ptr)
881
882 freez(local_process_stats);
883
894 - if (process_functions.libnetdata) {
895 - dlclose(process_functions.libnetdata);
896 - }
897 -
898 - freez(process_functions.map_fd);
884 + freez(process_data.map_fd);
885 freez(current_apps_data);
886 freez(prev_apps_data);
887 }
@@ -913,7 +899,8 @@ static void ebpf_process_cleanup(void *ptr)
899 *
900 * @param length is the length for the vectors used inside the collector.
901 */
916 -static void ebpf_process_allocate_global_vectors(size_t length) {
902 +static void ebpf_process_allocate_global_vectors(size_t length)
903 +{
904 process_aggregated_data = callocz(length, sizeof(netdata_syscall_stat_t));
905 process_publish_aggregated = callocz(length, sizeof(netdata_publish_syscall_t));
906 process_hash_values = callocz(ebpf_nprocs, sizeof(netdata_idx_t));
@@ -923,17 +910,19 @@ static void ebpf_process_allocate_global_vectors(size_t length) {
910 prev_apps_data = callocz((size_t)pid_max, sizeof(ebpf_process_publish_apps_t *));
911 }
912
926 -void change_process_event() {
913 +void change_process_event()
914 +{
915 int i;
916 if (running_on_kernel < NETDATA_KERNEL_V5_3)
917 process_probes[EBPF_SYS_CLONE_IDX].name = NULL;
918
931 - for (i = 0; process_probes[i].name ; i++ ) {
919 + for (i = 0; process_probes[i].name; i++) {
920 process_probes[i].type = 'p';
921 }
922 }
923
936 -static void change_syscalls() {
924 +static void change_syscalls()
925 +{
926 static char *lfork = { "do_fork" };
927 process_id_names[7] = lfork;
928 process_probes[8].name = lfork;
@@ -943,16 +932,11 @@ static void change_syscalls() {
932 * Set local variables
933 *
934 */
946 -static void set_local_pointers() {
947 -#ifndef STATIC
948 - bpf_map_lookup_elem = process_functions.bpf_map_lookup_elem;
949 -
950 - bpf_map_delete_elem = process_functions.bpf_map_delete_elem;
951 -#endif
952 -
953 - map_fd = process_functions.map_fd;
935 +static void set_local_pointers()
936 +{
937 + map_fd = process_data.map_fd;
938
955 - if (process_functions.isrh >= NETDATA_MINIMUM_RH_VERSION && process_functions.isrh < NETDATA_RH_8)
939 + if (process_data.isrh >= NETDATA_MINIMUM_RH_VERSION && process_data.isrh < NETDATA_RH_8)
940 change_syscalls();
941 }
942
@@ -974,7 +958,7 @@ static void wait_for_all_threads_die()
958
959 int max = 10;
960 int i;
977 - for (i = 0; i < max ; i++) {
961 + for (i = 0; i < max; i++) {
962 heartbeat_next(&hb, 200000);
963
964 size_t j, counter = 0, compare = 0;
@@ -1005,25 +989,26 @@ void *ebpf_process_thread(void *ptr)
989
990 ebpf_module_t *em = (ebpf_module_t *)ptr;
991 process_enabled = em->enabled;
1008 - fill_ebpf_functions(&process_functions);
992 + fill_ebpf_data(&process_data);
993
994 pthread_mutex_lock(&lock);
995 ebpf_process_allocate_global_vectors(NETDATA_MAX_MONITOR_VECTOR);
996
1013 - if (ebpf_load_libraries(&process_functions, "libnetdata_ebpf.so", ebpf_plugin_dir)) {
997 + if (ebpf_update_kernel(&process_data)) {
998 pthread_mutex_unlock(&lock);
999 goto endprocess;
1000 }
1001
1002 set_local_pointers();
1019 - if (ebpf_load_program(ebpf_plugin_dir, em->thread_id, em->mode, kernel_string,
1020 - em->thread_name, process_functions.map_fd, process_functions.load_bpf_file) ) {
1003 + if (ebpf_load_program(
1004 + ebpf_plugin_dir, em->thread_id, em->mode, kernel_string, em->thread_name, process_data.map_fd)) {
1005 pthread_mutex_unlock(&lock);
1006 goto endprocess;
1007 }
1008
1025 - ebpf_global_labels(process_aggregated_data, process_publish_aggregated, process_dimension_names,
1026 - process_id_names, NETDATA_MAX_MONITOR_VECTOR);
1009 + ebpf_global_labels(
1010 + process_aggregated_data, process_publish_aggregated, process_dimension_names, process_id_names,
1011 + NETDATA_MAX_MONITOR_VECTOR);
1012
1013 if (process_enabled) {
1014 ebpf_create_global_charts(em);
@@ -1031,7 +1016,7 @@ void *ebpf_process_thread(void *ptr)
1016
1017 pthread_mutex_unlock(&lock);
1018
1034 - process_collector((usec_t)(em->update_time*USEC_PER_SEC), em);
1019 + process_collector((usec_t)(em->update_time * USEC_PER_SEC), em);
1020
1021 endprocess:
1022 wait_for_all_threads_die();
collectors/ebpf.plugin/ebpf_process.h
+64 -62
@@ -1,59 +1,60 @@
1 -#ifndef _NETDATA_EBPF_PROCESS_H_
2 -# define _NETDATA_EBPF_PROCESS_H_ 1
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2
4 -//Groups used on Dashboard
5 -# define NETDATA_FILE_GROUP "File"
6 -# define NETDATA_VFS_GROUP "VFS"
7 -# define NETDATA_PROCESS_GROUP "Process"
3 +#ifndef NETDATA_EBPF_PROCESS_H
4 +#define NETDATA_EBPF_PROCESS_H 1
5
9 -//Internal constants
10 -# define NETDATA_GLOBAL_VECTOR 24
11 -# define NETDATA_MAX_MONITOR_VECTOR 9
12 -# define NETDATA_VFS_ERRORS 3
6 +// Groups used on Dashboard
7 +#define NETDATA_FILE_GROUP "File"
8 +#define NETDATA_VFS_GROUP "VFS"
9 +#define NETDATA_PROCESS_GROUP "Process"
10
14 -//Map index
15 -# define NETDATA_DEL_START 2
16 -# define NETDATA_IN_START_BYTE 3
17 -# define NETDATA_EXIT_START 5
18 -# define NETDATA_PROCESS_START 7
11 +// Internal constants
12 +#define NETDATA_GLOBAL_VECTOR 24
13 +#define NETDATA_MAX_MONITOR_VECTOR 9
14 +#define NETDATA_VFS_ERRORS 3
15 +
16 +// Map index
17 +#define NETDATA_DEL_START 2
18 +#define NETDATA_IN_START_BYTE 3
19 +#define NETDATA_EXIT_START 5
20 +#define NETDATA_PROCESS_START 7
21
22 // Global chart name
21 -# define NETDATA_FILE_OPEN_CLOSE_COUNT "file_descriptor"
22 -# define NETDATA_FILE_OPEN_ERR_COUNT "file_error"
23 -# define NETDATA_VFS_FILE_CLEAN_COUNT "deleted_objects"
24 -# define NETDATA_VFS_FILE_IO_COUNT "io"
25 -# define NETDATA_VFS_FILE_ERR_COUNT "io_error"
23 +#define NETDATA_FILE_OPEN_CLOSE_COUNT "file_descriptor"
24 +#define NETDATA_FILE_OPEN_ERR_COUNT "file_error"
25 +#define NETDATA_VFS_FILE_CLEAN_COUNT "deleted_objects"
26 +#define NETDATA_VFS_FILE_IO_COUNT "io"
27 +#define NETDATA_VFS_FILE_ERR_COUNT "io_error"
28
27 -# define NETDATA_EXIT_SYSCALL "exit"
28 -# define NETDATA_PROCESS_SYSCALL "process_thread"
29 -# define NETDATA_PROCESS_ERROR_NAME "task_error"
30 -# define NETDATA_PROCESS_STATUS_NAME "process_status"
29 +#define NETDATA_EXIT_SYSCALL "exit"
30 +#define NETDATA_PROCESS_SYSCALL "process_thread"
31 +#define NETDATA_PROCESS_ERROR_NAME "task_error"
32 +#define NETDATA_PROCESS_STATUS_NAME "process_status"
33
32 -# define NETDATA_VFS_IO_FILE_BYTES "io_bytes"
33 -# define NETDATA_VFS_DIM_IN_FILE_BYTES "write"
34 -# define NETDATA_VFS_DIM_OUT_FILE_BYTES "read"
34 +#define NETDATA_VFS_IO_FILE_BYTES "io_bytes"
35 +#define NETDATA_VFS_DIM_IN_FILE_BYTES "write"
36 +#define NETDATA_VFS_DIM_OUT_FILE_BYTES "read"
37
38 // Charts created on Apps submenu
37 -# define NETDATA_SYSCALL_APPS_FILE_OPEN "file_open"
38 -# define NETDATA_SYSCALL_APPS_FILE_CLOSED "file_closed"
39 -# define NETDATA_SYSCALL_APPS_FILE_DELETED "file_deleted"
40 -# define NETDATA_SYSCALL_APPS_VFS_WRITE_CALLS "vfs_write_call"
41 -# define NETDATA_SYSCALL_APPS_VFS_READ_CALLS "vfs_read_call"
42 -# define NETDATA_SYSCALL_APPS_VFS_WRITE_BYTES "vfs_write_bytes"
43 -# define NETDATA_SYSCALL_APPS_VFS_READ_BYTES "vfs_read_bytes"
44 -# define NETDATA_SYSCALL_APPS_TASK_PROCESS "process_create"
45 -# define NETDATA_SYSCALL_APPS_TASK_THREAD "thread_create"
46 -# define NETDATA_SYSCALL_APPS_TASK_CLOSE "task_close"
39 +#define NETDATA_SYSCALL_APPS_FILE_OPEN "file_open"
40 +#define NETDATA_SYSCALL_APPS_FILE_CLOSED "file_closed"
41 +#define NETDATA_SYSCALL_APPS_FILE_DELETED "file_deleted"
42 +#define NETDATA_SYSCALL_APPS_VFS_WRITE_CALLS "vfs_write_call"
43 +#define NETDATA_SYSCALL_APPS_VFS_READ_CALLS "vfs_read_call"
44 +#define NETDATA_SYSCALL_APPS_VFS_WRITE_BYTES "vfs_write_bytes"
45 +#define NETDATA_SYSCALL_APPS_VFS_READ_BYTES "vfs_read_bytes"
46 +#define NETDATA_SYSCALL_APPS_TASK_PROCESS "process_create"
47 +#define NETDATA_SYSCALL_APPS_TASK_THREAD "thread_create"
48 +#define NETDATA_SYSCALL_APPS_TASK_CLOSE "task_close"
49
50 // Charts created on Apps submenu, if and only if, the return mode is active
51
50 -# define NETDATA_SYSCALL_APPS_FILE_OPEN_ERROR "file_open_error"
51 -# define NETDATA_SYSCALL_APPS_FILE_CLOSE_ERROR "file_close_error"
52 -# define NETDATA_SYSCALL_APPS_VFS_WRITE_CALLS_ERROR "vfs_write_error"
53 -# define NETDATA_SYSCALL_APPS_VFS_READ_CALLS_ERROR "vfs_read_error"
54 -
52 +#define NETDATA_SYSCALL_APPS_FILE_OPEN_ERROR "file_open_error"
53 +#define NETDATA_SYSCALL_APPS_FILE_CLOSE_ERROR "file_close_error"
54 +#define NETDATA_SYSCALL_APPS_VFS_WRITE_CALLS_ERROR "vfs_write_error"
55 +#define NETDATA_SYSCALL_APPS_VFS_READ_CALLS_ERROR "vfs_read_error"
56
56 -//Index from kernel
57 +// Index from kernel
58 typedef enum ebpf_process_index {
59 NETDATA_KEY_CALLS_DO_SYS_OPEN,
60 NETDATA_KEY_ERROR_DO_SYS_OPEN,
@@ -93,7 +94,7 @@ typedef enum ebpf_process_index {
94 } ebpf_process_index_t;
95
96 typedef struct ebpf_process_publish_apps {
96 - //Number of calls during the last read
97 + // Number of calls during the last read
98 uint64_t call_sys_open;
99 uint64_t call_close_fd;
100 uint64_t call_vfs_unlink;
@@ -104,7 +105,7 @@ typedef struct ebpf_process_publish_apps {
105 uint64_t call_do_fork;
106 uint64_t call_sys_clone;
107
107 - //Number of errors during the last read
108 + // Number of errors during the last read
109 uint64_t ecall_sys_open;
110 uint64_t ecall_close_fd;
111 uint64_t ecall_vfs_unlink;
@@ -113,24 +114,25 @@ typedef struct ebpf_process_publish_apps {
114 uint64_t ecall_do_fork;
115 uint64_t ecall_sys_clone;
116
116 - //Number of bytes during the last read
117 + // Number of bytes during the last read
118 uint64_t bytes_written;
119 uint64_t bytes_read;
120
120 - //Dimensions sent to chart
121 - uint64_t publish_open ;
122 - uint64_t publish_closed ;
123 - uint64_t publish_deleted ;
124 - uint64_t publish_write_call ;
125 - uint64_t publish_write_bytes ;
126 - uint64_t publish_read_call ;
127 - uint64_t publish_read_bytes ;
121 + // Dimensions sent to chart
122 + uint64_t publish_open;
123 + uint64_t publish_closed;
124 + uint64_t publish_deleted;
125 + uint64_t publish_write_call;
126 + uint64_t publish_write_bytes;
127 + uint64_t publish_read_call;
128 + uint64_t publish_read_bytes;
129 uint64_t publish_process;
129 - uint64_t publish_thread ;
130 - uint64_t publish_task ;
131 - uint64_t publish_open_error ;
132 - uint64_t publish_close_error ;
133 - uint64_t publish_write_error ;
134 - uint64_t publish_read_error ;
135 -}ebpf_process_publish_apps_t;
136 -# endif
130 + uint64_t publish_thread;
131 + uint64_t publish_task;
132 + uint64_t publish_open_error;
133 + uint64_t publish_close_error;
134 + uint64_t publish_write_error;
135 + uint64_t publish_read_error;
136 +} ebpf_process_publish_apps_t;
137 +
138 +#endif /* NETDATA_EBPF_PROCESS_H */
collectors/ebpf.plugin/ebpf_socket.c
+59 -75
@@ -12,14 +12,14 @@
12 *****************************************************************/
13
14 static char *socket_dimension_names[NETDATA_MAX_SOCKET_VECTOR] = { "sent", "received", "close", "sent", "received" };
15 -static char *socket_id_names[NETDATA_MAX_SOCKET_VECTOR] = { "tcp_sendmsg", "tcp_cleanup_rbuf", "tcp_close", "udp_sendmsg",
16 - "udp_recvmsg" };
15 +static char *socket_id_names[NETDATA_MAX_SOCKET_VECTOR] = { "tcp_sendmsg", "tcp_cleanup_rbuf", "tcp_close",
16 + "udp_sendmsg", "udp_recvmsg" };
17
18 static netdata_idx_t *socket_hash_values = NULL;
19 static netdata_syscall_stat_t *socket_aggregated_data = NULL;
20 static netdata_publish_syscall_t *socket_publish_aggregated = NULL;
21
22 -static ebpf_functions_t socket_functions;
22 +static ebpf_data_t socket_data;
23
24 static ebpf_socket_publish_apps_t **socket_bandwidth_curr = NULL;
25 static ebpf_socket_publish_apps_t **socket_bandwidth_prev = NULL;
@@ -27,20 +27,7 @@ static ebpf_bandwidth_t *bandwidth_vector = NULL;
27
28 static int socket_apps_created = 0;
29
30 -#ifndef STATIC
31 -/**
32 - * Pointers used when collector is dynamically linked
33 - */
34 -
35 -//Libbpf (It is necessary to have at least kernel 4.10)
36 -static int (*bpf_map_lookup_elem)(int, const void *, void *);
37 -static int (*bpf_map_delete_elem)(int fd, const void *key);
38 -
30 static int *map_fd = NULL;
40 -/**
41 - * End of the pointers
42 - */
43 -#endif
31
32 /*****************************************************************
33 *
@@ -56,19 +43,18 @@ static int *map_fd = NULL;
43 * @param udp structure to store IO from udp sockets
44 * @param input the structure with the input data.
45 */
59 -static void ebpf_update_global_publish(netdata_publish_syscall_t *publish,
60 - netdata_publish_vfs_common_t *tcp,
61 - netdata_publish_vfs_common_t *udp,
62 - netdata_syscall_stat_t *input) {
63 -
46 +static void ebpf_update_global_publish(
47 + netdata_publish_syscall_t *publish, netdata_publish_vfs_common_t *tcp, netdata_publish_vfs_common_t *udp,
48 + netdata_syscall_stat_t *input)
49 +{
50 netdata_publish_syscall_t *move = publish;
65 - while(move) {
66 - if(input->call != move->pcall) {
51 + while (move) {
52 + if (input->call != move->pcall) {
53 //This condition happens to avoid initial values with dimensions higher than normal values.
68 - if(move->pcall) {
69 - move->ncall = (input->call > move->pcall)?input->call - move->pcall: move->pcall - input->call;
70 - move->nbyte = (input->bytes > move->pbyte)?input->bytes - move->pbyte: move->pbyte - input->bytes;
71 - move->nerr = (input->ecall > move->nerr)?input->ecall - move->perr: move->perr - input->ecall;
54 + if (move->pcall) {
55 + move->ncall = (input->call > move->pcall) ? input->call - move->pcall : move->pcall - input->call;
56 + move->nbyte = (input->bytes > move->pbyte) ? input->bytes - move->pbyte : move->pbyte - input->bytes;
57 + move->nerr = (input->ecall > move->nerr) ? input->ecall - move->perr : move->perr - input->ecall;
58 } else {
59 move->ncall = 0;
60 move->nbyte = 0;
@@ -101,8 +87,7 @@ static void ebpf_update_global_publish(netdata_publish_syscall_t *publish,
87 * @param curr Last values read from memory.
88 * @param prev Previous values read from memory.
89 */
104 -static void ebpf_socket_update_apps_publish(ebpf_socket_publish_apps_t *curr,
105 - ebpf_socket_publish_apps_t *prev)
90 +static void ebpf_socket_update_apps_publish(ebpf_socket_publish_apps_t *curr, ebpf_socket_publish_apps_t *prev)
91 {
92 curr->publish_recv = curr->received - prev->received;
93 curr->publish_sent = curr->sent - prev->sent;
@@ -113,23 +98,28 @@ static void ebpf_socket_update_apps_publish(ebpf_socket_publish_apps_t *curr,
98 *
99 * @param em the structure with thread information
100 */
116 -static void ebpf_socket_send_data(ebpf_module_t *em) {
101 +static void ebpf_socket_send_data(ebpf_module_t *em)
102 +{
103 netdata_publish_vfs_common_t common_tcp;
104 netdata_publish_vfs_common_t common_udp;
105 ebpf_update_global_publish(socket_publish_aggregated, &common_tcp, &common_udp, socket_aggregated_data);
106
121 - write_count_chart(NETDATA_TCP_FUNCTION_COUNT, NETDATA_EBPF_FAMILY, socket_publish_aggregated, 3);
122 - write_io_chart(NETDATA_TCP_FUNCTION_BYTES, NETDATA_EBPF_FAMILY, socket_id_names[0], socket_id_names[1], &common_tcp);
107 + write_count_chart(
108 + NETDATA_TCP_FUNCTION_COUNT, NETDATA_EBPF_FAMILY, socket_publish_aggregated, 3);
109 + write_io_chart(
110 + NETDATA_TCP_FUNCTION_BYTES, NETDATA_EBPF_FAMILY, socket_id_names[0], socket_id_names[1], &common_tcp);
111 if (em->mode < MODE_ENTRY) {
124 - write_err_chart(NETDATA_TCP_FUNCTION_ERROR, NETDATA_EBPF_FAMILY, socket_publish_aggregated, 2);
112 + write_err_chart(
113 + NETDATA_TCP_FUNCTION_ERROR, NETDATA_EBPF_FAMILY, socket_publish_aggregated, 2);
114 }
115
127 - write_count_chart(NETDATA_UDP_FUNCTION_COUNT, NETDATA_EBPF_FAMILY,
128 - &socket_publish_aggregated[NETDATA_UDP_START], 2);
129 - write_io_chart(NETDATA_UDP_FUNCTION_BYTES, NETDATA_EBPF_FAMILY, socket_id_names[3], socket_id_names[4], &common_udp);
116 + write_count_chart(
117 + NETDATA_UDP_FUNCTION_COUNT, NETDATA_EBPF_FAMILY, &socket_publish_aggregated[NETDATA_UDP_START], 2);
118 + write_io_chart(
119 + NETDATA_UDP_FUNCTION_BYTES, NETDATA_EBPF_FAMILY, socket_id_names[3], socket_id_names[4], &common_udp);
120 if (em->mode < MODE_ENTRY) {
131 - write_err_chart(NETDATA_UDP_FUNCTION_ERROR, NETDATA_EBPF_FAMILY,
132 - &socket_publish_aggregated[NETDATA_UDP_START], 2);
121 + write_err_chart(
122 + NETDATA_UDP_FUNCTION_ERROR, NETDATA_EBPF_FAMILY, &socket_publish_aggregated[NETDATA_UDP_START], 2);
123 }
124 }
125
@@ -166,7 +156,7 @@ long long ebpf_socket_sum_values_for_pids(struct pid_on_target *root, size_t off
156 */
157 void ebpf_socket_send_apps_data(ebpf_module_t *em, struct target *root)
158 {
169 - (void)em;
159 + UNUSED(em);
160 if (!socket_apps_created)
161 return;
162
@@ -174,7 +164,7 @@ void ebpf_socket_send_apps_data(ebpf_module_t *em, struct target *root)
164 collected_number value;
165
166 write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_NET_APPS_BANDWIDTH_SENT);
177 - for (w = root; w ; w = w->next) {
167 + for (w = root; w; w = w->next) {
168 if (unlikely(w->exposed && w->processes)) {
169 value = ebpf_socket_sum_values_for_pids(w->root_pid, offsetof(ebpf_socket_publish_apps_t, publish_sent));
170 write_chart_dimension(w->name, value);
@@ -183,7 +173,7 @@ void ebpf_socket_send_apps_data(ebpf_module_t *em, struct target *root)
173 write_end_chart();
174
175 write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_NET_APPS_BANDWIDTH_RECV);
186 - for (w = root; w ; w = w->next) {
176 + for (w = root; w; w = w->next) {
177 if (unlikely(w->exposed && w->processes)) {
178 value = ebpf_socket_sum_values_for_pids(w->root_pid, offsetof(ebpf_socket_publish_apps_t, publish_recv));
179 write_chart_dimension(w->name, value);
@@ -205,7 +195,8 @@ void ebpf_socket_send_apps_data(ebpf_module_t *em, struct target *root)
195 *
196 * @param em a pointer to the structure with the default values.
197 */
208 -static void ebpf_create_global_charts(ebpf_module_t *em) {
198 +static void ebpf_create_global_charts(ebpf_module_t *em)
199 +{
200 ebpf_create_chart(NETDATA_EBPF_FAMILY,
201 NETDATA_TCP_FUNCTION_COUNT,
202 "Calls to internal functions",
@@ -280,7 +271,7 @@ static void ebpf_create_global_charts(ebpf_module_t *em) {
271 */
272 void ebpf_socket_create_apps_charts(ebpf_module_t *em, struct target *root)
273 {
283 - (void)em;
274 + UNUSED(em);
275 ebpf_create_charts_on_apps(NETDATA_NET_APPS_BANDWIDTH_SENT,
276 "Bytes sent",
277 EBPF_COMMON_DIMENSION_BYTESS,
@@ -314,7 +305,7 @@ static void read_hash_global_tables()
305
306 netdata_idx_t *val = socket_hash_values;
307 int fd = map_fd[4];
317 - for (idx = 0; idx < NETDATA_SOCKET_COUNTER ; idx++) {
308 + for (idx = 0; idx < NETDATA_SOCKET_COUNTER; idx++) {
309 if (!bpf_map_lookup_elem(fd, &idx, val)) {
310 uint64_t total = 0;
311 int i;
@@ -353,7 +344,7 @@ static void read_hash_global_tables()
344 */
345 void ebpf_socket_fill_publish_apps(uint32_t current_pid, ebpf_bandwidth_t *eb)
346 {
356 - ebpf_socket_publish_apps_t *curr= socket_bandwidth_curr[current_pid];
347 + ebpf_socket_publish_apps_t *curr = socket_bandwidth_curr[current_pid];
348 ebpf_socket_publish_apps_t *prev = socket_bandwidth_prev[current_pid];
349 if (!curr) {
350 ebpf_socket_publish_apps_t *ptr = callocz(2, sizeof(ebpf_socket_publish_apps_t));
@@ -378,7 +369,7 @@ void ebpf_socket_fill_publish_apps(uint32_t current_pid, ebpf_bandwidth_t *eb)
369 */
370 void ebpf_socket_bandwidth_accumulator(ebpf_bandwidth_t *out)
371 {
381 - int i, end = (running_on_kernel >= NETDATA_KERNEL_V4_15)?ebpf_nprocs:1;
372 + int i, end = (running_on_kernel >= NETDATA_KERNEL_V4_15) ? ebpf_nprocs : 1;
373 ebpf_bandwidth_t *total = &out[0];
374 for (i = 1; i < end; i++) {
375 ebpf_bandwidth_t *move = &out[i];
@@ -395,7 +386,7 @@ static void ebpf_socket_update_apps_data()
386 int fd = map_fd[0];
387 ebpf_bandwidth_t *eb = bandwidth_vector;
388 uint32_t key;
398 - struct pid_stat *pids = root_of_pids;
389 + struct pid_stat *pids = root_of_pids;
390 while (pids) {
391 key = pids->pid;
392
@@ -421,7 +412,6 @@ static void ebpf_socket_update_apps_data()
412 *
413 *****************************************************************/
414
424 -
415 /**
416 * Main loop for this collector.
417 *
@@ -430,14 +420,14 @@ static void ebpf_socket_update_apps_data()
420 */
421 static void socket_collector(usec_t step, ebpf_module_t *em)
422 {
433 - (void)em;
434 - (void)step;
423 + UNUSED(em);
424 + UNUSED(step);
425 heartbeat_t hb;
426 heartbeat_init(&hb);
427
428 int socket_apps_enabled = ebpf_modules[EBPF_MODULE_SOCKET_IDX].apps_charts;
429 int socket_global_enabled = ebpf_modules[EBPF_MODULE_SOCKET_IDX].global_charts;
440 - while(!close_ebpf_plugin) {
430 + while (!close_ebpf_plugin) {
431 pthread_mutex_lock(&collect_data_mutex);
432 pthread_cond_wait(&collect_data_cond_var, &collect_data_mutex);
433
@@ -475,16 +465,12 @@ static void socket_collector(usec_t step, ebpf_module_t *em)
465 */
466 static void ebpf_socket_cleanup(void *ptr)
467 {
478 - (void)ptr;
468 + UNUSED(ptr);
469 freez(socket_aggregated_data);
470 freez(socket_publish_aggregated);
471 freez(socket_hash_values);
472
483 - if (socket_functions.libnetdata) {
484 - dlclose(socket_functions.libnetdata);
485 - }
486 -
487 - freez(socket_functions.map_fd);
473 + freez(socket_data.map_fd);
474 freez(socket_bandwidth_curr);
475 freez(socket_bandwidth_prev);
476 freez(bandwidth_vector);
@@ -505,17 +491,19 @@ static void ebpf_socket_cleanup(void *ptr)
491 *
492 * @param length is the length for the vectors used inside the collector.
493 */
508 -static void ebpf_socket_allocate_global_vectors(size_t length) {
494 +static void ebpf_socket_allocate_global_vectors(size_t length)
495 +{
496 socket_aggregated_data = callocz(length, sizeof(netdata_syscall_stat_t));
497 socket_publish_aggregated = callocz(length, sizeof(netdata_publish_syscall_t));
498 socket_hash_values = callocz(ebpf_nprocs, sizeof(netdata_idx_t));
499
500 socket_bandwidth_curr = callocz((size_t)pid_max, sizeof(ebpf_socket_publish_apps_t *));
501 socket_bandwidth_prev = callocz((size_t)pid_max, sizeof(ebpf_socket_publish_apps_t *));
515 - bandwidth_vector = callocz((size_t) ebpf_nprocs, sizeof(ebpf_bandwidth_t));
502 + bandwidth_vector = callocz((size_t)ebpf_nprocs, sizeof(ebpf_bandwidth_t));
503 }
504
518 -void change_socket_event() {
505 +void change_socket_event()
506 +{
507 socket_probes[0].type = 'p';
508 socket_probes[4].type = 'p';
509 socket_probes[5].type = 'p';
@@ -525,14 +513,9 @@ void change_socket_event() {
513 /**
514 * Set local function pointers, this function will never be compiled with static libraries
515 */
528 -static void set_local_pointers(ebpf_module_t *em) {
529 -#ifndef STATIC
530 - bpf_map_lookup_elem = socket_functions.bpf_map_lookup_elem;
531 - (void) bpf_map_lookup_elem;
532 - bpf_map_delete_elem = socket_functions.bpf_map_delete_elem;
533 - (void) bpf_map_delete_elem;
534 -#endif
535 - map_fd = socket_functions.map_fd;
516 +static void set_local_pointers(ebpf_module_t *em)
517 +{
518 + map_fd = socket_data.map_fd;
519
520 if (em->mode == MODE_ENTRY) {
521 change_socket_event();
@@ -559,7 +542,7 @@ void *ebpf_socket_thread(void *ptr)
542 netdata_thread_cleanup_push(ebpf_socket_cleanup, ptr);
543
544 ebpf_module_t *em = (ebpf_module_t *)ptr;
562 - fill_ebpf_functions(&socket_functions);
545 + fill_ebpf_data(&socket_data);
546
547 if (!em->enabled)
548 goto endsocket;
@@ -568,26 +551,27 @@ void *ebpf_socket_thread(void *ptr)
551
552 ebpf_socket_allocate_global_vectors(NETDATA_MAX_SOCKET_VECTOR);
553
571 - if (ebpf_load_libraries(&socket_functions, "libnetdata_ebpf.so", ebpf_plugin_dir)) {
554 + if (ebpf_update_kernel(&socket_data)) {
555 pthread_mutex_unlock(&lock);
556 goto endsocket;
557 }
558
559 set_local_pointers(em);
577 - if (ebpf_load_program(ebpf_plugin_dir, em->thread_id, em->mode, kernel_string,
578 - em->thread_name, socket_functions.map_fd, socket_functions.load_bpf_file) ) {
560 + if (ebpf_load_program(
561 + ebpf_plugin_dir, em->thread_id, em->mode, kernel_string, em->thread_name, socket_data.map_fd)) {
562 pthread_mutex_unlock(&lock);
563 goto endsocket;
564 }
565
583 - ebpf_global_labels(socket_aggregated_data, socket_publish_aggregated, socket_dimension_names,
584 - socket_id_names, NETDATA_MAX_SOCKET_VECTOR);
566 + ebpf_global_labels(
567 + socket_aggregated_data, socket_publish_aggregated, socket_dimension_names, socket_id_names,
568 + NETDATA_MAX_SOCKET_VECTOR);
569
570 ebpf_create_global_charts(em);
571
572 pthread_mutex_unlock(&lock);
573
590 - socket_collector((usec_t)(em->update_time*USEC_PER_SEC), em);
574 + socket_collector((usec_t)(em->update_time * USEC_PER_SEC), em);
575
576 endsocket:
577 netdata_thread_cleanup_pop(1);
collectors/ebpf.plugin/ebpf_socket.h
+20 -18
@@ -1,11 +1,13 @@
1 -#ifndef _NETDATA_EBPF_SOCKET_H_
2 -# define _NETDATA_EBPF_SOCKET_H_ 1
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2
4 -# define NETDATA_SOCKET_COUNTER 13
3 +#ifndef NETDATA_EBPF_SOCKET_H
4 +#define NETDATA_EBPF_SOCKET_H 1
5
6 -# define NETDATA_MAX_SOCKET_VECTOR 5
6 +#define NETDATA_SOCKET_COUNTER 13
7
8 -# define NETDATA_UDP_START 3
8 +#define NETDATA_MAX_SOCKET_VECTOR 5
9 +
10 +#define NETDATA_UDP_START 3
11
12 typedef enum ebpf_socket_idx {
13 NETDATA_KEY_CALLS_TCP_SENDMSG,
@@ -27,28 +29,28 @@ typedef enum ebpf_socket_idx {
29 NETDATA_KEY_BYTES_UDP_SENDMSG
30 } ebpf_socket_index_t;
31
30 -# define NETDATA_SOCKET_GROUP "Socket"
32 +#define NETDATA_SOCKET_GROUP "Socket"
33
32 -//Global chart name
33 -# define NETDATA_TCP_FUNCTION_COUNT "tcp_functions"
34 -# define NETDATA_TCP_FUNCTION_BYTES "tcp_bandwidth"
35 -# define NETDATA_TCP_FUNCTION_ERROR "tcp_error"
36 -# define NETDATA_UDP_FUNCTION_COUNT "udp_functions"
37 -# define NETDATA_UDP_FUNCTION_BYTES "udp_bandwidth"
38 -# define NETDATA_UDP_FUNCTION_ERROR "udp_error"
34 +// Global chart name
35 +#define NETDATA_TCP_FUNCTION_COUNT "tcp_functions"
36 +#define NETDATA_TCP_FUNCTION_BYTES "tcp_bandwidth"
37 +#define NETDATA_TCP_FUNCTION_ERROR "tcp_error"
38 +#define NETDATA_UDP_FUNCTION_COUNT "udp_functions"
39 +#define NETDATA_UDP_FUNCTION_BYTES "udp_bandwidth"
40 +#define NETDATA_UDP_FUNCTION_ERROR "udp_error"
41
42 // Charts created on Apps submenu
41 -# define NETDATA_NET_APPS_BANDWIDTH_SENT "bandwidth_sent"
42 -# define NETDATA_NET_APPS_BANDWIDTH_RECV "bandwidth_recv"
43 +#define NETDATA_NET_APPS_BANDWIDTH_SENT "bandwidth_sent"
44 +#define NETDATA_NET_APPS_BANDWIDTH_RECV "bandwidth_recv"
45
46 typedef struct ebpf_socket_publish_apps {
45 - //Data read
47 + // Data read
48 uint64_t sent;
49 uint64_t received;
50
49 - //Publish information.
51 + // Publish information.
52 uint64_t publish_sent;
53 uint64_t publish_recv;
54 } ebpf_socket_publish_apps_t;
55
54 -#endif
56 +#endif /* NETDATA_EBPF_SOCKET_H */
configure.ac
+24 -14
@@ -405,17 +405,6 @@ PKG_CHECK_MODULES([JSON],[json-c],AC_CHECK_LIB(
405
406 OPTIONAL_JSONC_LIBS="${JSONC_LIBS}"
407
408 -# -----------------------------------------------------------------------------
409 -# VFS plugin libs
410 -
411 -AC_CHECK_LIB(
412 - [dl],
413 - [dlopen],
414 - [EBPF_LIBS="-ldl"]
415 -)
416 -
417 -OPTIONAL_EBPF_LIBS="${EBPF_LIBS}"
418 -
408 # -----------------------------------------------------------------------------
409 # DB engine and HTTPS
410 test "${enable_dbengine}" = "yes" -a -z "${LZ4_LIBS}" && \
@@ -957,8 +946,28 @@ AM_CONDITIONAL([ENABLE_PLUGIN_PERF], [test "${enable_plugin_perf}" = "yes"])
946 # -----------------------------------------------------------------------------
947 # ebpf.plugin
948
949 +PKG_CHECK_MODULES(
950 + [LIBELF],
951 + [libelf],
952 + [have_libelf=yes],
953 + [have_libelf=no]
954 +)
955 +
956 +AC_CHECK_TYPE(
957 + [struct bpf_prog_info],
958 + [have_bpf=yes],
959 + [have_bpf=no],
960 + [#include <linux/bpf.h>]
961 +)
962 +
963 AC_MSG_CHECKING([if ebpf.plugin should be enabled])
961 -if test "${build_target}" == "linux" -a "${EBPF_LIBS}"; then
964 +if test "${build_target}" = "linux" -a \
965 + "${have_libelf}" = "yes" -a \
966 + "${have_bpf}" = "yes" -a \
967 + -f externaldeps/libbpf/libbpf.a; then
968 + OPTIONAL_BPF_CFLAGS="${LIBELF_CFLAGS} -I externaldeps/libbpf/include"
969 + OPTIONAL_BPF_LIBS="externaldeps/libbpf/libbpf.a ${LIBELF_LIBS}"
970 + AC_DEFINE([HAVE_LIBBPF], [1], [libbpf usability])
971 enable_ebpf="yes"
972 else
973 enable_ebpf="no"
@@ -1330,7 +1339,7 @@ AC_SUBST([webdir])
1339 CFLAGS="${CFLAGS} ${OPTIONAL_MATH_CFLAGS} ${OPTIONAL_NFACCT_CFLAGS} ${OPTIONAL_ZLIB_CFLAGS} ${OPTIONAL_UUID_CFLAGS} \
1340 ${OPTIONAL_LIBCAP_CFLAGS} ${OPTIONAL_IPMIMONITORING_CFLAGS} ${OPTIONAL_CUPS_CFLAGS} ${OPTIONAL_XENSTAT_FLAGS} \
1341 ${OPTIONAL_KINESIS_CFLAGS} ${OPTIONAL_PUBSUB_CFLAGS} ${OPTIONAL_PROMETHEUS_REMOTE_WRITE_CFLAGS} \
1333 - ${OPTIONAL_MONGOC_CFLAGS} ${LWS_CFLAGS} ${OPTIONAL_JSONC_STATIC_CFLAGS}"
1342 + ${OPTIONAL_MONGOC_CFLAGS} ${LWS_CFLAGS} ${OPTIONAL_JSONC_STATIC_CFLAGS} ${OPTIONAL_BPF_CFLAGS}"
1343
1344 CXXFLAGS="${CFLAGS} ${CXX11FLAG}"
1345
@@ -1352,7 +1361,6 @@ AC_SUBST([OPTIONAL_UV_LIBS])
1361 AC_SUBST([OPTIONAL_LZ4_LIBS])
1362 AC_SUBST([OPTIONAL_JUDY_LIBS])
1363 AC_SUBST([OPTIONAL_SSL_LIBS])
1355 -AC_SUBST([OPTIONAL_EBPF_LIBS])
1364 AC_SUBST([OPTIONAL_JSONC_LIBS])
1365 AC_SUBST([OPTIONAL_NFACCT_CFLAGS])
1366 AC_SUBST([OPTIONAL_NFACCT_LIBS])
@@ -1360,6 +1368,8 @@ AC_SUBST([OPTIONAL_ZLIB_CFLAGS])
1368 AC_SUBST([OPTIONAL_ZLIB_LIBS])
1369 AC_SUBST([OPTIONAL_UUID_CFLAGS])
1370 AC_SUBST([OPTIONAL_UUID_LIBS])
1371 +AC_SUBST([OPTIONAL_BPF_CFLAGS])
1372 +AC_SUBST([OPTIONAL_BPF_LIBS])
1373 AC_SUBST([OPTIONAL_MQTT_LIBS])
1374 AC_SUBST([OPTIONAL_LIBCAP_CFLAGS])
1375 AC_SUBST([OPTIONAL_LIBCAP_LIBS])
libnetdata/ebpf/README.md
+1
@@ -0,0 +1 @@
1 +[![analytics](https://www.google-analytics.com/collect?v=1&aip=1&t=pageview&_s=1&ds=github&dr=https%3A%2F%2Fgithub.com%2Fnetdata%2Fnetdata&dl=https%3A%2F%2Fmy-netdata.io%2Fgithub%2Flibnetdata%2Febpf%2FREADME&_u=MAC~&cid=5792dfd7-8dc4-476b-af31-da2fdb9f93d2&tid=UA-64295674-3)](<>)
libnetdata/ebpf/ebpf.c
+69 -96
@@ -1,3 +1,5 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 #include <sys/types.h>
4 #include <sys/stat.h>
5 #include <fcntl.h>
@@ -5,10 +7,11 @@
7
8 #include "../libnetdata.h"
9
8 -static int clean_kprobe_event(FILE *out, char *filename, char *father_pid, netdata_ebpf_events_t *ptr) {
9 - int fd = open(filename, O_WRONLY | O_APPEND, 0);
10 +static int clean_kprobe_event(FILE *out, char *filename, char *father_pid, netdata_ebpf_events_t *ptr)
11 +{
12 + int fd = open(filename, O_WRONLY | O_APPEND, 0);
13 if (fd < 0) {
11 - if(out) {
14 + if (out) {
15 fprintf(out, "Cannot open %s : %s\n", filename, strerror(errno));
16 }
17 return 1;
@@ -20,10 +23,10 @@ static int clean_kprobe_event(FILE *out, char *filename, char *father_pid, netda
23 if (length > 0) {
24 ssize_t written = write(fd, cmd, strlen(cmd));
25 if (written < 0) {
23 - if(out) {
24 - fprintf(out
25 - , "Cannot remove the event (%d, %d) '%s' from %s : %s\n"
26 - , getppid(), getpid(), cmd, filename, strerror((int)errno));
26 + if (out) {
27 + fprintf(
28 + out, "Cannot remove the event (%d, %d) '%s' from %s : %s\n", getppid(), getpid(), cmd, filename,
29 + strerror((int)errno));
30 }
31 ret = 1;
32 }
@@ -34,16 +37,17 @@ static int clean_kprobe_event(FILE *out, char *filename, char *father_pid, netda
37 return ret;
38 }
39
37 -int clean_kprobe_events(FILE *out, int pid, netdata_ebpf_events_t *ptr) {
40 +int clean_kprobe_events(FILE *out, int pid, netdata_ebpf_events_t *ptr)
41 +{
42 debug(D_EXIT, "Cleaning parent process events.");
39 - char filename[FILENAME_MAX +1];
43 + char filename[FILENAME_MAX + 1];
44 snprintf(filename, FILENAME_MAX, "%s%s", NETDATA_DEBUGFS, "kprobe_events");
45
46 char removeme[16];
43 - snprintf(removeme, 15,"%d", pid);
47 + snprintf(removeme, 15, "%d", pid);
48
49 int i;
46 - for (i = 0 ; ptr[i].name ; i++) {
50 + for (i = 0; ptr[i].name; i++) {
51 if (clean_kprobe_event(out, filename, removeme, &ptr[i])) {
52 break;
53 }
@@ -54,7 +58,8 @@ int clean_kprobe_events(FILE *out, int pid, netdata_ebpf_events_t *ptr) {
58
59 //----------------------------------------------------------------------------------------------------------------------
60
57 -int get_kernel_version(char *out, int size) {
61 +int get_kernel_version(char *out, int size)
62 +{
63 char major[16], minor[16], patch[16];
64 char ver[256];
65 char *version = ver;
@@ -73,12 +78,14 @@ int get_kernel_version(char *out, int size) {
78 close(fd);
79
80 char *move = major;
76 - while (*version && *version != '.') *move++ = *version++;
81 + while (*version && *version != '.')
82 + *move++ = *version++;
83 *move = '\0';
84
85 version++;
86 move = minor;
81 - while (*version && *version != '.') *move++ = *version++;
87 + while (*version && *version != '.')
88 + *move++ = *version++;
89 *move = '\0';
90
91 if (*version)
@@ -87,27 +94,28 @@ int get_kernel_version(char *out, int size) {
94 return -1;
95
96 move = patch;
90 - while (*version && *version != '\n') *move++ = *version++;
97 + while (*version && *version != '\n')
98 + *move++ = *version++;
99 *move = '\0';
100
101 fd = snprintf(out, (size_t)size, "%s.%s.%s", major, minor, patch);
102 if (fd > size)
103 error("The buffer to store kernel version is not smaller than necessary.");
104
97 - return ((int)(str2l(major)*65536) + (int)(str2l(minor)*256) + (int)str2l(patch));
105 + return ((int)(str2l(major) * 65536) + (int)(str2l(minor) * 256) + (int)str2l(patch));
106 }
107
108 int get_redhat_release()
109 {
110 char buffer[256];
103 - int major,minor;
111 + int major, minor;
112 FILE *fp = fopen("/etc/redhat-release", "r");
113
114 if (fp) {
115 major = 0;
116 minor = -1;
117 size_t length = fread(buffer, sizeof(char), 255, fp);
110 - if (length > 4 ) {
118 + if (length > 4) {
119 buffer[length] = '\0';
120 char *end = strchr(buffer, '.');
121 char *start;
@@ -117,13 +125,13 @@ int get_redhat_release()
125 if (end > buffer) {
126 start = end - 1;
127
120 - major = strtol( start, NULL, 10);
128 + major = strtol(start, NULL, 10);
129 start = ++end;
130
131 end++;
124 - if(end) {
132 + if (end) {
133 end = 0x00;
126 - minor = strtol( start, NULL, 10);
134 + minor = strtol(start, NULL, 10);
135 } else {
136 minor = -1;
137 }
@@ -132,19 +140,21 @@ int get_redhat_release()
140 }
141
142 fclose(fp);
135 - return ((major*256) + minor);
143 + return ((major * 256) + minor);
144 } else {
145 return -1;
146 }
147 }
148
141 -static int has_ebpf_kernel_version(int version) {
142 - //Kernel 4.11.0 or RH > 7.5
143 - return (version >= NETDATA_MINIMUM_EBPF_KERNEL || get_redhat_release() >= NETDATA_MINIMUM_RH_VERSION);
149 +static int has_ebpf_kernel_version(int version)
150 +{
151 + // Kernel 4.11.0 or RH > 7.5
152 + return (version >= NETDATA_MINIMUM_EBPF_KERNEL || get_redhat_release() >= NETDATA_MINIMUM_RH_VERSION);
153 }
154
146 -int has_condition_to_run(int version) {
147 - if(!has_ebpf_kernel_version(version))
155 +int has_condition_to_run(int version)
156 +{
157 + if (!has_ebpf_kernel_version(version))
158 return 0;
159
160 return 1;
@@ -152,7 +162,8 @@ int has_condition_to_run(int version) {
162
163 //----------------------------------------------------------------------------------------------------------------------
164
155 -char *ebpf_library_suffix(int version, int isrh) {
165 +char *ebpf_kernel_suffix(int version, int isrh)
166 +{
167 if (isrh) {
168 if (version >= NETDATA_EBPF_KERNEL_4_11)
169 return "4.18.0";
@@ -172,101 +183,63 @@ char *ebpf_library_suffix(int version, int isrh) {
183
184 //----------------------------------------------------------------------------------------------------------------------
185
175 -int ebpf_load_libraries(ebpf_functions_t *ef, char *libbase, char *pluginsdir)
186 +int ebpf_update_kernel(ebpf_data_t *ed)
187 {
177 - char *err = NULL;
178 - char lpath[4096];
179 - char netdatasl[128];
180 - void *libnetdata;
181 -
182 - snprintf(netdatasl, 127, "%s.%s", libbase, ef->kernel_string);
183 - snprintf(lpath, 4095, "%s/%s", pluginsdir, netdatasl);
184 - libnetdata = dlopen(lpath, RTLD_LAZY);
185 - if (!libnetdata) {
186 - info("Cannot load library %s for the current kernel.", lpath);
187 -
188 - //Update kernel
189 - char *library = ebpf_library_suffix(ef->running_on_kernel, (ef->isrh < 0)?0:1);
190 - size_t length = strlen(library);
191 - strncpyz(ef->kernel_string, library, length);
192 - ef->kernel_string[length] = '\0';
193 -
194 - //Try to load the default version
195 - snprintf(netdatasl, 127, "%s.%s", libbase, ef->kernel_string);
196 - snprintf(lpath, 4095, "%s/%s", pluginsdir, netdatasl);
197 - libnetdata = dlopen(lpath, RTLD_LAZY);
198 - if (!libnetdata) {
199 - error("Cannot load %s default library.", lpath);
200 - return -1;
201 - } else {
202 - info("Default shared library %s loaded with success.", lpath);
203 - ef->libnetdata = libnetdata;
204 - }
205 - } else {
206 - info("Current shared library %s loaded with success.", lpath);
207 - ef->libnetdata = libnetdata;
208 - }
209 -
210 - ef->load_bpf_file = dlsym(libnetdata, "load_bpf_file");
211 - if ((err = dlerror()) != NULL) {
212 - error("Cannot find load_bpf_file: %s", err);
213 - return -1;
214 - }
215 -
216 - ef->bpf_map_lookup_elem = dlsym(libnetdata, "bpf_map_lookup_elem");
217 - if ((err = dlerror()) != NULL) {
218 - error("Cannot find bpf_map_lookup_elem: %s", err);
219 - return -1;
220 - }
221 -
222 - ef->bpf_map_delete_elem = dlsym(libnetdata, "bpf_map_delete_elem");
223 - if ((err = dlerror()) != NULL) {
224 - error("Cannot find bpf_map_delete_elem: %s", err);
225 - return -1;
226 - }
227 -
228 - ef->bpf_map_get_next_key = dlsym(libnetdata, "bpf_map_get_next_key");
229 - if ((err = dlerror()) != NULL) {
230 - error("Cannot find bpf_map_delete_elem: %s", err);
231 - return -1;
232 - }
188 + char *kernel = ebpf_kernel_suffix(ed->running_on_kernel, (ed->isrh < 0) ? 0 : 1);
189 + size_t length = strlen(kernel);
190 + strncpyz(ed->kernel_string, kernel, length);
191 + ed->kernel_string[length] = '\0';
192
193 return 0;
194 }
195
237 -static int select_file(char *name, const char *program, size_t length, int mode , char *kernel_string) {
196 +static int select_file(char *name, const char *program, size_t length, int mode, char *kernel_string)
197 +{
198 int ret = -1;
199 if (!mode)
200 ret = snprintf(name, length, "rnetdata_ebpf_%s.%s.o", program, kernel_string);
241 - else if(mode == 1)
201 + else if (mode == 1)
202 ret = snprintf(name, length, "dnetdata_ebpf_%s.%s.o", program, kernel_string);
243 - else if(mode == 2)
203 + else if (mode == 2)
204 ret = snprintf(name, length, "pnetdata_ebpf_%s.%s.o", program, kernel_string);
205
206 return ret;
207 }
208
249 -int ebpf_load_program(char *plugins_dir,
250 - int event_id, int mode ,
251 - char *kernel_string,
252 - const char *name,
253 - int *map_fd,
254 - int (*load_bpf_file)(int *, char *, int))
209 +int ebpf_load_program(char *plugins_dir, int event_id, int mode, char *kernel_string, const char *name, int *map_fd)
210 {
211 + UNUSED(event_id);
212 +
213 char lpath[4096];
214 char lname[128];
215 + struct bpf_object *obj;
216 + int prog_fd;
217
218 int test = select_file(lname, name, (size_t)127, mode, kernel_string);
219 if (test < 0 || test > 127)
220 return -1;
221
263 - snprintf(lpath, 4096, "%s/%s", plugins_dir, lname);
264 - if (load_bpf_file(map_fd, lpath, event_id)) {
222 + snprintf(lpath, 4096, "%s/%s", plugins_dir, lname);
223 + if (bpf_prog_load(lpath, BPF_PROG_TYPE_KPROBE, &obj, &prog_fd)) {
224 info("Cannot load program: %s", lpath);
225 return -1;
226 } else {
227 info("The eBPF program %s was loaded with success.", name);
228 }
229
230 + struct bpf_map *map;
231 + size_t i = 0;
232 + bpf_map__for_each(map, obj)
233 + {
234 + map_fd[i] = bpf_map__fd(map);
235 + i++;
236 + }
237 +
238 + struct bpf_program *prog;
239 + bpf_object__for_each_program(prog, obj)
240 + {
241 + bpf_program__attach(prog);
242 + }
243 +
244 return 0;
245 }
libnetdata/ebpf/ebpf.h
+20 -23
@@ -1,7 +1,12 @@
1 -#ifndef _NETDATA_EBPF_H_
2 -# define _NETDATA_EBPF_H_ 1
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2
4 -# define NETDATA_DEBUGFS "/sys/kernel/debug/tracing/"
3 +#ifndef NETDATA_EBPF_H
4 +#define NETDATA_EBPF_H 1
5 +
6 +#include <bpf/bpf.h>
7 +#include <bpf/libbpf.h>
8 +
9 +#define NETDATA_DEBUGFS "/sys/kernel/debug/tracing/"
10
11 /**
12 * The next magic number is got doing the following math:
@@ -9,7 +14,7 @@
14 *
15 * For more details, please, read /usr/include/linux/version.h
16 */
12 -# define NETDATA_MINIMUM_EBPF_KERNEL 264960
17 +#define NETDATA_MINIMUM_EBPF_KERNEL 264960
18
19 /**
20 * The RedHat magic number was got doing:
@@ -19,65 +24,57 @@
24 * For more details, please, read /usr/include/linux/version.h
25 * in any Red Hat installation.
26 */
22 -# define NETDATA_MINIMUM_RH_VERSION 1797
27 +#define NETDATA_MINIMUM_RH_VERSION 1797
28
29 /**
30 * 2048 = 8*256 + 0
31 */
27 -# define NETDATA_RH_8 2048
32 +#define NETDATA_RH_8 2048
33
34 /**
35 * Kernel 4.17
36 *
37 * 266496 = 4*65536 + 17*256
38 */
34 -# define NETDATA_EBPF_KERNEL_4_17 266496
39 +#define NETDATA_EBPF_KERNEL_4_17 266496
40
41 /**
42 * Kernel 4.15
43 *
44 * 265984 = 4*65536 + 15*256
45 */
41 -# define NETDATA_EBPF_KERNEL_4_15 265984
46 +#define NETDATA_EBPF_KERNEL_4_15 265984
47
48 /**
49 * Kernel 4.11
50 *
51 * 264960 = 4*65536 + 15*256
52 */
48 -# define NETDATA_EBPF_KERNEL_4_11 264960
53 +#define NETDATA_EBPF_KERNEL_4_11 264960
54
55 typedef struct netdata_ebpf_events {
56 char type;
57 char *name;
58 } netdata_ebpf_events_t;
59
55 -typedef struct ebpf_functions {
56 - void *libnetdata;
57 - int (*load_bpf_file)(int *, char *, int);
58 - //Libbpf (It is necessary to have at least kernel 4.10)
59 - int (*bpf_map_lookup_elem)(int, const void *, void *);
60 - int (*bpf_map_delete_elem)(int fd, const void *key);
61 - int (*bpf_map_get_next_key)(int fd, const void *key, void *next_key);
62 -
60 +typedef struct ebpf_data {
61 int *map_fd;
62
63 char *kernel_string;
64 uint32_t running_on_kernel;
65 int isrh;
68 -} ebpf_functions_t;
66 +} ebpf_data_t;
67
68 extern int clean_kprobe_events(FILE *out, int pid, netdata_ebpf_events_t *ptr);
69 extern int get_kernel_version(char *out, int size);
70 extern int get_redhat_release();
71 extern int has_condition_to_run(int version);
74 -extern char *ebpf_library_suffix(int version, int isrh);
75 -extern int ebpf_load_libraries(ebpf_functions_t *ef, char *libbase, char *pluginsdir);
72 +extern char *ebpf_kernel_suffix(int version, int isrh);
73 +extern int ebpf_update_kernel(ebpf_data_t *ef);
74 extern int ebpf_load_program(char *plugins_dir,
75 int event_id, int mode,
76 char *kernel_string,
77 const char *name,
80 - int *map_fd,
81 - int (*load_bpf_file)(int *,char *, int));
78 + int *map_fd);
79
83 -#endif
80 +#endif /* NETDATA_EBPF_H */
libnetdata/ebpf/libbpf.c.diff new
+229
@@ -0,0 +1,229 @@
1 +--- a/src/libbpf.c
2 ++++ b/src/libbpf.c
3 +@@ -620,6 +620,93 @@ bpf_object__init_prog_names(struct bpf_object *obj)
4 + return 0;
5 + }
6 +
7 ++static __u32 choose_specific_version0(int fd, __u32 current)
8 ++{
9 ++ char ver[256];
10 ++ __u32 v_major, v_minor, v_patch;
11 ++ ssize_t len = read(fd, ver, sizeof(ver));
12 ++ if (len < 0) {
13 ++ return 0;
14 ++ }
15 ++ ver[len] = '\0';
16 ++
17 ++ char *first = strchr(ver, ' ');
18 ++ if (!first) {
19 ++ return 0;
20 ++ }
21 ++
22 ++ first++;
23 ++ char *version = strchr(first, ' ');
24 ++ if (!version) {
25 ++ return 0;
26 ++ }
27 ++
28 ++ version++;
29 ++ if (sscanf(version, "%u.%u.%u", &v_major, &v_minor, &v_patch) != 3)
30 ++ return current;
31 ++
32 ++ return KERNEL_VERSION(v_major, v_minor, v_patch);
33 ++}
34 ++
35 ++static __u32 choose_kernel_version(__u32 current)
36 ++{
37 ++ FILE *fp_d = fopen("/etc/debian_version","r");
38 ++ int fp_u = open("/proc/version_signature", O_RDONLY);
39 ++ FILE *fp_rh = fopen("/etc/redhat-release","r");
40 ++ char tmp[32];
41 ++ int de = 0;
42 ++ __u32 ret;
43 ++
44 ++ if (!fp_d && !fp_rh && fp_u == -1)
45 ++ return current;
46 ++
47 ++ struct utsname u;
48 ++ uname(&u);
49 ++
50 ++ if (fp_d) {
51 ++ fclose(fp_d);
52 ++ de = 1;
53 ++ }
54 ++
55 ++ if (fp_rh) {
56 ++ fclose(fp_rh);
57 ++ de = 0;
58 ++ }
59 ++
60 ++ if ( fp_u > 0 ) {
61 ++ ret = choose_specific_version0(fp_u, current);
62 ++ close(fp_u);
63 ++ return (!ret)?current:ret;
64 ++ }
65 ++
66 ++ __u32 v_kernel,v_major, v_minor, v_patch;
67 ++ __u32 r_kernel,r_major, r_minor, r_patch;
68 ++
69 ++ if (sscanf(u.release, "%u.%u.%u-%u", &v_kernel, &v_major, &v_minor, &v_patch) != 4)
70 ++ return current;
71 ++
72 ++ int length = snprintf(tmp, 31, "%u.%u", v_kernel, v_major);
73 ++ tmp[length] = '\0';
74 ++
75 ++ char *parse = strstr(u.version, tmp);
76 ++ if (!parse) {
77 ++ return current;
78 ++ }
79 ++
80 ++ char *space = strchr(parse, ' ');
81 ++ if(space) {
82 ++ length = (int)(space - parse);
83 ++ strncpy(tmp, parse, (size_t)length);
84 ++ tmp[length] = '\0';
85 ++ }
86 ++
87 ++ if (sscanf(tmp, "%u.%u.%u-%u", &r_kernel, &r_major, &r_minor, &r_patch) != 4)
88 ++ return current;
89 ++
90 ++ ret = (de)?KERNEL_VERSION(r_kernel, r_major, r_minor):KERNEL_VERSION(r_kernel, r_major, r_minor) + r_patch;
91 ++ return (ret > current)?ret:current;
92 ++}
93 ++
94 + static __u32 get_kernel_version(void)
95 + {
96 + __u32 major, minor, patch;
97 +@@ -628,7 +715,11 @@ static __u32 get_kernel_version(void)
98 + uname(&info);
99 + if (sscanf(info.release, "%u.%u.%u", &major, &minor, &patch) != 3)
100 + return 0;
101 +- return KERNEL_VERSION(major, minor, patch);
102 ++
103 ++ if (major < 5)
104 ++ return choose_kernel_version(KERNEL_VERSION(major, minor, patch));
105 ++ else
106 ++ return KERNEL_VERSION(major, minor, patch);
107 + }
108 +
109 + static const struct btf_member *
110 +@@ -3239,6 +3330,10 @@ int bpf_map__resize(struct bpf_map *map, __u32 max_entries)
111 + static int
112 + bpf_object__probe_loading(struct bpf_object *obj)
113 + {
114 ++ // Don't probe loading for very old kernels. CentOS 7 can't load this probe.
115 ++ if (obj->kern_version <= KERNEL_VERSION(3, 10, 0))
116 ++ return 0;
117 ++
118 + struct bpf_load_program_attr attr;
119 + char *cp, errmsg[STRERR_BUFSIZE];
120 + struct bpf_insn insns[] = {
121 +@@ -7612,6 +7707,88 @@ static int perf_event_open_probe(bool uprobe, bool retprobe, const char *name,
122 + return pfd;
123 + }
124 +
125 ++static int perf_event_open_old_kprobe(bool retprobe, const char *name)
126 ++{
127 ++#define DEBUG_FS "/sys/kernel/debug/tracing/"
128 ++ struct perf_event_attr attr = {};
129 ++ char errmsg[STRERR_BUFSIZE];
130 ++ int kfd = -1, ret = -1, err;
131 ++ char event_alias[256], buf[PATH_MAX];
132 ++ const char *event_prefix = "";
133 ++ bool event_was_written = false;
134 ++
135 ++ kfd = open(DEBUG_FS "kprobe_events", O_WRONLY | O_APPEND, 0);
136 ++ if (kfd < 0) {
137 ++ pr_warn("failed to open '%s%s': %s\n",
138 ++ DEBUG_FS,
139 ++ "kprobe_events",
140 ++ libbpf_strerror_r(kfd, errmsg, sizeof(errmsg)));
141 ++ return kfd;
142 ++ }
143 ++
144 ++ char type = retprobe ? 'r' : 'p';
145 ++ snprintf(event_alias, sizeof(event_alias), "%c_netdata_%s_%d", type, name, getpid());
146 ++
147 ++#ifdef __x86_64__
148 ++ if (strncmp(name, "sys_", 4) == 0) {
149 ++ snprintf(buf, sizeof(buf), "%c:__x64_%s __x64_%s",
150 ++ type, event_alias, name);
151 ++ ret = write(kfd, buf, strlen(buf));
152 ++
153 ++ if (ret >= 0) {
154 ++ event_was_written = true;
155 ++ event_prefix = "__x64_";
156 ++ }
157 ++ }
158 ++#endif
159 ++
160 ++ if (!event_was_written) {
161 ++ snprintf(buf, sizeof(buf), "%c:%s %s",
162 ++ type, event_alias, name);
163 ++ ret = write(kfd, buf, strlen(buf));
164 ++ if (ret < 0) {
165 ++ pr_warn("failed to create kprobe '%s': %s\n",
166 ++ name,
167 ++ libbpf_strerror_r(ret, errmsg, sizeof(errmsg)));
168 ++ close(kfd);
169 ++ return ret;
170 ++ }
171 ++ }
172 ++
173 ++ close(kfd);
174 ++
175 ++ snprintf(buf, sizeof(buf), DEBUG_FS "events/kprobes/%s%s/id",
176 ++ event_prefix,
177 ++ event_alias);
178 ++
179 ++ ret = parse_uint_from_file(buf, "%d\n");
180 ++ if (ret < 0) {
181 ++ pr_warn("failed to determine event id: %s\n",
182 ++ libbpf_strerror_r(ret, errmsg, sizeof(errmsg)));
183 ++ return ret;
184 ++ }
185 ++ attr.config = ret;
186 ++
187 ++ attr.size = sizeof(attr);
188 ++ attr.type = PERF_TYPE_TRACEPOINT;
189 ++ attr.config1 = ptr_to_u64(name); /* kprobe_func */
190 ++ attr.config2 = 0; /* kprobe_addr */
191 ++
192 ++ /* pid filter is meaningful only for uprobes */
193 ++ kfd = syscall(__NR_perf_event_open, &attr,
194 ++ -1 /* pid */,
195 ++ 0 /* cpu */,
196 ++ -1 /* group_fd */, PERF_FLAG_FD_CLOEXEC);
197 ++ if (kfd < 0) {
198 ++ err = -errno;
199 ++ pr_warn("%s perf_event_open_old_kprobe() failed: %s\n",
200 ++ "kprobe",
201 ++ libbpf_strerror_r(err, errmsg, sizeof(errmsg)));
202 ++ return err;
203 ++ }
204 ++ return kfd;
205 ++}
206 ++
207 + struct bpf_link *bpf_program__attach_kprobe(struct bpf_program *prog,
208 + bool retprobe,
209 + const char *func_name)
210 +@@ -7623,11 +7800,14 @@ struct bpf_link *bpf_program__attach_kprobe(struct bpf_program *prog,
211 + pfd = perf_event_open_probe(false /* uprobe */, retprobe, func_name,
212 + 0 /* offset */, -1 /* pid */);
213 + if (pfd < 0) {
214 +- pr_warn("program '%s': failed to create %s '%s' perf event: %s\n",
215 +- bpf_program__title(prog, false),
216 +- retprobe ? "kretprobe" : "kprobe", func_name,
217 +- libbpf_strerror_r(pfd, errmsg, sizeof(errmsg)));
218 +- return ERR_PTR(pfd);
219 ++ pfd = perf_event_open_old_kprobe(retprobe, func_name);
220 ++ if (pfd < 0) {
221 ++ pr_warn("program '%s': failed to create %s '%s' perf event: %s\n",
222 ++ bpf_program__title(prog, false),
223 ++ retprobe ? "kretprobe" : "kprobe", func_name,
224 ++ libbpf_strerror_r(pfd, errmsg, sizeof(errmsg)));
225 ++ return ERR_PTR(pfd);
226 ++ }
227 + }
228 + link = bpf_program__attach_perf_event(prog, pfd);
229 + if (IS_ERR(link)) {
libnetdata/libnetdata.h
+2
@@ -314,7 +314,9 @@ extern char *netdata_configured_host_prefix;
314 #include "log/log.h"
315 #include "procfile/procfile.h"
316 #include "dictionary/dictionary.h"
317 +#ifdef HAVE_LIBBPF
318 #include "ebpf/ebpf.h"
319 +#endif
320 #include "eval/eval.h"
321 #include "statistical/statistical.h"
322 #include "adaptive_resortable_list/adaptive_resortable_list.h"
netdata-installer.sh
+66
@@ -679,6 +679,72 @@ bundle_jsonc() {
679
680 bundle_jsonc
681
682 +# -----------------------------------------------------------------------------
683 +
684 +build_libbpf() {
685 + pushd "${1}/src" > /dev/null || exit 1
686 + run env CFLAGS= CXXFLAGS= LDFLAGS= BUILD_STATIC_ONLY=y OBJDIR=build DESTDIR=.. make install
687 + popd > /dev/null || exit 1
688 +}
689 +
690 +copy_libbpf() {
691 + target_dir="${PWD}/externaldeps/libbpf"
692 +
693 + if [ "$(uname -m)" = x86_64 ]; then
694 + lib_subdir="lib64"
695 + else
696 + lib_subdir="lib"
697 + fi
698 +
699 + run mkdir -p "${target_dir}" || return 1
700 +
701 + run cp "${1}/usr/${lib_subdir}/libbpf.a" "${target_dir}/libbpf.a" || return 1
702 + run cp -r "${1}/usr/include" "${target_dir}" || return 1
703 +}
704 +
705 +bundle_libbpf() {
706 + if { [ -n "${NETDATA_DISABLE_EBPF}" ] && [ ${NETDATA_DISABLE_EBPF} = 1 ]; } || [ "$(uname -s)" != Linux ]; then
707 + return 0
708 + fi
709 +
710 + progress "Prepare libbpf"
711 +
712 + LIBBPF_PACKAGE_VERSION="$(cat packaging/libbpf.version)"
713 +
714 + tmp="$(mktemp -d -t netdata-libbpf-XXXXXX)"
715 + LIBBPF_PACKAGE_BASENAME="v${LIBBPF_PACKAGE_VERSION}.tar.gz"
716 +
717 + if fetch_and_verify "libbpf" \
718 + "https://github.com/libbpf/libbpf/archive/${LIBBPF_PACKAGE_BASENAME}" \
719 + "${LIBBPF_PACKAGE_BASENAME}" \
720 + "${tmp}" \
721 + "${NETDATA_LOCAL_TARBALL_OVERRIDE_LIBBPF}"; then
722 + if run tar -xf "${tmp}/${LIBBPF_PACKAGE_BASENAME}" -C "${tmp}" &&
723 + run git apply --directory="${tmp}/libbpf-${LIBBPF_PACKAGE_VERSION}" --unsafe-paths libnetdata/ebpf/libbpf.c.diff &&
724 + build_libbpf "${tmp}/libbpf-${LIBBPF_PACKAGE_VERSION}" &&
725 + copy_libbpf "${tmp}/libbpf-${LIBBPF_PACKAGE_VERSION}" &&
726 + rm -rf "${tmp}"; then
727 + run_ok "libbpf built and prepared."
728 + else
729 + run_failed "Failed to build libbpf."
730 + if [ -n "${NETDATA_DISABLE_EBPF}" ] && [ ${NETDATA_DISABLE_EBPF} = 0 ]; then
731 + exit 1
732 + else
733 + defer_error_highlighted "Failed to build libbpf. You may not be able to use eBPF plugin."
734 + fi
735 + fi
736 + else
737 + run_failed "Unable to fetch sources for libbpf."
738 + if [ -n "${NETDATA_DISABLE_EBPF}" ] && [ ${NETDATA_DISABLE_EBPF} = 0 ]; then
739 + exit 1
740 + else
741 + defer_error_highlighted "Unable to fetch sources for libbpf. You may not be able to use eBPF plugin."
742 + fi
743 + fi
744 +}
745 +
746 +bundle_libbpf
747 +
748 # -----------------------------------------------------------------------------
749 # If we have the dashboard switching logic, make sure we're on the classic
750 # dashboard during the install (updates don't work correctly otherwise).
packaging/installer/install-required-packages.sh
+33 -2
@@ -32,6 +32,7 @@ PACKAGES_UPDATE_IPSETS=${PACKAGES_UPDATE_IPSETS-0}
32 PACKAGES_NETDATA_DEMO_SITE=${PACKAGES_NETDATA_DEMO_SITE-0}
33 PACKAGES_NETDATA_SENSORS=${PACKAGES_NETDATA_SENSORS-0}
34 PACKAGES_NETDATA_DATABASE=${PACKAGES_NETDATA_DATABASE-0}
35 +PACKAGES_NETDATA_EBPF=${PACKAGES_NETDATA_EBPF-0}
36
37 # needed commands
38 lsb_release=$(command -v lsb_release 2> /dev/null)
@@ -1182,6 +1183,27 @@ declare -A pkg_zip=(
1183 ['default']="zip"
1184 )
1185
1186 +declare -A pkg_libelf=(
1187 + ['alpine']="elfutils-dev"
1188 + ['arch']="libelf"
1189 + ['gentoo']="dev-libs/libelf"
1190 + ['debian']="libelf-dev"
1191 + ['ubuntu']="libelf-dev"
1192 + ['fedora']="elfutils-libelf-devel"
1193 + ['centos']="elfutils-libelf-devel"
1194 + ['rhel']="elfutils-libelf-devel"
1195 + ['clearlinux']="devpkg-elfutils"
1196 + ['suse']="libelf-devel"
1197 + ['macos']="NOTREQUIRED"
1198 + ['freebsd']="NOTREQUIRED"
1199 + ['default']="libelf-devel"
1200 +
1201 + # exceptions
1202 + ['alpine-3.5']="libelf-dev"
1203 + ['alpine-3.4']="libelf-dev"
1204 + ['alpine-3.3']="libelf-dev"
1205 +)
1206 +
1207 validate_package_trees() {
1208 if type -t validate_tree_${tree} > /dev/null; then
1209 validate_tree_${tree}
@@ -1317,7 +1339,7 @@ packages() {
1339 fi
1340
1341 # -------------------------------------------------------------------------
1320 - # sensors
1342 + # netdata database
1343 if [ "${PACKAGES_NETDATA_DATABASE}" -ne 0 ]; then
1344 suitable_package libuv
1345 suitable_package lz4
@@ -1325,6 +1347,12 @@ packages() {
1347 suitable_package judy
1348 fi
1349
1350 + # -------------------------------------------------------------------------
1351 + # ebpf plugin
1352 + if [ "${PACKAGES_NETDATA_EBPF}" -ne 0 ]; then
1353 + suitable_package libelf
1354 + fi
1355 +
1356 # -------------------------------------------------------------------------
1357 # scripting interpreters for netdata plugins
1358
@@ -1860,7 +1888,7 @@ EOF
1888 remote_log() {
1889 # log success or failure on our system
1890 # to help us solve installation issues
1863 - curl > /dev/null 2>&1 -Ss --max-time 3 "https://registry.my-netdata.io/log/installer?status=${1}&error=${2}&distribution=${distribution}&version=${version}&installer=${package_installer}&tree=${tree}&detection=${detection}&netdata=${PACKAGES_NETDATA}&nodejs=${PACKAGES_NETDATA_NODEJS}&python=${PACKAGES_NETDATA_PYTHON}&python3=${PACKAGES_NETDATA_PYTHON3}&mysql=${PACKAGES_NETDATA_PYTHON_MYSQL}&postgres=${PACKAGES_NETDATA_PYTHON_POSTGRES}&pymongo=${PACKAGES_NETDATA_PYTHON_MONGO}&sensors=${PACKAGES_NETDATA_SENSORS}&database=${PACKAGES_NETDATA_DATABASE}&firehol=${PACKAGES_FIREHOL}&fireqos=${PACKAGES_FIREQOS}&iprange=${PACKAGES_IPRANGE}&update_ipsets=${PACKAGES_UPDATE_IPSETS}&demo=${PACKAGES_NETDATA_DEMO_SITE}"
1891 + curl > /dev/null 2>&1 -Ss --max-time 3 "https://registry.my-netdata.io/log/installer?status=${1}&error=${2}&distribution=${distribution}&version=${version}&installer=${package_installer}&tree=${tree}&detection=${detection}&netdata=${PACKAGES_NETDATA}&nodejs=${PACKAGES_NETDATA_NODEJS}&python=${PACKAGES_NETDATA_PYTHON}&python3=${PACKAGES_NETDATA_PYTHON3}&mysql=${PACKAGES_NETDATA_PYTHON_MYSQL}&postgres=${PACKAGES_NETDATA_PYTHON_POSTGRES}&pymongo=${PACKAGES_NETDATA_PYTHON_MONGO}&sensors=${PACKAGES_NETDATA_SENSORS}&database=${PACKAGES_NETDATA_DATABASE}&ebpf=${PACKAGES_NETDATA_EBPF}&firehol=${PACKAGES_FIREHOL}&fireqos=${PACKAGES_FIREQOS}&iprange=${PACKAGES_IPRANGE}&update_ipsets=${PACKAGES_UPDATE_IPSETS}&demo=${PACKAGES_NETDATA_DEMO_SITE}"
1892 }
1893
1894 if [ -z "${1}" ]; then
@@ -1935,12 +1963,14 @@ while [ -n "${1}" ]; do
1963 fi
1964 PACKAGES_NETDATA_SENSORS=1
1965 PACKAGES_NETDATA_DATABASE=1
1966 + PACKAGES_NETDATA_EBPF=1
1967 ;;
1968
1969 netdata)
1970 PACKAGES_NETDATA=1
1971 PACKAGES_NETDATA_PYTHON3=1
1972 PACKAGES_NETDATA_DATABASE=1
1973 + PACKAGES_NETDATA_EBPF=1
1974 ;;
1975
1976 python | netdata-python)
@@ -2023,6 +2053,7 @@ while [ -n "${1}" ]; do
2053 PACKAGES_UPDATE_IPSETS=1
2054 PACKAGES_NETDATA_DEMO_SITE=1
2055 PACKAGES_NETDATA_DATABASE=1
2056 + PACKAGES_NETDATA_EBPF=1
2057 ;;
2058
2059 help | -h | --help)
packaging/installer/methods/manual.md
+5 -4
@@ -68,16 +68,16 @@ This is how to do it by hand:
68
69 ```sh
70 # Debian / Ubuntu
71 -apt-get install zlib1g-dev uuid-dev libuv1-dev liblz4-dev libjudy-dev libssl-dev libmnl-dev gcc make git autoconf autoconf-archive autogen automake pkg-config curl python cmake
71 +apt-get install zlib1g-dev uuid-dev libuv1-dev liblz4-dev libjudy-dev libssl-dev libelf-dev libmnl-dev gcc make git autoconf autoconf-archive autogen automake pkg-config curl python cmake
72
73 # Fedora
74 -dnf install zlib-devel libuuid-devel libuv-devel lz4-devel Judy-devel openssl-devel libmnl-devel gcc make git autoconf autoconf-archive autogen automake pkgconfig curl findutils python cmake
74 +dnf install zlib-devel libuuid-devel libuv-devel lz4-devel Judy-devel openssl-devel elfutils-libelf-devel libmnl-devel gcc make git autoconf autoconf-archive autogen automake pkgconfig curl findutils python cmake
75
76 # CentOS / Red Hat Enterprise Linux
77 -yum install autoconf automake curl gcc git libmnl-devel libuuid-devel openssl-devel libuv-devel lz4-devel Judy-devel make nc pkgconfig python zlib-devel cmake
77 +yum install autoconf automake curl gcc git libmnl-devel libuuid-devel openssl-devel libuv-devel lz4-devel Judy-devel elfutils-libelf-devel make nc pkgconfig python zlib-devel cmake
78
79 # openSUSE
80 -zypper install zlib-devel libuuid-devel libuv-devel liblz4-devel judy-devel libopenssl-devel libmnl-devel gcc make git autoconf autoconf-archive autogen automake pkgconfig curl findutils python cmake
80 +zypper install zlib-devel libuuid-devel libuv-devel liblz4-devel judy-devel libopenssl-devel libelf-devel libmnl-devel gcc make git autoconf autoconf-archive autogen automake pkgconfig curl findutils python cmake
81 ```
82
83 Once Netdata is compiled, to run it the following packages are required (already installed using the above commands):
@@ -107,6 +107,7 @@ Netdata plugins and various aspects of Netdata can be enabled or benefit when th
107 | `python-pymongo`|used for monitoring **mongodb** databases|
108 | `nodejs`|used for `node.js` plugins for monitoring **named** and **SNMP** devices|
109 | `lm-sensors`|for monitoring **hardware sensors**|
110 +| `libelf`|for monitoring kernel-level metrics using eBPF|
111 | `libmnl`|for collecting netfilter metrics|
112 | `netcat`|for shell plugins to collect metrics from remote systems|
113
packaging/libbpf.checksums new
+1
@@ -0,0 +1 @@
1 +c216c13b48f5fbd870a9b10a9cb747e0e6063f547e327c4d5a0688713e26a1a4 v0.0.9.tar.gz
packaging/libbpf.version new
+1
@@ -0,0 +1 @@
1 +0.0.9