CO-RE and syscalls (#12318)
thiagoftsm committed
Mar 8, 2022 at 17:49 UTC
6123a8e1a66aa1c3d44e454f866588495b5a145e
23 files changed
+1085
-40
.gitignore
+1
@@ -72,6 +72,7 @@ cgroup-network
72
ebpf.plugin
73
collectors/ebpf.plugin/reset_netdata_trace.sh
74
!ebpf.plugin/
75
+collectors/ebpf.plugin/includes/
76
77
# protoc generated files
78
*.pb.cc
Makefile.am
+1
@@ -61,6 +61,7 @@ dist_noinst_DATA = \
61
netdata.cppcheck \
62
netdata.spec \
63
packaging/bundle-ebpf.sh \
64
+ packaging/bundle-ebpf-co-re.sh \
65
packaging/bundle-judy.sh \
66
packaging/bundle-libbpf.sh \
67
packaging/check-kernel-config.sh \
collectors/ebpf.plugin/ebpf.c
+78
-16
@@ -68,7 +68,7 @@ ebpf_module_t ebpf_modules[] = {
68
.config_file = NETDATA_SYNC_CONFIG_FILE,
69
// All syscalls have the same kernels
70
.kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4,
71
- .load = EBPF_LOAD_LEGACY, .targets = NULL},
71
+ .load = EBPF_LOAD_LEGACY, .targets = sync_targets},
72
{ .thread_name = "dc", .config_name = "dc", .enabled = 0, .start_routine = ebpf_dcstat_thread,
73
.update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = CONFIG_BOOLEAN_NO,
74
.cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
@@ -113,7 +113,7 @@ ebpf_module_t ebpf_modules[] = {
113
.pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &mount_config,
114
.config_file = NETDATA_MOUNT_CONFIG_FILE,
115
.kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4,
116
- .load = EBPF_LOAD_LEGACY, .targets = NULL},
116
+ .load = EBPF_LOAD_LEGACY, .targets = mount_targets},
117
{ .thread_name = "fd", .config_name = "fd", .enabled = 0, .start_routine = ebpf_fd_thread,
118
.update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = CONFIG_BOOLEAN_NO,
119
.cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
@@ -151,7 +151,7 @@ ebpf_module_t ebpf_modules[] = {
151
.pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &shm_config,
152
.config_file = NETDATA_DIRECTORY_SHM_CONFIG_FILE,
153
.kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4,
154
- .load = EBPF_LOAD_LEGACY, .targets = NULL},
154
+ .load = EBPF_LOAD_LEGACY, .targets = shm_targets},
155
{ .thread_name = "mdflush", .config_name = "mdflush", .enabled = 0, .start_routine = ebpf_mdflush_thread,
156
.update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = CONFIG_BOOLEAN_NO,
157
.cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0, .apps_routine = NULL, .maps = NULL,
@@ -181,6 +181,11 @@ ebpf_network_viewer_options_t network_viewer_opt;
181
ebpf_plugin_stats_t plugin_statistics = {.core = 0, .legacy = 0, .running = 0, .threads = 0, .tracepoints = 0,
182
.probes = 0, .retprobes = 0, .trampolines = 0};
183
184
+#ifdef LIBBPF_MAJOR_VERSION
185
+struct btf *default_btf = NULL;
186
+#endif
187
+char *btf_path = NULL;
188
+
189
/*****************************************************************
190
*
191
* FUNCTIONS USED TO CLEAN MEMORY AND OPERATE SYSTEM FILES
@@ -290,6 +295,11 @@ static void ebpf_exit(int sig)
295
}
296
*/
297
298
+#ifdef LIBBPF_MAJOR_VERSION
299
+ if (default_btf)
300
+ btf__free(default_btf);
301
+#endif
302
+
303
exit(sig);
304
}
305
@@ -1116,6 +1126,56 @@ static void ebpf_update_table_size()
1126
}
1127
}
1128
1129
+/**
1130
+ * Set Load mode
1131
+ *
1132
+ * @param load default load mode.
1133
+ */
1134
+static inline void ebpf_set_load_mode(netdata_ebpf_load_mode_t load)
1135
+{
1136
+#ifdef LIBBPF_MAJOR_VERSION
1137
+ if (load == EBPF_LOAD_CORE || load == EBPF_LOAD_PLAY_DICE) {
1138
+ load = (!default_btf) ? EBPF_LOAD_LEGACY : EBPF_LOAD_CORE;
1139
+ }
1140
+#else
1141
+ load = EBPF_LOAD_LEGACY;
1142
+#endif
1143
+
1144
+ int i;
1145
+ for (i = 0; ebpf_modules[i].thread_name; i++) {
1146
+ // TO DO: Use `load` variable after we change all threads.
1147
+ ebpf_modules[i].load = EBPF_LOAD_LEGACY; // load ;
1148
+ }
1149
+}
1150
+
1151
+/**
1152
+ * Update mode
1153
+ *
1154
+ * @param str value read from configuration file.
1155
+ */
1156
+static inline void epbf_update_load_mode(char *str)
1157
+{
1158
+ netdata_ebpf_load_mode_t load = epbf_convert_string_to_load_mode(str);
1159
+
1160
+ ebpf_set_load_mode(load);
1161
+}
1162
+
1163
+#ifdef LIBBPF_MAJOR_VERSION
1164
+/**
1165
+ * Set default btf file
1166
+ *
1167
+ * Load the default BTF file on environment.
1168
+ */
1169
+static void ebpf_set_default_btf_file()
1170
+{
1171
+ char path[PATH_MAX + 1];
1172
+ snprintfz(path, PATH_MAX, "%s/vmlinux", btf_path);
1173
+ default_btf = ebpf_parse_btf_file(path);
1174
+ if (!default_btf)
1175
+ info("Your environment does not have BTF file %s/vmlinux. The plugin will work with 'legacy' code.",
1176
+ btf_path);
1177
+}
1178
+#endif
1179
1180
/**
1181
* Read collector values
@@ -1137,6 +1197,17 @@ static void read_collector_values(int *disable_apps, int *disable_cgroups, int u
1197
1198
how_to_load(value);
1199
1200
+ btf_path = appconfig_get(&collector_config, EBPF_GLOBAL_SECTION, EBPF_CFG_PROGRAM_PATH,
1201
+ EBPF_DEFAULT_BTF_FILE);
1202
+
1203
+#ifdef LIBBPF_MAJOR_VERSION
1204
+ ebpf_set_default_btf_file();
1205
+#endif
1206
+
1207
+ value = appconfig_get(&collector_config, EBPF_GLOBAL_SECTION, EBPF_CFG_TYPE_FORMAT, EBPF_CFG_DEFAULT_PROGRAM);
1208
+
1209
+ epbf_update_load_mode(value);
1210
+
1211
ebpf_update_interval(update_every);
1212
1213
ebpf_update_table_size();
@@ -1372,19 +1443,6 @@ static inline void ebpf_load_thread_config()
1443
}
1444
}
1445
1375
-/**
1376
- * Set Load mode
1377
- *
1378
- * @param load default load mode.
1379
- */
1380
-static inline void ebpf_set_load_mode(netdata_ebpf_load_mode_t load)
1381
-{
1382
- int i;
1383
- for (i = 0; ebpf_modules[i].thread_name; i++) {
1384
- ebpf_modules[i].load = load;
1385
- }
1386
-}
1387
-
1446
/**
1447
* Parse arguments given from user.
1448
*
@@ -1842,6 +1900,10 @@ int main(int argc, char **argv)
1900
1901
ebpf_allocate_common_vectors();
1902
1903
+#ifdef LIBBPF_MAJOR_VERSION
1904
+ libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
1905
+#endif
1906
+
1907
read_local_addresses();
1908
read_local_ports("/proc/net/tcp", IPPROTO_TCP);
1909
read_local_ports("/proc/net/tcp6", IPPROTO_TCP);
collectors/ebpf.plugin/ebpf.d/mount.conf
+12
-1
@@ -3,6 +3,17 @@
3
# `return : In the `return` mode, the eBPF collector monitors the same kernel functions as `entry`, but also creates
4
# new charts for the return of these functions, such as errors.
5
#
6
-#[global]
6
+# The `ebpf type format` option accepts the following values :
7
+# `auto` : The eBPF collector will investigate hardware and select between the two next options.
8
+# `legacy`: The eBPF collector will load the legacy code. Note: This has a bigger overload.
9
+# `co-re` : The eBPF collector will use latest tracing method. Note: This is not available on all platforms.
10
+#
11
+# The `ebpf co-re tracing` option accepts the following values:
12
+# `trampoline`: This is the default mode used by the eBPF collector, due the small overhead added to host.
13
+# `tracepoint`: When available, the eBPF collector will use kernel tracepoint to monitor syscall.
14
+# `probe` : This is the same as legacy code.
15
+[global]
16
# ebpf load mode = entry
17
# update every = 1
18
+ ebpf type format = auto
19
+ ebpf co-re tracing = trampoline
collectors/ebpf.plugin/ebpf.d/shm.conf
+13
-1
@@ -8,13 +8,25 @@
8
# If you want to disable the integration with `apps.plugin` or `cgroups.plugin` along with the above charts, change
9
# the setting `apps` and `cgroups` to 'no'.
10
#
11
+# The `ebpf type format` option accepts the following values :
12
+# `auto` : The eBPF collector will investigate hardware and select between the two next options.
13
+# `legacy`: The eBPF collector will load the legacy code. Note: This has a bigger overload.
14
+# `co-re` : The eBPF collector will use latest tracing method. Note: This is not available on all platforms.
15
+#
16
+# The `ebpf co-re tracing` option accepts the following values:
17
+# `trampoline`: This is the default mode used by the eBPF collector, due the small overhead added to host.
18
+# `tracepoint`: When available, the eBPF collector will use kernel tracepoint to monitor syscall.
19
+# `probe` : This is the same as legacy code.
20
+#
21
# Uncomment lines to define specific options for thread.
12
-#[global]
22
+[global]
23
# ebpf load mode = entry
24
# apps = yes
25
# cgroups = no
26
# update every = 10
27
# pid table size = 32768
28
+ ebpf type format = auto
29
+ ebpf co-re tracing = trampoline
30
31
# List of monitored syscalls
32
[syscalls]
collectors/ebpf.plugin/ebpf.d/sync.conf
+12
-1
@@ -8,12 +8,23 @@
8
# If you want to disable the integration with `apps.plugin` or `cgroups.plugin` along with the above charts, change
9
# the setting `apps` and `cgroups` to 'no'.
10
#
11
+# The `ebpf type format` option accepts the following values :
12
+# `auto` : The eBPF collector will investigate hardware and select between the two next options.
13
+# `legacy`: The eBPF collector will load the legacy code. Note: This has a bigger overload.
14
+# `co-re` : The eBPF collector will use latest tracing method. Note: This is not available on all platforms.
15
+#
16
+# The `ebpf co-re tracing` option accepts the following values:
17
+# `trampoline`: This is the default mode used by the eBPF collector, due the small overhead added to host.
18
+# `tracepoint`: When available, the eBPF collector will use kernel tracepoint to monitor syscall.
19
+# `probe` : This is the same as legacy code.
20
#
12
-#[global]
21
+[global]
22
# ebpf load mode = entry
23
# apps = yes
24
# cgroups = no
25
# update every = 10
26
+ ebpf type format = auto
27
+ ebpf co-re tracing = trampoline
28
29
# List of monitored syscalls
30
[syscalls]
collectors/ebpf.plugin/ebpf.h
+1
@@ -264,6 +264,7 @@ extern pthread_mutex_t mutex_cgroup_shm;
264
extern size_t all_pids_count;
265
extern uint32_t finalized_threads;
266
extern ebpf_plugin_stats_t plugin_statistics;
267
+extern struct btf *default_btf;
268
269
// Socket functions and variables
270
// Common functions
collectors/ebpf.plugin/ebpf_mount.c
+232
-2
@@ -30,6 +30,196 @@ struct netdata_static_thread mount_thread = {"MOUNT KERNEL",
30
NULL, NULL, 1, NULL,
31
NULL, NULL};
32
33
+netdata_ebpf_targets_t mount_targets[] = { {.name = "mount", .mode = EBPF_LOAD_TRAMPOLINE},
34
+ {.name = "umount", .mode = EBPF_LOAD_TRAMPOLINE},
35
+ {.name = NULL, .mode = EBPF_LOAD_TRAMPOLINE}};
36
+
37
+#ifdef LIBBPF_MAJOR_VERSION
38
+#include "includes/mount.skel.h" // BTF code
39
+
40
+static struct mount_bpf *bpf_obj = NULL;
41
+
42
+/*****************************************************************
43
+ *
44
+ * BTF FUNCTIONS
45
+ *
46
+ *****************************************************************/
47
+
48
+/*
49
+ * Disable probe
50
+ *
51
+ * Disable all probes to use exclusively another method.
52
+ *
53
+ * @param obj is the main structure for bpf objects.
54
+ */
55
+static inline void ebpf_mount_disable_probe(struct mount_bpf *obj)
56
+{
57
+ bpf_program__set_autoload(obj->progs.netdata_mount_probe, false);
58
+ bpf_program__set_autoload(obj->progs.netdata_umount_probe, false);
59
+
60
+ bpf_program__set_autoload(obj->progs.netdata_mount_retprobe, false);
61
+ bpf_program__set_autoload(obj->progs.netdata_umount_retprobe, false);
62
+}
63
+
64
+/*
65
+ * Disable tracepoint
66
+ *
67
+ * Disable all tracepoints to use exclusively another method.
68
+ *
69
+ * @param obj is the main structure for bpf objects.
70
+ */
71
+static inline void ebpf_mount_disable_tracepoint(struct mount_bpf *obj)
72
+{
73
+ bpf_program__set_autoload(obj->progs.netdata_mount_exit, false);
74
+ bpf_program__set_autoload(obj->progs.netdata_umount_exit, false);
75
+}
76
+
77
+/*
78
+ * Disable trampoline
79
+ *
80
+ * Disable all trampoline to use exclusively another method.
81
+ *
82
+ * @param obj is the main structure for bpf objects.
83
+ */
84
+static inline void ebpf_mount_disable_trampoline(struct mount_bpf *obj)
85
+{
86
+ bpf_program__set_autoload(obj->progs.netdata_mount_fentry, false);
87
+ bpf_program__set_autoload(obj->progs.netdata_umount_fentry, false);
88
+ bpf_program__set_autoload(obj->progs.netdata_mount_fexit, false);
89
+ bpf_program__set_autoload(obj->progs.netdata_umount_fexit, false);
90
+}
91
+
92
+/**
93
+ * Set trampoline target
94
+ *
95
+ * Set the targets we will monitor.
96
+ *
97
+ * @param obj is the main structure for bpf objects.
98
+ */
99
+static inline void netdata_set_trampoline_target(struct mount_bpf *obj)
100
+{
101
+ char syscall[NETDATA_EBPF_MAX_SYSCALL_LENGTH + 1];
102
+ ebpf_select_host_prefix(syscall, NETDATA_EBPF_MAX_SYSCALL_LENGTH,
103
+ mount_targets[NETDATA_MOUNT_SYSCALL].name, running_on_kernel);
104
+
105
+ bpf_program__set_attach_target(obj->progs.netdata_mount_fentry, 0,
106
+ syscall);
107
+
108
+ bpf_program__set_attach_target(obj->progs.netdata_mount_fexit, 0,
109
+ syscall);
110
+
111
+ ebpf_select_host_prefix(syscall, NETDATA_EBPF_MAX_SYSCALL_LENGTH,
112
+ mount_targets[NETDATA_UMOUNT_SYSCALL].name, running_on_kernel);
113
+
114
+ bpf_program__set_attach_target(obj->progs.netdata_umount_fentry, 0,
115
+ syscall);
116
+
117
+ bpf_program__set_attach_target(obj->progs.netdata_umount_fexit, 0,
118
+ syscall);
119
+}
120
+
121
+/**
122
+ * Mount Attach Probe
123
+ *
124
+ * Attach probes to target
125
+ *
126
+ * @param obj is the main structure for bpf objects.
127
+ *
128
+ * @return It returns 0 on success and -1 otherwise.
129
+ */
130
+static int ebpf_mount_attach_probe(struct mount_bpf *obj)
131
+{
132
+ char syscall[NETDATA_EBPF_MAX_SYSCALL_LENGTH + 1];
133
+
134
+ ebpf_select_host_prefix(syscall, NETDATA_EBPF_MAX_SYSCALL_LENGTH,
135
+ mount_targets[NETDATA_MOUNT_SYSCALL].name, running_on_kernel);
136
+
137
+ obj->links.netdata_mount_probe = bpf_program__attach_kprobe(obj->progs.netdata_mount_probe,
138
+ false, syscall);
139
+ int ret = (int)libbpf_get_error(obj->links.netdata_mount_probe);
140
+ if (ret)
141
+ return -1;
142
+
143
+ obj->links.netdata_mount_retprobe = bpf_program__attach_kprobe(obj->progs.netdata_mount_retprobe,
144
+ true, syscall);
145
+ ret = (int)libbpf_get_error(obj->links.netdata_mount_retprobe);
146
+ if (ret)
147
+ return -1;
148
+
149
+ ebpf_select_host_prefix(syscall, NETDATA_EBPF_MAX_SYSCALL_LENGTH,
150
+ mount_targets[NETDATA_UMOUNT_SYSCALL].name, running_on_kernel);
151
+
152
+ obj->links.netdata_umount_probe = bpf_program__attach_kprobe(obj->progs.netdata_umount_probe,
153
+ false, syscall);
154
+ ret = (int)libbpf_get_error(obj->links.netdata_umount_probe);
155
+ if (ret)
156
+ return -1;
157
+
158
+ obj->links.netdata_umount_retprobe = bpf_program__attach_kprobe(obj->progs.netdata_umount_retprobe,
159
+ true, syscall);
160
+ ret = (int)libbpf_get_error(obj->links.netdata_umount_retprobe);
161
+ if (ret)
162
+ return -1;
163
+
164
+ return 0;
165
+}
166
+
167
+/**
168
+ * Set hash tables
169
+ *
170
+ * Set the values for maps according the value given by kernel.
171
+ *
172
+ * @param obj is the main structure for bpf objects.
173
+ */
174
+static void ebpf_mount_set_hash_tables(struct mount_bpf *obj)
175
+{
176
+ mount_maps[NETDATA_KEY_MOUNT_TABLE].map_fd = bpf_map__fd(obj->maps.tbl_mount);
177
+}
178
+
179
+/**
180
+ * Load and attach
181
+ *
182
+ * Load and attach the eBPF code in kernel.
183
+ *
184
+ * @param obj is the main structure for bpf objects.
185
+ * @param em structure with configuration
186
+ *
187
+ * @return it returns 0 on succes and -1 otherwise
188
+ */
189
+static inline int ebpf_mount_load_and_attach(struct mount_bpf *obj, ebpf_module_t *em)
190
+{
191
+ netdata_ebpf_targets_t *mt = em->targets;
192
+ netdata_ebpf_program_loaded_t test = mt[NETDATA_MOUNT_SYSCALL].mode;
193
+
194
+ // We are testing only one, because all will have the same behavior
195
+ if (test == EBPF_LOAD_TRAMPOLINE ) {
196
+ ebpf_mount_disable_probe(obj);
197
+ ebpf_mount_disable_tracepoint(obj);
198
+
199
+ netdata_set_trampoline_target(obj);
200
+ } else if (test == EBPF_LOAD_PROBE ||
201
+ test == EBPF_LOAD_RETPROBE ) {
202
+ ebpf_mount_disable_tracepoint(obj);
203
+ ebpf_mount_disable_trampoline(obj);
204
+ } else {
205
+ ebpf_mount_disable_probe(obj);
206
+ ebpf_mount_disable_trampoline(obj);
207
+ }
208
+
209
+ int ret = mount_bpf__load(obj);
210
+ if (!ret) {
211
+ if (test != EBPF_LOAD_PROBE && test != EBPF_LOAD_RETPROBE )
212
+ ret = mount_bpf__attach(obj);
213
+ else
214
+ ret = ebpf_mount_attach_probe(obj);
215
+
216
+ if (!ret)
217
+ ebpf_mount_set_hash_tables(obj);
218
+ }
219
+
220
+ return ret;
221
+}
222
+#endif
223
/*****************************************************************
224
*
225
* FUNCTIONS TO CLOSE THE THREAD
@@ -59,6 +249,11 @@ static void ebpf_mount_cleanup(void *ptr)
249
}
250
bpf_object__close(objects);
251
}
252
+#ifdef LIBBPF_MAJOR_VERSION
253
+ else if (bpf_obj)
254
+ mount_bpf__destroy(bpf_obj);
255
+#endif
256
+
257
}
258
259
/*****************************************************************
@@ -219,6 +414,39 @@ static void ebpf_create_mount_charts(int update_every)
414
*
415
*****************************************************************/
416
417
+/*
418
+ * Load BPF
419
+ *
420
+ * Load BPF files.
421
+ *
422
+ * @param em the structure with configuration
423
+ */
424
+static int ebpf_mount_load_bpf(ebpf_module_t *em)
425
+{
426
+ int ret = 0;
427
+ if (em->load == EBPF_LOAD_LEGACY) {
428
+ probe_links = ebpf_load_program(ebpf_plugin_dir, em, running_on_kernel, isrh, &objects);
429
+ if (!probe_links) {
430
+ em->enabled = CONFIG_BOOLEAN_NO;
431
+ ret = -1;
432
+ }
433
+ }
434
+#ifdef LIBBPF_MAJOR_VERSION
435
+ else {
436
+ bpf_obj = mount_bpf__open();
437
+ if (!bpf_obj)
438
+ ret = -1;
439
+ else
440
+ ret = ebpf_mount_load_and_attach(bpf_obj, em);
441
+ }
442
+#endif
443
+
444
+ if (ret)
445
+ error("%s %s", EBPF_DEFAULT_ERROR_MSG, em->thread_name);
446
+
447
+ return ret;
448
+}
449
+
450
/**
451
* Mount thread
452
*
@@ -238,8 +466,10 @@ void *ebpf_mount_thread(void *ptr)
466
if (!em->enabled)
467
goto endmount;
468
241
- probe_links = ebpf_load_program(ebpf_plugin_dir, em, running_on_kernel, isrh, &objects);
242
- if (!probe_links) {
469
+#ifdef LIBBPF_MAJOR_VERSION
470
+ ebpf_adjust_thread_load(em, default_btf);
471
+#endif
472
+ if (ebpf_mount_load_bpf(em)) {
473
em->enabled = CONFIG_BOOLEAN_NO;
474
goto endmount;
475
}
collectors/ebpf.plugin/ebpf_mount.h
+8
@@ -30,7 +30,15 @@ enum mount_tables {
30
NETDATA_KEY_MOUNT_TABLE
31
};
32
33
+enum netdata_mount_syscalls {
34
+ NETDATA_MOUNT_SYSCALL,
35
+ NETDATA_UMOUNT_SYSCALL,
36
+
37
+ NETDATA_MOUNT_SYSCALLS_END
38
+};
39
+
40
extern struct config mount_config;
41
extern void *ebpf_mount_thread(void *ptr);
42
+extern netdata_ebpf_targets_t mount_targets[];
43
44
#endif /* NETDATA_EBPF_MOUNT_H */
collectors/ebpf.plugin/ebpf_shm.c
+239
-2
@@ -41,6 +41,203 @@ static struct bpf_object *objects = NULL;
41
struct netdata_static_thread shm_threads = {"SHM KERNEL", NULL, NULL, 1,
42
NULL, NULL, NULL};
43
44
+netdata_ebpf_targets_t shm_targets[] = { {.name = "shmget", .mode = EBPF_LOAD_TRAMPOLINE},
45
+ {.name = "shmat", .mode = EBPF_LOAD_TRAMPOLINE},
46
+ {.name = "shmdt", .mode = EBPF_LOAD_TRAMPOLINE},
47
+ {.name = "shmctl", .mode = EBPF_LOAD_TRAMPOLINE},
48
+ {.name = NULL, .mode = EBPF_LOAD_TRAMPOLINE}};
49
+
50
+#ifdef LIBBPF_MAJOR_VERSION
51
+#include "includes/shm.skel.h"
52
+
53
+static struct shm_bpf *bpf_obj = NULL;
54
+
55
+/*****************************************************************
56
+ *
57
+ * BTF FUNCTIONS
58
+ *
59
+ *****************************************************************/
60
+
61
+/*
62
+ * Disable tracepoint
63
+ *
64
+ * Disable all tracepoints to use exclusively another method.
65
+ *
66
+ * @param obj is the main structure for bpf objects.
67
+ */
68
+static void ebpf_shm_disable_tracepoint(struct shm_bpf *obj)
69
+{
70
+ bpf_program__set_autoload(obj->progs.netdata_syscall_shmget, false);
71
+ bpf_program__set_autoload(obj->progs.netdata_syscall_shmat, false);
72
+ bpf_program__set_autoload(obj->progs.netdata_syscall_shmdt, false);
73
+ bpf_program__set_autoload(obj->progs.netdata_syscall_shmctl, false);
74
+}
75
+
76
+/*
77
+ * Disable probe
78
+ *
79
+ * Disable all probes to use exclusively another method.
80
+ *
81
+ * @param obj is the main structure for bpf objects.
82
+ */
83
+static void ebpf_disable_probe(struct shm_bpf *obj)
84
+{
85
+ bpf_program__set_autoload(obj->progs.netdata_shmget_probe, false);
86
+ bpf_program__set_autoload(obj->progs.netdata_shmat_probe, false);
87
+ bpf_program__set_autoload(obj->progs.netdata_shmdt_probe, false);
88
+ bpf_program__set_autoload(obj->progs.netdata_shmctl_probe, false);
89
+}
90
+
91
+/*
92
+ * Disable trampoline
93
+ *
94
+ * Disable all trampoline to use exclusively another method.
95
+ *
96
+ * @param obj is the main structure for bpf objects.
97
+ */
98
+static void ebpf_disable_trampoline(struct shm_bpf *obj)
99
+{
100
+ bpf_program__set_autoload(obj->progs.netdata_shmget_fentry, false);
101
+ bpf_program__set_autoload(obj->progs.netdata_shmat_fentry, false);
102
+ bpf_program__set_autoload(obj->progs.netdata_shmdt_fentry, false);
103
+ bpf_program__set_autoload(obj->progs.netdata_shmctl_fentry, false);
104
+}
105
+
106
+/**
107
+ * Set trampoline target
108
+ *
109
+ * Set the targets we will monitor.
110
+ *
111
+ * @param obj is the main structure for bpf objects.
112
+ */
113
+static void ebpf_set_trampoline_target(struct shm_bpf *obj)
114
+{
115
+ char syscall[NETDATA_EBPF_MAX_SYSCALL_LENGTH + 1];
116
+ ebpf_select_host_prefix(syscall, NETDATA_EBPF_MAX_SYSCALL_LENGTH,
117
+ shm_targets[NETDATA_KEY_SHMGET_CALL].name, running_on_kernel);
118
+
119
+ bpf_program__set_attach_target(obj->progs.netdata_shmget_fentry, 0,
120
+ syscall);
121
+
122
+ ebpf_select_host_prefix(syscall, NETDATA_EBPF_MAX_SYSCALL_LENGTH,
123
+ shm_targets[NETDATA_KEY_SHMAT_CALL].name, running_on_kernel);
124
+ bpf_program__set_attach_target(obj->progs.netdata_shmat_fentry, 0,
125
+ syscall);
126
+
127
+ ebpf_select_host_prefix(syscall, NETDATA_EBPF_MAX_SYSCALL_LENGTH,
128
+ shm_targets[NETDATA_KEY_SHMDT_CALL].name, running_on_kernel);
129
+ bpf_program__set_attach_target(obj->progs.netdata_shmdt_fentry, 0,
130
+ syscall);
131
+
132
+ ebpf_select_host_prefix(syscall, NETDATA_EBPF_MAX_SYSCALL_LENGTH,
133
+ shm_targets[NETDATA_KEY_SHMCTL_CALL].name, running_on_kernel);
134
+ bpf_program__set_attach_target(obj->progs.netdata_shmctl_fentry, 0,
135
+ syscall);
136
+}
137
+
138
+/**
139
+ * SHM Attach Probe
140
+ *
141
+ * Attach probes to target
142
+ *
143
+ * @param obj is the main structure for bpf objects.
144
+ *
145
+ * @return It returns 0 on success and -1 otherwise.
146
+ */
147
+static int ebpf_shm_attach_probe(struct shm_bpf *obj)
148
+{
149
+ char syscall[NETDATA_EBPF_MAX_SYSCALL_LENGTH + 1];
150
+ ebpf_select_host_prefix(syscall, NETDATA_EBPF_MAX_SYSCALL_LENGTH,
151
+ shm_targets[NETDATA_KEY_SHMGET_CALL].name, running_on_kernel);
152
+
153
+ obj->links.netdata_shmget_probe = bpf_program__attach_kprobe(obj->progs.netdata_shmget_probe,
154
+ false, syscall);
155
+ int ret = (int)libbpf_get_error(obj->links.netdata_shmget_probe);
156
+ if (ret)
157
+ return -1;
158
+
159
+ ebpf_select_host_prefix(syscall, NETDATA_EBPF_MAX_SYSCALL_LENGTH,
160
+ shm_targets[NETDATA_KEY_SHMAT_CALL].name, running_on_kernel);
161
+ obj->links.netdata_shmat_probe = bpf_program__attach_kprobe(obj->progs.netdata_shmat_probe,
162
+ false, syscall);
163
+ ret = (int)libbpf_get_error(obj->links.netdata_shmat_probe);
164
+ if (ret)
165
+ return -1;
166
+
167
+ ebpf_select_host_prefix(syscall, NETDATA_EBPF_MAX_SYSCALL_LENGTH,
168
+ shm_targets[NETDATA_KEY_SHMDT_CALL].name, running_on_kernel);
169
+ obj->links.netdata_shmdt_probe = bpf_program__attach_kprobe(obj->progs.netdata_shmdt_probe,
170
+ false, syscall);
171
+ ret = (int)libbpf_get_error(obj->links.netdata_shmdt_probe);
172
+ if (ret)
173
+ return -1;
174
+
175
+ ebpf_select_host_prefix(syscall, NETDATA_EBPF_MAX_SYSCALL_LENGTH,
176
+ shm_targets[NETDATA_KEY_SHMCTL_CALL].name, running_on_kernel);
177
+ obj->links.netdata_shmctl_probe = bpf_program__attach_kprobe(obj->progs.netdata_shmctl_probe,
178
+ false, syscall);
179
+ ret = (int)libbpf_get_error(obj->links.netdata_shmctl_probe);
180
+ if (ret)
181
+ return -1;
182
+
183
+ return 0;
184
+}
185
+
186
+/**
187
+ * Set hash tables
188
+ *
189
+ * Set the values for maps according the value given by kernel.
190
+ */
191
+static void ebpf_shm_set_hash_tables(struct shm_bpf *obj)
192
+{
193
+ shm_maps[NETDATA_PID_SHM_TABLE].map_fd = bpf_map__fd(obj->maps.tbl_pid_shm);
194
+ shm_maps[NETDATA_SHM_CONTROLLER].map_fd = bpf_map__fd(obj->maps.shm_ctrl);
195
+ shm_maps[NETDATA_SHM_GLOBAL_TABLE].map_fd = bpf_map__fd(obj->maps.tbl_shm);
196
+}
197
+
198
+/**
199
+ * Load and attach
200
+ *
201
+ * Load and attach the eBPF code in kernel.
202
+ *
203
+ * @param obj is the main structure for bpf objects.
204
+ * @param em structure with configuration
205
+ *
206
+ * @return it returns 0 on succes and -1 otherwise
207
+ */
208
+static inline int ebpf_shm_load_and_attach(struct shm_bpf *obj, ebpf_module_t *em)
209
+{
210
+ netdata_ebpf_targets_t *shmt = em->targets;
211
+ netdata_ebpf_program_loaded_t test = shmt[NETDATA_KEY_SHMGET_CALL].mode;
212
+
213
+ // We are testing only one, because all will have the same behavior
214
+ if (test == EBPF_LOAD_TRAMPOLINE ) {
215
+ ebpf_shm_disable_tracepoint(obj);
216
+ ebpf_disable_probe(obj);
217
+
218
+ ebpf_set_trampoline_target(obj);
219
+ } else if (test == EBPF_LOAD_PROBE || test == EBPF_LOAD_RETPROBE ) {
220
+ ebpf_shm_disable_tracepoint(obj);
221
+ ebpf_disable_trampoline(obj);
222
+ } else {
223
+ ebpf_disable_probe(obj);
224
+ ebpf_disable_trampoline(obj);
225
+ }
226
+
227
+ int ret = shm_bpf__load(obj);
228
+ if (!ret) {
229
+ if (test != EBPF_LOAD_PROBE && test != EBPF_LOAD_RETPROBE)
230
+ shm_bpf__attach(obj);
231
+ else
232
+ ret = ebpf_shm_attach_probe(obj);
233
+
234
+ if (!ret)
235
+ ebpf_shm_set_hash_tables(obj);
236
+ }
237
+
238
+ return ret;
239
+}
240
+#endif
241
/*****************************************************************
242
* FUNCTIONS TO CLOSE THE THREAD
243
*****************************************************************/
@@ -91,6 +288,10 @@ static void ebpf_shm_cleanup(void *ptr)
288
}
289
bpf_object__close(objects);
290
}
291
+#ifdef LIBBPF_MAJOR_VERSION
292
+ else if (bpf_obj)
293
+ shm_bpf__destroy(bpf_obj);
294
+#endif
295
}
296
297
/*****************************************************************
@@ -802,6 +1003,40 @@ static void ebpf_create_shm_charts(int update_every)
1003
fflush(stdout);
1004
}
1005
1006
+/*
1007
+ * Load BPF
1008
+ *
1009
+ * Load BPF files.
1010
+ *
1011
+ * @param em the structure with configuration
1012
+ */
1013
+static int ebpf_shm_load_bpf(ebpf_module_t *em)
1014
+{
1015
+ int ret = 0;
1016
+ if (em->load == EBPF_LOAD_LEGACY) {
1017
+ probe_links = ebpf_load_program(ebpf_plugin_dir, em, running_on_kernel, isrh, &objects);
1018
+ if (!probe_links) {
1019
+ em->enabled = CONFIG_BOOLEAN_NO;
1020
+ ret = -1;
1021
+ }
1022
+ }
1023
+#ifdef LIBBPF_MAJOR_VERSION
1024
+ else {
1025
+ bpf_obj = shm_bpf__open();
1026
+ if (!bpf_obj)
1027
+ ret = -1;
1028
+ else
1029
+ ret = ebpf_shm_load_and_attach(bpf_obj, em);
1030
+ }
1031
+#endif
1032
+
1033
+
1034
+ if (ret)
1035
+ error("%s %s", EBPF_DEFAULT_ERROR_MSG, em->thread_name);
1036
+
1037
+ return ret;
1038
+}
1039
+
1040
/**
1041
* Shared memory thread.
1042
*
@@ -821,8 +1056,10 @@ void *ebpf_shm_thread(void *ptr)
1056
goto endshm;
1057
}
1058
824
- probe_links = ebpf_load_program(ebpf_plugin_dir, em, running_on_kernel, isrh, &objects);
825
- if (!probe_links) {
1059
+#ifdef LIBBPF_MAJOR_VERSION
1060
+ ebpf_adjust_thread_load(em, default_btf);
1061
+#endif
1062
+ if (ebpf_shm_load_bpf(em)) {
1063
em->enabled = CONFIG_BOOLEAN_NO;
1064
goto endshm;
1065
}
collectors/ebpf.plugin/ebpf_shm.h
+1
@@ -57,6 +57,7 @@ extern netdata_publish_shm_t **shm_pid;
57
extern void *ebpf_shm_thread(void *ptr);
58
extern void ebpf_shm_create_apps_charts(struct ebpf_module *em, void *ptr);
59
extern void clean_shm_pid_structures();
60
+extern netdata_ebpf_targets_t shm_targets[];
61
62
extern struct config shm_config;
63
collectors/ebpf.plugin/ebpf_sync.c
+194
-11
@@ -44,21 +44,179 @@ struct config sync_config = { .first_section = NULL,
44
.rwlock = AVL_LOCK_INITIALIZER } };
45
46
ebpf_sync_syscalls_t local_syscalls[] = {
47
- {.syscall = "sync", .enabled = CONFIG_BOOLEAN_YES, .objects = NULL, .probe_links = NULL},
48
- {.syscall = "syncfs", .enabled = CONFIG_BOOLEAN_YES, .objects = NULL, .probe_links = NULL},
49
- {.syscall = "msync", .enabled = CONFIG_BOOLEAN_YES, .objects = NULL, .probe_links = NULL},
50
- {.syscall = "fsync", .enabled = CONFIG_BOOLEAN_YES, .objects = NULL, .probe_links = NULL},
51
- {.syscall = "fdatasync", .enabled = CONFIG_BOOLEAN_YES, .objects = NULL, .probe_links = NULL},
52
- {.syscall = "sync_file_range", .enabled = CONFIG_BOOLEAN_YES, .objects = NULL, .probe_links = NULL},
47
+ {.syscall = NETDATA_SYSCALLS_SYNC, .enabled = CONFIG_BOOLEAN_YES, .objects = NULL, .probe_links = NULL},
48
+ {.syscall = NETDATA_SYSCALLS_SYNCFS, .enabled = CONFIG_BOOLEAN_YES, .objects = NULL, .probe_links = NULL},
49
+ {.syscall = NETDATA_SYSCALLS_MSYNC, .enabled = CONFIG_BOOLEAN_YES, .objects = NULL, .probe_links = NULL},
50
+ {.syscall = NETDATA_SYSCALLS_FSYNC, .enabled = CONFIG_BOOLEAN_YES, .objects = NULL, .probe_links = NULL},
51
+ {.syscall = NETDATA_SYSCALLS_FDATASYNC, .enabled = CONFIG_BOOLEAN_YES, .objects = NULL, .probe_links = NULL},
52
+ {.syscall = NETDATA_SYSCALLS_SYNC_FILE_RANGE, .enabled = CONFIG_BOOLEAN_YES, .objects = NULL, .probe_links = NULL},
53
{.syscall = NULL, .enabled = CONFIG_BOOLEAN_NO, .objects = NULL, .probe_links = NULL}
54
};
55
56
+netdata_ebpf_targets_t sync_targets[] = { {.name = NETDATA_SYSCALLS_SYNC, .mode = EBPF_LOAD_TRAMPOLINE},
57
+ {.name = NETDATA_SYSCALLS_SYNCFS, .mode = EBPF_LOAD_TRAMPOLINE},
58
+ {.name = NETDATA_SYSCALLS_MSYNC, .mode = EBPF_LOAD_TRAMPOLINE},
59
+ {.name = NETDATA_SYSCALLS_FSYNC, .mode = EBPF_LOAD_TRAMPOLINE},
60
+ {.name = NETDATA_SYSCALLS_FDATASYNC, .mode = EBPF_LOAD_TRAMPOLINE},
61
+ {.name = NETDATA_SYSCALLS_SYNC_FILE_RANGE, .mode = EBPF_LOAD_TRAMPOLINE},
62
+ {.name = NULL, .mode = EBPF_LOAD_TRAMPOLINE}};
63
+
64
+
65
+#ifdef LIBBPF_MAJOR_VERSION
66
+/*****************************************************************
67
+ *
68
+ * BTF FUNCTIONS
69
+ *
70
+ *****************************************************************/
71
+
72
+/**
73
+ * Disable probe
74
+ *
75
+ * Disable kprobe to use another method.
76
+ *
77
+ * @param obj is the main structure for bpf objects.
78
+ */
79
+static inline void ebpf_sync_disable_probe(struct sync_bpf *obj)
80
+{
81
+ bpf_program__set_autoload(obj->progs.netdata_sync_kprobe, false);
82
+}
83
+
84
+/**
85
+ * Disable tramppoline
86
+ *
87
+ * Disable trampoline to use another method.
88
+ *
89
+ * @param obj is the main structure for bpf objects.
90
+ */
91
+static inline void ebpf_sync_disable_trampoline(struct sync_bpf *obj)
92
+{
93
+ bpf_program__set_autoload(obj->progs.netdata_sync_fentry, false);
94
+}
95
+
96
+/**
97
+ * Disable tracepoint
98
+ *
99
+ * Disable tracepoints according information given.
100
+ *
101
+ * @param obj object loaded
102
+ * @param idx Which syscall will not be disabled
103
+ */
104
+void ebpf_sync_disable_tracepoints(struct sync_bpf *obj, sync_syscalls_index_t idx)
105
+{
106
+ if (idx != NETDATA_SYNC_SYNC_IDX)
107
+ bpf_program__set_autoload(obj->progs.netdata_sync_entry, false);
108
+
109
+ if (idx != NETDATA_SYNC_SYNCFS_IDX)
110
+ bpf_program__set_autoload(obj->progs.netdata_syncfs_entry, false);
111
+
112
+ if (idx != NETDATA_SYNC_MSYNC_IDX)
113
+ bpf_program__set_autoload(obj->progs.netdata_msync_entry, false);
114
+
115
+ if (idx != NETDATA_SYNC_FSYNC_IDX)
116
+ bpf_program__set_autoload(obj->progs.netdata_fsync_entry, false);
117
+
118
+ if (idx != NETDATA_SYNC_FDATASYNC_IDX)
119
+ bpf_program__set_autoload(obj->progs.netdata_fdatasync_entry, false);
120
+
121
+ if (idx != NETDATA_SYNC_SYNC_FILE_RANGE_IDX)
122
+ bpf_program__set_autoload(obj->progs.netdata_sync_file_range_entry, false);
123
+}
124
+
125
+/**
126
+ * Set hash tables
127
+ *
128
+ * Set the values for maps according the value given by kernel.
129
+ *
130
+ * @param obj is the main structure for bpf objects.
131
+ * @param idx the index for the main structure
132
+ */
133
+static void ebpf_sync_set_hash_tables(struct sync_bpf *obj, sync_syscalls_index_t idx)
134
+{
135
+ sync_maps[idx].map_fd = bpf_map__fd(obj->maps.tbl_sync);
136
+}
137
+
138
+/**
139
+ * Load and attach
140
+ *
141
+ * Load and attach the eBPF code in kernel.
142
+ *
143
+ * @param obj is the main structure for bpf objects.
144
+ * @param em the structure with configuration
145
+ * @param target the syscall that we are attaching a tracer.
146
+ * @param idx the index for the main structure
147
+ *
148
+ * @return it returns 0 on succes and -1 otherwise
149
+ */
150
+static inline int ebpf_sync_load_and_attach(struct sync_bpf *obj, ebpf_module_t *em, char *target,
151
+ sync_syscalls_index_t idx)
152
+{
153
+ netdata_ebpf_targets_t *synct = em->targets;
154
+ netdata_ebpf_program_loaded_t test = synct[NETDATA_SYNC_SYNC_IDX].mode;
155
+
156
+ if (test == EBPF_LOAD_TRAMPOLINE) {
157
+ ebpf_sync_disable_probe(obj);
158
+ ebpf_sync_disable_tracepoints(obj, NETDATA_SYNC_IDX_END);
159
+
160
+ bpf_program__set_attach_target(obj->progs.netdata_sync_fentry, 0,
161
+ target);
162
+ } else if (test == EBPF_LOAD_PROBE ||
163
+ test == EBPF_LOAD_RETPROBE) {
164
+ ebpf_sync_disable_tracepoints(obj, NETDATA_SYNC_IDX_END);
165
+ ebpf_sync_disable_trampoline(obj);
166
+ } else {
167
+ ebpf_sync_disable_probe(obj);
168
+ ebpf_sync_disable_trampoline(obj);
169
+
170
+ ebpf_sync_disable_tracepoints(obj, idx);
171
+ }
172
+
173
+ int ret = sync_bpf__load(obj);
174
+ if (!ret) {
175
+ if (test != EBPF_LOAD_PROBE && test != EBPF_LOAD_RETPROBE) {
176
+ ret = sync_bpf__attach(obj);
177
+ } else {
178
+ obj->links.netdata_sync_kprobe = bpf_program__attach_kprobe(obj->progs.netdata_sync_kprobe,
179
+ false, target);
180
+ ret = (int)libbpf_get_error(obj->links.netdata_sync_kprobe);
181
+ }
182
+
183
+ if (!ret)
184
+ ebpf_sync_set_hash_tables(obj, idx);
185
+ }
186
+
187
+ return ret;
188
+}
189
+#endif
190
+
191
/*****************************************************************
192
*
193
* INITIALIZE THREAD
194
*
195
*****************************************************************/
196
197
+/**
198
+ * Load Legacy
199
+ *
200
+ * Load legacy code.
201
+ *
202
+ * @param w is the sync output structure with pointers to objects loaded.
203
+ * @param em is structure with configuration
204
+ *
205
+ * @return 0 on success and -1 otherwise.
206
+ */
207
+static int ebpf_sync_load_legacy(ebpf_sync_syscalls_t *w, ebpf_module_t *em)
208
+{
209
+ em->thread_name = w->syscall;
210
+ if (!w->probe_links) {
211
+ w->probe_links = ebpf_load_program(ebpf_plugin_dir, em, running_on_kernel, isrh, &w->objects);
212
+ if (!w->probe_links) {
213
+ return -1;
214
+ }
215
+ }
216
+
217
+ return 0;
218
+}
219
+
220
/*
221
* Initialize Syscalls
222
*
@@ -70,15 +228,33 @@ static int ebpf_sync_initialize_syscall(ebpf_module_t *em)
228
{
229
int i;
230
const char *saved_name = em->thread_name;
231
+ sync_syscalls_index_t errors = 0;
232
for (i = 0; local_syscalls[i].syscall; i++) {
233
ebpf_sync_syscalls_t *w = &local_syscalls[i];
75
- if (!w->probe_links && w->enabled) {
76
- em->thread_name = w->syscall;
77
- w->probe_links = ebpf_load_program(ebpf_plugin_dir, em, running_on_kernel, isrh, &w->objects);
78
- if (!w->probe_links) {
234
+ if (w->enabled) {
235
+ if (em->load == EBPF_LOAD_LEGACY) {
236
+ if (ebpf_sync_load_legacy(w, em))
237
+ errors++;
238
+
239
em->thread_name = saved_name;
80
- return -1;
240
}
241
+#ifdef LIBBPF_MAJOR_VERSION
242
+ else {
243
+ char syscall[NETDATA_EBPF_MAX_SYSCALL_LENGTH];
244
+ ebpf_select_host_prefix(syscall, NETDATA_EBPF_MAX_SYSCALL_LENGTH, w->syscall, running_on_kernel);
245
+ w->sync_obj = sync_bpf__open();
246
+ if (!w->sync_obj) {
247
+ errors++;
248
+ } else {
249
+ if (ebpf_sync_load_and_attach(w->sync_obj, em, syscall, i)) {
250
+ if (ebpf_sync_load_legacy(w, em))
251
+ errors++;
252
+
253
+ em->thread_name = saved_name;
254
+ }
255
+ }
256
+ }
257
+#endif
258
}
259
}
260
em->thread_name = saved_name;
@@ -254,6 +430,10 @@ void ebpf_sync_cleanup_objects()
430
}
431
bpf_object__close(w->objects);
432
}
433
+#ifdef LIBBPF_MAJOR_VERSION
434
+ else if (w->sync_obj)
435
+ sync_bpf__destroy(w->sync_obj);
436
+#endif
437
}
438
}
439
@@ -386,6 +566,9 @@ void *ebpf_sync_thread(void *ptr)
566
if (!em->enabled)
567
goto endsync;
568
569
+#ifdef LIBBPF_MAJOR_VERSION
570
+ ebpf_adjust_thread_load(em, default_btf);
571
+#endif
572
if (ebpf_sync_initialize_syscall(em)) {
573
em->enabled = CONFIG_BOOLEAN_NO;
574
goto endsync;
collectors/ebpf.plugin/ebpf_sync.h
+22
-2
@@ -3,6 +3,10 @@
3
#ifndef NETDATA_EBPF_SYNC_H
4
#define NETDATA_EBPF_SYNC_H 1
5
6
+#ifdef LIBBPF_MAJOR_VERSION
7
+#include "includes/sync.skel.h"
8
+#endif
9
+
10
// Module name
11
#define NETDATA_EBPF_MODULE_NAME_SYNC "sync"
12
@@ -13,13 +17,20 @@
17
#define NETDATA_EBPF_FILE_SEGMENT_CHART "file_segment"
18
#define NETDATA_EBPF_SYNC_SUBMENU "synchronization (eBPF)"
19
20
+#define NETDATA_SYSCALLS_SYNC "sync"
21
+#define NETDATA_SYSCALLS_SYNCFS "syncfs"
22
+#define NETDATA_SYSCALLS_MSYNC "msync"
23
+#define NETDATA_SYSCALLS_FSYNC "fsync"
24
+#define NETDATA_SYSCALLS_FDATASYNC "fdatasync"
25
+#define NETDATA_SYSCALLS_SYNC_FILE_RANGE "sync_file_range"
26
+
27
#define NETDATA_EBPF_SYNC_SLEEP_MS 800000ULL
28
29
// configuration file
30
#define NETDATA_SYNC_CONFIG_FILE "sync.conf"
31
#define NETDATA_SYNC_CONFIG_NAME "syscalls"
32
22
-enum sync_syscalls_index {
33
+typedef enum sync_syscalls_index {
34
NETDATA_SYNC_SYNC_IDX,
35
NETDATA_SYNC_SYNCFS_IDX,
36
NETDATA_SYNC_MSYNC_IDX,
@@ -28,15 +39,23 @@ enum sync_syscalls_index {
39
NETDATA_SYNC_SYNC_FILE_RANGE_IDX,
40
41
NETDATA_SYNC_IDX_END
31
-};
42
+} sync_syscalls_index_t;
43
44
typedef struct ebpf_sync_syscalls {
45
char *syscall;
46
int enabled;
47
uint32_t flags;
48
49
+ // BTF structure
50
struct bpf_object *objects;
51
struct bpf_link **probe_links;
52
+
53
+ // BPF structure
54
+#ifdef LIBBPF_MAJOR_VERSION
55
+ struct sync_bpf *sync_obj;
56
+#else
57
+ void *sync_obj;
58
+#endif
59
} ebpf_sync_syscalls_t;
60
61
enum netdata_sync_charts {
@@ -52,5 +71,6 @@ enum netdata_sync_table {
71
72
extern void *ebpf_sync_thread(void *ptr);
73
extern struct config sync_config;
74
+extern netdata_ebpf_targets_t sync_targets[];
75
76
#endif /* NETDATA_EBPF_SYNC_H */
configure.ac
+1
-1
@@ -1218,7 +1218,7 @@ if test "${build_target}" = "linux" -a "${enable_ebpf}" != "no"; then
1218
if test "${have_libelf}" = "yes" -a \
1219
"${have_bpf}" = "yes" -a \
1220
"${have_libbpf}" = "yes"; then
1221
- OPTIONAL_BPF_CFLAGS="${LIBELF_CFLAGS} -I \$(abs_top_srcdir)/externaldeps/libbpf/include"
1221
+ OPTIONAL_BPF_CFLAGS="${LIBELF_CFLAGS} -I \$(abs_top_srcdir)/externaldeps/libbpf/include -I \$(abs_top_srcdir)/externaldeps/libbpf/include/uapi"
1222
OPTIONAL_BPF_LIBS="\$(abs_top_srcdir)/externaldeps/libbpf/libbpf.a ${LIBELF_LIBS}"
1223
AC_DEFINE([HAVE_LIBBPF], [1], [libbpf usability])
1224
enable_ebpf="yes"
contrib/debian/rules
+1
@@ -43,6 +43,7 @@ override_dh_installinit:
43
override_dh_auto_configure:
44
if [ $(HAVE_EBPF) -eq 1 ]; then \
45
packaging/bundle-libbpf.sh . ${TOP}/usr/libexec/netdata/plugins.d; \
46
+ packaging/bundle-ebpf-co-re.sh . ${TOP}/usr/libexec/netdata/plugins.d; \
47
fi
48
autoreconf -ivf
49
dh_auto_configure -- --prefix=/usr --sysconfdir=/etc --localstatedir=/var --libdir=/usr/lib \
libnetdata/ebpf/ebpf.c
+169
-3
@@ -718,14 +718,131 @@ static void ebpf_select_mode_string(char *output, size_t len, netdata_run_mode_t
718
}
719
720
/**
721
+ * Convert string to load mode
722
+ *
723
+ * Convert the string given as argument to value present in enum.
724
+ *
725
+ * @param str value read from configuraion file.
726
+ *
727
+ * @return It returns the value to be used.
728
+ */
729
+netdata_ebpf_load_mode_t epbf_convert_string_to_load_mode(char *str)
730
+{
731
+ if (!strcasecmp(str, EBPF_CFG_CORE_PROGRAM))
732
+ return EBPF_LOAD_CORE;
733
+ else if (!strcasecmp(str, EBPF_CFG_LEGACY_PROGRAM))
734
+ return EBPF_LOAD_LEGACY;
735
+
736
+ return EBPF_LOAD_PLAY_DICE;
737
+}
738
+
739
+/**
740
+ * Convert load mode to string
741
+ *
742
+ * @param mode value that will select the string
743
+ *
744
+ * @return It returns the string associated to mode.
745
+ */
746
+static char *ebpf_convert_load_mode_to_string(netdata_ebpf_load_mode_t mode)
747
+{
748
+ if (mode == EBPF_LOAD_CORE)
749
+ return EBPF_CFG_CORE_PROGRAM;
750
+ else if (mode == EBPF_LOAD_LEGACY)
751
+ return EBPF_CFG_LEGACY_PROGRAM;
752
+
753
+ return EBPF_CFG_DEFAULT_PROGRAM;
754
+}
755
+
756
+/**
757
+ * CO-RE type
758
+ *
759
+ * Select the preferential type of CO-RE
760
+ *
761
+ * @param str value read from configuration file.
762
+ * @param lmode load mode used by collector.
763
+ */
764
+netdata_ebpf_program_loaded_t ebpf_convert_core_type(char *str, netdata_run_mode_t lmode)
765
+{
766
+ if (!strcasecmp(str, EBPF_CFG_ATTACH_TRACEPOINT))
767
+ return EBPF_LOAD_TRACEPOINT;
768
+ else if (!strcasecmp(str, EBPF_CFG_ATTACH_PROBE)) {
769
+ return (lmode == MODE_ENTRY) ? EBPF_LOAD_PROBE : EBPF_LOAD_RETPROBE;
770
+ }
771
+
772
+ return EBPF_LOAD_TRAMPOLINE;
773
+}
774
+
775
+#ifdef LIBBPF_MAJOR_VERSION
776
+/**
777
+ * Adjust Thread Load
778
+ *
779
+ * Adjust thread configuraton according specified load.
780
+ *
781
+ * @param mod the main structure that will be adjusted.
782
+ * @param file the btf file used with thread.
783
+ */
784
+void ebpf_adjust_thread_load(ebpf_module_t *mod, struct btf *file)
785
+{
786
+ if (!file) {
787
+ mod->load = EBPF_LOAD_LEGACY;
788
+ } else if (mod->load == EBPF_LOAD_PLAY_DICE && file) {
789
+ mod->load = EBPF_LOAD_CORE;
790
+ }
791
+}
792
+
793
+/**
794
+ *
795
+ * @param filename
796
+ * @return
797
+ */
798
+struct btf *ebpf_parse_btf_file(const char *filename)
799
+{
800
+ struct btf *bf = btf__parse(filename, NULL);
801
+ if (libbpf_get_error(bf)) {
802
+ fprintf(stderr, "Cannot parse btf file");
803
+ btf__free(bf);
804
+ return NULL;
805
+ }
806
+
807
+ return bf;
808
+}
809
+#endif
810
+
811
+/**
812
+ * Update target with configuration
813
+ *
814
+ * Update target load mode with value.
815
+ *
816
+ * @param em the module structure
817
+ * @param value value used to update.
818
+ */
819
+static void ebpf_update_target_with_conf(ebpf_module_t *em, netdata_ebpf_program_loaded_t value)
820
+{
821
+ netdata_ebpf_targets_t *targets = em->targets;
822
+ if (!targets) {
823
+ return;
824
+ }
825
+
826
+ int i = 0;
827
+ while (targets[i].name) {
828
+ targets[i].mode = value;
829
+ i++;
830
+ }
831
+}
832
+
833
+/**
834
+ * Update Module using config
835
+ *
836
+ * Update configuration for a specific thread.
837
+ *
838
* @param modules structure that will be updated
839
*/
840
void ebpf_update_module_using_config(ebpf_module_t *modules)
841
{
842
char default_value[EBPF_MAX_MODE_LENGTH + 1];
843
ebpf_select_mode_string(default_value, EBPF_MAX_MODE_LENGTH, modules->mode);
727
- char *mode = appconfig_get(modules->cfg, EBPF_GLOBAL_SECTION, EBPF_CFG_LOAD_MODE, default_value);
728
- modules->mode = ebpf_select_mode(mode);
844
+ char *value = appconfig_get(modules->cfg, EBPF_GLOBAL_SECTION, EBPF_CFG_LOAD_MODE, default_value);
845
+ modules->mode = ebpf_select_mode(value);
846
847
modules->update_every = (int)appconfig_get_number(modules->cfg, EBPF_GLOBAL_SECTION,
848
EBPF_CFG_UPDATE_EVERY, modules->update_every);
@@ -735,8 +852,15 @@ void ebpf_update_module_using_config(ebpf_module_t *modules)
852
853
modules->pid_map_size = (uint32_t)appconfig_get_number(modules->cfg, EBPF_GLOBAL_SECTION, EBPF_CFG_PID_SIZE,
854
modules->pid_map_size);
738
-}
855
856
+ value = ebpf_convert_load_mode_to_string(modules->load);
857
+ value = appconfig_get(modules->cfg, EBPF_GLOBAL_SECTION, EBPF_CFG_TYPE_FORMAT, value);
858
+ modules->load = epbf_convert_string_to_load_mode(value);
859
+
860
+ value = appconfig_get(modules->cfg, EBPF_GLOBAL_SECTION, EBPF_CFG_CORE_ATTACH, EBPF_CFG_ATTACH_TRAMPOLINE);
861
+ netdata_ebpf_program_loaded_t fill_lm = ebpf_convert_core_type(value, modules->mode);
862
+ ebpf_update_target_with_conf(modules, fill_lm);
863
+}
864
865
/**
866
* Update module
@@ -993,3 +1117,45 @@ int ebpf_disable_tracing_values(char *subsys, char *eventname)
1117
{
1118
return ebpf_change_tracing_values(subsys, eventname, "0");
1119
}
1120
+
1121
+/**
1122
+ * Select PC prefix
1123
+ *
1124
+ * Identify the prefix to run on PC architecture.
1125
+ *
1126
+ * @return It returns 32 or 64 according to host arch.
1127
+ */
1128
+static uint32_t ebpf_select_pc_prefix()
1129
+{
1130
+ long counter = 1;
1131
+ uint32_t i;
1132
+ for (i = 0; i < 128; i++) {
1133
+ counter <<= 1;
1134
+ if (counter < 0)
1135
+ break;
1136
+ }
1137
+
1138
+ return counter;
1139
+}
1140
+
1141
+/**
1142
+ * Select Host Prefix
1143
+ *
1144
+ * Select prefix to syscall when host is running a kernel newer than 4.17.0
1145
+ *
1146
+ * @param output the vector to store data.
1147
+ * @param length length of output vector.
1148
+ * @param syscall the syscall that prefix will be attached;
1149
+ * @param kver the current kernel version in format MAJOR*65536 + MINOR*256 + PATCH
1150
+ */
1151
+void ebpf_select_host_prefix(char *output, size_t length, char *syscall, int kver)
1152
+{
1153
+ if (kver < NETDATA_EBPF_KERNEL_4_17)
1154
+ snprintfz(output, length, "sys_%s", syscall);
1155
+ else {
1156
+ uint32_t arch = ebpf_select_pc_prefix();
1157
+ // Prefix selected according https://www.kernel.org/doc/html/latest/process/adding-syscalls.html
1158
+ char *prefix = (arch == 32) ? "__ia32" : "__x64";
1159
+ snprintfz(output, length, "%s_sys_%s", prefix, syscall);
1160
+ }
1161
+}
\ No newline at end of file
libnetdata/ebpf/ebpf.h
+31
@@ -5,6 +5,10 @@
5
6
#include <bpf/bpf.h>
7
#include <bpf/libbpf.h>
8
+#ifdef LIBBPF_DEPRECATED
9
+#include <bpf/btf.h>
10
+#include <linux/btf.h>
11
+#endif
12
#include <stdlib.h> // Necessary for stdtoul
13
14
#define NETDATA_DEBUGFS "/sys/kernel/debug/tracing/"
@@ -17,6 +21,18 @@
21
#define EBPF_CFG_LOAD_MODE_RETURN "return"
22
#define EBPF_MAX_MODE_LENGTH 6
23
24
+#define EBPF_CFG_TYPE_FORMAT "ebpf type format"
25
+#define EBPF_CFG_DEFAULT_PROGRAM "auto"
26
+#define EBPF_CFG_CORE_PROGRAM "CO-RE"
27
+#define EBPF_CFG_LEGACY_PROGRAM "legacy"
28
+
29
+#define EBPF_CFG_CORE_ATTACH "ebpf co-re tracing"
30
+#define EBPF_CFG_ATTACH_TRAMPOLINE "trampoline"
31
+#define EBPF_CFG_ATTACH_TRACEPOINT "tracepoint"
32
+#define EBPF_CFG_ATTACH_PROBE "probe"
33
+
34
+#define EBPF_CFG_PROGRAM_PATH "btf path"
35
+
36
#define EBPF_CFG_UPDATE_EVERY "update every"
37
#define EBPF_CFG_PID_SIZE "pid table size"
38
#define EBPF_CFG_APPLICATION "apps"
@@ -254,4 +270,19 @@ extern int ebpf_is_tracepoint_enabled(char *subsys, char *eventname);
270
extern int ebpf_enable_tracing_values(char *subsys, char *eventname);
271
extern int ebpf_disable_tracing_values(char *subsys, char *eventname);
272
273
+// BTF Section
274
+#define EBPF_DEFAULT_BTF_FILE "/sys/kernel/btf"
275
+#define EBPF_DEFAULT_ERROR_MSG "Cannot open or load BPF file for thread"
276
+
277
+// BTF helpers
278
+#define NETDATA_EBPF_MAX_SYSCALL_LENGTH 255
279
+
280
+extern netdata_ebpf_load_mode_t epbf_convert_string_to_load_mode(char *str);
281
+extern netdata_ebpf_program_loaded_t ebpf_convert_core_type(char *str, netdata_run_mode_t lmode);
282
+extern void ebpf_select_host_prefix(char *output, size_t length, char *syscall, int kver);
283
+#ifdef LIBBPF_MAJOR_VERSION
284
+extern void ebpf_adjust_thread_load(ebpf_module_t *mod, struct btf *file);
285
+extern struct btf *ebpf_parse_btf_file(const char *filename);
286
+#endif
287
+
288
#endif /* NETDATA_EBPF_H */
netdata-installer.sh
+54
@@ -967,6 +967,7 @@ copy_libbpf() {
967
968
run cp "${1}/usr/${lib_subdir}/libbpf.a" "${target_dir}/libbpf.a" || return 1
969
run cp -r "${1}/usr/include" "${target_dir}" || return 1
970
+ run cp -r "${1}/include/uapi" "${target_dir}/include" || return 1
971
}
972
973
bundle_libbpf() {
@@ -1025,6 +1026,59 @@ bundle_libbpf() {
1026
1027
bundle_libbpf
1028
1029
+copy_co_re() {
1030
+ cp -R "${1}/includes" "collectors/ebpf.plugin/"
1031
+}
1032
+
1033
+bundle_ebpf_co_re() {
1034
+ if { [ -n "${NETDATA_DISABLE_EBPF}" ] && [ ${NETDATA_DISABLE_EBPF} = 1 ]; } || [ "$(uname -s)" != Linux ]; then
1035
+ return 0
1036
+ fi
1037
+
1038
+ [ -n "${GITHUB_ACTIONS}" ] && echo "::group::Bundling libbpf."
1039
+
1040
+ progress "eBPF CO-RE"
1041
+
1042
+ CORE_PACKAGE_VERSION="$(cat packaging/ebpf-co-re.version)"
1043
+
1044
+ tmp="$(mktemp -d -t netdata-ebpf-co-re-XXXXXX)"
1045
+ CORE_PACKAGE_BASENAME="netdata-ebpf-co-re-glibc-${CORE_PACKAGE_VERSION}.tar.xz"
1046
+
1047
+ if fetch_and_verify "ebpf-co-re" \
1048
+ "https://github.com/netdata/ebpf-co-re/releases/download/${CORE_PACKAGE_VERSION}/${CORE_PACKAGE_BASENAME}" \
1049
+ "${CORE_PACKAGE_BASENAME}" \
1050
+ "${tmp}" \
1051
+ "${NETDATA_LOCAL_TARBALL_OVERRIDE_CORE}"; then
1052
+ if run tar --no-same-owner -xf "${tmp}/${CORE_PACKAGE_BASENAME}" -C "${tmp}" &&
1053
+ copy_co_re "${tmp}" &&
1054
+ rm -rf "${tmp}"; then
1055
+ run_ok "libbpf built and prepared."
1056
+ else
1057
+ run_failed "Failed to get eBPF CO-RE files."
1058
+ if [ -n "${NETDATA_DISABLE_EBPF}" ] && [ ${NETDATA_DISABLE_EBPF} = 0 ]; then
1059
+ exit 1
1060
+ else
1061
+ defer_error_highlighted "Failed to get CO-RE. You will not be able to use eBPF plugin."
1062
+ NETDATA_DISABLE_EBPF=1
1063
+ NETDATA_CONFIGURE_OPTIONS="$(echo "${NETDATA_CONFIGURE_OPTIONS%--disable-ebpf)}" | sed 's/$/ --disable-ebpf/g')"
1064
+ fi
1065
+ fi
1066
+ else
1067
+ run_failed "Unable to fetch sources for libbpf."
1068
+ if [ -n "${NETDATA_DISABLE_EBPF}" ] && [ ${NETDATA_DISABLE_EBPF} = 0 ]; then
1069
+ exit 1
1070
+ else
1071
+ defer_error_highlighted "Unable to fetch sources for eBPF CO-RE. You will not be able to use eBPF plugin."
1072
+ NETDATA_DISABLE_EBPF=1
1073
+ NETDATA_CONFIGURE_OPTIONS="$(echo "${NETDATA_CONFIGURE_OPTIONS%--disable-ebpf)}" | sed 's/$/ --disable-ebpf/g')"
1074
+ fi
1075
+ fi
1076
+
1077
+ [ -n "${GITHUB_ACTIONS}" ] && echo "::endgroup::"
1078
+}
1079
+
1080
+bundle_ebpf_co_re
1081
+
1082
# -----------------------------------------------------------------------------
1083
# If we have the dashboard switching logic, make sure we're on the classic
1084
# dashboard during the install (updates don't work correctly otherwise).
netdata.spec.in
+3
@@ -239,11 +239,14 @@ export CFLAGS="${CFLAGS} -fPIC" && ${RPM_BUILD_DIR}/%{name}-%{version}/packaging
239
%if 0%{?centos_ver:1}
240
%if %{centos_ver} < 8
241
export CFLAGS="${CFLAGS} -fPIC" && ${RPM_BUILD_DIR}/%{name}-%{version}/packaging/bundle-libbpf.sh ${RPM_BUILD_DIR}/%{name}-%{version} centos7
242
+export CFLAGS="${CFLAGS} -fPIC" && ${RPM_BUILD_DIR}/%{name}-%{version}/packaging/bundle-ebpf-co-re.sh ${RPM_BUILD_DIR}/%{name}-%{version}
243
%else
244
export CFLAGS="${CFLAGS} -fPIC" && ${RPM_BUILD_DIR}/%{name}-%{version}/packaging/bundle-libbpf.sh ${RPM_BUILD_DIR}/%{name}-%{version} centos8
245
+export CFLAGS="${CFLAGS} -fPIC" && ${RPM_BUILD_DIR}/%{name}-%{version}/packaging/bundle-ebpf-co-re.sh ${RPM_BUILD_DIR}/%{name}-%{version}
246
%endif
247
%else
248
export CFLAGS="${CFLAGS} -fPIC" && ${RPM_BUILD_DIR}/%{name}-%{version}/packaging/bundle-libbpf.sh ${RPM_BUILD_DIR}/%{name}-%{version} other
249
+export CFLAGS="${CFLAGS} -fPIC" && ${RPM_BUILD_DIR}/%{name}-%{version}/packaging/bundle-ebpf-co-re.sh ${RPM_BUILD_DIR}/%{name}-%{version}
250
%endif
251
%endif
252
packaging/bundle-ebpf-co-re.sh
new
+9
@@ -0,0 +1,9 @@
1
+#!/bin/sh
2
+
3
+SRCDIR="${1}"
4
+
5
+CORE_VERSION="$(cat "${SRCDIR}/packaging/ebpf-co-re.version")"
6
+CORE_TARBALL="netdata-ebpf-co-re-glibc-${CORE_VERSION}.tar.xz"
7
+curl -sSL --connect-timeout 10 --retry 3 "https://github.com/netdata/ebpf-co-re/releases/download/${CORE_VERSION}/${CORE_TARBALL}" > "${CORE_TARBALL}" || exit 1
8
+grep "${CORE_TARBALL}" "${SRCDIR}/packaging/ebpf-co-re.checksums" | sha256sum -c - || exit 1
9
+tar -xaf "${CORE_TARBALL}" -C "${SRCDIR}/collectors/ebpf.plugin" || exit 1
packaging/bundle-libbpf.sh
+1
@@ -24,3 +24,4 @@ tar -xzf "${LIBBPF_TARBALL}" -C "${1}/externaldeps/libbpf" || exit 1
24
make -C "${LIBBPF_BUILD_PATH}/src" BUILD_STATIC_ONLY=1 OBJDIR=build/ DESTDIR=../ install || exit 1
25
cp -a "${LIBBPF_BUILD_PATH}/usr/${lib_subdir}/libbpf.a" "${1}/externaldeps/libbpf" || exit 1
26
cp -a "${LIBBPF_BUILD_PATH}/usr/include" "${1}/externaldeps/libbpf" || exit 1
27
+cp -a "${LIBBPF_BUILD_PATH}/include/uapi" "${1}/externaldeps/libbpf/include" || exit 1
packaging/ebpf-co-re.checksums
new
+1
@@ -0,0 +1 @@
1
+da6929bc3a432240369bcb84c86e607d1ed255cd9530620d2f355e105ce376d6 netdata-ebpf-co-re-glibc-v0.9.2.tar.xz
packaging/ebpf-co-re.version
new
+1
@@ -0,0 +1 @@
1
+v0.9.2