@cryptotaxi247 / netdata-1 / commits / 6123a8e1a

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