Commit caec5495 authored by Alexei Starovoitov's avatar Alexei Starovoitov
Browse files

Merge branch 'libbpf: support custom SEC() handlers'



Andrii Nakryiko says:

====================

Add ability for user applications and libraries to register custom BPF program
SEC() handlers. See patch #2 for examples where this is useful.

Patch #1 does some preliminary refactoring to allow exponsing program
init, preload, and attach callbacks as public API. It also establishes
a protocol to allow optional auto-attach behavior. This will also help the
case of sometimes auto-attachable uprobes.

v4->v5:
  - API documentation improvements (Daniel);
v3->v4:
  - init_fn -> prog_setup_fn, preload_fn -> prog_prepare_load_fn (Alexei);
v2->v3:
  - moved callbacks and cookie into OPTS struct (Alan);
  - added more test scenarios (Alan);
  - address most of Alan's feedback, but kept API name;
v1->v2:
  - resubmitting due to git send-email screw up.

Cc: Alan Maguire <alan.maguire@oracle.com>
====================

Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parents d59e3cba aa963bcb
Loading
Loading
Loading
Loading
+231 −101
Original line number Diff line number Diff line
@@ -201,12 +201,6 @@ struct reloc_desc {
	};
};

struct bpf_sec_def;

typedef int (*init_fn_t)(struct bpf_program *prog, long cookie);
typedef int (*preload_fn_t)(struct bpf_program *prog, struct bpf_prog_load_opts *opts, long cookie);
typedef struct bpf_link *(*attach_fn_t)(const struct bpf_program *prog, long cookie);

/* stored as sec_def->cookie for all libbpf-supported SEC()s */
enum sec_def_flags {
	SEC_NONE = 0,
@@ -234,14 +228,15 @@ enum sec_def_flags {
};

struct bpf_sec_def {
	const char *sec;
	char *sec;
	enum bpf_prog_type prog_type;
	enum bpf_attach_type expected_attach_type;
	long cookie;
	int handler_id;

