diff options
-rw-r--r-- | collectors/ebpf.plugin/ebpf.c | 47 | ||||
-rw-r--r-- | collectors/ebpf.plugin/ebpf.h | 6 | ||||
-rw-r--r-- | collectors/ebpf.plugin/ebpf_disk.c | 76 | ||||
-rw-r--r-- | collectors/ebpf.plugin/ebpf_disk.h | 5 | ||||
-rw-r--r-- | collectors/ebpf.plugin/ebpf_filesystem.c | 226 | ||||
-rw-r--r-- | collectors/ebpf.plugin/ebpf_filesystem.h | 3 | ||||
-rw-r--r-- | collectors/ebpf.plugin/ebpf_hardirq.c | 70 | ||||
-rw-r--r-- | collectors/ebpf.plugin/ebpf_hardirq.h | 5 | ||||
-rw-r--r-- | collectors/ebpf.plugin/ebpf_mdflush.c | 139 | ||||
-rw-r--r-- | collectors/ebpf.plugin/ebpf_mdflush.h | 7 | ||||
-rw-r--r-- | libnetdata/ebpf/ebpf.h | 18 |
11 files changed, 576 insertions, 26 deletions
diff --git a/collectors/ebpf.plugin/ebpf.c b/collectors/ebpf.plugin/ebpf.c index d4f51992e2..a9afad803e 100644 --- a/collectors/ebpf.plugin/ebpf.c +++ b/collectors/ebpf.plugin/ebpf.c @@ -186,7 +186,7 @@ ebpf_module_t ebpf_modules[] = { .apps_routine = NULL, .maps = NULL, .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &mdflush_config, .config_file = NETDATA_DIRECTORY_MDFLUSH_CONFIG_FILE, .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14, - .load = EBPF_LOAD_LEGACY, .targets = NULL, .probe_links = NULL, .objects = NULL, + .load = EBPF_LOAD_LEGACY, .targets = mdflush_targets, .probe_links = NULL, .objects = NULL, .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES}, { .thread_name = NULL, .enabled = 0, .start_routine = NULL, .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 0, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO, .apps_level = NETDATA_APPS_NOT_SET, @@ -378,7 +378,13 @@ ebpf_filesystem_partitions_t localfs[] = .enabled = CONFIG_BOOLEAN_YES, .addresses = {.function = NULL, .addr = 0}, .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4, - .fs_maps = NULL}, + .fs_maps = NULL, + .fs_obj = NULL, + .functions = { "ext4_file_read_iter", + "ext4_file_write_iter", + "ext4_file_open", + "ext4_sync_file", + NULL }}, {.filesystem = "xfs", .optional_filesystem = NULL, .family = "xfs", @@ -388,7 +394,13 @@ ebpf_filesystem_partitions_t localfs[] = .enabled = CONFIG_BOOLEAN_YES, .addresses = {.function = NULL, .addr = 0}, .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4, - .fs_maps = NULL}, + .fs_maps = NULL, + .fs_obj = NULL, + .functions = { "xfs_file_read_iter", + "xfs_file_write_iter", + "xfs_file_open", + "xfs_file_fsync", + NULL }}, {.filesystem = "nfs", .optional_filesystem = "nfs4", .family = "nfs", @@ -398,7 +410,13 @@ ebpf_filesystem_partitions_t localfs[] = .enabled = CONFIG_BOOLEAN_YES, .addresses = {.function = NULL, .addr = 0}, .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4, - .fs_maps = NULL}, + .fs_maps = NULL, + .fs_obj = NULL, + .functions = { "nfs_file_read", + "nfs_file_write", + "nfs_open", + "nfs_getattr", + NULL }}, // // "nfs4_file_open" - not present on all kernels {.filesystem = "zfs", .optional_filesystem = NULL, .family = "zfs", @@ -408,7 +426,13 @@ ebpf_filesystem_partitions_t localfs[] = .enabled = CONFIG_BOOLEAN_YES, .addresses = {.function = NULL, .addr = 0}, .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4, - .fs_maps = NULL}, + .fs_maps = NULL, + .fs_obj = NULL, + .functions = { "zpl_iter_read", + "zpl_iter_write", + "zpl_open", + "zpl_fsync", + NULL }}, {.filesystem = "btrfs", .optional_filesystem = NULL, .family = "btrfs", @@ -418,7 +442,13 @@ ebpf_filesystem_partitions_t localfs[] = .enabled = CONFIG_BOOLEAN_YES, .addresses = {.function = "btrfs_file_operations", .addr = 0}, .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_10, - .fs_maps = NULL}, + .fs_maps = NULL, + .fs_obj = NULL, + .functions = { "btrfs_file_read_iter", + "btrfs_file_write_iter", + "btrfs_file_open", + "btrfs_sync_file", + NULL }}, {.filesystem = NULL, .optional_filesystem = NULL, .family = NULL, @@ -427,7 +457,7 @@ ebpf_filesystem_partitions_t localfs[] = .flags = NETDATA_FILESYSTEM_FLAG_NO_PARTITION, .enabled = CONFIG_BOOLEAN_YES, .addresses = {.function = NULL, .addr = 0}, - .kernels = 0, .fs_maps = NULL}}; + .kernels = 0, .fs_maps = NULL, .fs_obj = NULL}}; ebpf_sync_syscalls_t local_syscalls[] = { {.syscall = NETDATA_SYSCALLS_SYNC, .enabled = CONFIG_BOOLEAN_YES, .objects = NULL, .probe_links = NULL, @@ -493,7 +523,10 @@ ebpf_plugin_stats_t plugin_statistics = {.core = 0, .legacy = 0, .running = 0, . struct btf *default_btf = NULL; struct cachestat_bpf *cachestat_bpf_obj = NULL; struct dc_bpf *dc_bpf_obj = NULL; +struct disk_bpf *disk_bpf_obj = NULL; struct fd_bpf *fd_bpf_obj = NULL; +struct hardirq_bpf *hardirq_bpf_obj = NULL; +struct mdflush_bpf *mdflush_bpf_obj = NULL; struct mount_bpf *mount_bpf_obj = NULL; struct shm_bpf *shm_bpf_obj = NULL; struct socket_bpf *socket_bpf_obj = NULL; diff --git a/collectors/ebpf.plugin/ebpf.h b/collectors/ebpf.plugin/ebpf.h index ae24c302c5..a8a2f27a92 100644 --- a/collectors/ebpf.plugin/ebpf.h +++ b/collectors/ebpf.plugin/ebpf.h @@ -39,7 +39,10 @@ #ifdef LIBBPF_MAJOR_VERSION // BTF code #include "includes/cachestat.skel.h" #include "includes/dc.skel.h" +#include "includes/disk.skel.h" #include "includes/fd.skel.h" +#include "includes/hardirq.skel.h" +#include "includes/mdflush.skel.h" #include "includes/mount.skel.h" #include "includes/shm.skel.h" #include "includes/socket.skel.h" @@ -48,8 +51,11 @@ extern struct cachestat_bpf *cachestat_bpf_obj; extern struct dc_bpf *dc_bpf_obj; +extern struct disk_bpf *disk_bpf_obj; extern struct fd_bpf *fd_bpf_obj; +extern struct hardirq_bpf *hardirq_bpf_obj; extern struct mount_bpf *mount_bpf_obj; +extern struct mdflush_bpf *mdflush_bpf_obj; extern struct shm_bpf *shm_bpf_obj; extern struct socket_bpf *socket_bpf_obj; extern struct swap_bpf *bpf_obj; diff --git a/collectors/ebpf.plugin/ebpf_disk.c b/collectors/ebpf.plugin/ebpf_disk.c index 0e2b6154bc..026e44ec89 100644 --- a/collectors/ebpf.plugin/ebpf_disk.c +++ b/collectors/ebpf.plugin/ebpf_disk.c @@ -52,6 +52,39 @@ static netdata_idx_t *disk_hash_values = NULL; ebpf_publish_disk_t *plot_disks = NULL; pthread_mutex_t plot_mutex; +#ifdef LIBBPF_MAJOR_VERSION +/** + * Set hash table + * + * Set the values for maps according the value given by kernel. + * + * @param obj is the main structure for bpf objects. + */ +static inline void ebpf_disk_set_hash_table(struct disk_bpf *obj) + { + disk_maps[NETDATA_DISK_IO].map_fd = bpf_map__fd(obj->maps.tbl_disk_iocall); + } + +/** + * Load and attach + * + * Load and attach the eBPF code in kernel. + * + * @param obj is the main structure for bpf objects. + * + * @return it returns 0 on success and -1 otherwise + */ +static inline int ebpf_disk_load_and_attach(struct disk_bpf *obj) +{ + int ret = disk_bpf__load(obj); + if (ret) { + return ret; + } + + return disk_bpf__attach(obj); +} +#endif + /***************************************************************** * * FUNCTIONS TO MANIPULATE HARD DISKS @@ -702,7 +735,7 @@ static void disk_collector(ebpf_module_t *em) continue; counter = 0; - read_hard_disk_tables(disk_maps[NETDATA_DISK_READ].map_fd, maps_per_core); + read_hard_disk_tables(disk_maps[NETDATA_DISK_IO].map_fd, maps_per_core); pthread_mutex_lock(&lock); ebpf_remove_pointer_from_plot_disk(em); ebpf_latency_send_hd_data(update_every); @@ -749,6 +782,43 @@ static int ebpf_disk_enable_tracepoints() return 0; } +/* + * Load BPF + * + * Load BPF files. + * + * @param em the structure with configuration + * + * @return It returns 0 on success and -1 otherwise. + */ +static int ebpf_disk_load_bpf(ebpf_module_t *em) +{ + int ret = 0; + if (em->load & EBPF_LOAD_LEGACY) { + em->probe_links = ebpf_load_program(ebpf_plugin_dir, em, running_on_kernel, isrh, &em->objects); + if (!em->probe_links) { + ret = -1; + } + } +#ifdef LIBBPF_MAJOR_VERSION + else { + disk_bpf_obj = disk_bpf__open(); + if (!disk_bpf_obj) + ret = -1; + else { + ret = ebpf_disk_load_and_attach(disk_bpf_obj); + if (!ret) + ebpf_disk_set_hash_table(disk_bpf_obj); + } + } +#endif + + if (ret) + error("%s %s", EBPF_DEFAULT_ERROR_MSG, em->thread_name); + + return ret; +} + /** * Disk thread * @@ -781,9 +851,9 @@ void *ebpf_disk_thread(void *ptr) #ifdef LIBBPF_MAJOR_VERSION ebpf_define_map_type(disk_maps, em->maps_per_core, running_on_kernel); + ebpf_adjust_thread_load(em, default_btf); #endif - em->probe_links = ebpf_load_program(ebpf_plugin_dir, em, running_on_kernel, isrh, &em->objects); - if (!em->probe_links) { + if (ebpf_disk_load_bpf(em)) { goto enddisk; } diff --git a/collectors/ebpf.plugin/ebpf_disk.h b/collectors/ebpf.plugin/ebpf_disk.h index 69c7058758..ebe6709ae9 100644 --- a/collectors/ebpf.plugin/ebpf_disk.h +++ b/collectors/ebpf.plugin/ebpf_disk.h @@ -54,10 +54,7 @@ typedef struct netdata_ebpf_disks { struct netdata_ebpf_disks *next; } netdata_ebpf_disks_t; -enum ebpf_disk_tables { - NETDATA_DISK_READ, - NETDATA_DISK_TMP -}; +enum ebpf_disk_tables { NETDATA_DISK_IO }; typedef struct block_key { uint32_t bin; diff --git a/collectors/ebpf.plugin/ebpf_filesystem.c b/collectors/ebpf.plugin/ebpf_filesystem.c index a613ec705f..ab39db972b 100644 --- a/collectors/ebpf.plugin/ebpf_filesystem.c +++ b/collectors/ebpf.plugin/ebpf_filesystem.c @@ -131,6 +131,202 @@ static netdata_publish_syscall_t filesystem_publish_aggregated[NETDATA_EBPF_HIST char **dimensions = NULL; static netdata_idx_t *filesystem_hash_values = NULL; +#ifdef LIBBPF_MAJOR_VERSION +/** + * FS disable kprobe + * + * Disable kprobes, because system will use trampolines. + * We are not calling this function for while, because we are prioritizing kprobes. We opted by this road, because + * distribution are still not deliverying necessary btf files per FS. + * + * @param obj FS object loaded. + */ +static void ebpf_fs_disable_kprobe(struct filesystem_bpf *obj) + { + // kprobe + bpf_program__set_autoload(obj->progs.netdata_fs_file_read_probe, false); + bpf_program__set_autoload(obj->progs.netdata_fs_file_write_probe, false); + bpf_program__set_autoload(obj->progs.netdata_fs_file_open_probe, false); + bpf_program__set_autoload(obj->progs.netdata_fs_2nd_file_open_probe, false); + bpf_program__set_autoload(obj->progs.netdata_fs_getattr_probe, false); + // kretprobe + bpf_program__set_autoload(obj->progs.netdata_fs_file_read_retprobe, false); + bpf_program__set_autoload(obj->progs.netdata_fs_file_write_retprobe, false); + bpf_program__set_autoload(obj->progs.netdata_fs_file_open_retprobe, false); + bpf_program__set_autoload(obj->progs.netdata_fs_2nd_file_open_retprobe, false); + bpf_program__set_autoload(obj->progs.netdata_fs_getattr_retprobe, false); + } + + /** + * Disable trampoline + * + * Disable trampolines to use kprobes. + * + * @param obj FS object loaded. + */ + static void ebpf_fs_disable_trampoline(struct filesystem_bpf *obj) + { + // entry + bpf_program__set_autoload(obj->progs.netdata_fs_file_read_entry, false); + bpf_program__set_autoload(obj->progs.netdata_fs_file_write_entry, false); + bpf_program__set_autoload(obj->progs.netdata_fs_file_open_entry, false); + bpf_program__set_autoload(obj->progs.netdata_fs_getattr_entry, false); + bpf_program__set_autoload(obj->progs.netdata_fs_2nd_file_open_entry, false); + + // exit + bpf_program__set_autoload(obj->progs.netdata_fs_file_read_exit, false); + bpf_program__set_autoload(obj->progs.netdata_fs_file_write_exit, false); + bpf_program__set_autoload(obj->progs.netdata_fs_file_open_exit, false); + bpf_program__set_autoload(obj->progs.netdata_fs_getattr_exit, false); + bpf_program__set_autoload(obj->progs.netdata_fs_2nd_file_open_exit, false); + } + + /** + * Set targets + * + * Set targets for each objects. + * + * @param obj FS object loaded. + * @param functions array with function names. + */ + static void ebpf_fs_set_target(struct filesystem_bpf *obj, const char **functions) +{ + // entry + bpf_program__set_attach_target(obj->progs.netdata_fs_file_read_entry, 0, + functions[NETDATA_KEY_BTF_READ]); + bpf_program__set_attach_target(obj->progs.netdata_fs_file_write_entry, 0, + functions[NETDATA_KEY_BTF_WRITE]); + bpf_program__set_attach_target(obj->progs.netdata_fs_file_open_entry, 0, + functions[NETDATA_KEY_BTF_OPEN]); + bpf_program__set_attach_target(obj->progs.netdata_fs_getattr_entry, 0, + functions[NETDATA_KEY_BTF_SYNC_ATTR]); + + // exit + bpf_program__set_attach_target(obj->progs.netdata_fs_file_read_exit, 0, + functions[NETDATA_KEY_BTF_READ]); + bpf_program__set_attach_target(obj->progs.netdata_fs_file_write_exit, 0, + functions[NETDATA_KEY_BTF_WRITE]); + bpf_program__set_attach_target(obj->progs.netdata_fs_file_open_exit, 0, + functions[NETDATA_KEY_BTF_OPEN]); + bpf_program__set_attach_target(obj->progs.netdata_fs_getattr_exit, 0, + functions[NETDATA_KEY_BTF_SYNC_ATTR]); + + if (functions[NETDATA_KEY_BTF_OPEN2]) { + bpf_program__set_attach_target(obj->progs.netdata_fs_2nd_file_open_entry, 0, + functions[NETDATA_KEY_BTF_OPEN2]); + bpf_program__set_attach_target(obj->progs.netdata_fs_2nd_file_open_exit, 0, + functions[NETDATA_KEY_BTF_OPEN2]); + } else { + bpf_program__set_autoload(obj->progs.netdata_fs_2nd_file_open_entry, false); + bpf_program__set_autoload(obj->progs.netdata_fs_2nd_file_open_exit, false); + } +} + +/** + * Attach Kprobe + * + * Attach kprobe on targets + * + * @param obj FS object loaded. + * @param functions array with function names. + */ +static int ebpf_fs_attach_kprobe(struct filesystem_bpf *obj, const char **functions) +{ + // kprobe + obj->links.netdata_fs_file_read_probe = bpf_program__attach_kprobe(obj->progs.netdata_fs_file_read_probe, + false, functions[NETDATA_KEY_BTF_READ]); + if (libbpf_get_error(obj->links.netdata_fs_file_read_probe)) + return -1; + + obj->links.netdata_fs_file_write_probe = bpf_program__attach_kprobe(obj->progs.netdata_fs_file_write_probe, + false, functions[NETDATA_KEY_BTF_WRITE]); + if (libbpf_get_error(obj->links.netdata_fs_file_write_probe)) + return -1; + + obj->links.netdata_fs_file_open_probe = bpf_program__attach_kprobe(obj->progs.netdata_fs_file_open_probe, + false, functions[NETDATA_KEY_BTF_OPEN]); + if (libbpf_get_error(obj->links.netdata_fs_file_open_probe)) + return -1; + + obj->links.netdata_fs_getattr_probe = bpf_program__attach_kprobe(obj->progs.netdata_fs_getattr_probe, + false, functions[NETDATA_KEY_BTF_SYNC_ATTR]); + if (libbpf_get_error(obj->links.netdata_fs_getattr_probe)) + return -1; + + // kretprobe + obj->links.netdata_fs_file_read_retprobe = bpf_program__attach_kprobe(obj->progs.netdata_fs_file_read_retprobe, + false, functions[NETDATA_KEY_BTF_READ]); + if (libbpf_get_error(obj->links.netdata_fs_file_read_retprobe)) + return -1; + + obj->links.netdata_fs_file_write_retprobe = bpf_program__attach_kprobe(obj->progs.netdata_fs_file_write_retprobe, + false, functions[NETDATA_KEY_BTF_WRITE]); + if (libbpf_get_error(obj->links.netdata_fs_file_write_retprobe)) + return -1; + + obj->links.netdata_fs_file_open_retprobe = bpf_program__attach_kprobe(obj->progs.netdata_fs_file_open_retprobe, + false, functions[NETDATA_KEY_BTF_OPEN]); + if (libbpf_get_error(obj->links.netdata_fs_file_open_retprobe)) + return -1; + + obj->links.netdata_fs_getattr_retprobe = bpf_program__attach_kprobe(obj->progs.netdata_fs_getattr_retprobe, + false, functions[NETDATA_KEY_BTF_SYNC_ATTR]); + if (libbpf_get_error(obj->links.netdata_fs_getattr_retprobe)) + return -1; + + if (functions[NETDATA_KEY_BTF_OPEN2]) { + obj->links.netdata_fs_2nd_file_open_probe = bpf_program__attach_kprobe(obj->progs.netdata_fs_2nd_file_open_probe, + false, functions[NETDATA_KEY_BTF_OPEN2]); + if (libbpf_get_error(obj->links.netdata_fs_2nd_file_open_probe)) + return -1; + + obj->links.netdata_fs_2nd_file_open_retprobe = bpf_program__attach_kprobe(obj->progs.netdata_fs_2nd_file_open_retprobe, + false, functions[NETDATA_KEY_BTF_OPEN2]); + if (libbpf_get_error(obj->links.netdata_fs_2nd_file_open_retprobe)) + return -1; + } + + return 0; +} + +/** + * Load and Attach + * + * Load binary and attach to targets. + * + * @param map Structure with information about maps. + * @param obj FS object loaded. + * @param functions array with function names. + * @param bf sttruct with btf file loaded. + */ +static inline int ebpf_fs_load_and_attach(ebpf_local_maps_t *map, struct filesystem_bpf *obj, + const char **functions, struct btf *bf) +{ + if (bf) { + ebpf_fs_disable_kprobe(obj); + ebpf_fs_set_target(obj, functions); + } else { + ebpf_fs_disable_trampoline(obj); + } + + int ret = filesystem_bpf__load(obj); + if (ret) { + fprintf(stderr, "failed to load BPF object: %d\n", ret); + return -1; + } + + if (bf) + ret = filesystem_bpf__attach(obj); + else + ret = ebpf_fs_attach_kprobe(obj, functions); + + if (!ret) + map->map_fd = bpf_map__fd(obj->maps.tbl_fs);; + + return ret; +} +#endif + /***************************************************************** * * COMMON FUNCTIONS @@ -275,13 +471,28 @@ int ebpf_filesystem_initialize_ebpf_data(ebpf_module_t *em) #ifdef LIBBPF_MAJOR_VERSION ebpf_define_map_type(em->maps, em->maps_per_core, running_on_kernel); #endif - efp->probe_links = ebpf_load_program(ebpf_plugin_dir, em, running_on_kernel, isrh, &efp->objects); - if (!efp->probe_links) { - em->thread_name = saved_name; - em->kernels = kernels; - em->maps = NULL; - return -1; + if (em->load & EBPF_LOAD_LEGACY) { + efp->probe_links = ebpf_load_program(ebpf_plugin_dir, em, running_on_kernel, isrh, &efp->objects); + if (!efp->probe_links) { + em->thread_name = saved_name; + em->kernels = kernels; + return -1; + } + } +#ifdef LIBBPF_MAJOR_VERSION + else { + efp->fs_obj = filesystem_bpf__open(); + if (!efp->fs_obj) { + em->thread_name = saved_name; + em->kernels = kernels; + return -1; + } else { + if (ebpf_fs_load_and_attach(em->maps, efp->fs_obj, + efp->functions, NULL)) + return -1; + } } +#endif efp->flags |= NETDATA_FILESYSTEM_FLAG_HAS_PARTITION; pthread_mutex_lock(&lock); ebpf_update_kernel_memory(&plugin_statistics, efp->fs_maps, EBPF_ACTION_STAT_ADD); @@ -683,6 +894,9 @@ void *ebpf_filesystem_thread(void *ptr) // Initialize optional as zero, to identify when there are not partitions to monitor em->optional = 0; +#ifdef LIBBPF_MAJOR_VERSION + ebpf_adjust_thread_load(em, default_btf); +#endif if (ebpf_update_partitions(em)) { if (em->optional) netdata_log_info("Netdata cannot monitor the filesystems used on this host."); diff --git a/collectors/ebpf.plugin/ebpf_filesystem.h b/collectors/ebpf.plugin/ebpf_filesystem.h index b1126badb6..04c0e74c40 100644 --- a/collectors/ebpf.plugin/ebpf_filesystem.h +++ b/collectors/ebpf.plugin/ebpf_filesystem.h @@ -7,6 +7,9 @@ #define NETDATA_EBPF_MODULE_NAME_FILESYSTEM "filesystem" #include "ebpf.h" +#ifdef LIBBPF_MAJOR_VERSION +#include "includes/filesystem.skel.h" +#endif #define NETDATA_FS_MAX_DIST_NAME 64UL diff --git a/collectors/ebpf.plugin/ebpf_hardirq.c b/collectors/ebpf.plugin/ebpf_hardirq.c index f714c261c0..6dd19e313d 100644 --- a/collectors/ebpf.plugin/ebpf_hardirq.c +++ b/collectors/ebpf.plugin/ebpf_hardirq.c @@ -9,8 +9,6 @@ struct config hardirq_config = { .first_section = NULL, .index = { .avl_tree = { .root = NULL, .compar = appconfig_section_compare }, .rwlock = AVL_LOCK_INITIALIZER } }; -#define HARDIRQ_MAP_LATENCY 0 -#define HARDIRQ_MAP_LATENCY_STATIC 1 static ebpf_local_maps_t hardirq_maps[] = { { .name = "tbl_hardirq", @@ -138,6 +136,36 @@ static hardirq_static_val_t hardirq_static_vals[] = { // thread will write to netdata agent. static avl_tree_lock hardirq_pub; +#ifdef LIBBPF_MAJOR_VERSION +/** + * Set hash table + * + * Set the values for maps according the value given by kernel. + * + * @param obj is the main structure for bpf objects. + */ +static inline void ebpf_hardirq_set_hash_table(struct hardirq_bpf *obj) +{ + hardirq_maps[HARDIRQ_MAP_LATENCY].map_fd = bpf_map__fd(obj->maps.tbl_hardirq); + hardirq_maps[HARDIRQ_MAP_LATENCY_STATIC].map_fd = bpf_map__fd(obj->maps.tbl_hardirq_static); +} + +/** + * Load and Attach + * + * Load and attach bpf software. + */ +static inline int ebpf_hardirq_load_and_attach(struct hardirq_bpf *obj) +{ + int ret = hardirq_bpf__load(obj); + if (ret) { + return -1; + } + + return hardirq_bpf__attach(obj); +} +#endif + /***************************************************************** * * ARAL SECTION @@ -540,6 +568,40 @@ static void hardirq_collector(ebpf_module_t *em) * EBPF HARDIRQ THREAD *****************************************************************/ +/* + * Load BPF + * + * Load BPF files. + * + * @param em the structure with configuration + * + * @return It returns 0 on success and -1 otherwise. + */ +static int ebpf_hardirq_load_bpf(ebpf_module_t *em) +{ + int ret = 0; + if (em->load & EBPF_LOAD_LEGACY) { + em->probe_links = ebpf_load_program(ebpf_plugin_dir, em, running_on_kernel, isrh, &em->objects); + if (!em->probe_links) { + ret = -1; + } + } +#ifdef LIBBPF_MAJOR_VERSION + else { + hardirq_bpf_obj = hardirq_bpf__open(); + if (!hardirq_bpf_obj) + ret = -1; + else { + ret = ebpf_hardirq_load_and_attach(hardirq_bpf_obj); + if (!ret) + ebpf_hardirq_set_hash_table(hardirq_bpf_obj); + } + } +#endif + + return ret; +} + /** * Hard IRQ latency thread. * @@ -559,9 +621,9 @@ void *ebpf_hardirq_thread(void *ptr) #ifdef LIBBPF_MAJOR_VERSION ebpf_define_map_type(em->maps, em->maps_per_core, running_on_kernel); + ebpf_adjust_thread_load(em, default_btf); #endif - em->probe_links = ebpf_load_program(ebpf_plugin_dir, em, running_on_kernel, isrh, &em->objects); - if (!em->probe_links) { + if (ebpf_hardirq_load_bpf(em)) { goto endhardirq; } diff --git a/collectors/ebpf.plugin/ebpf_hardirq.h b/collectors/ebpf.plugin/ebpf_hardirq.h index 52dea1e560..d727ed3ae5 100644 --- a/collectors/ebpf.plugin/ebpf_hardirq.h +++ b/collectors/ebpf.plugin/ebpf_hardirq.h @@ -34,6 +34,11 @@ enum hardirq_ebpf_static { HARDIRQ_EBPF_STATIC_END }; +enum hardirq_maps { + HARDIRQ_MAP_LATENCY, + HARDIRQ_MAP_LATENCY_STATIC +}; + typedef struct hardirq_ebpf_static_val { uint64_t latency; uint64_t ts; diff --git a/collectors/ebpf.plugin/ebpf_mdflush.c b/collectors/ebpf.plugin/ebpf_mdflush.c index 65ed860a46..7179e5e7ce 100644 --- a/collectors/ebpf.plugin/ebpf_mdflush.c +++ b/collectors/ebpf.plugin/ebpf_mdflush.c @@ -31,6 +31,10 @@ static ebpf_local_maps_t mdflush_maps[] = { } }; +netdata_ebpf_targets_t mdflush_targets[] = { {.name = "md_flush_request", .mode = EBPF_LOAD_TRAMPOLINE}, + {.name = NULL, .mode = EBPF_LOAD_TRAMPOLINE}}; + + // store for "published" data from the reader thread, which the collector // thread will write to netdata agent. static avl_tree_lock mdflush_pub; @@ -38,6 +42,93 @@ static avl_tree_lock mdflush_pub; // tmp store for mdflush values we get from a per-CPU eBPF map. static mdflush_ebpf_val_t *mdflush_ebpf_vals = NULL; +#ifdef LIBBPF_MAJOR_VERSION +/** + * Disable probes + * + * Disable probes to use trampolines. + * + * @param obj the loaded object structure. + */ +static inline void ebpf_disable_probes(struct mdflush_bpf *obj) +{ + bpf_program__set_autoload(obj->progs.netdata_md_flush_request_kprobe, false); +} + +/** + * Disable trampolines + * + * Disable trampoliness to use probes. + * + * @param obj the loaded object structure. + */ +static inline void ebpf_disable_trampoline(struct mdflush_bpf *obj) +{ + bpf_program__set_autoload(obj->progs.netdata_md_flush_request_fentry, false); +} + +/** + * Set Trampoline + * + * Define target to attach trampoline + * + * @param obj the loaded object structure. + */ +static void ebpf_set_trampoline_target(struct mdflush_bpf *obj) +{ + bpf_program__set_attach_target(obj->progs.netdata_md_flush_request_fentry, 0, + mdflush_targets[NETDATA_MD_FLUSH_REQUEST].name); +} + +/** + * Load probe + * + * Load probe to monitor internal function. + * + * @param obj the loaded object structure. + */ +static inline int ebpf_load_probes(struct mdflush_bpf *obj) +{ + obj->links.netdata_md_flush_request_kprobe = bpf_program__attach_kprobe(obj->progs.netdata_md_flush_request_kprobe, + false, + mdflush_targets[NETDATA_MD_FLUSH_REQUEST].name); + return libbpf_get_error(obj->links.netdata_md_flush_request_kprobe); +} + +/** + * Load and Attach + * + * Load and attach bpf codes according user selection. + * + * @param obj the loaded object structure. + * @param em the structure with configuration + */ +static inline int ebpf_mdflush_load_and_attach(struct mdflush_bpf *obj, ebpf_module_t *em) +{ + int mode = em->targets[NETDATA_MD_FLUSH_REQUEST].mode; + if (mode == EBPF_LOAD_TRAMPOLINE) { // trampoline + ebpf_disable_probes(obj); + + ebpf_set_trampoline_target(obj); + } else // kprobe + ebpf_disable_trampoline(obj); + + int ret = mdflush_bpf__load(obj); + if (ret) { + fprintf(stderr, "failed to load BPF object: %d\n", ret); + return -1; + } + + if (mode == EBPF_LOAD_TRAMPOLINE) + ret = mdflush_bpf__attach(obj); + else + ret = ebpf_load_probes(obj); + + return ret; +} + +#endif + /** * MDflush exit * @@ -235,6 +326,49 @@ static void mdflush_collector(ebpf_module_t *em) } } +/* + * Load BPF + * + * Load BPF files. + * + * @param em the structure with configuration + * + * @return It returns 0 on success and -1 otherwise. + */ +static int ebpf_mdflush_load_bpf(ebpf_module_t *em) +{ + int ret = 0; + if (em->load & EBPF_LOAD_LEGACY) { + em->probe_links = ebpf_load_program(ebpf_plugin_dir, em, running_on_kernel, isrh, &em->objects); + if (!em->probe_links) { + ret = -1; + } + } +#ifdef LIBBPF_MAJOR_VERSION + else { + mdflush_bpf_obj = mdflush_bpf__open(); + if (!mdflush_bpf_obj) + ret = -1; + else { + ret = ebpf_mdflush_load_and_attach(mdflush_bpf_obj, em); + if (ret && em->targets[NETDATA_MD_FLUSH_REQUEST].mode == EBPF_LOAD_TRAMPOLINE) { + mdflush_bpf__destroy(mdflush_bpf_obj); + mdflush_bpf_obj = mdflush_bpf__open(); + if (!mdflush_bpf_obj) + ret = -1; + else { + em->targets[NETDATA_MD_FLUSH_REQUEST].mode = EBPF_LOAD_PROBE; + ret = ebpf_mdflush_load_and_attach(mdflush_bpf_obj, em); + } + } + } + } +#endif + + return ret; +} + + /** * mdflush thread. * @@ -256,9 +390,10 @@ void *ebpf_mdflush_thread(void *ptr) #ifdef LIBBPF_MAJOR_VERSION ebpf_define_map_type(em->maps, em->maps_per_core, running_on_kernel); + ebpf_adjust_thread_load(em, default_btf); #endif - em->probe_links = ebpf_load_program(ebpf_plugin_dir, em, running_on_kernel, isrh, &em->objects); - if (!em->probe_links) { + if (ebpf_mdflush_load_bpf(em)) { + error("Cannot load eBPF software."); goto endmdflush; } diff --git a/collectors/ebpf.plugin/ebpf_mdflush.h b/collectors/ebpf.plugin/ebpf_mdflush.h index 4913ad019d..c0b0eca682 100644 --- a/collectors/ebpf.plugin/ebpf_mdflush.h +++ b/collectors/ebpf.plugin/ebpf_mdflush.h @@ -33,8 +33,15 @@ typedef struct netdata_mdflush { uint64_t cnt; } netdata_mdflush_t; +enum netdata_mdflush_targets { + NETDATA_MD_FLUSH_REQUEST, + + NETDATA_MD_FLUSH_END +}; + void *ebpf_mdflush_thread(void *ptr); extern struct config mdflush_config; +extern netdata_ebpf_targets_t mdflush_targets[]; #endif diff --git a/libnetdata/ebpf/ebpf.h b/libnetdata/ebpf/ebpf.h index e82aaedd47..455372753d 100644 --- a/libnetdata/ebpf/ebpf.h +++ b/libnetdata/ebpf/ebpf.h @@ -340,6 +340,16 @@ typedef struct netdata_ebpf_histogram { uint64_t histogram[NETDATA_EBPF_HIST_MAX_BINS]; } netdata_ebpf_histogram_t; +enum fs_btf_counters { + NETDATA_KEY_BTF_READ, + NETDATA_KEY_BTF_WRITE, + NETDATA_KEY_BTF_OPEN, + NETDATA_KEY_BTF_SYNC_ATTR, + NETDATA_KEY_BTF_OPEN2, + + NETDATA_FS_BTF_END +}; + typedef struct ebpf_filesystem_partitions { char *filesystem; char *optional_filesystem; @@ -359,6 +369,14 @@ typedef struct ebpf_filesystem_partitions { ebpf_addresses_t addresses; uint64_t kernels; ebpf_local_maps_t *fs_maps; + + // BPF structure +#ifdef LIBBPF_MAJOR_VERSION + struct filesystem_bpf *fs_obj; +#else + void *fs_obj; +#endif + const char *functions[NETDATA_FS_BTF_END]; } ebpf_filesystem_partitions_t; typedef struct ebpf_sync_syscalls { |