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
+[](<>)
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