	init_fn_t init_fn;
	preload_fn_t preload_fn;
	attach_fn_t attach_fn;
	libbpf_prog_setup_fn_t prog_setup_fn;
	libbpf_prog_prepare_load_fn_t prog_prepare_load_fn;
	libbpf_prog_attach_fn_t prog_attach_fn;
};

/*
@@ -6572,8 +6567,8 @@ static int bpf_object__sanitize_prog(struct bpf_object *obj, struct bpf_program
static int libbpf_find_attach_btf_id(struct bpf_program *prog, const char *attach_name,
				     int *btf_obj_fd, int *btf_type_id);

/* this is called as prog->sec_def->preload_fn for libbpf-supported sec_defs */
static int libbpf_preload_prog(struct bpf_program *prog,
/* this is called as prog->sec_def->prog_prepare_load_fn for libbpf-supported sec_defs */
static int libbpf_prepare_prog_load(struct bpf_program *prog,
				    struct bpf_prog_load_opts *opts, long cookie)
{
	enum sec_def_flags def = cookie;
@@ -6670,8 +6665,8 @@ static int bpf_object_load_prog_instance(struct bpf_object *obj, struct bpf_prog
	load_attr.fd_array = obj->fd_array;

	/* adjust load_attr if sec_def provides custom preload callback */
	if (prog->sec_def && prog->sec_def->preload_fn) {
		err = prog->sec_def->preload_fn(prog, &load_attr, prog->sec_def->cookie);
	if (prog->sec_def && prog->sec_def->prog_prepare_load_fn) {
		err = prog->sec_def->prog_prepare_load_fn(prog, &load_attr, prog->sec_def->cookie);
		if (err < 0) {
			pr_warn("prog '%s': failed to prepare load attributes: %d\n",
				prog->name, err);
@@ -6971,8 +6966,8 @@ static int bpf_object_init_progs(struct bpf_object *obj, const struct bpf_object
		/* sec_def can have custom callback which should be called
		 * after bpf_program is initialized to adjust its properties
		 */
		if (prog->sec_def->init_fn) {
			err = prog->sec_def->init_fn(prog, prog->sec_def->cookie);
		if (prog->sec_def->prog_setup_fn) {
			err = prog->sec_def->prog_setup_fn(prog, prog->sec_def->cookie);
			if (err < 0) {
				pr_warn("prog '%s': failed to initialize: %d\n",
					prog->name, err);
@@ -8589,20 +8584,20 @@ int bpf_program__set_log_buf(struct bpf_program *prog, char *log_buf, size_t log
}

#define SEC_DEF(sec_pfx, ptype, atype, flags, ...) {			    \
	.sec = sec_pfx,							    \
	.sec = (char *)sec_pfx,						    \
	.prog_type = BPF_PROG_TYPE_##ptype,				    \
	.expected_attach_type = atype,					    \
	.cookie = (long)(flags),					    \
	.preload_fn = libbpf_preload_prog,				    \
	.prog_prepare_load_fn = libbpf_prepare_prog_load,		    \
	__VA_ARGS__							    \
}

static struct bpf_link *attach_kprobe(const struct bpf_program *prog, long cookie);
static struct bpf_link *attach_tp(const struct bpf_program *prog, long cookie);
static struct bpf_link *attach_raw_tp(const struct bpf_program *prog, long cookie);
static struct bpf_link *attach_trace(const struct bpf_program *prog, long cookie);
static struct bpf_link *attach_lsm(const struct bpf_program *prog, long cookie);
static struct bpf_link *attach_iter(const struct bpf_program *prog, long cookie);
static int attach_kprobe(const struct bpf_program *prog, long cookie, struct bpf_link **link);
static int attach_tp(const struct bpf_program *prog, long cookie, struct bpf_link **link);
static int attach_raw_tp(const struct bpf_program *prog, long cookie, struct bpf_link **link);
static int attach_trace(const struct bpf_program *prog, long cookie, struct bpf_link **link);
static int attach_lsm(const struct bpf_program *prog, long cookie, struct bpf_link **link);
static int attach_iter(const struct bpf_program *prog, long cookie, struct bpf_link **link);

static const struct bpf_sec_def section_defs[] = {
	SEC_DEF("socket",		SOCKET_FILTER, 0, SEC_NONE | SEC_SLOPPY_PFX),
@@ -8682,25 +8677,108 @@ static const struct bpf_sec_def section_defs[] = {
	SEC_DEF("sk_lookup",		SK_LOOKUP, BPF_SK_LOOKUP, SEC_ATTACHABLE | SEC_SLOPPY_PFX),
};

#define MAX_TYPE_NAME_SIZE 32
static size_t custom_sec_def_cnt;
static struct bpf_sec_def *custom_sec_defs;
static struct bpf_sec_def custom_fallback_def;
static bool has_custom_fallback_def;

static const struct bpf_sec_def *find_sec_def(const char *sec_name)
static int last_custom_sec_def_handler_id;

int libbpf_register_prog_handler(const char *sec,
				 enum bpf_prog_type prog_type,
				 enum bpf_attach_type exp_attach_type,
				 const struct libbpf_prog_handler_opts *opts)
{
	const struct bpf_sec_def *sec_def;
	enum sec_def_flags sec_flags;
	int i, n = ARRAY_SIZE(section_defs), len;
	bool strict = libbpf_mode & LIBBPF_STRICT_SEC_NAME;
	struct bpf_sec_def *sec_def;

	for (i = 0; i < n; i++) {
		sec_def = &section_defs[i];
		sec_flags = sec_def->cookie;
		len = strlen(sec_def->sec);
	if (!OPTS_VALID(opts, libbpf_prog_handler_opts))
		return libbpf_err(-EINVAL);

	if (last_custom_sec_def_handler_id == INT_MAX) /* prevent overflow */
		return libbpf_err(-E2BIG);

	if (sec) {
		sec_def = libbpf_reallocarray(custom_sec_defs, custom_sec_def_cnt + 1,
					      sizeof(*sec_def));
		if (!sec_def)
			return libbpf_err(-ENOMEM);

		custom_sec_defs = sec_def;
		sec_def = &custom_sec_defs[custom_sec_def_cnt];
	} else {
		if (has_custom_fallback_def)
			return libbpf_err(-EBUSY);

		sec_def = &custom_fallback_def;
	}

	sec_def->sec = sec ? strdup(sec) : NULL;
	if (sec && !sec_def->sec)
		return libbpf_err(-ENOMEM);

	sec_def->prog_type = prog_type;
	sec_def->expected_attach_type = exp_attach_type;
	sec_def->cookie = OPTS_GET(opts, cookie, 0);

	sec_def->prog_setup_fn = OPTS_GET(opts, prog_setup_fn, NULL);
	sec_def->prog_prepare_load_fn = OPTS_GET(opts, prog_prepare_load_fn, NULL);
	sec_def->prog_attach_fn = OPTS_GET(opts, prog_attach_fn, NULL);

	sec_def->handler_id = ++last_custom_sec_def_handler_id;

	if (sec)
		custom_sec_def_cnt++;
	else
		has_custom_fallback_def = true;

	return sec_def->handler_id;
}

int libbpf_unregister_prog_handler(int handler_id)
{
	struct bpf_sec_def *sec_defs;
	int i;

	if (handler_id <= 0)
		return libbpf_err(-EINVAL);

	if (has_custom_fallback_def && custom_fallback_def.handler_id == handler_id) {
		memset(&custom_fallback_def, 0, sizeof(custom_fallback_def));
		has_custom_fallback_def = false;
		return 0;
	}

	for (i = 0; i < custom_sec_def_cnt; i++) {
		if (custom_sec_defs[i].handler_id == handler_id)
			break;
	}

	if (i == custom_sec_def_cnt)
		return libbpf_err(-ENOENT);

	free(custom_sec_defs[i].sec);
	for (i = i + 1; i < custom_sec_def_cnt; i++)
		custom_sec_defs[i - 1] = custom_sec_defs[i];
	custom_sec_def_cnt--;

	/* try to shrink the array, but it's ok if we couldn't */
	sec_defs = libbpf_reallocarray(custom_sec_defs, custom_sec_def_cnt, sizeof(*sec_defs));
	if (sec_defs)
		custom_sec_defs = sec_defs;

	return 0;
}

static bool sec_def_matches(const struct bpf_sec_def *sec_def, const char *sec_name,
			    bool allow_sloppy)
{
	size_t len = strlen(sec_def->sec);

	/* "type/" always has to have proper SEC("type/extras") form */
	if (sec_def->sec[len - 1] == '/') {
		if (str_has_pfx(sec_name, sec_def->sec))
				return sec_def;
			continue;
			return true;
		return false;
	}

	/* "type+" means it can be either exact SEC("type") or
@@ -8710,11 +8788,11 @@ static const struct bpf_sec_def *find_sec_def(const char *sec_name)
		len--;
		/* not even a prefix */
		if (strncmp(sec_name, sec_def->sec, len) != 0)
				continue;
			return false;
		/* exact match or has '/' separator */
		if (sec_name[len] == '\0' || sec_name[len] == '/')
				return sec_def;
			continue;
			return true;
		return false;
	}

	/* SEC_SLOPPY_PFX definitions are allowed to be just prefix
@@ -8722,21 +8800,44 @@ static const struct bpf_sec_def *find_sec_def(const char *sec_name)
	 * (LIBBPF_STRICT_SEC_NAME) is enabled, in which case the
	 * match has to be exact.
	 */
		if ((sec_flags & SEC_SLOPPY_PFX) && !strict)  {
			if (str_has_pfx(sec_name, sec_def->sec))
				return sec_def;
			continue;
		}
	if (allow_sloppy && str_has_pfx(sec_name, sec_def->sec))
		return true;

	/* Definitions not marked SEC_SLOPPY_PFX (e.g.,
	 * SEC("syscall")) are exact matches in both modes.
	 */
		if (strcmp(sec_name, sec_def->sec) == 0)
	return strcmp(sec_name, sec_def->sec) == 0;
}

static const struct bpf_sec_def *find_sec_def(const char *sec_name)
{
	const struct bpf_sec_def *sec_def;
	int i, n;
	bool strict = libbpf_mode & LIBBPF_STRICT_SEC_NAME, allow_sloppy;

	n = custom_sec_def_cnt;
	for (i = 0; i < n; i++) {
		sec_def = &custom_sec_defs[i];
		if (sec_def_matches(sec_def, sec_name, false))
			return sec_def;
	}

	n = ARRAY_SIZE(section_defs);
	for (i = 0; i < n; i++) {
		sec_def = &section_defs[i];
		allow_sloppy = (sec_def->cookie & SEC_SLOPPY_PFX) && !strict;
		if (sec_def_matches(sec_def, sec_name, allow_sloppy))
			return sec_def;
	}

	if (has_custom_fallback_def)
		return &custom_fallback_def;

	return NULL;
}

#define MAX_TYPE_NAME_SIZE 32

static char *libbpf_get_type_names(bool attach_type)
{
	int i, len = ARRAY_SIZE(section_defs) * MAX_TYPE_NAME_SIZE;
@@ -8752,7 +8853,7 @@ static char *libbpf_get_type_names(bool attach_type)
		const struct bpf_sec_def *sec_def = &section_defs[i];

		if (attach_type) {
			if (sec_def->preload_fn != libbpf_preload_prog)
			if (sec_def->prog_prepare_load_fn != libbpf_prepare_prog_load)
				continue;

			if (!(sec_def->cookie & SEC_ATTACHABLE))
@@ -9135,7 +9236,7 @@ int libbpf_attach_type_by_name(const char *name,
		return libbpf_err(-EINVAL);
	}

	if (sec_def->preload_fn != libbpf_preload_prog)
	if (sec_def->prog_prepare_load_fn != libbpf_prepare_prog_load)
		return libbpf_err(-EINVAL);
	if (!(sec_def->cookie & SEC_ATTACHABLE))
		return libbpf_err(-EINVAL);
@@ -10109,14 +10210,13 @@ struct bpf_link *bpf_program__attach_kprobe(const struct bpf_program *prog,
	return bpf_program__attach_kprobe_opts(prog, func_name, &opts);
}

static struct bpf_link *attach_kprobe(const struct bpf_program *prog, long cookie)
static int attach_kprobe(const struct bpf_program *prog, long cookie, struct bpf_link **link)
{
	DECLARE_LIBBPF_OPTS(bpf_kprobe_opts, opts);
	unsigned long offset = 0;
	struct bpf_link *link;
	const char *func_name;
	char *func;
	int n, err;
	int n;

	opts.retprobe = str_has_pfx(prog->sec_name, "kretprobe/");
	if (opts.retprobe)
@@ -10126,21 +10226,19 @@ static struct bpf_link *attach_kprobe(const struct bpf_program *prog, long cooki

	n = sscanf(func_name, "%m[a-zA-Z0-9_.]+%li", &func, &offset);
	if (n < 1) {
		err = -EINVAL;
		pr_warn("kprobe name is invalid: %s\n", func_name);
		return libbpf_err_ptr(err);
		return -EINVAL;
	}
	if (opts.retprobe && offset != 0) {
		free(func);
		err = -EINVAL;
		pr_warn("kretprobes do not support offset specification\n");
		return libbpf_err_ptr(err);
		return -EINVAL;
	}

	opts.offset = offset;
	link = bpf_program__attach_kprobe_opts(prog, func, &opts);
	*link = bpf_program__attach_kprobe_opts(prog, func, &opts);
	free(func);
	return link;
	return libbpf_get_error(*link);
}

static void gen_uprobe_legacy_event_name(char *buf, size_t buf_sz,
@@ -10395,14 +10493,13 @@ struct bpf_link *bpf_program__attach_tracepoint(const struct bpf_program *prog,
	return bpf_program__attach_tracepoint_opts(prog, tp_category, tp_name, NULL);
}

static struct bpf_link *attach_tp(const struct bpf_program *prog, long cookie)
static int attach_tp(const struct bpf_program *prog, long cookie, struct bpf_link **link)
{
	char *sec_name, *tp_cat, *tp_name;
	struct bpf_link *link;

	sec_name = strdup(prog->sec_name);
	if (!sec_name)
		return libbpf_err_ptr(-ENOMEM);
		return -ENOMEM;

	/* extract "tp/<category>/<name>" or "tracepoint/<category>/<name>" */
	if (str_has_pfx(prog->sec_name, "tp/"))
@@ -10412,14 +10509,14 @@ static struct bpf_link *attach_tp(const struct bpf_program *prog, long cookie)
	tp_name = strchr(tp_cat, '/');
	if (!tp_name) {
		free(sec_name);
		return libbpf_err_ptr(-EINVAL);
		return -EINVAL;
	}
	*tp_name = '\0';
	tp_name++;

	link = bpf_program__attach_tracepoint(prog, tp_cat, tp_name);
	*link = bpf_program__attach_tracepoint(prog, tp_cat, tp_name);
	free(sec_name);
	return link;
	return libbpf_get_error(*link);
}

struct bpf_link *bpf_program__attach_raw_tracepoint(const struct bpf_program *prog,
@@ -10452,7 +10549,7 @@ struct bpf_link *bpf_program__attach_raw_tracepoint(const struct bpf_program *pr
	return link;
}

static struct bpf_link *attach_raw_tp(const struct bpf_program *prog, long cookie)
static int attach_raw_tp(const struct bpf_program *prog, long cookie, struct bpf_link **link)
{
	static const char *const prefixes[] = {
		"raw_tp/",
@@ -10472,10 +10569,11 @@ static struct bpf_link *attach_raw_tp(const struct bpf_program *prog, long cooki
	if (!tp_name) {
		pr_warn("prog '%s': invalid section name '%s'\n",
			prog->name, prog->sec_name);
		return libbpf_err_ptr(-EINVAL);
		return -EINVAL;
	}

	return bpf_program__attach_raw_tracepoint(prog, tp_name);
	*link = bpf_program__attach_raw_tracepoint(prog, tp_name);
	return libbpf_get_error(link);
}

/* Common logic for all BPF program types that attach to a btf_id */
@@ -10518,14 +10616,16 @@ struct bpf_link *bpf_program__attach_lsm(const struct bpf_program *prog)
	return bpf_program__attach_btf_id(prog);
}

static struct bpf_link *attach_trace(const struct bpf_program *prog, long cookie)
static int attach_trace(const struct bpf_program *prog, long cookie, struct bpf_link **link)
{
	return bpf_program__attach_trace(prog);
	*link = bpf_program__attach_trace(prog);
	return libbpf_get_error(*link);
}

static struct bpf_link *attach_lsm(const struct bpf_program *prog, long cookie)
static int attach_lsm(const struct bpf_program *prog, long cookie, struct bpf_link **link)
{
	return bpf_program__attach_lsm(prog);
	*link = bpf_program__attach_lsm(prog);
	return libbpf_get_error(*link);
}

static struct bpf_link *
@@ -10654,17 +10754,33 @@ bpf_program__attach_iter(const struct bpf_program *prog,
	return link;
}

static struct bpf_link *attach_iter(const struct bpf_program *prog, long cookie)
static int attach_iter(const struct bpf_program *prog, long cookie, struct bpf_link **link)
{
	return bpf_program__attach_iter(prog, NULL);
	*link = bpf_program__attach_iter(prog, NULL);
	return libbpf_get_error(*link);
}

struct bpf_link *bpf_program__attach(const struct bpf_program *prog)
{
	if (!prog->sec_def || !prog->sec_def->attach_fn)
		return libbpf_err_ptr(-ESRCH);
	struct bpf_link *link = NULL;
	int err;

	if (!prog->sec_def || !prog->sec_def->prog_attach_fn)
		return libbpf_err_ptr(-EOPNOTSUPP);

	return prog->sec_def->attach_fn(prog, prog->sec_def->cookie);
	err = prog->sec_def->prog_attach_fn(prog, prog->sec_def->cookie, &link);
	if (err)
		return libbpf_err_ptr(err);

	/* When calling bpf_program__attach() explicitly, auto-attach support
	 * is expected to work, so NULL returned link is considered an error.
	 * This is different for skeleton's attach, see comment in
	 * bpf_object__attach_skeleton().
	 */
	if (!link)
		return libbpf_err_ptr(-EOPNOTSUPP);

	return link;
}

static int bpf_link__detach_struct_ops(struct bpf_link *link)
@@ -11805,16 +11921,30 @@ int bpf_object__attach_skeleton(struct bpf_object_skeleton *s)
			continue;

		/* auto-attaching not supported for this program */
		if (!prog->sec_def || !prog->sec_def->attach_fn)
		if (!prog->sec_def || !prog->sec_def->prog_attach_fn)
			continue;

		/* if user already set the link manually, don't attempt auto-attach */
		if (*link)
			continue;

		*link = bpf_program__attach(prog);
		err = libbpf_get_error(*link);
		err = prog->sec_def->prog_attach_fn(prog, prog->sec_def->cookie, link);
		if (err) {
			pr_warn("failed to auto-attach program '%s': %d\n",
			pr_warn("prog '%s': failed to auto-attach: %d\n",
				bpf_program__name(prog), err);
			return libbpf_err(err);
		}

		/* It's possible that for some SEC() definitions auto-attach
		 * is supported in some cases (e.g., if definition completely
		 * specifies target information), but is not in other cases.
		 * SEC("uprobe") is one such case. If user specified target
		 * binary and function name, such BPF program can be
		 * auto-attached. But if not, it shouldn't trigger skeleton's
		 * attach to fail. It should just be skipped.
		 * attach_fn signals such case with returning 0 (no error) and
		 * setting link to NULL.
		 */
	}

	return 0;
+109 −0
Original line number Diff line number Diff line
@@ -1328,6 +1328,115 @@ LIBBPF_API int bpf_linker__add_file(struct bpf_linker *linker,
LIBBPF_API int bpf_linker__finalize(struct bpf_linker *linker);
LIBBPF_API void bpf_linker__free(struct bpf_linker *linker);

/*
 * Custom handling of BPF program's SEC() definitions
 */

struct bpf_prog_load_opts; /* defined in bpf.h */

/* Called during bpf_object__open() for each recognized BPF program. Callback
 * can use various bpf_program__set_*() setters to adjust whatever properties
 * are necessary.
 */
typedef int (*libbpf_prog_setup_fn_t)(struct bpf_program *prog, long cookie);

/* Called right before libbpf performs bpf_prog_load() to load BPF program
 * into the kernel. Callback can adjust opts as necessary.
 */
typedef int (*libbpf_prog_prepare_load_fn_t)(struct bpf_program *prog,
					     struct bpf_prog_load_opts *opts, long cookie);

/* Called during skeleton attach or through bpf_program__attach(). If
 * auto-attach is not supported, callback should return 0 and set link to
 * NULL (it's not considered an error during skeleton attach, but it will be
 * an error for bpf_program__attach() calls). On error, error should be
 * returned directly and link set to NULL. On success, return 0 and set link
 * to a valid struct bpf_link.
 */
typedef int (*libbpf_prog_attach_fn_t)(const struct bpf_program *prog, long cookie,
				       struct bpf_link **link);

struct libbpf_prog_handler_opts {
	/* size of this struct, for forward/backward compatiblity */
	size_t sz;
	/* User-provided value that is passed to prog_setup_fn,
	 * prog_prepare_load_fn, and prog_attach_fn callbacks. Allows user to
	 * register one set of callbacks for multiple SEC() definitions and
	 * still be able to distinguish them, if necessary. For example,
	 * libbpf itself is using this to pass necessary flags (e.g.,
	 * sleepable flag) to a common internal SEC() handler.
	 */
	long cookie;
	/* BPF program initialization callback (see libbpf_prog_setup_fn_t).
	 * Callback is optional, pass NULL if it's not necessary.
	 */
	libbpf_prog_setup_fn_t prog_setup_fn;
	/* BPF program loading callback (see libbpf_prog_prepare_load_fn_t).
	 * Callback is optional, pass NULL if it's not necessary.
	 */
	libbpf_prog_prepare_load_fn_t prog_prepare_load_fn;
	/* BPF program attach callback (see libbpf_prog_attach_fn_t).
	 * Callback is optional, pass NULL if it's not necessary.
	 */
	libbpf_prog_attach_fn_t prog_attach_fn;
};
#define libbpf_prog_handler_opts__last_field prog_attach_fn

/**
 * @brief **libbpf_register_prog_handler()** registers a custom BPF program
 * SEC() handler.
 * @param sec section prefix for which custom handler is registered
 * @param prog_type BPF program type associated with specified section
 * @param exp_attach_type Expected BPF attach type associated with specified section
 * @param opts optional cookie, callbacks, and other extra options
 * @return Non-negative handler ID is returned on success. This handler ID has
 * to be passed to *libbpf_unregister_prog_handler()* to unregister such
 * custom handler. Negative error code is returned on error.
 *
 * *sec* defines which SEC() definitions are handled by this custom handler
 * registration. *sec* can have few different forms:
 *   - if *sec* is just a plain string (e.g., "abc"), it will match only
 *   SEC("abc"). If BPF program specifies SEC("abc/whatever") it will result
 *   in an error;
 *   - if *sec* is of the form "abc/", proper SEC() form is
 *   SEC("abc/something"), where acceptable "something" should be checked by
 *   *prog_init_fn* callback, if there are additional restrictions;
 *   - if *sec* is of the form "abc+", it will successfully match both
 *   SEC("abc") and SEC("abc/whatever") forms;
 *   - if *sec* is NULL, custom handler is registered for any BPF program that
 *   doesn't match any of the registered (custom or libbpf's own) SEC()
 *   handlers. There could be only one such generic custom handler registered
 *   at any given time.
 *
 * All custom handlers (except the one with *sec* == NULL) are processed
 * before libbpf's own SEC() handlers. It is allowed to "override" libbpf's
 * SEC() handlers by registering custom ones for the same section prefix
 * (i.e., it's possible to have custom SEC("perf_event/LLC-load-misses")
 * handler).
 *
 * Note, like much of global libbpf APIs (e.g., libbpf_set_print(),
 * libbpf_set_strict_mode(), etc)) these APIs are not thread-safe. User needs
 * to ensure synchronization if there is a risk of running this API from
 * multiple threads simultaneously.
 */
LIBBPF_API int libbpf_register_prog_handler(const char *sec,
					    enum bpf_prog_type prog_type,
					    enum bpf_attach_type exp_attach_type,
					    const struct libbpf_prog_handler_opts *opts);
/**
 * @brief *libbpf_unregister_prog_handler()* unregisters previously registered
 * custom BPF program SEC() handler.
 * @param handler_id handler ID returned by *libbpf_register_prog_handler()*
 * after successful registration
 * @return 0 on success, negative error code if handler isn't found
 *
 * Note, like much of global libbpf APIs (e.g., libbpf_set_print(),
 * libbpf_set_strict_mode(), etc)) these APIs are not thread-safe. User needs
 * to ensure synchronization if there is a risk of running this API from
 * multiple threads simultaneously.
 */
LIBBPF_API int libbpf_unregister_prog_handler(int handler_id);

#ifdef __cplusplus
} /* extern "C" */
#endif
+6 −0
Original line number Diff line number Diff line
@@ -439,3 +439,9 @@ LIBBPF_0.7.0 {
		libbpf_probe_bpf_prog_type;
		libbpf_set_memlock_rlim_max;
} LIBBPF_0.6.0;

LIBBPF_0.8.0 {
	global:
		libbpf_register_prog_handler;
		libbpf_unregister_prog_handler;
} LIBBPF_0.7.0;
+1 −1
Original line number Diff line number Diff line
@@ -4,6 +4,6 @@
#define __LIBBPF_VERSION_H

#define LIBBPF_MAJOR_VERSION 0
#define LIBBPF_MINOR_VERSION 7
#define LIBBPF_MINOR_VERSION 8

#endif /* __LIBBPF_VERSION_H */
+176 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading