diff --git a/Makefile b/Makefile index 21b1aaa1..6ffe8176 100644 --- a/Makefile +++ b/Makefile @@ -35,9 +35,9 @@ build-unit-test: cmake --build build --config Debug --target bpftime_runtime_tests unit-test: ## run catch2 unit tests - make -C runtime/test/bpf + make -C runtime/test/bpf && cp runtime/test/bpf/*.bpf.o build/runtime/test/ ./build/runtime/unit-test/bpftime_runtime_tests - cd build/runtime && ctest -VV + cd build/runtime/test && ctest -VV build: ## build the package cmake -Bbuild -DBPFTIME_ENABLE_UNIT_TESTING=1 diff --git a/runtime/src/bpftime_shm_json.cpp b/runtime/src/bpftime_shm_json.cpp index 0a003ced..d52ba5b7 100644 --- a/runtime/src/bpftime_shm_json.cpp +++ b/runtime/src/bpftime_shm_json.cpp @@ -71,21 +71,22 @@ extern "C" int bpftime_import_global_shm_from_json(const char *filename) static int import_shm_handler_from_json(bpftime_shm &shm, json value, int fd) { std::string handler_type = value["type"]; + spdlog::info("import handler type {} fd {}", handler_type, fd); if (handler_type == "bpf_prog_handler") { std::string insns_str = value["attr"]["insns"]; - std::string name = value["attr"]["name"]; + std::string name = value["name"]; int type = value["attr"]["type"]; int cnt = value["attr"]["cnt"]; std::vector insns; insns.resize(cnt); int res = hex_string_to_buffer(insns_str, (unsigned char *)insns.data(), - insns_str.size()); + insns.size() * sizeof(ebpf_inst)); if (res < 0) { spdlog::error("Failed to parse insns in json"); return -1; } - + shm.add_bpf_prog(fd, insns.data(), cnt, name.c_str(), type); } else if (handler_type == "bpf_map_handler") { std::string name = value["name"]; @@ -141,6 +142,7 @@ int bpftime::bpftime_import_shm_from_json(bpftime_shm &shm, file.close(); for (auto &[key, value] : j.items()) { int fd = std::stoi(key); + spdlog::info("import handler fd {} {}", fd, value.dump()); int res = import_shm_handler_from_json(shm, value, fd); if (res < 0) { spdlog::error("Failed to import handler from json"); @@ -182,17 +184,16 @@ int bpftime::bpftime_export_shm_to_json(const bpftime_shm &shm, const char *name = prog_handler.name.c_str(); // record the prog into json, key is the index of the // prog - j[std::to_string(i)] = { - { "type", "bpf_prog_handler" }, - { "attr", - { "type", prog_handler.type }, - { "insns", - buffer_to_hex_string( - (const unsigned char *)insns, - sizeof(ebpf_inst) * cnt) }, - { "cnt", cnt }, - { "name", name } } - }; + json attr = { { "type", prog_handler.type }, + { "insns", + buffer_to_hex_string( + (const unsigned char *)insns, + sizeof(ebpf_inst) * cnt) }, + { "cnt", cnt } }; + j[std::to_string(i)] = + json{ { "type", "bpf_prog_handler" }, + { "attr", attr }, + { "name", name } }; // append attach fds to the json for (auto &fd : prog_handler.attach_fds) { j[std::to_string(i)]["attr"]["attach_fds"] @@ -226,11 +227,12 @@ int bpftime::bpftime_export_shm_to_json(const bpftime_shm &shm, spdlog::info("epoll_handler found at {}", i); } else if (std::holds_alternative(handler)) { auto &h = std::get(handler); - j[std::to_string(i)] = { { "type", "bpf_link_handler" }, - { "attr", - { "prog_fd", h.prog_fd }, - { "target_fd", - h.target_fd } } }; + j[std::to_string(i)] = { + { "type", "bpf_link_handler" }, + { "attr", + { { "prog_fd", h.prog_fd }, + { "target_fd", h.target_fd } } } + }; spdlog::info( "bpf_link_handler found at {},link {} -> {}", i, h.prog_fd, h.target_fd); diff --git a/runtime/test/bpf/.output/bpf/bpf.h b/runtime/test/bpf/.output/bpf/bpf.h index c676295a..74c2887c 100644 --- a/runtime/test/bpf/.output/bpf/bpf.h +++ b/runtime/test/bpf/.output/bpf/bpf.h @@ -312,22 +312,68 @@ LIBBPF_API int bpf_obj_get(const char *pathname); LIBBPF_API int bpf_obj_get_opts(const char *pathname, const struct bpf_obj_get_opts *opts); -struct bpf_prog_attach_opts { - size_t sz; /* size of this struct for forward/backward compatibility */ - unsigned int flags; - int replace_prog_fd; -}; -#define bpf_prog_attach_opts__last_field replace_prog_fd - LIBBPF_API int bpf_prog_attach(int prog_fd, int attachable_fd, enum bpf_attach_type type, unsigned int flags); -LIBBPF_API int bpf_prog_attach_opts(int prog_fd, int attachable_fd, - enum bpf_attach_type type, - const struct bpf_prog_attach_opts *opts); LIBBPF_API int bpf_prog_detach(int attachable_fd, enum bpf_attach_type type); LIBBPF_API int bpf_prog_detach2(int prog_fd, int attachable_fd, enum bpf_attach_type type); +struct bpf_prog_attach_opts { + size_t sz; /* size of this struct for forward/backward compatibility */ + __u32 flags; + union { + int replace_prog_fd; + int replace_fd; + }; + int relative_fd; + __u32 relative_id; + __u64 expected_revision; + size_t :0; +}; +#define bpf_prog_attach_opts__last_field expected_revision + +struct bpf_prog_detach_opts { + size_t sz; /* size of this struct for forward/backward compatibility */ + __u32 flags; + int relative_fd; + __u32 relative_id; + __u64 expected_revision; + size_t :0; +}; +#define bpf_prog_detach_opts__last_field expected_revision + +/** + * @brief **bpf_prog_attach_opts()** attaches the BPF program corresponding to + * *prog_fd* to a *target* which can represent a file descriptor or netdevice + * ifindex. + * + * @param prog_fd BPF program file descriptor + * @param target attach location file descriptor or ifindex + * @param type attach type for the BPF program + * @param opts options for configuring the attachment + * @return 0, on success; negative error code, otherwise (errno is also set to + * the error code) + */ +LIBBPF_API int bpf_prog_attach_opts(int prog_fd, int target, + enum bpf_attach_type type, + const struct bpf_prog_attach_opts *opts); + +/** + * @brief **bpf_prog_detach_opts()** detaches the BPF program corresponding to + * *prog_fd* from a *target* which can represent a file descriptor or netdevice + * ifindex. + * + * @param prog_fd BPF program file descriptor + * @param target detach location file descriptor or ifindex + * @param type detach type for the BPF program + * @param opts options for configuring the detachment + * @return 0, on success; negative error code, otherwise (errno is also set to + * the error code) + */ +LIBBPF_API int bpf_prog_detach_opts(int prog_fd, int target, + enum bpf_attach_type type, + const struct bpf_prog_detach_opts *opts); + union bpf_iter_link_info; /* defined in up-to-date linux/bpf.h */ struct bpf_link_create_opts { size_t sz; /* size of this struct for forward/backward compatibility */ @@ -346,6 +392,15 @@ struct bpf_link_create_opts { const unsigned long *addrs; const __u64 *cookies; } kprobe_multi; + struct { + __u32 flags; + __u32 cnt; + const char *path; + const unsigned long *offsets; + const unsigned long *ref_ctr_offsets; + const __u64 *cookies; + __u32 pid; + } uprobe_multi; struct { __u64 cookie; } tracing; @@ -355,10 +410,15 @@ struct bpf_link_create_opts { __s32 priority; __u32 flags; } netfilter; + struct { + __u32 relative_fd; + __u32 relative_id; + __u64 expected_revision; + } tcx; }; size_t :0; }; -#define bpf_link_create_opts__last_field kprobe_multi.cookies +#define bpf_link_create_opts__last_field uprobe_multi.pid LIBBPF_API int bpf_link_create(int prog_fd, int target_fd, enum bpf_attach_type attach_type, @@ -495,13 +555,31 @@ struct bpf_prog_query_opts { __u32 query_flags; __u32 attach_flags; /* output argument */ __u32 *prog_ids; - __u32 prog_cnt; /* input+output argument */ + union { + /* input+output argument */ + __u32 prog_cnt; + __u32 count; + }; __u32 *prog_attach_flags; + __u32 *link_ids; + __u32 *link_attach_flags; + __u64 revision; + size_t :0; }; -#define bpf_prog_query_opts__last_field prog_attach_flags +#define bpf_prog_query_opts__last_field revision -LIBBPF_API int bpf_prog_query_opts(int target_fd, - enum bpf_attach_type type, +/** + * @brief **bpf_prog_query_opts()** queries the BPF programs and BPF links + * which are attached to *target* which can represent a file descriptor or + * netdevice ifindex. + * + * @param target query location file descriptor or ifindex + * @param type attach type for the BPF program + * @param opts options for configuring the query + * @return 0, on success; negative error code, otherwise (errno is also set to + * the error code) + */ +LIBBPF_API int bpf_prog_query_opts(int target, enum bpf_attach_type type, struct bpf_prog_query_opts *opts); LIBBPF_API int bpf_prog_query(int target_fd, enum bpf_attach_type type, __u32 query_flags, __u32 *attach_flags, diff --git a/runtime/test/bpf/.output/bpf/bpf_helper_defs.h b/runtime/test/bpf/.output/bpf/bpf_helper_defs.h index e338dbec..01c662ef 100644 --- a/runtime/test/bpf/.output/bpf/bpf_helper_defs.h +++ b/runtime/test/bpf/.output/bpf/bpf_helper_defs.h @@ -350,7 +350,9 @@ static long (*bpf_tail_call)(void *ctx, void *prog_array_map, __u32 index) = (vo * direct packet access. * * Returns - * 0 on success, or a negative error in case of failure. + * 0 on success, or a negative error in case of failure. Positive + * error indicates a potential drop or congestion in the target + * device. The particular positive error codes are not defined. */ static long (*bpf_clone_redirect)(struct __sk_buff *skb, __u32 ifindex, __u64 flags) = (void *) 13; @@ -3033,9 +3035,6 @@ static __u64 (*bpf_get_current_ancestor_cgroup_id)(int ancestor_level) = (void * * * **-EOPNOTSUPP** if the operation is not supported, for example * a call from outside of TC ingress. - * - * **-ESOCKTNOSUPPORT** if the socket type is not supported - * (reuseport). */ static long (*bpf_sk_assign)(void *ctx, void *sk, __u64 flags) = (void *) 124; @@ -4065,9 +4064,14 @@ static long (*bpf_timer_cancel)(struct bpf_timer *timer) = (void *) 172; * * Get address of the traced function (for tracing and kprobe programs). * + * When called for kprobe program attached as uprobe it returns + * probe address for both entry and return uprobe. + * + * * Returns - * Address of the traced function. + * Address of the traced function for kprobe. * 0 for kprobes placed within the function (not at the entry). + * Address of the probe for uprobe and return uprobe. */ static __u64 (*bpf_get_func_ip)(void *ctx) = (void *) 173; diff --git a/runtime/test/bpf/.output/bpf/bpf_helpers.h b/runtime/test/bpf/.output/bpf/bpf_helpers.h index bbab9ad9..77ceea57 100644 --- a/runtime/test/bpf/.output/bpf/bpf_helpers.h +++ b/runtime/test/bpf/.output/bpf/bpf_helpers.h @@ -181,6 +181,7 @@ enum libbpf_tristate { #define __ksym __attribute__((section(".ksyms"))) #define __kptr_untrusted __attribute__((btf_type_tag("kptr_untrusted"))) #define __kptr __attribute__((btf_type_tag("kptr"))) +#define __percpu_kptr __attribute__((btf_type_tag("percpu_kptr"))) #define bpf_ksym_exists(sym) ({ \ _Static_assert(!__builtin_constant_p(!!sym), #sym " should be marked as __weak"); \ diff --git a/runtime/test/bpf/.output/bpf/bpf_tracing.h b/runtime/test/bpf/.output/bpf/bpf_tracing.h index be076a40..3803479d 100644 --- a/runtime/test/bpf/.output/bpf/bpf_tracing.h +++ b/runtime/test/bpf/.output/bpf/bpf_tracing.h @@ -2,7 +2,7 @@ #ifndef __BPF_TRACING_H__ #define __BPF_TRACING_H__ -#include +#include "bpf_helpers.h" /* Scan the ARCH passed in from ARCH env variable (see Makefile) */ #if defined(__TARGET_ARCH_x86) diff --git a/runtime/test/bpf/.output/bpf/libbpf.h b/runtime/test/bpf/.output/bpf/libbpf.h index 10642ad6..47537843 100644 --- a/runtime/test/bpf/.output/bpf/libbpf.h +++ b/runtime/test/bpf/.output/bpf/libbpf.h @@ -266,6 +266,7 @@ LIBBPF_API int bpf_object__pin_programs(struct bpf_object *obj, LIBBPF_API int bpf_object__unpin_programs(struct bpf_object *obj, const char *path); LIBBPF_API int bpf_object__pin(struct bpf_object *object, const char *path); +LIBBPF_API int bpf_object__unpin(struct bpf_object *object, const char *path); LIBBPF_API const char *bpf_object__name(const struct bpf_object *obj); LIBBPF_API unsigned int bpf_object__kversion(const struct bpf_object *obj); @@ -529,6 +530,57 @@ bpf_program__attach_kprobe_multi_opts(const struct bpf_program *prog, const char *pattern, const struct bpf_kprobe_multi_opts *opts); +struct bpf_uprobe_multi_opts { + /* size of this struct, for forward/backward compatibility */ + size_t sz; + /* array of function symbols to attach to */ + const char **syms; + /* array of function addresses to attach to */ + const unsigned long *offsets; + /* optional, array of associated ref counter offsets */ + const unsigned long *ref_ctr_offsets; + /* optional, array of associated BPF cookies */ + const __u64 *cookies; + /* number of elements in syms/addrs/cookies arrays */ + size_t cnt; + /* create return uprobes */ + bool retprobe; + size_t :0; +}; + +#define bpf_uprobe_multi_opts__last_field retprobe + +/** + * @brief **bpf_program__attach_uprobe_multi()** attaches a BPF program + * to multiple uprobes with uprobe_multi link. + * + * User can specify 2 mutually exclusive set of inputs: + * + * 1) use only path/func_pattern/pid arguments + * + * 2) use path/pid with allowed combinations of + * syms/offsets/ref_ctr_offsets/cookies/cnt + * + * - syms and offsets are mutually exclusive + * - ref_ctr_offsets and cookies are optional + * + * + * @param prog BPF program to attach + * @param pid Process ID to attach the uprobe to, 0 for self (own process), + * -1 for all processes + * @param binary_path Path to binary + * @param func_pattern Regular expression to specify functions to attach + * BPF program to + * @param opts Additional options (see **struct bpf_uprobe_multi_opts**) + * @return 0, on success; negative error code, otherwise + */ +LIBBPF_API struct bpf_link * +bpf_program__attach_uprobe_multi(const struct bpf_program *prog, + pid_t pid, + const char *binary_path, + const char *func_pattern, + const struct bpf_uprobe_multi_opts *opts); + struct bpf_ksyscall_opts { /* size of this struct, for forward/backward compatibility */ size_t sz; @@ -733,6 +785,21 @@ LIBBPF_API struct bpf_link * bpf_program__attach_netfilter(const struct bpf_program *prog, const struct bpf_netfilter_opts *opts); +struct bpf_tcx_opts { + /* size of this struct, for forward/backward compatibility */ + size_t sz; + __u32 flags; + __u32 relative_fd; + __u32 relative_id; + __u64 expected_revision; + size_t :0; +}; +#define bpf_tcx_opts__last_field expected_revision + +LIBBPF_API struct bpf_link * +bpf_program__attach_tcx(const struct bpf_program *prog, int ifindex, + const struct bpf_tcx_opts *opts); + struct bpf_map; LIBBPF_API struct bpf_link *bpf_map__attach_struct_ops(const struct bpf_map *map); @@ -1105,9 +1172,10 @@ struct bpf_xdp_query_opts { __u32 skb_prog_id; /* output */ __u8 attach_mode; /* output */ __u64 feature_flags; /* output */ + __u32 xdp_zc_max_segs; /* output */ size_t :0; }; -#define bpf_xdp_query_opts__last_field feature_flags +#define bpf_xdp_query_opts__last_field xdp_zc_max_segs LIBBPF_API int bpf_xdp_attach(int ifindex, int prog_fd, __u32 flags, const struct bpf_xdp_attach_opts *opts); @@ -1161,6 +1229,7 @@ LIBBPF_API int bpf_tc_query(const struct bpf_tc_hook *hook, /* Ring buffer APIs */ struct ring_buffer; +struct ring; struct user_ring_buffer; typedef int (*ring_buffer_sample_fn)(void *ctx, void *data, size_t size); @@ -1181,6 +1250,78 @@ LIBBPF_API int ring_buffer__poll(struct ring_buffer *rb, int timeout_ms); LIBBPF_API int ring_buffer__consume(struct ring_buffer *rb); LIBBPF_API int ring_buffer__epoll_fd(const struct ring_buffer *rb); +/** + * @brief **ring_buffer__ring()** returns the ringbuffer object inside a given + * ringbuffer manager representing a single BPF_MAP_TYPE_RINGBUF map instance. + * + * @param rb A ringbuffer manager object. + * @param idx An index into the ringbuffers contained within the ringbuffer + * manager object. The index is 0-based and corresponds to the order in which + * ring_buffer__add was called. + * @return A ringbuffer object on success; NULL and errno set if the index is + * invalid. + */ +LIBBPF_API struct ring *ring_buffer__ring(struct ring_buffer *rb, + unsigned int idx); + +/** + * @brief **ring__consumer_pos()** returns the current consumer position in the + * given ringbuffer. + * + * @param r A ringbuffer object. + * @return The current consumer position. + */ +LIBBPF_API unsigned long ring__consumer_pos(const struct ring *r); + +/** + * @brief **ring__producer_pos()** returns the current producer position in the + * given ringbuffer. + * + * @param r A ringbuffer object. + * @return The current producer position. + */ +LIBBPF_API unsigned long ring__producer_pos(const struct ring *r); + +/** + * @brief **ring__avail_data_size()** returns the number of bytes in the + * ringbuffer not yet consumed. This has no locking associated with it, so it + * can be inaccurate if operations are ongoing while this is called. However, it + * should still show the correct trend over the long-term. + * + * @param r A ringbuffer object. + * @return The number of bytes not yet consumed. + */ +LIBBPF_API size_t ring__avail_data_size(const struct ring *r); + +/** + * @brief **ring__size()** returns the total size of the ringbuffer's map data + * area (excluding special producer/consumer pages). Effectively this gives the + * amount of usable bytes of data inside the ringbuffer. + * + * @param r A ringbuffer object. + * @return The total size of the ringbuffer map data area. + */ +LIBBPF_API size_t ring__size(const struct ring *r); + +/** + * @brief **ring__map_fd()** returns the file descriptor underlying the given + * ringbuffer. + * + * @param r A ringbuffer object. + * @return The underlying ringbuffer file descriptor + */ +LIBBPF_API int ring__map_fd(const struct ring *r); + +/** + * @brief **ring__consume()** consumes available ringbuffer data without event + * polling. + * + * @param r A ringbuffer object. + * @return The number of records consumed (or INT_MAX, whichever is less), or + * a negative number if any of the callbacks return an error. + */ +LIBBPF_API int ring__consume(struct ring *r); + struct user_ring_buffer_opts { size_t sz; /* size of this struct, for forward/backward compatibility */ }; diff --git a/runtime/test/bpf/.output/bpf/libbpf_common.h b/runtime/test/bpf/.output/bpf/libbpf_common.h index 9a7937f3..b7060f25 100644 --- a/runtime/test/bpf/.output/bpf/libbpf_common.h +++ b/runtime/test/bpf/.output/bpf/libbpf_common.h @@ -70,4 +70,20 @@ }; \ }) +/* Helper macro to clear and optionally reinitialize libbpf options struct + * + * Small helper macro to reset all fields and to reinitialize the common + * structure size member. Values provided by users in struct initializer- + * syntax as varargs can be provided as well to reinitialize options struct + * specific members. + */ +#define LIBBPF_OPTS_RESET(NAME, ...) \ + do { \ + memset(&NAME, 0, sizeof(NAME)); \ + NAME = (typeof(NAME)) { \ + .sz = sizeof(NAME), \ + __VA_ARGS__ \ + }; \ + } while (0) + #endif /* __LIBBPF_LIBBPF_COMMON_H */ diff --git a/runtime/test/bpf/.output/bpf/usdt.bpf.h b/runtime/test/bpf/.output/bpf/usdt.bpf.h index 0bd4c135..f6763300 100644 --- a/runtime/test/bpf/.output/bpf/usdt.bpf.h +++ b/runtime/test/bpf/.output/bpf/usdt.bpf.h @@ -4,8 +4,8 @@ #define __USDT_BPF_H__ #include -#include -#include +#include "bpf_helpers.h" +#include "bpf_tracing.h" /* Below types and maps are internal implementation details of libbpf's USDT * support and are subjects to change. Also, bpf_usdt_xxx() API helpers should