Commit fe20ce3a authored by Daniel Borkmann's avatar Daniel Borkmann Committed by Alexei Starovoitov
Browse files

libbpf: Add opts-based attach/detach/query API for tcx



Extend libbpf attach opts and add a new detach opts API so this can be used
to add/remove fd-based tcx BPF programs. The old-style bpf_prog_detach() and
bpf_prog_detach2() APIs are refactored to reuse the new bpf_prog_detach_opts()
internally.

The bpf_prog_query_opts() API got extended to be able to handle the new
link_ids, link_attach_flags and revision fields.

For concrete usage examples, see the extensive selftests that have been
developed as part of this series.

Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
Acked-by: default avatarAndrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/r/20230719140858.13224-4-daniel@iogearbox.net


Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parent e420bed0
Loading
Loading
Loading
Loading
+71 −36
Original line number Diff line number Diff line
@@ -629,57 +629,91 @@ int bpf_prog_attach(int prog_fd, int target_fd, enum bpf_attach_type type,
	return bpf_prog_attach_opts(prog_fd, target_fd, type, &opts);
}

int bpf_prog_attach_opts(int prog_fd, int target_fd,
			  enum bpf_attach_type type,
int bpf_prog_attach_opts(int prog_fd, int target, enum bpf_attach_type type,
			 const struct bpf_prog_attach_opts *opts)
{
	const size_t attr_sz = offsetofend(union bpf_attr, replace_bpf_fd);
	const size_t attr_sz = offsetofend(union bpf_attr, expected_revision);
	__u32 relative_id, flags;
	int ret, relative_fd;
	union bpf_attr attr;
	int ret;

	if (!OPTS_VALID(opts, bpf_prog_attach_opts))
		return libbpf_err(-EINVAL);

	relative_id = OPTS_GET(opts, relative_id, 0);
	relative_fd = OPTS_GET(opts, relative_fd, 0);
	flags = OPTS_GET(opts, flags, 0);

	/* validate we don't have unexpected combinations of non-zero fields */
	if (relative_fd && relative_id)
		return libbpf_err(-EINVAL);

	memset(&attr, 0, attr_sz);
	attr.target_fd	   = target_fd;
	attr.target_fd		= target;
	attr.attach_bpf_fd	= prog_fd;
	attr.attach_type	= type;
	attr.attach_flags  = OPTS_GET(opts, flags, 0);
	attr.replace_bpf_fd = OPTS_GET(opts, replace_prog_fd, 0);
	attr.replace_bpf_fd	= OPTS_GET(opts, replace_fd, 0);
	attr.expected_revision	= OPTS_GET(opts, expected_revision, 0);

	if (relative_id) {
		attr.attach_flags = flags | BPF_F_ID;
		attr.relative_id  = relative_id;
	} else {
		attr.attach_flags = flags;
		attr.relative_fd  = relative_fd;
	}

	ret = sys_bpf(BPF_PROG_ATTACH, &attr, attr_sz);
	return libbpf_err_errno(ret);
}

int bpf_prog_detach(int target_fd, enum bpf_attach_type type)
int bpf_prog_detach_opts(int prog_fd, int target, enum bpf_attach_type type,
			 const struct bpf_prog_detach_opts *opts)
{
	const size_t attr_sz = offsetofend(union bpf_attr, replace_bpf_fd);
	const size_t attr_sz = offsetofend(union bpf_attr, expected_revision);
	__u32 relative_id, flags;
	int ret, relative_fd;
	union bpf_attr attr;
	int ret;

	memset(&attr, 0, attr_sz);
	attr.target_fd	 = target_fd;
	attr.attach_type = type;
	if (!OPTS_VALID(opts, bpf_prog_detach_opts))
		return libbpf_err(-EINVAL);

	ret = sys_bpf(BPF_PROG_DETACH, &attr, attr_sz);
	return libbpf_err_errno(ret);
}
	relative_id = OPTS_GET(opts, relative_id, 0);
	relative_fd = OPTS_GET(opts, relative_fd, 0);
	flags = OPTS_GET(opts, flags, 0);

int bpf_prog_detach2(int prog_fd, int target_fd, enum bpf_attach_type type)
{
	const size_t attr_sz = offsetofend(union bpf_attr, replace_bpf_fd);
	union bpf_attr attr;
	int ret;
	/* validate we don't have unexpected combinations of non-zero fields */
	if (relative_fd && relative_id)
		return libbpf_err(-EINVAL);

	memset(&attr, 0, attr_sz);
	attr.target_fd	 = target_fd;
	attr.target_fd		= target;
	attr.attach_bpf_fd	= prog_fd;
	attr.attach_type	= type;
	attr.expected_revision	= OPTS_GET(opts, expected_revision, 0);

	if (relative_id) {
		attr.attach_flags = flags | BPF_F_ID;
		attr.relative_id  = relative_id;
	} else {
		attr.attach_flags = flags;
		attr.relative_fd  = relative_fd;
	}

	ret = sys_bpf(BPF_PROG_DETACH, &attr, attr_sz);
	return libbpf_err_errno(ret);
}

int bpf_prog_detach(int target_fd, enum bpf_attach_type type)
{
	return bpf_prog_detach_opts(0, target_fd, type, NULL);
}

int bpf_prog_detach2(int prog_fd, int target_fd, enum bpf_attach_type type)
{
	return bpf_prog_detach_opts(prog_fd, target_fd, type, NULL);
}

int bpf_link_create(int prog_fd, int target_fd,
		    enum bpf_attach_type attach_type,
		    const struct bpf_link_create_opts *opts)
@@ -841,8 +875,7 @@ int bpf_iter_create(int link_fd)
	return libbpf_err_errno(fd);
}

