Split eBPF programs (#11401)
thiagoftsm committed
Aug 11, 2021 at 19:12 UTC
5518445f5e69a8c88684f1dcb4e78ff0f425bad0
23 files changed
+774
-225
CMakeLists.txt
+2
@@ -492,6 +492,8 @@ set(EBPF_PROCESS_PLUGIN_FILES
492
collectors/ebpf.plugin/ebpf_dcstat.h
493
collectors/ebpf.plugin/ebpf_disk.c
494
collectors/ebpf.plugin/ebpf_disk.h
495
+ collectors/ebpf.plugin/ebpf_fd.c
496
+ collectors/ebpf.plugin/ebpf_fd.h
497
collectors/ebpf.plugin/ebpf_mount.c
498
collectors/ebpf.plugin/ebpf_mount.h
499
collectors/ebpf.plugin/ebpf_filesystem.c
Makefile.am
+2
@@ -295,6 +295,8 @@ EBPF_PLUGIN_FILES = \
295
collectors/ebpf.plugin/ebpf_dcstat.h \
296
collectors/ebpf.plugin/ebpf_disk.c \
297
collectors/ebpf.plugin/ebpf_disk.h \
298
+ collectors/ebpf.plugin/ebpf_fd.c \
299
+ collectors/ebpf.plugin/ebpf_fd.h \
300
collectors/ebpf.plugin/ebpf_filesystem.c \
301
collectors/ebpf.plugin/ebpf_filesystem.h \
302
collectors/ebpf.plugin/ebpf_mount.c \
collectors/all.h
+5
-1
@@ -154,7 +154,11 @@
154
#define NETDATA_CHART_PRIO_EBPF_FILESYSTEM_CHARTS 2160
155
156
// Mount Points
157
-#define NETDATA_CHART_PRIO_EBPF_MOUNT_CHARTS 2195
157
+#define NETDATA_CHART_PRIO_EBPF_MOUNT_CHARTS 2190
158
+
159
+// File descriptor
160
+#define NETDATA_CHART_PRIO_EBPF_FD_CHARTS 2195
161
+
162
163
// NFS (server)
164
collectors/ebpf.plugin/Makefile.am
+1
@@ -35,6 +35,7 @@ dist_ebpfconfig_DATA = \
35
ebpf.d/cachestat.conf \
36
ebpf.d/dcstat.conf \
37
ebpf.d/disk.conf \
38
+ ebpf.d/fd.conf \
39
ebpf.d/filesystem.conf \
40
ebpf.d/mount.conf \
41
ebpf.d/network.conf \
collectors/ebpf.plugin/README.md
+13
-7
@@ -210,6 +210,16 @@ When the integration is enabled, eBPF collector allocates memory for each proces
210
211
The eBPF collector enables and runs the following eBPF programs by default:
212
213
+- `fd` : This eBPF program creates charts that show information about calls to open files.
214
+- `mount`: This eBPF program creates charts that show calls for syscalls mount(2) and umount(2).
215
+- `sync`: Montitor calls for syscalls sync(2), fsync(2), fdatasync(2), syncfs(2), msync(2), and sync_file_range(2).
216
+- `network viewer`: This eBPF program creates charts with information about `TCP` and `UDP` functions, including the
217
+ bandwidth consumed by each.
218
+- `vfs`: This eBPF program creates charts that show information about VFS (Virtual File System) functions.
219
+- `process`: This eBPF program creates charts that show information about process life.
220
+ When in `return` mode, it also creates charts showing errors when these operations are executed.
221
+
222
+You can also enable the following eBPF programs:
223
- `cachestat`: Netdata's eBPF data collector creates charts about the memory page cache. When the integration with
224
[`apps.plugin`](/collectors/apps.plugin/README.md) is enabled, this collector creates charts for the whole host _and_
225
for each application.
@@ -217,13 +227,8 @@ The eBPF collector enables and runs the following eBPF programs by default:
227
`kprobes` for `lookup_fast()` and `d_lookup()` to identify if files are inside directory cache, outside and
228
files are not found.
229
- `disk` : This eBPF program creates charts that show information about disk latency independent of filesystem.
220
-- `filesystem`: This eBPF program creates charts that show latency information for selected filesystem.
221
-- `process`: This eBPF program creates charts that show information about process creation, calls to open files.
222
- When in `return` mode, it also creates charts showing errors when these operations are executed.
223
-- `network viewer`: This eBPF program creates charts with information about `TCP` and `UDP` functions, including the
224
- bandwidth consumed by each.
225
-- `sync`: Montitor calls for syscalls sync(2), fsync(2), fdatasync(2), syncfs(2), msync(2), and sync_file_range(2).
226
-- `vfs`: This eBPF program creates charts that show information about VFS (Virtual File System) functions.
230
+- `filesystem` : This eBPF program creates charts that show information about some filesystem latency.
231
+- `swap` : This eBPF program creates charts that show information about swap access.
232
233
## Thread configuration
234
@@ -242,6 +247,7 @@ The following configuration files are available:
247
- `cachestat.conf`: Configuration for the `cachestat` thread.
248
- `dcstat.conf`: Configuration for the `dcstat` thread.
249
- `disk.conf`: Configuration for the `disk` thread.
250
+- `fd.conf`: Configuration for the `file descriptor` thread.
251
- `filesystem.conf`: Configuration for the `filesystem` thread.
252
- `process.conf`: Configuration for the `process` thread.
253
- `network.conf`: Configuration for the `network viewer` thread. This config file overwrites the global options and
collectors/ebpf.plugin/ebpf.c
+48
-19
@@ -105,7 +105,7 @@ ebpf_module_t ebpf_modules[] = {
105
.optional = 0, .apps_routine = ebpf_swap_create_apps_charts, .maps = NULL,
106
.pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &swap_config,
107
.config_file = NETDATA_DIRECTORY_SWAP_CONFIG_FILE},
108
- { .thread_name = "vfs", .config_name = "swap", .enabled = 0, .start_routine = ebpf_vfs_thread,
108
+ { .thread_name = "vfs", .config_name = "vfs", .enabled = 0, .start_routine = ebpf_vfs_thread,
109
.update_time = 1, .global_charts = 1, .apps_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY,
110
.optional = 0, .apps_routine = ebpf_vfs_create_apps_charts, .maps = NULL,
111
.pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &vfs_config,
@@ -114,17 +114,22 @@ ebpf_module_t ebpf_modules[] = {
114
.update_time = 1, .global_charts = 1, .apps_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY,
115
.optional = 0, .apps_routine = NULL, .maps = NULL,
116
.pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &fs_config,
117
- .config_file = NETDATA_SYNC_CONFIG_FILE},
117
+ .config_file = NETDATA_FILESYSTEM_CONFIG_FILE},
118
{ .thread_name = "disk", .config_name = "disk", .enabled = 0, .start_routine = ebpf_disk_thread,
119
.update_time = 1, .global_charts = 1, .apps_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY,
120
.optional = 0, .apps_routine = NULL, .maps = NULL,
121
.pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &disk_config,
122
- .config_file = NETDATA_SYNC_CONFIG_FILE},
122
+ .config_file = NETDATA_DISK_CONFIG_FILE},
123
{ .thread_name = "mount", .config_name = "mount", .enabled = 0, .start_routine = ebpf_mount_thread,
124
.update_time = 1, .global_charts = 1, .apps_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY,
125
.optional = 0, .apps_routine = NULL, .maps = NULL,
126
.pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &mount_config,
127
- .config_file = NETDATA_SYNC_CONFIG_FILE},
127
+ .config_file = NETDATA_MOUNT_CONFIG_FILE},
128
+ { .thread_name = "fd", .config_name = "fd", .enabled = 0, .start_routine = ebpf_fd_thread,
129
+ .update_time = 1, .global_charts = 1, .apps_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY,
130
+ .optional = 0, .apps_routine = ebpf_fd_create_apps_charts, .maps = NULL,
131
+ .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &fd_config,
132
+ .config_file = NETDATA_FD_CONFIG_FILE},
133
{ .thread_name = NULL, .enabled = 0, .start_routine = NULL, .update_time = 1,
134
.global_charts = 0, .apps_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY,
135
.optional = 0, .apps_routine = NULL, .maps = NULL, .pid_map_size = 0, .names = NULL,
@@ -199,6 +204,12 @@ static void ebpf_exit(int sig)
204
freez(vfs_pid);
205
}
206
207
+ if (ebpf_modules[EBPF_MODULE_FD_IDX].enabled) {
208
+ ebpf_modules[EBPF_MODULE_FD_IDX].enabled = 0;
209
+ clean_fd_pid_structures();
210
+ freez(fd_pid);
211
+ }
212
+
213
/*
214
int ret = fork();
215
if (ret < 0) // error
@@ -1040,6 +1051,13 @@ static void read_collector_values(int *disable_apps)
1051
started++;
1052
}
1053
1054
+ enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "fd",
1055
+ CONFIG_BOOLEAN_YES);
1056
+ if (enabled) {
1057
+ ebpf_enable_chart(EBPF_MODULE_FD_IDX, *disable_apps);
1058
+ started++;
1059
+ }
1060
+
1061
if (!started){
1062
ebpf_enable_all_charts(*disable_apps);
1063
// Read network viewer section
@@ -1118,21 +1136,22 @@ static void parse_args(int argc, char **argv)
1136
int freq = 0;
1137
int option_index = 0;
1138
static struct option long_options[] = {
1121
- {"help", no_argument, 0, 'h' },
1122
- {"version", no_argument, 0, 'v' },
1123
- {"global", no_argument, 0, 'g' },
1124
- {"all", no_argument, 0, 'a' },
1125
- {"cachestat", no_argument, 0, 'c' },
1126
- {"dcstat", no_argument, 0, 'd' },
1127
- {"disk", no_argument, 0, 'k' },
1128
- {"filesystem", no_argument, 0, 'i' },
1129
- {"mount", no_argument, 0, 'm' },
1130
- {"net", no_argument, 0, 'n' },
1131
- {"process", no_argument, 0, 'p' },
1132
- {"return", no_argument, 0, 'r' },
1133
- {"sync", no_argument, 0, 's' },
1134
- {"swap", no_argument, 0, 'w' },
1135
- {"vfs", no_argument, 0, 'f' },
1139
+ {"help", no_argument, 0, 'h' },
1140
+ {"version", no_argument, 0, 'v' },
1141
+ {"global", no_argument, 0, 'g' },
1142
+ {"all", no_argument, 0, 'a' },
1143
+ {"cachestat", no_argument, 0, 'c' },
1144
+ {"dcstat", no_argument, 0, 'd' },
1145
+ {"disk", no_argument, 0, 'k' },
1146
+ {"filesystem", no_argument, 0, 'i' },
1147
+ {"filedescriptor", no_argument, 0, 'e' },
1148
+ {"mount", no_argument, 0, 'm' },
1149
+ {"net", no_argument, 0, 'n' },
1150
+ {"process", no_argument, 0, 'p' },
1151
+ {"return", no_argument, 0, 'r' },
1152
+ {"sync", no_argument, 0, 's' },
1153
+ {"swap", no_argument, 0, 'w' },
1154
+ {"vfs", no_argument, 0, 'f' },
1155
{0, 0, 0, 0}
1156
};
1157
@@ -1215,6 +1234,14 @@ static void parse_args(int argc, char **argv)
1234
ebpf_enable_chart(EBPF_MODULE_MOUNT_IDX, disable_apps);
1235
#ifdef NETDATA_INTERNAL_CHECKS
1236
info("EBPF enabling \"mount\" chart, because it was started with the option \"--mount\" or \"-m\".");
1237
+#endif
1238
+ break;
1239
+ }
1240
+ case 'e': {
1241
+ enabled = 1;
1242
+ ebpf_enable_chart(EBPF_MODULE_FD_IDX, disable_apps);
1243
+#ifdef NETDATA_INTERNAL_CHECKS
1244
+ info("EBPF enabling \"filedescriptor\" chart, because it was started with the option \"--filedescriptor\" or \"-e\".");
1245
#endif
1246
break;
1247
}
@@ -1544,6 +1571,8 @@ int main(int argc, char **argv)
1571
NULL, NULL, ebpf_modules[EBPF_MODULE_DISK_IDX].start_routine},
1572
{"EBPF MOUNT" , NULL, NULL, 1,
1573
NULL, NULL, ebpf_modules[EBPF_MODULE_MOUNT_IDX].start_routine},
1574
+ {"EBPF FD" , NULL, NULL, 1,
1575
+ NULL, NULL, ebpf_modules[EBPF_MODULE_FD_IDX].start_routine},
1576
{NULL , NULL, NULL, 0,
1577
NULL, NULL, NULL}
1578
};
collectors/ebpf.plugin/ebpf.d.conf
+3
-1
@@ -28,9 +28,10 @@
28
# `cachestat` : Make charts for kernel functions related to page cache.
29
# `dcstat` : Make charts for kernel functions related to directory cache.
30
# `disk` : Monitor I/O latencies for disks
31
+# `fd` : This eBPF program creates charts that show information about file manipulation.
32
# `mount` : Monitor calls for syscalls mount and umount
33
# `filesystem`: Monitor calls for functions used to manipulate specific filesystems
33
-# `process` : This eBPF program creates charts that show information about process creation, and file manipulation.
34
+# `process` : This eBPF program creates charts that show information about process life.
35
# `socket` : This eBPF program creates charts with information about `TCP` and `UDP` functions, including the
36
# bandwidth consumed by each.
37
# `sync` : Montitor calls for syscall sync(2).
@@ -41,6 +42,7 @@
42
cachestat = no
43
dcstat = no
44
disk = no
45
+ fd = yes
46
filesystem = no
47
mount = yes
48
process = yes
collectors/ebpf.plugin/ebpf.d/fd.conf
new
+17
@@ -0,0 +1,17 @@
1
+# The `ebpf load mode` option accepts the following values :
2
+# `entry` : The eBPF collector only monitors calls for the functions, and does not show charts related to errors.
3
+# `return : In the `return` mode, the eBPF collector monitors the same kernel functions as `entry`, but also creates
4
+# new charts for the return of these functions, such as errors.
5
+#
6
+# The eBPF collector also creates charts for each running application through an integration with the `apps plugin`.
7
+# If you want to disable the integration with `apps.plugin` along with the above charts, change the setting `apps` to
8
+# 'no'.
9
+#
10
+# The `pid table size` defines the maximum number of PIDs stored inside the hash table.
11
+#
12
+# Uncomment lines to define specific options for thread.
13
+[global]
14
+# ebpf load mode = entry
15
+# apps = yes
16
+ update every = 1
17
+# pid table size = 32768
collectors/ebpf.plugin/ebpf.h
+2
-1
@@ -83,7 +83,8 @@ enum ebpf_module_indexes {
83
EBPF_MODULE_VFS_IDX,
84
EBPF_MODULE_FILESYSTEM_IDX,
85
EBPF_MODULE_DISK_IDX,
86
- EBPF_MODULE_MOUNT_IDX
86
+ EBPF_MODULE_MOUNT_IDX,
87
+ EBPF_MODULE_FD_IDX
88
};
89
90
// Copied from musl header
collectors/ebpf.plugin/ebpf_apps.c
+6
@@ -945,6 +945,12 @@ void cleanup_variables_from_other_threads(uint32_t pid)
945
freez(vfs_pid[pid]);
946
vfs_pid[pid] = NULL;
947
}
948
+
949
+ // Clean fd structure
950
+ if (fd_pid) {
951
+ freez(fd_pid[pid]);
952
+ fd_pid[pid] = NULL;
953
+ }
954
}
955
956
/**
collectors/ebpf.plugin/ebpf_apps.h
+3
-1
@@ -11,7 +11,7 @@
11
#include "libnetdata/ebpf/ebpf.h"
12
13
#define NETDATA_APPS_FAMILY "apps"
14
-#define NETDATA_APPS_FILE_GROUP "file (eBPF)"
14
+#define NETDATA_APPS_FILE_GROUP "file_access"
15
#define NETDATA_APPS_VFS_GROUP "vfs (eBPF)"
16
#define NETDATA_APPS_PROCESS_GROUP "process (eBPF)"
17
#define NETDATA_APPS_NET_GROUP "net (eBPF)"
@@ -21,6 +21,7 @@
21
#include "ebpf_process.h"
22
#include "ebpf_dcstat.h"
23
#include "ebpf_disk.h"
24
+#include "ebpf_fd.h"
25
#include "ebpf_filesystem.h"
26
#include "ebpf_cachestat.h"
27
#include "ebpf_mount.h"
@@ -120,6 +121,7 @@ struct target {
121
netdata_publish_dcstat_t dcstat;
122
netdata_publish_swap_t swap;
123
netdata_publish_vfs_t vfs;
124
+ netdata_fd_stat_t fd;
125
126
/* These variables are not necessary for eBPF collector
127
kernel_uint_t minflt;
collectors/ebpf.plugin/ebpf_disk.h
+3
@@ -13,6 +13,9 @@
13
14
#define NETDATA_LATENCY_DISK_SLEEP_MS 650000ULL
15
16
+// Process configuration name
17
+#define NETDATA_DISK_CONFIG_FILE "disk.conf"
18
+
19
// Decode function extracted from: https://elixir.bootlin.com/linux/v5.10.8/source/include/linux/kdev_t.h#L7
20
#define MINORBITS 20
21
#define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi))
collectors/ebpf.plugin/ebpf_fd.c
new
+533
@@ -0,0 +1,533 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+#include "ebpf.h"
4
+#include "ebpf_fd.h"
5
+
6
+static char *fd_dimension_names[NETDATA_FD_SYSCALL_END] = { "open", "close" };
7
+static char *fd_id_names[NETDATA_FD_SYSCALL_END] = { "do_sys_open", "__close_fd" };
8
+
9
+static netdata_syscall_stat_t fd_aggregated_data[NETDATA_FD_SYSCALL_END];
10
+static netdata_publish_syscall_t fd_publish_aggregated[NETDATA_FD_SYSCALL_END];
11
+
12
+static ebpf_local_maps_t fd_maps[] = {{.name = "tbl_fd_pid", .internal_input = ND_EBPF_DEFAULT_PID_SIZE,
13
+ .user_input = 0,
14
+ .type = NETDATA_EBPF_MAP_RESIZABLE | NETDATA_EBPF_MAP_PID,
15
+ .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED},
16
+ {.name = "tbl_fd_global", .internal_input = NETDATA_KEY_END_VECTOR,
17
+ .user_input = 0, .type = NETDATA_EBPF_MAP_STATIC,
18
+ .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED},
19
+ {.name = "fd_ctrl", .internal_input = NETDATA_CONTROLLER_END,
20
+ .user_input = 0,
21
+ .type = NETDATA_EBPF_MAP_CONTROLLER,
22
+ .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED},
23
+ {.name = NULL, .internal_input = 0, .user_input = 0,
24
+ .type = NETDATA_EBPF_MAP_CONTROLLER,
25
+ .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED}};
26
+
27
+
28
+struct config fd_config = { .first_section = NULL, .last_section = NULL, .mutex = NETDATA_MUTEX_INITIALIZER,
29
+ .index = {.avl_tree = { .root = NULL, .compar = appconfig_section_compare },
30
+ .rwlock = AVL_LOCK_INITIALIZER } };
31
+
32
+static ebpf_data_t fd_data;
33
+static struct bpf_link **probe_links = NULL;
34
+static struct bpf_object *objects = NULL;
35
+
36
+struct netdata_static_thread fd_thread = {"FD KERNEL", NULL, NULL, 1, NULL,
37
+ NULL, NULL};
38
+static int read_thread_closed = 1;
39
+static netdata_idx_t fd_hash_values[NETDATA_FD_COUNTER];
40
+static netdata_idx_t *fd_values = NULL;
41
+
42
+netdata_fd_stat_t *fd_vector = NULL;
43
+netdata_fd_stat_t **fd_pid;
44
+
45
+/*****************************************************************
46
+ *
47
+ * FUNCTIONS TO CLOSE THE THREAD
48
+ *
49
+ *****************************************************************/
50
+
51
+/**
52
+ * Clean PID structures
53
+ *
54
+ * Clean the allocated structures.
55
+ */
56
+void clean_fd_pid_structures() {
57
+ struct pid_stat *pids = root_of_pids;
58
+ while (pids) {
59
+ freez(fd_pid[pids->pid]);
60
+
61
+ pids = pids->next;
62
+ }
63
+}
64
+
65
+/**
66
+ * Clean up the main thread.
67
+ *
68
+ * @param ptr thread data.
69
+ */
70
+static void ebpf_fd_cleanup(void *ptr)
71
+{
72
+ ebpf_module_t *em = (ebpf_module_t *)ptr;
73
+ if (!em->enabled)
74
+ return;
75
+
76
+ heartbeat_t hb;
77
+ heartbeat_init(&hb);
78
+ uint32_t tick = 2 * USEC_PER_MS;
79
+ while (!read_thread_closed) {
80
+ usec_t dt = heartbeat_next(&hb, tick);
81
+ UNUSED(dt);
82
+ }
83
+
84
+ ebpf_cleanup_publish_syscall(fd_publish_aggregated);
85
+ freez(fd_data.map_fd);
86
+ freez(fd_thread.thread);
87
+ freez(fd_values);
88
+ freez(fd_vector);
89
+
90
+ if (probe_links) {
91
+ struct bpf_program *prog;
92
+ size_t i = 0 ;
93
+ bpf_object__for_each_program(prog, objects) {
94
+ bpf_link__destroy(probe_links[i]);
95
+ i++;
96
+ }
97
+ bpf_object__close(objects);
98
+ }
99
+}
100
+
101
+/*****************************************************************
102
+ *
103
+ * MAIN LOOP
104
+ *
105
+ *****************************************************************/
106
+
107
+/**
108
+ * Send data to Netdata calling auxiliar functions.
109
+ *
110
+ * @param em the structure with thread information
111
+ */
112
+static void ebpf_fd_send_data(ebpf_module_t *em)
113
+{
114
+ fd_publish_aggregated[NETDATA_FD_SYSCALL_OPEN].ncall = fd_hash_values[NETDATA_KEY_CALLS_DO_SYS_OPEN];
115
+ fd_publish_aggregated[NETDATA_FD_SYSCALL_OPEN].nerr = fd_hash_values[NETDATA_KEY_ERROR_DO_SYS_OPEN];
116
+
117
+ fd_publish_aggregated[NETDATA_FD_SYSCALL_CLOSE].ncall = fd_hash_values[NETDATA_KEY_CALLS_CLOSE_FD];
118
+ fd_publish_aggregated[NETDATA_FD_SYSCALL_CLOSE].nerr = fd_hash_values[NETDATA_KEY_ERROR_CLOSE_FD];
119
+
120
+ write_count_chart(NETDATA_FILE_OPEN_CLOSE_COUNT, NETDATA_FILESYSTEM_FAMILY, fd_publish_aggregated,
121
+ NETDATA_FD_SYSCALL_END);
122
+
123
+ if (em->mode < MODE_ENTRY) {
124
+ write_err_chart(NETDATA_FILE_OPEN_ERR_COUNT, NETDATA_FILESYSTEM_FAMILY,
125
+ fd_publish_aggregated, NETDATA_FD_SYSCALL_END);
126
+ }
127
+}
128
+
129
+/**
130
+ * Read global counter
131
+ *
132
+ * Read the table with number of calls for all functions
133
+ */
134
+static void read_global_table()
135
+{
136
+ uint32_t idx;
137
+ netdata_idx_t *val = fd_hash_values;
138
+ netdata_idx_t *stored = fd_values;
139
+ int fd = fd_maps[NETDATA_FD_GLOBAL_STATS].map_fd;
140
+
141
+ for (idx = NETDATA_KEY_CALLS_DO_SYS_OPEN; idx < NETDATA_FD_COUNTER; idx++) {
142
+ if (!bpf_map_lookup_elem(fd, &idx, stored)) {
143
+ int i;
144
+ int end = ebpf_nprocs;
145
+ netdata_idx_t total = 0;
146
+ for (i = 0; i < end; i++)
147
+ total += stored[i];
148
+
149
+ val[idx] = total;
150
+ }
151
+ }
152
+}
153
+
154
+/**
155
+ * File descriptor read hash
156
+ *
157
+ * This is the thread callback.
158
+ * This thread is necessary, because we cannot freeze the whole plugin to read the data.
159
+ *
160
+ * @param ptr It is a NULL value for this thread.
161
+ *
162
+ * @return It always returns NULL.
163
+ */
164
+void *ebpf_fd_read_hash(void *ptr)
165
+{
166
+ read_thread_closed = 0;
167
+
168
+ heartbeat_t hb;
169
+ heartbeat_init(&hb);
170
+
171
+ ebpf_module_t *em = (ebpf_module_t *)ptr;
172
+ usec_t step = NETDATA_FD_SLEEP_MS * em->update_time;
173
+ while (!close_ebpf_plugin) {
174
+ usec_t dt = heartbeat_next(&hb, step);
175
+ (void)dt;
176
+
177
+ read_global_table();
178
+ }
179
+
180
+ read_thread_closed = 1;
181
+ return NULL;
182
+}
183
+
184
+/**
185
+ * Apps Accumulator
186
+ *
187
+ * Sum all values read from kernel and store in the first address.
188
+ *
189
+ * @param out the vector with read values.
190
+ */
191
+static void fd_apps_accumulator(netdata_fd_stat_t *out)
192
+{
193
+ int i, end = (running_on_kernel >= NETDATA_KERNEL_V4_15) ? ebpf_nprocs : 1;
194
+ netdata_fd_stat_t *total = &out[0];
195
+ for (i = 1; i < end; i++) {
196
+ netdata_fd_stat_t *w = &out[i];
197
+ total->open_call += w->open_call;
198
+ total->close_call += w->close_call;
199
+ total->open_err += w->open_err;
200
+ total->close_err += w->close_err;
201
+ }
202
+}
203
+
204
+/**
205
+ * Fill PID
206
+ *
207
+ * Fill PID structures
208
+ *
209
+ * @param current_pid pid that we are collecting data
210
+ * @param out values read from hash tables;
211
+ */
212
+static void fd_fill_pid(uint32_t current_pid, netdata_fd_stat_t *publish)
213
+{
214
+ netdata_fd_stat_t *curr = fd_pid[current_pid];
215
+ if (!curr) {
216
+ curr = callocz(1, sizeof(netdata_fd_stat_t));
217
+ fd_pid[current_pid] = curr;
218
+ }
219
+
220
+ memcpy(curr, &publish[0], sizeof(netdata_fd_stat_t));
221
+}
222
+
223
+/**
224
+ * Read APPS table
225
+ *
226
+ * Read the apps table and store data inside the structure.
227
+ */
228
+static void read_apps_table()
229
+{
230
+ netdata_fd_stat_t *fv = fd_vector;
231
+ uint32_t key;
232
+ struct pid_stat *pids = root_of_pids;
233
+ int fd = fd_maps[NETDATA_FD_PID_STATS].map_fd;
234
+ size_t length = sizeof(netdata_fd_stat_t) * ebpf_nprocs;
235
+ while (pids) {
236
+ key = pids->pid;
237
+
238
+ if (bpf_map_lookup_elem(fd, &key, fv)) {
239
+ pids = pids->next;
240
+ continue;
241
+ }
242
+
243
+ fd_apps_accumulator(fv);
244
+
245
+ fd_fill_pid(key, fv);
246
+
247
+ // We are cleaning to avoid passing data read from one process to other.
248
+ memset(fv, 0, length);
249
+
250
+ pids = pids->next;
251
+ }
252
+}
253
+
254
+/**
255
+ * Sum PIDs
256
+ *
257
+ * Sum values for all targets.
258
+ *
259
+ * @param fd the output
260
+ * @param root list of pids
261
+ */
262
+static void ebpf_fd_sum_pids(netdata_fd_stat_t *fd, struct pid_on_target *root)
263
+{
264
+ uint32_t open_call = 0;
265
+ uint32_t close_call = 0;
266
+ uint32_t open_err = 0;
267
+ uint32_t close_err = 0;
268
+
269
+ while (root) {
270
+ int32_t pid = root->pid;
271
+ netdata_fd_stat_t *w = fd_pid[pid];
272
+ if (w) {
273
+ open_call += w->open_call;
274
+ close_call += w->close_call;
275
+ open_err += w->open_err;
276
+ close_err += w->close_err;
277
+ }
278
+
279
+ root = root->next;
280
+ }
281
+
282
+ // These conditions were added, because we are using incremental algorithm
283
+ fd->open_call = (open_call >= fd->open_call) ? open_call : fd->open_call;
284
+ fd->close_call = (close_call >= fd->close_call) ? close_call : fd->close_call;
285
+ fd->open_err = (open_err >= fd->open_err) ? open_err : fd->open_err;
286
+ fd->close_err = (close_err >= fd->close_err) ? close_err : fd->close_err;
287
+}
288
+
289
+/**
290
+ * Send data to Netdata calling auxiliar functions.
291
+ *
292
+ * @param em the structure with thread information
293
+ * @param root the target list.
294
+*/
295
+void ebpf_fd_send_apps_data(ebpf_module_t *em, struct target *root)
296
+{
297
+ struct target *w;
298
+ for (w = root; w; w = w->next) {
299
+ if (unlikely(w->exposed && w->processes)) {
300
+ ebpf_fd_sum_pids(&w->fd, w->root_pid);
301
+ }
302
+ }
303
+
304
+ write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_SYSCALL_APPS_FILE_OPEN);
305
+ for (w = root; w; w = w->next) {
306
+ if (unlikely(w->exposed && w->processes)) {
307
+ write_chart_dimension(w->name, w->fd.open_call);
308
+ }
309
+ }
310
+ write_end_chart();
311
+
312
+ if (em->mode < MODE_ENTRY) {
313
+ write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_SYSCALL_APPS_FILE_OPEN_ERROR);
314
+ for (w = root; w; w = w->next) {
315
+ if (unlikely(w->exposed && w->processes)) {
316
+ write_chart_dimension(w->name, w->fd.open_err);
317
+ }
318
+ }
319
+ write_end_chart();
320
+ }
321
+
322
+ write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_SYSCALL_APPS_FILE_CLOSED);
323
+ for (w = root; w; w = w->next) {
324
+ if (unlikely(w->exposed && w->processes)) {
325
+ write_chart_dimension(w->name, w->fd.close_call);
326
+ }
327
+ }
328
+ write_end_chart();
329
+
330
+ if (em->mode < MODE_ENTRY) {
331
+ write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_SYSCALL_APPS_FILE_CLOSE_ERROR);
332
+ for (w = root; w; w = w->next) {
333
+ if (unlikely(w->exposed && w->processes)) {
334
+ write_chart_dimension(w->name, w->fd.close_err);
335
+ }
336
+ }
337
+ write_end_chart();
338
+ }
339
+}
340
+
341
+/**
342
+* Main loop for this collector.
343
+*/
344
+static void fd_collector(ebpf_module_t *em)
345
+{
346
+ fd_thread.thread = mallocz(sizeof(netdata_thread_t));
347
+ fd_thread.start_routine = ebpf_fd_read_hash;
348
+
349
+ netdata_thread_create(fd_thread.thread, fd_thread.name, NETDATA_THREAD_OPTION_JOINABLE,
350
+ ebpf_fd_read_hash, em);
351
+
352
+ int apps = em->apps_charts;
353
+ while (!close_ebpf_plugin) {
354
+ pthread_mutex_lock(&collect_data_mutex);
355
+ pthread_cond_wait(&collect_data_cond_var, &collect_data_mutex);
356
+
357
+ if (apps)
358
+ read_apps_table();
359
+
360
+ pthread_mutex_lock(&lock);
361
+
362
+ ebpf_fd_send_data(em);
363
+
364
+ if (apps)
365
+ ebpf_fd_send_apps_data(em, apps_groups_root_target);
366
+
367
+ pthread_mutex_unlock(&lock);
368
+ pthread_mutex_unlock(&collect_data_mutex);
369
+ }
370
+}
371
+
372
+/*****************************************************************
373
+ *
374
+ * CREATE CHARTS
375
+ *
376
+ *****************************************************************/
377
+
378
+/**
379
+ * Create apps charts
380
+ *
381
+ * Call ebpf_create_chart to create the charts on apps submenu.
382
+ *
383
+ * @param em a pointer to the structure with the default values.
384
+ */
385
+void ebpf_fd_create_apps_charts(struct ebpf_module *em, void *ptr)
386
+{
387
+ struct target *root = ptr;
388
+ ebpf_create_charts_on_apps(NETDATA_SYSCALL_APPS_FILE_OPEN,
389
+ "Number of open files",
390
+ EBPF_COMMON_DIMENSION_CALL,
391
+ NETDATA_APPS_FILE_GROUP,
392
+ NETDATA_EBPF_CHART_TYPE_STACKED,
393
+ 20061,
394
+ ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
395
+ root, NETDATA_EBPF_MODULE_NAME_PROCESS);
396
+
397
+ if (em->mode < MODE_ENTRY) {
398
+ ebpf_create_charts_on_apps(NETDATA_SYSCALL_APPS_FILE_OPEN_ERROR,
399
+ "Fails to open files",
400
+ EBPF_COMMON_DIMENSION_CALL,
401
+ NETDATA_APPS_FILE_GROUP,
402
+ NETDATA_EBPF_CHART_TYPE_STACKED,
403
+ 20062,
404
+ ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
405
+ root, NETDATA_EBPF_MODULE_NAME_PROCESS);
406
+ }
407
+
408
+ ebpf_create_charts_on_apps(NETDATA_SYSCALL_APPS_FILE_CLOSED,
409
+ "Files closed",
410
+ EBPF_COMMON_DIMENSION_CALL,
411
+ NETDATA_APPS_FILE_GROUP,
412
+ NETDATA_EBPF_CHART_TYPE_STACKED,
413
+ 20063,
414
+ ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
415
+ root, NETDATA_EBPF_MODULE_NAME_PROCESS);
416
+
417
+ if (em->mode < MODE_ENTRY) {
418
+ ebpf_create_charts_on_apps(NETDATA_SYSCALL_APPS_FILE_CLOSE_ERROR,
419
+ "Fails to close files",
420
+ EBPF_COMMON_DIMENSION_CALL,
421
+ NETDATA_APPS_FILE_GROUP,
422
+ NETDATA_EBPF_CHART_TYPE_STACKED,
423
+ 20064,
424
+ ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
425
+ root, NETDATA_EBPF_MODULE_NAME_PROCESS);
426
+ }
427
+}
428
+
429
+/**
430
+ * Create global charts
431
+ *
432
+ * Call ebpf_create_chart to create the charts for the collector.
433
+ *
434
+ * @param em a pointer to the structure with the default values.
435
+ */
436
+static void ebpf_create_fd_global_charts(ebpf_module_t *em)
437
+{
438
+ ebpf_create_chart(NETDATA_FILESYSTEM_FAMILY,
439
+ NETDATA_FILE_OPEN_CLOSE_COUNT,
440
+ "Open and close calls",
441
+ EBPF_COMMON_DIMENSION_CALL,
442
+ NETDATA_FILE_GROUP,
443
+ NULL,
444
+ NETDATA_EBPF_CHART_TYPE_LINE,
445
+ NETDATA_CHART_PRIO_EBPF_FD_CHARTS,
446
+ ebpf_create_global_dimension,
447
+ fd_publish_aggregated,
448
+ NETDATA_FD_SYSCALL_END,
449
+ NETDATA_EBPF_MODULE_NAME_FD);
450
+
451
+ if (em->mode < MODE_ENTRY) {
452
+ ebpf_create_chart(NETDATA_FILESYSTEM_FAMILY,
453
+ NETDATA_FILE_OPEN_ERR_COUNT,
454
+ "Open fails",
455
+ EBPF_COMMON_DIMENSION_CALL,
456
+ NETDATA_FILE_GROUP,
457
+ NULL,
458
+ NETDATA_EBPF_CHART_TYPE_LINE,
459
+ NETDATA_CHART_PRIO_EBPF_FD_CHARTS + 1,
460
+ ebpf_create_global_dimension,
461
+ fd_publish_aggregated,
462
+ NETDATA_FD_SYSCALL_END,
463
+ NETDATA_EBPF_MODULE_NAME_FD);
464
+ }
465
+}
466
+
467
+/*****************************************************************
468
+ *
469
+ * MAIN THREAD
470
+ *
471
+ *****************************************************************/
472
+
473
+/**
474
+ * Allocate vectors used with this thread.
475
+ *
476
+ * We are not testing the return, because callocz does this and shutdown the software
477
+ * case it was not possible to allocate.
478
+ */
479
+static void ebpf_fd_allocate_global_vectors()
480
+{
481
+ fd_pid = callocz((size_t)pid_max, sizeof(netdata_fd_stat_t *));
482
+ fd_vector = callocz((size_t)ebpf_nprocs, sizeof(netdata_fd_stat_t));
483
+
484
+ fd_values = callocz((size_t)ebpf_nprocs, sizeof(netdata_idx_t));
485
+}
486
+
487
+/**
488
+ * Directory Cache thread
489
+ *
490
+ * Thread used to make dcstat thread
491
+ *
492
+ * @param ptr a pointer to `struct ebpf_module`
493
+ *
494
+ * @return It always returns NULL
495
+ */
496
+void *ebpf_fd_thread(void *ptr)
497
+{
498
+ netdata_thread_cleanup_push(ebpf_fd_cleanup, ptr);
499
+
500
+ ebpf_module_t *em = (ebpf_module_t *)ptr;
501
+ em->maps = fd_maps;
502
+ fill_ebpf_data(&fd_data);
503
+
504
+ if (!em->enabled)
505
+ goto endfd;
506
+
507
+ if (ebpf_update_kernel(&fd_data))
508
+ goto endfd;
509
+
510
+ ebpf_fd_allocate_global_vectors();
511
+
512
+ probe_links = ebpf_load_program(ebpf_plugin_dir, em, kernel_string, &objects, fd_data.map_fd);
513
+ if (!probe_links) {
514
+ goto endfd;
515
+ }
516
+
517
+ int algorithms[NETDATA_FD_SYSCALL_END] = {
518
+ NETDATA_EBPF_INCREMENTAL_IDX, NETDATA_EBPF_INCREMENTAL_IDX
519
+ };
520
+
521
+ ebpf_global_labels(fd_aggregated_data, fd_publish_aggregated, fd_dimension_names, fd_id_names,
522
+ algorithms, NETDATA_FD_SYSCALL_END);
523
+
524
+ pthread_mutex_lock(&lock);
525
+ ebpf_create_fd_global_charts(em);
526
+ pthread_mutex_unlock(&lock);
527
+
528
+ fd_collector(em);
529
+
530
+endfd:
531
+ netdata_thread_cleanup_pop(1);
532
+ return NULL;
533
+}
collectors/ebpf.plugin/ebpf_fd.h
new
+74
@@ -0,0 +1,74 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+#ifndef NETDATA_EBPF_FD_H
4
+#define NETDATA_EBPF_FD_H 1
5
+
6
+// Module name
7
+#define NETDATA_EBPF_MODULE_NAME_FD "filedescriptor"
8
+
9
+#define NETDATA_FD_SLEEP_MS 850000ULL
10
+
11
+// Menu group
12
+#define NETDATA_FILE_GROUP "File_access"
13
+
14
+// Global chart name
15
+#define NETDATA_FILE_OPEN_CLOSE_COUNT "file_descriptor"
16
+#define NETDATA_FILE_OPEN_ERR_COUNT "file_error"
17
+
18
+// Charts created on Apps submenu
19
+#define NETDATA_SYSCALL_APPS_FILE_OPEN "file_open"
20
+#define NETDATA_SYSCALL_APPS_FILE_CLOSED "file_closed"
21
+#define NETDATA_SYSCALL_APPS_FILE_OPEN_ERROR "file_open_error"
22
+#define NETDATA_SYSCALL_APPS_FILE_CLOSE_ERROR "file_close_error"
23
+
24
+// Process configuration name
25
+#define NETDATA_FD_CONFIG_FILE "fd.conf"
26
+
27
+typedef struct netdata_fd_stat {
28
+ uint64_t pid_tgid; // Unique identifier
29
+ uint32_t pid; // Process ID
30
+
31
+ uint32_t open_call; // Open syscalls (open and openat)
32
+ uint32_t close_call; // Close syscall (close)
33
+
34
+ // Errors
35
+ uint32_t open_err;
36
+ uint32_t close_err;
37
+} netdata_fd_stat_t;
38
+
39
+enum fd_tables {
40
+ NETDATA_FD_PID_STATS,
41
+ NETDATA_FD_GLOBAL_STATS,
42
+
43
+ // Keep this as last and don't skip numbers as it is used as element counter
44
+ NETDATA_FD_CONTROLLER
45
+};
46
+
47
+enum fd_counters {
48
+ NETDATA_KEY_CALLS_DO_SYS_OPEN,
49
+ NETDATA_KEY_ERROR_DO_SYS_OPEN,
50
+
51
+ NETDATA_KEY_CALLS_CLOSE_FD,
52
+ NETDATA_KEY_ERROR_CLOSE_FD,
53
+
54
+ // Keep this as last and don't skip numbers as it is used as element counter
55
+ NETDATA_FD_COUNTER
56
+};
57
+
58
+enum fd_syscalls {
59
+ NETDATA_FD_SYSCALL_OPEN,
60
+ NETDATA_FD_SYSCALL_CLOSE,
61
+
62
+ // Do not insert nothing after this value
63
+ NETDATA_FD_SYSCALL_END
64
+};
65
+
66
+
67
+extern void *ebpf_fd_thread(void *ptr);
68
+extern void ebpf_fd_create_apps_charts(struct ebpf_module *em, void *ptr);
69
+extern struct config fd_config;
70
+extern netdata_fd_stat_t **fd_pid;
71
+extern void clean_fd_pid_structures();
72
+
73
+#endif /* NETDATA_EBPF_FD_H */
74
+
collectors/ebpf.plugin/ebpf_filesystem.h
+3
@@ -13,6 +13,9 @@
13
#define NETDATA_FILESYSTEM_CONFIG_NAME "filesystem"
14
#define NETDATA_FILESYSTEM_READ_SLEEP_MS 600000ULL
15
16
+// Process configuration name
17
+#define NETDATA_FILESYSTEM_CONFIG_FILE "filesystem.conf"
18
+
19
typedef struct netdata_fs_hist {
20
uint32_t hist_id;
21
uint32_t bin;
collectors/ebpf.plugin/ebpf_mount.h
+3
@@ -14,6 +14,9 @@
14
#define NETDATA_EBPF_MOUNT_ERRORS "error"
15
#define NETDATA_EBPF_MOUNT_FAMILY "mount (eBPF)"
16
17
+// Process configuration name
18
+#define NETDATA_MOUNT_CONFIG_FILE "mount.conf"
19
+
20
enum mount_counters {
21
NETDATA_KEY_MOUNT_CALL,
22
NETDATA_KEY_UMOUNT_CALL,
collectors/ebpf.plugin/ebpf_process.c
+13
-145
@@ -11,10 +11,8 @@
11
*
12
*****************************************************************/
13
14
-static char *process_dimension_names[NETDATA_KEY_PUBLISH_PROCESS_END] = { "open", "close", "process",
15
- "task", "process", "thread" };
16
-static char *process_id_names[NETDATA_KEY_PUBLISH_PROCESS_END] = { "do_sys_open", "__close_fd", "do_exit",
17
- "release_task", "_do_fork", "sys_clone" };
14
+static char *process_dimension_names[NETDATA_KEY_PUBLISH_PROCESS_END] = { "process", "task", "process", "thread" };
15
+static char *process_id_names[NETDATA_KEY_PUBLISH_PROCESS_END] = { "do_exit", "release_task", "_do_fork", "sys_clone" };
16
static char *status[] = { "process", "zombie" };
17
18
static ebpf_local_maps_t process_maps[] = {{.name = "tbl_pid_stats", .internal_input = ND_EBPF_DEFAULT_PID_SIZE,
@@ -69,24 +67,15 @@ static void ebpf_update_global_publish(netdata_publish_syscall_t *publish, netda
67
netdata_syscall_stat_t *input)
68
{
69
netdata_publish_syscall_t *move = publish;
72
- int selector = NETDATA_KEY_PUBLISH_PROCESS_OPEN;
70
+ int selector = NETDATA_KEY_PUBLISH_PROCESS_EXIT;
71
while (move) {
74
- // Until NETDATA_KEY_PUBLISH_PROCESS_EXIT we are creating accumulators, so it is possible
75
- // to use incremental charts, but after this we will do some math with the values, so we are storing
76
- // absolute values
77
- if (selector < NETDATA_KEY_PUBLISH_PROCESS_EXIT) {
78
- move->ncall = input->call;
79
- move->nbyte = input->bytes;
80
- move->nerr = input->ecall;
81
- } else {
82
- move->ncall = (input->call > move->pcall) ? input->call - move->pcall : move->pcall - input->call;
83
- move->nbyte = (input->bytes > move->pbyte) ? input->bytes - move->pbyte : move->pbyte - input->bytes;
84
- move->nerr = (input->ecall > move->nerr) ? input->ecall - move->perr : move->perr - input->ecall;
72
+ move->ncall = (input->call > move->pcall) ? input->call - move->pcall : move->pcall - input->call;
73
+ move->nbyte = (input->bytes > move->pbyte) ? input->bytes - move->pbyte : move->pbyte - input->bytes;
74
+ move->nerr = (input->ecall > move->nerr) ? input->ecall - move->perr : move->perr - input->ecall;
75
86
- move->pcall = input->call;
87
- move->pbyte = input->bytes;
88
- move->perr = input->ecall;
89
- }
76
+ move->pcall = input->call;
77
+ move->pbyte = input->bytes;
78
+ move->perr = input->ecall;
79
80
input = input->next;
81
move = move->next;
@@ -126,8 +115,6 @@ static void ebpf_process_send_data(ebpf_module_t *em)
115
netdata_publish_vfs_common_t pvc;
116
ebpf_update_global_publish(process_publish_aggregated, &pvc, process_aggregated_data);
117
129
- write_count_chart(NETDATA_FILE_OPEN_CLOSE_COUNT, NETDATA_EBPF_FAMILY, process_publish_aggregated, 2);
130
-
118
write_count_chart(NETDATA_EXIT_SYSCALL, NETDATA_EBPF_FAMILY,
119
&process_publish_aggregated[NETDATA_KEY_PUBLISH_PROCESS_EXIT], 2);
120
write_count_chart(NETDATA_PROCESS_SYSCALL, NETDATA_EBPF_FAMILY,
@@ -135,8 +122,6 @@ static void ebpf_process_send_data(ebpf_module_t *em)
122
123
write_status_chart(NETDATA_EBPF_FAMILY, &pvc);
124
if (em->mode < MODE_ENTRY) {
138
- write_err_chart(NETDATA_FILE_OPEN_ERR_COUNT, NETDATA_EBPF_FAMILY,
139
- process_publish_aggregated, 2);
125
write_err_chart(NETDATA_PROCESS_ERROR_NAME, NETDATA_EBPF_FAMILY,
126
&process_publish_aggregated[NETDATA_KEY_PUBLISH_PROCESS_FORK], 2);
127
}
@@ -194,56 +179,13 @@ void ebpf_process_remove_pids()
179
/**
180
* Send data to Netdata calling auxiliar functions.
181
*
197
- * @param em the structure with thread information
182
* @param root the target list.
183
*/
200
-void ebpf_process_send_apps_data(ebpf_module_t *em, struct target *root)
184
+void ebpf_process_send_apps_data(struct target *root)
185
{
186
struct target *w;
187
collected_number value;
188
205
- write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_SYSCALL_APPS_FILE_OPEN);
206
- for (w = root; w; w = w->next) {
207
- if (unlikely(w->exposed && w->processes)) {
208
- value = ebpf_process_sum_values_for_pids(w->root_pid, offsetof(ebpf_process_publish_apps_t, call_sys_open));
209
- write_chart_dimension(w->name, value);
210
- }
211
- }
212
- write_end_chart();
213
-
214
- if (em->mode < MODE_ENTRY) {
215
- write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_SYSCALL_APPS_FILE_OPEN_ERROR);
216
- for (w = root; w; w = w->next) {
217
- if (unlikely(w->exposed && w->processes)) {
218
- value = ebpf_process_sum_values_for_pids(w->root_pid,
219
- offsetof(ebpf_process_publish_apps_t, ecall_sys_open));
220
- write_chart_dimension(w->name, value);
221
- }
222
- }
223
- write_end_chart();
224
- }
225
-
226
- write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_SYSCALL_APPS_FILE_CLOSED);
227
- for (w = root; w; w = w->next) {
228
- if (unlikely(w->exposed && w->processes)) {
229
- value = ebpf_process_sum_values_for_pids(w->root_pid, offsetof(ebpf_process_publish_apps_t, call_close_fd));
230
- write_chart_dimension(w->name, value);
231
- }
232
- }
233
- write_end_chart();
234
-
235
- if (em->mode < MODE_ENTRY) {
236
- write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_SYSCALL_APPS_FILE_CLOSE_ERROR);
237
- for (w = root; w; w = w->next) {
238
- if (unlikely(w->exposed && w->processes)) {
239
- value = ebpf_process_sum_values_for_pids(w->root_pid,
240
- offsetof(ebpf_process_publish_apps_t, ecall_close_fd));
241
- write_chart_dimension(w->name, value);
242
- }
243
- }
244
- write_end_chart();
245
- }
246
-
189
write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_SYSCALL_APPS_TASK_PROCESS);
190
for (w = root; w; w = w->next) {
191
if (unlikely(w->exposed && w->processes)) {
@@ -305,15 +247,11 @@ static void read_hash_global_tables()
247
}
248
}
249
308
- process_aggregated_data[NETDATA_KEY_PUBLISH_PROCESS_OPEN].call = res[NETDATA_KEY_CALLS_DO_SYS_OPEN];
309
- process_aggregated_data[NETDATA_KEY_PUBLISH_PROCESS_CLOSE].call = res[NETDATA_KEY_CALLS_CLOSE_FD];
250
process_aggregated_data[NETDATA_KEY_PUBLISH_PROCESS_EXIT].call = res[NETDATA_KEY_CALLS_DO_EXIT];
251
process_aggregated_data[NETDATA_KEY_PUBLISH_PROCESS_RELEASE_TASK].call = res[NETDATA_KEY_CALLS_RELEASE_TASK];
252
process_aggregated_data[NETDATA_KEY_PUBLISH_PROCESS_FORK].call = res[NETDATA_KEY_CALLS_DO_FORK];
253
process_aggregated_data[NETDATA_KEY_PUBLISH_PROCESS_CLONE].call = res[NETDATA_KEY_CALLS_SYS_CLONE];
254
315
- process_aggregated_data[NETDATA_KEY_PUBLISH_PROCESS_OPEN].ecall = res[NETDATA_KEY_ERROR_DO_SYS_OPEN];
316
- process_aggregated_data[NETDATA_KEY_PUBLISH_PROCESS_CLOSE].ecall = res[NETDATA_KEY_ERROR_CLOSE_FD];
255
process_aggregated_data[NETDATA_KEY_PUBLISH_PROCESS_FORK].ecall = res[NETDATA_KEY_ERROR_DO_FORK];
256
process_aggregated_data[NETDATA_KEY_PUBLISH_PROCESS_CLONE].ecall = res[NETDATA_KEY_ERROR_SYS_CLONE];
257
}
@@ -339,15 +277,11 @@ static void ebpf_process_update_apps_data()
277
}
278
279
//Read data
342
- cad->call_sys_open = ps->open_call;
343
- cad->call_close_fd = ps->close_call;
280
cad->call_do_exit = ps->exit_call;
281
cad->call_release_task = ps->release_call;
282
cad->call_do_fork = ps->fork_call;
283
cad->call_sys_clone = ps->clone_call;
284
349
- cad->ecall_sys_open = ps->open_err;
350
- cad->ecall_close_fd = ps->close_err;
285
cad->ecall_do_fork = ps->fork_err;
286
cad->ecall_sys_clone = ps->clone_err;
287
@@ -394,32 +328,6 @@ static void ebpf_process_status_chart(char *family, char *name, char *axis,
328
*/
329
static void ebpf_create_global_charts(ebpf_module_t *em)
330
{
397
- ebpf_create_chart(NETDATA_EBPF_FAMILY,
398
- NETDATA_FILE_OPEN_CLOSE_COUNT,
399
- "Open and close calls",
400
- EBPF_COMMON_DIMENSION_CALL,
401
- NETDATA_FILE_GROUP,
402
- NULL,
403
- NETDATA_EBPF_CHART_TYPE_LINE,
404
- 21000,
405
- ebpf_create_global_dimension,
406
- process_publish_aggregated,
407
- 2, NETDATA_EBPF_MODULE_NAME_PROCESS);
408
-
409
- if (em->mode < MODE_ENTRY) {
410
- ebpf_create_chart(NETDATA_EBPF_FAMILY,
411
- NETDATA_FILE_OPEN_ERR_COUNT,
412
- "Open fails",
413
- EBPF_COMMON_DIMENSION_CALL,
414
- NETDATA_FILE_GROUP,
415
- NULL,
416
- NETDATA_EBPF_CHART_TYPE_LINE,
417
- 21001,
418
- ebpf_create_global_dimension,
419
- process_publish_aggregated,
420
- 2, NETDATA_EBPF_MODULE_NAME_PROCESS);
421
- }
422
-
331
ebpf_create_chart(NETDATA_EBPF_FAMILY,
332
NETDATA_PROCESS_SYSCALL,
333
"Start process",
@@ -476,47 +384,8 @@ static void ebpf_create_global_charts(ebpf_module_t *em)
384
*/
385
void ebpf_process_create_apps_charts(struct ebpf_module *em, void *ptr)
386
{
387
+ UNUSED(em);
388
struct target *root = ptr;
480
- ebpf_create_charts_on_apps(NETDATA_SYSCALL_APPS_FILE_OPEN,
481
- "Number of open files",
482
- EBPF_COMMON_DIMENSION_CALL,
483
- NETDATA_APPS_FILE_GROUP,
484
- NETDATA_EBPF_CHART_TYPE_STACKED,
485
- 20061,
486
- ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
487
- root, NETDATA_EBPF_MODULE_NAME_PROCESS);
488
-
489
- if (em->mode < MODE_ENTRY) {
490
- ebpf_create_charts_on_apps(NETDATA_SYSCALL_APPS_FILE_OPEN_ERROR,
491
- "Fails to open files",
492
- EBPF_COMMON_DIMENSION_CALL,
493
- NETDATA_APPS_FILE_GROUP,
494
- NETDATA_EBPF_CHART_TYPE_STACKED,
495
- 20062,
496
- ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
497
- root, NETDATA_EBPF_MODULE_NAME_PROCESS);
498
- }
499
-
500
- ebpf_create_charts_on_apps(NETDATA_SYSCALL_APPS_FILE_CLOSED,
501
- "Files closed",
502
- EBPF_COMMON_DIMENSION_CALL,
503
- NETDATA_APPS_FILE_GROUP,
504
- NETDATA_EBPF_CHART_TYPE_STACKED,
505
- 20063,
506
- ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
507
- root, NETDATA_EBPF_MODULE_NAME_PROCESS);
508
-
509
- if (em->mode < MODE_ENTRY) {
510
- ebpf_create_charts_on_apps(NETDATA_SYSCALL_APPS_FILE_CLOSE_ERROR,
511
- "Fails to close files",
512
- EBPF_COMMON_DIMENSION_CALL,
513
- NETDATA_APPS_FILE_GROUP,
514
- NETDATA_EBPF_CHART_TYPE_STACKED,
515
- 20064,
516
- ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
517
- root, NETDATA_EBPF_MODULE_NAME_PROCESS);
518
- }
519
-
389
ebpf_create_charts_on_apps(NETDATA_SYSCALL_APPS_TASK_PROCESS,
390
"Process started",
391
EBPF_COMMON_DIMENSION_CALL,
@@ -640,7 +509,7 @@ static void process_collector(usec_t step, ebpf_module_t *em)
509
}
510
511
if (publish_apps) {
643
- ebpf_process_send_apps_data(em, apps_groups_root_target);
512
+ ebpf_process_send_apps_data(apps_groups_root_target);
513
}
514
pthread_mutex_unlock(&lock);
515
@@ -814,8 +683,7 @@ void *ebpf_process_thread(void *ptr)
683
}
684
685
int algorithms[NETDATA_KEY_PUBLISH_PROCESS_END] = {
817
- NETDATA_EBPF_INCREMENTAL_IDX, NETDATA_EBPF_INCREMENTAL_IDX, NETDATA_EBPF_ABSOLUTE_IDX,
818
- NETDATA_EBPF_ABSOLUTE_IDX, NETDATA_EBPF_ABSOLUTE_IDX, NETDATA_EBPF_ABSOLUTE_IDX
686
+ NETDATA_EBPF_ABSOLUTE_IDX, NETDATA_EBPF_ABSOLUTE_IDX, NETDATA_EBPF_ABSOLUTE_IDX, NETDATA_EBPF_ABSOLUTE_IDX
687
};
688
689
ebpf_global_labels(
collectors/ebpf.plugin/ebpf_process.h
-23
@@ -7,38 +7,24 @@
7
#define NETDATA_EBPF_MODULE_NAME_PROCESS "process"
8
9
// Groups used on Dashboard
10
-#define NETDATA_FILE_GROUP "File"
10
#define NETDATA_PROCESS_GROUP "Process"
11
12
// Global chart name
14
-#define NETDATA_FILE_OPEN_CLOSE_COUNT "file_descriptor"
15
-#define NETDATA_FILE_OPEN_ERR_COUNT "file_error"
16
-
13
#define NETDATA_EXIT_SYSCALL "exit"
14
#define NETDATA_PROCESS_SYSCALL "process_thread"
15
#define NETDATA_PROCESS_ERROR_NAME "task_error"
16
#define NETDATA_PROCESS_STATUS_NAME "process_status"
17
18
// Charts created on Apps submenu
23
-#define NETDATA_SYSCALL_APPS_FILE_OPEN "file_open"
24
-#define NETDATA_SYSCALL_APPS_FILE_CLOSED "file_closed"
19
#define NETDATA_SYSCALL_APPS_TASK_PROCESS "process_create"
20
#define NETDATA_SYSCALL_APPS_TASK_THREAD "thread_create"
21
#define NETDATA_SYSCALL_APPS_TASK_CLOSE "task_close"
22
29
-// Charts created on Apps submenu, if and only if, the return mode is active
30
-
31
-#define NETDATA_SYSCALL_APPS_FILE_OPEN_ERROR "file_open_error"
32
-#define NETDATA_SYSCALL_APPS_FILE_CLOSE_ERROR "file_close_error"
33
-
23
// Process configuration name
24
#define NETDATA_PROCESS_CONFIG_FILE "process.conf"
25
26
// Index from kernel
27
typedef enum ebpf_process_index {
39
- NETDATA_KEY_CALLS_DO_SYS_OPEN,
40
- NETDATA_KEY_ERROR_DO_SYS_OPEN,
41
-
28
NETDATA_KEY_CALLS_DO_EXIT,
29
30
NETDATA_KEY_CALLS_RELEASE_TASK,
@@ -46,9 +32,6 @@ typedef enum ebpf_process_index {
32
NETDATA_KEY_CALLS_DO_FORK,
33
NETDATA_KEY_ERROR_DO_FORK,
34
49
- NETDATA_KEY_CALLS_CLOSE_FD,
50
- NETDATA_KEY_ERROR_CLOSE_FD,
51
-
35
NETDATA_KEY_CALLS_SYS_CLONE,
36
NETDATA_KEY_ERROR_SYS_CLONE,
37
@@ -61,8 +44,6 @@ typedef enum ebpf_process_index {
44
// values (the three initial positions) and absolute values
45
// (the remaining charts).
46
typedef enum netdata_publish_process {
64
- NETDATA_KEY_PUBLISH_PROCESS_OPEN,
65
- NETDATA_KEY_PUBLISH_PROCESS_CLOSE,
47
NETDATA_KEY_PUBLISH_PROCESS_EXIT,
48
NETDATA_KEY_PUBLISH_PROCESS_RELEASE_TASK,
49
NETDATA_KEY_PUBLISH_PROCESS_FORK,
@@ -73,16 +54,12 @@ typedef enum netdata_publish_process {
54
55
typedef struct ebpf_process_publish_apps {
56
// Number of calls during the last read
76
- uint64_t call_sys_open;
77
- uint64_t call_close_fd;
57
uint64_t call_do_exit;
58
uint64_t call_release_task;
59
uint64_t call_do_fork;
60
uint64_t call_sys_clone;
61
62
// Number of errors during the last read
84
- uint64_t ecall_sys_open;
85
- uint64_t ecall_close_fd;
63
uint64_t ecall_do_fork;
64
uint64_t ecall_sys_clone;
65
} ebpf_process_publish_apps_t;
libnetdata/ebpf/ebpf.c
+12
-4
@@ -541,10 +541,16 @@ static netdata_run_mode_t ebpf_select_mode(char *mode)
541
return MODE_ENTRY;
542
}
543
544
-void ebpf_update_module_using_config(ebpf_module_t *modules)
544
+/**
545
+ * @param modules structure that will be updated
546
+ * @param user_cfg is this an user configuration?
547
+ */
548
+void ebpf_update_module_using_config(ebpf_module_t *modules, int user_cfg)
549
{
546
- char *mode = appconfig_get(modules->cfg, EBPF_GLOBAL_SECTION, EBPF_CFG_LOAD_MODE, EBPF_CFG_LOAD_MODE_DEFAULT);
547
- modules->mode = ebpf_select_mode(mode);
550
+ if (user_cfg) {
551
+ char *mode = appconfig_get(modules->cfg, EBPF_GLOBAL_SECTION, EBPF_CFG_LOAD_MODE, EBPF_CFG_LOAD_MODE_DEFAULT);
552
+ modules->mode = ebpf_select_mode(mode);
553
+ }
554
555
modules->update_time = (int)appconfig_get_number(modules->cfg, EBPF_GLOBAL_SECTION,
556
EBPF_CFG_UPDATE_EVERY, modules->update_time);
@@ -571,15 +577,17 @@ void ebpf_update_module(ebpf_module_t *em)
577
{
578
char filename[FILENAME_MAX+1];
579
ebpf_mount_config_name(filename, FILENAME_MAX, ebpf_user_config_dir, em->config_file);
580
+ int from_user = 1;
581
if (!ebpf_load_config(em->cfg, filename)) {
582
ebpf_mount_config_name(filename, FILENAME_MAX, ebpf_stock_config_dir, em->config_file);
583
+ from_user = 0;
584
if (!ebpf_load_config(em->cfg, filename)) {
585
error("Cannot load the ebpf configuration file %s", em->config_file);
586
return;
587
}
588
}
589
582
- ebpf_update_module_using_config(em);
590
+ ebpf_update_module_using_config(em, from_user);
591
}
592
593
//----------------------------------------------------------------------------------------------------------------------
libnetdata/ebpf/ebpf.h
-1
@@ -178,7 +178,6 @@ extern struct bpf_link **ebpf_load_program(char *plugins_dir,
178
179
extern void ebpf_mount_config_name(char *filename, size_t length, char *path, const char *config);
180
extern int ebpf_load_config(struct config *config, char *filename);
181
-extern void ebpf_update_module_using_config(ebpf_module_t *modules);
181
extern void ebpf_update_module(ebpf_module_t *em);
182
extern void ebpf_update_names(ebpf_specify_name_t *opt, ebpf_module_t *em);
183
extern void ebpf_load_addresses(ebpf_addresses_t *fa, int fd);
packaging/ebpf.checksums
+3
-3
@@ -1,3 +1,3 @@
1
-0e5d9bbbffeef735534edaf5efa73e2f44b705699268bcc3028e48434e7fe8d0 netdata-kernel-collector-glibc-v0.7.6.tar.xz
2
-ee189fd82dae3c9e68756f88364bfdb97a29adb134ea7d95ae22f6059db4a632 netdata-kernel-collector-musl-v0.7.6.tar.xz
3
-98a31a53b9f7ca7b95c44ec12126357dc7d4c4d4a547142c8573a886ac6de430 netdata-kernel-collector-static-v0.7.6.tar.xz
1
+c04f3832933315669b009d629fe9cbef33d8202aa9b57d45e3777e2385ae0c5b netdata-kernel-collector-glibc-v0.7.6.1.tar.xz
2
+25e9ea852b5ec593be0d6329f1c62e0b6aa872ebc835462d3514a2c9fb9294ef netdata-kernel-collector-musl-v0.7.6.1.tar.xz
3
+6704049d192bb47d2f26fee1ce9add0e93cfde62b0672c56cf4b5ea6bd6bf5e9 netdata-kernel-collector-static-v0.7.6.1.tar.xz
packaging/ebpf.version
+1
-1
@@ -1 +1 @@
1
-v0.7.6
1
+v0.7.6.1
web/gui/dashboard_info.js
+27
-18
@@ -825,6 +825,16 @@ netdataDashboard.submenu = {
825
'filesystem.BTRFS_latency': {
826
title: 'BTRFS Latency',
827
info: 'Latency is the time it takes for an event to be completed. We calculate the difference between the calling and return times, we get the logarithmic for the final result and we sum one value to the respective bin. Based on the eBPF <a href="https://github.com/iovisor/bcc/blob/master/tools/btrfsdist_example.txt" target="_blank">btrfsdist</a> from BCC tools.'
828
+ },
829
+
830
+ 'filesystem.File_access': {
831
+ title: 'File Access',
832
+ info: 'When integration with apps is <a href="https://learn.netdata.cloud/guides/troubleshoot/monitor-debug-applications-ebpf" target="_blank">enabled</a>, Netdata also shows file access per <a href="#menu_apps_submenu_file_access">application</a>.'
833
+ },
834
+
835
+ 'apps.file_access': {
836
+ title: 'File Access',
837
+ info: 'Netdata also gives a summary for this chart on <a href="#menu_filesystem_submenu_File_access">Filesystem submenu</a> (more details on <a href="https://learn.netdata.cloud/docs/agent/collectors/ebpf.plugin#file" target="_blank">eBPF plugin file chart section</a>).'
838
}
839
};
840
@@ -3609,6 +3619,23 @@ netdataDashboard.context = {
3619
info: 'Monitor errors in calls to syscalls <code>mount(2)</code> and <code>umount(2)</code>.'
3620
},
3621
3622
+ 'filesystem.file_descriptor': {
3623
+ info: 'Calls for internal functions on Linux kernel. The open dimension is attached to the kernel internal function <code>do_sys_open</code> ( For kernels newer than <code>5.5.19</code> we add a kprobe to <code>do_sys_openat2</code>. ), which is the common function called from'+
3624
+ ' <a href="https://www.man7.org/linux/man-pages/man2/open.2.html" target="_blank">open(2)</a> ' +
3625
+ ' and <a href="https://www.man7.org/linux/man-pages/man2/openat.2.html" target="_blank">openat(2)</a>. ' +
3626
+ ' The close dimension is attached to the function <code>__close_fd</code> or <code>close_fd</code> according to your kernel version, which is called from system call' +
3627
+ ' <a href="https://www.man7.org/linux/man-pages/man2/close.2.html" target="_blank">close(2)</a>. '
3628
+ },
3629
+
3630
+ 'filesystem.file_error': {
3631
+ info: 'Failed calls to the kernel internal function <code>do_sys_open</code> ( For kernels newer than <code>5.5.19</code> we add a kprobe to <code>do_sys_openat2</code>. ), which is the common function called from'+
3632
+ ' <a href="https://www.man7.org/linux/man-pages/man2/open.2.html" target="_blank">open(2)</a> ' +
3633
+ ' and <a href="https://www.man7.org/linux/man-pages/man2/openat.2.html" target="_blank">openat(2)</a>. ' +
3634
+ ' The close dimension is attached to the function <code>__close_fd</code> or <code>close_fd</code> according to your kernel version, which is called from system call' +
3635
+ ' <a href="https://www.man7.org/linux/man-pages/man2/close.2.html" target="_blank">close(2)</a>. '
3636
+ },
3637
+
3638
+
3639
// ------------------------------------------------------------------------
3640
// eBPF
3641
@@ -3642,24 +3669,6 @@ netdataDashboard.context = {
3669
info: 'Bytes sent and received for functions <code>udp_sendmsg</code> and <code>udp_recvmsg</code>.'
3670
},
3671
3645
- 'ebpf.file_descriptor': {
3646
- title : 'File access',
3647
- info: 'Calls for internal functions on Linux kernel. The open dimension is attached to the kernel internal function <code>do_sys_open</code> ( For kernels newer than <code>5.5.19</code> we add a kprobe to <code>do_sys_openat2</code>. ), which is the common function called from'+
3648
- ' <a href="https://www.man7.org/linux/man-pages/man2/open.2.html" target="_blank">open(2)</a> ' +
3649
- ' and <a href="https://www.man7.org/linux/man-pages/man2/openat.2.html" target="_blank">openat(2)</a>. ' +
3650
- ' The close dimension is attached to the function <code>__close_fd</code> or <code>close_fd</code> according to your kernel version, which is called from system call' +
3651
- ' <a href="https://www.man7.org/linux/man-pages/man2/close.2.html" target="_blank">close(2)</a>. '
3652
- },
3653
-
3654
- 'ebpf.file_error': {
3655
- title : 'File access error',
3656
- info: 'Failed calls to the kernel internal function <code>do_sys_open</code> ( For kernels newer than <code>5.5.19</code> we add a kprobe to <code>do_sys_openat2</code>. ), which is the common function called from'+
3657
- ' <a href="https://www.man7.org/linux/man-pages/man2/open.2.html" target="_blank">open(2)</a> ' +
3658
- ' and <a href="https://www.man7.org/linux/man-pages/man2/openat.2.html" target="_blank">openat(2)</a>. ' +
3659
- ' The close dimension is attached to the function <code>__close_fd</code> or <code>close_fd</code> according to your kernel version, which is called from system call' +
3660
- ' <a href="https://www.man7.org/linux/man-pages/man2/close.2.html" target="_blank">close(2)</a>. '
3661
- },
3662
-
3672
'ebpf.process_thread': {
3673
title : 'Task creation',
3674
info: 'Number of times that either <a href="https://www.ece.uic.edu/~yshi1/linux/lkse/node4.html#SECTION00421000000000000000" target="_blank">do_fork</a>, or <code>kernel_clone</code> if you are running kernel newer than 5.9.16, is called to create a new task, which is the common name used to define process and tasks inside the kernel. Netdata identifies the threads by counting the number of calls for <a href="https://linux.die.net/man/2/clone" target="_blank">sys_clone</a> that has the flag <code>CLONE_THREAD</code> set.'