@cryptotaxi247 / netdata-1 / commits / 8a126c947

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_ */