eBPF socket function (#15850)
thiagoftsm committed
Sep 14, 2023 at 13:33 UTC
8fbb89b1dba9efede1ddae235f9de77048dae7fc
29 files changed
+2886
-2398
collectors/ebpf.plugin/README.md
+52
-19
@@ -261,7 +261,7 @@ You can also enable the following eBPF programs:
261
- `swap` : This eBPF program creates charts that show information about swap access.
262
- `mdflush`: This eBPF program creates charts that show information about
263
- `sync`: Monitor calls to syscalls sync(2), fsync(2), fdatasync(2), syncfs(2), msync(2), and sync_file_range(2).
264
-- `network viewer`: This eBPF program creates charts with information about `TCP` and `UDP` functions, including the
264
+- `socket`: This eBPF program creates charts with information about `TCP` and `UDP` functions, including the
265
bandwidth consumed by each.
266
multi-device software flushes.
267
- `vfs`: This eBPF program creates charts that show information about VFS (Virtual File System) functions.
@@ -302,12 +302,13 @@ are divided in the following sections:
302
303
#### `[network connections]`
304
305
-You can configure the information shown on `outbound` and `inbound` charts with the settings in this section.
305
+You can configure the information shown with function `ebpf_socket` using the settings in this section.
306
307
```conf
308
[network connections]
309
- maximum dimensions = 500
309
+ enabled = yes
310
resolve hostname ips = no
311
+ resolve service names = yes
312
ports = 1-1024 !145 !domain
313
hostnames = !example.com
314
ips = !127.0.0.1/8 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 fc00::/7
@@ -318,24 +319,23 @@ write `ports = 19999`, Netdata will collect only connections for itself. The `ho
319
[simple patterns](https://github.com/netdata/netdata/blob/master/libnetdata/simple_pattern/README.md). The `ports`, and `ips` settings accept negation (`!`) to deny
320
specific values or asterisk alone to define all values.
321
321
-In the above example, Netdata will collect metrics for all ports between 1 and 443, with the exception of 53 (domain)
322
-and 145.
322
+In the above example, Netdata will collect metrics for all ports between `1` and `1024`, with the exception of `53` (domain)
323
+and `145`.
324
325
The following options are available:
326
327
+- `enabled`: Disable network connections monitoring. This can affect directly some funcion output.
328
+- `resolve hostname ips`: Enable resolving IPs to hostnames. It is disabled by default because it can be too slow.
329
+- `resolve service names`: Convert destination ports into service names, for example, port `53` protocol `UDP` becomes `domain`.
330
+ all names are read from /etc/services.
331
- `ports`: Define the destination ports for Netdata to monitor.
332
- `hostnames`: The list of hostnames that can be resolved to an IP address.
333
- `ips`: The IP or range of IPs that you want to monitor. You can use IPv4 or IPv6 addresses, use dashes to define a
329
- range of IPs, or use CIDR values. By default, only data for private IP addresses is collected, but this can
330
- be changed with the `ips` setting.
334
+ range of IPs, or use CIDR values.
335
332
-By default, Netdata displays up to 500 dimensions on network connection charts. If there are more possible dimensions,
333
-they will be bundled into the `other` dimension. You can increase the number of shown dimensions by changing
334
-the `maximum dimensions` setting.
335
-
336
-The dimensions for the traffic charts are created using the destination IPs of the sockets by default. This can be
337
-changed setting `resolve hostname ips = yes` and restarting Netdata, after this Netdata will create dimensions using
338
-the `hostnames` every time that is possible to resolve IPs to their hostnames.
336
+By default the traffic table is created using the destination IPs and ports of the sockets. This can be
337
+changed, so that Netdata uses service names (if possible), by specifying `resolve service name = yes` in the configuration
338
+section.
339
340
#### `[service name]`
341
@@ -990,13 +990,15 @@ shows how the lockdown module impacts `ebpf.plugin` based on the selected option
990
If you or your distribution compiled the kernel with the last combination, your system cannot load shared libraries
991
required to run `ebpf.plugin`.
992
993
-## Function
993
+## Functions
994
+
995
+### ebpf_thread
996
997
The eBPF plugin has a [function](https://github.com/netdata/netdata/blob/master/docs/cloud/netdata-functions.md) named
998
`ebpf_thread` that controls its internal threads and helps to reduce the overhead on host. Using the function you
999
can run the plugin with all threads disabled and enable them only when you want to take a look in specific areas.
1000
999
-### List threads
1001
+#### List threads
1002
1003
To list all threads status you can query directly the endpoint function:
1004
@@ -1006,7 +1008,7 @@ It is also possible to query a specific thread adding keyword `thread` and threa
1008
1009
`http://localhost:19999/api/v1/function?function=ebpf_thread%20thread:mount`
1010
1009
-### Enable thread
1011
+#### Enable thread
1012
1013
It is possible to enable a specific thread using the keyword `enable`:
1014
@@ -1019,14 +1021,14 @@ after the thread name:
1021
1022
in this example thread `mount` will run during 600 seconds (10 minutes).
1023
1022
-### Disable thread
1024
+#### Disable thread
1025
1026
It is also possible to stop any thread running using the keyword `disable`. For example, to disable `cachestat` you can
1027
request:
1028
1029
`http://localhost:19999/api/v1/function?function=ebpf_thread%20disable:cachestat`
1030
1029
-### Debugging threads
1031
+#### Debugging threads
1032
1033
You can verify the impact of threads on the host by running the
1034
[ebpf_thread_function.sh](https://github.com/netdata/netdata/blob/master/tests/ebpf/ebpf_thread_function.sh)
@@ -1036,3 +1038,34 @@ You can check the results of having threads running on your environment in the N
1038
dashboard
1039
1040
<img src="https://github.com/netdata/netdata/assets/49162938/91823573-114c-4c16-b634-cc46f7bb1bcf" alt="Threads running." />
1041
+
1042
+### ebpf_socket
1043
+
1044
+The eBPF plugin has a [function](https://github.com/netdata/netdata/blob/master/docs/cloud/netdata-functions.md) named
1045
+`ebpf_socket` that shows the current status of open sockets on host.
1046
+
1047
+#### Families
1048
+
1049
+The plugin shows by default sockets for IPV4 and IPV6, but it is possible to select a specific family by passing the
1050
+family as an argument:
1051
+
1052
+`http://localhost:19999/api/v1/function?function=ebpf_socket%20family:IPV4`
1053
+
1054
+#### Resolve
1055
+
1056
+The plugin resolves ports to service names by default. You can show the port number by disabling the name resolution:
1057
+
1058
+`http://localhost:19999/api/v1/function?function=ebpf_socket%20resolve:NO`
1059
+
1060
+#### CIDR
1061
+
1062
+The plugin shows connections for all possible destination IPs by default. You can limit the range by specifying the CIDR:
1063
+
1064
+`http://localhost:19999/api/v1/function?function=ebpf_socket%20cidr:192.168.1.0/24`
1065
+
1066
+#### PORT
1067
+
1068
+The plugin shows connections for all possible ports by default. You can limit the range by specifying a port or range
1069
+of ports:
1070
+
1071
+`http://localhost:19999/api/v1/function?function=ebpf_socket%20port:1-1024`
collectors/ebpf.plugin/ebpf.c
+1136
-133
@@ -49,176 +49,258 @@ struct netdata_static_thread cgroup_integration_thread = {
49
};
50
51
ebpf_module_t ebpf_modules[] = {
52
- { .thread_name = "process", .config_name = "process", .thread_description = NETDATA_EBPF_MODULE_PROCESS_DESC,
53
- .enabled = 0, .start_routine = ebpf_process_thread,
52
+ { .info = {.thread_name = "process",
53
+ .config_name = "process",
54
+ .thread_description = NETDATA_EBPF_MODULE_PROCESS_DESC},
55
+ .functions = {.start_routine = ebpf_process_thread,
56
+ .apps_routine = ebpf_process_create_apps_charts,
57
+ .fnct_routine = NULL},
58
+ .enabled = 0,
59
.update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
60
.apps_level = NETDATA_APPS_LEVEL_REAL_PARENT, .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
56
- .apps_routine = ebpf_process_create_apps_charts, .maps = NULL,
57
- .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &process_config,
61
+ .maps = NULL, .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &process_config,
62
.config_file = NETDATA_PROCESS_CONFIG_FILE,
63
.kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_10 |
64
NETDATA_V5_14,
65
.load = EBPF_LOAD_LEGACY, .targets = NULL, .probe_links = NULL, .objects = NULL,
66
.thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES, .lifetime = EBPF_DEFAULT_LIFETIME, .running_time = 0 },
63
- { .thread_name = "socket", .config_name = "socket", .thread_description = NETDATA_EBPF_SOCKET_MODULE_DESC,
64
- .enabled = 0, .start_routine = ebpf_socket_thread,
67
+ { .info = {.thread_name = "socket",
68
+ .config_name = "socket",
69
+ .thread_description = NETDATA_EBPF_SOCKET_MODULE_DESC},
70
+ .functions = {.start_routine = ebpf_socket_thread,
71
+ .apps_routine = ebpf_socket_create_apps_charts,
72
+ .fnct_routine = ebpf_socket_read_open_connections,
73
+ .fcnt_name = EBPF_FUNCTION_SOCKET,
74
+ .fcnt_desc = EBPF_PLUGIN_SOCKET_FUNCTION_DESCRIPTION,
75
+ .fcnt_thread_chart_name = NULL,
76
+ .fcnt_thread_lifetime_name = NULL},
77
+ .enabled = 0,
78
.update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
79
.apps_level = NETDATA_APPS_LEVEL_REAL_PARENT, .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
67
- .apps_routine = ebpf_socket_create_apps_charts, .maps = NULL,
80
+ .maps = NULL,
81
.pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &socket_config,
82
.config_file = NETDATA_NETWORK_CONFIG_FILE,
83
.kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14,
84
.load = EBPF_LOAD_LEGACY, .targets = socket_targets, .probe_links = NULL, .objects = NULL,
85
.thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES, .lifetime = EBPF_DEFAULT_LIFETIME, .running_time = 0},
73
- { .thread_name = "cachestat", .config_name = "cachestat", .thread_description = NETDATA_EBPF_CACHESTAT_MODULE_DESC,
74
- .enabled = 0, .start_routine = ebpf_cachestat_thread,
86
+ { .info = {.thread_name = "cachestat", .config_name = "cachestat", .thread_description = NETDATA_EBPF_CACHESTAT_MODULE_DESC},
87
+ .functions = {.start_routine = ebpf_cachestat_thread,
88
+ .apps_routine = ebpf_cachestat_create_apps_charts,
89
+ .fnct_routine = NULL},
90
+ .enabled = 0,
91
.update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
92
.apps_level = NETDATA_APPS_LEVEL_REAL_PARENT, .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
77
- .apps_routine = ebpf_cachestat_create_apps_charts, .maps = cachestat_maps,
78
- .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &cachestat_config,
93
+ .maps = cachestat_maps, .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &cachestat_config,
94
.config_file = NETDATA_CACHESTAT_CONFIG_FILE,
95
.kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18|
96
NETDATA_V5_4 | NETDATA_V5_14 | NETDATA_V5_15 | NETDATA_V5_16,
97
.load = EBPF_LOAD_LEGACY, .targets = cachestat_targets, .probe_links = NULL, .objects = NULL,
98
.thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES, .lifetime = EBPF_DEFAULT_LIFETIME, .running_time = 0},
84
- { .thread_name = "sync", .config_name = "sync", .thread_description = NETDATA_EBPF_SYNC_MODULE_DESC,
85
- .enabled = 0, .start_routine = ebpf_sync_thread,
99
+ { .info = {.thread_name = "sync",
100
+ .config_name = "sync",
101
+ .thread_description = NETDATA_EBPF_SYNC_MODULE_DESC},
102
+ .functions = {.start_routine = ebpf_sync_thread,
103
+ .apps_routine = NULL,
104
+ .fnct_routine = NULL},
105
+ .enabled = 0, .maps = NULL,
106
.update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
107
.apps_level = NETDATA_APPS_NOT_SET, .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
88
- .apps_routine = NULL, .maps = NULL, .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &sync_config,
108
+ .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &sync_config,
109
.config_file = NETDATA_SYNC_CONFIG_FILE,
110
// All syscalls have the same kernels
111
.kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14,
112
.load = EBPF_LOAD_LEGACY, .targets = sync_targets, .probe_links = NULL, .objects = NULL,
113
.thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES, .lifetime = EBPF_DEFAULT_LIFETIME, .running_time = 0},
94
- { .thread_name = "dc", .config_name = "dc", .thread_description = NETDATA_EBPF_DC_MODULE_DESC,
95
- .enabled = 0, .start_routine = ebpf_dcstat_thread,
114
+ { .info = {.thread_name = "dc",
115
+ .config_name = "dc",
116
+ .thread_description = NETDATA_EBPF_DC_MODULE_DESC},
117
+ .functions = {.start_routine = ebpf_dcstat_thread,
118
+ .apps_routine = ebpf_dcstat_create_apps_charts,
119
+ .fnct_routine = NULL},
120
+ .enabled = 0,
121
.update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
122
.apps_level = NETDATA_APPS_LEVEL_REAL_PARENT, .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
98
- .apps_routine = ebpf_dcstat_create_apps_charts, .maps = dcstat_maps,
123
+ .maps = dcstat_maps,
124
.pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &dcstat_config,
125
.config_file = NETDATA_DIRECTORY_DCSTAT_CONFIG_FILE,
126
.kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14,
127
.load = EBPF_LOAD_LEGACY, .targets = dc_targets, .probe_links = NULL, .objects = NULL,
128
.thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES, .lifetime = EBPF_DEFAULT_LIFETIME, .running_time = 0},
104
- { .thread_name = "swap", .config_name = "swap", .thread_description = NETDATA_EBPF_SWAP_MODULE_DESC,
105
- .enabled = 0, .start_routine = ebpf_swap_thread,
129
+ { .info = {.thread_name = "swap", .config_name = "swap", .thread_description = NETDATA_EBPF_SWAP_MODULE_DESC},
130
+ .functions = {.start_routine = ebpf_swap_thread,
131
+ .apps_routine = ebpf_swap_create_apps_charts,
132
+ .fnct_routine = NULL},
133
+ .enabled = 0,
134
.update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
135
.apps_level = NETDATA_APPS_LEVEL_REAL_PARENT, .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
108
- .apps_routine = ebpf_swap_create_apps_charts, .maps = NULL,
136
+ .maps = NULL,
137
.pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &swap_config,
138
.config_file = NETDATA_DIRECTORY_SWAP_CONFIG_FILE,
139
.kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14,
140
.load = EBPF_LOAD_LEGACY, .targets = swap_targets, .probe_links = NULL, .objects = NULL,
141
.thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES, .lifetime = EBPF_DEFAULT_LIFETIME, .running_time = 0},
114
- { .thread_name = "vfs", .config_name = "vfs", .thread_description = NETDATA_EBPF_VFS_MODULE_DESC,
115
- .enabled = 0, .start_routine = ebpf_vfs_thread,
142
+ { .info = {.thread_name = "vfs",
143
+ .config_name = "vfs",
144
+ .thread_description = NETDATA_EBPF_VFS_MODULE_DESC},
145
+ .functions = {.start_routine = ebpf_vfs_thread,
146
+ .apps_routine = ebpf_vfs_create_apps_charts,
147
+ .fnct_routine = NULL},
148
+ .enabled = 0,
149
.update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
150
.apps_level = NETDATA_APPS_LEVEL_REAL_PARENT, .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
118
- .apps_routine = ebpf_vfs_create_apps_charts, .maps = NULL,
151
+ .maps = NULL,
152
.pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &vfs_config,
153
.config_file = NETDATA_DIRECTORY_VFS_CONFIG_FILE,
154
.kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14,
155
.load = EBPF_LOAD_LEGACY, .targets = vfs_targets, .probe_links = NULL, .objects = NULL,
156
.thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES, .lifetime = EBPF_DEFAULT_LIFETIME, .running_time = 0},
124
- { .thread_name = "filesystem", .config_name = "filesystem", .thread_description = NETDATA_EBPF_FS_MODULE_DESC,
125
- .enabled = 0, .start_routine = ebpf_filesystem_thread,
157
+ { .info = {.thread_name = "filesystem", .config_name = "filesystem", .thread_description = NETDATA_EBPF_FS_MODULE_DESC},
158
+ .functions = {.start_routine = ebpf_filesystem_thread,
159
+ .apps_routine = NULL,
160
+ .fnct_routine = NULL},
161
+ .enabled = 0,
162
.update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
163
.apps_level = NETDATA_APPS_NOT_SET, .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
128
- .apps_routine = NULL, .maps = NULL, .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &fs_config,
164
+ .maps = NULL, .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &fs_config,
165
.config_file = NETDATA_FILESYSTEM_CONFIG_FILE,
166
//We are setting kernels as zero, because we load eBPF programs according the kernel running.
167
.kernels = 0, .load = EBPF_LOAD_LEGACY, .targets = NULL, .probe_links = NULL, .objects = NULL,
168
.thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES, .lifetime = EBPF_DEFAULT_LIFETIME, .running_time = 0},
133
- { .thread_name = "disk", .config_name = "disk", .thread_description = NETDATA_EBPF_DISK_MODULE_DESC,
134
- .enabled = 0, .start_routine = ebpf_disk_thread,
169
+ { .info = {.thread_name = "disk",
170
+ .config_name = "disk",
171
+ .thread_description = NETDATA_EBPF_DISK_MODULE_DESC},
172
+ .functions = {.start_routine = ebpf_disk_thread,
173
+ .apps_routine = NULL,
174
+ .fnct_routine = NULL},
175
+ .enabled = 0,
176
.update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
177
.apps_level = NETDATA_APPS_NOT_SET, .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
137
- .apps_routine = NULL, .maps = NULL, .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &disk_config,
178
+ .maps = NULL, .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &disk_config,
179
.config_file = NETDATA_DISK_CONFIG_FILE,
180
.kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14,
181
.load = EBPF_LOAD_LEGACY, .targets = NULL, .probe_links = NULL, .objects = NULL,
182
.thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES, .lifetime = EBPF_DEFAULT_LIFETIME, .running_time = 0},
142
- { .thread_name = "mount", .config_name = "mount", .thread_description = NETDATA_EBPF_MOUNT_MODULE_DESC,
143
- .enabled = 0, .start_routine = ebpf_mount_thread,
183
+ { .info = {.thread_name = "mount",
184
+ .config_name = "mount",
185
+ .thread_description = NETDATA_EBPF_MOUNT_MODULE_DESC},
186
+ .functions = {.start_routine = ebpf_mount_thread,
187
+ .apps_routine = NULL,
188
+ .fnct_routine = NULL},
189
+ .enabled = 0,
190
.update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
191
.apps_level = NETDATA_APPS_NOT_SET, .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
146
- .apps_routine = NULL, .maps = NULL, .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &mount_config,
192
+ .maps = NULL, .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &mount_config,
193
.config_file = NETDATA_MOUNT_CONFIG_FILE,
194
.kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14,
195
.load = EBPF_LOAD_LEGACY, .targets = mount_targets, .probe_links = NULL, .objects = NULL,
196
.thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES, .lifetime = EBPF_DEFAULT_LIFETIME, .running_time = 0},
151
- { .thread_name = "fd", .config_name = "fd", .thread_description = NETDATA_EBPF_FD_MODULE_DESC,
152
- .enabled = 0, .start_routine = ebpf_fd_thread,
197
+ { .info = { .thread_name = "fd",
198
+ .config_name = "fd",
199
+ .thread_description = NETDATA_EBPF_FD_MODULE_DESC},
200
+ .functions = {.start_routine = ebpf_fd_thread,
201
+ .apps_routine = ebpf_fd_create_apps_charts,
202
+ .fnct_routine = NULL},
203
+ .enabled = 0,
204
.update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
205
.apps_level = NETDATA_APPS_LEVEL_REAL_PARENT, .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
155
- .apps_routine = ebpf_fd_create_apps_charts, .maps = NULL,
206
+ .maps = NULL,
207
.pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &fd_config,
208
.config_file = NETDATA_FD_CONFIG_FILE,
209
.kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_11 |
210
NETDATA_V5_14,
211
.load = EBPF_LOAD_LEGACY, .targets = fd_targets, .probe_links = NULL, .objects = NULL,
212
.thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES, .lifetime = EBPF_DEFAULT_LIFETIME, .running_time = 0},
162
- { .thread_name = "hardirq", .config_name = "hardirq", .thread_description = NETDATA_EBPF_HARDIRQ_MODULE_DESC,
163
- .enabled = 0, .start_routine = ebpf_hardirq_thread,
213
+ { .info = { .thread_name = "hardirq",
214
+ .config_name = "hardirq",
215
+ .thread_description = NETDATA_EBPF_HARDIRQ_MODULE_DESC},
216
+ .functions = {.start_routine = ebpf_hardirq_thread,
217
+ .apps_routine = NULL,
218
+ .fnct_routine = NULL},
219
+ .enabled = 0,
220
.update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
221
.apps_level = NETDATA_APPS_NOT_SET, .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
166
- .apps_routine = NULL, .maps = NULL, .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &hardirq_config,
222
+ .maps = NULL, .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &hardirq_config,
223
.config_file = NETDATA_HARDIRQ_CONFIG_FILE,
224
.kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14,
225
.load = EBPF_LOAD_LEGACY, .targets = NULL, .probe_links = NULL, .objects = NULL,
226
.thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES, .lifetime = EBPF_DEFAULT_LIFETIME, .running_time = 0},
171
- { .thread_name = "softirq", .config_name = "softirq", .thread_description = NETDATA_EBPF_SOFTIRQ_MODULE_DESC,
172
- .enabled = 0, .start_routine = ebpf_softirq_thread,
227
+ { .info = { .thread_name = "softirq",
228
+ .config_name = "softirq",
229
+ .thread_description = NETDATA_EBPF_SOFTIRQ_MODULE_DESC},
230
+ .functions = {.start_routine = ebpf_softirq_thread,
231
+ .apps_routine = NULL,
232
+ .fnct_routine = NULL },
233
+ .enabled = 0,
234
.update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
235
.apps_level = NETDATA_APPS_NOT_SET, .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
175
- .apps_routine = NULL, .maps = NULL, .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &softirq_config,
236
+ .maps = NULL, .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &softirq_config,
237
.config_file = NETDATA_SOFTIRQ_CONFIG_FILE,
238
.kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14,
239
.load = EBPF_LOAD_LEGACY, .targets = NULL, .probe_links = NULL, .objects = NULL,
240
.thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES, .lifetime = EBPF_DEFAULT_LIFETIME, .running_time = 0},
180
- { .thread_name = "oomkill", .config_name = "oomkill", .thread_description = NETDATA_EBPF_OOMKILL_MODULE_DESC,
181
- .enabled = 0, .start_routine = ebpf_oomkill_thread,
241
+ { .info = {.thread_name = "oomkill",
242
+ .config_name = "oomkill",
243
+ .thread_description = NETDATA_EBPF_OOMKILL_MODULE_DESC},
244
+ .functions = {.start_routine = ebpf_oomkill_thread,
245
+ .apps_routine = ebpf_oomkill_create_apps_charts,
246
+ .fnct_routine = NULL},.enabled = 0,
247
.update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
248
.apps_level = NETDATA_APPS_LEVEL_REAL_PARENT, .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
184
- .apps_routine = ebpf_oomkill_create_apps_charts, .maps = NULL,
249
+ .maps = NULL,
250
.pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &oomkill_config,
251
.config_file = NETDATA_OOMKILL_CONFIG_FILE,
252
.kernels = NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14,
253
.load = EBPF_LOAD_LEGACY, .targets = NULL, .probe_links = NULL, .objects = NULL,
254
.thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES, .lifetime = EBPF_DEFAULT_LIFETIME, .running_time = 0},
190
- { .thread_name = "shm", .config_name = "shm", .thread_description = NETDATA_EBPF_SHM_MODULE_DESC,
191
- .enabled = 0, .start_routine = ebpf_shm_thread,
255
+ { .info = {.thread_name = "shm",
256
+ .config_name = "shm",
257
+ .thread_description = NETDATA_EBPF_SHM_MODULE_DESC},
258
+ .functions = {.start_routine = ebpf_shm_thread,
259
+ .apps_routine = ebpf_shm_create_apps_charts,
260
+ .fnct_routine = NULL},
261
+ .enabled = 0,
262
.update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
263
.apps_level = NETDATA_APPS_LEVEL_REAL_PARENT, .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
194
- .apps_routine = ebpf_shm_create_apps_charts, .maps = NULL,
264
+ .maps = NULL,
265
.pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &shm_config,
266
.config_file = NETDATA_DIRECTORY_SHM_CONFIG_FILE,
267
.kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14,
268
.load = EBPF_LOAD_LEGACY, .targets = shm_targets, .probe_links = NULL, .objects = NULL,
269
.thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES, .lifetime = EBPF_DEFAULT_LIFETIME, .running_time = 0},
200
- { .thread_name = "mdflush", .config_name = "mdflush", .thread_description = NETDATA_EBPF_MD_MODULE_DESC,
201
- .enabled = 0, .start_routine = ebpf_mdflush_thread,
270
+ { .info = { .thread_name = "mdflush",
271
+ .config_name = "mdflush",
272
+ .thread_description = NETDATA_EBPF_MD_MODULE_DESC},
273
+ .functions = {.start_routine = ebpf_mdflush_thread,
274
+ .apps_routine = NULL,
275
+ .fnct_routine = NULL},
276
+ .enabled = 0,
277
.update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
278
.apps_level = NETDATA_APPS_NOT_SET, .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
204
- .apps_routine = NULL, .maps = NULL, .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &mdflush_config,
279
+ .maps = NULL, .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &mdflush_config,
280
.config_file = NETDATA_DIRECTORY_MDFLUSH_CONFIG_FILE,
281
.kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14,
282
.load = EBPF_LOAD_LEGACY, .targets = mdflush_targets, .probe_links = NULL, .objects = NULL,
283
.thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES, .lifetime = EBPF_DEFAULT_LIFETIME, .running_time = 0},
209
- { .thread_name = "functions", .config_name = "functions", .thread_description = NETDATA_EBPF_FUNCTIONS_MODULE_DESC,
210
- .enabled = 1, .start_routine = ebpf_function_thread,
284
+ { .info = { .thread_name = "functions",
285
+ .config_name = "functions",
286
+ .thread_description = NETDATA_EBPF_FUNCTIONS_MODULE_DESC},
287
+ .functions = {.start_routine = ebpf_function_thread,
288
+ .apps_routine = NULL,
289
+ .fnct_routine = NULL},
290
+ .enabled = 1,
291
.update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
292
.apps_level = NETDATA_APPS_NOT_SET, .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
213
- .apps_routine = NULL, .maps = NULL, .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = NULL,
293
+ .maps = NULL, .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = NULL,
294
.config_file = NETDATA_DIRECTORY_FUNCTIONS_CONFIG_FILE,
295
.kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14,
296
.load = EBPF_LOAD_LEGACY, .targets = NULL, .probe_links = NULL, .objects = NULL,
297
.thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES, .lifetime = EBPF_DEFAULT_LIFETIME, .running_time = 0},
218
- { .thread_name = NULL, .enabled = 0, .start_routine = NULL, .update_every = EBPF_DEFAULT_UPDATE_EVERY,
298
+ { .info = {.thread_name = NULL, .config_name = NULL},
299
+ .functions = {.start_routine = NULL, .apps_routine = NULL, .fnct_routine = NULL},
300
+ .enabled = 0, .update_every = EBPF_DEFAULT_UPDATE_EVERY,
301
.global_charts = 0, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO, .apps_level = NETDATA_APPS_NOT_SET,
220
- .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0, .apps_routine = NULL, .maps = NULL,
221
- .pid_map_size = 0, .names = NULL, .cfg = NULL, .config_name = NULL, .kernels = 0, .load = EBPF_LOAD_LEGACY,
302
+ .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0, .maps = NULL,
303
+ .pid_map_size = 0, .names = NULL, .cfg = NULL, .kernels = 0, .load = EBPF_LOAD_LEGACY,
304
.targets = NULL, .probe_links = NULL, .objects = NULL, .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES},
305
};
306
@@ -559,6 +641,7 @@ ebpf_network_viewer_options_t network_viewer_opt;
641
ebpf_plugin_stats_t plugin_statistics = {.core = 0, .legacy = 0, .running = 0, .threads = 0, .tracepoints = 0,
642
.probes = 0, .retprobes = 0, .trampolines = 0, .memlock_kern = 0,
643
.hash_tables = 0};
644
+netdata_ebpf_judy_pid_t ebpf_judy_pid = {.pid_table = NULL, .index = {.JudyLArray = NULL}};
645
646
#ifdef LIBBPF_MAJOR_VERSION
647
struct btf *default_btf = NULL;
@@ -578,6 +661,61 @@ void *default_btf = NULL;
661
#endif
662
char *btf_path = NULL;
663
664
+/*****************************************************************
665
+ *
666
+ * FUNCTIONS USED TO MANIPULATE JUDY ARRAY
667
+ *
668
+ *****************************************************************/
669
+
670
+/**
671
+ * Hashtable insert unsafe
672
+ *
673
+ * Find or create a value associated to the index
674
+ *
675
+ * @return The lsocket = 0 when new item added to the array otherwise the existing item value is returned in *lsocket
676
+ * we return a pointer to a pointer, so that the caller can put anything needed at the value of the index.
677
+ * The pointer to pointer we return has to be used before any other operation that may change the index (insert/delete).
678
+ *
679
+ */
680
+void **ebpf_judy_insert_unsafe(PPvoid_t arr, Word_t key)
681
+{
682
+ JError_t J_Error;
683
+ Pvoid_t *idx = JudyLIns(arr, key, &J_Error);
684
+ if (unlikely(idx == PJERR)) {
685
+ netdata_log_error("Cannot add PID to JudyL, JU_ERRNO_* == %u, ID == %d",
686
+ JU_ERRNO(&J_Error), JU_ERRID(&J_Error));
687
+ }
688
+
689
+ return idx;
690
+}
691
+
692
+/**
693
+ * Get PID from judy
694
+ *
695
+ * Get a pointer for the `pid` from judy_array;
696
+ *
697
+ * @param judy_array a judy array where PID is the primary key
698
+ * @param pid pid stored.
699
+ */
700
+netdata_ebpf_judy_pid_stats_t *ebpf_get_pid_from_judy_unsafe(PPvoid_t judy_array, uint32_t pid)
701
+{
702
+ netdata_ebpf_judy_pid_stats_t **pid_pptr =
703
+ (netdata_ebpf_judy_pid_stats_t **)ebpf_judy_insert_unsafe(judy_array, pid);
704
+ netdata_ebpf_judy_pid_stats_t *pid_ptr = *pid_pptr;
705
+ if (likely(*pid_pptr == NULL)) {
706
+ // a new PID added to the index
707
+ *pid_pptr = aral_mallocz(ebpf_judy_pid.pid_table);
708
+
709
+ pid_ptr = *pid_pptr;
710
+
711
+ pid_ptr->cmdline = NULL;
712
+ pid_ptr->socket_stats.JudyLArray = NULL;
713
+ rw_spinlock_init(&pid_ptr->socket_stats.rw_spinlock);
714
+ }
715
+
716
+ return pid_ptr;
717
+}
718
+
719
/*****************************************************************
720
*
721
* FUNCTIONS USED TO ALLOCATE APPS/CGROUP MEMORIES (ARAL)
@@ -626,7 +764,7 @@ static inline void ebpf_check_before2go()
764
i = 0;
765
int j;
766
pthread_mutex_lock(&ebpf_exit_cleanup);
629
- for (j = 0; ebpf_modules[j].thread_name != NULL; j++) {
767
+ for (j = 0; ebpf_modules[j].info.thread_name != NULL; j++) {
768
if (ebpf_modules[j].enabled < NETDATA_THREAD_EBPF_STOPPING)
769
i++;
770
}
@@ -704,14 +842,15 @@ void ebpf_unload_legacy_code(struct bpf_object *objects, struct bpf_link **probe
842
static void ebpf_unload_unique_maps()
843
{
844
int i;
707
- for (i = 0; ebpf_modules[i].thread_name; i++) {
845
+ for (i = 0; ebpf_modules[i].info.thread_name; i++) {
846
// These threads are cleaned with other functions
847
if (i != EBPF_MODULE_SOCKET_IDX)
848
continue;
849
850
if (ebpf_modules[i].enabled != NETDATA_THREAD_EBPF_STOPPED) {
851
if (ebpf_modules[i].enabled != NETDATA_THREAD_EBPF_NOT_RUNNING)
714
- netdata_log_error("Cannot unload maps for thread %s, because it is not stopped.", ebpf_modules[i].thread_name);
852
+ netdata_log_error("Cannot unload maps for thread %s, because it is not stopped.",
853
+ ebpf_modules[i].info.thread_name);
854
855
continue;
856
}
@@ -781,7 +920,7 @@ int ebpf_exit_plugin = 0;
920
*
921
* @param sig is the signal number used to close the collector
922
*/
784
-static void ebpf_stop_threads(int sig)
923
+void ebpf_stop_threads(int sig)
924
{
925
UNUSED(sig);
926
static int only_one = 0;
@@ -794,11 +933,11 @@ static void ebpf_stop_threads(int sig)
933
}
934
only_one = 1;
935
int i;
797
- for (i = 0; ebpf_modules[i].thread_name != NULL; i++) {
936
+ for (i = 0; ebpf_modules[i].info.thread_name != NULL; i++) {
937
if (ebpf_modules[i].enabled < NETDATA_THREAD_EBPF_STOPPING) {
938
netdata_thread_cancel(*ebpf_modules[i].thread->thread);
939
#ifdef NETDATA_DEV_MODE
801
- netdata_log_info("Sending cancel for thread %s", ebpf_modules[i].thread_name);
940
+ netdata_log_info("Sending cancel for thread %s", ebpf_modules[i].info.thread_name);
941
#endif
942
}
943
}
@@ -839,8 +978,8 @@ static void ebpf_stop_threads(int sig)
978
* @param root a pointer for the targets.
979
*/
980
static inline void ebpf_create_apps_for_module(ebpf_module_t *em, struct ebpf_target *root) {
842
- if (em->enabled < NETDATA_THREAD_EBPF_STOPPING && em->apps_charts && em->apps_routine)
843
- em->apps_routine(em, root);
981
+ if (em->enabled < NETDATA_THREAD_EBPF_STOPPING && em->apps_charts && em->functions.apps_routine)
982
+ em->functions.apps_routine(em, root);
983
}
984
985
/**
@@ -1368,6 +1507,607 @@ void ebpf_read_global_table_stats(netdata_idx_t *stats,
1507
}
1508
}
1509
1510
+/*****************************************************************
1511
+ *
1512
+ * FUNCTIONS USED WITH SOCKET
1513
+ *
1514
+ *****************************************************************/
1515
+
1516
+/**
1517
+ * Netmask
1518
+ *
1519
+ * Copied from iprange (https://github.com/firehol/iprange/blob/master/iprange.h)
1520
+ *
1521
+ * @param prefix create the netmask based in the CIDR value.
1522
+ *
1523
+ * @return
1524
+ */
1525
+static inline in_addr_t ebpf_netmask(int prefix) {
1526
+
1527
+ if (prefix == 0)
1528
+ return (~((in_addr_t) - 1));
1529
+ else
1530
+ return (in_addr_t)(~((1 << (32 - prefix)) - 1));
1531
+
1532
+}
1533
+
1534
+/**
1535
+ * Broadcast
1536
+ *
1537
+ * Copied from iprange (https://github.com/firehol/iprange/blob/master/iprange.h)
1538
+ *
1539
+ * @param addr is the ip address
1540
+ * @param prefix is the CIDR value.
1541
+ *
1542
+ * @return It returns the last address of the range
1543
+ */
1544
+static inline in_addr_t ebpf_broadcast(in_addr_t addr, int prefix)
1545
+{
1546
+ return (addr | ~ebpf_netmask(prefix));
1547
+}
1548
+
1549
+/**
1550
+ * Network
1551
+ *
1552
+ * Copied from iprange (https://github.com/firehol/iprange/blob/master/iprange.h)
1553
+ *
1554
+ * @param addr is the ip address
1555
+ * @param prefix is the CIDR value.
1556
+ *
1557
+ * @return It returns the first address of the range.
1558
+ */
1559
+static inline in_addr_t ebpf_ipv4_network(in_addr_t addr, int prefix)
1560
+{
1561
+ return (addr & ebpf_netmask(prefix));
1562
+}
1563
+
1564
+/**
1565
+ * Calculate ipv6 first address
1566
+ *
1567
+ * @param out the address to store the first address.
1568
+ * @param in the address used to do the math.
1569
+ * @param prefix number of bits used to calculate the address
1570
+ */
1571
+static void get_ipv6_first_addr(union netdata_ip_t *out, union netdata_ip_t *in, uint64_t prefix)
1572
+{
1573
+ uint64_t mask,tmp;
1574
+ uint64_t ret[2];
1575
+
1576
+ memcpy(ret, in->addr32, sizeof(union netdata_ip_t));
1577
+
1578
+ if (prefix == 128) {
1579
+ memcpy(out->addr32, in->addr32, sizeof(union netdata_ip_t));
1580
+ return;
1581
+ } else if (!prefix) {
1582
+ ret[0] = ret[1] = 0;
1583
+ memcpy(out->addr32, ret, sizeof(union netdata_ip_t));
1584
+ return;
1585
+ } else if (prefix <= 64) {
1586
+ ret[1] = 0ULL;
1587
+
1588
+ tmp = be64toh(ret[0]);
1589
+ mask = 0xFFFFFFFFFFFFFFFFULL << (64 - prefix);
1590
+ tmp &= mask;
1591
+ ret[0] = htobe64(tmp);
1592
+ } else {
1593
+ mask = 0xFFFFFFFFFFFFFFFFULL << (128 - prefix);
1594
+ tmp = be64toh(ret[1]);
1595
+ tmp &= mask;
1596
+ ret[1] = htobe64(tmp);
1597
+ }
1598
+
1599
+ memcpy(out->addr32, ret, sizeof(union netdata_ip_t));
1600
+}
1601
+
1602
+/**
1603
+ * Get IPV6 Last Address
1604
+ *
1605
+ * @param out the address to store the last address.
1606
+ * @param in the address used to do the math.
1607
+ * @param prefix number of bits used to calculate the address
1608
+ */
1609
+static void get_ipv6_last_addr(union netdata_ip_t *out, union netdata_ip_t *in, uint64_t prefix)
1610
+{
1611
+ uint64_t mask,tmp;
1612
+ uint64_t ret[2];
1613
+ memcpy(ret, in->addr32, sizeof(union netdata_ip_t));
1614
+
1615
+ if (prefix == 128) {
1616
+ memcpy(out->addr32, in->addr32, sizeof(union netdata_ip_t));
1617
+ return;
1618
+ } else if (!prefix) {
1619
+ ret[0] = ret[1] = 0xFFFFFFFFFFFFFFFF;
1620
+ memcpy(out->addr32, ret, sizeof(union netdata_ip_t));
1621
+ return;
1622
+ } else if (prefix <= 64) {
1623
+ ret[1] = 0xFFFFFFFFFFFFFFFFULL;
1624
+
1625
+ tmp = be64toh(ret[0]);
1626
+ mask = 0xFFFFFFFFFFFFFFFFULL << (64 - prefix);
1627
+ tmp |= ~mask;
1628
+ ret[0] = htobe64(tmp);
1629
+ } else {
1630
+ mask = 0xFFFFFFFFFFFFFFFFULL << (128 - prefix);
1631
+ tmp = be64toh(ret[1]);
1632
+ tmp |= ~mask;
1633
+ ret[1] = htobe64(tmp);
1634
+ }
1635
+
1636
+ memcpy(out->addr32, ret, sizeof(union netdata_ip_t));
1637
+}
1638
+
1639
+/**
1640
+ * IP to network long
1641
+ *
1642
+ * @param dst the vector to store the result
1643
+ * @param ip the source ip given by our users.
1644
+ * @param domain the ip domain (IPV4 or IPV6)
1645
+ * @param source the original string
1646
+ *
1647
+ * @return it returns 0 on success and -1 otherwise.
1648
+ */
1649
+static inline int ebpf_ip2nl(uint8_t *dst, char *ip, int domain, char *source)
1650
+{
1651
+ if (inet_pton(domain, ip, dst) <= 0) {
1652
+ netdata_log_error("The address specified (%s) is invalid ", source);
1653
+ return -1;
1654
+ }
1655
+
1656
+ return 0;
1657
+}
1658
+
1659
+/**
1660
+ * Clean port Structure
1661
+ *
1662
+ * Clean the allocated list.
1663
+ *
1664
+ * @param clean the list that will be cleaned
1665
+ */
1666
+void ebpf_clean_port_structure(ebpf_network_viewer_port_list_t **clean)
1667
+{
1668
+ ebpf_network_viewer_port_list_t *move = *clean;
1669
+ while (move) {
1670
+ ebpf_network_viewer_port_list_t *next = move->next;
1671
+ freez(move->value);
1672
+ freez(move);
1673
+
1674
+ move = next;
1675
+ }
1676
+ *clean = NULL;
1677
+}
1678
+
1679
+/**
1680
+ * Clean IP structure
1681
+ *
1682
+ * Clean the allocated list.
1683
+ *
1684
+ * @param clean the list that will be cleaned
1685
+ */
1686
+void ebpf_clean_ip_structure(ebpf_network_viewer_ip_list_t **clean)
1687
+{
1688
+ ebpf_network_viewer_ip_list_t *move = *clean;
1689
+ while (move) {
1690
+ ebpf_network_viewer_ip_list_t *next = move->next;
1691
+ freez(move->value);
1692
+ freez(move);
1693
+
1694
+ move = next;
1695
+ }
1696
+ *clean = NULL;
1697
+}
1698
+
1699
+/**
1700
+ * Parse IP List
1701
+ *
1702
+ * Parse IP list and link it.
1703
+ *
1704
+ * @param out a pointer to store the link list
1705
+ * @param ip the value given as parameter
1706
+ */
1707
+static void ebpf_parse_ip_list_unsafe(void **out, char *ip)
1708
+{
1709
+ ebpf_network_viewer_ip_list_t **list = (ebpf_network_viewer_ip_list_t **)out;
1710
+
1711
+ char *ipdup = strdupz(ip);
1712
+ union netdata_ip_t first = { };
1713
+ union netdata_ip_t last = { };
1714
+ char *is_ipv6;
1715
+ if (*ip == '*' && *(ip+1) == '\0') {
1716
+ memset(first.addr8, 0, sizeof(first.addr8));
1717
+ memset(last.addr8, 0xFF, sizeof(last.addr8));
1718
+
1719
+ is_ipv6 = ip;
1720
+
1721
+ ebpf_clean_ip_structure(list);
1722
+ goto storethisip;
1723
+ }
1724
+
1725
+ char *end = ip;
1726
+ // Move while I cannot find a separator
1727
+ while (*end && *end != '/' && *end != '-') end++;
1728
+
1729
+ // We will use only the classic IPV6 for while, but we could consider the base 85 in a near future
1730
+ // https://tools.ietf.org/html/rfc1924
1731
+ is_ipv6 = strchr(ip, ':');
1732
+
1733
+ int select;
1734
+ if (*end && !is_ipv6) { // IPV4 range
1735
+ select = (*end == '/') ? 0 : 1;
1736
+ *end++ = '\0';
1737
+ if (*end == '!') {
1738
+ netdata_log_info("The exclusion cannot be in the second part of the range %s, it will be ignored.", ipdup);
1739
+ goto cleanipdup;
1740
+ }
1741
+
1742
+ if (!select) { // CIDR
1743
+ select = ebpf_ip2nl(first.addr8, ip, AF_INET, ipdup);
1744
+ if (select)
1745
+ goto cleanipdup;
1746
+
1747
+ select = (int) str2i(end);
1748
+ if (select < NETDATA_MINIMUM_IPV4_CIDR || select > NETDATA_MAXIMUM_IPV4_CIDR) {
1749
+ netdata_log_info("The specified CIDR %s is not valid, the IP %s will be ignored.", end, ip);
1750
+ goto cleanipdup;
1751
+ }
1752
+
1753
+ last.addr32[0] = htonl(ebpf_broadcast(ntohl(first.addr32[0]), select));
1754
+ // This was added to remove
1755
+ // https://app.codacy.com/manual/netdata/netdata/pullRequest?prid=5810941&bid=19021977
1756
+ UNUSED(last.addr32[0]);
1757
+
1758
+ uint32_t ipv4_test = htonl(ebpf_ipv4_network(ntohl(first.addr32[0]), select));
1759
+ if (first.addr32[0] != ipv4_test) {
1760
+ first.addr32[0] = ipv4_test;
1761
+ struct in_addr ipv4_convert;
1762
+ ipv4_convert.s_addr = ipv4_test;
1763
+ char ipv4_msg[INET_ADDRSTRLEN];
1764
+ if(inet_ntop(AF_INET, &ipv4_convert, ipv4_msg, INET_ADDRSTRLEN))
1765
+ netdata_log_info("The network value of CIDR %s was updated for %s .", ipdup, ipv4_msg);
1766
+ }
1767
+ } else { // Range
1768
+ select = ebpf_ip2nl(first.addr8, ip, AF_INET, ipdup);
1769
+ if (select)
1770
+ goto cleanipdup;
1771
+
1772
+ select = ebpf_ip2nl(last.addr8, end, AF_INET, ipdup);
1773
+ if (select)
1774
+ goto cleanipdup;
1775
+ }
1776
+
1777
+ if (htonl(first.addr32[0]) > htonl(last.addr32[0])) {
1778
+ netdata_log_info("The specified range %s is invalid, the second address is smallest than the first, it will be ignored.",
1779
+ ipdup);
1780
+ goto cleanipdup;
1781
+ }
1782
+ } else if (is_ipv6) { // IPV6
1783
+ if (!*end) { // Unique
1784
+ select = ebpf_ip2nl(first.addr8, ip, AF_INET6, ipdup);
1785
+ if (select)
1786
+ goto cleanipdup;
1787
+
1788
+ memcpy(last.addr8, first.addr8, sizeof(first.addr8));
1789
+ } else if (*end == '-') {
1790
+ *end++ = 0x00;
1791
+ if (*end == '!') {
1792
+ netdata_log_info("The exclusion cannot be in the second part of the range %s, it will be ignored.", ipdup);
1793
+ goto cleanipdup;
1794
+ }
1795
+
1796
+ select = ebpf_ip2nl(first.addr8, ip, AF_INET6, ipdup);
1797
+ if (select)
1798
+ goto cleanipdup;
1799
+
1800
+ select = ebpf_ip2nl(last.addr8, end, AF_INET6, ipdup);
1801
+ if (select)
1802
+ goto cleanipdup;
1803
+ } else { // CIDR
1804
+ *end++ = 0x00;
1805
+ if (*end == '!') {
1806
+ netdata_log_info("The exclusion cannot be in the second part of the range %s, it will be ignored.", ipdup);
1807
+ goto cleanipdup;
1808
+ }
1809
+
1810
+ select = str2i(end);
1811
+ if (select < 0 || select > 128) {
1812
+ netdata_log_info("The CIDR %s is not valid, the address %s will be ignored.", end, ip);
1813
+ goto cleanipdup;
1814
+ }
1815
+
1816
+ uint64_t prefix = (uint64_t)select;
1817
+ select = ebpf_ip2nl(first.addr8, ip, AF_INET6, ipdup);
1818
+ if (select)
1819
+ goto cleanipdup;
1820
+
1821
+ get_ipv6_last_addr(&last, &first, prefix);
1822
+
1823
+ union netdata_ip_t ipv6_test;
1824
+ get_ipv6_first_addr(&ipv6_test, &first, prefix);
1825
+
1826
+ if (memcmp(first.addr8, ipv6_test.addr8, sizeof(union netdata_ip_t)) != 0) {
1827
+ memcpy(first.addr8, ipv6_test.addr8, sizeof(union netdata_ip_t));
1828
+
1829
+ struct in6_addr ipv6_convert;
1830
+ memcpy(ipv6_convert.s6_addr, ipv6_test.addr8, sizeof(union netdata_ip_t));
1831
+
1832
+ char ipv6_msg[INET6_ADDRSTRLEN];
1833
+ if(inet_ntop(AF_INET6, &ipv6_convert, ipv6_msg, INET6_ADDRSTRLEN))
1834
+ netdata_log_info("The network value of CIDR %s was updated for %s .", ipdup, ipv6_msg);
1835
+ }
1836
+ }
1837
+
1838
+ if ((be64toh(*(uint64_t *)&first.addr32[2]) > be64toh(*(uint64_t *)&last.addr32[2]) &&
1839
+ !memcmp(first.addr32, last.addr32, 2*sizeof(uint32_t))) ||
1840
+ (be64toh(*(uint64_t *)&first.addr32) > be64toh(*(uint64_t *)&last.addr32)) ) {
1841
+ netdata_log_info("The specified range %s is invalid, the second address is smallest than the first, it will be ignored.",
1842
+ ipdup);
1843
+ goto cleanipdup;
1844
+ }
1845
+ } else { // Unique ip
1846
+ select = ebpf_ip2nl(first.addr8, ip, AF_INET, ipdup);
1847
+ if (select)
1848
+ goto cleanipdup;
1849
+
1850
+ memcpy(last.addr8, first.addr8, sizeof(first.addr8));
1851
+ }
1852
+
1853
+ ebpf_network_viewer_ip_list_t *store;
1854
+
1855
+ storethisip:
1856
+ store = callocz(1, sizeof(ebpf_network_viewer_ip_list_t));
1857
+ store->value = ipdup;
1858
+ store->hash = simple_hash(ipdup);
1859
+ store->ver = (uint8_t)(!is_ipv6)?AF_INET:AF_INET6;
1860
+ memcpy(store->first.addr8, first.addr8, sizeof(first.addr8));
1861
+ memcpy(store->last.addr8, last.addr8, sizeof(last.addr8));
1862
+
1863
+ ebpf_fill_ip_list_unsafe(list, store, "socket");
1864
+ return;
1865
+
1866
+ cleanipdup:
1867
+ freez(ipdup);
1868
+}
1869
+
1870
+/**
1871
+ * Parse IP Range
1872
+ *
1873
+ * Parse the IP ranges given and create Network Viewer IP Structure
1874
+ *
1875
+ * @param ptr is a pointer with the text to parse.
1876
+ */
1877
+void ebpf_parse_ips_unsafe(char *ptr)
1878
+{
1879
+ // No value
1880
+ if (unlikely(!ptr))
1881
+ return;
1882
+
1883
+ while (likely(ptr)) {
1884
+ // Move forward until next valid character
1885
+ while (isspace(*ptr)) ptr++;
1886
+
1887
+ // No valid value found
1888
+ if (unlikely(!*ptr))
1889
+ return;
1890
+
1891
+ // Find space that ends the list
1892
+ char *end = strchr(ptr, ' ');
1893
+ if (end) {
1894
+ *end++ = '\0';
1895
+ }
1896
+
1897
+ int neg = 0;
1898
+ if (*ptr == '!') {
1899
+ neg++;
1900
+ ptr++;
1901
+ }
1902
+
1903
+ if (isascii(*ptr)) { // Parse port
1904
+ ebpf_parse_ip_list_unsafe(
1905
+ (!neg) ? (void **)&network_viewer_opt.included_ips : (void **)&network_viewer_opt.excluded_ips, ptr);
1906
+ }
1907
+
1908
+ ptr = end;
1909
+ }
1910
+}
1911
+
1912
+/**
1913
+ * Fill Port list
1914
+ *
1915
+ * @param out a pointer to the link list.
1916
+ * @param in the structure that will be linked.
1917
+ */
1918
+static inline void fill_port_list(ebpf_network_viewer_port_list_t **out, ebpf_network_viewer_port_list_t *in)
1919
+{
1920
+ if (likely(*out)) {
1921
+ ebpf_network_viewer_port_list_t *move = *out, *store = *out;
1922
+ uint16_t first = ntohs(in->first);
1923
+ uint16_t last = ntohs(in->last);
1924
+ while (move) {
1925
+ uint16_t cmp_first = ntohs(move->first);
1926
+ uint16_t cmp_last = ntohs(move->last);
1927
+ if (cmp_first <= first && first <= cmp_last &&
1928
+ cmp_first <= last && last <= cmp_last ) {
1929
+ netdata_log_info("The range/value (%u, %u) is inside the range/value (%u, %u) already inserted, it will be ignored.",
1930
+ first, last, cmp_first, cmp_last);
1931
+ freez(in->value);
1932
+ freez(in);
1933
+ return;
1934
+ } else if (first <= cmp_first && cmp_first <= last &&
1935
+ first <= cmp_last && cmp_last <= last) {
1936
+ netdata_log_info("The range (%u, %u) is bigger than previous range (%u, %u) already inserted, the previous will be ignored.",
1937
+ first, last, cmp_first, cmp_last);
1938
+ freez(move->value);
1939
+ move->value = in->value;
1940
+ move->first = in->first;
1941
+ move->last = in->last;
1942
+ freez(in);
1943
+ return;
1944
+ }
1945
+
1946
+ store = move;
1947
+ move = move->next;
1948
+ }
1949
+
1950
+ store->next = in;
1951
+ } else {
1952
+ *out = in;
1953
+ }
1954
+
1955
+#ifdef NETDATA_INTERNAL_CHECKS
1956
+ netdata_log_info("Adding values %s( %u, %u) to %s port list used on network viewer",
1957
+ in->value, in->first, in->last,
1958
+ (*out == network_viewer_opt.included_port)?"included":"excluded");
1959
+#endif
1960
+}
1961
+
1962
+/**
1963
+ * Parse Service List
1964
+ *
1965
+ * @param out a pointer to store the link list
1966
+ * @param service the service used to create the structure that will be linked.
1967
+ */
1968
+static void ebpf_parse_service_list(void **out, char *service)
1969
+{
1970
+ ebpf_network_viewer_port_list_t **list = (ebpf_network_viewer_port_list_t **)out;
1971
+ struct servent *serv = getservbyname((const char *)service, "tcp");
1972
+ if (!serv)
1973
+ serv = getservbyname((const char *)service, "udp");
1974
+
1975
+ if (!serv) {
1976
+ netdata_log_info("Cannot resolve the service '%s' with protocols TCP and UDP, it will be ignored", service);
1977
+ return;
1978
+ }
1979
+
1980
+ ebpf_network_viewer_port_list_t *w = callocz(1, sizeof(ebpf_network_viewer_port_list_t));
1981
+ w->value = strdupz(service);
1982
+ w->hash = simple_hash(service);
1983
+
1984
+ w->first = w->last = (uint16_t)serv->s_port;
1985
+
1986
+ fill_port_list(list, w);
1987
+}
1988
+
1989
+/**
1990
+ * Parse port list
1991
+ *
1992
+ * Parse an allocated port list with the range given
1993
+ *
1994
+ * @param out a pointer to store the link list
1995
+ * @param range the informed range for the user.
1996
+ */
1997
+static void ebpf_parse_port_list(void **out, char *range)
1998
+{
1999
+ int first, last;
2000
+ ebpf_network_viewer_port_list_t **list = (ebpf_network_viewer_port_list_t **)out;
2001
+
2002
+ char *copied = strdupz(range);
2003
+ if (*range == '*' && *(range+1) == '\0') {
2004
+ first = 1;
2005
+ last = 65535;
2006
+
2007
+ ebpf_clean_port_structure(list);
2008
+ goto fillenvpl;
2009
+ }
2010
+
2011
+ char *end = range;
2012
+ //Move while I cannot find a separator
2013
+ while (*end && *end != ':' && *end != '-') end++;
2014
+
2015
+ //It has a range
2016
+ if (likely(*end)) {
2017
+ *end++ = '\0';
2018
+ if (*end == '!') {
2019
+ netdata_log_info("The exclusion cannot be in the second part of the range, the range %s will be ignored.", copied);
2020
+ freez(copied);
2021
+ return;
2022
+ }
2023
+ last = str2i((const char *)end);
2024
+ } else {
2025
+ last = 0;
2026
+ }
2027
+
2028
+ first = str2i((const char *)range);
2029
+ if (first < NETDATA_MINIMUM_PORT_VALUE || first > NETDATA_MAXIMUM_PORT_VALUE) {
2030
+ netdata_log_info("The first port %d of the range \"%s\" is invalid and it will be ignored!", first, copied);
2031
+ freez(copied);
2032
+ return;
2033
+ }
2034
+
2035
+ if (!last)
2036
+ last = first;
2037
+
2038
+ if (last < NETDATA_MINIMUM_PORT_VALUE || last > NETDATA_MAXIMUM_PORT_VALUE) {
2039
+ netdata_log_info("The second port %d of the range \"%s\" is invalid and the whole range will be ignored!", last, copied);
2040
+ freez(copied);
2041
+ return;
2042
+ }
2043
+
2044
+ if (first > last) {
2045
+ netdata_log_info("The specified order %s is wrong, the smallest value is always the first, it will be ignored!", copied);
2046
+ freez(copied);
2047
+ return;
2048
+ }
2049
+
2050
+ ebpf_network_viewer_port_list_t *w;
2051
+ fillenvpl:
2052
+ w = callocz(1, sizeof(ebpf_network_viewer_port_list_t));
2053
+ w->value = copied;
2054
+ w->hash = simple_hash(copied);
2055
+ w->first = (uint16_t)first;
2056
+ w->last = (uint16_t)last;
2057
+ w->cmp_first = (uint16_t)first;
2058
+ w->cmp_last = (uint16_t)last;
2059
+
2060
+ fill_port_list(list, w);
2061
+}
2062
+
2063
+/**
2064
+ * Parse Port Range
2065
+ *
2066
+ * Parse the port ranges given and create Network Viewer Port Structure
2067
+ *
2068
+ * @param ptr is a pointer with the text to parse.
2069
+ */
2070
+void ebpf_parse_ports(char *ptr)
2071
+{
2072
+ // No value
2073
+ if (unlikely(!ptr))
2074
+ return;
2075
+
2076
+ while (likely(ptr)) {
2077
+ // Move forward until next valid character
2078
+ while (isspace(*ptr)) ptr++;
2079
+
2080
+ // No valid value found
2081
+ if (unlikely(!*ptr))
2082
+ return;
2083
+
2084
+ // Find space that ends the list
2085
+ char *end = strchr(ptr, ' ');
2086
+ if (end) {
2087
+ *end++ = '\0';
2088
+ }
2089
+
2090
+ int neg = 0;
2091
+ if (*ptr == '!') {
2092
+ neg++;
2093
+ ptr++;
2094
+ }
2095
+
2096
+ if (isdigit(*ptr)) { // Parse port
2097
+ ebpf_parse_port_list(
2098
+ (!neg) ? (void **)&network_viewer_opt.included_port : (void **)&network_viewer_opt.excluded_port, ptr);
2099
+ } else if (isalpha(*ptr)) { // Parse service
2100
+ ebpf_parse_service_list(
2101
+ (!neg) ? (void **)&network_viewer_opt.included_port : (void **)&network_viewer_opt.excluded_port, ptr);
2102
+ } else if (*ptr == '*') { // All
2103
+ ebpf_parse_port_list(
2104
+ (!neg) ? (void **)&network_viewer_opt.included_port : (void **)&network_viewer_opt.excluded_port, ptr);
2105
+ }
2106
+
2107
+ ptr = end;
2108
+ }
2109
+}
2110
+
2111
/*****************************************************************
2112
*
2113
* FUNCTIONS TO DEFINE OPTIONS
@@ -1432,7 +2172,7 @@ static inline void ebpf_enable_specific_chart(struct ebpf_module *em, int disabl
2172
2173
// oomkill stores data inside apps submenu, so it always need to have apps_enabled for plugin to create
2174
// its chart, without this comparison eBPF.plugin will try to store invalid data when apps is disabled.
1435
- if (!strcmp(em->thread_name, "oomkill")) {
2175
+ if (!strcmp(em->info.thread_name, "oomkill")) {
2176
em->apps_charts = NETDATA_EBPF_APPS_FLAG_YES;
2177
}
2178
@@ -1451,7 +2191,7 @@ static inline void ebpf_enable_specific_chart(struct ebpf_module *em, int disabl
2191
static inline void disable_all_global_charts()
2192
{
2193
int i;
1454
- for (i = 0; ebpf_modules[i].thread_name; i++) {
2194
+ for (i = 0; ebpf_modules[i].info.thread_name; i++) {
2195
ebpf_modules[i].enabled = 0;
2196
ebpf_modules[i].global_charts = 0;
2197
}
@@ -1465,7 +2205,7 @@ static inline void disable_all_global_charts()
2205
static inline void ebpf_enable_chart(int idx, int disable_cgroup)
2206
{
2207
int i;
1468
- for (i = 0; ebpf_modules[i].thread_name; i++) {
2208
+ for (i = 0; ebpf_modules[i].info.thread_name; i++) {
2209
if (i == idx) {
2210
ebpf_enable_specific_chart(&ebpf_modules[i], disable_cgroup);
2211
break;
@@ -1481,7 +2221,7 @@ static inline void ebpf_enable_chart(int idx, int disable_cgroup)
2221
static inline void ebpf_disable_cgroups()
2222
{
2223
int i;
1484
- for (i = 0; ebpf_modules[i].thread_name; i++) {
2224
+ for (i = 0; ebpf_modules[i].info.thread_name; i++) {
2225
ebpf_modules[i].cgroup_charts = 0;
2226
}
2227
}
@@ -1661,6 +2401,203 @@ uint32_t ebpf_enable_tracepoints(ebpf_tracepoint_t *tps)
2401
*
2402
*****************************************************************/
2403
2404
+/**
2405
+ * Is ip inside the range
2406
+ *
2407
+ * Check if the ip is inside a IP range
2408
+ *
2409
+ * @param rfirst the first ip address of the range
2410
+ * @param rlast the last ip address of the range
2411
+ * @param cmpfirst the first ip to compare
2412
+ * @param cmplast the last ip to compare
2413
+ * @param family the IP family
2414
+ *
2415
+ * @return It returns 1 if the IP is inside the range and 0 otherwise
2416
+ */
2417
+static int ebpf_is_ip_inside_range(union netdata_ip_t *rfirst, union netdata_ip_t *rlast,
2418
+ union netdata_ip_t *cmpfirst, union netdata_ip_t *cmplast, int family)
2419
+{
2420
+ if (family == AF_INET) {
2421
+ if ((rfirst->addr32[0] <= cmpfirst->addr32[0]) && (rlast->addr32[0] >= cmplast->addr32[0]))
2422
+ return 1;
2423
+ } else {
2424
+ if (memcmp(rfirst->addr8, cmpfirst->addr8, sizeof(union netdata_ip_t)) <= 0 &&
2425
+ memcmp(rlast->addr8, cmplast->addr8, sizeof(union netdata_ip_t)) >= 0) {
2426
+ return 1;
2427
+ }
2428
+
2429
+ }
2430
+ return 0;
2431
+}
2432
+
2433
+/**
2434
+ * Fill IP list
2435
+ *
2436
+ * @param out a pointer to the link list.
2437
+ * @param in the structure that will be linked.
2438
+ * @param table the modified table.
2439
+ */
2440
+void ebpf_fill_ip_list_unsafe(ebpf_network_viewer_ip_list_t **out, ebpf_network_viewer_ip_list_t *in,
2441
+ char *table __maybe_unused)
2442
+{
2443
+ if (in->ver == AF_INET) { // It is simpler to compare using host order
2444
+ in->first.addr32[0] = ntohl(in->first.addr32[0]);
2445
+ in->last.addr32[0] = ntohl(in->last.addr32[0]);
2446
+ }
2447
+ if (likely(*out)) {
2448
+ ebpf_network_viewer_ip_list_t *move = *out, *store = *out;
2449
+ while (move) {
2450
+ if (in->ver == move->ver &&
2451
+ ebpf_is_ip_inside_range(&move->first, &move->last, &in->first, &in->last, in->ver)) {
2452
+#ifdef NETDATA_DEV_MODE
2453
+ netdata_log_info("The range/value (%s) is inside the range/value (%s) already inserted, it will be ignored.",
2454
+ in->value, move->value);
2455
+#endif
2456
+ freez(in->value);
2457
+ freez(in);
2458
+ return;
2459
+ }
2460
+ store = move;
2461
+ move = move->next;
2462
+ }
2463
+
2464
+ store->next = in;
2465
+ } else {
2466
+ *out = in;
2467
+ }
2468
+
2469
+#ifdef NETDATA_DEV_MODE
2470
+ char first[256], last[512];
2471
+ if (in->ver == AF_INET) {
2472
+ netdata_log_info("Adding values %s: (%u - %u) to %s IP list \"%s\" used on network viewer",
2473
+ in->value, in->first.addr32[0], in->last.addr32[0],
2474
+ (*out == network_viewer_opt.included_ips)?"included":"excluded",
2475
+ table);
2476
+ } else {
2477
+ if (inet_ntop(AF_INET6, in->first.addr8, first, INET6_ADDRSTRLEN) &&
2478
+ inet_ntop(AF_INET6, in->last.addr8, last, INET6_ADDRSTRLEN))
2479
+ netdata_log_info("Adding values %s - %s to %s IP list \"%s\" used on network viewer",
2480
+ first, last,
2481
+ (*out == network_viewer_opt.included_ips)?"included":"excluded",
2482
+ table);
2483
+ }
2484
+#endif
2485
+}
2486
+
2487
+/**
2488
+ * Link hostname
2489
+ *
2490
+ * @param out is the output link list
2491
+ * @param in the hostname to add to list.
2492
+ */
2493
+static void ebpf_link_hostname(ebpf_network_viewer_hostname_list_t **out, ebpf_network_viewer_hostname_list_t *in)
2494
+{
2495
+ if (likely(*out)) {
2496
+ ebpf_network_viewer_hostname_list_t *move = *out;
2497
+ for (; move->next ; move = move->next ) {
2498
+ if (move->hash == in->hash && !strcmp(move->value, in->value)) {
2499
+ netdata_log_info("The hostname %s was already inserted, it will be ignored.", in->value);
2500
+ freez(in->value);
2501
+ simple_pattern_free(in->value_pattern);
2502
+ freez(in);
2503
+ return;
2504
+ }
2505
+ }
2506
+
2507
+ move->next = in;
2508
+ } else {
2509
+ *out = in;
2510
+ }
2511
+#ifdef NETDATA_INTERNAL_CHECKS
2512
+ netdata_log_info("Adding value %s to %s hostname list used on network viewer",
2513
+ in->value,
2514
+ (*out == network_viewer_opt.included_hostnames)?"included":"excluded");
2515
+#endif
2516
+}
2517
+
2518
+/**
2519
+ * Link Hostnames
2520
+ *
2521
+ * Parse the list of hostnames to create the link list.
2522
+ * This is not associated with the IP, because simple patterns like *example* cannot be resolved to IP.
2523
+ *
2524
+ * @param out is the output link list
2525
+ * @param parse is a pointer with the text to parser.
2526
+ */
2527
+static void ebpf_link_hostnames(char *parse)
2528
+{
2529
+ // No value
2530
+ if (unlikely(!parse))
2531
+ return;
2532
+
2533
+ while (likely(parse)) {
2534
+ // Find the first valid value
2535
+ while (isspace(*parse)) parse++;
2536
+
2537
+ // No valid value found
2538
+ if (unlikely(!*parse))
2539
+ return;
2540
+
2541
+ // Find space that ends the list
2542
+ char *end = strchr(parse, ' ');
2543
+ if (end) {
2544
+ *end++ = '\0';
2545
+ }
2546
+
2547
+ int neg = 0;
2548
+ if (*parse == '!') {
2549
+ neg++;
2550
+ parse++;
2551
+ }
2552
+
2553
+ ebpf_network_viewer_hostname_list_t *hostname = callocz(1 , sizeof(ebpf_network_viewer_hostname_list_t));
2554
+ hostname->value = strdupz(parse);
2555
+ hostname->hash = simple_hash(parse);
2556
+ hostname->value_pattern = simple_pattern_create(parse, NULL, SIMPLE_PATTERN_EXACT, true);
2557
+
2558
+ ebpf_link_hostname((!neg) ? &network_viewer_opt.included_hostnames :
2559
+ &network_viewer_opt.excluded_hostnames,
2560
+ hostname);
2561
+
2562
+ parse = end;
2563
+ }
2564
+}
2565
+
2566
+/**
2567
+ * Parse network viewer section
2568
+ *
2569
+ * @param cfg the configuration structure
2570
+ */
2571
+void parse_network_viewer_section(struct config *cfg)
2572
+{
2573
+ network_viewer_opt.hostname_resolution_enabled = appconfig_get_boolean(cfg,
2574
+ EBPF_NETWORK_VIEWER_SECTION,
2575
+ EBPF_CONFIG_RESOLVE_HOSTNAME,
2576
+ CONFIG_BOOLEAN_NO);
2577
+
2578
+ network_viewer_opt.service_resolution_enabled = appconfig_get_boolean(cfg,
2579
+ EBPF_NETWORK_VIEWER_SECTION,
2580
+ EBPF_CONFIG_RESOLVE_SERVICE,
2581
+ CONFIG_BOOLEAN_YES);
2582
+
2583
+ char *value = appconfig_get(cfg, EBPF_NETWORK_VIEWER_SECTION, EBPF_CONFIG_PORTS, NULL);
2584
+ ebpf_parse_ports(value);
2585
+
2586
+ if (network_viewer_opt.hostname_resolution_enabled) {
2587
+ value = appconfig_get(cfg, EBPF_NETWORK_VIEWER_SECTION, EBPF_CONFIG_HOSTNAMES, NULL);
2588
+ ebpf_link_hostnames(value);
2589
+ } else {
2590
+ netdata_log_info("Name resolution is disabled, collector will not parse \"hostnames\" list.");
2591
+ }
2592
+
2593
+ value = appconfig_get(cfg,
2594
+ EBPF_NETWORK_VIEWER_SECTION,
2595
+ "ips",
2596
+ NULL);
2597
+ //"ips", "!127.0.0.1/8 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 fc00::/7 !::1/128");
2598
+ ebpf_parse_ips_unsafe(value);
2599
+}
2600
+
2601
/**
2602
* Read Local Ports
2603
*
@@ -1705,7 +2642,7 @@ static void read_local_ports(char *filename, uint8_t proto)
2642
*
2643
* Read the local address from the interfaces.
2644
*/
1708
-static void read_local_addresses()
2645
+void ebpf_read_local_addresses_unsafe()
2646
{
2647
struct ifaddrs *ifaddr, *ifa;
2648
if (getifaddrs(&ifaddr) == -1) {
@@ -1754,9 +2691,8 @@ static void read_local_addresses()
2691
}
2692
}
2693
1757
- ebpf_fill_ip_list((family == AF_INET)?&network_viewer_opt.ipv4_local_ip:&network_viewer_opt.ipv6_local_ip,
1758
- w,
1759
- "selector");
2694
+ ebpf_fill_ip_list_unsafe(
2695
+ (family == AF_INET) ? &network_viewer_opt.ipv4_local_ip : &network_viewer_opt.ipv6_local_ip, w, "selector");
2696
}
2697
2698
freeifaddrs(ifaddr);
@@ -1773,6 +2709,7 @@ void ebpf_start_pthread_variables()
2709
pthread_mutex_init(&ebpf_exit_cleanup, NULL);
2710
pthread_mutex_init(&collect_data_mutex, NULL);
2711
pthread_mutex_init(&mutex_cgroup_shm, NULL);
2712
+ rw_spinlock_init(&ebpf_judy_pid.index.rw_spinlock);
2713
}
2714
2715
/**
@@ -1780,6 +2717,8 @@ void ebpf_start_pthread_variables()
2717
*/
2718
static void ebpf_allocate_common_vectors()
2719
{
2720
+ ebpf_judy_pid.pid_table = ebpf_allocate_pid_aral(NETDATA_EBPF_PID_SOCKET_ARAL_TABLE_NAME,
2721
+ sizeof(netdata_ebpf_judy_pid_stats_t));
2722
ebpf_all_pids = callocz((size_t)pid_max, sizeof(struct ebpf_pid_stat *));
2723
ebpf_aral_init();
2724
}
@@ -1825,7 +2764,7 @@ static void ebpf_update_interval(int update_every)
2764
int i;
2765
int value = (int) appconfig_get_number(&collector_config, EBPF_GLOBAL_SECTION, EBPF_CFG_UPDATE_EVERY,
2766
update_every);
1828
- for (i = 0; ebpf_modules[i].thread_name; i++) {
2767
+ for (i = 0; ebpf_modules[i].info.thread_name; i++) {
2768
ebpf_modules[i].update_every = value;
2769
}
2770
}
@@ -1840,7 +2779,7 @@ static void ebpf_update_table_size()
2779
int i;
2780
uint32_t value = (uint32_t) appconfig_get_number(&collector_config, EBPF_GLOBAL_SECTION,
2781
EBPF_CFG_PID_SIZE, ND_EBPF_DEFAULT_PID_SIZE);
1843
- for (i = 0; ebpf_modules[i].thread_name; i++) {
2782
+ for (i = 0; ebpf_modules[i].info.thread_name; i++) {
2783
ebpf_modules[i].pid_map_size = value;
2784
}
2785
}
@@ -1855,7 +2794,7 @@ static void ebpf_update_lifetime()
2794
int i;
2795
uint32_t value = (uint32_t) appconfig_get_number(&collector_config, EBPF_GLOBAL_SECTION,
2796
EBPF_CFG_LIFETIME, EBPF_DEFAULT_LIFETIME);
1858
- for (i = 0; ebpf_modules[i].thread_name; i++) {
2797
+ for (i = 0; ebpf_modules[i].info.thread_name; i++) {
2798
ebpf_modules[i].lifetime = value;
2799
}
2800
}
@@ -1868,7 +2807,7 @@ static void ebpf_update_lifetime()
2807
static inline void ebpf_set_load_mode(netdata_ebpf_load_mode_t load, netdata_ebpf_load_mode_t origin)
2808
{
2809
int i;
1871
- for (i = 0; ebpf_modules[i].thread_name; i++) {
2810
+ for (i = 0; ebpf_modules[i].info.thread_name; i++) {
2811
ebpf_modules[i].load &= ~NETDATA_EBPF_LOAD_METHODS;
2812
ebpf_modules[i].load |= load | origin ;
2813
}
@@ -1897,7 +2836,7 @@ static void ebpf_update_map_per_core()
2836
int i;
2837
int value = appconfig_get_boolean(&collector_config, EBPF_GLOBAL_SECTION,
2838
EBPF_CFG_MAPS_PER_CORE, CONFIG_BOOLEAN_YES);
1900
- for (i = 0; ebpf_modules[i].thread_name; i++) {
2839
+ for (i = 0; ebpf_modules[i].info.thread_name; i++) {
2840
ebpf_modules[i].maps_per_core = value;
2841
}
2842
}
@@ -1961,7 +2900,7 @@ static void read_collector_values(int *disable_cgroups,
2900
2901
// Read ebpf programs section
2902
enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION,
1964
- ebpf_modules[EBPF_MODULE_PROCESS_IDX].config_name, CONFIG_BOOLEAN_YES);
2903
+ ebpf_modules[EBPF_MODULE_PROCESS_IDX].info.config_name, CONFIG_BOOLEAN_YES);
2904
if (enabled) {
2905
ebpf_enable_chart(EBPF_MODULE_PROCESS_IDX, *disable_cgroups);
2906
}
@@ -1971,7 +2910,7 @@ static void read_collector_values(int *disable_cgroups,
2910
CONFIG_BOOLEAN_NO);
2911
if (!enabled)
2912
enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION,
1974
- ebpf_modules[EBPF_MODULE_SOCKET_IDX].config_name,
2913
+ ebpf_modules[EBPF_MODULE_SOCKET_IDX].info.config_name,
2914
CONFIG_BOOLEAN_NO);
2915
if (enabled) {
2916
ebpf_enable_chart(EBPF_MODULE_SOCKET_IDX, *disable_cgroups);
@@ -1979,10 +2918,11 @@ static void read_collector_values(int *disable_cgroups,
2918
2919
// This is kept to keep compatibility
2920
enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "network connection monitoring",
1982
- CONFIG_BOOLEAN_NO);
2921
+ CONFIG_BOOLEAN_YES);
2922
if (!enabled)
2923
enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "network connections",
1985
- CONFIG_BOOLEAN_NO);
2924
+ CONFIG_BOOLEAN_YES);
2925
+
2926
network_viewer_opt.enabled = enabled;
2927
if (enabled) {
2928
if (!ebpf_modules[EBPF_MODULE_SOCKET_IDX].enabled)
@@ -1991,7 +2931,7 @@ static void read_collector_values(int *disable_cgroups,
2931
// Read network viewer section if network viewer is enabled
2932
// This is kept here to keep backward compatibility
2933
parse_network_viewer_section(&collector_config);
1994
- parse_service_name_section(&collector_config);
2934
+ ebpf_parse_service_name_section(&collector_config);
2935
}
2936
2937
enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "cachestat",
@@ -2238,7 +3178,7 @@ static void ebpf_parse_args(int argc, char **argv)
3178
};
3179
3180
memset(&network_viewer_opt, 0, sizeof(network_viewer_opt));
2241
- network_viewer_opt.max_dim = NETDATA_NV_CAP_VALUE;
3181
+ rw_spinlock_init(&network_viewer_opt.rw_spinlock);
3182
3183
if (argc > 1) {
3184
int n = (int)str2l(argv[1]);
@@ -2250,6 +3190,7 @@ static void ebpf_parse_args(int argc, char **argv)
3190
if (!freq)
3191
freq = EBPF_DEFAULT_UPDATE_EVERY;
3192
3193
+ //rw_spinlock_write_lock(&network_viewer_opt.rw_spinlock);
3194
if (ebpf_load_collector_config(ebpf_user_config_dir, &disable_cgroups, freq)) {
3195
netdata_log_info(
3196
"Does not have a configuration file inside `%s/ebpf.d.conf. It will try to load stock file.",
@@ -2260,6 +3201,7 @@ static void ebpf_parse_args(int argc, char **argv)
3201
}
3202
3203
ebpf_load_thread_config();
3204
+ //rw_spinlock_write_unlock(&network_viewer_opt.rw_spinlock);
3205
3206
while (1) {
3207
int c = getopt_long_only(argc, argv, "", long_options, &option_index);
@@ -2510,8 +3452,8 @@ static inline void ebpf_send_hash_table_pid_data(char *chart, uint32_t idx)
3452
write_begin_chart(NETDATA_MONITORING_FAMILY, chart);
3453
for (i = 0; i < EBPF_MODULE_FUNCTION_IDX; i++) {
3454
ebpf_module_t *wem = &ebpf_modules[i];
2513
- if (wem->apps_routine)
2514
- write_chart_dimension((char *)wem->thread_name,
3455
+ if (wem->functions.apps_routine)
3456
+ write_chart_dimension((char *)wem->info.thread_name,
3457
(wem->enabled < NETDATA_THREAD_EBPF_STOPPING) ?
3458
wem->hash_table_stats[idx]:
3459
0);
@@ -2531,7 +3473,7 @@ static inline void ebpf_send_global_hash_table_data()
3473
write_begin_chart(NETDATA_MONITORING_FAMILY, NETDATA_EBPF_HASH_TABLES_GLOBAL_ELEMENTS);
3474
for (i = 0; i < EBPF_MODULE_FUNCTION_IDX; i++) {
3475
ebpf_module_t *wem = &ebpf_modules[i];
2534
- write_chart_dimension((char *)wem->thread_name,
3476
+ write_chart_dimension((char *)wem->info.thread_name,
3477
(wem->enabled < NETDATA_THREAD_EBPF_STOPPING) ? NETDATA_CONTROLLER_END: 0);
3478
}
3479
write_end_chart();
@@ -2551,7 +3493,10 @@ void ebpf_send_statistic_data()
3493
int i;
3494
for (i = 0; i < EBPF_MODULE_FUNCTION_IDX; i++) {
3495
ebpf_module_t *wem = &ebpf_modules[i];
2554
- write_chart_dimension((char *)wem->thread_name, (wem->enabled < NETDATA_THREAD_EBPF_STOPPING) ? 1 : 0);
3496
+ if (wem->functions.fnct_routine)
3497
+ continue;
3498
+
3499
+ write_chart_dimension((char *)wem->info.thread_name, (wem->enabled < NETDATA_THREAD_EBPF_STOPPING) ? 1 : 0);
3500
}
3501
write_end_chart();
3502
@@ -2560,7 +3505,10 @@ void ebpf_send_statistic_data()
3505
ebpf_module_t *wem = &ebpf_modules[i];
3506
// Threads like VFS is slow to load and this can create an invalid number, this is the motive
3507
// we are also testing wem->lifetime value.
2563
- write_chart_dimension((char *)wem->thread_name,
3508
+ if (wem->functions.fnct_routine)
3509
+ continue;
3510
+
3511
+ write_chart_dimension((char *)wem->info.thread_name,
3512
(wem->lifetime && wem->enabled < NETDATA_THREAD_EBPF_STOPPING) ?
3513
(long long) (wem->lifetime - wem->running_time):
3514
0) ;
@@ -2589,6 +3537,23 @@ void ebpf_send_statistic_data()
3537
3538
ebpf_send_hash_table_pid_data(NETDATA_EBPF_HASH_TABLES_INSERT_PID_ELEMENTS, NETDATA_EBPF_GLOBAL_TABLE_PID_TABLE_ADD);
3539
ebpf_send_hash_table_pid_data(NETDATA_EBPF_HASH_TABLES_REMOVE_PID_ELEMENTS, NETDATA_EBPF_GLOBAL_TABLE_PID_TABLE_DEL);
3540
+
3541
+ for (i = 0; i < EBPF_MODULE_FUNCTION_IDX; i++) {
3542
+ ebpf_module_t *wem = &ebpf_modules[i];
3543
+ if (!wem->functions.fnct_routine)
3544
+ continue;
3545
+
3546
+ write_begin_chart(NETDATA_MONITORING_FAMILY, (char *)wem->functions.fcnt_thread_chart_name);
3547
+ write_chart_dimension((char *)wem->info.thread_name, (wem->enabled < NETDATA_THREAD_EBPF_STOPPING) ? 1 : 0);
3548
+ write_end_chart();
3549
+
3550
+ write_begin_chart(NETDATA_MONITORING_FAMILY, (char *)wem->functions.fcnt_thread_lifetime_name);
3551
+ write_chart_dimension((char *)wem->info.thread_name,
3552
+ (wem->lifetime && wem->enabled < NETDATA_THREAD_EBPF_STOPPING) ?
3553
+ (long long) (wem->lifetime - wem->running_time):
3554
+ 0) ;
3555
+ write_end_chart();
3556
+ }
3557
}
3558
3559
/**
@@ -2607,57 +3572,51 @@ static void update_internal_metric_variable()
3572
}
3573
3574
/**
2610
- * Create chart for Statistic Thread
3575
+ * Create Thread Chart
3576
*
2612
- * Write to standard output current values for threads.
3577
+ * Write to standard output current values for threads charts.
3578
*
3579
+ * @param name is the chart name
3580
+ * @param title chart title.
3581
+ * @param units chart units
3582
+ * @param order is the chart order
3583
* @param update_every time used to update charts
3584
+ * @param module a module to create a specific chart.
3585
*/
2616
-static inline void ebpf_create_statistic_thread_chart(int update_every)
3586
+static void ebpf_create_thread_chart(char *name,
3587
+ char *title,
3588
+ char *units,
3589
+ int order,
3590
+ int update_every,
3591
+ ebpf_module_t *module)
3592
{
3593
+ // common call for specific and all charts.
3594
ebpf_write_chart_cmd(NETDATA_MONITORING_FAMILY,
2619
- NETDATA_EBPF_THREADS,
2620
- "Threads running.",
2621
- "boolean",
3595
+ name,
3596
+ title,
3597
+ units,
3598
NETDATA_EBPF_FAMILY,
3599
NETDATA_EBPF_CHART_TYPE_LINE,
3600
NULL,
2625
- NETDATA_EBPF_ORDER_STAT_THREADS,
3601
+ order,
3602
update_every,
2627
- NETDATA_EBPF_MODULE_NAME_PROCESS);
3603
+ "main");
3604
2629
- int i;
2630
- for (i = 0; i < EBPF_MODULE_FUNCTION_IDX; i++) {
2631
- ebpf_write_global_dimension((char *)ebpf_modules[i].thread_name,
2632
- (char *)ebpf_modules[i].thread_name,
3605
+ if (module) {
3606
+ ebpf_write_global_dimension((char *)module->info.thread_name,
3607
+ (char *)module->info.thread_name,
3608
ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
3609
+ return;
3610
}
2635
-}
2636
-
2637
-/**
2638
- * Create lifetime Thread Chart
2639
- *
2640
- * Write to standard output current values for threads lifetime.
2641
- *
2642
- * @param update_every time used to update charts
2643
- */
2644
-static inline void ebpf_create_lifetime_thread_chart(int update_every)
2645
-{
2646
- ebpf_write_chart_cmd(NETDATA_MONITORING_FAMILY,
2647
- NETDATA_EBPF_LIFE_TIME,
2648
- "Threads running.",
2649
- "seconds",
2650
- NETDATA_EBPF_FAMILY,
2651
- NETDATA_EBPF_CHART_TYPE_LINE,
2652
- NULL,
2653
- NETDATA_EBPF_ORDER_STAT_LIFE_TIME,
2654
- update_every,
2655
- NETDATA_EBPF_MODULE_NAME_PROCESS);
3611
3612
int i;
3613
for (i = 0; i < EBPF_MODULE_FUNCTION_IDX; i++) {
2659
- ebpf_write_global_dimension((char *)ebpf_modules[i].thread_name,
2660
- (char *)ebpf_modules[i].thread_name,
3614
+ ebpf_module_t *em = &ebpf_modules[i];
3615
+ if (em->functions.fnct_routine)
3616
+ continue;
3617
+
3618
+ ebpf_write_global_dimension((char *)em->info.thread_name,
3619
+ (char *)em->info.thread_name,
3620
ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
3621
}
3622
}
@@ -2792,8 +3751,8 @@ static void ebpf_create_statistic_hash_global_elements(int update_every)
3751
3752
int i;
3753
for (i = 0; i < EBPF_MODULE_FUNCTION_IDX; i++) {
2795
- ebpf_write_global_dimension((char *)ebpf_modules[i].thread_name,
2796
- (char *)ebpf_modules[i].thread_name,
3754
+ ebpf_write_global_dimension((char *)ebpf_modules[i].info.thread_name,
3755
+ (char *)ebpf_modules[i].info.thread_name,
3756
ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
3757
}
3758
}
@@ -2824,9 +3783,9 @@ static void ebpf_create_statistic_hash_pid_table(int update_every, char *id, cha
3783
int i;
3784
for (i = 0; i < EBPF_MODULE_FUNCTION_IDX; i++) {
3785
ebpf_module_t *wem = &ebpf_modules[i];
2827
- if (wem->apps_routine)
2828
- ebpf_write_global_dimension((char *)wem->thread_name,
2829
- (char *)wem->thread_name,
3786
+ if (wem->functions.apps_routine)
3787
+ ebpf_write_global_dimension((char *)wem->info.thread_name,
3788
+ (char *)wem->info.thread_name,
3789
ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX]);
3790
}
3791
}
@@ -2850,16 +3809,60 @@ static void ebpf_create_statistic_charts(int update_every)
3809
3810
create_charts = 0;
3811
2853
- ebpf_create_statistic_thread_chart(update_every);
3812
+ ebpf_create_thread_chart(NETDATA_EBPF_THREADS,
3813
+ "Threads running.",
3814
+ "boolean",
3815
+ NETDATA_EBPF_ORDER_STAT_THREADS,
3816
+ update_every,
3817
+ NULL);
3818
#ifdef NETDATA_DEV_MODE
3819
EBPF_PLUGIN_FUNCTIONS(EBPF_FUNCTION_THREAD, EBPF_PLUGIN_THREAD_FUNCTION_DESCRIPTION);
3820
#endif
3821
2858
- ebpf_create_lifetime_thread_chart(update_every);
3822
+ ebpf_create_thread_chart(NETDATA_EBPF_LIFE_TIME,
3823
+ "Time remaining for thread.",
3824
+ "seconds",
3825
+ NETDATA_EBPF_ORDER_STAT_LIFE_TIME,
3826
+ update_every,
3827
+ NULL);
3828
#ifdef NETDATA_DEV_MODE
3829
EBPF_PLUGIN_FUNCTIONS(EBPF_FUNCTION_THREAD, EBPF_PLUGIN_THREAD_FUNCTION_DESCRIPTION);
3830
#endif
3831
3832
+ int i,j;
3833
+ char name[256];
3834
+ for (i = 0, j = NETDATA_EBPF_ORDER_FUNCTION_PER_THREAD; i < EBPF_MODULE_FUNCTION_IDX; i++) {
3835
+ ebpf_module_t *em = &ebpf_modules[i];
3836
+ if (!em->functions.fnct_routine)
3837
+ continue;
3838
+
3839
+ em->functions.order_thread_chart = j;
3840
+ snprintfz(name, 255,"%s_%s", NETDATA_EBPF_THREADS, em->info.thread_name);
3841
+ em->functions.fcnt_thread_chart_name = strdupz(name);
3842
+ ebpf_create_thread_chart(name,
3843
+ "Threads running.",
3844
+ "boolean",
3845
+ j++,
3846
+ update_every,
3847
+ em);
3848
+#ifdef NETDATA_DEV_MODE
3849
+ EBPF_PLUGIN_FUNCTIONS(em->functions.fcnt_name, em->functions.fcnt_desc);
3850
+#endif
3851
+
3852
+ em->functions.order_thread_lifetime = j;
3853
+ snprintfz(name, 255,"%s_%s", NETDATA_EBPF_LIFE_TIME, em->info.thread_name);
3854
+ em->functions.fcnt_thread_lifetime_name = strdupz(name);
3855
+ ebpf_create_thread_chart(name,
3856
+ "Time remaining for thread.",
3857
+ "seconds",
3858
+ j++,
3859
+ update_every,
3860
+ em);
3861
+#ifdef NETDATA_DEV_MODE
3862
+ EBPF_PLUGIN_FUNCTIONS(em->functions.fcnt_name, em->functions.fcnt_desc);
3863
+#endif
3864
+ }
3865
+
3866
ebpf_create_statistic_load_chart(update_every);
3867
3868
ebpf_create_statistic_kernel_memory(update_every);
@@ -3040,8 +4043,8 @@ static void ebpf_manage_pid(pid_t pid)
4043
static void ebpf_set_static_routine()
4044
{
4045
int i;
3043
- for (i = 0; ebpf_modules[i].thread_name; i++) {
3044
- ebpf_threads[i].start_routine = ebpf_modules[i].start_routine;
4046
+ for (i = 0; ebpf_modules[i].info.thread_name; i++) {
4047
+ ebpf_threads[i].start_routine = ebpf_modules[i].functions.start_routine;
4048
}
4049
}
4050
@@ -3095,7 +4098,7 @@ int main(int argc, char **argv)
4098
libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
4099
#endif
4100
3098
- read_local_addresses();
4101
+ ebpf_read_local_addresses_unsafe();
4102
read_local_ports("/proc/net/tcp", IPPROTO_TCP);
4103
read_local_ports("/proc/net/tcp6", IPPROTO_TCP);
4104
read_local_ports("/proc/net/udp", IPPROTO_UDP);
collectors/ebpf.plugin/ebpf.d/network.conf
+12
-6
@@ -26,6 +26,11 @@
26
#
27
# The `maps per core` defines if hash tables will be per core or not. This option is ignored on kernels older than 4.6.
28
#
29
+# The `collect pid` option defines the PID stored inside hash tables and accepts the following options:
30
+# `real parent`: Only stores real parent inside PID
31
+# `parent` : Only stores parent PID.
32
+# `all` : Stores all PIDs used by software. This is the most expensive option.
33
+#
34
# The `lifetime` defines the time length a thread will run when it is enabled by a function.
35
#
36
# Uncomment lines to define specific options for thread.
@@ -35,12 +40,12 @@
40
# cgroups = no
41
# update every = 10
42
bandwidth table size = 16384
38
- ipv4 connection table size = 16384
39
- ipv6 connection table size = 16384
43
+ socket monitoring table size = 16384
44
udp connection table size = 4096
45
ebpf type format = auto
42
- ebpf co-re tracing = trampoline
46
+ ebpf co-re tracing = probe
47
maps per core = no
48
+ collect pid = all
49
lifetime = 300
50
51
#
@@ -49,11 +54,12 @@
54
# This is a feature with status WIP(Work in Progress)
55
#
56
[network connections]
52
- maximum dimensions = 50
57
+ enabled = yes
58
resolve hostnames = no
54
- resolve service names = no
59
+ resolve service names = yes
60
ports = *
56
- ips = !127.0.0.1/8 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 fc00::/7 !::1/128
61
+# ips = !127.0.0.1/8 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 fc00::/7 !::1/128
62
+ ips = *
63
hostnames = *
64
65
[service name]
collectors/ebpf.plugin/ebpf.h
+30
@@ -31,6 +31,7 @@
31
#include "daemon/main.h"
32
33
#include "ebpf_apps.h"
34
+#include "ebpf_functions.h"
35
#include "ebpf_cgroup.h"
36
37
#define NETDATA_EBPF_OLD_CONFIG_FILE "ebpf.conf"
@@ -98,6 +99,26 @@ typedef struct netdata_error_report {
99
int err;
100
} netdata_error_report_t;
101
102
+typedef struct netdata_ebpf_judy_pid {
103
+ ARAL *pid_table;
104
+
105
+ // Index for PIDs
106
+ struct { // support for multiple indexing engines
107
+ Pvoid_t JudyLArray; // the hash table
108
+ RW_SPINLOCK rw_spinlock; // protect the index
109
+ } index;
110
+} netdata_ebpf_judy_pid_t;
111
+
112
+typedef struct netdata_ebpf_judy_pid_stats {
113
+ char *cmdline;
114
+
115
+ // Index for Socket timestamp
116
+ struct { // support for multiple indexing engines
117
+ Pvoid_t JudyLArray; // the hash table
118
+ RW_SPINLOCK rw_spinlock; // protect the index
119
+ } socket_stats;
120
+} netdata_ebpf_judy_pid_stats_t;
121
+
122
extern ebpf_module_t ebpf_modules[];
123
enum ebpf_main_index {
124
EBPF_MODULE_PROCESS_IDX,
@@ -322,10 +343,19 @@ void ebpf_unload_legacy_code(struct bpf_object *objects, struct bpf_link **probe
343
344
void ebpf_read_global_table_stats(netdata_idx_t *stats, netdata_idx_t *values, int map_fd,
345
int maps_per_core, uint32_t begin, uint32_t end);
346
+void **ebpf_judy_insert_unsafe(PPvoid_t arr, Word_t key);
347
+netdata_ebpf_judy_pid_stats_t *ebpf_get_pid_from_judy_unsafe(PPvoid_t judy_array, uint32_t pid);
348
+
349
+void parse_network_viewer_section(struct config *cfg);
350
+void ebpf_clean_ip_structure(ebpf_network_viewer_ip_list_t **clean);
351
+void ebpf_clean_port_structure(ebpf_network_viewer_port_list_t **clean);
352
+void ebpf_read_local_addresses_unsafe();
353
354
extern ebpf_filesystem_partitions_t localfs[];
355
extern ebpf_sync_syscalls_t local_syscalls[];
356
extern int ebpf_exit_plugin;
357
+void ebpf_stop_threads(int sig);
358
+extern netdata_ebpf_judy_pid_t ebpf_judy_pid;
359
360
#define EBPF_MAX_SYNCHRONIZATION_TIME 300
361
collectors/ebpf.plugin/ebpf_apps.c
+28
-64
@@ -375,58 +375,6 @@ int ebpf_read_hash_table(void *ep, int fd, uint32_t pid)
375
return -1;
376
}
377
378
-/**
379
- * Read socket statistic
380
- *
381
- * Read information from kernel ring to user ring.
382
- *
383
- * @param ep the table with all process stats values.
384
- * @param fd the file descriptor mapped from kernel
385
- * @param ef a pointer for the functions mapped from dynamic library
386
- * @param pids the list of pids associated to a target.
387
- *
388
- * @return
389
- */
390
-size_t read_bandwidth_statistic_using_pid_on_target(ebpf_bandwidth_t **ep, int fd, struct ebpf_pid_on_target *pids)
391
-{
392
- size_t count = 0;
393
- while (pids) {
394
- uint32_t current_pid = pids->pid;
395
- if (!ebpf_read_hash_table(ep[current_pid], fd, current_pid))
396
- count++;
397
-
398
- pids = pids->next;
399
- }
400
-
401
- return count;
402
-}
403
-
404
-/**
405
- * Read bandwidth statistic using hash table
406
- *
407
- * @param out the output tensor that will receive the information.
408
- * @param fd the file descriptor that has the data
409
- * @param bpf_map_lookup_elem a pointer for the function to read the data
410
- * @param bpf_map_get_next_key a pointer fo the function to read the index.
411
- */
412
-size_t read_bandwidth_statistic_using_hash_table(ebpf_bandwidth_t **out, int fd)
413
-{
414
- size_t count = 0;
415
- uint32_t key = 0;
416
- uint32_t next_key = 0;
417
-
418
- while (bpf_map_get_next_key(fd, &key, &next_key) == 0) {
419
- ebpf_bandwidth_t *eps = out[next_key];
420
- if (!eps) {
421
- eps = callocz(1, sizeof(ebpf_process_stat_t));
422
- out[next_key] = eps;
423
- }
424
- ebpf_read_hash_table(eps, fd, next_key);
425
- }
426
-
427
- return count;
428
-}
429
-
378
/*****************************************************************
379
*
380
* FUNCTIONS CALLED FROM COLLECTORS
@@ -887,6 +835,7 @@ static inline int read_proc_pid_cmdline(struct ebpf_pid_stat *p)
835
{
836
static char cmdline[MAX_CMDLINE + 1];
837
838
+ int ret = 0;
839
if (unlikely(!p->cmdline_filename)) {
840
char filename[FILENAME_MAX + 1];
841
snprintfz(filename, FILENAME_MAX, "%s/proc/%d/cmdline", netdata_configured_host_prefix, p->pid);
@@ -909,20 +858,23 @@ static inline int read_proc_pid_cmdline(struct ebpf_pid_stat *p)
858
cmdline[i] = ' ';
859
}
860
912
- if (p->cmdline)
913
- freez(p->cmdline);
914
- p->cmdline = strdupz(cmdline);
915
-
861
debug_log("Read file '%s' contents: %s", p->cmdline_filename, p->cmdline);
862
918
- return 1;
863
+ ret = 1;
864
865
cleanup:
866
// copy the command to the command line
867
if (p->cmdline)
868
freez(p->cmdline);
869
p->cmdline = strdupz(p->comm);
925
- return 0;
870
+
871
+ rw_spinlock_write_lock(&ebpf_judy_pid.index.rw_spinlock);
872
+ netdata_ebpf_judy_pid_stats_t *pid_ptr = ebpf_get_pid_from_judy_unsafe(&ebpf_judy_pid.index.JudyLArray, p->pid);
873
+ if (pid_ptr)
874
+ pid_ptr->cmdline = p->cmdline;
875
+ rw_spinlock_write_unlock(&ebpf_judy_pid.index.rw_spinlock);
876
+
877
+ return ret;
878
}
879
880
/**
@@ -1238,6 +1190,24 @@ static inline void del_pid_entry(pid_t pid)
1190
freez(p->status_filename);
1191
freez(p->io_filename);
1192
freez(p->cmdline_filename);
1193
+
1194
+ rw_spinlock_write_lock(&ebpf_judy_pid.index.rw_spinlock);
1195
+ netdata_ebpf_judy_pid_stats_t *pid_ptr = ebpf_get_pid_from_judy_unsafe(&ebpf_judy_pid.index.JudyLArray, p->pid);
1196
+ if (pid_ptr) {
1197
+ if (pid_ptr->socket_stats.JudyLArray) {
1198
+ Word_t local_socket = 0;
1199
+ Pvoid_t *socket_value;
1200
+ bool first_socket = true;
1201
+ while ((socket_value = JudyLFirstThenNext(pid_ptr->socket_stats.JudyLArray, &local_socket, &first_socket))) {
1202
+ netdata_socket_plus_t *socket_clean = *socket_value;
1203
+ aral_freez(aral_socket_table, socket_clean);
1204
+ }
1205
+ JudyLFreeArray(&pid_ptr->socket_stats.JudyLArray, PJE0);
1206
+ }
1207
+ JudyLDel(&ebpf_judy_pid.index.JudyLArray, p->pid, PJE0);
1208
+ }
1209
+ rw_spinlock_write_unlock(&ebpf_judy_pid.index.rw_spinlock);
1210
+
1211
freez(p->cmdline);
1212
ebpf_pid_stat_release(p);
1213
@@ -1279,12 +1249,6 @@ int get_pid_comm(pid_t pid, size_t n, char *dest)
1249
*/
1250
void cleanup_variables_from_other_threads(uint32_t pid)
1251
{
1282
- // Clean socket structures
1283
- if (socket_bandwidth_curr) {
1284
- ebpf_socket_release(socket_bandwidth_curr[pid]);
1285
- socket_bandwidth_curr[pid] = NULL;
1286
- }
1287
-
1252
// Clean cachestat structure
1253
if (cachestat_pid) {
1254
ebpf_cachestat_release(cachestat_pid[pid]);
collectors/ebpf.plugin/ebpf_apps.h
-24
@@ -150,24 +150,6 @@ typedef struct ebpf_process_stat {
150
uint8_t removeme;
151
} ebpf_process_stat_t;
152
153
-typedef struct ebpf_bandwidth {
154
- uint32_t pid;
155
-
156
- uint64_t first; // First timestamp
157
- uint64_t ct; // Last timestamp
158
- uint64_t bytes_sent; // Bytes sent
159
- uint64_t bytes_received; // Bytes received
160
- uint64_t call_tcp_sent; // Number of times tcp_sendmsg was called
161
- uint64_t call_tcp_received; // Number of times tcp_cleanup_rbuf was called
162
- uint64_t retransmit; // Number of times tcp_retransmit was called
163
- uint64_t call_udp_sent; // Number of times udp_sendmsg was called
164
- uint64_t call_udp_received; // Number of times udp_recvmsg was called
165
- uint64_t close; // Number of times tcp_close was called
166
- uint64_t drop; // THIS IS NOT USED FOR WHILE, we are in groom section
167
- uint32_t tcp_v4_connection; // Number of times tcp_v4_connection was called.
168
- uint32_t tcp_v6_connection; // Number of times tcp_v6_connection was called.
169
-} ebpf_bandwidth_t;
170
-
153
/**
154
* Internal function used to write debug messages.
155
*
@@ -208,12 +190,6 @@ int ebpf_read_hash_table(void *ep, int fd, uint32_t pid);
190
191
int get_pid_comm(pid_t pid, size_t n, char *dest);
192
211
-size_t read_processes_statistic_using_pid_on_target(ebpf_process_stat_t **ep,
212
- int fd,
213
- struct ebpf_pid_on_target *pids);
214
-
215
-size_t read_bandwidth_statistic_using_pid_on_target(ebpf_bandwidth_t **ep, int fd, struct ebpf_pid_on_target *pids);
216
-
193
void collect_data_for_all_processes(int tbl_pid_stats_fd, int maps_per_core);
194
void ebpf_process_apps_accumulator(ebpf_process_stat_t *out, int maps_per_core);
195
collectors/ebpf.plugin/ebpf_cachestat.c
+1
-1
@@ -1479,7 +1479,7 @@ static int ebpf_cachestat_load_bpf(ebpf_module_t *em)
1479
#endif
1480
1481
if (ret)
1482
- netdata_log_error("%s %s", EBPF_DEFAULT_ERROR_MSG, em->thread_name);
1482
+ netdata_log_error("%s %s", EBPF_DEFAULT_ERROR_MSG, em->info.thread_name);
1483
1484
return ret;
1485
}
collectors/ebpf.plugin/ebpf_cgroup.h
+1
-1
@@ -21,7 +21,7 @@ struct pid_on_target2 {
21
ebpf_process_stat_t ps;
22
netdata_dcstat_pid_t dc;
23
netdata_publish_shm_t shm;
24
- ebpf_bandwidth_t socket;
24
+ netdata_socket_t socket;
25
netdata_cachestat_pid_t cachestat;
26
27
struct pid_on_target2 *next;
collectors/ebpf.plugin/ebpf_dcstat.c
+1
-1
@@ -1311,7 +1311,7 @@ static int ebpf_dcstat_load_bpf(ebpf_module_t *em)
1311
#endif
1312
1313
if (ret)
1314
- netdata_log_error("%s %s", EBPF_DEFAULT_ERROR_MSG, em->thread_name);
1314
+ netdata_log_error("%s %s", EBPF_DEFAULT_ERROR_MSG, em->info.thread_name);
1315
1316
return ret;
1317
}
collectors/ebpf.plugin/ebpf_disk.c
+1
-1
@@ -873,7 +873,7 @@ static int ebpf_disk_load_bpf(ebpf_module_t *em)
873
#endif
874
875
if (ret)
876
- netdata_log_error("%s %s", EBPF_DEFAULT_ERROR_MSG, em->thread_name);
876
+ netdata_log_error("%s %s", EBPF_DEFAULT_ERROR_MSG, em->info.thread_name);
877
878
return ret;
879
}
collectors/ebpf.plugin/ebpf_fd.c
+1
-1
@@ -1337,7 +1337,7 @@ static int ebpf_fd_load_bpf(ebpf_module_t *em)
1337
#endif
1338
1339
if (ret)
1340
- netdata_log_error("%s %s", EBPF_DEFAULT_ERROR_MSG, em->thread_name);
1340
+ netdata_log_error("%s %s", EBPF_DEFAULT_ERROR_MSG, em->info.thread_name);
1341
1342
return ret;
1343
}
collectors/ebpf.plugin/ebpf_filesystem.c
+5
-5
@@ -470,12 +470,12 @@ int ebpf_filesystem_initialize_ebpf_data(ebpf_module_t *em)
470
{
471
pthread_mutex_lock(&lock);
472
int i;
473
- const char *saved_name = em->thread_name;
473
+ const char *saved_name = em->info.thread_name;
474
uint64_t kernels = em->kernels;
475
for (i = 0; localfs[i].filesystem; i++) {
476
ebpf_filesystem_partitions_t *efp = &localfs[i];
477
if (!efp->probe_links && efp->flags & NETDATA_FILESYSTEM_LOAD_EBPF_PROGRAM) {
478
- em->thread_name = efp->filesystem;
478
+ em->info.thread_name = efp->filesystem;
479
em->kernels = efp->kernels;
480
em->maps = efp->fs_maps;
481
#ifdef LIBBPF_MAJOR_VERSION
@@ -484,7 +484,7 @@ int ebpf_filesystem_initialize_ebpf_data(ebpf_module_t *em)
484
if (em->load & EBPF_LOAD_LEGACY) {
485
efp->probe_links = ebpf_load_program(ebpf_plugin_dir, em, running_on_kernel, isrh, &efp->objects);
486
if (!efp->probe_links) {
487
- em->thread_name = saved_name;
487
+ em->info.thread_name = saved_name;
488
em->kernels = kernels;
489
em->maps = NULL;
490
pthread_mutex_unlock(&lock);
@@ -495,7 +495,7 @@ int ebpf_filesystem_initialize_ebpf_data(ebpf_module_t *em)
495
else {
496
efp->fs_obj = filesystem_bpf__open();
497
if (!efp->fs_obj) {
498
- em->thread_name = saved_name;
498
+ em->info.thread_name = saved_name;
499
em->kernels = kernels;
500
return -1;
501
} else {
@@ -515,7 +515,7 @@ int ebpf_filesystem_initialize_ebpf_data(ebpf_module_t *em)
515
}
516
efp->flags &= ~NETDATA_FILESYSTEM_LOAD_EBPF_PROGRAM;
517
}
518
- em->thread_name = saved_name;
518
+ em->info.thread_name = saved_name;
519
pthread_mutex_unlock(&lock);
520
em->kernels = kernels;
521
em->maps = NULL;
collectors/ebpf.plugin/ebpf_functions.c
+755
-25
@@ -3,6 +3,42 @@
3
#include "ebpf.h"
4
#include "ebpf_functions.h"
5
6
+/*****************************************************************
7
+ * EBPF FUNCTION COMMON
8
+ *****************************************************************/
9
+
10
+RW_SPINLOCK rw_spinlock; // protect the buffer
11
+
12
+/**
13
+ * Function Start thread
14
+ *
15
+ * Start a specific thread after user request.
16
+ *
17
+ * @param em The structure with thread information
18
+ * @param period
19
+ * @return
20
+ */
21
+static int ebpf_function_start_thread(ebpf_module_t *em, int period)
22
+{
23
+ struct netdata_static_thread *st = em->thread;
24
+ // another request for thread that already ran, cleanup and restart
25
+ if (st->thread)
26
+ freez(st->thread);
27
+
28
+ if (period <= 0)
29
+ period = EBPF_DEFAULT_LIFETIME;
30
+
31
+ st->thread = mallocz(sizeof(netdata_thread_t));
32
+ em->enabled = NETDATA_THREAD_EBPF_FUNCTION_RUNNING;
33
+ em->lifetime = period;
34
+
35
+#ifdef NETDATA_INTERNAL_CHECKS
36
+ netdata_log_info("Starting thread %s with lifetime = %d", em->info.thread_name, period);
37
+#endif
38
+
39
+ return netdata_thread_create(st->thread, st->name, NETDATA_THREAD_OPTION_DEFAULT, st->start_routine, em);
40
+}
41
+
42
/*****************************************************************
43
* EBPF SELECT MODULE
44
*****************************************************************/
@@ -17,7 +53,7 @@
53
ebpf_module_t *ebpf_functions_select_module(const char *thread_name) {
54
int i;
55
for (i = 0; i < EBPF_MODULE_FUNCTION_IDX; i++) {
20
- if (strcmp(ebpf_modules[i].thread_name, thread_name) == 0) {
56
+ if (strcmp(ebpf_modules[i].info.thread_name, thread_name) == 0) {
57
return &ebpf_modules[i];
58
}
59
}
@@ -56,7 +92,6 @@ static void ebpf_function_thread_manipulation_help(const char *transaction) {
92
" Disable a sp.\n"
93
"\n"
94
"Filters can be combined. Each filter can be given only one time.\n"
59
- "Process thread is not controlled by functions until we finish the creation of functions per thread..\n"
95
);
96
97
pthread_mutex_lock(&lock);
@@ -66,7 +101,6 @@ static void ebpf_function_thread_manipulation_help(const char *transaction) {
101
buffer_free(wb);
102
}
103
69
-
104
/*****************************************************************
105
* EBPF ERROR FUNCTIONS
106
*****************************************************************/
@@ -91,7 +125,7 @@ static void ebpf_function_error(const char *transaction, int code, const char *m
125
*****************************************************************/
126
127
/**
94
- * Function enable
128
+ * Function: thread
129
*
130
* Enable a specific thread.
131
*
@@ -140,27 +174,15 @@ static void ebpf_function_thread_manipulation(const char *transaction,
174
175
pthread_mutex_lock(&ebpf_exit_cleanup);
176
if (lem->enabled > NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
143
- struct netdata_static_thread *st = lem->thread;
177
// Load configuration again
178
ebpf_update_module(lem, default_btf, running_on_kernel, isrh);
179
147
- // another request for thread that already ran, cleanup and restart
148
- if (st->thread)
149
- freez(st->thread);
150
-
151
- if (period <= 0)
152
- period = EBPF_DEFAULT_LIFETIME;
153
-
154
- st->thread = mallocz(sizeof(netdata_thread_t));
155
- lem->enabled = NETDATA_THREAD_EBPF_FUNCTION_RUNNING;
156
- lem->lifetime = period;
157
-
158
-#ifdef NETDATA_INTERNAL_CHECKS
159
- netdata_log_info("Starting thread %s with lifetime = %d", thread_name, period);
160
-#endif
161
-
162
- netdata_thread_create(st->thread, st->name, NETDATA_THREAD_OPTION_DEFAULT,
163
- st->start_routine, lem);
180
+ if (ebpf_function_start_thread(lem, period)) {
181
+ ebpf_function_error(transaction,
182
+ HTTP_RESP_INTERNAL_SERVER_ERROR,
183
+ "Cannot start thread.");
184
+ return;
185
+ }
186
} else {
187
lem->running_time = 0;
188
if (period > 0) // user is modifying period to run
@@ -225,10 +247,10 @@ static void ebpf_function_thread_manipulation(const char *transaction,
247
// THE ORDER SHOULD BE THE SAME WITH THE FIELDS!
248
249
// thread name
228
- buffer_json_add_array_item_string(wb, wem->thread_name);
250
+ buffer_json_add_array_item_string(wb, wem->info.thread_name);
251
252
// description
231
- buffer_json_add_array_item_string(wb, wem->thread_description);
253
+ buffer_json_add_array_item_string(wb, wem->info.thread_description);
254
// Either it is not running or received a disabled signal and it is stopping.
255
if (wem->enabled > NETDATA_THREAD_EBPF_FUNCTION_RUNNING ||
256
(!wem->lifetime && (int)wem->running_time == wem->update_every)) {
@@ -266,7 +288,7 @@ static void ebpf_function_thread_manipulation(const char *transaction,
288
RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE, 0, NULL, NAN,
289
RRDF_FIELD_SORT_ASCENDING, NULL, RRDF_FIELD_SUMMARY_COUNT,
290
RRDF_FIELD_FILTER_MULTISELECT,
269
- RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_STICKY, NULL);
291
+ RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_STICKY | RRDF_FIELD_OPTS_UNIQUE_KEY, NULL);
292
293
buffer_rrdf_table_add_field(wb, fields_id++, "Description", "Thread Desc", RRDF_FIELD_TYPE_STRING,
294
RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE, 0, NULL, NAN,
@@ -355,6 +377,698 @@ static void ebpf_function_thread_manipulation(const char *transaction,
377
buffer_free(wb);
378
}
379
380
+/*****************************************************************
381
+ * EBPF SOCKET FUNCTION
382
+ *****************************************************************/
383
+
384
+/**
385
+ * Thread Help
386
+ *
387
+ * Shows help with all options accepted by thread function.
388
+ *
389
+ * @param transaction the transaction id that Netdata sent for this function execution
390
+*/
391
+static void ebpf_function_socket_help(const char *transaction) {
392
+ pthread_mutex_lock(&lock);
393
+ pluginsd_function_result_begin_to_stdout(transaction, HTTP_RESP_OK, "text/plain", now_realtime_sec() + 3600);
394
+ fprintf(stdout, "%s",
395
+ "ebpf.plugin / socket\n"
396
+ "\n"
397
+ "Function `socket` display information for all open sockets during ebpf.plugin runtime.\n"
398
+ "During thread runtime the plugin is always collecting data, but when an option is modified, the plugin\n"
399
+ "resets completely the previous table and can show a clean data for the first request before to bring the\n"
400
+ "modified request.\n"
401
+ "\n"
402
+ "The following filters are supported:\n"
403
+ "\n"
404
+ " family:FAMILY\n"
405
+ " Shows information for the FAMILY specified. Option accepts IPV4, IPV6 and all, that is the default.\n"
406
+ "\n"
407
+ " period:PERIOD\n"
408
+ " Enable socket to run a specific PERIOD in seconds. When PERIOD is not\n"
409
+ " specified plugin will use the default 300 seconds\n"
410
+ "\n"
411
+ " resolve:BOOL\n"
412
+ " Resolve service name, default value is YES.\n"
413
+ "\n"
414
+ " range:CIDR\n"
415
+ " Show sockets that have only a specific destination. Default all addresses.\n"
416
+ "\n"
417
+ " port:range\n"
418
+ " Show sockets that have only a specific destination.\n"
419
+ "\n"
420
+ " reset\n"
421
+ " Send a reset to collector. When a collector receives this command, it uses everything defined in configuration file.\n"
422
+ "\n"
423
+ " interfaces\n"
424
+ " When the collector receives this command, it read all available interfaces on host.\n"
425
+ "\n"
426
+ "Filters can be combined. Each filter can be given only one time. Default all ports\n"
427
+ );
428
+ pluginsd_function_result_end_to_stdout();
429
+ fflush(stdout);
430
+ pthread_mutex_unlock(&lock);
431
+}
432
+
433
+/**
434
+ * Fill Fake socket
435
+ *
436
+ * Fill socket with an invalid request.
437
+ *
438
+ * @param fake_values is the structure where we are storing the value.
439
+ */
440
+static inline void ebpf_socket_fill_fake_socket(netdata_socket_plus_t *fake_values)
441
+{
442
+ snprintfz(fake_values->socket_string.src_ip, INET6_ADDRSTRLEN, "%s", "127.0.0.1");
443
+ snprintfz(fake_values->socket_string.dst_ip, INET6_ADDRSTRLEN, "%s", "127.0.0.1");
444
+ fake_values->pid = getpid();
445
+ //fake_values->socket_string.src_port = 0;
446
+ fake_values->socket_string.dst_port[0] = 0;
447
+ snprintfz(fake_values->socket_string.dst_ip, NI_MAXSERV, "%s", "none");
448
+ fake_values->data.family = AF_INET;
449
+ fake_values->data.protocol = AF_UNSPEC;
450
+}
451
+
452
+/**
453
+ * Fill function buffer
454
+ *
455
+ * Fill buffer with data to be shown on cloud.
456
+ *
457
+ * @param wb buffer where we store data.
458
+ * @param values data read from hash table
459
+ * @param name the process name
460
+ */
461
+static void ebpf_fill_function_buffer(BUFFER *wb, netdata_socket_plus_t *values, char *name)
462
+{
463
+ buffer_json_add_array_item_array(wb);
464
+
465
+ // IMPORTANT!
466
+ // THE ORDER SHOULD BE THE SAME WITH THE FIELDS!
467
+
468
+ // PID
469
+ buffer_json_add_array_item_uint64(wb, (uint64_t)values->pid);
470
+
471
+ // NAME
472
+ buffer_json_add_array_item_string(wb, (name) ? name : "not identified");
473
+
474
+ // Origin
475
+ buffer_json_add_array_item_string(wb, (values->data.external_origin) ? "incoming" : "outgoing");
476
+
477
+ // Source IP
478
+ buffer_json_add_array_item_string(wb, values->socket_string.src_ip);
479
+
480
+ // SRC Port
481
+ //buffer_json_add_array_item_uint64(wb, (uint64_t) values->socket_string.src_port);
482
+
483
+ // Destination IP
484
+ buffer_json_add_array_item_string(wb, values->socket_string.dst_ip);
485
+
486
+ // DST Port
487
+ buffer_json_add_array_item_string(wb, values->socket_string.dst_port);
488
+
489
+ uint64_t connections;
490
+ if (values->data.protocol == IPPROTO_TCP) {
491
+ // Protocol
492
+ buffer_json_add_array_item_string(wb, "TCP");
493
+
494
+ // Bytes received
495
+ buffer_json_add_array_item_uint64(wb, (uint64_t) values->data.tcp.tcp_bytes_received);
496
+
497
+ // Bytes sent
498
+ buffer_json_add_array_item_uint64(wb, (uint64_t) values->data.tcp.tcp_bytes_sent);
499
+
500
+ // Connections
501
+ connections = values->data.tcp.ipv4_connect + values->data.tcp.ipv6_connect;
502
+ } else if (values->data.protocol == IPPROTO_UDP) {
503
+ // Protocol
504
+ buffer_json_add_array_item_string(wb, "UDP");
505
+
506
+ // Bytes received
507
+ buffer_json_add_array_item_uint64(wb, (uint64_t) values->data.udp.udp_bytes_received);
508
+
509
+ // Bytes sent
510
+ buffer_json_add_array_item_uint64(wb, (uint64_t) values->data.udp.udp_bytes_sent);
511
+
512
+ // Connections
513
+ connections = values->data.udp.call_udp_sent + values->data.udp.call_udp_received;
514
+ } else {
515
+ // Protocol
516
+ buffer_json_add_array_item_string(wb, "UNSPEC");
517
+
518
+ // Bytes received
519
+ buffer_json_add_array_item_uint64(wb, 0);
520
+
521
+ // Bytes sent
522
+ buffer_json_add_array_item_uint64(wb, 0);
523
+
524
+ connections = 1;
525
+ }
526
+
527
+ // Connections
528
+ if (values->flags & NETDATA_SOCKET_FLAGS_ALREADY_OPEN) {
529
+ connections++;
530
+ } else if (!connections) {
531
+ // If no connections, this means that we lost when connection was opened
532
+ values->flags |= NETDATA_SOCKET_FLAGS_ALREADY_OPEN;
533
+ connections++;
534
+ }
535
+ buffer_json_add_array_item_uint64(wb, connections);
536
+
537
+ buffer_json_array_close(wb);
538
+}
539
+
540
+/**
541
+ * Clean Judy array unsafe
542
+ *
543
+ * Clean all Judy Array allocated to show table when a function is called.
544
+ * Before to call this function it is necessary to lock `ebpf_judy_pid.index.rw_spinlock`.
545
+ **/
546
+static void ebpf_socket_clean_judy_array_unsafe()
547
+{
548
+ if (!ebpf_judy_pid.index.JudyLArray)
549
+ return;
550
+
551
+ Pvoid_t *pid_value, *socket_value;
552
+ Word_t local_pid = 0, local_socket = 0;
553
+ bool first_pid = true, first_socket = true;
554
+ while ((pid_value = JudyLFirstThenNext(ebpf_judy_pid.index.JudyLArray, &local_pid, &first_pid))) {
555
+ netdata_ebpf_judy_pid_stats_t *pid_ptr = (netdata_ebpf_judy_pid_stats_t *)*pid_value;
556
+ rw_spinlock_write_lock(&pid_ptr->socket_stats.rw_spinlock);
557
+ if (pid_ptr->socket_stats.JudyLArray) {
558
+ while ((socket_value = JudyLFirstThenNext(pid_ptr->socket_stats.JudyLArray, &local_socket, &first_socket))) {
559
+ netdata_socket_plus_t *socket_clean = *socket_value;
560
+ aral_freez(aral_socket_table, socket_clean);
561
+ }
562
+ JudyLFreeArray(&pid_ptr->socket_stats.JudyLArray, PJE0);
563
+ pid_ptr->socket_stats.JudyLArray = NULL;
564
+ }
565
+ rw_spinlock_write_unlock(&pid_ptr->socket_stats.rw_spinlock);
566
+ }
567
+}
568
+
569
+/**
570
+ * Fill function buffer unsafe
571
+ *
572
+ * Fill the function buffer with socket information. Before to call this function it is necessary to lock
573
+ * ebpf_judy_pid.index.rw_spinlock
574
+ *
575
+ * @param buf buffer used to store data to be shown by function.
576
+ *
577
+ * @return it returns 0 on success and -1 otherwise.
578
+ */
579
+static void ebpf_socket_fill_function_buffer_unsafe(BUFFER *buf)
580
+{
581
+ int counter = 0;
582
+
583
+ Pvoid_t *pid_value, *socket_value;
584
+ Word_t local_pid = 0;
585
+ bool first_pid = true;
586
+ while ((pid_value = JudyLFirstThenNext(ebpf_judy_pid.index.JudyLArray, &local_pid, &first_pid))) {
587
+ netdata_ebpf_judy_pid_stats_t *pid_ptr = (netdata_ebpf_judy_pid_stats_t *)*pid_value;
588
+ bool first_socket = true;
589
+ Word_t local_timestamp = 0;
590
+ rw_spinlock_read_lock(&pid_ptr->socket_stats.rw_spinlock);
591
+ if (pid_ptr->socket_stats.JudyLArray) {
592
+ while ((socket_value = JudyLFirstThenNext(pid_ptr->socket_stats.JudyLArray, &local_timestamp, &first_socket))) {
593
+ netdata_socket_plus_t *values = (netdata_socket_plus_t *)*socket_value;
594
+ ebpf_fill_function_buffer(buf, values, pid_ptr->cmdline);
595
+ }
596
+ counter++;
597
+ }
598
+ rw_spinlock_read_unlock(&pid_ptr->socket_stats.rw_spinlock);
599
+ }
600
+
601
+ if (!counter) {
602
+ netdata_socket_plus_t fake_values = { };
603
+ ebpf_socket_fill_fake_socket(&fake_values);
604
+ ebpf_fill_function_buffer(buf, &fake_values, NULL);
605
+ }
606
+}
607
+
608
+/**
609
+ * Socket read hash
610
+ *
611
+ * This is the thread callback.
612
+ * This thread is necessary, because we cannot freeze the whole plugin to read the data on very busy socket.
613
+ *
614
+ * @param buf the buffer to store data;
615
+ * @param em the module main structure.
616
+ *
617
+ * @return It always returns NULL.
618
+ */
619
+void ebpf_socket_read_open_connections(BUFFER *buf, struct ebpf_module *em)
620
+{
621
+ // thread was not initialized or Array was reset
622
+ rw_spinlock_read_lock(&ebpf_judy_pid.index.rw_spinlock);
623
+ if (!em->maps || (em->maps[NETDATA_SOCKET_OPEN_SOCKET].map_fd == ND_EBPF_MAP_FD_NOT_INITIALIZED) ||
624
+ !ebpf_judy_pid.index.JudyLArray){
625
+ netdata_socket_plus_t fake_values = { };
626
+
627
+ ebpf_socket_fill_fake_socket(&fake_values);
628
+
629
+ ebpf_fill_function_buffer(buf, &fake_values, NULL);
630
+ rw_spinlock_read_unlock(&ebpf_judy_pid.index.rw_spinlock);
631
+ return;
632
+ }
633
+
634
+ rw_spinlock_read_lock(&network_viewer_opt.rw_spinlock);
635
+ ebpf_socket_fill_function_buffer_unsafe(buf);
636
+ rw_spinlock_read_unlock(&network_viewer_opt.rw_spinlock);
637
+ rw_spinlock_read_unlock(&ebpf_judy_pid.index.rw_spinlock);
638
+}
639
+
640
+/**
641
+ * Function: Socket
642
+ *
643
+ * Show information for sockets stored in hash tables.
644
+ *
645
+ * @param transaction the transaction id that Netdata sent for this function execution
646
+ * @param function function name and arguments given to thread.
647
+ * @param line_buffer buffer used to parse args
648
+ * @param line_max Number of arguments given
649
+ * @param timeout The function timeout
650
+ * @param em The structure with thread information
651
+ */
652
+static void ebpf_function_socket_manipulation(const char *transaction,
653
+ char *function __maybe_unused,
654
+ char *line_buffer __maybe_unused,
655
+ int line_max __maybe_unused,
656
+ int timeout __maybe_unused,
657
+ ebpf_module_t *em)
658
+{
659
+ UNUSED(line_buffer);
660
+ UNUSED(timeout);
661
+
662
+ char *words[PLUGINSD_MAX_WORDS] = {NULL};
663
+ size_t num_words = quoted_strings_splitter_pluginsd(function, words, PLUGINSD_MAX_WORDS);
664
+ const char *name;
665
+ int period = -1;
666
+ rw_spinlock_write_lock(&ebpf_judy_pid.index.rw_spinlock);
667
+ network_viewer_opt.enabled = CONFIG_BOOLEAN_YES;
668
+ uint32_t previous;
669
+
670
+ for (int i = 1; i < PLUGINSD_MAX_WORDS; i++) {
671
+ const char *keyword = get_word(words, num_words, i);
672
+ if (!keyword)
673
+ break;
674
+
675
+ if (strncmp(keyword, EBPF_FUNCTION_SOCKET_FAMILY, sizeof(EBPF_FUNCTION_SOCKET_FAMILY) - 1) == 0) {
676
+ name = &keyword[sizeof(EBPF_FUNCTION_SOCKET_FAMILY) - 1];
677
+ previous = network_viewer_opt.family;
678
+ uint32_t family = AF_UNSPEC;
679
+ if (!strcmp(name, "IPV4"))
680
+ family = AF_INET;
681
+ else if (!strcmp(name, "IPV6"))
682
+ family = AF_INET6;
683
+
684
+ if (family != previous) {
685
+ rw_spinlock_write_lock(&network_viewer_opt.rw_spinlock);
686
+ network_viewer_opt.family = family;
687
+ rw_spinlock_write_unlock(&network_viewer_opt.rw_spinlock);
688
+ ebpf_socket_clean_judy_array_unsafe();
689
+ }
690
+ } else if (strncmp(keyword, EBPF_FUNCTION_SOCKET_PERIOD, sizeof(EBPF_FUNCTION_SOCKET_PERIOD) - 1) == 0) {
691
+ name = &keyword[sizeof(EBPF_FUNCTION_SOCKET_PERIOD) - 1];
692
+ pthread_mutex_lock(&ebpf_exit_cleanup);
693
+ period = str2i(name);
694
+ if (period > 0) {
695
+ em->lifetime = period;
696
+ } else
697
+ em->lifetime = EBPF_NON_FUNCTION_LIFE_TIME;
698
+
699
+#ifdef NETDATA_DEV_MODE
700
+ collector_info("Lifetime modified for %u", em->lifetime);
701
+#endif
702
+ pthread_mutex_unlock(&ebpf_exit_cleanup);
703
+ } else if (strncmp(keyword, EBPF_FUNCTION_SOCKET_RESOLVE, sizeof(EBPF_FUNCTION_SOCKET_RESOLVE) - 1) == 0) {
704
+ previous = network_viewer_opt.service_resolution_enabled;
705
+ uint32_t resolution;
706
+ name = &keyword[sizeof(EBPF_FUNCTION_SOCKET_RESOLVE) - 1];
707
+ resolution = (!strcasecmp(name, "YES")) ? CONFIG_BOOLEAN_YES : CONFIG_BOOLEAN_NO;
708
+
709
+ if (previous != resolution) {
710
+ rw_spinlock_write_lock(&network_viewer_opt.rw_spinlock);
711
+ network_viewer_opt.service_resolution_enabled = resolution;
712
+ rw_spinlock_write_unlock(&network_viewer_opt.rw_spinlock);
713
+
714
+ ebpf_socket_clean_judy_array_unsafe();
715
+ }
716
+ } else if (strncmp(keyword, EBPF_FUNCTION_SOCKET_RANGE, sizeof(EBPF_FUNCTION_SOCKET_RANGE) - 1) == 0) {
717
+ name = &keyword[sizeof(EBPF_FUNCTION_SOCKET_RANGE) - 1];
718
+ rw_spinlock_write_lock(&network_viewer_opt.rw_spinlock);
719
+ ebpf_clean_ip_structure(&network_viewer_opt.included_ips);
720
+ ebpf_clean_ip_structure(&network_viewer_opt.excluded_ips);
721
+ ebpf_parse_ips_unsafe((char *)name);
722
+ rw_spinlock_write_unlock(&network_viewer_opt.rw_spinlock);
723
+
724
+ ebpf_socket_clean_judy_array_unsafe();
725
+ } else if (strncmp(keyword, EBPF_FUNCTION_SOCKET_PORT, sizeof(EBPF_FUNCTION_SOCKET_PORT) - 1) == 0) {
726
+ name = &keyword[sizeof(EBPF_FUNCTION_SOCKET_PORT) - 1];
727
+ rw_spinlock_write_lock(&network_viewer_opt.rw_spinlock);
728
+ ebpf_clean_port_structure(&network_viewer_opt.included_port);
729
+ ebpf_clean_port_structure(&network_viewer_opt.excluded_port);
730
+ ebpf_parse_ports((char *)name);
731
+ rw_spinlock_write_unlock(&network_viewer_opt.rw_spinlock);
732
+
733
+ ebpf_socket_clean_judy_array_unsafe();
734
+ } else if (strncmp(keyword, EBPF_FUNCTION_SOCKET_RESET, sizeof(EBPF_FUNCTION_SOCKET_RESET) - 1) == 0) {
735
+ rw_spinlock_write_lock(&network_viewer_opt.rw_spinlock);
736
+ ebpf_clean_port_structure(&network_viewer_opt.included_port);
737
+ ebpf_clean_port_structure(&network_viewer_opt.excluded_port);
738
+
739
+ ebpf_clean_ip_structure(&network_viewer_opt.included_ips);
740
+ ebpf_clean_ip_structure(&network_viewer_opt.excluded_ips);
741
+ ebpf_clean_ip_structure(&network_viewer_opt.ipv4_local_ip);
742
+ ebpf_clean_ip_structure(&network_viewer_opt.ipv6_local_ip);
743
+
744
+ parse_network_viewer_section(&socket_config);
745
+ ebpf_read_local_addresses_unsafe();
746
+ network_viewer_opt.enabled = CONFIG_BOOLEAN_YES;
747
+ rw_spinlock_write_unlock(&network_viewer_opt.rw_spinlock);
748
+ } else if (strncmp(keyword, EBPF_FUNCTION_SOCKET_INTERFACES, sizeof(EBPF_FUNCTION_SOCKET_INTERFACES) - 1) == 0) {
749
+ rw_spinlock_write_lock(&network_viewer_opt.rw_spinlock);
750
+ ebpf_read_local_addresses_unsafe();
751
+ rw_spinlock_write_unlock(&network_viewer_opt.rw_spinlock);
752
+ } else if (strncmp(keyword, "help", 4) == 0) {
753
+ ebpf_function_socket_help(transaction);
754
+ rw_spinlock_write_unlock(&ebpf_judy_pid.index.rw_spinlock);
755
+ return;
756
+ }
757
+ }
758
+ rw_spinlock_write_unlock(&ebpf_judy_pid.index.rw_spinlock);
759
+
760
+ pthread_mutex_lock(&ebpf_exit_cleanup);
761
+ if (em->enabled > NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
762
+ // Cleanup when we already had a thread running
763
+ rw_spinlock_write_lock(&ebpf_judy_pid.index.rw_spinlock);
764
+ ebpf_socket_clean_judy_array_unsafe();
765
+ rw_spinlock_write_unlock(&ebpf_judy_pid.index.rw_spinlock);
766
+
767
+ if (ebpf_function_start_thread(em, period)) {
768
+ ebpf_function_error(transaction,
769
+ HTTP_RESP_INTERNAL_SERVER_ERROR,
770
+ "Cannot start thread.");
771
+ pthread_mutex_unlock(&ebpf_exit_cleanup);
772
+ return;
773
+ }
774
+ } else {
775
+ if (period < 0 && em->lifetime < EBPF_NON_FUNCTION_LIFE_TIME) {
776
+ em->lifetime = EBPF_NON_FUNCTION_LIFE_TIME;
777
+ }
778
+ }
779
+ pthread_mutex_unlock(&ebpf_exit_cleanup);
780
+
781
+ time_t expires = now_realtime_sec() + em->update_every;
782
+
783
+ BUFFER *wb = buffer_create(PLUGINSD_LINE_MAX, NULL);
784
+ buffer_json_initialize(wb, "\"", "\"", 0, true, false);
785
+ buffer_json_member_add_uint64(wb, "status", HTTP_RESP_OK);
786
+ buffer_json_member_add_string(wb, "type", "table");
787
+ buffer_json_member_add_time_t(wb, "update_every", em->update_every);
788
+ buffer_json_member_add_string(wb, "help", EBPF_PLUGIN_SOCKET_FUNCTION_DESCRIPTION);
789
+
790
+ // Collect data
791
+ buffer_json_member_add_array(wb, "data");
792
+ ebpf_socket_read_open_connections(wb, em);
793
+ buffer_json_array_close(wb); // data
794
+
795
+ buffer_json_member_add_object(wb, "columns");
796
+ {
797
+ int fields_id = 0;
798
+
799
+ // IMPORTANT!
800
+ // THE ORDER SHOULD BE THE SAME WITH THE VALUES!
801
+ buffer_rrdf_table_add_field(wb, fields_id++, "PID", "Process ID", RRDF_FIELD_TYPE_INTEGER,
802
+ RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NUMBER, 0, NULL, NAN,
803
+ RRDF_FIELD_SORT_ASCENDING, NULL, RRDF_FIELD_SUMMARY_COUNT,
804
+ RRDF_FIELD_FILTER_MULTISELECT,
805
+ RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_STICKY,
806
+ NULL);
807
+
808
+ buffer_rrdf_table_add_field(wb, fields_id++, "Process Name", "Process Name", RRDF_FIELD_TYPE_STRING,
809
+ RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE, 0, NULL, NAN,
810
+ RRDF_FIELD_SORT_ASCENDING, NULL, RRDF_FIELD_SUMMARY_COUNT,
811
+ RRDF_FIELD_FILTER_MULTISELECT,
812
+ RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_STICKY, NULL);
813
+
814
+ buffer_rrdf_table_add_field(wb, fields_id++, "Origin", "The connection origin.", RRDF_FIELD_TYPE_STRING,
815
+ RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE, 0, NULL, NAN,
816
+ RRDF_FIELD_SORT_ASCENDING, NULL, RRDF_FIELD_SUMMARY_COUNT,
817
+ RRDF_FIELD_FILTER_MULTISELECT,
818
+ RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_STICKY, NULL);
819
+
820
+ buffer_rrdf_table_add_field(wb, fields_id++, "Request from", "Request from IP", RRDF_FIELD_TYPE_STRING,
821
+ RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE, 0, NULL, NAN,
822
+ RRDF_FIELD_SORT_ASCENDING, NULL, RRDF_FIELD_SUMMARY_COUNT,
823
+ RRDF_FIELD_FILTER_MULTISELECT,
824
+ RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_STICKY, NULL);
825
+
826
+ /*
827
+ buffer_rrdf_table_add_field(wb, fields_id++, "SRC PORT", "Source Port", RRDF_FIELD_TYPE_INTEGER,
828
+ RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NUMBER, 0, NULL, NAN,
829
+ RRDF_FIELD_SORT_ASCENDING, NULL, RRDF_FIELD_SUMMARY_COUNT,
830
+ RRDF_FIELD_FILTER_MULTISELECT,
831
+ RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_STICKY,
832
+ NULL);
833
+ */
834
+
835
+ buffer_rrdf_table_add_field(wb, fields_id++, "Destination IP", "Destination IP", RRDF_FIELD_TYPE_STRING,
836
+ RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE, 0, NULL, NAN,
837
+ RRDF_FIELD_SORT_ASCENDING, NULL, RRDF_FIELD_SUMMARY_COUNT,
838
+ RRDF_FIELD_FILTER_MULTISELECT,
839
+ RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_STICKY, NULL);
840
+
841
+ buffer_rrdf_table_add_field(wb, fields_id++, "Destination Port", "Destination Port", RRDF_FIELD_TYPE_STRING,
842
+ RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE, 0, NULL, NAN,
843
+ RRDF_FIELD_SORT_ASCENDING, NULL, RRDF_FIELD_SUMMARY_COUNT,
844
+ RRDF_FIELD_FILTER_MULTISELECT,
845
+ RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_STICKY, NULL);
846
+
847
+ buffer_rrdf_table_add_field(wb, fields_id++, "Protocol", "Communication protocol", RRDF_FIELD_TYPE_STRING,
848
+ RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE, 0, NULL, NAN,
849
+ RRDF_FIELD_SORT_ASCENDING, NULL, RRDF_FIELD_SUMMARY_COUNT,
850
+ RRDF_FIELD_FILTER_MULTISELECT,
851
+ RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_STICKY, NULL);
852
+
853
+ buffer_rrdf_table_add_field(wb, fields_id++, "Incoming Bandwidth", "Bytes received.", RRDF_FIELD_TYPE_INTEGER,
854
+ RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NUMBER, 0, NULL, NAN,
855
+ RRDF_FIELD_SORT_ASCENDING, NULL, RRDF_FIELD_SUMMARY_COUNT,
856
+ RRDF_FIELD_FILTER_MULTISELECT,
857
+ RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_STICKY,
858
+ NULL);
859
+
860
+ buffer_rrdf_table_add_field(wb, fields_id++, "Outgoing Bandwidth", "Bytes sent.", RRDF_FIELD_TYPE_INTEGER,
861
+ RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NUMBER, 0, NULL, NAN,
862
+ RRDF_FIELD_SORT_ASCENDING, NULL, RRDF_FIELD_SUMMARY_COUNT,
863
+ RRDF_FIELD_FILTER_MULTISELECT,
864
+ RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_STICKY,
865
+ NULL);
866
+
867
+ buffer_rrdf_table_add_field(wb, fields_id, "Connections", "Number of calls to tcp_vX_connections and udp_sendmsg, where X is the protocol version.", RRDF_FIELD_TYPE_INTEGER,
868
+ RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NUMBER, 0, NULL, NAN,
869
+ RRDF_FIELD_SORT_ASCENDING, NULL, RRDF_FIELD_SUMMARY_COUNT,
870
+ RRDF_FIELD_FILTER_MULTISELECT,
871
+ RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_STICKY,
872
+ NULL);
873
+ }
874
+ buffer_json_object_close(wb); // columns
875
+
876
+ buffer_json_member_add_object(wb, "charts");
877
+ {
878
+ // OutBound Connections
879
+ buffer_json_member_add_object(wb, "IPInboundConn");
880
+ {
881
+ buffer_json_member_add_string(wb, "name", "TCP Inbound Connection");
882
+ buffer_json_member_add_string(wb, "type", "line");
883
+ buffer_json_member_add_array(wb, "columns");
884
+ {
885
+ buffer_json_add_array_item_string(wb, "connected_tcp");
886
+ buffer_json_add_array_item_string(wb, "connected_udp");
887
+ }
888
+ buffer_json_array_close(wb);
889
+ }
890
+ buffer_json_object_close(wb);
891
+
892
+ // OutBound Connections
893
+ buffer_json_member_add_object(wb, "IPTCPOutboundConn");
894
+ {
895
+ buffer_json_member_add_string(wb, "name", "TCP Outbound Connection");
896
+ buffer_json_member_add_string(wb, "type", "line");
897
+ buffer_json_member_add_array(wb, "columns");
898
+ {
899
+ buffer_json_add_array_item_string(wb, "connected_V4");
900
+ buffer_json_add_array_item_string(wb, "connected_V6");
901
+ }
902
+ buffer_json_array_close(wb);
903
+ }
904
+ buffer_json_object_close(wb);
905
+
906
+ // TCP Functions
907
+ buffer_json_member_add_object(wb, "TCPFunctions");
908
+ {
909
+ buffer_json_member_add_string(wb, "name", "TCPFunctions");
910
+ buffer_json_member_add_string(wb, "type", "line");
911
+ buffer_json_member_add_array(wb, "columns");
912
+ {
913
+ buffer_json_add_array_item_string(wb, "received");
914
+ buffer_json_add_array_item_string(wb, "sent");
915
+ buffer_json_add_array_item_string(wb, "close");
916
+ }
917
+ buffer_json_array_close(wb);
918
+ }
919
+ buffer_json_object_close(wb);
920
+
921
+ // TCP Bandwidth
922
+ buffer_json_member_add_object(wb, "TCPBandwidth");
923
+ {
924
+ buffer_json_member_add_string(wb, "name", "TCPBandwidth");
925
+ buffer_json_member_add_string(wb, "type", "line");
926
+ buffer_json_member_add_array(wb, "columns");
927
+ {
928
+ buffer_json_add_array_item_string(wb, "received");
929
+ buffer_json_add_array_item_string(wb, "sent");
930
+ }
931
+ buffer_json_array_close(wb);
932
+ }
933
+ buffer_json_object_close(wb);
934
+
935
+ // UDP Functions
936
+ buffer_json_member_add_object(wb, "UDPFunctions");
937
+ {
938
+ buffer_json_member_add_string(wb, "name", "UDPFunctions");
939
+ buffer_json_member_add_string(wb, "type", "line");
940
+ buffer_json_member_add_array(wb, "columns");
941
+ {
942
+ buffer_json_add_array_item_string(wb, "received");
943
+ buffer_json_add_array_item_string(wb, "sent");
944
+ }
945
+ buffer_json_array_close(wb);
946
+ }
947
+ buffer_json_object_close(wb);
948
+
949
+ // UDP Bandwidth
950
+ buffer_json_member_add_object(wb, "UDPBandwidth");
951
+ {
952
+ buffer_json_member_add_string(wb, "name", "UDPBandwidth");
953
+ buffer_json_member_add_string(wb, "type", "line");
954
+ buffer_json_member_add_array(wb, "columns");
955
+ {
956
+ buffer_json_add_array_item_string(wb, "received");
957
+ buffer_json_add_array_item_string(wb, "sent");
958
+ }
959
+ buffer_json_array_close(wb);
960
+ }
961
+ buffer_json_object_close(wb);
962
+
963
+ }
964
+ buffer_json_object_close(wb); // charts
965
+
966
+ buffer_json_member_add_string(wb, "default_sort_column", "PID");
967
+
968
+ // Do we use only on fields that can be groupped?
969
+ buffer_json_member_add_object(wb, "group_by");
970
+ {
971
+ // group by PID
972
+ buffer_json_member_add_object(wb, "PID");
973
+ {
974
+ buffer_json_member_add_string(wb, "name", "Process ID");
975
+ buffer_json_member_add_array(wb, "columns");
976
+ {
977
+ buffer_json_add_array_item_string(wb, "PID");
978
+ }
979
+ buffer_json_array_close(wb);
980
+ }
981
+ buffer_json_object_close(wb);
982
+
983
+ // group by Process Name
984
+ buffer_json_member_add_object(wb, "Process Name");
985
+ {
986
+ buffer_json_member_add_string(wb, "name", "Process Name");
987
+ buffer_json_member_add_array(wb, "columns");
988
+ {
989
+ buffer_json_add_array_item_string(wb, "Process Name");
990
+ }
991
+ buffer_json_array_close(wb);
992
+ }
993
+ buffer_json_object_close(wb);
994
+
995
+ // group by Process Name
996
+ buffer_json_member_add_object(wb, "Origin");
997
+ {
998
+ buffer_json_member_add_string(wb, "name", "Origin");
999
+ buffer_json_member_add_array(wb, "columns");
1000
+ {
1001
+ buffer_json_add_array_item_string(wb, "Origin");
1002
+ }
1003
+ buffer_json_array_close(wb);
1004
+ }
1005
+ buffer_json_object_close(wb);
1006
+
1007
+ // group by Request From IP
1008
+ buffer_json_member_add_object(wb, "Request from");
1009
+ {
1010
+ buffer_json_member_add_string(wb, "name", "Request from IP");
1011
+ buffer_json_member_add_array(wb, "columns");
1012
+ {
1013
+ buffer_json_add_array_item_string(wb, "Request from");
1014
+ }
1015
+ buffer_json_array_close(wb);
1016
+ }
1017
+ buffer_json_object_close(wb);
1018
+
1019
+ // group by Destination IP
1020
+ buffer_json_member_add_object(wb, "Destination IP");
1021
+ {
1022
+ buffer_json_member_add_string(wb, "name", "Destination IP");
1023
+ buffer_json_member_add_array(wb, "columns");
1024
+ {
1025
+ buffer_json_add_array_item_string(wb, "Destination IP");
1026
+ }
1027
+ buffer_json_array_close(wb);
1028
+ }
1029
+ buffer_json_object_close(wb);
1030
+
1031
+ // group by DST Port
1032
+ buffer_json_member_add_object(wb, "Destination Port");
1033
+ {
1034
+ buffer_json_member_add_string(wb, "name", "Destination Port");
1035
+ buffer_json_member_add_array(wb, "columns");
1036
+ {
1037
+ buffer_json_add_array_item_string(wb, "Destination Port");
1038
+ }
1039
+ buffer_json_array_close(wb);
1040
+ }
1041
+ buffer_json_object_close(wb);
1042
+
1043
+ // group by Protocol
1044
+ buffer_json_member_add_object(wb, "Protocol");
1045
+ {
1046
+ buffer_json_member_add_string(wb, "name", "Protocol");
1047
+ buffer_json_member_add_array(wb, "columns");
1048
+ {
1049
+ buffer_json_add_array_item_string(wb, "Protocol");
1050
+ }
1051
+ buffer_json_array_close(wb);
1052
+ }
1053
+ buffer_json_object_close(wb);
1054
+ }
1055
+ buffer_json_object_close(wb); // group_by
1056
+
1057
+ buffer_json_member_add_time_t(wb, "expires", expires);
1058
+ buffer_json_finalize(wb);
1059
+
1060
+ // Lock necessary to avoid race condition
1061
+ pthread_mutex_lock(&lock);
1062
+ pluginsd_function_result_begin_to_stdout(transaction, HTTP_RESP_OK, "application/json", expires);
1063
+
1064
+ fwrite(buffer_tostring(wb), buffer_strlen(wb), 1, stdout);
1065
+
1066
+ pluginsd_function_result_end_to_stdout();
1067
+ fflush(stdout);
1068
+ pthread_mutex_unlock(&lock);
1069
+
1070
+ buffer_free(wb);
1071
+}
1072
1073
/*****************************************************************
1074
* EBPF FUNCTION THREAD
@@ -372,6 +1086,7 @@ void *ebpf_function_thread(void *ptr)
1086
ebpf_module_t *em = (ebpf_module_t *)ptr;
1087
char buffer[PLUGINSD_LINE_MAX + 1];
1088
1089
+ rw_spinlock_init(&rw_spinlock);
1090
char *s = NULL;
1091
while(!ebpf_exit_plugin && (s = fgets(buffer, PLUGINSD_LINE_MAX, stdin))) {
1092
char *words[PLUGINSD_MAX_WORDS] = { NULL };
@@ -393,6 +1108,7 @@ void *ebpf_function_thread(void *ptr)
1108
}
1109
else {
1110
int timeout = str2i(timeout_s);
1111
+ rw_spinlock_write_lock(&rw_spinlock);
1112
if (!strncmp(function, EBPF_FUNCTION_THREAD, sizeof(EBPF_FUNCTION_THREAD) - 1))
1113
ebpf_function_thread_manipulation(transaction,
1114
function,
@@ -400,14 +1116,28 @@ void *ebpf_function_thread(void *ptr)
1116
PLUGINSD_LINE_MAX + 1,
1117
timeout,
1118
em);
1119
+ else if (!strncmp(function, EBPF_FUNCTION_SOCKET, sizeof(EBPF_FUNCTION_SOCKET) - 1))
1120
+ ebpf_function_socket_manipulation(transaction,
1121
+ function,
1122
+ buffer,
1123
+ PLUGINSD_LINE_MAX + 1,
1124
+ timeout,
1125
+ &ebpf_modules[EBPF_MODULE_SOCKET_IDX]);
1126
else
1127
ebpf_function_error(transaction,
1128
HTTP_RESP_NOT_FOUND,
1129
"No function with this name found in ebpf.plugin.");
1130
+
1131
+ rw_spinlock_write_unlock(&rw_spinlock);
1132
}
1133
}
1134
else
1135
netdata_log_error("Received unknown command: %s", keyword ? keyword : "(unset)");
1136
}
1137
+
1138
+ if(!s || feof(stdin) || ferror(stdin)) {
1139
+ ebpf_stop_threads(SIGQUIT);
1140
+ netdata_log_error("Received error on stdin.");
1141
+ }
1142
return NULL;
1143
}
collectors/ebpf.plugin/ebpf_functions.h
+19
-4
@@ -3,20 +3,25 @@
3
#ifndef NETDATA_EBPF_FUNCTIONS_H
4
#define NETDATA_EBPF_FUNCTIONS_H 1
5
6
+#ifdef NETDATA_DEV_MODE
7
+// Common
8
+static inline void EBPF_PLUGIN_FUNCTIONS(const char *NAME, const char *DESC) {
9
+ fprintf(stdout, "%s \"%s\" 10 \"%s\"\n", PLUGINSD_KEYWORD_FUNCTION, NAME, DESC);
10
+}
11
+#endif
12
+
13
// configuration file & description
14
#define NETDATA_DIRECTORY_FUNCTIONS_CONFIG_FILE "functions.conf"
15
#define NETDATA_EBPF_FUNCTIONS_MODULE_DESC "Show information about current function status."
16
17
// function list
18
#define EBPF_FUNCTION_THREAD "ebpf_thread"
19
+#define EBPF_FUNCTION_SOCKET "ebpf_socket"
20
21
+// thread constants
22
#define EBPF_PLUGIN_THREAD_FUNCTION_DESCRIPTION "Detailed information about eBPF threads."
23
#define EBPF_PLUGIN_THREAD_FUNCTION_ERROR_THREAD_NOT_FOUND "ebpf.plugin does not have thread named "
24
16
-#define EBPF_PLUGIN_FUNCTIONS(NAME, DESC) do { \
17
- fprintf(stdout, PLUGINSD_KEYWORD_FUNCTION " \"" NAME "\" 10 \"%s\"\n", DESC); \
18
-} while(0)
19
-
25
#define EBPF_THREADS_SELECT_THREAD "thread:"
26
#define EBPF_THREADS_ENABLE_CATEGORY "enable:"
27
#define EBPF_THREADS_DISABLE_CATEGORY "disable:"
@@ -24,6 +29,16 @@
29
#define EBPF_THREAD_STATUS_RUNNING "running"
30
#define EBPF_THREAD_STATUS_STOPPED "stopped"
31
32
+// socket constants
33
+#define EBPF_PLUGIN_SOCKET_FUNCTION_DESCRIPTION "Detailed information about open sockets."
34
+#define EBPF_FUNCTION_SOCKET_FAMILY "family:"
35
+#define EBPF_FUNCTION_SOCKET_PERIOD "period:"
36
+#define EBPF_FUNCTION_SOCKET_RESOLVE "resolve:"
37
+#define EBPF_FUNCTION_SOCKET_RANGE "range:"
38
+#define EBPF_FUNCTION_SOCKET_PORT "port:"
39
+#define EBPF_FUNCTION_SOCKET_RESET "reset"
40
+#define EBPF_FUNCTION_SOCKET_INTERFACES "interfaces"
41
+
42
void *ebpf_function_thread(void *ptr);
43
44
#endif
collectors/ebpf.plugin/ebpf_mount.c
+1
-1
@@ -466,7 +466,7 @@ static int ebpf_mount_load_bpf(ebpf_module_t *em)
466
#endif
467
468
if (ret)
469
- netdata_log_error("%s %s", EBPF_DEFAULT_ERROR_MSG, em->thread_name);
469
+ netdata_log_error("%s %s", EBPF_DEFAULT_ERROR_MSG, em->info.thread_name);
470
471
return ret;
472
}
collectors/ebpf.plugin/ebpf_process.h
+2
-1
@@ -52,7 +52,8 @@ enum netdata_ebpf_stats_order {
52
NETDATA_EBPF_ORDER_STAT_HASH_GLOBAL_TABLE_TOTAL,
53
NETDATA_EBPF_ORDER_STAT_HASH_PID_TABLE_ADDED,
54
NETDATA_EBPF_ORDER_STAT_HASH_PID_TABLE_REMOVED,
55
- NETATA_EBPF_ORDER_STAT_ARAL_BEGIN
55
+ NETATA_EBPF_ORDER_STAT_ARAL_BEGIN,
56
+ NETDATA_EBPF_ORDER_FUNCTION_PER_THREAD,
57
};
58
59
enum netdata_ebpf_load_mode_stats{
collectors/ebpf.plugin/ebpf_shm.c
+1
-1
@@ -1222,7 +1222,7 @@ static int ebpf_shm_load_bpf(ebpf_module_t *em)
1222
1223
1224
if (ret)
1225
- netdata_log_error("%s %s", EBPF_DEFAULT_ERROR_MSG, em->thread_name);
1225
+ netdata_log_error("%s %s", EBPF_DEFAULT_ERROR_MSG, em->info.thread_name);
1226
1227
return ret;
1228
}
collectors/ebpf.plugin/ebpf_socket.c
+724
-1980
@@ -5,9 +5,6 @@
5
#include "ebpf.h"
6
#include "ebpf_socket.h"
7
8
-// ----------------------------------------------------------------------------
9
-// ARAL vectors used to speed up processing
10
-
8
/*****************************************************************
9
*
10
* GLOBAL VARIABLES
@@ -23,16 +20,7 @@ static char *socket_id_names[NETDATA_MAX_SOCKET_VECTOR] = { "tcp_cleanup_rbuf",
20
"tcp_connect_v4", "tcp_connect_v6", "inet_csk_accept_tcp",
21
"inet_csk_accept_udp" };
22
26
-static ebpf_local_maps_t socket_maps[] = {{.name = "tbl_bandwidth",
27
- .internal_input = NETDATA_COMPILED_CONNECTIONS_ALLOWED,
28
- .user_input = NETDATA_MAXIMUM_CONNECTIONS_ALLOWED,
29
- .type = NETDATA_EBPF_MAP_RESIZABLE | NETDATA_EBPF_MAP_PID,
30
- .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
31
-#ifdef LIBBPF_MAJOR_VERSION
32
- .map_type = BPF_MAP_TYPE_PERCPU_HASH
33
-#endif
34
- },
35
- {.name = "tbl_global_sock",
23
+static ebpf_local_maps_t socket_maps[] = {{.name = "tbl_global_sock",
24
.internal_input = NETDATA_SOCKET_COUNTER,
25
.user_input = 0, .type = NETDATA_EBPF_MAP_STATIC,
26
.map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
@@ -48,16 +36,7 @@ static ebpf_local_maps_t socket_maps[] = {{.name = "tbl_bandwidth",
36
.map_type = BPF_MAP_TYPE_PERCPU_HASH
37
#endif
38
},
51
- {.name = "tbl_conn_ipv4",
52
- .internal_input = NETDATA_COMPILED_CONNECTIONS_ALLOWED,
53
- .user_input = NETDATA_MAXIMUM_CONNECTIONS_ALLOWED,
54
- .type = NETDATA_EBPF_MAP_STATIC,
55
- .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
56
-#ifdef LIBBPF_MAJOR_VERSION
57
- .map_type = BPF_MAP_TYPE_PERCPU_HASH
58
-#endif
59
- },
60
- {.name = "tbl_conn_ipv6",
39
+ {.name = "tbl_nd_socket",
40
.internal_input = NETDATA_COMPILED_CONNECTIONS_ALLOWED,
41
.user_input = NETDATA_MAXIMUM_CONNECTIONS_ALLOWED,
42
.type = NETDATA_EBPF_MAP_STATIC,
@@ -93,11 +72,6 @@ static netdata_idx_t *socket_hash_values = NULL;
72
static netdata_syscall_stat_t socket_aggregated_data[NETDATA_MAX_SOCKET_VECTOR];
73
static netdata_publish_syscall_t socket_publish_aggregated[NETDATA_MAX_SOCKET_VECTOR];
74
96
-static ebpf_bandwidth_t *bandwidth_vector = NULL;
97
-
98
-pthread_mutex_t nv_mutex;
99
-netdata_vector_plot_t inbound_vectors = { .plot = NULL, .next = 0, .last = 0 };
100
-netdata_vector_plot_t outbound_vectors = { .plot = NULL, .next = 0, .last = 0 };
75
netdata_socket_t *socket_values;
76
77
ebpf_network_viewer_port_list_t *listen_ports = NULL;
@@ -108,28 +82,30 @@ struct config socket_config = { .first_section = NULL,
82
.index = { .avl_tree = { .root = NULL, .compar = appconfig_section_compare },
83
.rwlock = AVL_LOCK_INITIALIZER } };
84
111
-netdata_ebpf_targets_t socket_targets[] = { {.name = "inet_csk_accept", .mode = EBPF_LOAD_TRAMPOLINE},
112
- {.name = "tcp_retransmit_skb", .mode = EBPF_LOAD_TRAMPOLINE},
113
- {.name = "tcp_cleanup_rbuf", .mode = EBPF_LOAD_TRAMPOLINE},
114
- {.name = "tcp_close", .mode = EBPF_LOAD_TRAMPOLINE},
115
- {.name = "udp_recvmsg", .mode = EBPF_LOAD_TRAMPOLINE},
116
- {.name = "tcp_sendmsg", .mode = EBPF_LOAD_TRAMPOLINE},
117
- {.name = "udp_sendmsg", .mode = EBPF_LOAD_TRAMPOLINE},
118
- {.name = "tcp_v4_connect", .mode = EBPF_LOAD_TRAMPOLINE},
119
- {.name = "tcp_v6_connect", .mode = EBPF_LOAD_TRAMPOLINE},
85
+netdata_ebpf_targets_t socket_targets[] = { {.name = "inet_csk_accept", .mode = EBPF_LOAD_PROBE},
86
+ {.name = "tcp_retransmit_skb", .mode = EBPF_LOAD_PROBE},
87
+ {.name = "tcp_cleanup_rbuf", .mode = EBPF_LOAD_PROBE},
88
+ {.name = "tcp_close", .mode = EBPF_LOAD_PROBE},
89
+ {.name = "udp_recvmsg", .mode = EBPF_LOAD_PROBE},
90
+ {.name = "tcp_sendmsg", .mode = EBPF_LOAD_PROBE},
91
+ {.name = "udp_sendmsg", .mode = EBPF_LOAD_PROBE},
92
+ {.name = "tcp_v4_connect", .mode = EBPF_LOAD_PROBE},
93
+ {.name = "tcp_v6_connect", .mode = EBPF_LOAD_PROBE},
94
{.name = NULL, .mode = EBPF_LOAD_TRAMPOLINE}};
95
122
-struct netdata_static_thread socket_threads = {
123
- .name = "EBPF SOCKET READ",
124
- .config_section = NULL,
125
- .config_name = NULL,
126
- .env_name = NULL,
127
- .enabled = 1,
128
- .thread = NULL,
129
- .init_routine = NULL,
130
- .start_routine = NULL
96
+struct netdata_static_thread ebpf_read_socket = {
97
+ .name = "EBPF_READ_SOCKET",
98
+ .config_section = NULL,
99
+ .config_name = NULL,
100
+ .env_name = NULL,
101
+ .enabled = 1,
102
+ .thread = NULL,
103
+ .init_routine = NULL,
104
+ .start_routine = NULL
105
};
106
107
+ARAL *aral_socket_table = NULL;
108
+
109
#ifdef NETDATA_DEV_MODE
110
int socket_disable_priority;
111
#endif
@@ -145,7 +121,9 @@ int socket_disable_priority;
121
static void ebpf_socket_disable_probes(struct socket_bpf *obj)
122
{
123
bpf_program__set_autoload(obj->progs.netdata_inet_csk_accept_kretprobe, false);
124
+ bpf_program__set_autoload(obj->progs.netdata_tcp_v4_connect_kprobe, false);
125
bpf_program__set_autoload(obj->progs.netdata_tcp_v4_connect_kretprobe, false);
126
+ bpf_program__set_autoload(obj->progs.netdata_tcp_v6_connect_kprobe, false);
127
bpf_program__set_autoload(obj->progs.netdata_tcp_v6_connect_kretprobe, false);
128
bpf_program__set_autoload(obj->progs.netdata_tcp_retransmit_skb_kprobe, false);
129
bpf_program__set_autoload(obj->progs.netdata_tcp_cleanup_rbuf_kprobe, false);
@@ -156,7 +134,6 @@ static void ebpf_socket_disable_probes(struct socket_bpf *obj)
134
bpf_program__set_autoload(obj->progs.netdata_tcp_sendmsg_kprobe, false);
135
bpf_program__set_autoload(obj->progs.netdata_udp_sendmsg_kretprobe, false);
136
bpf_program__set_autoload(obj->progs.netdata_udp_sendmsg_kprobe, false);
159
- bpf_program__set_autoload(obj->progs.netdata_socket_release_task_kprobe, false);
137
}
138
139
/**
@@ -168,8 +145,10 @@ static void ebpf_socket_disable_probes(struct socket_bpf *obj)
145
*/
146
static void ebpf_socket_disable_trampoline(struct socket_bpf *obj)
147
{
171
- bpf_program__set_autoload(obj->progs.netdata_inet_csk_accept_fentry, false);
148
+ bpf_program__set_autoload(obj->progs.netdata_inet_csk_accept_fexit, false);
149
+ bpf_program__set_autoload(obj->progs.netdata_tcp_v4_connect_fentry, false);
150
bpf_program__set_autoload(obj->progs.netdata_tcp_v4_connect_fexit, false);
151
+ bpf_program__set_autoload(obj->progs.netdata_tcp_v6_connect_fentry, false);
152
bpf_program__set_autoload(obj->progs.netdata_tcp_v6_connect_fexit, false);
153
bpf_program__set_autoload(obj->progs.netdata_tcp_retransmit_skb_fentry, false);
154
bpf_program__set_autoload(obj->progs.netdata_tcp_cleanup_rbuf_fentry, false);
@@ -180,7 +159,6 @@ static void ebpf_socket_disable_trampoline(struct socket_bpf *obj)
159
bpf_program__set_autoload(obj->progs.netdata_tcp_sendmsg_fexit, false);
160
bpf_program__set_autoload(obj->progs.netdata_udp_sendmsg_fentry, false);
161
bpf_program__set_autoload(obj->progs.netdata_udp_sendmsg_fexit, false);
183
- bpf_program__set_autoload(obj->progs.netdata_socket_release_task_fentry, false);
162
}
163
164
/**
@@ -190,12 +168,18 @@ static void ebpf_socket_disable_trampoline(struct socket_bpf *obj)
168
*/
169
static void ebpf_set_trampoline_target(struct socket_bpf *obj)
170
{
193
- bpf_program__set_attach_target(obj->progs.netdata_inet_csk_accept_fentry, 0,
171
+ bpf_program__set_attach_target(obj->progs.netdata_inet_csk_accept_fexit, 0,
172
socket_targets[NETDATA_FCNT_INET_CSK_ACCEPT].name);
173
174
+ bpf_program__set_attach_target(obj->progs.netdata_tcp_v4_connect_fentry, 0,
175
+ socket_targets[NETDATA_FCNT_TCP_V4_CONNECT].name);
176
+
177
bpf_program__set_attach_target(obj->progs.netdata_tcp_v4_connect_fexit, 0,
178
socket_targets[NETDATA_FCNT_TCP_V4_CONNECT].name);
179
180
+ bpf_program__set_attach_target(obj->progs.netdata_tcp_v6_connect_fentry, 0,
181
+ socket_targets[NETDATA_FCNT_TCP_V6_CONNECT].name);
182
+
183
bpf_program__set_attach_target(obj->progs.netdata_tcp_v6_connect_fexit, 0,
184
socket_targets[NETDATA_FCNT_TCP_V6_CONNECT].name);
185
@@ -205,7 +189,8 @@ static void ebpf_set_trampoline_target(struct socket_bpf *obj)
189
bpf_program__set_attach_target(obj->progs.netdata_tcp_cleanup_rbuf_fentry, 0,
190
socket_targets[NETDATA_FCNT_CLEANUP_RBUF].name);
191
208
- bpf_program__set_attach_target(obj->progs.netdata_tcp_close_fentry, 0, socket_targets[NETDATA_FCNT_TCP_CLOSE].name);
192
+ bpf_program__set_attach_target(obj->progs.netdata_tcp_close_fentry, 0,
193
+ socket_targets[NETDATA_FCNT_TCP_CLOSE].name);
194
195
bpf_program__set_attach_target(obj->progs.netdata_udp_recvmsg_fentry, 0,
196
socket_targets[NETDATA_FCNT_UDP_RECEVMSG].name);
@@ -224,8 +209,6 @@ static void ebpf_set_trampoline_target(struct socket_bpf *obj)
209
210
bpf_program__set_attach_target(obj->progs.netdata_udp_sendmsg_fexit, 0,
211
socket_targets[NETDATA_FCNT_UDP_SENDMSG].name);
227
-
228
- bpf_program__set_attach_target(obj->progs.netdata_socket_release_task_fentry, 0, EBPF_COMMON_FNCT_CLEAN_UP);
212
}
213
214
@@ -241,9 +224,13 @@ static inline void ebpf_socket_disable_specific_trampoline(struct socket_bpf *ob
224
{
225
if (sel == MODE_RETURN) {
226
bpf_program__set_autoload(obj->progs.netdata_tcp_sendmsg_fentry, false);
227
+ bpf_program__set_autoload(obj->progs.netdata_tcp_v4_connect_fentry, false);
228
+ bpf_program__set_autoload(obj->progs.netdata_tcp_v6_connect_fentry, false);
229
bpf_program__set_autoload(obj->progs.netdata_udp_sendmsg_fentry, false);
230
} else {
231
bpf_program__set_autoload(obj->progs.netdata_tcp_sendmsg_fexit, false);
232
+ bpf_program__set_autoload(obj->progs.netdata_tcp_v4_connect_fexit, false);
233
+ bpf_program__set_autoload(obj->progs.netdata_tcp_v6_connect_fexit, false);
234
bpf_program__set_autoload(obj->progs.netdata_udp_sendmsg_fexit, false);
235
}
236
}
@@ -260,9 +247,13 @@ static inline void ebpf_socket_disable_specific_probe(struct socket_bpf *obj, ne
247
{
248
if (sel == MODE_RETURN) {
249
bpf_program__set_autoload(obj->progs.netdata_tcp_sendmsg_kprobe, false);
250
+ bpf_program__set_autoload(obj->progs.netdata_tcp_v4_connect_kprobe, false);
251
+ bpf_program__set_autoload(obj->progs.netdata_tcp_v6_connect_kprobe, false);
252
bpf_program__set_autoload(obj->progs.netdata_udp_sendmsg_kprobe, false);
253
} else {
254
bpf_program__set_autoload(obj->progs.netdata_tcp_sendmsg_kretprobe, false);
255
+ bpf_program__set_autoload(obj->progs.netdata_tcp_v4_connect_kretprobe, false);
256
+ bpf_program__set_autoload(obj->progs.netdata_tcp_v6_connect_kretprobe, false);
257
bpf_program__set_autoload(obj->progs.netdata_udp_sendmsg_kretprobe, false);
258
}
259
}
@@ -275,26 +266,12 @@ static inline void ebpf_socket_disable_specific_probe(struct socket_bpf *obj, ne
266
* @param obj is the main structure for bpf objects.
267
* @param sel option selected by user.
268
*/
278
-static int ebpf_socket_attach_probes(struct socket_bpf *obj, netdata_run_mode_t sel)
269
+static long ebpf_socket_attach_probes(struct socket_bpf *obj, netdata_run_mode_t sel)
270
{
271
obj->links.netdata_inet_csk_accept_kretprobe = bpf_program__attach_kprobe(obj->progs.netdata_inet_csk_accept_kretprobe,
272
true,
273
socket_targets[NETDATA_FCNT_INET_CSK_ACCEPT].name);
283
- int ret = libbpf_get_error(obj->links.netdata_inet_csk_accept_kretprobe);
284
- if (ret)
285
- return -1;
286
-
287
- obj->links.netdata_tcp_v4_connect_kretprobe = bpf_program__attach_kprobe(obj->progs.netdata_tcp_v4_connect_kretprobe,
288
- true,
289
- socket_targets[NETDATA_FCNT_TCP_V4_CONNECT].name);
290
- ret = libbpf_get_error(obj->links.netdata_tcp_v4_connect_kretprobe);
291
- if (ret)
292
- return -1;
293
-
294
- obj->links.netdata_tcp_v6_connect_kretprobe = bpf_program__attach_kprobe(obj->progs.netdata_tcp_v6_connect_kretprobe,
295
- true,
296
- socket_targets[NETDATA_FCNT_TCP_V6_CONNECT].name);
297
- ret = libbpf_get_error(obj->links.netdata_tcp_v6_connect_kretprobe);
274
+ long ret = libbpf_get_error(obj->links.netdata_inet_csk_accept_kretprobe);
275
if (ret)
276
return -1;
277
@@ -347,6 +324,20 @@ static int ebpf_socket_attach_probes(struct socket_bpf *obj, netdata_run_mode_t
324
ret = libbpf_get_error(obj->links.netdata_udp_sendmsg_kretprobe);
325
if (ret)
326
return -1;
327
+
328
+ obj->links.netdata_tcp_v4_connect_kretprobe = bpf_program__attach_kprobe(obj->progs.netdata_tcp_v4_connect_kretprobe,
329
+ true,
330
+ socket_targets[NETDATA_FCNT_TCP_V4_CONNECT].name);
331
+ ret = libbpf_get_error(obj->links.netdata_tcp_v4_connect_kretprobe);
332
+ if (ret)
333
+ return -1;
334
+
335
+ obj->links.netdata_tcp_v6_connect_kretprobe = bpf_program__attach_kprobe(obj->progs.netdata_tcp_v6_connect_kretprobe,
336
+ true,
337
+ socket_targets[NETDATA_FCNT_TCP_V6_CONNECT].name);
338
+ ret = libbpf_get_error(obj->links.netdata_tcp_v6_connect_kretprobe);
339
+ if (ret)
340
+ return -1;
341
} else {
342
obj->links.netdata_tcp_sendmsg_kprobe = bpf_program__attach_kprobe(obj->progs.netdata_tcp_sendmsg_kprobe,
343
false,
@@ -361,13 +352,21 @@ static int ebpf_socket_attach_probes(struct socket_bpf *obj, netdata_run_mode_t
352
ret = libbpf_get_error(obj->links.netdata_udp_sendmsg_kprobe);
353
if (ret)
354
return -1;
364
- }
355
366
- obj->links.netdata_socket_release_task_kprobe = bpf_program__attach_kprobe(obj->progs.netdata_socket_release_task_kprobe,
367
- false, EBPF_COMMON_FNCT_CLEAN_UP);
368
- ret = libbpf_get_error(obj->links.netdata_socket_release_task_kprobe);
369
- if (ret)
370
- return -1;
356
+ obj->links.netdata_tcp_v4_connect_kprobe = bpf_program__attach_kprobe(obj->progs.netdata_tcp_v4_connect_kprobe,
357
+ false,
358
+ socket_targets[NETDATA_FCNT_TCP_V4_CONNECT].name);
359
+ ret = libbpf_get_error(obj->links.netdata_tcp_v4_connect_kprobe);
360
+ if (ret)
361
+ return -1;
362
+
363
+ obj->links.netdata_tcp_v6_connect_kprobe = bpf_program__attach_kprobe(obj->progs.netdata_tcp_v6_connect_kprobe,
364
+ false,
365
+ socket_targets[NETDATA_FCNT_TCP_V6_CONNECT].name);
366
+ ret = libbpf_get_error(obj->links.netdata_tcp_v6_connect_kprobe);
367
+ if (ret)
368
+ return -1;
369
+ }
370
371
return 0;
372
}
@@ -381,11 +380,9 @@ static int ebpf_socket_attach_probes(struct socket_bpf *obj, netdata_run_mode_t
380
*/
381
static void ebpf_socket_set_hash_tables(struct socket_bpf *obj)
382
{
384
- socket_maps[NETDATA_SOCKET_TABLE_BANDWIDTH].map_fd = bpf_map__fd(obj->maps.tbl_bandwidth);
383
socket_maps[NETDATA_SOCKET_GLOBAL].map_fd = bpf_map__fd(obj->maps.tbl_global_sock);
384
socket_maps[NETDATA_SOCKET_LPORTS].map_fd = bpf_map__fd(obj->maps.tbl_lports);
387
- socket_maps[NETDATA_SOCKET_TABLE_IPV4].map_fd = bpf_map__fd(obj->maps.tbl_conn_ipv4);
388
- socket_maps[NETDATA_SOCKET_TABLE_IPV6].map_fd = bpf_map__fd(obj->maps.tbl_conn_ipv6);
385
+ socket_maps[NETDATA_SOCKET_OPEN_SOCKET].map_fd = bpf_map__fd(obj->maps.tbl_nd_socket);
386
socket_maps[NETDATA_SOCKET_TABLE_UDP].map_fd = bpf_map__fd(obj->maps.tbl_nv_udp);
387
socket_maps[NETDATA_SOCKET_TABLE_CTRL].map_fd = bpf_map__fd(obj->maps.socket_ctrl);
388
}
@@ -400,22 +397,13 @@ static void ebpf_socket_set_hash_tables(struct socket_bpf *obj)
397
*/
398
static void ebpf_socket_adjust_map(struct socket_bpf *obj, ebpf_module_t *em)
399
{
403
- ebpf_update_map_size(obj->maps.tbl_bandwidth, &socket_maps[NETDATA_SOCKET_TABLE_BANDWIDTH],
404
- em, bpf_map__name(obj->maps.tbl_bandwidth));
405
-
406
- ebpf_update_map_size(obj->maps.tbl_conn_ipv4, &socket_maps[NETDATA_SOCKET_TABLE_IPV4],
407
- em, bpf_map__name(obj->maps.tbl_conn_ipv4));
408
-
409
- ebpf_update_map_size(obj->maps.tbl_conn_ipv6, &socket_maps[NETDATA_SOCKET_TABLE_IPV6],
410
- em, bpf_map__name(obj->maps.tbl_conn_ipv6));
400
+ ebpf_update_map_size(obj->maps.tbl_nd_socket, &socket_maps[NETDATA_SOCKET_OPEN_SOCKET],
401
+ em, bpf_map__name(obj->maps.tbl_nd_socket));
402
403
ebpf_update_map_size(obj->maps.tbl_nv_udp, &socket_maps[NETDATA_SOCKET_TABLE_UDP],
404
em, bpf_map__name(obj->maps.tbl_nv_udp));
405
415
-
416
- ebpf_update_map_type(obj->maps.tbl_bandwidth, &socket_maps[NETDATA_SOCKET_TABLE_BANDWIDTH]);
417
- ebpf_update_map_type(obj->maps.tbl_conn_ipv4, &socket_maps[NETDATA_SOCKET_TABLE_IPV4]);
418
- ebpf_update_map_type(obj->maps.tbl_conn_ipv6, &socket_maps[NETDATA_SOCKET_TABLE_IPV6]);
406
+ ebpf_update_map_type(obj->maps.tbl_nd_socket, &socket_maps[NETDATA_SOCKET_OPEN_SOCKET]);
407
ebpf_update_map_type(obj->maps.tbl_nv_udp, &socket_maps[NETDATA_SOCKET_TABLE_UDP]);
408
ebpf_update_map_type(obj->maps.socket_ctrl, &socket_maps[NETDATA_SOCKET_TABLE_CTRL]);
409
ebpf_update_map_type(obj->maps.tbl_global_sock, &socket_maps[NETDATA_SOCKET_GLOBAL]);
@@ -459,7 +447,7 @@ static inline int ebpf_socket_load_and_attach(struct socket_bpf *obj, ebpf_modul
447
if (test == EBPF_LOAD_TRAMPOLINE) {
448
ret = socket_bpf__attach(obj);
449
} else {
462
- ret = ebpf_socket_attach_probes(obj, em->mode);
450
+ ret = (int)ebpf_socket_attach_probes(obj, em->mode);
451
}
452
453
if (!ret) {
@@ -479,211 +467,392 @@ static inline int ebpf_socket_load_and_attach(struct socket_bpf *obj, ebpf_modul
467
*****************************************************************/
468
469
/**
482
- * Clean internal socket plot
470
+ * Socket Free
471
*
484
- * Clean all structures allocated with strdupz.
472
+ * Cleanup variables after child threads to stop
473
*
486
- * @param ptr the pointer with addresses to clean.
474
+ * @param ptr thread data.
475
*/
488
-static inline void clean_internal_socket_plot(netdata_socket_plot_t *ptr)
476
+static void ebpf_socket_free(ebpf_module_t *em )
477
{
490
- freez(ptr->dimension_recv);
491
- freez(ptr->dimension_sent);
492
- freez(ptr->resolved_name);
493
- freez(ptr->dimension_retransmit);
478
+ pthread_mutex_lock(&ebpf_exit_cleanup);
479
+ em->enabled = NETDATA_THREAD_EBPF_STOPPED;
480
+ ebpf_update_stats(&plugin_statistics, em);
481
+ ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps, EBPF_ACTION_STAT_REMOVE);
482
+ pthread_mutex_unlock(&ebpf_exit_cleanup);
483
}
484
485
/**
497
- * Clean socket plot
486
+ * Obsolete Systemd Socket Charts
487
*
499
- * Clean the allocated data for inbound and outbound vectors.
500
-static void clean_allocated_socket_plot()
501
-{
502
- if (!network_viewer_opt.enabled)
503
- return;
504
-
505
- uint32_t i;
506
- uint32_t end = inbound_vectors.last;
507
- netdata_socket_plot_t *plot = inbound_vectors.plot;
508
- for (i = 0; i < end; i++) {
509
- clean_internal_socket_plot(&plot[i]);
510
- }
511
-
512
- clean_internal_socket_plot(&plot[inbound_vectors.last]);
513
-
514
- end = outbound_vectors.last;
515
- plot = outbound_vectors.plot;
516
- for (i = 0; i < end; i++) {
517
- clean_internal_socket_plot(&plot[i]);
518
- }
519
- clean_internal_socket_plot(&plot[outbound_vectors.last]);
520
-}
521
- */
522
-
523
-/**
524
- * Clean network ports allocated during initialization.
488
+ * Obsolete charts when systemd is enabled
489
*
526
- * @param ptr a pointer to the link list.
527
-static void clean_network_ports(ebpf_network_viewer_port_list_t *ptr)
490
+ * @param update_every value to overwrite the update frequency set by the server.
491
+ **/
492
+static void ebpf_obsolete_systemd_socket_charts(int update_every)
493
{
529
- if (unlikely(!ptr))
530
- return;
531
-
532
- while (ptr) {
533
- ebpf_network_viewer_port_list_t *next = ptr->next;
534
- freez(ptr->value);
535
- freez(ptr);
536
- ptr = next;
537
- }
494
+ int order = 20080;
495
+ ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
496
+ NETDATA_NET_APPS_CONNECTION_TCP_V4,
497
+ "Calls to tcp_v4_connection",
498
+ EBPF_COMMON_DIMENSION_CONNECTIONS,
499
+ NETDATA_APPS_NET_GROUP,
500
+ NETDATA_EBPF_CHART_TYPE_STACKED,
501
+ NETDATA_SERVICES_SOCKET_TCP_V4_CONN_CONTEXT,
502
+ order++,
503
+ update_every);
504
+
505
+ ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
506
+ NETDATA_NET_APPS_CONNECTION_TCP_V6,
507
+ "Calls to tcp_v6_connection",
508
+ EBPF_COMMON_DIMENSION_CONNECTIONS,
509
+ NETDATA_APPS_NET_GROUP,
510
+ NETDATA_EBPF_CHART_TYPE_STACKED,
511
+ NETDATA_SERVICES_SOCKET_TCP_V6_CONN_CONTEXT,
512
+ order++,
513
+ update_every);
514
+
515
+ ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
516
+ NETDATA_NET_APPS_BANDWIDTH_RECV,
517
+ "Bytes received",
518
+ EBPF_COMMON_DIMENSION_BITS,
519
+ NETDATA_APPS_NET_GROUP,
520
+ NETDATA_EBPF_CHART_TYPE_STACKED,
521
+ NETDATA_SERVICES_SOCKET_BYTES_RECV_CONTEXT,
522
+ order++,
523
+ update_every);
524
+
525
+ ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
526
+ NETDATA_NET_APPS_BANDWIDTH_SENT,
527
+ "Bytes sent",
528
+ EBPF_COMMON_DIMENSION_BITS,
529
+ NETDATA_APPS_NET_GROUP,
530
+ NETDATA_EBPF_CHART_TYPE_STACKED,
531
+ NETDATA_SERVICES_SOCKET_BYTES_SEND_CONTEXT,
532
+ order++,
533
+ update_every);
534
+
535
+ ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
536
+ NETDATA_NET_APPS_BANDWIDTH_TCP_RECV_CALLS,
537
+ "Calls to tcp_cleanup_rbuf.",
538
+ EBPF_COMMON_DIMENSION_CALL,
539
+ NETDATA_APPS_NET_GROUP,
540
+ NETDATA_EBPF_CHART_TYPE_STACKED,
541
+ NETDATA_SERVICES_SOCKET_TCP_RECV_CONTEXT,
542
+ order++,
543
+ update_every);
544
+
545
+ ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
546
+ NETDATA_NET_APPS_BANDWIDTH_TCP_SEND_CALLS,
547
+ "Calls to tcp_sendmsg.",
548
+ EBPF_COMMON_DIMENSION_CALL,
549
+ NETDATA_APPS_NET_GROUP,
550
+ NETDATA_EBPF_CHART_TYPE_STACKED,
551
+ NETDATA_SERVICES_SOCKET_TCP_SEND_CONTEXT,
552
+ order++,
553
+ update_every);
554
+
555
+ ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
556
+ NETDATA_NET_APPS_BANDWIDTH_TCP_RETRANSMIT,
557
+ "Calls to tcp_retransmit",
558
+ EBPF_COMMON_DIMENSION_CALL,
559
+ NETDATA_APPS_NET_GROUP,
560
+ NETDATA_EBPF_CHART_TYPE_STACKED,
561
+ NETDATA_SERVICES_SOCKET_TCP_RETRANSMIT_CONTEXT,
562
+ order++,
563
+ update_every);
564
+
565
+ ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
566
+ NETDATA_NET_APPS_BANDWIDTH_UDP_SEND_CALLS,
567
+ "Calls to udp_sendmsg",
568
+ EBPF_COMMON_DIMENSION_CALL,
569
+ NETDATA_APPS_NET_GROUP,
570
+ NETDATA_EBPF_CHART_TYPE_STACKED,
571
+ NETDATA_SERVICES_SOCKET_UDP_SEND_CONTEXT,
572
+ order++,
573
+ update_every);
574
+
575
+ ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
576
+ NETDATA_NET_APPS_BANDWIDTH_UDP_RECV_CALLS,
577
+ "Calls to udp_recvmsg",
578
+ EBPF_COMMON_DIMENSION_CALL,
579
+ NETDATA_APPS_NET_GROUP,
580
+ NETDATA_EBPF_CHART_TYPE_STACKED,
581
+ NETDATA_SERVICES_SOCKET_UDP_RECV_CONTEXT,
582
+ order++,
583
+ update_every);
584
}
539
- */
585
586
+static void ebpf_obsolete_specific_socket_charts(char *type, int update_every);
587
/**
542
- * Clean service names
588
+ * Obsolete cgroup chart
589
*
544
- * Clean the allocated link list that stores names.
590
+ * Send obsolete for all charts created before to close.
591
*
546
- * @param names the link list.
547
-static void clean_service_names(ebpf_network_viewer_dim_name_t *names)
548
-{
549
- if (unlikely(!names))
550
- return;
551
-
552
- while (names) {
553
- ebpf_network_viewer_dim_name_t *next = names->next;
554
- freez(names->name);
555
- freez(names);
556
- names = next;
557
- }
558
-}
592
+ * @param em a pointer to `struct ebpf_module`
593
*/
594
+static inline void ebpf_obsolete_socket_cgroup_charts(ebpf_module_t *em) {
595
+ pthread_mutex_lock(&mutex_cgroup_shm);
596
561
-/**
562
- * Clean hostnames
563
- *
564
- * @param hostnames the hostnames to clean
565
-static void clean_hostnames(ebpf_network_viewer_hostname_list_t *hostnames)
566
-{
567
- if (unlikely(!hostnames))
568
- return;
597
+ ebpf_obsolete_systemd_socket_charts(em->update_every);
598
570
- while (hostnames) {
571
- ebpf_network_viewer_hostname_list_t *next = hostnames->next;
572
- freez(hostnames->value);
573
- simple_pattern_free(hostnames->value_pattern);
574
- freez(hostnames);
575
- hostnames = next;
599
+ ebpf_cgroup_target_t *ect;
600
+ for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
601
+ if (ect->systemd)
602
+ continue;
603
+
604
+ ebpf_obsolete_specific_socket_charts(ect->name, em->update_every);
605
}
606
+ pthread_mutex_unlock(&mutex_cgroup_shm);
607
}
578
- */
608
609
/**
581
- * Clean port Structure
610
+ * Create apps charts
611
*
583
- * Clean the allocated list.
612
+ * Call ebpf_create_chart to create the charts on apps submenu.
613
*
585
- * @param clean the list that will be cleaned
614
+ * @param em a pointer to the structure with the default values.
615
*/
587
-void clean_port_structure(ebpf_network_viewer_port_list_t **clean)
616
+void ebpf_socket_obsolete_apps_charts(struct ebpf_module *em)
617
{
589
- ebpf_network_viewer_port_list_t *move = *clean;
590
- while (move) {
591
- ebpf_network_viewer_port_list_t *next = move->next;
592
- freez(move->value);
593
- freez(move);
594
-
595
- move = next;
596
- }
597
- *clean = NULL;
598
-}
599
-
600
-/**
601
- * Clean IP structure
602
- *
603
- * Clean the allocated list.
618
+ int order = 20080;
619
+ ebpf_write_chart_obsolete(NETDATA_APPS_FAMILY,
620
+ NETDATA_NET_APPS_CONNECTION_TCP_V4,
621
+ "Calls to tcp_v4_connection",
622
+ EBPF_COMMON_DIMENSION_CONNECTIONS,
623
+ NETDATA_APPS_NET_GROUP,
624
+ NETDATA_EBPF_CHART_TYPE_STACKED,
625
+ NULL,
626
+ order++,
627
+ em->update_every);
628
+
629
+ ebpf_write_chart_obsolete(NETDATA_APPS_FAMILY,
630
+ NETDATA_NET_APPS_CONNECTION_TCP_V6,
631
+ "Calls to tcp_v6_connection",
632
+ EBPF_COMMON_DIMENSION_CONNECTIONS,
633
+ NETDATA_APPS_NET_GROUP,
634
+ NETDATA_EBPF_CHART_TYPE_STACKED,
635
+ NULL,
636
+ order++,
637
+ em->update_every);
638
+
639
+ ebpf_write_chart_obsolete(NETDATA_APPS_FAMILY,
640
+ NETDATA_NET_APPS_BANDWIDTH_SENT,
641
+ "Bytes sent",
642
+ EBPF_COMMON_DIMENSION_BITS,
643
+ NETDATA_APPS_NET_GROUP,
644
+ NETDATA_EBPF_CHART_TYPE_STACKED,
645
+ NULL,
646
+ order++,
647
+ em->update_every);
648
+
649
+ ebpf_write_chart_obsolete(NETDATA_APPS_FAMILY,
650
+ NETDATA_NET_APPS_BANDWIDTH_RECV,
651
+ "bytes received",
652
+ EBPF_COMMON_DIMENSION_BITS,
653
+ NETDATA_APPS_NET_GROUP,
654
+ NETDATA_EBPF_CHART_TYPE_STACKED,
655
+ NULL,
656
+ order++,
657
+ em->update_every);
658
+
659
+ ebpf_write_chart_obsolete(NETDATA_APPS_FAMILY,
660
+ NETDATA_NET_APPS_BANDWIDTH_TCP_SEND_CALLS,
661
+ "Calls for tcp_sendmsg",
662
+ EBPF_COMMON_DIMENSION_CALL,
663
+ NETDATA_APPS_NET_GROUP,
664
+ NETDATA_EBPF_CHART_TYPE_STACKED,
665
+ NULL,
666
+ order++,
667
+ em->update_every);
668
+
669
+ ebpf_write_chart_obsolete(NETDATA_APPS_FAMILY,
670
+ NETDATA_NET_APPS_BANDWIDTH_TCP_RECV_CALLS,
671
+ "Calls for tcp_cleanup_rbuf",
672
+ EBPF_COMMON_DIMENSION_CALL,
673
+ NETDATA_APPS_NET_GROUP,
674
+ NETDATA_EBPF_CHART_TYPE_STACKED,
675
+ NULL,
676
+ order++,
677
+ em->update_every);
678
+
679
+ ebpf_write_chart_obsolete(NETDATA_APPS_FAMILY,
680
+ NETDATA_NET_APPS_BANDWIDTH_TCP_RETRANSMIT,
681
+ "Calls for tcp_retransmit",
682
+ EBPF_COMMON_DIMENSION_CALL,
683
+ NETDATA_APPS_NET_GROUP,
684
+ NETDATA_EBPF_CHART_TYPE_STACKED,
685
+ NULL,
686
+ order++,
687
+ em->update_every);
688
+
689
+ ebpf_write_chart_obsolete(NETDATA_APPS_FAMILY,
690
+ NETDATA_NET_APPS_BANDWIDTH_UDP_SEND_CALLS,
691
+ "Calls for udp_sendmsg",
692
+ EBPF_COMMON_DIMENSION_CALL,
693
+ NETDATA_APPS_NET_GROUP,
694
+ NETDATA_EBPF_CHART_TYPE_STACKED,
695
+ NULL,
696
+ order++,
697
+ em->update_every);
698
+
699
+ ebpf_write_chart_obsolete(NETDATA_APPS_FAMILY,
700
+ NETDATA_NET_APPS_BANDWIDTH_UDP_RECV_CALLS,
701
+ "Calls for udp_recvmsg",
702
+ EBPF_COMMON_DIMENSION_CALL,
703
+ NETDATA_APPS_NET_GROUP,
704
+ NETDATA_EBPF_CHART_TYPE_STACKED,
705
+ NULL,
706
+ order++,
707
+ em->update_every);
708
+}
709
+
710
+/**
711
+ * Obsolete global charts
712
+ *
713
+ * Obsolete charts created.
714
*
605
- * @param clean the list that will be cleaned
715
+ * @param em a pointer to the structure with the default values.
716
*/
607
-static void clean_ip_structure(ebpf_network_viewer_ip_list_t **clean)
717
+static void ebpf_socket_obsolete_global_charts(ebpf_module_t *em)
718
{
609
- ebpf_network_viewer_ip_list_t *move = *clean;
610
- while (move) {
611
- ebpf_network_viewer_ip_list_t *next = move->next;
612
- freez(move->value);
613
- freez(move);
719
+ int order = 21070;
720
+ ebpf_write_chart_obsolete(NETDATA_EBPF_IP_FAMILY,
721
+ NETDATA_INBOUND_CONNECTIONS,
722
+ "Inbound connections.",
723
+ EBPF_COMMON_DIMENSION_CONNECTIONS,
724
+ NETDATA_SOCKET_KERNEL_FUNCTIONS,
725
+ NETDATA_EBPF_CHART_TYPE_LINE,
726
+ NULL,
727
+ order++,
728
+ em->update_every);
729
+
730
+ ebpf_write_chart_obsolete(NETDATA_EBPF_IP_FAMILY,
731
+ NETDATA_TCP_OUTBOUND_CONNECTIONS,
732
+ "TCP outbound connections.",
733
+ EBPF_COMMON_DIMENSION_CONNECTIONS,
734
+ NETDATA_SOCKET_KERNEL_FUNCTIONS,
735
+ NETDATA_EBPF_CHART_TYPE_LINE,
736
+ NULL,
737
+ order++,
738
+ em->update_every);
739
+
740
+
741
+ ebpf_write_chart_obsolete(NETDATA_EBPF_IP_FAMILY,
742
+ NETDATA_TCP_FUNCTION_COUNT,
743
+ "Calls to internal functions",
744
+ EBPF_COMMON_DIMENSION_CALL,
745
+ NETDATA_SOCKET_KERNEL_FUNCTIONS,
746
+ NETDATA_EBPF_CHART_TYPE_LINE,
747
+ NULL,
748
+ order++,
749
+ em->update_every);
750
+
751
+ ebpf_write_chart_obsolete(NETDATA_EBPF_IP_FAMILY,
752
+ NETDATA_TCP_FUNCTION_BITS,
753
+ "TCP bandwidth",
754
+ EBPF_COMMON_DIMENSION_BITS,
755
+ NETDATA_SOCKET_KERNEL_FUNCTIONS,
756
+ NETDATA_EBPF_CHART_TYPE_LINE,
757
+ NULL,
758
+ order++,
759
+ em->update_every);
760
+
761
+ if (em->mode < MODE_ENTRY) {
762
+ ebpf_write_chart_obsolete(NETDATA_EBPF_IP_FAMILY,
763
+ NETDATA_TCP_FUNCTION_ERROR,
764
+ "TCP errors",
765
+ EBPF_COMMON_DIMENSION_CALL,
766
+ NETDATA_SOCKET_KERNEL_FUNCTIONS,
767
+ NETDATA_EBPF_CHART_TYPE_LINE,
768
+ NULL,
769
+ order++,
770
+ em->update_every);
771
+ }
772
+
773
+ ebpf_write_chart_obsolete(NETDATA_EBPF_IP_FAMILY,
774
+ NETDATA_TCP_RETRANSMIT,
775
+ "Packages retransmitted",
776
+ EBPF_COMMON_DIMENSION_CALL,
777
+ NETDATA_SOCKET_KERNEL_FUNCTIONS,
778
+ NETDATA_EBPF_CHART_TYPE_LINE,
779
+ NULL,
780
+ order++,
781
+ em->update_every);
782
+
783
+ ebpf_write_chart_obsolete(NETDATA_EBPF_IP_FAMILY,
784
+ NETDATA_UDP_FUNCTION_COUNT,
785
+ "UDP calls",
786
+ EBPF_COMMON_DIMENSION_CALL,
787
+ NETDATA_SOCKET_KERNEL_FUNCTIONS,
788
+ NETDATA_EBPF_CHART_TYPE_LINE,
789
+ NULL,
790
+ order++,
791
+ em->update_every);
792
+
793
+ ebpf_write_chart_obsolete(NETDATA_EBPF_IP_FAMILY,
794
+ NETDATA_UDP_FUNCTION_BITS,
795
+ "UDP bandwidth",
796
+ EBPF_COMMON_DIMENSION_BITS,
797
+ NETDATA_SOCKET_KERNEL_FUNCTIONS,
798
+ NETDATA_EBPF_CHART_TYPE_LINE,
799
+ NULL,
800
+ order++,
801
+ em->update_every);
802
615
- move = next;
803
+ if (em->mode < MODE_ENTRY) {
804
+ ebpf_write_chart_obsolete(NETDATA_EBPF_IP_FAMILY,
805
+ NETDATA_UDP_FUNCTION_ERROR,
806
+ "UDP errors",
807
+ EBPF_COMMON_DIMENSION_CALL,
808
+ NETDATA_SOCKET_KERNEL_FUNCTIONS,
809
+ NETDATA_EBPF_CHART_TYPE_LINE,
810
+ NULL,
811
+ order++,
812
+ em->update_every);
813
}
617
- *clean = NULL;
618
-}
814
815
+ fflush(stdout);
816
+}
817
/**
621
- * Socket Free
818
+ * Socket exit
819
*
623
- * Cleanup variables after child threads to stop
820
+ * Clean up the main thread.
821
*
822
* @param ptr thread data.
823
*/
627
-static void ebpf_socket_free(ebpf_module_t *em )
824
+static void ebpf_socket_exit(void *ptr)
825
{
629
- /* We can have thousands of sockets to clean, so we are transferring
630
- * for OS the responsibility while we do not use ARAL here
631
- freez(socket_hash_values);
826
+ ebpf_module_t *em = (ebpf_module_t *)ptr;
827
633
- freez(bandwidth_vector);
828
+ if (ebpf_read_socket.thread)
829
+ netdata_thread_cancel(*ebpf_read_socket.thread);
830
635
- freez(socket_values);
636
- clean_allocated_socket_plot();
637
- freez(inbound_vectors.plot);
638
- freez(outbound_vectors.plot);
831
+ if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
832
+ pthread_mutex_lock(&lock);
833
640
- clean_port_structure(&listen_ports);
834
+ if (em->cgroup_charts) {
835
+ ebpf_obsolete_socket_cgroup_charts(em);
836
+ fflush(stdout);
837
+ }
838
642
- clean_network_ports(network_viewer_opt.included_port);
643
- clean_network_ports(network_viewer_opt.excluded_port);
644
- clean_service_names(network_viewer_opt.names);
645
- clean_hostnames(network_viewer_opt.included_hostnames);
646
- clean_hostnames(network_viewer_opt.excluded_hostnames);
647
- */
839
+ if (em->apps_charts & NETDATA_EBPF_APPS_FLAG_CHART_CREATED) {
840
+ ebpf_socket_obsolete_apps_charts(em);
841
+ fflush(stdout);
842
+ }
843
649
- pthread_mutex_destroy(&nv_mutex);
844
+ ebpf_socket_obsolete_global_charts(em);
845
651
- pthread_mutex_lock(&ebpf_exit_cleanup);
652
- em->enabled = NETDATA_THREAD_EBPF_STOPPED;
653
- ebpf_update_stats(&plugin_statistics, em);
654
- ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps, EBPF_ACTION_STAT_REMOVE);
655
- pthread_mutex_unlock(&ebpf_exit_cleanup);
656
-}
846
+#ifdef NETDATA_DEV_MODE
847
+ if (ebpf_aral_socket_pid)
848
+ ebpf_statistic_obsolete_aral_chart(em, socket_disable_priority);
849
+#endif
850
+ pthread_mutex_unlock(&lock);
851
+ }
852
658
-/**
659
- * Socket exit
660
- *
661
- * Clean up the main thread.
662
- *
663
- * @param ptr thread data.
664
- */
665
-static void ebpf_socket_exit(void *ptr)
666
-{
667
- ebpf_module_t *em = (ebpf_module_t *)ptr;
668
- pthread_mutex_lock(&nv_mutex);
669
- if (socket_threads.thread)
670
- netdata_thread_cancel(*socket_threads.thread);
671
- pthread_mutex_unlock(&nv_mutex);
853
ebpf_socket_free(em);
854
}
855
675
-/**
676
- * Socket cleanup
677
- *
678
- * Clean up allocated addresses.
679
- *
680
- * @param ptr thread data.
681
- */
682
-void ebpf_socket_cleanup(void *ptr)
683
-{
684
- UNUSED(ptr);
685
-}
686
-
856
/*****************************************************************
857
*
858
* PROCESS DATA AND SEND TO NETDATA
@@ -736,174 +905,6 @@ static void ebpf_update_global_publish(
905
udp->read = (long)publish[4].nbyte;
906
}
907
739
-/**
740
- * Update Network Viewer plot data
741
- *
742
- * @param plot the structure where the data will be stored
743
- * @param sock the last update from the socket
744
- */
745
-static inline void update_nv_plot_data(netdata_plot_values_t *plot, netdata_socket_t *sock)
746
-{
747
- if (sock->ct != plot->last_time) {
748
- plot->last_time = sock->ct;
749
- plot->plot_recv_packets = sock->recv_packets;
750
- plot->plot_sent_packets = sock->sent_packets;
751
- plot->plot_recv_bytes = sock->recv_bytes;
752
- plot->plot_sent_bytes = sock->sent_bytes;
753
- plot->plot_retransmit = sock->retransmit;
754
- }
755
-
756
- sock->recv_packets = 0;
757
- sock->sent_packets = 0;
758
- sock->recv_bytes = 0;
759
- sock->sent_bytes = 0;
760
- sock->retransmit = 0;
761
-}
762
-
763
-/**
764
- * Calculate Network Viewer Plot
765
- *
766
- * Do math with collected values before to plot data.
767
- */
768
-static inline void calculate_nv_plot()
769
-{
770
- pthread_mutex_lock(&nv_mutex);
771
- uint32_t i;
772
- uint32_t end = inbound_vectors.next;
773
- for (i = 0; i < end; i++) {
774
- update_nv_plot_data(&inbound_vectors.plot[i].plot, &inbound_vectors.plot[i].sock);
775
- }
776
- inbound_vectors.max_plot = end;
777
-
778
- // The 'Other' dimension is always calculated for the chart to have at least one dimension
779
- update_nv_plot_data(&inbound_vectors.plot[inbound_vectors.last].plot,
780
- &inbound_vectors.plot[inbound_vectors.last].sock);
781
-
782
- end = outbound_vectors.next;
783
- for (i = 0; i < end; i++) {
784
- update_nv_plot_data(&outbound_vectors.plot[i].plot, &outbound_vectors.plot[i].sock);
785
- }
786
- outbound_vectors.max_plot = end;
787
-
788
- /*
789
- // The 'Other' dimension is always calculated for the chart to have at least one dimension
790
- update_nv_plot_data(&outbound_vectors.plot[outbound_vectors.last].plot,
791
- &outbound_vectors.plot[outbound_vectors.last].sock);
792
- */
793
- pthread_mutex_unlock(&nv_mutex);
794
-}
795
-
796
-/**
797
- * Network viewer send bytes
798
- *
799
- * @param ptr the structure with values to plot
800
- * @param chart the chart name.
801
- */
802
-static inline void ebpf_socket_nv_send_bytes(netdata_vector_plot_t *ptr, char *chart)
803
-{
804
- uint32_t i;
805
- uint32_t end = ptr->last_plot;
806
- netdata_socket_plot_t *w = ptr->plot;
807
- collected_number value;
808
-
809
- write_begin_chart(NETDATA_EBPF_FAMILY, chart);
810
- for (i = 0; i < end; i++) {
811
- value = ((collected_number) w[i].plot.plot_sent_bytes);
812
- write_chart_dimension(w[i].dimension_sent, value);
813
- value = (collected_number) w[i].plot.plot_recv_bytes;
814
- write_chart_dimension(w[i].dimension_recv, value);
815
- }
816
-
817
- i = ptr->last;
818
- value = ((collected_number) w[i].plot.plot_sent_bytes);
819
- write_chart_dimension(w[i].dimension_sent, value);
820
- value = (collected_number) w[i].plot.plot_recv_bytes;
821
- write_chart_dimension(w[i].dimension_recv, value);
822
- write_end_chart();
823
-}
824
-
825
-/**
826
- * Network Viewer Send packets
827
- *
828
- * @param ptr the structure with values to plot
829
- * @param chart the chart name.
830
- */
831
-static inline void ebpf_socket_nv_send_packets(netdata_vector_plot_t *ptr, char *chart)
832
-{
833
- uint32_t i;
834
- uint32_t end = ptr->last_plot;
835
- netdata_socket_plot_t *w = ptr->plot;
836
- collected_number value;
837
-
838
- write_begin_chart(NETDATA_EBPF_FAMILY, chart);
839
- for (i = 0; i < end; i++) {
840
- value = ((collected_number)w[i].plot.plot_sent_packets);
841
- write_chart_dimension(w[i].dimension_sent, value);
842
- value = (collected_number) w[i].plot.plot_recv_packets;
843
- write_chart_dimension(w[i].dimension_recv, value);
844
- }
845
-
846
- i = ptr->last;
847
- value = ((collected_number)w[i].plot.plot_sent_packets);
848
- write_chart_dimension(w[i].dimension_sent, value);
849
- value = (collected_number)w[i].plot.plot_recv_packets;
850
- write_chart_dimension(w[i].dimension_recv, value);
851
- write_end_chart();
852
-}
853
-
854
-/**
855
- * Network Viewer Send Retransmit
856
- *
857
- * @param ptr the structure with values to plot
858
- * @param chart the chart name.
859
- */
860
-static inline void ebpf_socket_nv_send_retransmit(netdata_vector_plot_t *ptr, char *chart)
861
-{
862
- uint32_t i;
863
- uint32_t end = ptr->last_plot;
864
- netdata_socket_plot_t *w = ptr->plot;
865
- collected_number value;
866
-
867
- write_begin_chart(NETDATA_EBPF_FAMILY, chart);
868
- for (i = 0; i < end; i++) {
869
- value = (collected_number) w[i].plot.plot_retransmit;
870
- write_chart_dimension(w[i].dimension_retransmit, value);
871
- }
872
-
873
- i = ptr->last;
874
- value = (collected_number)w[i].plot.plot_retransmit;
875
- write_chart_dimension(w[i].dimension_retransmit, value);
876
- write_end_chart();
877
-}
878
-
879
-/**
880
- * Send network viewer data
881
- *
882
- * @param ptr the pointer to plot data
883
- */
884
-static void ebpf_socket_send_nv_data(netdata_vector_plot_t *ptr)
885
-{
886
- if (!ptr->flags)
887
- return;
888
-
889
- if (ptr == (netdata_vector_plot_t *)&outbound_vectors) {
890
- ebpf_socket_nv_send_bytes(ptr, NETDATA_NV_OUTBOUND_BYTES);
891
- fflush(stdout);
892
-
893
- ebpf_socket_nv_send_packets(ptr, NETDATA_NV_OUTBOUND_PACKETS);
894
- fflush(stdout);
895
-
896
- ebpf_socket_nv_send_retransmit(ptr, NETDATA_NV_OUTBOUND_RETRANSMIT);
897
- fflush(stdout);
898
- } else {
899
- ebpf_socket_nv_send_bytes(ptr, NETDATA_NV_INBOUND_BYTES);
900
- fflush(stdout);
901
-
902
- ebpf_socket_nv_send_packets(ptr, NETDATA_NV_INBOUND_PACKETS);
903
- fflush(stdout);
904
- }
905
-}
906
-
908
/**
909
* Send Global Inbound connection
910
*
@@ -1112,7 +1113,7 @@ void ebpf_socket_send_apps_data(ebpf_module_t *em, struct ebpf_target *root)
1113
*
1114
* @param em a pointer to the structure with the default values.
1115
*/
1115
-static void ebpf_create_global_charts(ebpf_module_t *em)
1116
+static void ebpf_socket_create_global_charts(ebpf_module_t *em)
1117
{
1118
int order = 21070;
1119
ebpf_create_chart(NETDATA_EBPF_IP_FAMILY,
@@ -1319,138 +1320,6 @@ void ebpf_socket_create_apps_charts(struct ebpf_module *em, void *ptr)
1320
em->apps_charts |= NETDATA_EBPF_APPS_FLAG_CHART_CREATED;
1321
}
1322
1322
-/**
1323
- * Create network viewer chart
1324
- *
1325
- * Create common charts.
1326
- *
1327
- * @param id chart id
1328
- * @param title chart title
1329
- * @param units units label
1330
- * @param family group name used to attach the chart on dashboard
1331
- * @param order chart order
1332
- * @param update_every value to overwrite the update frequency set by the server.
1333
- * @param ptr plot structure with values.
1334
- */
1335
-static void ebpf_socket_create_nv_chart(char *id, char *title, char *units,
1336
- char *family, int order, int update_every, netdata_vector_plot_t *ptr)
1337
-{
1338
- ebpf_write_chart_cmd(NETDATA_EBPF_FAMILY,
1339
- id,
1340
- title,
1341
- units,
1342
- family,
1343
- NETDATA_EBPF_CHART_TYPE_STACKED,
1344
- NULL,
1345
- order,
1346
- update_every,
1347
- NETDATA_EBPF_MODULE_NAME_SOCKET);
1348
-
1349
- uint32_t i;
1350
- uint32_t end = ptr->last_plot;
1351
- netdata_socket_plot_t *w = ptr->plot;
1352
- for (i = 0; i < end; i++) {
1353
- fprintf(stdout, "DIMENSION %s '' incremental -1 1\n", w[i].dimension_sent);
1354
- fprintf(stdout, "DIMENSION %s '' incremental 1 1\n", w[i].dimension_recv);
1355
- }
1356
-
1357
- end = ptr->last;
1358
- fprintf(stdout, "DIMENSION %s '' incremental -1 1\n", w[end].dimension_sent);
1359
- fprintf(stdout, "DIMENSION %s '' incremental 1 1\n", w[end].dimension_recv);
1360
-}
1361
-
1362
-/**
1363
- * Create network viewer retransmit
1364
- *
1365
- * Create a specific chart.
1366
- *
1367
- * @param id the chart id
1368
- * @param title the chart title
1369
- * @param units the units label
1370
- * @param family the group name used to attach the chart on dashboard
1371
- * @param order the chart order
1372
- * @param update_every value to overwrite the update frequency set by the server.
1373
- * @param ptr the plot structure with values.
1374
- */
1375
-static void ebpf_socket_create_nv_retransmit(char *id, char *title, char *units,
1376
- char *family, int order, int update_every, netdata_vector_plot_t *ptr)
1377
-{
1378
- ebpf_write_chart_cmd(NETDATA_EBPF_FAMILY,
1379
- id,
1380
- title,
1381
- units,
1382
- family,
1383
- NETDATA_EBPF_CHART_TYPE_STACKED,
1384
- NULL,
1385
- order,
1386
- update_every,
1387
- NETDATA_EBPF_MODULE_NAME_SOCKET);
1388
-
1389
- uint32_t i;
1390
- uint32_t end = ptr->last_plot;
1391
- netdata_socket_plot_t *w = ptr->plot;
1392
- for (i = 0; i < end; i++) {
1393
- fprintf(stdout, "DIMENSION %s '' incremental 1 1\n", w[i].dimension_retransmit);
1394
- }
1395
-
1396
- end = ptr->last;
1397
- fprintf(stdout, "DIMENSION %s '' incremental 1 1\n", w[end].dimension_retransmit);
1398
-}
1399
-
1400
-/**
1401
- * Create Network Viewer charts
1402
- *
1403
- * Recreate the charts when new sockets are created.
1404
- *
1405
- * @param ptr a pointer for inbound or outbound vectors.
1406
- * @param update_every value to overwrite the update frequency set by the server.
1407
- */
1408
-static void ebpf_socket_create_nv_charts(netdata_vector_plot_t *ptr, int update_every)
1409
-{
1410
- // We do not have new sockets, so we do not need move forward
1411
- if (ptr->max_plot == ptr->last_plot)
1412
- return;
1413
-
1414
- ptr->last_plot = ptr->max_plot;
1415
-
1416
- if (ptr == (netdata_vector_plot_t *)&outbound_vectors) {
1417
- ebpf_socket_create_nv_chart(NETDATA_NV_OUTBOUND_BYTES,
1418
- "Outbound connections (bytes).", EBPF_COMMON_DIMENSION_BYTES,
1419
- NETDATA_NETWORK_CONNECTIONS_GROUP,
1420
- 21080,
1421
- update_every, ptr);
1422
-
1423
- ebpf_socket_create_nv_chart(NETDATA_NV_OUTBOUND_PACKETS,
1424
- "Outbound connections (packets)",
1425
- EBPF_COMMON_DIMENSION_PACKETS,
1426
- NETDATA_NETWORK_CONNECTIONS_GROUP,
1427
- 21082,
1428
- update_every, ptr);
1429
-
1430
- ebpf_socket_create_nv_retransmit(NETDATA_NV_OUTBOUND_RETRANSMIT,
1431
- "Retransmitted packets",
1432
- EBPF_COMMON_DIMENSION_CALL,
1433
- NETDATA_NETWORK_CONNECTIONS_GROUP,
1434
- 21083,
1435
- update_every, ptr);
1436
- } else {
1437
- ebpf_socket_create_nv_chart(NETDATA_NV_INBOUND_BYTES,
1438
- "Inbound connections (bytes)", EBPF_COMMON_DIMENSION_BYTES,
1439
- NETDATA_NETWORK_CONNECTIONS_GROUP,
1440
- 21084,
1441
- update_every, ptr);
1442
-
1443
- ebpf_socket_create_nv_chart(NETDATA_NV_INBOUND_PACKETS,
1444
- "Inbound connections (packets)",
1445
- EBPF_COMMON_DIMENSION_PACKETS,
1446
- NETDATA_NETWORK_CONNECTIONS_GROUP,
1447
- 21085,
1448
- update_every, ptr);
1449
- }
1450
-
1451
- ptr->flags |= NETWORK_VIEWER_CHARTS_CREATED;
1452
-}
1453
-
1323
/*****************************************************************
1324
*
1325
* READ INFORMATION FROM KERNEL RING
@@ -1517,7 +1386,7 @@ static int ebpf_is_specific_ip_inside_range(union netdata_ip_t *cmp, int family)
1386
*
1387
* @return It returns 1 when cmp is inside and 0 otherwise.
1388
*/
1520
-static int is_port_inside_range(uint16_t cmp)
1389
+static int ebpf_is_port_inside_range(uint16_t cmp)
1390
{
1391
// We do not have restrictions for ports.
1392
if (!network_viewer_opt.excluded_port && !network_viewer_opt.included_port)
@@ -1525,7 +1394,6 @@ static int is_port_inside_range(uint16_t cmp)
1394
1395
// Test if port is excluded
1396
ebpf_network_viewer_port_list_t *move = network_viewer_opt.excluded_port;
1528
- cmp = htons(cmp);
1397
while (move) {
1398
if (move->cmp_first <= cmp && cmp <= move->cmp_last)
1399
return 0;
@@ -1583,493 +1451,322 @@ int hostname_matches_pattern(char *cmp)
1451
* Compare destination addresses and destination ports to define next steps
1452
*
1453
* @param key the socket read from kernel ring
1586
- * @param family the family used to compare IPs (AF_INET and AF_INET6)
1454
+ * @param data the socket data used also used to refuse some sockets.
1455
*
1456
* @return It returns 1 if this socket is inside the ranges and 0 otherwise.
1457
*/
1590
-int is_socket_allowed(netdata_socket_idx_t *key, int family)
1458
+int ebpf_is_socket_allowed(netdata_socket_idx_t *key, netdata_socket_t *data)
1459
{
1592
- if (!is_port_inside_range(key->dport))
1593
- return 0;
1460
+ int ret = 0;
1461
+ // If family is not AF_UNSPEC and it is different of specified
1462
+ if (network_viewer_opt.family && network_viewer_opt.family != data->family)
1463
+ goto endsocketallowed;
1464
1595
- return ebpf_is_specific_ip_inside_range(&key->daddr, family);
1596
-}
1465
+ if (!ebpf_is_port_inside_range(key->dport))
1466
+ goto endsocketallowed;
1467
1598
-/**
1599
- * Compare sockets
1600
- *
1601
- * Compare destination address and destination port.
1602
- * We do not compare source port, because it is random.
1603
- * We also do not compare source address, because inbound and outbound connections are stored in separated AVL trees.
1604
- *
1605
- * @param a pointer to netdata_socket_plot
1606
- * @param b pointer to netdata_socket_plot
1607
- *
1608
- * @return It returns 0 case the values are equal, 1 case a is bigger than b and -1 case a is smaller than b.
1609
- */
1610
-static int ebpf_compare_sockets(void *a, void *b)
1611
-{
1612
- struct netdata_socket_plot *val1 = a;
1613
- struct netdata_socket_plot *val2 = b;
1614
- int cmp = 0;
1615
-
1616
- // We do not need to compare val2 family, because data inside hash table is always from the same family
1617
- if (val1->family == AF_INET) { //IPV4
1618
- if (network_viewer_opt.included_port || network_viewer_opt.excluded_port)
1619
- cmp = memcmp(&val1->index.dport, &val2->index.dport, sizeof(uint16_t));
1620
-
1621
- if (!cmp) {
1622
- cmp = memcmp(&val1->index.daddr.addr32[0], &val2->index.daddr.addr32[0], sizeof(uint32_t));
1623
- }
1624
- } else {
1625
- if (network_viewer_opt.included_port || network_viewer_opt.excluded_port)
1626
- cmp = memcmp(&val1->index.dport, &val2->index.dport, sizeof(uint16_t));
1627
-
1628
- if (!cmp) {
1629
- cmp = memcmp(&val1->index.daddr.addr32, &val2->index.daddr.addr32, 4*sizeof(uint32_t));
1630
- }
1631
- }
1468
+ ret = ebpf_is_specific_ip_inside_range(&key->daddr, data->family);
1469
1633
- return cmp;
1470
+endsocketallowed:
1471
+ return ret;
1472
}
1473
1474
/**
1637
- * Build dimension name
1638
- *
1639
- * Fill dimension name vector with values given
1640
- *
1641
- * @param dimname the output vector
1642
- * @param hostname the hostname for the socket.
1643
- * @param service_name the service used to connect.
1644
- * @param proto the protocol used in this connection
1645
- * @param family is this IPV4(AF_INET) or IPV6(AF_INET6)
1475
+ * Hash accumulator
1476
*
1647
- * @return it returns the size of the data copied on success and -1 otherwise.
1477
+ * @param values the values used to calculate the data.
1478
+ * @param family the connection family
1479
+ * @param end the values size.
1480
*/
1649
-static inline int ebpf_build_outbound_dimension_name(char *dimname, char *hostname, char *service_name,
1650
- char *proto, int family)
1481
+static void ebpf_hash_socket_accumulator(netdata_socket_t *values, int end)
1482
{
1652
- if (network_viewer_opt.included_port || network_viewer_opt.excluded_port)
1653
- return snprintf(dimname, CONFIG_MAX_NAME - 7, (family == AF_INET)?"%s:%s:%s_":"%s:%s:[%s]_",
1654
- service_name, proto, hostname);
1655
-
1656
- return snprintf(dimname, CONFIG_MAX_NAME - 7, (family == AF_INET)?"%s:%s_":"%s:[%s]_",
1657
- proto, hostname);
1658
-}
1483
+ int i;
1484
+ uint8_t protocol = values[0].protocol;
1485
+ uint64_t ct = values[0].current_timestamp;
1486
+ uint64_t ft = values[0].first_timestamp;
1487
+ uint16_t family = AF_UNSPEC;
1488
+ uint32_t external_origin = values[0].external_origin;
1489
+ for (i = 1; i < end; i++) {
1490
+ netdata_socket_t *w = &values[i];
1491
1660
-/**
1661
- * Fill inbound dimension name
1662
- *
1663
- * Mount the dimension name with the input given
1664
- *
1665
- * @param dimname the output vector
1666
- * @param service_name the service used to connect.
1667
- * @param proto the protocol used in this connection
1668
- *
1669
- * @return it returns the size of the data copied on success and -1 otherwise.
1670
- */
1671
-static inline int build_inbound_dimension_name(char *dimname, char *service_name, char *proto)
1672
-{
1673
- return snprintf(dimname, CONFIG_MAX_NAME - 7, "%s:%s_", service_name,
1674
- proto);
1675
-}
1492
+ values[0].tcp.call_tcp_sent += w->tcp.call_tcp_sent;
1493
+ values[0].tcp.call_tcp_received += w->tcp.call_tcp_received;
1494
+ values[0].tcp.tcp_bytes_received += w->tcp.tcp_bytes_received;
1495
+ values[0].tcp.tcp_bytes_sent += w->tcp.tcp_bytes_sent;
1496
+ values[0].tcp.close += w->tcp.close;
1497
+ values[0].tcp.retransmit += w->tcp.retransmit;
1498
+ values[0].tcp.ipv4_connect += w->tcp.ipv4_connect;
1499
+ values[0].tcp.ipv6_connect += w->tcp.ipv6_connect;
1500
1677
-/**
1678
- * Fill Resolved Name
1679
- *
1680
- * Fill the resolved name structure with the value given.
1681
- * The hostname is the largest value possible, if it is necessary to cut some value, it must be cut.
1682
- *
1683
- * @param ptr the output vector
1684
- * @param hostname the hostname resolved or IP.
1685
- * @param length the length for the hostname.
1686
- * @param service_name the service name associated to the connection
1687
- * @param is_outbound the is this an outbound connection
1688
- */
1689
-static inline void fill_resolved_name(netdata_socket_plot_t *ptr, char *hostname, size_t length,
1690
- char *service_name, int is_outbound)
1691
-{
1692
- if (length < NETDATA_MAX_NETWORK_COMBINED_LENGTH)
1693
- ptr->resolved_name = strdupz(hostname);
1694
- else {
1695
- length = NETDATA_MAX_NETWORK_COMBINED_LENGTH;
1696
- ptr->resolved_name = mallocz( NETDATA_MAX_NETWORK_COMBINED_LENGTH + 1);
1697
- memcpy(ptr->resolved_name, hostname, length);
1698
- ptr->resolved_name[length] = '\0';
1699
- }
1700
-
1701
- char dimname[CONFIG_MAX_NAME];
1702
- int size;
1703
- char *protocol;
1704
- if (ptr->sock.protocol == IPPROTO_UDP) {
1705
- protocol = "UDP";
1706
- } else if (ptr->sock.protocol == IPPROTO_TCP) {
1707
- protocol = "TCP";
1708
- } else {
1709
- protocol = "ALL";
1710
- }
1501
+ if (!protocol)
1502
+ protocol = w->protocol;
1503
1712
- if (is_outbound)
1713
- size = ebpf_build_outbound_dimension_name(dimname, hostname, service_name, protocol, ptr->family);
1714
- else
1715
- size = build_inbound_dimension_name(dimname,service_name, protocol);
1504
+ if (family == AF_UNSPEC)
1505
+ family = w->family;
1506
1717
- if (size > 0) {
1718
- strcpy(&dimname[size], "sent");
1719
- dimname[size + 4] = '\0';
1720
- ptr->dimension_sent = strdupz(dimname);
1507
+ if (w->current_timestamp > ct)
1508
+ ct = w->current_timestamp;
1509
1722
- strcpy(&dimname[size], "recv");
1723
- ptr->dimension_recv = strdupz(dimname);
1510
+ if (!ft)
1511
+ ft = w->first_timestamp;
1512
1725
- dimname[size - 1] = '\0';
1726
- ptr->dimension_retransmit = strdupz(dimname);
1513
+ if (w->external_origin)
1514
+ external_origin = NETDATA_EBPF_SRC_IP_ORIGIN_EXTERNAL;
1515
}
1516
+
1517
+ values[0].protocol = (!protocol)?IPPROTO_TCP:protocol;
1518
+ values[0].current_timestamp = ct;
1519
+ values[0].first_timestamp = ft;
1520
+ values[0].external_origin = external_origin;
1521
}
1522
1523
/**
1731
- * Mount dimension names
1732
- *
1733
- * Fill the vector names after to resolve the addresses
1524
+ * Translate socket
1525
*
1735
- * @param ptr a pointer to the structure where the values are stored.
1736
- * @param is_outbound is a outbound ptr value?
1526
+ * Convert socket address to string
1527
*
1738
- * @return It returns 1 if the name is valid and 0 otherwise.
1528
+ * @param dst structure where we will store
1529
+ * @param key the socket address
1530
*/
1740
-int fill_names(netdata_socket_plot_t *ptr, int is_outbound)
1531
+static void ebpf_socket_translate(netdata_socket_plus_t *dst, netdata_socket_idx_t *key)
1532
{
1742
- char hostname[NI_MAXHOST], service_name[NI_MAXSERV];
1743
- if (ptr->resolved)
1744
- return 1;
1745
-
1533
+ uint32_t resolve = network_viewer_opt.service_resolution_enabled;
1534
+ char service[NI_MAXSERV];
1535
int ret;
1747
- static int resolve_name = -1;
1748
- static int resolve_service = -1;
1749
- if (resolve_name == -1)
1750
- resolve_name = network_viewer_opt.hostname_resolution_enabled;
1751
-
1752
- if (resolve_service == -1)
1753
- resolve_service = network_viewer_opt.service_resolution_enabled;
1754
-
1755
- netdata_socket_idx_t *idx = &ptr->index;
1756
-
1757
- char *errname = { "Not resolved" };
1758
- // Resolve Name
1759
- if (ptr->family == AF_INET) { //IPV4
1760
- struct sockaddr_in myaddr;
1761
- memset(&myaddr, 0 , sizeof(myaddr));
1762
-
1763
- myaddr.sin_family = ptr->family;
1764
- if (is_outbound) {
1765
- myaddr.sin_port = idx->dport;
1766
- myaddr.sin_addr.s_addr = idx->daddr.addr32[0];
1767
- } else {
1768
- myaddr.sin_port = idx->sport;
1769
- myaddr.sin_addr.s_addr = idx->saddr.addr32[0];
1770
- }
1771
-
1772
- ret = (!resolve_name)?-1:getnameinfo((struct sockaddr *)&myaddr, sizeof(myaddr), hostname,
1773
- sizeof(hostname), service_name, sizeof(service_name), NI_NAMEREQD);
1774
-
1775
- if (!ret && !resolve_service) {
1776
- snprintf(service_name, sizeof(service_name), "%u", ntohs(myaddr.sin_port));
1536
+ if (dst->data.family == AF_INET) {
1537
+ struct sockaddr_in ipv4_addr = { };
1538
+ ipv4_addr.sin_port = 0;
1539
+ ipv4_addr.sin_addr.s_addr = key->saddr.addr32[0];
1540
+ ipv4_addr.sin_family = AF_INET;
1541
+ if (resolve) {
1542
+ // NI_NAMEREQD : It is too slow
1543
+ ret = getnameinfo((struct sockaddr *) &ipv4_addr, sizeof(ipv4_addr), dst->socket_string.src_ip,
1544
+ INET6_ADDRSTRLEN, service, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV);
1545
+ if (ret) {
1546
+ collector_error("Cannot resolve name: %s", gai_strerror(ret));
1547
+ resolve = 0;
1548
+ } else {
1549
+ ipv4_addr.sin_addr.s_addr = key->daddr.addr32[0];
1550
+
1551
+ ipv4_addr.sin_port = key->dport;
1552
+ ret = getnameinfo((struct sockaddr *) &ipv4_addr, sizeof(ipv4_addr), dst->socket_string.dst_ip,
1553
+ INET6_ADDRSTRLEN, dst->socket_string.dst_port, NI_MAXSERV,
1554
+ NI_NUMERICHOST);
1555
+ if (ret) {
1556
+ collector_error("Cannot resolve name: %s", gai_strerror(ret));
1557
+ resolve = 0;
1558
+ }
1559
+ }
1560
}
1561
1779
- if (ret) {
1780
- // I cannot resolve the name, I will use the IP
1781
- if (!inet_ntop(AF_INET, &myaddr.sin_addr.s_addr, hostname, NI_MAXHOST)) {
1782
- strncpy(hostname, errname, 13);
1783
- }
1562
+ // When resolution fail, we should use addresses
1563
+ if (!resolve) {
1564
+ ipv4_addr.sin_addr.s_addr = key->saddr.addr32[0];
1565
1785
- snprintf(service_name, sizeof(service_name), "%u", ntohs(myaddr.sin_port));
1786
- ret = 1;
1787
- }
1788
- } else { // IPV6
1789
- struct sockaddr_in6 myaddr6;
1790
- memset(&myaddr6, 0 , sizeof(myaddr6));
1791
-
1792
- myaddr6.sin6_family = AF_INET6;
1793
- if (is_outbound) {
1794
- myaddr6.sin6_port = idx->dport;
1795
- memcpy(myaddr6.sin6_addr.s6_addr, idx->daddr.addr8, sizeof(union netdata_ip_t));
1796
- } else {
1797
- myaddr6.sin6_port = idx->sport;
1798
- memcpy(myaddr6.sin6_addr.s6_addr, idx->saddr.addr8, sizeof(union netdata_ip_t));
1799
- }
1566
+ if(!inet_ntop(AF_INET, &ipv4_addr.sin_addr, dst->socket_string.src_ip, INET6_ADDRSTRLEN))
1567
+ netdata_log_info("Cannot convert IP %u .", ipv4_addr.sin_addr.s_addr);
1568
1801
- ret = (!resolve_name)?-1:getnameinfo((struct sockaddr *)&myaddr6, sizeof(myaddr6), hostname,
1802
- sizeof(hostname), service_name, sizeof(service_name), NI_NAMEREQD);
1569
+ ipv4_addr.sin_addr.s_addr = key->daddr.addr32[0];
1570
1804
- if (!ret && !resolve_service) {
1805
- snprintf(service_name, sizeof(service_name), "%u", ntohs(myaddr6.sin6_port));
1571
+ if(!inet_ntop(AF_INET, &ipv4_addr.sin_addr, dst->socket_string.dst_ip, INET6_ADDRSTRLEN))
1572
+ netdata_log_info("Cannot convert IP %u .", ipv4_addr.sin_addr.s_addr);
1573
+ snprintfz(dst->socket_string.dst_port, NI_MAXSERV, "%u", ntohs(key->dport));
1574
}
1807
-
1808
- if (ret) {
1809
- // I cannot resolve the name, I will use the IP
1810
- if (!inet_ntop(AF_INET6, myaddr6.sin6_addr.s6_addr, hostname, NI_MAXHOST)) {
1811
- strncpy(hostname, errname, 13);
1575
+ } else {
1576
+ struct sockaddr_in6 ipv6_addr = { };
1577
+ memcpy(&ipv6_addr.sin6_addr, key->saddr.addr8, sizeof(key->saddr.addr8));
1578
+ ipv6_addr.sin6_family = AF_INET6;
1579
+ if (resolve) {
1580
+ ret = getnameinfo((struct sockaddr *) &ipv6_addr, sizeof(ipv6_addr), dst->socket_string.src_ip,
1581
+ INET6_ADDRSTRLEN, service, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV);
1582
+ if (ret) {
1583
+ collector_error("Cannot resolve name: %s", gai_strerror(ret));
1584
+ resolve = 0;
1585
+ } else {
1586
+ memcpy(&ipv6_addr.sin6_addr, key->daddr.addr8, sizeof(key->daddr.addr8));
1587
+ ret = getnameinfo((struct sockaddr *) &ipv6_addr, sizeof(ipv6_addr), dst->socket_string.dst_ip,
1588
+ INET6_ADDRSTRLEN, dst->socket_string.dst_port, NI_MAXSERV,
1589
+ NI_NUMERICHOST);
1590
+ if (ret) {
1591
+ collector_error("Cannot resolve name: %s", gai_strerror(ret));
1592
+ resolve = 0;
1593
+ }
1594
}
1595
+ }
1596
1814
- snprintf(service_name, sizeof(service_name), "%u", ntohs(myaddr6.sin6_port));
1597
+ if (!resolve) {
1598
+ memcpy(&ipv6_addr.sin6_addr, key->saddr.addr8, sizeof(key->saddr.addr8));
1599
+ if(!inet_ntop(AF_INET6, &ipv6_addr.sin6_addr, dst->socket_string.src_ip, INET6_ADDRSTRLEN))
1600
+ netdata_log_info("Cannot convert IPv6 Address.");
1601
1816
- ret = 1;
1602
+ memcpy(&ipv6_addr.sin6_addr, key->daddr.addr8, sizeof(key->daddr.addr8));
1603
+ if(!inet_ntop(AF_INET6, &ipv6_addr.sin6_addr, dst->socket_string.dst_ip, INET6_ADDRSTRLEN))
1604
+ netdata_log_info("Cannot convert IPv6 Address.");
1605
+ snprintfz(dst->socket_string.dst_port, NI_MAXSERV, "%u", ntohs(key->dport));
1606
}
1607
}
1608
+ dst->pid = key->pid;
1609
1820
- fill_resolved_name(ptr, hostname,
1821
- strlen(hostname) + strlen(service_name)+ NETDATA_DOTS_PROTOCOL_COMBINED_LENGTH,
1822
- service_name, is_outbound);
1823
-
1824
- if (resolve_name && !ret)
1825
- ret = hostname_matches_pattern(hostname);
1826
-
1827
- ptr->resolved++;
1828
-
1829
- return ret;
1830
-}
1831
-
1832
-/**
1833
- * Fill last Network Viewer Dimension
1834
- *
1835
- * Fill the unique dimension that is always plotted.
1836
- *
1837
- * @param ptr the pointer for the last dimension
1838
- * @param is_outbound is this an inbound structure?
1839
- */
1840
-static void fill_last_nv_dimension(netdata_socket_plot_t *ptr, int is_outbound)
1841
-{
1842
- char hostname[NI_MAXHOST], service_name[NI_MAXSERV];
1843
- char *other = { "other" };
1844
- // We are also copying the NULL bytes to avoid warnings in new compilers
1845
- strncpy(hostname, other, 6);
1846
- strncpy(service_name, other, 6);
1847
-
1848
- ptr->family = AF_INET;
1849
- ptr->sock.protocol = 255;
1850
- ptr->flags = (!is_outbound)?NETDATA_INBOUND_DIRECTION:NETDATA_OUTBOUND_DIRECTION;
1851
-
1852
- fill_resolved_name(ptr, hostname, 10 + NETDATA_DOTS_PROTOCOL_COMBINED_LENGTH, service_name, is_outbound);
1853
-
1854
-#ifdef NETDATA_INTERNAL_CHECKS
1855
- netdata_log_info("Last %s dimension added: ID = %u, IP = OTHER, NAME = %s, DIM1 = %s, DIM2 = %s, DIM3 = %s",
1856
- (is_outbound)?"outbound":"inbound", network_viewer_opt.max_dim - 1, ptr->resolved_name,
1857
- ptr->dimension_recv, ptr->dimension_sent, ptr->dimension_retransmit);
1610
+ if (!strcmp(dst->socket_string.dst_port, "0"))
1611
+ snprintfz(dst->socket_string.dst_port, NI_MAXSERV, "%u", ntohs(key->dport));
1612
+#ifdef NETDATA_DEV_MODE
1613
+ collector_info("New socket: { ORIGIN IP: %s, ORIGIN : %u, DST IP:%s, DST PORT: %s, PID: %u, PROTO: %d, FAMILY: %d}",
1614
+ dst->socket_string.src_ip,
1615
+ dst->data.external_origin,
1616
+ dst->socket_string.dst_ip,
1617
+ dst->socket_string.dst_port,
1618
+ dst->pid,
1619
+ dst->data.protocol,
1620
+ dst->data.family
1621
+ );
1622
#endif
1623
}
1624
1625
/**
1862
- * Update Socket Data
1626
+ * Update array vectors
1627
*
1864
- * Update the socket information with last collected data
1628
+ * Read data from hash table and update vectors.
1629
*
1866
- * @param sock
1867
- * @param lvalues
1630
+ * @param em the structure with configuration
1631
*/
1869
-static inline void update_socket_data(netdata_socket_t *sock, netdata_socket_t *lvalues)
1632
+static void ebpf_update_array_vectors(ebpf_module_t *em)
1633
{
1871
- sock->recv_packets = lvalues->recv_packets;
1872
- sock->sent_packets = lvalues->sent_packets;
1873
- sock->recv_bytes = lvalues->recv_bytes;
1874
- sock->sent_bytes = lvalues->sent_bytes;
1875
- sock->retransmit = lvalues->retransmit;
1876
- sock->ct = lvalues->ct;
1877
-}
1634
+ netdata_thread_disable_cancelability();
1635
+ netdata_socket_idx_t key = {};
1636
+ netdata_socket_idx_t next_key = {};
1637
1879
-/**
1880
- * Store socket inside avl
1881
- *
1882
- * Store the socket values inside the avl tree.
1883
- *
1884
- * @param out the structure with information used to plot charts.
1885
- * @param lvalues Values read from socket ring.
1886
- * @param lindex the index information, the real socket.
1887
- * @param family the family associated to the socket
1888
- * @param flags the connection flags
1889
- */
1890
-static void store_socket_inside_avl(netdata_vector_plot_t *out, netdata_socket_t *lvalues,
1891
- netdata_socket_idx_t *lindex, int family, uint32_t flags)
1892
-{
1893
- netdata_socket_plot_t test, *ret ;
1638
+ int maps_per_core = em->maps_per_core;
1639
+ int fd = em->maps[NETDATA_SOCKET_OPEN_SOCKET].map_fd;
1640
1895
- memcpy(&test.index, lindex, sizeof(netdata_socket_idx_t));
1896
- test.flags = flags;
1641
+ netdata_socket_t *values = socket_values;
1642
+ size_t length = sizeof(netdata_socket_t);
1643
+ int test, end;
1644
+ if (maps_per_core) {
1645
+ length *= ebpf_nprocs;
1646
+ end = ebpf_nprocs;
1647
+ } else
1648
+ end = 1;
1649
1898
- ret = (netdata_socket_plot_t *) avl_search_lock(&out->tree, (avl_t *)&test);
1899
- if (ret) {
1900
- if (lvalues->ct != ret->plot.last_time) {
1901
- update_socket_data(&ret->sock, lvalues);
1650
+ // We need to reset the values when we are working on kernel 4.15 or newer, because kernel does not create
1651
+ // values for specific processor unless it is used to store data. As result of this behavior one the next socket
1652
+ // can have values from the previous one.
1653
+ memset(values, 0, length);
1654
+ time_t update_time = time(NULL);
1655
+ while (bpf_map_get_next_key(fd, &key, &next_key) == 0) {
1656
+ test = bpf_map_lookup_elem(fd, &key, values);
1657
+ if (test < 0) {
1658
+ goto end_socket_loop;
1659
}
1903
- } else {
1904
- uint32_t curr = out->next;
1905
- uint32_t last = out->last;
1906
-
1907
- netdata_socket_plot_t *w = &out->plot[curr];
1908
-
1909
- int resolved;
1910
- if (curr == last) {
1911
- if (lvalues->ct != w->plot.last_time) {
1912
- update_socket_data(&w->sock, lvalues);
1913
- }
1914
- return;
1915
- } else {
1916
- memcpy(&w->sock, lvalues, sizeof(netdata_socket_t));
1917
- memcpy(&w->index, lindex, sizeof(netdata_socket_idx_t));
1918
- w->family = family;
1660
1920
- resolved = fill_names(w, out != (netdata_vector_plot_t *)&inbound_vectors);
1661
+ if (key.pid > (uint32_t)pid_max) {
1662
+ goto end_socket_loop;
1663
}
1664
1923
- if (!resolved) {
1924
- freez(w->resolved_name);
1925
- freez(w->dimension_sent);
1926
- freez(w->dimension_recv);
1927
- freez(w->dimension_retransmit);
1928
-
1929
- memset(w, 0, sizeof(netdata_socket_plot_t));
1665
+ ebpf_hash_socket_accumulator(values, end);
1666
+ ebpf_socket_fill_publish_apps(key.pid, values);
1667
1931
- return;
1668
+ // We update UDP to show info with charts, but we do not show them with functions
1669
+ /*
1670
+ if (key.dport == NETDATA_EBPF_UDP_PORT && values[0].protocol == IPPROTO_UDP) {
1671
+ bpf_map_delete_elem(fd, &key);
1672
+ goto end_socket_loop;
1673
}
1674
+ */
1675
1934
- w->flags = flags;
1935
- netdata_socket_plot_t *check ;
1936
- check = (netdata_socket_plot_t *) avl_insert_lock(&out->tree, (avl_t *)w);
1937
- if (check != w)
1938
- netdata_log_error("Internal error, cannot insert the AVL tree.");
1939
-
1940
-#ifdef NETDATA_INTERNAL_CHECKS
1941
- char iptext[INET6_ADDRSTRLEN];
1942
- if (inet_ntop(family, &w->index.daddr.addr8, iptext, sizeof(iptext)))
1943
- netdata_log_info("New %s dimension added: ID = %u, IP = %s, NAME = %s, DIM1 = %s, DIM2 = %s, DIM3 = %s",
1944
- (out == &inbound_vectors)?"inbound":"outbound", curr, iptext, w->resolved_name,
1945
- w->dimension_recv, w->dimension_sent, w->dimension_retransmit);
1946
-#endif
1947
- curr++;
1948
- if (curr > last)
1949
- curr = last;
1950
- out->next = curr;
1951
- }
1952
-}
1953
-
1954
-/**
1955
- * Compare Vector to store
1956
- *
1957
- * Compare input values with local address to select table to store.
1958
- *
1959
- * @param direction store inbound and outbound direction.
1960
- * @param cmp index read from hash table.
1961
- * @param proto the protocol read.
1962
- *
1963
- * @return It returns the structure with address to compare.
1964
- */
1965
-netdata_vector_plot_t * select_vector_to_store(uint32_t *direction, netdata_socket_idx_t *cmp, uint8_t proto)
1966
-{
1967
- if (!listen_ports) {
1968
- *direction = NETDATA_OUTBOUND_DIRECTION;
1969
- return &outbound_vectors;
1970
- }
1971
-
1972
- ebpf_network_viewer_port_list_t *move_ports = listen_ports;
1973
- while (move_ports) {
1974
- if (move_ports->protocol == proto && move_ports->first == cmp->sport) {
1975
- *direction = NETDATA_INBOUND_DIRECTION;
1976
- return &inbound_vectors;
1676
+ // Discard non-bind sockets
1677
+ if (!key.daddr.addr64[0] && !key.daddr.addr64[1] && !key.saddr.addr64[0] && !key.saddr.addr64[1]) {
1678
+ bpf_map_delete_elem(fd, &key);
1679
+ goto end_socket_loop;
1680
}
1681
1979
- move_ports = move_ports->next;
1980
- }
1682
+ // When socket is not allowed, we do not append it to table, but we are still keeping it to accumulate data.
1683
+ if (!ebpf_is_socket_allowed(&key, values)) {
1684
+ goto end_socket_loop;
1685
+ }
1686
1982
- *direction = NETDATA_OUTBOUND_DIRECTION;
1983
- return &outbound_vectors;
1984
-}
1687
+ // Get PID structure
1688
+ rw_spinlock_write_lock(&ebpf_judy_pid.index.rw_spinlock);
1689
+ PPvoid_t judy_array = &ebpf_judy_pid.index.JudyLArray;
1690
+ netdata_ebpf_judy_pid_stats_t *pid_ptr = ebpf_get_pid_from_judy_unsafe(judy_array, key.pid);
1691
+ if (!pid_ptr) {
1692
+ goto end_socket_loop;
1693
+ }
1694
1986
-/**
1987
- * Hash accumulator
1988
- *
1989
- * @param values the values used to calculate the data.
1990
- * @param key the key to store data.
1991
- * @param family the connection family
1992
- * @param end the values size.
1993
- */
1994
-static void hash_accumulator(netdata_socket_t *values, netdata_socket_idx_t *key, int family, int end)
1995
-{
1996
- if (!network_viewer_opt.enabled || !is_socket_allowed(key, family))
1997
- return;
1695
+ // Get Socket structure
1696
+ rw_spinlock_write_lock(&pid_ptr->socket_stats.rw_spinlock);
1697
+ netdata_socket_plus_t **socket_pptr = (netdata_socket_plus_t **)ebpf_judy_insert_unsafe(
1698
+ &pid_ptr->socket_stats.JudyLArray, values[0].first_timestamp);
1699
+ netdata_socket_plus_t *socket_ptr = *socket_pptr;
1700
+ bool translate = false;
1701
+ if (likely(*socket_pptr == NULL)) {
1702
+ *socket_pptr = aral_mallocz(aral_socket_table);
1703
1999
- uint64_t bsent = 0, brecv = 0, psent = 0, precv = 0;
2000
- uint16_t retransmit = 0;
2001
- int i;
2002
- uint8_t protocol = values[0].protocol;
2003
- uint64_t ct = values[0].ct;
2004
- for (i = 1; i < end; i++) {
2005
- netdata_socket_t *w = &values[i];
1704
+ socket_ptr = *socket_pptr;
1705
2007
- precv += w->recv_packets;
2008
- psent += w->sent_packets;
2009
- brecv += w->recv_bytes;
2010
- bsent += w->sent_bytes;
2011
- retransmit += w->retransmit;
1706
+ translate = true;
1707
+ }
1708
+ uint64_t prev_period = socket_ptr->data.current_timestamp;
1709
+ memcpy(&socket_ptr->data, &values[0], sizeof(netdata_socket_t));
1710
+ if (translate)
1711
+ ebpf_socket_translate(socket_ptr, &key);
1712
+ else { // Check socket was updated
1713
+ if (prev_period) {
1714
+ if (values[0].current_timestamp > prev_period) // Socket updated
1715
+ socket_ptr->last_update = update_time;
1716
+ else if ((update_time - socket_ptr->last_update) > em->update_every) {
1717
+ // Socket was not updated since last read
1718
+ JudyLDel(&pid_ptr->socket_stats.JudyLArray, values[0].first_timestamp, PJE0);
1719
+ aral_freez(aral_socket_table, socket_ptr);
1720
+ }
1721
+ } else // First time
1722
+ socket_ptr->last_update = update_time;
1723
+ }
1724
2013
- if (!protocol)
2014
- protocol = w->protocol;
1725
+ rw_spinlock_write_unlock(&pid_ptr->socket_stats.rw_spinlock);
1726
+ rw_spinlock_write_unlock(&ebpf_judy_pid.index.rw_spinlock);
1727
2016
- if (w->ct != ct)
2017
- ct = w->ct;
1728
+end_socket_loop:
1729
+ memset(values, 0, length);
1730
+ memcpy(&key, &next_key, sizeof(key));
1731
}
2019
-
2020
- values[0].recv_packets += precv;
2021
- values[0].sent_packets += psent;
2022
- values[0].recv_bytes += brecv;
2023
- values[0].sent_bytes += bsent;
2024
- values[0].retransmit += retransmit;
2025
- values[0].protocol = (!protocol)?IPPROTO_TCP:protocol;
2026
- values[0].ct = ct;
2027
-
2028
- uint32_t dir;
2029
- netdata_vector_plot_t *table = select_vector_to_store(&dir, key, protocol);
2030
- store_socket_inside_avl(table, &values[0], key, family, dir);
1732
+ netdata_thread_enable_cancelability();
1733
}
1734
1735
/**
2034
- * Read socket hash table
1736
+ * Socket thread
1737
*
2036
- * Read data from hash tables created on kernel ring.
1738
+ * Thread used to generate socket charts.
1739
*
2038
- * @param fd the hash table with data.
2039
- * @param family the family associated to the hash table
2040
- * @param maps_per_core do I need to read all cores?
1740
+ * @param ptr a pointer to `struct ebpf_module`
1741
*
2042
- * @return it returns 0 on success and -1 otherwise.
1742
+ * @return It always return NULL
1743
*/
2044
-static void ebpf_read_socket_hash_table(int fd, int family, int maps_per_core)
1744
+void *ebpf_read_socket_thread(void *ptr)
1745
{
2046
- netdata_socket_idx_t key = {};
2047
- netdata_socket_idx_t next_key = {};
1746
+ heartbeat_t hb;
1747
+ heartbeat_init(&hb);
1748
2049
- netdata_socket_t *values = socket_values;
2050
- size_t length = sizeof(netdata_socket_t);
2051
- int test, end;
2052
- if (maps_per_core) {
2053
- length *= ebpf_nprocs;
2054
- end = ebpf_nprocs;
2055
- } else
2056
- end = 1;
1749
+ ebpf_module_t *em = (ebpf_module_t *)ptr;
1750
2058
- while (bpf_map_get_next_key(fd, &key, &next_key) == 0) {
2059
- // We need to reset the values when we are working on kernel 4.15 or newer, because kernel does not create
2060
- // values for specific processor unless it is used to store data. As result of this behavior one the next socket
2061
- // can have values from the previous one.
2062
- memset(values, 0, length);
2063
- test = bpf_map_lookup_elem(fd, &key, values);
2064
- if (test < 0) {
2065
- key = next_key;
1751
+ ebpf_update_array_vectors(em);
1752
+
1753
+ int update_every = em->update_every;
1754
+ int counter = update_every - 1;
1755
+
1756
+ uint32_t running_time = 0;
1757
+ uint32_t lifetime = em->lifetime;
1758
+ usec_t period = update_every * USEC_PER_SEC;
1759
+ while (!ebpf_exit_plugin && running_time < lifetime) {
1760
+ (void)heartbeat_next(&hb, period);
1761
+ if (ebpf_exit_plugin || ++counter != update_every)
1762
continue;
2067
- }
1763
2069
- hash_accumulator(values, &key, family, end);
1764
+ ebpf_update_array_vectors(em);
1765
2071
- key = next_key;
1766
+ counter = 0;
1767
}
1768
+
1769
+ return NULL;
1770
}
1771
1772
/**
@@ -2164,44 +1861,6 @@ static void read_listen_table()
1861
}
1862
}
1863
2167
-/**
2168
- * Socket read hash
2169
- *
2170
- * This is the thread callback.
2171
- * This thread is necessary, because we cannot freeze the whole plugin to read the data on very busy socket.
2172
- *
2173
- * @param ptr It is a NULL value for this thread.
2174
- *
2175
- * @return It always returns NULL.
2176
- */
2177
-void *ebpf_socket_read_hash(void *ptr)
2178
-{
2179
- netdata_thread_cleanup_push(ebpf_socket_cleanup, ptr);
2180
- ebpf_module_t *em = (ebpf_module_t *)ptr;
2181
-
2182
- heartbeat_t hb;
2183
- heartbeat_init(&hb);
2184
- int fd_ipv4 = socket_maps[NETDATA_SOCKET_TABLE_IPV4].map_fd;
2185
- int fd_ipv6 = socket_maps[NETDATA_SOCKET_TABLE_IPV6].map_fd;
2186
- int maps_per_core = em->maps_per_core;
2187
- // This thread is cancelled from another thread
2188
- uint32_t running_time;
2189
- uint32_t lifetime = em->lifetime;
2190
- for (running_time = 0;!ebpf_exit_plugin && running_time < lifetime; running_time++) {
2191
- (void)heartbeat_next(&hb, USEC_PER_SEC);
2192
- if (ebpf_exit_plugin)
2193
- break;
2194
-
2195
- pthread_mutex_lock(&nv_mutex);
2196
- ebpf_read_socket_hash_table(fd_ipv4, AF_INET, maps_per_core);
2197
- ebpf_read_socket_hash_table(fd_ipv6, AF_INET6, maps_per_core);
2198
- pthread_mutex_unlock(&nv_mutex);
2199
- }
2200
-
2201
- netdata_thread_cleanup_pop(1);
2202
- return NULL;
2203
-}
2204
-
1864
/**
1865
* Read the hash table and store data to allocated vectors.
1866
*
@@ -2251,9 +1910,9 @@ static void ebpf_socket_read_hash_global_tables(netdata_idx_t *stats, int maps_p
1910
* Fill publish apps when necessary.
1911
*
1912
* @param current_pid the PID that I am updating
2254
- * @param eb the structure with data read from memory.
1913
+ * @param ns the structure with data read from memory.
1914
*/
2256
-void ebpf_socket_fill_publish_apps(uint32_t current_pid, ebpf_bandwidth_t *eb)
1915
+void ebpf_socket_fill_publish_apps(uint32_t current_pid, netdata_socket_t *ns)
1916
{
1917
ebpf_socket_publish_apps_t *curr = socket_bandwidth_curr[current_pid];
1918
if (!curr) {
@@ -2261,98 +1920,33 @@ void ebpf_socket_fill_publish_apps(uint32_t current_pid, ebpf_bandwidth_t *eb)
1920
socket_bandwidth_curr[current_pid] = curr;
1921
}
1922
2264
- curr->bytes_sent = eb->bytes_sent;
2265
- curr->bytes_received = eb->bytes_received;
2266
- curr->call_tcp_sent = eb->call_tcp_sent;
2267
- curr->call_tcp_received = eb->call_tcp_received;
2268
- curr->retransmit = eb->retransmit;
2269
- curr->call_udp_sent = eb->call_udp_sent;
2270
- curr->call_udp_received = eb->call_udp_received;
2271
- curr->call_close = eb->close;
2272
- curr->call_tcp_v4_connection = eb->tcp_v4_connection;
2273
- curr->call_tcp_v6_connection = eb->tcp_v6_connection;
2274
-}
2275
-
2276
-/**
2277
- * Bandwidth accumulator.
2278
- *
2279
- * @param out the vector with the values to sum
2280
- */
2281
-void ebpf_socket_bandwidth_accumulator(ebpf_bandwidth_t *out, int maps_per_core)
2282
-{
2283
- int i, end = (maps_per_core) ? ebpf_nprocs : 1;
2284
- ebpf_bandwidth_t *total = &out[0];
2285
- for (i = 1; i < end; i++) {
2286
- ebpf_bandwidth_t *move = &out[i];
2287
- total->bytes_sent += move->bytes_sent;
2288
- total->bytes_received += move->bytes_received;
2289
- total->call_tcp_sent += move->call_tcp_sent;
2290
- total->call_tcp_received += move->call_tcp_received;
2291
- total->retransmit += move->retransmit;
2292
- total->call_udp_sent += move->call_udp_sent;
2293
- total->call_udp_received += move->call_udp_received;
2294
- total->close += move->close;
2295
- total->tcp_v4_connection += move->tcp_v4_connection;
2296
- total->tcp_v6_connection += move->tcp_v6_connection;
2297
- }
2298
-}
2299
-
2300
-/**
2301
- * Update the apps data reading information from the hash table
2302
- *
2303
- * @param maps_per_core do I need to read all cores?
2304
- */
2305
-static void ebpf_socket_update_apps_data(int maps_per_core)
2306
-{
2307
- int fd = socket_maps[NETDATA_SOCKET_TABLE_BANDWIDTH].map_fd;
2308
- ebpf_bandwidth_t *eb = bandwidth_vector;
2309
- uint32_t key;
2310
- struct ebpf_pid_stat *pids = ebpf_root_of_pids;
2311
- size_t length = sizeof(ebpf_bandwidth_t);
2312
- if (maps_per_core)
2313
- length *= ebpf_nprocs;
2314
- while (pids) {
2315
- key = pids->pid;
2316
-
2317
- if (bpf_map_lookup_elem(fd, &key, eb)) {
2318
- pids = pids->next;
2319
- continue;
2320
- }
2321
-
2322
- ebpf_socket_bandwidth_accumulator(eb, maps_per_core);
2323
-
2324
- ebpf_socket_fill_publish_apps(key, eb);
2325
-
2326
- memset(eb, 0, length);
1923
+ curr->bytes_sent += ns->tcp.tcp_bytes_sent;
1924
+ curr->bytes_received += ns->tcp.tcp_bytes_received;
1925
+ curr->call_tcp_sent += ns->tcp.call_tcp_sent;
1926
+ curr->call_tcp_received += ns->tcp.call_tcp_received;
1927
+ curr->retransmit += ns->tcp.retransmit;
1928
+ curr->call_close += ns->tcp.close;
1929
+ curr->call_tcp_v4_connection += ns->tcp.ipv4_connect;
1930
+ curr->call_tcp_v6_connection += ns->tcp.ipv6_connect;
1931
2328
- pids = pids->next;
2329
- }
1932
+ curr->call_udp_sent += ns->udp.call_udp_sent;
1933
+ curr->call_udp_received += ns->udp.call_udp_received;
1934
}
1935
1936
/**
1937
* Update cgroup
1938
*
1939
* Update cgroup data based in PIDs.
2336
- *
2337
- * @param maps_per_core do I need to read all cores?
1940
*/
2339
-static void ebpf_update_socket_cgroup(int maps_per_core)
1941
+static void ebpf_update_socket_cgroup()
1942
{
1943
ebpf_cgroup_target_t *ect ;
1944
2343
- ebpf_bandwidth_t *eb = bandwidth_vector;
2344
- int fd = socket_maps[NETDATA_SOCKET_TABLE_BANDWIDTH].map_fd;
2345
-
2346
- size_t length = sizeof(ebpf_bandwidth_t);
2347
- if (maps_per_core)
2348
- length *= ebpf_nprocs;
2349
-
1945
pthread_mutex_lock(&mutex_cgroup_shm);
1946
for (ect = ebpf_cgroup_pids; ect; ect = ect->next) {
1947
struct pid_on_target2 *pids;
1948
for (pids = ect->pids; pids; pids = pids->next) {
1949
int pid = pids->pid;
2355
- ebpf_bandwidth_t *out = &pids->socket;
1950
ebpf_socket_publish_apps_t *publish = &ect->publish_socket;
1951
if (likely(socket_bandwidth_curr) && socket_bandwidth_curr[pid]) {
1952
ebpf_socket_publish_apps_t *in = socket_bandwidth_curr[pid];
@@ -2367,25 +1961,6 @@ static void ebpf_update_socket_cgroup(int maps_per_core)
1961
publish->call_close = in->call_close;
1962
publish->call_tcp_v4_connection = in->call_tcp_v4_connection;
1963
publish->call_tcp_v6_connection = in->call_tcp_v6_connection;
2370
- } else {
2371
- if (!bpf_map_lookup_elem(fd, &pid, eb)) {
2372
- ebpf_socket_bandwidth_accumulator(eb, maps_per_core);
2373
-
2374
- memcpy(out, eb, sizeof(ebpf_bandwidth_t));
2375
-
2376
- publish->bytes_sent = out->bytes_sent;
2377
- publish->bytes_received = out->bytes_received;
2378
- publish->call_tcp_sent = out->call_tcp_sent;
2379
- publish->call_tcp_received = out->call_tcp_received;
2380
- publish->retransmit = out->retransmit;
2381
- publish->call_udp_sent = out->call_udp_sent;
2382
- publish->call_udp_received = out->call_udp_received;
2383
- publish->call_close = out->close;
2384
- publish->call_tcp_v4_connection = out->tcp_v4_connection;
2385
- publish->call_tcp_v6_connection = out->tcp_v6_connection;
2386
-
2387
- memset(eb, 0, length);
2388
- }
1964
}
1965
}
1966
}
@@ -2406,18 +1981,18 @@ static void ebpf_socket_sum_cgroup_pids(ebpf_socket_publish_apps_t *socket, stru
1981
memset(&accumulator, 0, sizeof(accumulator));
1982
1983
while (pids) {
2409
- ebpf_bandwidth_t *w = &pids->socket;
2410
-
2411
- accumulator.bytes_received += w->bytes_received;
2412
- accumulator.bytes_sent += w->bytes_sent;
2413
- accumulator.call_tcp_received += w->call_tcp_received;
2414
- accumulator.call_tcp_sent += w->call_tcp_sent;
2415
- accumulator.retransmit += w->retransmit;
2416
- accumulator.call_udp_received += w->call_udp_received;
2417
- accumulator.call_udp_sent += w->call_udp_sent;
2418
- accumulator.call_close += w->close;
2419
- accumulator.call_tcp_v4_connection += w->tcp_v4_connection;
2420
- accumulator.call_tcp_v6_connection += w->tcp_v6_connection;
1984
+ netdata_socket_t *w = &pids->socket;
1985
+
1986
+ accumulator.bytes_received += w->tcp.tcp_bytes_received;
1987
+ accumulator.bytes_sent += w->tcp.tcp_bytes_sent;
1988
+ accumulator.call_tcp_received += w->tcp.call_tcp_received;
1989
+ accumulator.call_tcp_sent += w->tcp.call_tcp_sent;
1990
+ accumulator.retransmit += w->tcp.retransmit;
1991
+ accumulator.call_close += w->tcp.close;
1992
+ accumulator.call_tcp_v4_connection += w->tcp.ipv4_connect;
1993
+ accumulator.call_tcp_v6_connection += w->tcp.ipv6_connect;
1994
+ accumulator.call_udp_received += w->udp.call_udp_received;
1995
+ accumulator.call_udp_sent += w->udp.call_udp_sent;
1996
1997
pids = pids->next;
1998
}
@@ -2902,15 +2477,6 @@ static void socket_collector(ebpf_module_t *em)
2477
{
2478
heartbeat_t hb;
2479
heartbeat_init(&hb);
2905
- uint32_t network_connection = network_viewer_opt.enabled;
2906
-
2907
- if (network_connection) {
2908
- socket_threads.thread = mallocz(sizeof(netdata_thread_t));
2909
- socket_threads.start_routine = ebpf_socket_read_hash;
2910
-
2911
- netdata_thread_create(socket_threads.thread, socket_threads.name,
2912
- NETDATA_THREAD_OPTION_DEFAULT, ebpf_socket_read_hash, em);
2913
- }
2480
2481
int cgroups = em->cgroup_charts;
2482
if (cgroups)
@@ -2937,14 +2503,8 @@ static void socket_collector(ebpf_module_t *em)
2503
}
2504
2505
pthread_mutex_lock(&collect_data_mutex);
2940
- if (socket_apps_enabled)
2941
- ebpf_socket_update_apps_data(maps_per_core);
2942
-
2506
if (cgroups)
2944
- ebpf_update_socket_cgroup(maps_per_core);
2945
-
2946
- if (network_connection)
2947
- calculate_nv_plot();
2507
+ ebpf_update_socket_cgroup();
2508
2509
pthread_mutex_lock(&lock);
2510
if (socket_global_enabled)
@@ -2963,20 +2523,6 @@ static void socket_collector(ebpf_module_t *em)
2523
2524
fflush(stdout);
2525
2966
- if (network_connection) {
2967
- // We are calling fflush many times, because when we have a lot of dimensions
2968
- // we began to have not expected outputs and Netdata closed the plugin.
2969
- pthread_mutex_lock(&nv_mutex);
2970
- ebpf_socket_create_nv_charts(&inbound_vectors, update_every);
2971
- fflush(stdout);
2972
- ebpf_socket_send_nv_data(&inbound_vectors);
2973
-
2974
- ebpf_socket_create_nv_charts(&outbound_vectors, update_every);
2975
- fflush(stdout);
2976
- ebpf_socket_send_nv_data(&outbound_vectors);
2977
- pthread_mutex_unlock(&nv_mutex);
2978
-
2979
- }
2526
pthread_mutex_unlock(&lock);
2527
pthread_mutex_unlock(&collect_data_mutex);
2528
@@ -2998,42 +2544,24 @@ static void socket_collector(ebpf_module_t *em)
2544
*****************************************************************/
2545
2546
/**
3001
- * Allocate vectors used with this thread.
2547
+ * Initialize vectors used with this thread.
2548
+ *
2549
* We are not testing the return, because callocz does this and shutdown the software
2550
* case it was not possible to allocate.
3004
- *
3005
- * @param apps is apps enabled?
2551
*/
3007
-static void ebpf_socket_allocate_global_vectors(int apps)
2552
+static void ebpf_socket_initialize_global_vectors()
2553
{
2554
memset(socket_aggregated_data, 0 ,NETDATA_MAX_SOCKET_VECTOR * sizeof(netdata_syscall_stat_t));
2555
memset(socket_publish_aggregated, 0 ,NETDATA_MAX_SOCKET_VECTOR * sizeof(netdata_publish_syscall_t));
2556
socket_hash_values = callocz(ebpf_nprocs, sizeof(netdata_idx_t));
2557
3013
- if (apps) {
3014
- ebpf_socket_aral_init();
3015
- socket_bandwidth_curr = callocz((size_t)pid_max, sizeof(ebpf_socket_publish_apps_t *));
3016
- bandwidth_vector = callocz((size_t)ebpf_nprocs, sizeof(ebpf_bandwidth_t));
3017
- }
2558
+ ebpf_socket_aral_init();
2559
+ socket_bandwidth_curr = callocz((size_t)pid_max, sizeof(ebpf_socket_publish_apps_t *));
2560
3019
- socket_values = callocz((size_t)ebpf_nprocs, sizeof(netdata_socket_t));
3020
- if (network_viewer_opt.enabled) {
3021
- inbound_vectors.plot = callocz(network_viewer_opt.max_dim, sizeof(netdata_socket_plot_t));
3022
- outbound_vectors.plot = callocz(network_viewer_opt.max_dim, sizeof(netdata_socket_plot_t));
3023
- }
3024
-}
2561
+ aral_socket_table = ebpf_allocate_pid_aral(NETDATA_EBPF_SOCKET_ARAL_TABLE_NAME,
2562
+ sizeof(netdata_socket_plus_t));
2563
3026
-/**
3027
- * Initialize Inbound and Outbound
3028
- *
3029
- * Initialize the common outbound and inbound sockets.
3030
- */
3031
-static void initialize_inbound_outbound()
3032
-{
3033
- inbound_vectors.last = network_viewer_opt.max_dim - 1;
3034
- outbound_vectors.last = inbound_vectors.last;
3035
- fill_last_nv_dimension(&inbound_vectors.plot[inbound_vectors.last], 0);
3036
- fill_last_nv_dimension(&outbound_vectors.plot[outbound_vectors.last], 1);
2564
+ socket_values = callocz((size_t)ebpf_nprocs, sizeof(netdata_socket_t));
2565
}
2566
2567
/*****************************************************************
@@ -3043,794 +2571,7 @@ static void initialize_inbound_outbound()
2571
*****************************************************************/
2572
2573
/**
3046
- * Fill Port list
3047
- *
3048
- * @param out a pointer to the link list.
3049
- * @param in the structure that will be linked.
3050
- */
3051
-static inline void fill_port_list(ebpf_network_viewer_port_list_t **out, ebpf_network_viewer_port_list_t *in)
3052
-{
3053
- if (likely(*out)) {
3054
- ebpf_network_viewer_port_list_t *move = *out, *store = *out;
3055
- uint16_t first = ntohs(in->first);
3056
- uint16_t last = ntohs(in->last);
3057
- while (move) {
3058
- uint16_t cmp_first = ntohs(move->first);
3059
- uint16_t cmp_last = ntohs(move->last);
3060
- if (cmp_first <= first && first <= cmp_last &&
3061
- cmp_first <= last && last <= cmp_last ) {
3062
- netdata_log_info("The range/value (%u, %u) is inside the range/value (%u, %u) already inserted, it will be ignored.",
3063
- first, last, cmp_first, cmp_last);
3064
- freez(in->value);
3065
- freez(in);
3066
- return;
3067
- } else if (first <= cmp_first && cmp_first <= last &&
3068
- first <= cmp_last && cmp_last <= last) {
3069
- netdata_log_info("The range (%u, %u) is bigger than previous range (%u, %u) already inserted, the previous will be ignored.",
3070
- first, last, cmp_first, cmp_last);
3071
- freez(move->value);
3072
- move->value = in->value;
3073
- move->first = in->first;
3074
- move->last = in->last;
3075
- freez(in);
3076
- return;
3077
- }
3078
-
3079
- store = move;
3080
- move = move->next;
3081
- }
3082
-
3083
- store->next = in;
3084
- } else {
3085
- *out = in;
3086
- }
3087
-
3088
-#ifdef NETDATA_INTERNAL_CHECKS
3089
- netdata_log_info("Adding values %s( %u, %u) to %s port list used on network viewer",
3090
- in->value, ntohs(in->first), ntohs(in->last),
3091
- (*out == network_viewer_opt.included_port)?"included":"excluded");
3092
-#endif
3093
-}
3094
-
3095
-/**
3096
- * Parse Service List
3097
- *
3098
- * @param out a pointer to store the link list
3099
- * @param service the service used to create the structure that will be linked.
3100
- */
3101
-static void parse_service_list(void **out, char *service)
3102
-{
3103
- ebpf_network_viewer_port_list_t **list = (ebpf_network_viewer_port_list_t **)out;
3104
- struct servent *serv = getservbyname((const char *)service, "tcp");
3105
- if (!serv)
3106
- serv = getservbyname((const char *)service, "udp");
3107
-
3108
- if (!serv) {
3109
- netdata_log_info("Cannot resolv the service '%s' with protocols TCP and UDP, it will be ignored", service);
3110
- return;
3111
- }
3112
-
3113
- ebpf_network_viewer_port_list_t *w = callocz(1, sizeof(ebpf_network_viewer_port_list_t));
3114
- w->value = strdupz(service);
3115
- w->hash = simple_hash(service);
3116
-
3117
- w->first = w->last = (uint16_t)serv->s_port;
3118
-
3119
- fill_port_list(list, w);
3120
-}
3121
-
3122
-/**
3123
- * Netmask
3124
- *
3125
- * Copied from iprange (https://github.com/firehol/iprange/blob/master/iprange.h)
3126
- *
3127
- * @param prefix create the netmask based in the CIDR value.
3128
- *
3129
- * @return
3130
- */
3131
-static inline in_addr_t netmask(int prefix) {
3132
-
3133
- if (prefix == 0)
3134
- return (~((in_addr_t) - 1));
3135
- else
3136
- return (in_addr_t)(~((1 << (32 - prefix)) - 1));
3137
-
3138
-}
3139
-
3140
-/**
3141
- * Broadcast
3142
- *
3143
- * Copied from iprange (https://github.com/firehol/iprange/blob/master/iprange.h)
3144
- *
3145
- * @param addr is the ip address
3146
- * @param prefix is the CIDR value.
3147
- *
3148
- * @return It returns the last address of the range
3149
- */
3150
-static inline in_addr_t broadcast(in_addr_t addr, int prefix)
3151
-{
3152
- return (addr | ~netmask(prefix));
3153
-}
3154
-
3155
-/**
3156
- * Network
3157
- *
3158
- * Copied from iprange (https://github.com/firehol/iprange/blob/master/iprange.h)
3159
- *
3160
- * @param addr is the ip address
3161
- * @param prefix is the CIDR value.
3162
- *
3163
- * @return It returns the first address of the range.
3164
- */
3165
-static inline in_addr_t ipv4_network(in_addr_t addr, int prefix)
3166
-{
3167
- return (addr & netmask(prefix));
3168
-}
3169
-
3170
-/**
3171
- * IP to network long
3172
- *
3173
- * @param dst the vector to store the result
3174
- * @param ip the source ip given by our users.
3175
- * @param domain the ip domain (IPV4 or IPV6)
3176
- * @param source the original string
3177
- *
3178
- * @return it returns 0 on success and -1 otherwise.
3179
- */
3180
-static inline int ip2nl(uint8_t *dst, char *ip, int domain, char *source)
3181
-{
3182
- if (inet_pton(domain, ip, dst) <= 0) {
3183
- netdata_log_error("The address specified (%s) is invalid ", source);
3184
- return -1;
3185
- }
3186
-
3187
- return 0;
3188
-}
3189
-
3190
-/**
3191
- * Get IPV6 Last Address
3192
- *
3193
- * @param out the address to store the last address.
3194
- * @param in the address used to do the math.
3195
- * @param prefix number of bits used to calculate the address
3196
- */
3197
-static void get_ipv6_last_addr(union netdata_ip_t *out, union netdata_ip_t *in, uint64_t prefix)
3198
-{
3199
- uint64_t mask,tmp;
3200
- uint64_t ret[2];
3201
- memcpy(ret, in->addr32, sizeof(union netdata_ip_t));
3202
-
3203
- if (prefix == 128) {
3204
- memcpy(out->addr32, in->addr32, sizeof(union netdata_ip_t));
3205
- return;
3206
- } else if (!prefix) {
3207
- ret[0] = ret[1] = 0xFFFFFFFFFFFFFFFF;
3208
- memcpy(out->addr32, ret, sizeof(union netdata_ip_t));
3209
- return;
3210
- } else if (prefix <= 64) {
3211
- ret[1] = 0xFFFFFFFFFFFFFFFFULL;
3212
-
3213
- tmp = be64toh(ret[0]);
3214
- if (prefix > 0) {
3215
- mask = 0xFFFFFFFFFFFFFFFFULL << (64 - prefix);
3216
- tmp |= ~mask;
3217
- }
3218
- ret[0] = htobe64(tmp);
3219
- } else {
3220
- mask = 0xFFFFFFFFFFFFFFFFULL << (128 - prefix);
3221
- tmp = be64toh(ret[1]);
3222
- tmp |= ~mask;
3223
- ret[1] = htobe64(tmp);
3224
- }
3225
-
3226
- memcpy(out->addr32, ret, sizeof(union netdata_ip_t));
3227
-}
3228
-
3229
-/**
3230
- * Calculate ipv6 first address
3231
- *
3232
- * @param out the address to store the first address.
3233
- * @param in the address used to do the math.
3234
- * @param prefix number of bits used to calculate the address
3235
- */
3236
-static void get_ipv6_first_addr(union netdata_ip_t *out, union netdata_ip_t *in, uint64_t prefix)
3237
-{
3238
- uint64_t mask,tmp;
3239
- uint64_t ret[2];
3240
-
3241
- memcpy(ret, in->addr32, sizeof(union netdata_ip_t));
3242
-
3243
- if (prefix == 128) {
3244
- memcpy(out->addr32, in->addr32, sizeof(union netdata_ip_t));
3245
- return;
3246
- } else if (!prefix) {
3247
- ret[0] = ret[1] = 0;
3248
- memcpy(out->addr32, ret, sizeof(union netdata_ip_t));
3249
- return;
3250
- } else if (prefix <= 64) {
3251
- ret[1] = 0ULL;
3252
-
3253
- tmp = be64toh(ret[0]);
3254
- if (prefix > 0) {
3255
- mask = 0xFFFFFFFFFFFFFFFFULL << (64 - prefix);
3256
- tmp &= mask;
3257
- }
3258
- ret[0] = htobe64(tmp);
3259
- } else {
3260
- mask = 0xFFFFFFFFFFFFFFFFULL << (128 - prefix);
3261
- tmp = be64toh(ret[1]);
3262
- tmp &= mask;
3263
- ret[1] = htobe64(tmp);
3264
- }
3265
-
3266
- memcpy(out->addr32, ret, sizeof(union netdata_ip_t));
3267
-}
3268
-
3269
-/**
3270
- * Is ip inside the range
3271
- *
3272
- * Check if the ip is inside a IP range
3273
- *
3274
- * @param rfirst the first ip address of the range
3275
- * @param rlast the last ip address of the range
3276
- * @param cmpfirst the first ip to compare
3277
- * @param cmplast the last ip to compare
3278
- * @param family the IP family
3279
- *
3280
- * @return It returns 1 if the IP is inside the range and 0 otherwise
3281
- */
3282
-static int ebpf_is_ip_inside_range(union netdata_ip_t *rfirst, union netdata_ip_t *rlast,
3283
- union netdata_ip_t *cmpfirst, union netdata_ip_t *cmplast, int family)
3284
-{
3285
- if (family == AF_INET) {
3286
- if ((rfirst->addr32[0] <= cmpfirst->addr32[0]) && (rlast->addr32[0] >= cmplast->addr32[0]))
3287
- return 1;
3288
- } else {
3289
- if (memcmp(rfirst->addr8, cmpfirst->addr8, sizeof(union netdata_ip_t)) <= 0 &&
3290
- memcmp(rlast->addr8, cmplast->addr8, sizeof(union netdata_ip_t)) >= 0) {
3291
- return 1;
3292
- }
3293
-
3294
- }
3295
- return 0;
3296
-}
3297
-
3298
-/**
3299
- * Fill IP list
3300
- *
3301
- * @param out a pointer to the link list.
3302
- * @param in the structure that will be linked.
3303
- * @param table the modified table.
3304
- */
3305
-void ebpf_fill_ip_list(ebpf_network_viewer_ip_list_t **out, ebpf_network_viewer_ip_list_t *in, char *table)
3306
-{
3307
-#ifndef NETDATA_INTERNAL_CHECKS
3308
- UNUSED(table);
3309
-#endif
3310
- if (in->ver == AF_INET) { // It is simpler to compare using host order
3311
- in->first.addr32[0] = ntohl(in->first.addr32[0]);
3312
- in->last.addr32[0] = ntohl(in->last.addr32[0]);
3313
- }
3314
- if (likely(*out)) {
3315
- ebpf_network_viewer_ip_list_t *move = *out, *store = *out;
3316
- while (move) {
3317
- if (in->ver == move->ver &&
3318
- ebpf_is_ip_inside_range(&move->first, &move->last, &in->first, &in->last, in->ver)) {
3319
- netdata_log_info("The range/value (%s) is inside the range/value (%s) already inserted, it will be ignored.",
3320
- in->value, move->value);
3321
- freez(in->value);
3322
- freez(in);
3323
- return;
3324
- }
3325
- store = move;
3326
- move = move->next;
3327
- }
3328
-
3329
- store->next = in;
3330
- } else {
3331
- *out = in;
3332
- }
3333
-
3334
-#ifdef NETDATA_INTERNAL_CHECKS
3335
- char first[256], last[512];
3336
- if (in->ver == AF_INET) {
3337
- netdata_log_info("Adding values %s: (%u - %u) to %s IP list \"%s\" used on network viewer",
3338
- in->value, in->first.addr32[0], in->last.addr32[0],
3339
- (*out == network_viewer_opt.included_ips)?"included":"excluded",
3340
- table);
3341
- } else {
3342
- if (inet_ntop(AF_INET6, in->first.addr8, first, INET6_ADDRSTRLEN) &&
3343
- inet_ntop(AF_INET6, in->last.addr8, last, INET6_ADDRSTRLEN))
3344
- netdata_log_info("Adding values %s - %s to %s IP list \"%s\" used on network viewer",
3345
- first, last,
3346
- (*out == network_viewer_opt.included_ips)?"included":"excluded",
3347
- table);
3348
- }
3349
-#endif
3350
-}
3351
-
3352
-/**
3353
- * Parse IP List
3354
- *
3355
- * Parse IP list and link it.
3356
- *
3357
- * @param out a pointer to store the link list
3358
- * @param ip the value given as parameter
3359
- */
3360
-static void ebpf_parse_ip_list(void **out, char *ip)
3361
-{
3362
- ebpf_network_viewer_ip_list_t **list = (ebpf_network_viewer_ip_list_t **)out;
3363
-
3364
- char *ipdup = strdupz(ip);
3365
- union netdata_ip_t first = { };
3366
- union netdata_ip_t last = { };
3367
- char *is_ipv6;
3368
- if (*ip == '*' && *(ip+1) == '\0') {
3369
- memset(first.addr8, 0, sizeof(first.addr8));
3370
- memset(last.addr8, 0xFF, sizeof(last.addr8));
3371
-
3372
- is_ipv6 = ip;
3373
-
3374
- clean_ip_structure(list);
3375
- goto storethisip;
3376
- }
3377
-
3378
- char *end = ip;
3379
- // Move while I cannot find a separator
3380
- while (*end && *end != '/' && *end != '-') end++;
3381
-
3382
- // We will use only the classic IPV6 for while, but we could consider the base 85 in a near future
3383
- // https://tools.ietf.org/html/rfc1924
3384
- is_ipv6 = strchr(ip, ':');
3385
-
3386
- int select;
3387
- if (*end && !is_ipv6) { // IPV4 range
3388
- select = (*end == '/') ? 0 : 1;
3389
- *end++ = '\0';
3390
- if (*end == '!') {
3391
- netdata_log_info("The exclusion cannot be in the second part of the range %s, it will be ignored.", ipdup);
3392
- goto cleanipdup;
3393
- }
3394
-
3395
- if (!select) { // CIDR
3396
- select = ip2nl(first.addr8, ip, AF_INET, ipdup);
3397
- if (select)
3398
- goto cleanipdup;
3399
-
3400
- select = (int) str2i(end);
3401
- if (select < NETDATA_MINIMUM_IPV4_CIDR || select > NETDATA_MAXIMUM_IPV4_CIDR) {
3402
- netdata_log_info("The specified CIDR %s is not valid, the IP %s will be ignored.", end, ip);
3403
- goto cleanipdup;
3404
- }
3405
-
3406
- last.addr32[0] = htonl(broadcast(ntohl(first.addr32[0]), select));
3407
- // This was added to remove
3408
- // https://app.codacy.com/manual/netdata/netdata/pullRequest?prid=5810941&bid=19021977
3409
- UNUSED(last.addr32[0]);
3410
-
3411
- uint32_t ipv4_test = htonl(ipv4_network(ntohl(first.addr32[0]), select));
3412
- if (first.addr32[0] != ipv4_test) {
3413
- first.addr32[0] = ipv4_test;
3414
- struct in_addr ipv4_convert;
3415
- ipv4_convert.s_addr = ipv4_test;
3416
- char ipv4_msg[INET_ADDRSTRLEN];
3417
- if(inet_ntop(AF_INET, &ipv4_convert, ipv4_msg, INET_ADDRSTRLEN))
3418
- netdata_log_info("The network value of CIDR %s was updated for %s .", ipdup, ipv4_msg);
3419
- }
3420
- } else { // Range
3421
- select = ip2nl(first.addr8, ip, AF_INET, ipdup);
3422
- if (select)
3423
- goto cleanipdup;
3424
-
3425
- select = ip2nl(last.addr8, end, AF_INET, ipdup);
3426
- if (select)
3427
- goto cleanipdup;
3428
- }
3429
-
3430
- if (htonl(first.addr32[0]) > htonl(last.addr32[0])) {
3431
- netdata_log_info("The specified range %s is invalid, the second address is smallest than the first, it will be ignored.",
3432
- ipdup);
3433
- goto cleanipdup;
3434
- }
3435
- } else if (is_ipv6) { // IPV6
3436
- if (!*end) { // Unique
3437
- select = ip2nl(first.addr8, ip, AF_INET6, ipdup);
3438
- if (select)
3439
- goto cleanipdup;
3440
-
3441
- memcpy(last.addr8, first.addr8, sizeof(first.addr8));
3442
- } else if (*end == '-') {
3443
- *end++ = 0x00;
3444
- if (*end == '!') {
3445
- netdata_log_info("The exclusion cannot be in the second part of the range %s, it will be ignored.", ipdup);
3446
- goto cleanipdup;
3447
- }
3448
-
3449
- select = ip2nl(first.addr8, ip, AF_INET6, ipdup);
3450
- if (select)
3451
- goto cleanipdup;
3452
-
3453
- select = ip2nl(last.addr8, end, AF_INET6, ipdup);
3454
- if (select)
3455
- goto cleanipdup;
3456
- } else { // CIDR
3457
- *end++ = 0x00;
3458
- if (*end == '!') {
3459
- netdata_log_info("The exclusion cannot be in the second part of the range %s, it will be ignored.", ipdup);
3460
- goto cleanipdup;
3461
- }
3462
-
3463
- select = str2i(end);
3464
- if (select < 0 || select > 128) {
3465
- netdata_log_info("The CIDR %s is not valid, the address %s will be ignored.", end, ip);
3466
- goto cleanipdup;
3467
- }
3468
-
3469
- uint64_t prefix = (uint64_t)select;
3470
- select = ip2nl(first.addr8, ip, AF_INET6, ipdup);
3471
- if (select)
3472
- goto cleanipdup;
3473
-
3474
- get_ipv6_last_addr(&last, &first, prefix);
3475
-
3476
- union netdata_ip_t ipv6_test;
3477
- get_ipv6_first_addr(&ipv6_test, &first, prefix);
3478
-
3479
- if (memcmp(first.addr8, ipv6_test.addr8, sizeof(union netdata_ip_t)) != 0) {
3480
- memcpy(first.addr8, ipv6_test.addr8, sizeof(union netdata_ip_t));
3481
-
3482
- struct in6_addr ipv6_convert;
3483
- memcpy(ipv6_convert.s6_addr, ipv6_test.addr8, sizeof(union netdata_ip_t));
3484
-
3485
- char ipv6_msg[INET6_ADDRSTRLEN];
3486
- if(inet_ntop(AF_INET6, &ipv6_convert, ipv6_msg, INET6_ADDRSTRLEN))
3487
- netdata_log_info("The network value of CIDR %s was updated for %s .", ipdup, ipv6_msg);
3488
- }
3489
- }
3490
-
3491
- if ((be64toh(*(uint64_t *)&first.addr32[2]) > be64toh(*(uint64_t *)&last.addr32[2]) &&
3492
- !memcmp(first.addr32, last.addr32, 2*sizeof(uint32_t))) ||
3493
- (be64toh(*(uint64_t *)&first.addr32) > be64toh(*(uint64_t *)&last.addr32)) ) {
3494
- netdata_log_info("The specified range %s is invalid, the second address is smallest than the first, it will be ignored.",
3495
- ipdup);
3496
- goto cleanipdup;
3497
- }
3498
- } else { // Unique ip
3499
- select = ip2nl(first.addr8, ip, AF_INET, ipdup);
3500
- if (select)
3501
- goto cleanipdup;
3502
-
3503
- memcpy(last.addr8, first.addr8, sizeof(first.addr8));
3504
- }
3505
-
3506
- ebpf_network_viewer_ip_list_t *store;
3507
-
3508
-storethisip:
3509
- store = callocz(1, sizeof(ebpf_network_viewer_ip_list_t));
3510
- store->value = ipdup;
3511
- store->hash = simple_hash(ipdup);
3512
- store->ver = (uint8_t)(!is_ipv6)?AF_INET:AF_INET6;
3513
- memcpy(store->first.addr8, first.addr8, sizeof(first.addr8));
3514
- memcpy(store->last.addr8, last.addr8, sizeof(last.addr8));
3515
-
3516
- ebpf_fill_ip_list(list, store, "socket");
3517
- return;
3518
-
3519
-cleanipdup:
3520
- freez(ipdup);
3521
-}
3522
-
3523
-/**
3524
- * Parse IP Range
3525
- *
3526
- * Parse the IP ranges given and create Network Viewer IP Structure
3527
- *
3528
- * @param ptr is a pointer with the text to parse.
3529
- */
3530
-static void ebpf_parse_ips(char *ptr)
3531
-{
3532
- // No value
3533
- if (unlikely(!ptr))
3534
- return;
3535
-
3536
- while (likely(ptr)) {
3537
- // Move forward until next valid character
3538
- while (isspace(*ptr)) ptr++;
3539
-
3540
- // No valid value found
3541
- if (unlikely(!*ptr))
3542
- return;
3543
-
3544
- // Find space that ends the list
3545
- char *end = strchr(ptr, ' ');
3546
- if (end) {
3547
- *end++ = '\0';
3548
- }
3549
-
3550
- int neg = 0;
3551
- if (*ptr == '!') {
3552
- neg++;
3553
- ptr++;
3554
- }
3555
-
3556
- if (isascii(*ptr)) { // Parse port
3557
- ebpf_parse_ip_list((!neg)?(void **)&network_viewer_opt.included_ips:
3558
- (void **)&network_viewer_opt.excluded_ips,
3559
- ptr);
3560
- }
3561
-
3562
- ptr = end;
3563
- }
3564
-}
3565
-
3566
-
3567
-
3568
-/**
3569
- * Parse port list
3570
- *
3571
- * Parse an allocated port list with the range given
3572
- *
3573
- * @param out a pointer to store the link list
3574
- * @param range the informed range for the user.
3575
- */
3576
-static void parse_port_list(void **out, char *range)
3577
-{
3578
- int first, last;
3579
- ebpf_network_viewer_port_list_t **list = (ebpf_network_viewer_port_list_t **)out;
3580
-
3581
- char *copied = strdupz(range);
3582
- if (*range == '*' && *(range+1) == '\0') {
3583
- first = 1;
3584
- last = 65535;
3585
-
3586
- clean_port_structure(list);
3587
- goto fillenvpl;
3588
- }
3589
-
3590
- char *end = range;
3591
- //Move while I cannot find a separator
3592
- while (*end && *end != ':' && *end != '-') end++;
3593
-
3594
- //It has a range
3595
- if (likely(*end)) {
3596
- *end++ = '\0';
3597
- if (*end == '!') {
3598
- netdata_log_info("The exclusion cannot be in the second part of the range, the range %s will be ignored.", copied);
3599
- freez(copied);
3600
- return;
3601
- }
3602
- last = str2i((const char *)end);
3603
- } else {
3604
- last = 0;
3605
- }
3606
-
3607
- first = str2i((const char *)range);
3608
- if (first < NETDATA_MINIMUM_PORT_VALUE || first > NETDATA_MAXIMUM_PORT_VALUE) {
3609
- netdata_log_info("The first port %d of the range \"%s\" is invalid and it will be ignored!", first, copied);
3610
- freez(copied);
3611
- return;
3612
- }
3613
-
3614
- if (!last)
3615
- last = first;
3616
-
3617
- if (last < NETDATA_MINIMUM_PORT_VALUE || last > NETDATA_MAXIMUM_PORT_VALUE) {
3618
- netdata_log_info("The second port %d of the range \"%s\" is invalid and the whole range will be ignored!", last, copied);
3619
- freez(copied);
3620
- return;
3621
- }
3622
-
3623
- if (first > last) {
3624
- netdata_log_info("The specified order %s is wrong, the smallest value is always the first, it will be ignored!", copied);
3625
- freez(copied);
3626
- return;
3627
- }
3628
-
3629
- ebpf_network_viewer_port_list_t *w;
3630
-fillenvpl:
3631
- w = callocz(1, sizeof(ebpf_network_viewer_port_list_t));
3632
- w->value = copied;
3633
- w->hash = simple_hash(copied);
3634
- w->first = (uint16_t)htons((uint16_t)first);
3635
- w->last = (uint16_t)htons((uint16_t)last);
3636
- w->cmp_first = (uint16_t)first;
3637
- w->cmp_last = (uint16_t)last;
3638
-
3639
- fill_port_list(list, w);
3640
-}
3641
-
3642
-/**
3643
- * Read max dimension.
3644
- *
3645
- * Netdata plot two dimensions per connection, so it is necessary to adjust the values.
3646
- *
3647
- * @param cfg the configuration structure
3648
- */
3649
-static void read_max_dimension(struct config *cfg)
3650
-{
3651
- int maxdim ;
3652
- maxdim = (int) appconfig_get_number(cfg,
3653
- EBPF_NETWORK_VIEWER_SECTION,
3654
- EBPF_MAXIMUM_DIMENSIONS,
3655
- NETDATA_NV_CAP_VALUE);
3656
- if (maxdim < 0) {
3657
- netdata_log_error("'maximum dimensions = %d' must be a positive number, Netdata will change for default value %ld.",
3658
- maxdim, NETDATA_NV_CAP_VALUE);
3659
- maxdim = NETDATA_NV_CAP_VALUE;
3660
- }
3661
-
3662
- maxdim /= 2;
3663
- if (!maxdim) {
3664
- netdata_log_info("The number of dimensions is too small (%u), we are setting it to minimum 2", network_viewer_opt.max_dim);
3665
- network_viewer_opt.max_dim = 1;
3666
- return;
3667
- }
3668
-
3669
- network_viewer_opt.max_dim = (uint32_t)maxdim;
3670
-}
3671
-
3672
-/**
3673
- * Parse Port Range
3674
- *
3675
- * Parse the port ranges given and create Network Viewer Port Structure
3676
- *
3677
- * @param ptr is a pointer with the text to parse.
3678
- */
3679
-static void parse_ports(char *ptr)
3680
-{
3681
- // No value
3682
- if (unlikely(!ptr))
3683
- return;
3684
-
3685
- while (likely(ptr)) {
3686
- // Move forward until next valid character
3687
- while (isspace(*ptr)) ptr++;
3688
-
3689
- // No valid value found
3690
- if (unlikely(!*ptr))
3691
- return;
3692
-
3693
- // Find space that ends the list
3694
- char *end = strchr(ptr, ' ');
3695
- if (end) {
3696
- *end++ = '\0';
3697
- }
3698
-
3699
- int neg = 0;
3700
- if (*ptr == '!') {
3701
- neg++;
3702
- ptr++;
3703
- }
3704
-
3705
- if (isdigit(*ptr)) { // Parse port
3706
- parse_port_list((!neg)?(void **)&network_viewer_opt.included_port:(void **)&network_viewer_opt.excluded_port,
3707
- ptr);
3708
- } else if (isalpha(*ptr)) { // Parse service
3709
- parse_service_list((!neg)?(void **)&network_viewer_opt.included_port:(void **)&network_viewer_opt.excluded_port,
3710
- ptr);
3711
- } else if (*ptr == '*') { // All
3712
- parse_port_list((!neg)?(void **)&network_viewer_opt.included_port:(void **)&network_viewer_opt.excluded_port,
3713
- ptr);
3714
- }
3715
-
3716
- ptr = end;
3717
- }
3718
-}
3719
-
3720
-/**
3721
- * Link hostname
3722
- *
3723
- * @param out is the output link list
3724
- * @param in the hostname to add to list.
3725
- */
3726
-static void link_hostname(ebpf_network_viewer_hostname_list_t **out, ebpf_network_viewer_hostname_list_t *in)
3727
-{
3728
- if (likely(*out)) {
3729
- ebpf_network_viewer_hostname_list_t *move = *out;
3730
- for (; move->next ; move = move->next ) {
3731
- if (move->hash == in->hash && !strcmp(move->value, in->value)) {
3732
- netdata_log_info("The hostname %s was already inserted, it will be ignored.", in->value);
3733
- freez(in->value);
3734
- simple_pattern_free(in->value_pattern);
3735
- freez(in);
3736
- return;
3737
- }
3738
- }
3739
-
3740
- move->next = in;
3741
- } else {
3742
- *out = in;
3743
- }
3744
-#ifdef NETDATA_INTERNAL_CHECKS
3745
- netdata_log_info("Adding value %s to %s hostname list used on network viewer",
3746
- in->value,
3747
- (*out == network_viewer_opt.included_hostnames)?"included":"excluded");
3748
-#endif
3749
-}
3750
-
3751
-/**
3752
- * Link Hostnames
3753
- *
3754
- * Parse the list of hostnames to create the link list.
3755
- * This is not associated with the IP, because simple patterns like *example* cannot be resolved to IP.
3756
- *
3757
- * @param out is the output link list
3758
- * @param parse is a pointer with the text to parser.
3759
- */
3760
-static void link_hostnames(char *parse)
3761
-{
3762
- // No value
3763
- if (unlikely(!parse))
3764
- return;
3765
-
3766
- while (likely(parse)) {
3767
- // Find the first valid value
3768
- while (isspace(*parse)) parse++;
3769
-
3770
- // No valid value found
3771
- if (unlikely(!*parse))
3772
- return;
3773
-
3774
- // Find space that ends the list
3775
- char *end = strchr(parse, ' ');
3776
- if (end) {
3777
- *end++ = '\0';
3778
- }
3779
-
3780
- int neg = 0;
3781
- if (*parse == '!') {
3782
- neg++;
3783
- parse++;
3784
- }
3785
-
3786
- ebpf_network_viewer_hostname_list_t *hostname = callocz(1 , sizeof(ebpf_network_viewer_hostname_list_t));
3787
- hostname->value = strdupz(parse);
3788
- hostname->hash = simple_hash(parse);
3789
- hostname->value_pattern = simple_pattern_create(parse, NULL, SIMPLE_PATTERN_EXACT, true);
3790
-
3791
- link_hostname((!neg)?&network_viewer_opt.included_hostnames:&network_viewer_opt.excluded_hostnames,
3792
- hostname);
3793
-
3794
- parse = end;
3795
- }
3796
-}
3797
-
3798
-/**
3799
- * Parse network viewer section
3800
- *
3801
- * @param cfg the configuration structure
3802
- */
3803
-void parse_network_viewer_section(struct config *cfg)
3804
-{
3805
- read_max_dimension(cfg);
3806
-
3807
- network_viewer_opt.hostname_resolution_enabled = appconfig_get_boolean(cfg,
3808
- EBPF_NETWORK_VIEWER_SECTION,
3809
- EBPF_CONFIG_RESOLVE_HOSTNAME,
3810
- CONFIG_BOOLEAN_NO);
3811
-
3812
- network_viewer_opt.service_resolution_enabled = appconfig_get_boolean(cfg,
3813
- EBPF_NETWORK_VIEWER_SECTION,
3814
- EBPF_CONFIG_RESOLVE_SERVICE,
3815
- CONFIG_BOOLEAN_NO);
3816
-
3817
- char *value = appconfig_get(cfg, EBPF_NETWORK_VIEWER_SECTION, EBPF_CONFIG_PORTS, NULL);
3818
- parse_ports(value);
3819
-
3820
- if (network_viewer_opt.hostname_resolution_enabled) {
3821
- value = appconfig_get(cfg, EBPF_NETWORK_VIEWER_SECTION, EBPF_CONFIG_HOSTNAMES, NULL);
3822
- link_hostnames(value);
3823
- } else {
3824
- netdata_log_info("Name resolution is disabled, collector will not parser \"hostnames\" list.");
3825
- }
3826
-
3827
- value = appconfig_get(cfg, EBPF_NETWORK_VIEWER_SECTION,
3828
- "ips", "!127.0.0.1/8 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 fc00::/7 !::1/128");
3829
- ebpf_parse_ips(value);
3830
-}
3831
-
3832
-/**
3833
- * Link dimension name
2574
+ * Link dimension name
2575
*
2576
* Link user specified names inside a link list.
2577
*
@@ -3838,7 +2579,7 @@ void parse_network_viewer_section(struct config *cfg)
2579
* @param hash the calculated hash for the dimension name.
2580
* @param name the dimension name.
2581
*/
3841
-static void link_dimension_name(char *port, uint32_t hash, char *value)
2582
+static void ebpf_link_dimension_name(char *port, uint32_t hash, char *value)
2583
{
2584
int test = str2i(port);
2585
if (test < NETDATA_MINIMUM_PORT_VALUE || test > NETDATA_MAXIMUM_PORT_VALUE){
@@ -3883,13 +2624,13 @@ static void link_dimension_name(char *port, uint32_t hash, char *value)
2624
*
2625
* @param cfg the configuration structure
2626
*/
3886
-void parse_service_name_section(struct config *cfg)
2627
+void ebpf_parse_service_name_section(struct config *cfg)
2628
{
2629
struct section *co = appconfig_get_section(cfg, EBPF_SERVICE_NAME_SECTION);
2630
if (co) {
2631
struct config_option *cv;
2632
for (cv = co->values; cv ; cv = cv->next) {
3892
- link_dimension_name(cv->name, cv->hash, cv->value);
2633
+ ebpf_link_dimension_name(cv->name, cv->hash, cv->value);
2634
}
2635
}
2636
@@ -3910,23 +2651,21 @@ void parse_service_name_section(struct config *cfg)
2651
// if variable has an invalid value, we assume netdata is using 19999
2652
int default_port = str2i(port_string);
2653
if (default_port > 0 && default_port < 65536)
3913
- link_dimension_name(port_string, simple_hash(port_string), "Netdata");
2654
+ ebpf_link_dimension_name(port_string, simple_hash(port_string), "Netdata");
2655
}
2656
}
2657
2658
+/**
2659
+ * Parse table size options
2660
+ *
2661
+ * @param cfg configuration options read from user file.
2662
+ */
2663
void parse_table_size_options(struct config *cfg)
2664
{
3919
- socket_maps[NETDATA_SOCKET_TABLE_BANDWIDTH].user_input = (uint32_t) appconfig_get_number(cfg,
3920
- EBPF_GLOBAL_SECTION,
3921
- EBPF_CONFIG_BANDWIDTH_SIZE, NETDATA_MAXIMUM_CONNECTIONS_ALLOWED);
3922
-
3923
- socket_maps[NETDATA_SOCKET_TABLE_IPV4].user_input = (uint32_t) appconfig_get_number(cfg,
3924
- EBPF_GLOBAL_SECTION,
3925
- EBPF_CONFIG_IPV4_SIZE, NETDATA_MAXIMUM_CONNECTIONS_ALLOWED);
3926
-
3927
- socket_maps[NETDATA_SOCKET_TABLE_IPV6].user_input = (uint32_t) appconfig_get_number(cfg,
3928
- EBPF_GLOBAL_SECTION,
3929
- EBPF_CONFIG_IPV6_SIZE, NETDATA_MAXIMUM_CONNECTIONS_ALLOWED);
2665
+ socket_maps[NETDATA_SOCKET_OPEN_SOCKET].user_input = (uint32_t) appconfig_get_number(cfg,
2666
+ EBPF_GLOBAL_SECTION,
2667
+ EBPF_CONFIG_SOCKET_MONITORING_SIZE,
2668
+ NETDATA_MAXIMUM_CONNECTIONS_ALLOWED);
2669
2670
socket_maps[NETDATA_SOCKET_TABLE_UDP].user_input = (uint32_t) appconfig_get_number(cfg,
2671
EBPF_GLOBAL_SECTION,
@@ -3965,7 +2704,7 @@ static int ebpf_socket_load_bpf(ebpf_module_t *em)
2704
#endif
2705
2706
if (ret) {
3968
- netdata_log_error("%s %s", EBPF_DEFAULT_ERROR_MSG, em->thread_name);
2707
+ netdata_log_error("%s %s", EBPF_DEFAULT_ERROR_MSG, em->info.thread_name);
2708
}
2709
2710
return ret;
@@ -3985,25 +2724,23 @@ void *ebpf_socket_thread(void *ptr)
2724
netdata_thread_cleanup_push(ebpf_socket_exit, ptr);
2725
2726
ebpf_module_t *em = (ebpf_module_t *)ptr;
3988
- em->maps = socket_maps;
3989
-
3990
- parse_table_size_options(&socket_config);
3991
-
3992
- if (pthread_mutex_init(&nv_mutex, NULL)) {
3993
- netdata_log_error("Cannot initialize local mutex");
3994
- goto endsocket;
2727
+ if (em->enabled > NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
2728
+ collector_error("There is already a thread %s running", em->info.thread_name);
2729
+ return NULL;
2730
}
2731
3997
- ebpf_socket_allocate_global_vectors(em->apps_charts);
2732
+ em->maps = socket_maps;
2733
3999
- if (network_viewer_opt.enabled) {
4000
- memset(&inbound_vectors.tree, 0, sizeof(avl_tree_lock));
4001
- memset(&outbound_vectors.tree, 0, sizeof(avl_tree_lock));
4002
- avl_init_lock(&inbound_vectors.tree, ebpf_compare_sockets);
4003
- avl_init_lock(&outbound_vectors.tree, ebpf_compare_sockets);
2734
+ rw_spinlock_write_lock(&network_viewer_opt.rw_spinlock);
2735
+ // It was not enabled from main config file (ebpf.d.conf)
2736
+ if (!network_viewer_opt.enabled)
2737
+ network_viewer_opt.enabled = appconfig_get_boolean(&socket_config, EBPF_NETWORK_VIEWER_SECTION, "enabled",
2738
+ CONFIG_BOOLEAN_YES);
2739
+ rw_spinlock_write_unlock(&network_viewer_opt.rw_spinlock);
2740
4005
- initialize_inbound_outbound();
4006
- }
2741
+ parse_table_size_options(&socket_config);
2742
+
2743
+ ebpf_socket_initialize_global_vectors();
2744
2745
if (running_on_kernel < NETDATA_EBPF_KERNEL_5_0)
2746
em->mode = MODE_ENTRY;
@@ -4026,8 +2763,15 @@ void *ebpf_socket_thread(void *ptr)
2763
socket_aggregated_data, socket_publish_aggregated, socket_dimension_names, socket_id_names,
2764
algorithms, NETDATA_MAX_SOCKET_VECTOR);
2765
2766
+ ebpf_read_socket.thread = mallocz(sizeof(netdata_thread_t));
2767
+ netdata_thread_create(ebpf_read_socket.thread,
2768
+ ebpf_read_socket.name,
2769
+ NETDATA_THREAD_OPTION_DEFAULT,
2770
+ ebpf_read_socket_thread,
2771
+ em);
2772
+
2773
pthread_mutex_lock(&lock);
4030
- ebpf_create_global_charts(em);
2774
+ ebpf_socket_create_global_charts(em);
2775
2776
ebpf_update_stats(&plugin_statistics, em);
2777
ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps, EBPF_ACTION_STAT_ADD);
collectors/ebpf.plugin/ebpf_socket.h
+71
-93
@@ -4,6 +4,11 @@
4
#include <stdint.h>
5
#include "libnetdata/avl/avl.h"
6
7
+#include <sys/socket.h>
8
+#ifdef HAVE_NETDB_H
9
+#include <netdb.h>
10
+#endif
11
+
12
// Module name & description
13
#define NETDATA_EBPF_MODULE_NAME_SOCKET "socket"
14
#define NETDATA_EBPF_SOCKET_MODULE_DESC "Monitors TCP and UDP bandwidth. This thread is integrated with apps and cgroup."
@@ -11,8 +16,6 @@
16
// Vector indexes
17
#define NETDATA_UDP_START 3
18
14
-#define NETDATA_SOCKET_READ_SLEEP_MS 800000ULL
15
-
19
// config file
20
#define NETDATA_NETWORK_CONFIG_FILE "network.conf"
21
#define EBPF_NETWORK_VIEWER_SECTION "network connections"
@@ -21,18 +24,13 @@
24
#define EBPF_CONFIG_RESOLVE_SERVICE "resolve service names"
25
#define EBPF_CONFIG_PORTS "ports"
26
#define EBPF_CONFIG_HOSTNAMES "hostnames"
24
-#define EBPF_CONFIG_BANDWIDTH_SIZE "bandwidth table size"
25
-#define EBPF_CONFIG_IPV4_SIZE "ipv4 connection table size"
26
-#define EBPF_CONFIG_IPV6_SIZE "ipv6 connection table size"
27
+#define EBPF_CONFIG_SOCKET_MONITORING_SIZE "socket monitoring table size"
28
#define EBPF_CONFIG_UDP_SIZE "udp connection table size"
28
-#define EBPF_MAXIMUM_DIMENSIONS "maximum dimensions"
29
30
enum ebpf_socket_table_list {
31
- NETDATA_SOCKET_TABLE_BANDWIDTH,
31
NETDATA_SOCKET_GLOBAL,
32
NETDATA_SOCKET_LPORTS,
34
- NETDATA_SOCKET_TABLE_IPV4,
35
- NETDATA_SOCKET_TABLE_IPV6,
33
+ NETDATA_SOCKET_OPEN_SOCKET,
34
NETDATA_SOCKET_TABLE_UDP,
35
NETDATA_SOCKET_TABLE_CTRL
36
};
@@ -122,13 +120,6 @@ typedef enum ebpf_socket_idx {
120
#define NETDATA_NET_APPS_BANDWIDTH_UDP_SEND_CALLS "bandwidth_udp_send"
121
#define NETDATA_NET_APPS_BANDWIDTH_UDP_RECV_CALLS "bandwidth_udp_recv"
122
125
-// Network viewer charts
126
-#define NETDATA_NV_OUTBOUND_BYTES "outbound_bytes"
127
-#define NETDATA_NV_OUTBOUND_PACKETS "outbound_packets"
128
-#define NETDATA_NV_OUTBOUND_RETRANSMIT "outbound_retransmit"
129
-#define NETDATA_NV_INBOUND_BYTES "inbound_bytes"
130
-#define NETDATA_NV_INBOUND_PACKETS "inbound_packets"
131
-
123
// Port range
124
#define NETDATA_MINIMUM_PORT_VALUE 1
125
#define NETDATA_MAXIMUM_PORT_VALUE 65535
@@ -163,6 +154,8 @@ typedef enum ebpf_socket_idx {
154
155
// ARAL name
156
#define NETDATA_EBPF_SOCKET_ARAL_NAME "ebpf_socket"
157
+#define NETDATA_EBPF_PID_SOCKET_ARAL_TABLE_NAME "ebpf_pid_socket"
158
+#define NETDATA_EBPF_SOCKET_ARAL_TABLE_NAME "ebpf_socket_tbl"
159
160
typedef struct ebpf_socket_publish_apps {
161
// Data read
@@ -246,10 +239,11 @@ typedef struct ebpf_network_viewer_hostname_list {
239
struct ebpf_network_viewer_hostname_list *next;
240
} ebpf_network_viewer_hostname_list_t;
241
249
-#define NETDATA_NV_CAP_VALUE 50L
242
typedef struct ebpf_network_viewer_options {
243
+ RW_SPINLOCK rw_spinlock;
244
+
245
uint32_t enabled;
252
- uint32_t max_dim; // Store value read from 'maximum dimensions'
246
+ uint32_t family; // AF_INET, AF_INET6 or AF_UNSPEC (both)
247
248
uint32_t hostname_resolution_enabled;
249
uint32_t service_resolution_enabled;
@@ -275,98 +269,82 @@ extern ebpf_network_viewer_options_t network_viewer_opt;
269
* Structure to store socket information
270
*/
271
typedef struct netdata_socket {
278
- uint64_t recv_packets;
279
- uint64_t sent_packets;
280
- uint64_t recv_bytes;
281
- uint64_t sent_bytes;
282
- uint64_t first; // First timestamp
283
- uint64_t ct; // Current timestamp
284
- uint32_t retransmit; // It is never used with UDP
272
+ // Timestamp
273
+ uint64_t first_timestamp;
274
+ uint64_t current_timestamp;
275
+ // Socket additional info
276
uint16_t protocol;
286
- uint16_t reserved;
277
+ uint16_t family;
278
+ uint32_t external_origin;
279
+ struct {
280
+ uint32_t call_tcp_sent;
281
+ uint32_t call_tcp_received;
282
+ uint64_t tcp_bytes_sent;
283
+ uint64_t tcp_bytes_received;
284
+ uint32_t close; //It is never used with UDP
285
+ uint32_t retransmit; //It is never used with UDP
286
+ uint32_t ipv4_connect;
287
+ uint32_t ipv6_connect;
288
+ } tcp;
289
+
290
+ struct {
291
+ uint32_t call_udp_sent;
292
+ uint32_t call_udp_received;
293
+ uint64_t udp_bytes_sent;
294
+ uint64_t udp_bytes_received;
295
+ } udp;
296
} netdata_socket_t;
297
289
-typedef struct netdata_plot_values {
290
- // Values used in the previous iteration
291
- uint64_t recv_packets;
292
- uint64_t sent_packets;
293
- uint64_t recv_bytes;
294
- uint64_t sent_bytes;
295
- uint32_t retransmit;
298
+typedef enum netdata_socket_flags {
299
+ NETDATA_SOCKET_FLAGS_ALREADY_OPEN = (1<<0)
300
+} netdata_socket_flags_t;
301
+
302
+typedef enum netdata_socket_src_ip_origin {
303
+ NETDATA_EBPF_SRC_IP_ORIGIN_LOCAL,
304
+ NETDATA_EBPF_SRC_IP_ORIGIN_EXTERNAL
305
+} netdata_socket_src_ip_origin_t;
306
297
- uint64_t last_time;
307
+typedef struct netata_socket_plus {
308
+ netdata_socket_t data; // Data read from database
309
+ uint32_t pid;
310
+ time_t last_update;
311
+ netdata_socket_flags_t flags;
312
+
313
+ struct {
314
+ char src_ip[INET6_ADDRSTRLEN + 1];
315
+ // uint16_t src_port;
316
+ char dst_ip[INET6_ADDRSTRLEN+ 1];
317
+ char dst_port[NI_MAXSERV + 1];
318
+ } socket_string;
319
+} netdata_socket_plus_t;
320
+
321
+enum netdata_udp_ports {
322
+ NETDATA_EBPF_UDP_PORT = 53
323
+};
324
299
- // Values used to plot
300
- uint64_t plot_recv_packets;
301
- uint64_t plot_sent_packets;
302
- uint64_t plot_recv_bytes;
303
- uint64_t plot_sent_bytes;
304
- uint16_t plot_retransmit;
305
-} netdata_plot_values_t;
325
+extern ARAL *aral_socket_table;
326
327
/**
328
* Index used together previous structure
329
*/
330
typedef struct netdata_socket_idx {
331
union netdata_ip_t saddr;
312
- uint16_t sport;
332
+ //uint16_t sport;
333
union netdata_ip_t daddr;
334
uint16_t dport;
335
+ uint32_t pid;
336
} netdata_socket_idx_t;
337
317
-// Next values were defined according getnameinfo(3)
318
-#define NETDATA_MAX_NETWORK_COMBINED_LENGTH 1018
319
-#define NETDATA_DOTS_PROTOCOL_COMBINED_LENGTH 5 // :TCP:
320
-#define NETDATA_DIM_LENGTH_WITHOUT_SERVICE_PROTOCOL 979
321
-
322
-#define NETDATA_INBOUND_DIRECTION (uint32_t)1
323
-#define NETDATA_OUTBOUND_DIRECTION (uint32_t)2
324
-/**
325
- * Allocate the maximum number of structures in the beginning, this can force the collector to use more memory
326
- * in the long term, on the other had it is faster.
327
- */
328
-typedef struct netdata_socket_plot {
329
- // Search
330
- avl_t avl;
331
- netdata_socket_idx_t index;
332
-
333
- // Current data
334
- netdata_socket_t sock;
335
-
336
- // Previous values and values used to write on chart.
337
- netdata_plot_values_t plot;
338
-
339
- int family; // AF_INET or AF_INET6
340
- char *resolved_name; // Resolve only in the first call
341
- unsigned char resolved;
342
-
343
- char *dimension_sent;
344
- char *dimension_recv;
345
- char *dimension_retransmit;
346
-
347
- uint32_t flags;
348
-} netdata_socket_plot_t;
349
-
350
-#define NETWORK_VIEWER_CHARTS_CREATED (uint32_t)1
351
-typedef struct netdata_vector_plot {
352
- netdata_socket_plot_t *plot; // Vector used to plot charts
353
-
354
- avl_tree_lock tree; // AVL tree to speed up search
355
- uint32_t last; // The 'other' dimension, the last chart accepted.
356
- uint32_t next; // The next position to store in the vector.
357
- uint32_t max_plot; // Max number of elements to plot.
358
- uint32_t last_plot; // Last element plot
359
-
360
- uint32_t flags; // Flags
361
-
362
-} netdata_vector_plot_t;
363
-
364
-void clean_port_structure(ebpf_network_viewer_port_list_t **clean);
338
+void ebpf_clean_port_structure(ebpf_network_viewer_port_list_t **clean);
339
extern ebpf_network_viewer_port_list_t *listen_ports;
340
void update_listen_table(uint16_t value, uint16_t proto, netdata_passive_connection_t *values);
367
-void parse_network_viewer_section(struct config *cfg);
368
-void ebpf_fill_ip_list(ebpf_network_viewer_ip_list_t **out, ebpf_network_viewer_ip_list_t *in, char *table);
369
-void parse_service_name_section(struct config *cfg);
341
+void ebpf_fill_ip_list_unsafe(ebpf_network_viewer_ip_list_t **out, ebpf_network_viewer_ip_list_t *in, char *table);
342
+void ebpf_parse_service_name_section(struct config *cfg);
343
+void ebpf_parse_ips_unsafe(char *ptr);
344
+void ebpf_parse_ports(char *ptr);
345
+void ebpf_socket_read_open_connections(BUFFER *buf, struct ebpf_module *em);
346
+void ebpf_socket_fill_publish_apps(uint32_t current_pid, netdata_socket_t *ns);
347
+
348
349
extern struct config socket_config;
350
extern netdata_ebpf_targets_t socket_targets[];
collectors/ebpf.plugin/ebpf_swap.c
+1
-9
@@ -124,13 +124,6 @@ static int ebpf_swap_attach_kprobe(struct swap_bpf *obj)
124
if (ret)
125
return -1;
126
127
- obj->links.netdata_release_task_probe = bpf_program__attach_kprobe(obj->progs.netdata_release_task_probe,
128
- false,
129
- EBPF_COMMON_FNCT_CLEAN_UP);
130
- ret = libbpf_get_error(obj->links.netdata_swap_writepage_probe);
131
- if (ret)
132
- return -1;
133
-
127
return 0;
128
}
129
@@ -176,7 +169,6 @@ static void ebpf_swap_adjust_map(struct swap_bpf *obj, ebpf_module_t *em)
169
static void ebpf_swap_disable_release_task(struct swap_bpf *obj)
170
{
171
bpf_program__set_autoload(obj->progs.netdata_release_task_fentry, false);
179
- bpf_program__set_autoload(obj->progs.netdata_release_task_probe, false);
172
}
173
174
/**
@@ -959,7 +951,7 @@ static int ebpf_swap_load_bpf(ebpf_module_t *em)
951
#endif
952
953
if (ret)
962
- netdata_log_error("%s %s", EBPF_DEFAULT_ERROR_MSG, em->thread_name);
954
+ netdata_log_error("%s %s", EBPF_DEFAULT_ERROR_MSG, em->info.thread_name);
955
956
return ret;
957
}
collectors/ebpf.plugin/ebpf_sync.c
+5
-5
@@ -383,7 +383,7 @@ static void ebpf_sync_exit(void *ptr)
383
*/
384
static int ebpf_sync_load_legacy(ebpf_sync_syscalls_t *w, ebpf_module_t *em)
385
{
386
- em->thread_name = w->syscall;
386
+ em->info.thread_name = w->syscall;
387
if (!w->probe_links) {
388
w->probe_links = ebpf_load_program(ebpf_plugin_dir, em, running_on_kernel, isrh, &w->objects);
389
if (!w->probe_links) {
@@ -413,7 +413,7 @@ static int ebpf_sync_initialize_syscall(ebpf_module_t *em)
413
#endif
414
415
int i;
416
- const char *saved_name = em->thread_name;
416
+ const char *saved_name = em->info.thread_name;
417
int errors = 0;
418
for (i = 0; local_syscalls[i].syscall; i++) {
419
ebpf_sync_syscalls_t *w = &local_syscalls[i];
@@ -424,7 +424,7 @@ static int ebpf_sync_initialize_syscall(ebpf_module_t *em)
424
if (ebpf_sync_load_legacy(w, em))
425
errors++;
426
427
- em->thread_name = saved_name;
427
+ em->info.thread_name = saved_name;
428
}
429
#ifdef LIBBPF_MAJOR_VERSION
430
else {
@@ -446,12 +446,12 @@ static int ebpf_sync_initialize_syscall(ebpf_module_t *em)
446
w->enabled = false;
447
}
448
449
- em->thread_name = saved_name;
449
+ em->info.thread_name = saved_name;
450
}
451
#endif
452
}
453
}
454
- em->thread_name = saved_name;
454
+ em->info.thread_name = saved_name;
455
456
memset(sync_counter_aggregated_data, 0 , NETDATA_SYNC_IDX_END * sizeof(netdata_syscall_stat_t));
457
memset(sync_counter_publish_aggregated, 0 , NETDATA_SYNC_IDX_END * sizeof(netdata_publish_syscall_t));
collectors/ebpf.plugin/ebpf_unittest.c
+6
-6
@@ -12,8 +12,8 @@ ebpf_module_t test_em;
12
void ebpf_ut_initialize_structure(netdata_run_mode_t mode)
13
{
14
memset(&test_em, 0, sizeof(ebpf_module_t));
15
- test_em.thread_name = strdupz("process");
16
- test_em.config_name = test_em.thread_name;
15
+ test_em.info.thread_name = strdupz("process");
16
+ test_em.info.config_name = test_em.info.thread_name;
17
test_em.kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_10 |
18
NETDATA_V5_14;
19
test_em.pid_map_size = ND_EBPF_DEFAULT_PID_SIZE;
@@ -28,7 +28,7 @@ void ebpf_ut_initialize_structure(netdata_run_mode_t mode)
28
*/
29
void ebpf_ut_cleanup_memory()
30
{
31
- freez((void *)test_em.thread_name);
31
+ freez((void *)test_em.info.thread_name);
32
}
33
34
/**
@@ -70,14 +70,14 @@ int ebpf_ut_load_real_binary()
70
*/
71
int ebpf_ut_load_fake_binary()
72
{
73
- const char *original = test_em.thread_name;
73
+ const char *original = test_em.info.thread_name;
74
75
- test_em.thread_name = strdupz("I_am_not_here");
75
+ test_em.info.thread_name = strdupz("I_am_not_here");
76
int ret = ebpf_ut_load_binary();
77
78
ebpf_ut_cleanup_memory();
79
80
- test_em.thread_name = original;
80
+ test_em.info.thread_name = original;
81
82
return !ret;
83
}
docs/cloud/netdata-functions.md
+2
-1
@@ -33,7 +33,8 @@ functions - [plugins.d](https://github.com/netdata/netdata/blob/master/collector
33
| Function | Description | plugin - module |
34
| :-- | :-- | :-- |
35
| processes | Detailed information on the currently running processes on the node. | [apps.plugin](https://github.com/netdata/netdata/blob/master/collectors/apps.plugin/README.md) |
36
-| ebpf_thread | Controller for eBPF threads. | [ebpf.plugin](https://github.com/netdata/netdata/blob/master/collectors/ebpf.plugin/README.md) |
36
+| ebpf_socket | Detailed socket information. | [ebpf.plugin](https://github.com/netdata/netdata/blob/master/collectors/ebpf.plugin/README.md#ebpf_thread) |
37
+| ebpf_thread | Controller for eBPF threads. | [ebpf.plugin](https://github.com/netdata/netdata/blob/master/collectors/ebpf.plugin/README.md#ebpf_socket) |
38
39
If you have ideas or requests for other functions:
40
* Participate in the relevant [GitHub discussion](https://github.com/netdata/netdata/discussions/14412)
libnetdata/ebpf/ebpf.c
+5
-5
@@ -792,13 +792,13 @@ void ebpf_update_controller(int fd, ebpf_module_t *em)
792
{
793
uint32_t values[NETDATA_CONTROLLER_END] = {
794
(em->apps_charts & NETDATA_EBPF_APPS_FLAG_YES) | em->cgroup_charts,
795
- em->apps_level
795
+ em->apps_level, 0, 0, 0, 0
796
};
797
uint32_t key;
798
- uint32_t end = (em->apps_level != NETDATA_APPS_NOT_SET) ? NETDATA_CONTROLLER_END : NETDATA_CONTROLLER_APPS_LEVEL;
798
+ uint32_t end = NETDATA_CONTROLLER_PID_TABLE_ADD;
799
800
for (key = NETDATA_CONTROLLER_APPS_ENABLED; key < end; key++) {
801
- int ret = bpf_map_update_elem(fd, &key, &values[key], 0);
801
+ int ret = bpf_map_update_elem(fd, &key, &values[key], BPF_ANY);
802
if (ret)
803
netdata_log_error("Add key(%u) for controller table failed.", key);
804
}
@@ -855,7 +855,7 @@ struct bpf_link **ebpf_load_program(char *plugins_dir, ebpf_module_t *em, int kv
855
856
uint32_t idx = ebpf_select_index(em->kernels, is_rhf, kver);
857
858
- ebpf_mount_name(lpath, 4095, plugins_dir, idx, em->thread_name, em->mode, is_rhf);
858
+ ebpf_mount_name(lpath, 4095, plugins_dir, idx, em->info.thread_name, em->mode, is_rhf);
859
860
// When this function is called ebpf.plugin is using legacy code, so we should reset the variable
861
em->load &= ~ NETDATA_EBPF_LOAD_METHODS;
@@ -1269,7 +1269,7 @@ void ebpf_update_module_using_config(ebpf_module_t *modules, netdata_ebpf_load_m
1269
1270
#ifdef NETDATA_DEV_MODE
1271
netdata_log_info("The thread %s was configured with: mode = %s; update every = %d; apps = %s; cgroup = %s; ebpf type format = %s; ebpf co-re tracing = %s; collect pid = %s; maps per core = %s, lifetime=%u",
1272
- modules->thread_name,
1272
+ modules->info.thread_name,
1273
load_mode,
1274
modules->update_every,
1275
(modules->apps_charts)?"enabled":"disabled",
libnetdata/ebpf/ebpf.h
+20
-5
@@ -301,11 +301,27 @@ enum ebpf_global_table_values {
301
typedef uint64_t netdata_idx_t;
302
303
typedef struct ebpf_module {
304
- const char *thread_name;
305
- const char *config_name;
306
- const char *thread_description;
304
+ // Constants used with module
305
+ struct {
306
+ const char *thread_name;
307
+ const char *config_name;
308
+ const char *thread_description;
309
+ } info;
310
+
311
+ // Helpers used with plugin
312
+ struct {
313
+ void *(*start_routine)(void *); // the thread function
314
+ void (*apps_routine)(struct ebpf_module *em, void *ptr); // the apps charts
315
+ void (*fnct_routine)(BUFFER *bf, struct ebpf_module *em); // the function used for exteernal requests
316
+ const char *fcnt_name; // name given to cloud
317
+ const char *fcnt_desc; // description given about function
318
+ const char *fcnt_thread_chart_name;
319
+ int order_thread_chart;
320
+ const char *fcnt_thread_lifetime_name;
321
+ int order_thread_lifetime;
322
+ } functions;
323
+
324
enum ebpf_threads_status enabled;
308
- void *(*start_routine)(void *);
325
int update_every;
326
int global_charts;
327
netdata_apps_integration_flags_t apps_charts;
@@ -314,7 +330,6 @@ typedef struct ebpf_module {
330
netdata_run_mode_t mode;
331
uint32_t thread_id;
332
int optional;
317
- void (*apps_routine)(struct ebpf_module *em, void *ptr);
333
ebpf_local_maps_t *maps;
334
ebpf_specify_name_t *names;
335
uint32_t pid_map_size;
packaging/ebpf-co-re.checksums
+1
-1
@@ -1 +1 @@
1
-2abbbaf30a73e1ed365d42324a5128470568b008528c3ff8cd98d5eb86152f03 netdata-ebpf-co-re-glibc-v1.2.1.tar.xz
1
+7ef8d2a0f485b4c81942f66c50e1aedcd568b7997a933c50c0ebbd8353543c08 netdata-ebpf-co-re-glibc-v1.2.8.tar.xz
packaging/ebpf-co-re.version
+1
-1
@@ -1 +1 @@
1
-v1.2.1
1
+v1.2.8
packaging/ebpf.checksums
+3
-3
@@ -1,3 +1,3 @@
1
-cb0cd6ef4bdb8a39c42b152d328d4822217c59e1d616d3003bc67bc53a058275 ./netdata-kernel-collector-glibc-v1.2.1.tar.xz
2
-0633ff39e8654a21ab664a289f58daca5792cfaf2ed62dcaacf7cd267eeedd40 ./netdata-kernel-collector-musl-v1.2.1.tar.xz
3
-6ce60c5ac8f45cc6a01b7ac9ea150728963d0aca1ee6dfd568b0f8b2ba67b88b ./netdata-kernel-collector-static-v1.2.1.tar.xz
1
+9035b6b8dda5230c1ddc44991518a3ee069bd497ad5a8e5448b79dc4b8c51c43 ./netdata-kernel-collector-glibc-v1.2.8.tar.xz
2
+e5b1a141475f75c60c282a2e3ce8e3914893e75d474c976bad95f66d4c9846c5 ./netdata-kernel-collector-musl-v1.2.8.tar.xz
3
+d6081a2fedc9435d1ab430697cb101123cebaac07b62fb91d790ca526923f4e3 ./netdata-kernel-collector-static-v1.2.8.tar.xz
packaging/ebpf.version
+1
-1
@@ -1 +1 @@
1
-v1.2.1
1
+v1.2.8