int bpf_prog_query_opts(int target_fd,
			enum bpf_attach_type type,
int bpf_prog_query_opts(int target, enum bpf_attach_type type,
			struct bpf_prog_query_opts *opts)
{
	const size_t attr_sz = offsetofend(union bpf_attr, query);
@@ -853,18 +886,20 @@ int bpf_prog_query_opts(int target_fd,
		return libbpf_err(-EINVAL);

	memset(&attr, 0, attr_sz);

	attr.query.target_fd	= target_fd;
	attr.query.target_fd		= target;
	attr.query.attach_type		= type;
	attr.query.query_flags		= OPTS_GET(opts, query_flags, 0);
	attr.query.prog_cnt	= OPTS_GET(opts, prog_cnt, 0);
	attr.query.count		= OPTS_GET(opts, count, 0);
	attr.query.prog_ids		= ptr_to_u64(OPTS_GET(opts, prog_ids, NULL));
	attr.query.link_ids		= ptr_to_u64(OPTS_GET(opts, link_ids, NULL));
	attr.query.prog_attach_flags	= ptr_to_u64(OPTS_GET(opts, prog_attach_flags, NULL));
	attr.query.link_attach_flags	= ptr_to_u64(OPTS_GET(opts, link_attach_flags, NULL));

	ret = sys_bpf(BPF_PROG_QUERY, &attr, attr_sz);

	OPTS_SET(opts, attach_flags, attr.query.attach_flags);
	OPTS_SET(opts, prog_cnt, attr.query.prog_cnt);
	OPTS_SET(opts, revision, attr.query.revision);
	OPTS_SET(opts, count, attr.query.count);

	return libbpf_err_errno(ret);
}
+78 −14
Original line number Diff line number Diff line
@@ -312,21 +312,67 @@ 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);

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_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 */
	unsigned int flags;
	__u32 flags;
	union {
		int replace_prog_fd;
		int replace_fd;
	};
#define bpf_prog_attach_opts__last_field replace_prog_fd
	int relative_fd;
	__u32 relative_id;
	__u64 expected_revision;
	size_t :0;
};
#define bpf_prog_attach_opts__last_field expected_revision

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,
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);
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);

/**
 * @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 {
@@ -495,13 +541,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,
+9 −3
Original line number Diff line number Diff line
@@ -118,6 +118,8 @@ static const char * const attach_type_name[] = {
	[BPF_TRACE_KPROBE_MULTI]	= "trace_kprobe_multi",
	[BPF_STRUCT_OPS]		= "struct_ops",
	[BPF_NETFILTER]			= "netfilter",
	[BPF_TCX_INGRESS]		= "tcx_ingress",
	[BPF_TCX_EGRESS]		= "tcx_egress",
};

static const char * const link_type_name[] = {
@@ -8696,9 +8698,13 @@ static const struct bpf_sec_def section_defs[] = {
	SEC_DEF("ksyscall+",		KPROBE,	0, SEC_NONE, attach_ksyscall),
	SEC_DEF("kretsyscall+",		KPROBE, 0, SEC_NONE, attach_ksyscall),
	SEC_DEF("usdt+",		KPROBE,	0, SEC_NONE, attach_usdt),
	SEC_DEF("tc",			SCHED_CLS, 0, SEC_NONE),
	SEC_DEF("classifier",		SCHED_CLS, 0, SEC_NONE),
	SEC_DEF("action",		SCHED_ACT, 0, SEC_NONE),
	SEC_DEF("tc/ingress",		SCHED_CLS, BPF_TCX_INGRESS, SEC_NONE), /* alias for tcx */
	SEC_DEF("tc/egress",		SCHED_CLS, BPF_TCX_EGRESS, SEC_NONE),  /* alias for tcx */
	SEC_DEF("tcx/ingress",		SCHED_CLS, BPF_TCX_INGRESS, SEC_NONE),
	SEC_DEF("tcx/egress",		SCHED_CLS, BPF_TCX_EGRESS, SEC_NONE),
	SEC_DEF("tc",			SCHED_CLS, 0, SEC_NONE), /* deprecated / legacy, use tcx */
	SEC_DEF("classifier",		SCHED_CLS, 0, SEC_NONE), /* deprecated / legacy, use tcx */
	SEC_DEF("action",		SCHED_ACT, 0, SEC_NONE), /* deprecated / legacy, use tcx */
	SEC_DEF("tracepoint+",		TRACEPOINT, 0, SEC_NONE, attach_tp),
	SEC_DEF("tp+",			TRACEPOINT, 0, SEC_NONE, attach_tp),
	SEC_DEF("raw_tracepoint+",	RAW_TRACEPOINT, 0, SEC_NONE, attach_raw_tp),
+1 −0
Original line number Diff line number Diff line
@@ -395,5 +395,6 @@ LIBBPF_1.2.0 {
LIBBPF_1.3.0 {
	global:
		bpf_obj_pin_opts;
		bpf_prog_detach_opts;
		bpf_program__attach_netfilter;
} LIBBPF_1.2.0;