Modify eBPF.plugin integration (Part II, the sockets) (#19572)
thiagoftsm committed
Mar 7, 2025 at 21:50 UTC
8a126c9471b14aab505c9e42c790f860b5d63d67
8 files changed
+272
-48
CMakeLists.txt
+8
-1
@@ -1501,6 +1501,11 @@ set(INTERNAL_COLLECTORS_FILES
1501
src/collectors/common-contexts/mem-available.h
1502
)
1503
1504
+set(INTERCOMMUNICATION_COLLECTORS_FILES
1505
+ src/collectors/collectors-ipc/ebpf-ipc.c
1506
+ src/collectors/collectors-ipc/ebpf-ipc.h
1507
+ )
1508
+
1509
set(PLUGINSD_PLUGIN_FILES
1510
src/plugins.d/plugins_d.c
1511
src/plugins.d/plugins_d.h
@@ -2731,6 +2736,8 @@ if(ENABLE_PLUGIN_EBPF)
2736
src/collectors/ebpf.plugin/ebpf_shm.h
2737
src/collectors/ebpf.plugin/ebpf_socket.c
2738
src/collectors/ebpf.plugin/ebpf_socket.h
2739
+ src/collectors/ebpf.plugin/ebpf_socket_ipc.c
2740
+ src/collectors/ebpf.plugin/ebpf_socket_ipc.h
2741
src/collectors/ebpf.plugin/ebpf_softirq.c
2742
src/collectors/ebpf.plugin/ebpf_softirq.h
2743
src/collectors/ebpf.plugin/ebpf_sync.c
@@ -2751,7 +2758,7 @@ if(ENABLE_PLUGIN_EBPF)
2758
src/collectors/ebpf.plugin/libbpf_api/ebpf.h
2759
)
2760
2754
- add_executable(ebpf.plugin ${EBPF_PLUGIN_FILES})
2761
+ add_executable(ebpf.plugin ${EBPF_PLUGIN_FILES} ${INTERCOMMUNICATION_COLLECTORS_FILES})
2762
target_link_libraries(ebpf.plugin libnetdata)
2763
2764
netdata_add_libbpf_to_target(ebpf.plugin)
src/collectors/collectors-ipc/ebpf-ipc.c
new
+61
@@ -0,0 +1,61 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+#include "ebpf-ipc.h"
4
+
5
+netdata_ebpf_pid_stats_t *integration_shm;
6
+int shm_fd_ebpf_integration = -1;
7
+sem_t *shm_mutex_ebpf_integration = SEM_FAILED;
8
+
9
+void netdata_integration_cleanup_shm()
10
+{
11
+ if (shm_mutex_ebpf_integration != SEM_FAILED) {
12
+ sem_close(shm_mutex_ebpf_integration);
13
+ }
14
+
15
+ if (integration_shm) {
16
+ size_t length = os_get_system_pid_max() * sizeof(netdata_ebpf_pid_stats_t);
17
+ munmap(integration_shm, length);
18
+ }
19
+
20
+ if (shm_fd_ebpf_integration > 0) {
21
+ close(shm_fd_ebpf_integration);
22
+ }
23
+}
24
+
25
+int netdata_integration_initialize_shm(size_t pids)
26
+{
27
+ shm_fd_ebpf_integration = shm_open(NETDATA_EBPF_INTEGRATION_NAME, O_CREAT | O_RDWR, 0660);
28
+ if (shm_fd_ebpf_integration < 0) {
29
+ nd_log(NDLS_COLLECTORS, NDLP_ERR, "Cannot initialize shared memory. Integration won't happen.");
30
+ return -1;
31
+ }
32
+
33
+ size_t length = pids * sizeof(netdata_ebpf_pid_stats_t);
34
+ if (ftruncate(shm_fd_ebpf_integration, (off_t)length)) {
35
+ nd_log(NDLS_COLLECTORS, NDLP_ERR, "Cannot set size for shared memory.");
36
+ goto end_shm;
37
+ }
38
+
39
+ integration_shm = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd_ebpf_integration, 0);
40
+ if (unlikely(MAP_FAILED == integration_shm)) {
41
+ integration_shm = NULL;
42
+ nd_log(
43
+ NDLS_COLLECTORS,
44
+ NDLP_ERR,
45
+ "Cannot map shared memory used between cgroup and eBPF, integration won't happen");
46
+ goto end_shm;
47
+ }
48
+
49
+ shm_mutex_ebpf_integration = sem_open(
50
+ NETDATA_EBPF_SHM_INTEGRATION_NAME, O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, 1);
51
+ if (shm_mutex_ebpf_integration != SEM_FAILED) {
52
+ return 0;
53
+ }
54
+
55
+ nd_log(NDLS_COLLECTORS, NDLP_ERR, "Cannot create semaphore, integration between won't happen");
56
+ munmap(integration_shm, length);
57
+ integration_shm = NULL;
58
+
59
+end_shm:
60
+ return -1;
61
+}
src/collectors/collectors-ipc/ebpf-ipc.h
renamed
+25
-46
@@ -1,14 +1,25 @@
1
// SPDX-License-Identifier: GPL-3.0-or-later
2
3
-#ifndef NETDATA_SHARED_DATA_H
4
-#define NETDATA_SHARED_DATA_H 1
5
-
6
-#if defined(OS_LINUX)
3
+#ifndef NETDATA_EBPF_IPC_H
4
+#define NETDATA_EBPF_IPC_H 1
5
6
#ifndef TASK_COMM_LEN
7
#define TASK_COMM_LEN 16
8
#endif
9
10
+#include "libnetdata/libnetdata.h"
11
+#include <fcntl.h>
12
+#include <sys/stat.h>
13
+#include <semaphore.h>
14
+
15
+#ifdef __cplusplus
16
+extern "C" {
17
+#endif
18
+
19
+#include <stdlib.h>
20
+#include <stdio.h>
21
+#include <stdint.h>
22
+
23
// ----------------------------------------------------------------------------
24
// Enumeration used to identify threads with eBPF PIDs
25
enum ebpf_pids_index {
@@ -61,8 +72,8 @@ typedef struct netdata_socket {
72
uint32_t call_tcp_received;
73
uint64_t tcp_bytes_sent;
74
uint64_t tcp_bytes_received;
64
- uint32_t close; //It is never used with UDP
65
- uint32_t retransmit; //It is never used with UDP
75
+ uint32_t close; //It is never used with UDP
76
+ uint32_t retransmit; //It is never used with UDP
77
uint32_t ipv4_connect;
78
uint32_t ipv6_connect;
79
uint32_t state; // We do not have charts for it, because we are using network viewer plugin
@@ -153,8 +164,8 @@ typedef struct netdata_fd_stat {
164
uint32_t gid;
165
char name[TASK_COMM_LEN];
166
156
- uint32_t open_call; // Open syscalls (open and openat)
157
- uint32_t close_call; // Close syscall (close)
167
+ uint32_t open_call; // Open syscalls (open and openat)
168
+ uint32_t close_call; // Close syscall (close)
169
170
// Errors
171
uint32_t open_err;
@@ -188,46 +199,14 @@ typedef struct netdata_ebpf_pid_stats {
199
// ----------------------------------------------------------------------------
200
// Helpers used during integration
201
191
-#include <stdlib.h>
192
-
193
-enum netdata_integration_selector {
194
- NETDATA_INTEGRATION_APPS_EBPF,
195
- NETDATA_INTEGRATION_CGROUPS_EBPF,
196
- NETDATA_INTEGRATION_NETWORK_VIEWER_EBPF,
202
+#define NETDATA_EBPF_INTEGRATION_NAME "netdata_shm_integration_ebpf"
203
+#define NETDATA_EBPF_SHM_INTEGRATION_NAME "/netdata_sem_integration_ebpf"
204
198
- // This must be the last option always
199
- NETDATA_INTEGRATION_END
200
-};
205
+int netdata_integration_initialize_shm(size_t pids);
206
+void netdata_integration_cleanup_shm();
207
202
-static inline const char *netdata_integration_pipename(enum netdata_integration_selector idx) {
203
- const char *pipes[] = { "NETDATA_APPS_PIPENAME", "NETDATA_CGROUP_PIPENAME", "NETDATA_NV_PIPENAME"} ;
204
- const char *pipename = getenv(pipes[idx]);
205
- if (pipename)
206
- return pipename;
207
-
208
-#ifdef _WIN32
209
- switch (idx) {
210
- case NETDATA_INTEGRATION_NETWORK_VIEWER_EBPF:
211
- return "\\\\?\\pipe\\netdata-nv-cli";
212
- case NETDATA_INTEGRATION_CGROUPS_EBPF:
213
- return "\\\\?\\pipe\\netdata-cg-cli";
214
- case NETDATA_INTEGRATION_APPS_EBPF:
215
- default:
216
- return "\\\\?\\pipe\\netdata-apps-cli";
217
- }
218
-#else
219
- switch (idx) {
220
- case NETDATA_INTEGRATION_NETWORK_VIEWER_EBPF:
221
- return "/tmp/netdata-nv-ipc";
222
- case NETDATA_INTEGRATION_CGROUPS_EBPF:
223
- return "/tmp/netdata-cg-ipc";
224
- default:
225
- case NETDATA_INTEGRATION_APPS_EBPF:
226
- return "/tmp/netdata-apps-ipc";
227
- }
228
-#endif
208
+#ifdef __cplusplus
209
}
230
-
210
#endif
211
233
-#endif //NETDATA_SHARED_DATA_H
212
+#endif //NETDATA_EBPF_IPC_H
src/collectors/ebpf.plugin/ebpf.c
+56
@@ -27,6 +27,8 @@ int isrh = 0;
27
int main_thread_id = 0;
28
int process_pid_fd = -1;
29
uint64_t collect_pids = 0;
30
+static uint32_t integration_with_collectors = NETDATA_EBPF_INTEGRATION_DISABLED;
31
+ND_THREAD *socket_ipc = NULL;
32
static size_t global_iterations_counter = 1;
33
bool publish_internal_metrics = true;
34
@@ -982,6 +984,7 @@ static void ebpf_exit()
984
shm_unlink(NETDATA_SHARED_MEMORY_EBPF_CGROUP_NAME);
985
}
986
pthread_mutex_unlock(&mutex_cgroup_shm);
987
+ netdata_integration_cleanup_shm();
988
989
exit(0);
990
}
@@ -3182,6 +3185,34 @@ static void read_collector_values(int *disable_cgroups, int update_every, netdat
3185
}
3186
}
3187
3188
+static void ebpf_set_ipc_value(const char *integration)
3189
+{
3190
+ if (!strcmp(integration, NETDATA_EBPF_IPC_INTEGRATION_SHM)) {
3191
+ integration_with_collectors = NETDATA_EBPF_INTEGRATION_SHM;
3192
+ return;
3193
+ } else if (!strcmp(integration, NETDATA_EBPF_IPC_INTEGRATION_SOCKET)) {
3194
+ integration_with_collectors = NETDATA_EBPF_INTEGRATION_SOCKET;
3195
+ return;
3196
+ }
3197
+ integration_with_collectors = NETDATA_EBPF_INTEGRATION_DISABLED;
3198
+}
3199
+
3200
+static void ebpf_parse_ipc_section()
3201
+{
3202
+ const char *integration = inicfg_get(
3203
+ &collector_config,
3204
+ NETDATA_EBPF_IPC_SECTION,
3205
+ NETDATA_EBPF_IPC_INTEGRATION,
3206
+ NETDATA_EBPF_IPC_INTEGRATION_DISABLED);
3207
+ ebpf_set_ipc_value(integration);
3208
+
3209
+ ipc_sockets.default_bind_to = inicfg_get(
3210
+ &collector_config, NETDATA_EBPF_IPC_SECTION, NETDATA_EBPF_IPC_BIND_TO, NETDATA_EBPF_IPC_BIND_TO_DEFAULT);
3211
+
3212
+ ipc_sockets.backlog =
3213
+ (int)inicfg_get_number(&collector_config, NETDATA_EBPF_IPC_SECTION, NETDATA_EBPF_IPC_BACKLOG, 20);
3214
+}
3215
+
3216
/**
3217
* Load collector config
3218
*
@@ -3207,6 +3238,7 @@ static int ebpf_load_collector_config(char *path, int *disable_cgroups, int upda
3238
origin = EBPF_LOADED_FROM_USER;
3239
3240
read_collector_values(disable_cgroups, update_every, origin);
3241
+ ebpf_parse_ipc_section();
3242
3243
return 0;
3244
}
@@ -4138,6 +4170,28 @@ static pid_t ebpf_read_previous_pid(char *filename)
4170
return old_pid;
4171
}
4172
4173
+/**
4174
+ * Initialize Data Sharing
4175
+ *
4176
+ * Start sharing according to user configuration.
4177
+ */
4178
+static void ebpf_initialize_data_sharing()
4179
+{
4180
+ switch (integration_with_collectors) {
4181
+ case NETDATA_EBPF_INTEGRATION_SOCKET: {
4182
+ socket_ipc =
4183
+ nd_thread_create("ebpf_socket_ipc", NETDATA_THREAD_OPTION_DEFAULT, ebpf_socket_thread_ipc, NULL);
4184
+ break;
4185
+ }
4186
+ case NETDATA_EBPF_INTEGRATION_SHM:
4187
+ // All pid_map_size have the same value
4188
+ netdata_integration_initialize_shm(ebpf_modules[EBPF_MODULE_PROCESS_IDX].pid_map_size);
4189
+ case NETDATA_EBPF_INTEGRATION_DISABLED:
4190
+ default:
4191
+ break;
4192
+ }
4193
+}
4194
+
4195
/**
4196
* Kill previous process
4197
*
@@ -4270,6 +4324,8 @@ int main(int argc, char **argv)
4324
cgroup_integration_thread.thread =
4325
nd_thread_create(cgroup_integration_thread.name, NETDATA_THREAD_OPTION_DEFAULT, ebpf_cgroup_integration, NULL);
4326
4327
+ ebpf_initialize_data_sharing();
4328
+
4329
uint32_t i;
4330
for (i = 0; ebpf_threads[i].name != NULL; i++) {
4331
struct netdata_static_thread *st = &ebpf_threads[i];
src/collectors/ebpf.plugin/ebpf.d.conf
+22
@@ -75,3 +75,25 @@
75
swap = no
76
vfs = no
77
network connections = no
78
+
79
+#
80
+# Inter-Process Communication (IPC)
81
+#
82
+# Configurations for communication between different plugins.
83
+#
84
+# Available `integration` options:
85
+# `shm` : Shared Memory. Collectors will use the same shared memory
86
+# to avoid duplication.
87
+# `socket` : Unix socket. The eBPF plugin will not store data in the user ring;
88
+# it will only read data from the kernel and send it to requesting clients.
89
+# `disabled`: Disables data sharing between collectors.
90
+#
91
+# The `backlog` option defines the maximum number of concurrent connections that
92
+# can be queued for acceptance.
93
+#
94
+# The `bind to` option defines the path for unix socket
95
+#
96
+[ipc]
97
+ integration = disabled
98
+ bind to = unix:/tmp/netdata_ebpf_sock
99
+ backlog = 20
src/collectors/ebpf.plugin/ebpf_apps.h
+3
-1
@@ -4,7 +4,7 @@
4
#define NETDATA_EBPF_APPS_H 1
5
6
#include "libnetdata/libnetdata.h"
7
-#include "collectors/collectors-ipc/collectors-ipc.h"
7
+#include "collectors/collectors-ipc/ebpf-ipc.h"
8
#include "libbpf_api/ebpf.h"
9
10
#define NETDATA_APPS_FAMILY "apps"
@@ -33,6 +33,8 @@
33
#include "ebpf_swap.h"
34
#include "ebpf_vfs.h"
35
36
+#include "ebpf_socket_ipc.h"
37
+
38
#define EBPF_MAX_COMPARE_NAME 95
39
#define EBPF_MAX_NAME 100
40
src/collectors/ebpf.plugin/ebpf_socket_ipc.c
new
+65
@@ -0,0 +1,65 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+#include "ebpf_socket_ipc.h"
4
+
5
+LISTEN_SOCKETS ipc_sockets;
6
+
7
+static void ebpf_initialize_sockets()
8
+{
9
+ memset(&ipc_sockets, 0, sizeof(ipc_sockets));
10
+
11
+ ipc_sockets.config = &collector_config;
12
+ ipc_sockets.config_section = NETDATA_EBPF_IPC_INTEGRATION;
13
+}
14
+
15
+// Receive data
16
+static int ebpf_ipc_rcv_callback(POLLINFO *pi, nd_poll_event_t *events)
17
+{
18
+ (void)pi;
19
+ (void)events;
20
+
21
+ return 0;
22
+}
23
+
24
+static int ebpf_ipc_snd_callback(POLLINFO *pi __maybe_unused, nd_poll_event_t *events __maybe_unused)
25
+{
26
+ (void)pi;
27
+ (void)events;
28
+
29
+ return 0;
30
+}
31
+
32
+static bool ebpf_ipc_should_stop(void)
33
+{
34
+ return false;
35
+}
36
+
37
+void *ebpf_socket_thread_ipc(void *ptr)
38
+{
39
+ (void)ptr;
40
+
41
+ ebpf_initialize_sockets();
42
+
43
+ poll_events(
44
+ &ipc_sockets,
45
+ NULL,
46
+ NULL,
47
+ ebpf_ipc_rcv_callback,
48
+ ebpf_ipc_snd_callback,
49
+ NULL,
50
+ ebpf_ipc_should_stop,
51
+ NULL // No access control pattern
52
+ ,
53
+ 0 // No dns lookups for access control pattern
54
+ ,
55
+ NULL,
56
+ 0 // tcp request timeout, 0 = disabled
57
+ ,
58
+ 0 // tcp idle timeout, 0 = disabled
59
+ ,
60
+ EBPF_DEFAULT_UPDATE_EVERY * 1000,
61
+ ptr,
62
+ 0 // We are going to use UDP
63
+ );
64
+ return NULL;
65
+}
src/collectors/ebpf.plugin/ebpf_socket_ipc.h
new
+32
@@ -0,0 +1,32 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+#ifndef NETDATA_EBPF_SOCKET_IPC_H
4
+#define NETDATA_EBPF_SOCKET_IPC_H 1
5
+
6
+#define NETDATA_EBPF_IPC_SECTION "ipc"
7
+#define NETDATA_EBPF_IPC_INTEGRATION "integration"
8
+#define NETDATA_EBPF_IPC_BACKLOG "backlog"
9
+#define NETDATA_EBPF_IPC_BIND_TO "bind to"
10
+#define NETDATA_EBPF_IPC_BIND_TO_DEFAULT "unix:/tmp/netdata_ebpf_sock"
11
+
12
+#define NETDATA_EBPF_IPC_INTEGRATION_SHM "shm"
13
+#define NETDATA_EBPF_IPC_INTEGRATION_SOCKET "socket"
14
+#define NETDATA_EBPF_IPC_INTEGRATION_DISABLED "disabled"
15
+
16
+#include "ebpf.h"
17
+#include <fcntl.h>
18
+#include <sys/stat.h>
19
+#include <semaphore.h>
20
+
21
+enum ebpf_integration_list {
22
+ NETDATA_EBPF_INTEGRATION_DISABLED,
23
+ NETDATA_EBPF_INTEGRATION_SOCKET,
24
+ NETDATA_EBPF_INTEGRATION_SHM
25
+};
26
+
27
+extern LISTEN_SOCKETS ipc_sockets;
28
+extern sem_t *shm_mutex_ebpf_integration;
29
+void *ebpf_socket_thread_ipc(void *ptr);
30
+void netdata_integration_cleanup_shm();
31
+
32
+#endif /* NETDATA_EBPF_SOCKET_IPC_H_ */