Add doxygen comment blocks for all public bpf_link_* APIs in tools/lib/bpf/bpf.h. These doc comments are for: -bpf_link_create() -bpf_link_detach() -bpf_link_update() -bpf_link_get_next_id() -bpf_link_get_fd_by_id() -bpf_link_get_fd_by_id_opts() Signed-off-by: Jianyun Gao --- v1->v2: - Fixed the non-ASCII characters in this patch. The v1 is here: https://lore.kernel.org/lkml/20251031032627.1414462-4-jianyungao89@gmail.com/ tools/lib/bpf/bpf.h | 482 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 479 insertions(+), 3 deletions(-) diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h index cd96d7afed6b..9040fc891b81 100644 --- a/tools/lib/bpf/bpf.h +++ b/tools/lib/bpf/bpf.h @@ -1208,11 +1208,195 @@ struct bpf_link_create_opts { size_t :0; }; #define bpf_link_create_opts__last_field uprobe_multi.pid - +/** + * @brief Create a persistent BPF link that attaches a loaded BPF program to a + * kernel hook or target object. + * + * bpf_link_create() wraps the BPF_LINK_CREATE syscall command and establishes + * a first-class in-kernel "link" object representing the attachment of + * @p prog_fd to @p target_fd (or to a kernel entity implied by @p attach_type). + * The returned FD (>= 0) owns the lifetime of that attachment: closing it + * cleanly detaches the program without requiring a separate detach syscall. + * + * Compared to legacy bpf_prog_attach()/bpf_raw_tracepoint_open(), link-based + * attachment: + * - Provides explicit lifetime control (close(link_fd) == detach). + * - Enables richer introspection via bpf_link_get_info_by_fd(). + * - Avoids ambiguous detach semantics and races inherent in "implicit detach + * on last program FD close" patterns. + * + * Typical usage: + * struct bpf_link_create_opts opts = { + * .sz = sizeof(opts), + * .flags = 0, + * }; + * int link_fd = bpf_link_create(prog_fd, target_fd, BPF_TRACE_FENTRY, &opts); + * if (link_fd < 0) { + * // handle error + * } + * // ... use link_fd; close(link_fd) to detach later. + * + * @param prog_fd + * File descriptor of a previously loaded BPF program (from bpf_prog_load() + * or libbpf higher-level loader). Must be valid and compatible with + * @p attach_type. + * + * @param target_fd + * File descriptor of the attach target, when required by @p attach_type + * (e.g. a cgroup FD, perf event FD, network interface, or another BPF + * object). For some attach types (e.g. certain tracing variants) this may + * be -1 or ignored; passing an inappropriate FD yields -EINVAL. + * + * @param attach_type + * Enumeration value (enum bpf_attach_type) describing the hook/context + * at which the program should be executed (e.g. BPF_CGROUP_INET_INGRESS, + * BPF_TRACE_FENTRY, BPF_PERF_EVENT, BPF_NETFILTER, etc.). The program's + * bpf_prog_type and expected_attach_type must be compatible; otherwise + * verification will fail or the syscall returns -EINVAL/-EOPNOTSUPP. + * + * @param opts + * Optional pointer to a zero-initialized struct bpf_link_create_opts + * extended options; may be NULL for defaults. Must set opts->sz to + * sizeof(struct bpf_link_create_opts) when non-NULL. + * + * Common fields: + * - .flags: Link creation flags (most callers set 0; future kernels + * may define bits for pinning behaviors, exclusivity, etc.). + * - .target_btf_id: For BTF-enabled tracing/fentry/fexit/kprobe multi + * scenarios, identifies a BTF entity (function/type) this link + * targets. + * - .iter_info / .iter_info_len: Provide iterator-specific metadata + * for BPF iter programs. + * + * Attach-type specific nested unions: + * - .perf_event.bpf_cookie: User-defined cookie visible to program via + * bpf_get_attach_cookie() for PERF_EVENT and some tracing types. + * - .kprobe_multi: Batch (multi) kprobe attachment: + * * flags: KPROBE_MULTI_* flags controlling semantics. + * * cnt: Number of symbols/addresses. + * * syms / addrs: Symbol names or raw addresses (one of them + * used depending on kernel capabilities). + * * cookies: Optional per-probe cookies. + * - .uprobe_multi: Batch uprobes: + * * path: Target binary path. + * * offsets / ref_ctr_offsets: Instruction/file offsets and + * optional reference counter offsets. + * * pid: Target PID (0 for any or to let kernel decide). + * * cookies: Per-uprobe cookies. + * - .tracing.cookie: Generic tracing cookie for newer tracing types. + * - .netfilter: Attaching to Netfilter with: + * * pf (protocol family), hooknum, priority, flags. + * - .tcx / .netkit / .cgroup: Relative attachment variants allowing + * multi-attach ordering and revision consistency: + * * relative_fd / relative_id: Anchor or neighbor link/program. + * * expected_revision: Revision check to avoid races (fail with + * -ESTALE if mismatch). + * + * Zero any fields you do not explicitly use for forward compatibility. + * + * @return + * >= 0 : Link file descriptor (attachment active). + * < 0 : Negative error code (attachment failed; program not attached). + * + * Error Handling (negative libbpf-style codes; errno also set): + * - -EINVAL: Invalid prog_fd/target_fd/attach_type combination, malformed + * opts, bad sizes, unsupported flags, or missing required union + * fields. + * - -EOPNOTSUPP / -ENOTSUP: Attach type or creation mode unsupported by + * running kernel. + * - -EPERM / -EACCES: Insufficient privileges (CAP_BPF/CAP_SYS_ADMIN) or + * blocked by LSM/lockdown. + * - -ENOENT: Target object no longer exists (race) or unresolved symbol for + * kprobe/uprobes multi-attach. + * - -EBADF: Invalid file descriptor(s). + * - -ENOMEM: Kernel memory/resource exhaustion. + * - -ESTALE: Revision mismatch when using expected_revision (atomicity guard). + * - Other negative codes: Propagated from underlying bpf() syscall failures. + * + * Lifetime & Ownership: + * - Success returns a link FD. Caller must close() it to detach. + * - Closing the original program FD does NOT detach the link; only closing + * the link FD (or explicit bpf_link_detach()) does. + * - Link FDs can be pinned to bpffs via bpf_obj_pin() for persistence. + * + * Concurrency & Races: + * - Linking can fail if another concurrent operation changes target's state + * (revision checks can mitigate using expected_revision). + * - Multi-attach environments may reorder relative attachments if not using + * relative_* fields; always inspect returned link state if ordering matters. + * + * Introspection: + * - Use bpf_link_get_info_by_fd(link_fd, ...) to query link metadata + * (program ID, attach type, target, cookies, multi-probe details). + * - Enumerate existing links via bpf_link_get_next_id() then open with + * bpf_link_get_fd_by_id(). + * + */ LIBBPF_API int bpf_link_create(int prog_fd, int target_fd, enum bpf_attach_type attach_type, const struct bpf_link_create_opts *opts); - +/** + * @brief Detach (tear down) an existing BPF link represented by a link file descriptor. + * + * bpf_link_detach() issues the BPF_LINK_DETACH command to the kernel, breaking + * the association between a previously created BPF link (see bpf_link_create()) + * and its target (cgroup, tracing hook, perf event, netfilter hook, etc.). After + * a successful call the program will no longer be invoked at that attach point. + * + * In most cases you do not need to call bpf_link_detach() explicitly; simply + * closing the link FD (close(link_fd)) also detaches the link. This helper is + * useful when you want to explicitly detach early while keeping the FD open for + * introspection (e.g., querying link info after detachment) or when building + * higher-level lifecycle abstractions. + * + * Semantics: + * - Success makes the in-kernel link inactive; subsequent events at the hook + * no longer trigger the program. + * - The link FD itself does NOT automatically close; you are still responsible + * for close(link_fd) to release user space resources. + * - Repeated calls after a successful detach will fail (idempotency: only the + * first detach succeeds). + * + * Typical usage: + * int link_fd = bpf_link_create(prog_fd, target_fd, attach_type, &opts); + * ... + * if (bpf_link_detach(link_fd) < 0) + * perror("bpf_link_detach"); + * close(link_fd); // optional: now just releases the FD + * + * Concurrency & races: + * - Detaching can race with another thread closing or detaching the same link. + * In such cases you may observe -EBADF or -ENOENT. + * - Once detached, the program can be safely re-attached elsewhere if desired + * (requires a new link via bpf_link_create()). + * + * Privileges: + * - Usually requires CAP_BPF and/or CAP_SYS_ADMIN depending on kernel + * configuration, LSM, and lockdown mode. Lack of privileges yields -EPERM + * or -EACCES. + * + * Post-detach: + * - The program object remains loaded; its own FD is still valid and can be + * attached again. + * - Maps referenced by the program are unaffected. + * + * @param link_fd File descriptor of the active BPF link to detach; must have + * been obtained via bpf_link_create() or equivalent. + * + * @return 0 on success; < 0 on failure (negative error code as described above). + * + * Error handling (negative libbpf-style return codes, errno also set): + * - -EBADF: link_fd is not a valid open file descriptor. + * - -EINVAL: link_fd does not refer to a BPF link, or the kernel does not + * support BPF_LINK_DETACH for this link type. + * - -ENOENT: Link already detached or no longer exists (race with close()). + * - -EPERM / -EACCES: Insufficient privileges or denied by security policy. + * - -EOPNOTSUPP / -ENOTSUP: Kernel lacks support for link detachment of this + * specific attach type. + * - -ENOMEM: Transient kernel resource exhaustion (rare in this path). + * - Other negative codes may be propagated from the underlying bpf() syscall. + * + */ LIBBPF_API int bpf_link_detach(int link_fd); struct bpf_link_update_opts { @@ -1222,7 +1406,89 @@ struct bpf_link_update_opts { __u32 old_map_fd; /* expected old map FD */ }; #define bpf_link_update_opts__last_field old_map_fd - +/** + * @brief Atomically replace (update) the BPF program or map referenced by an + * existing link with a new program. + * + * bpf_link_update() wraps the BPF_LINK_UPDATE command of the bpf(2) syscall. + * It allows retargeting an already established BPF link (identified by + * link_fd) to point at a different loaded BPF program (new_prog_fd) without + * having to tear the link down (detach) and recreate it. This is typically + * used for hot-swapping a program while preserving: + * - Link pinning (bpffs path remains valid). + * - Relative ordering in multi-attach contexts (TC/XDP/cgroup revisions). + * - Existing references held by other processes. + * + * Consistency & safety: + * - The update is performed atomically: events arriving at the hook will + * either see the old program before the call, or the new one after the + * call; no window exists with an unattached link. + * - Optional expectations can be enforced via @p opts to avoid races: + * * old_prog_fd: Fail with -ESTALE if the link does not currently + * reference that program. + * * old_map_fd: (Kernel dependent) Can be used when links encapsulate + * a map association; if set and mismatched, update fails. + * * flags: Future extension bits (must be 0 on current kernels). + * + * Typical usage: + * struct bpf_link_update_opts u = { + * .sz = sizeof(u), + * .flags = 0, + * .old_prog_fd = old_fd, // set to 0 to skip validation + * }; + * if (bpf_link_update(link_fd, new_prog_fd, &u) < 0) + * perror("bpf_link_update"); + * + * Preconditions: + * - link_fd must refer to a valid, updatable BPF link. Not all link types + * support in-place program replacement; unsupported types return -EOPNOTSUPP. + * - new_prog_fd must be a loaded BPF program whose type and expected attach + * type are compatible with the link's attach context. + * - If @p opts is non-NULL, opts->sz MUST be set to sizeof(*opts). + * + * @param link_fd + * File descriptor of the existing BPF link to be updated. + * @param new_prog_fd + * File descriptor of the newly loaded BPF program that should replace + * the currently attached program. + * @param opts + * Optional pointer to bpf_link_update_opts controlling validation: + * - sz: Structure size for forward/backward compatibility. + * - flags: Reserved; must be 0 (unsupported bits yield -EINVAL). + * - old_prog_fd: Expected current program FD (0 to skip check). + * - old_map_fd: Expected current map FD (0 to skip; kernel-specific). + * Pass NULL for default (no expectation checks). + * + * @return + * 0 on success (link now points to new_prog_fd). + * <0 negative libbpf-style error code (typically -errno): + * - -EBADF: Invalid link_fd or new_prog_fd. + * - -EINVAL: Malformed opts (bad sz/flags) or incompatible program type. + * - -EOPNOTSUPP: Link type does not support updates. + * - -EPERM / -EACCES: Insufficient privileges (CAP_BPF/CAP_SYS_ADMIN) or blocked by LSM. + * - -ENOENT: Link no longer exists (race) or old_prog_fd refers to a non-existent program. + * - -ESTALE: Expectation mismatch (old_prog_fd / old_map_fd differs). + * - -ENOMEM: Kernel resource allocation failure. + * - Other -errno codes propagated from the bpf() syscall. + * + * Postconditions: + * - On success, the old program remains loaded; caller should close its FD + * if no longer needed. + * - Pinning status and link ID are preserved. + * - Maps referenced by the new program must be valid; no automatic rebinding + * occurs beyond program substitution. + * + * Caveats: + * - If verifier features differ (e.g., CO-RE relocations) ensure the new + * program was loaded with compatible expectations for the same hook. + * - Updating to a program of a strictly different attach semantics (e.g., + * sleepable vs non-sleepable) is rejected if the link type disallows it. + * + * Thread safety: + * - Safe to call concurrently with other update attempts; only one succeeds. + * - Consumers of the link see either old or new program; intermediate states + * are not observable. + */ LIBBPF_API int bpf_link_update(int link_fd, int new_prog_fd, const struct bpf_link_update_opts *opts); @@ -1338,6 +1604,72 @@ LIBBPF_API int bpf_prog_get_next_id(__u32 start_id, __u32 *next_id); */ LIBBPF_API int bpf_map_get_next_id(__u32 start_id, __u32 *next_id); LIBBPF_API int bpf_btf_get_next_id(__u32 start_id, __u32 *next_id); +/** + * @brief Retrieve the next existing BPF link ID after a given starting ID. + * + * This helper wraps the kernel's BPF_LINK_GET_NEXT_ID command and enumerates + * system-wide BPF link objects (each representing a persistent attachment of + * a BPF program) in strictly ascending order of their kernel-assigned IDs. + * It is typically used to iterate over all currently existing BPF links from + * user space. + * + * Enumeration pattern: + * 1. Initialize start_id to 0 to obtain the first (lowest) existing link ID. + * 2. On success, *next_id is set to the first link ID strictly greater than start_id. + * 3. Use the returned *next_id as the new start_id for the subsequent call. + * 4. Repeat until the function returns -ENOENT, indicating there is no link + * with ID greater than start_id (end of enumeration). + * + * Concurrency & races: + * - Links can be created or detached concurrently with enumeration. A link ID + * you just retrieved might become invalid before you convert it to an FD + * (via bpf_link_get_fd_by_id()). Always handle failures when opening by ID. + * - Enumeration does not provide a consistent snapshot; links created after + * you pass their predecessor ID may appear in later iterations. + * + * Lifetime considerations: + * - Link IDs are monotonically increasing and not reused until wraparound + * (effectively unreachable in normal operation). + * - Successfully retrieving an ID does not pin or otherwise prevent link + * detachment; obtain an FD immediately if you need to interact with the link. + * + * Usage example: + * __u32 id = 0, next; + * while (bpf_link_get_next_id(id, &next) == 0) { + * int link_fd = bpf_link_get_fd_by_id(next); + * if (link_fd >= 0) { + * // Inspect link (e.g., bpf_link_get_info_by_fd(link_fd)) + * close(link_fd); + * } + * id = next; + * } + * // Loop terminates when -ENOENT is returned. + * + * @param start_id + * Starting point for the search. The helper finds the first link ID + * strictly greater than start_id. Use 0 to begin enumeration. + * @param next_id + * Pointer to a __u32 that receives the next link ID on success. + * Must not be NULL. + * + * @return + * 0 on success (next_id populated); + * -ENOENT if there is no link ID greater than start_id (end of iteration); + * -EINVAL if next_id is NULL or invalid arguments were supplied; + * -EPERM / -EACCES if denied by security policy or lacking required privileges; + * Other negative libbpf-style errors (-errno) on transient or system failures. + * + * Error handling notes: + * - Treat -ENOENT as normal termination (not an error condition). + * - For other negative returns, errno will also be set to the underlying cause. + * + * After enumeration: + * - Convert retrieved IDs to FDs with bpf_link_get_fd_by_id() for introspection + * or detachment (via bpf_link_detach()). + * - Closing the FD does not destroy the link if other references remain (e.g., + * pinned in bpffs); the link persists until explicitly detached or all + * references are released. + */ LIBBPF_API int bpf_link_get_next_id(__u32 start_id, __u32 *next_id); struct bpf_get_fd_by_id_opts { @@ -1548,9 +1880,153 @@ LIBBPF_API int bpf_map_get_fd_by_id_opts(__u32 id, LIBBPF_API int bpf_btf_get_fd_by_id(__u32 id); LIBBPF_API int bpf_btf_get_fd_by_id_opts(__u32 id, const struct bpf_get_fd_by_id_opts *opts); +/** + * @brief Obtain a file descriptor for an existing BPF link given its kernel-assigned ID. + * + * bpf_link_get_fd_by_id() wraps the BPF_LINK_GET_FD_BY_ID command of the bpf(2) + * syscall. A BPF "link" is a persistent in-kernel object representing an + * attachment of a BPF program to some hook (cgroup, tracing point, perf event, + * netfilter hook, tc/xdp chain, etc.). Each link has a unique, monotonically + * increasing ID. This helper converts such an ID into a process-local file + * descriptor, allowing user space to inspect, pin, update, or detach the link. + * + * Typical enumeration + open pattern: + * __u32 id = 0, next; + * while (bpf_link_get_next_id(id, &next) == 0) { + * int link_fd = bpf_link_get_fd_by_id(next); + * if (link_fd >= 0) { + * // Use link_fd (e.g. bpf_link_get_info_by_fd(), bpf_link_detach(), pin) + * close(link_fd); + * } + * id = next; + * } + * // Loop terminates when bpf_link_get_next_id() returns -ENOENT. + * + * Concurrency & races: + * - A link may be detached (or otherwise invalidated) between discovering its ID + * and calling this function. In that case the call fails with -ENOENT. + * - Successfully retrieving a file descriptor does not prevent later detachment + * by other processes; always handle subsequent operation failures gracefully. + * + * Lifetime & ownership: + * - On success, the caller owns the returned FD and must close() it when done. + * - Closing the FD decreases the user space reference count; the underlying link + * persists while any references (FDs or pinned bpffs path) remain. + * - Detaching the link (via bpf_link_detach() or closing the last active FD) + * invalidates future operations on that FD. + * + * Privileges / access control: + * - May require CAP_BPF and/or CAP_SYS_ADMIN depending on kernel configuration, + * LSM policy, or lockdown mode. Lack of privileges yields -EPERM / -EACCES. + * - Security policies can deny access even if the link ID exists. + * + * Error handling (negative libbpf-style codes; errno is also set): + * - -ENOENT: No link with the specified ID (never existed or already detached). + * - -EPERM / -EACCES: Insufficient privilege or blocked by security policy. + * - -EINVAL: Invalid ID (e.g., 0) or kernel rejected the request (rare). + * - -ENOMEM: Transient kernel resource exhaustion while creating the FD. + * - -EBADF, -EFAULT, or other -errno values: Propagated from the underlying syscall. + * + * Usage notes: + * - Immediately call bpf_link_get_info_by_fd() after acquiring the FD if you need + * metadata (program ID, attach type, target, cookie, etc.). + * - To keep a link across process restarts, pin it to bpffs via bpf_obj_pin(). + * - Prefer using bpf_link_get_fd_by_id_opts() if you need extended open semantics + * (e.g., token-based delegated permissions) on newer kernels. + * + * @param id + * Kernel-assigned unique ID of the target BPF link (must be > 0). Usually + * obtained via bpf_link_get_next_id() or from a prior info query. + * + * @return + * >= 0 : File descriptor referring to the BPF link (caller must close()). + * < 0 : Negative error code (libbpf-style, typically -errno) on failure. + */ LIBBPF_API int bpf_link_get_fd_by_id(__u32 id); +/** + * @brief Obtain a file descriptor for an existing BPF link by kernel-assigned link ID + * with extended open options. + * + * bpf_link_get_fd_by_id_opts() is an extended variant of bpf_link_get_fd_by_id(). + * It wraps the BPF_LINK_GET_FD_BY_ID command of the bpf(2) syscall and converts a + * stable, monotonically increasing BPF link ID into a process-local file descriptor + * while honoring optional attributes supplied via @p opts. + * + * A BPF "link" represents a persistent attachment of a BPF program to some kernel + * hook (cgroup, tracing point, perf event, netfilter, tc/xdp chain, etc.). Links can + * be enumerated system-wide by first calling bpf_link_get_next_id(). + * + * Typical enumeration + open pattern: + * __u32 id = 0, next; + * while (bpf_link_get_next_id(id, &next) == 0) { + * struct bpf_get_fd_by_id_opts o = { + * .sz = sizeof(o), + * .open_flags = 0, + * .token_fd = 0, + * }; + * int link_fd = bpf_link_get_fd_by_id_opts(next, &o); + * if (link_fd >= 0) { + * // inspect link (e.g. bpf_link_get_info_by_fd(link_fd)) + * close(link_fd); + * } + * id = next; + * } + * // Loop ends when bpf_link_get_next_id() returns -ENOENT (no more links). + * + * Concurrency & races: + * - A link may detach between enumeration and opening; handle -ENOENT gracefully. + * - Successfully obtaining a FD does not prevent future detachment by other processes; + * subsequent operations (e.g., bpf_link_get_info_by_fd()) can still fail. + * + * Lifetime & ownership: + * - The returned FD holds a user-space reference; close() decrements it. + * - The underlying link persists while any references remain (FDs or bpffs pin). + * - Use bpf_obj_pin() to make the link persistent across process lifetimes. + * + * Security: + * - CAP_BPF and/or CAP_SYS_ADMIN may be required depending on kernel configuration. + * - Token-based access (token_fd) can allow operations in sandboxed environments. + * + * Follow-up introspection: + * - Call bpf_link_get_info_by_fd(link_fd, ...) to retrieve program ID, attach type, + * target info, cookies, and other metadata. + * - Detach via bpf_link_detach(link_fd) or simply close(link_fd). + * + * Recommended usage notes: + * - Always zero-initialize the opts struct before setting fields. + * - Treat -ENOENT after enumeration as normal termination, not an error condition. + * - Avoid relying on stable ordering beyond ascending ID sequence; links created + * during enumeration may appear after you pass their predecessor ID. + * + * @param id + * Kernel-assigned unique (non-zero) BPF link ID. Usually obtained from + * bpf_link_get_next_id() or from a prior info query. Must be > 0. + * + * @param opts + * Optional pointer to a zero-initialized struct bpf_get_fd_by_id_opts: + * - sz: MUST be set to sizeof(struct bpf_get_fd_by_id_opts) if @p opts + * is non-NULL (enables fwd/backward compatibility). + * - open_flags: Additional open/access flags (currently most callers set 0; + * unsupported bits yield -EINVAL; semantics are kernel-specific). + * - token_fd: File descriptor of a BPF token granting delegated permissions + * (set 0 or -1 if unused). Allows restricted environments to + * open the link without elevated global capabilities. + * Pass NULL for defaults (equivalent to open_flags=0, no token). + * + * @return + * >= 0 : File descriptor referencing the BPF link (caller owns it; close() when done). + * < 0 : Negative libbpf-style error code (typically -errno): + * - -ENOENT : Link with @p id does not exist (detached or never created). + * - -EPERM / -EACCES : Insufficient privilege or blocked by LSM/lockdown. + * - -EINVAL : Invalid @p id (0), malformed @p opts (bad sz / flags), or + * unsupported open_flags. + * - -ENOMEM : Transient kernel memory/resource exhaustion. + * - Other negative codes: Propagated from underlying bpf() syscall. + * + */ LIBBPF_API int bpf_link_get_fd_by_id_opts(__u32 id, const struct bpf_get_fd_by_id_opts *opts); + LIBBPF_API int bpf_obj_get_info_by_fd(int bpf_fd, void *info, __u32 *info_len); /** -- 2.34.1