Commit f7abbecd authored by Andrii Nakryiko's avatar Andrii Nakryiko
Browse files

Merge branch 'libbpf: Textual representation of enums'



Daniel Müller says:

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

This patch set introduces the means for querying a textual representation of
the following BPF related enum types:
- enum bpf_map_type
- enum bpf_prog_type
- enum bpf_attach_type
- enum bpf_link_type

To make that possible, we introduce a new public function for each of the types:
libbpf_bpf_<type>_type_str.

Having a way to query a textual representation has been asked for in the past
(by systemd, among others). Such representations can generally be useful in
tracing and logging contexts, among others. At this point, at least one client,
bpftool, maintains such a mapping manually, which is prone to get out of date as
new enum variants are introduced. libbpf is arguably best situated to keep this
list complete and up-to-date. This patch series adds BTF based tests to ensure
that exhaustiveness is upheld moving forward.

The libbpf provided textual representation can be inferred from the
corresponding enum variant name by removing the prefix and lowercasing the
remainder. E.g., BPF_PROG_TYPE_SOCKET_FILTER -> socket_filter. Unfortunately,
bpftool does not use such a programmatic approach for some of the
bpf_attach_type variants. We decided in favor of changing its behavior to work
with libbpf representations. However, for user inputs, specifically, we do
maintain support for the traditionally used names around (please see patch
"bpftool: Use libbpf_bpf_attach_type_str").

The patch series is structured as follows:
- for each enumeration type in {bpf_prog_type, bpf_map_type, bpf_attach_type,
  bpf_link_type}:
  - we first introduce the corresponding public libbpf API function
  - we then add BTF based self-tests
  - we lastly adjust bpftool to use the libbpf provided functionality

Signed-off-by: default avatarDaniel Müller <deso@posteo.net>
Cc: Quentin Monnet <quentin@isovalent.com>
---
Changelog:
v3 -> v4:
- use full string comparison for newly added attach types
- switched away from erroneously used kdoc-style comments
- removed unused prog_types variable and containing section from
  test_bpftool_synctypes.py
- adjusted wording in documentation of get_types_from_array function
- split various test_bpftool_synctypes.py changes into commits where they are
  required to eliminate temporary failures of this test

v2 -> v3:
- use LIBBPF_1.0.0 section in libbpf.map for newly added exports

v1 -> v2:
- adjusted bpftool to work with algorithmically determined attach types as
  libbpf now uses (just removed prefix from enum name and lowercased the rest)
  - adjusted tests, man page, and completion script to work with the new names
  - renamed bpf_attach_type_str -> bpf_attach_type_input_str
  - for input: added special cases that accept the traditionally used strings as
    well
- changed 'char const *' -> 'const char *'
====================

Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
parents cc168554 c7e7e279
Loading
Loading
Loading
Loading
+11 −5
Original line number Diff line number Diff line
@@ -31,11 +31,17 @@ CGROUP COMMANDS
|	**bpftool** **cgroup help**
|
|	*PROG* := { **id** *PROG_ID* | **pinned** *FILE* | **tag** *PROG_TAG* }
|	*ATTACH_TYPE* := { **ingress** | **egress** | **sock_create** | **sock_ops** | **device** |
|		**bind4** | **bind6** | **post_bind4** | **post_bind6** | **connect4** | **connect6** |
|		**getpeername4** | **getpeername6** | **getsockname4** | **getsockname6** | **sendmsg4** |
|		**sendmsg6** | **recvmsg4** | **recvmsg6** | **sysctl** | **getsockopt** | **setsockopt** |
|		**sock_release** }
|	*ATTACH_TYPE* := { **cgroup_inet_ingress** | **cgroup_inet_egress** |
|		**cgroup_inet_sock_create** | **cgroup_sock_ops** |
|		**cgroup_device** | **cgroup_inet4_bind** | **cgroup_inet6_bind** |
|		**cgroup_inet4_post_bind** | **cgroup_inet6_post_bind** |
|		**cgroup_inet4_connect** | **cgroup_inet6_connect** |
|		**cgroup_inet4_getpeername** | **cgroup_inet6_getpeername** |
|		**cgroup_inet4_getsockname** | **cgroup_inet6_getsockname** |
|		**cgroup_udp4_sendmsg** | **cgroup_udp6_sendmsg** |
|		**cgroup_udp4_recvmsg** | **cgroup_udp6_recvmsg** |
|		**cgroup_sysctl** | **cgroup_getsockopt** | **cgroup_setsockopt** |
|		**cgroup_inet_sock_release** }
|	*ATTACH_FLAGS* := { **multi** | **override** }

DESCRIPTION
+3 −2
Original line number Diff line number Diff line
@@ -54,7 +54,8 @@ PROG COMMANDS
|		**struct_ops** | **fentry** | **fexit** | **freplace** | **sk_lookup**
|	}
|	*ATTACH_TYPE* := {
|		**msg_verdict** | **skb_verdict** | **stream_verdict** | **stream_parser** | **flow_dissector**
|		**sk_msg_verdict** | **sk_skb_verdict** | **sk_skb_stream_verdict** |
|		**sk_skb_stream_parser** | **flow_dissector**
|	}
|	*METRICs* := {
|		**cycles** | **instructions** | **l1d_loads** | **llc_misses** |
+10 −8
Original line number Diff line number Diff line
@@ -407,8 +407,8 @@ _bpftool()
                            return 0
                            ;;
                        5)
                            local BPFTOOL_PROG_ATTACH_TYPES='msg_verdict \
                                skb_verdict stream_verdict stream_parser \
                            local BPFTOOL_PROG_ATTACH_TYPES='sk_msg_verdict \
                                sk_skb_verdict sk_skb_stream_verdict sk_skb_stream_parser \
                                flow_dissector'
                            COMPREPLY=( $( compgen -W "$BPFTOOL_PROG_ATTACH_TYPES" -- "$cur" ) )
                            return 0
@@ -1039,12 +1039,14 @@ _bpftool()
                    return 0
                    ;;
                attach|detach)
                    local BPFTOOL_CGROUP_ATTACH_TYPES='ingress egress \
                        sock_create sock_ops device \
                        bind4 bind6 post_bind4 post_bind6 connect4 connect6 \
                        getpeername4 getpeername6 getsockname4 getsockname6 \
                        sendmsg4 sendmsg6 recvmsg4 recvmsg6 sysctl getsockopt \
                        setsockopt sock_release'
                    local BPFTOOL_CGROUP_ATTACH_TYPES='cgroup_inet_ingress cgroup_inet_egress \
                        cgroup_inet_sock_create cgroup_sock_ops cgroup_device cgroup_inet4_bind \
                        cgroup_inet6_bind cgroup_inet4_post_bind cgroup_inet6_post_bind \
                        cgroup_inet4_connect cgroup_inet6_connect cgroup_inet4_getpeername \
                        cgroup_inet6_getpeername cgroup_inet4_getsockname cgroup_inet6_getsockname \
                        cgroup_udp4_sendmsg cgroup_udp6_sendmsg cgroup_udp4_recvmsg \
                        cgroup_udp6_recvmsg cgroup_sysctl cgroup_getsockopt cgroup_setsockopt \
                        cgroup_inet_sock_release'
                    local ATTACH_FLAGS='multi override'
                    local PROG_TYPE='id pinned tag name'
                    # Check for $prev = $command first
+36 −17
Original line number Diff line number Diff line
@@ -22,24 +22,42 @@
	"ATTACH_FLAGS := { multi | override }"

#define HELP_SPEC_ATTACH_TYPES						\
	"       ATTACH_TYPE := { ingress | egress | sock_create |\n"	       \
	"                        sock_ops | device | bind4 | bind6 |\n"	       \
	"                        post_bind4 | post_bind6 | connect4 |\n"       \
	"                        connect6 | getpeername4 | getpeername6 |\n"   \
	"                        getsockname4 | getsockname6 | sendmsg4 |\n"   \
	"                        sendmsg6 | recvmsg4 | recvmsg6 |\n"           \
	"                        sysctl | getsockopt | setsockopt |\n"	       \
	"                        sock_release }"
	"       ATTACH_TYPE := { cgroup_inet_ingress | cgroup_inet_egress |\n" \
	"                        cgroup_inet_sock_create | cgroup_sock_ops |\n" \
	"                        cgroup_device | cgroup_inet4_bind |\n" \
	"                        cgroup_inet6_bind | cgroup_inet4_post_bind |\n" \
	"                        cgroup_inet6_post_bind | cgroup_inet4_connect |\n" \
	"                        cgroup_inet6_connect | cgroup_inet4_getpeername |\n" \
	"                        cgroup_inet6_getpeername | cgroup_inet4_getsockname |\n" \
	"                        cgroup_inet6_getsockname | cgroup_udp4_sendmsg |\n" \
	"                        cgroup_udp6_sendmsg | cgroup_udp4_recvmsg |\n" \
	"                        cgroup_udp6_recvmsg | cgroup_sysctl |\n" \
	"                        cgroup_getsockopt | cgroup_setsockopt |\n" \
	"                        cgroup_inet_sock_release }"

static unsigned int query_flags;

static enum bpf_attach_type parse_attach_type(const char *str)
{
	const char *attach_type_str;
	enum bpf_attach_type type;

	for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) {
		if (attach_type_name[type] &&
		    is_prefix(str, attach_type_name[type]))
	for (type = 0; ; type++) {
		attach_type_str = libbpf_bpf_attach_type_str(type);
		if (!attach_type_str)
			break;
		if (!strcmp(str, attach_type_str))
			return type;
	}

	/* Also check traditionally used attach type strings. For these we keep
	 * allowing prefixed usage.
	 */
	for (type = 0; ; type++) {
		attach_type_str = bpf_attach_type_input_str(type);
		if (!attach_type_str)
			break;
		if (is_prefix(str, attach_type_str))
			return type;
	}

@@ -52,6 +70,7 @@ static int show_bpf_prog(int id, enum bpf_attach_type attach_type,
{
	char prog_name[MAX_PROG_FULL_NAME];
	struct bpf_prog_info info = {};
	const char *attach_type_str;
	__u32 info_len = sizeof(info);
	int prog_fd;

@@ -64,13 +83,13 @@ static int show_bpf_prog(int id, enum bpf_attach_type attach_type,
		return -1;
	}

	attach_type_str = libbpf_bpf_attach_type_str(attach_type);
	get_prog_full_name(&info, prog_fd, prog_name, sizeof(prog_name));
	if (json_output) {
		jsonw_start_object(json_wtr);
		jsonw_uint_field(json_wtr, "id", info.id);
		if (attach_type < ARRAY_SIZE(attach_type_name))
			jsonw_string_field(json_wtr, "attach_type",
					   attach_type_name[attach_type]);
		if (attach_type_str)
			jsonw_string_field(json_wtr, "attach_type", attach_type_str);
		else
			jsonw_uint_field(json_wtr, "attach_type", attach_type);
		jsonw_string_field(json_wtr, "attach_flags",
@@ -79,8 +98,8 @@ static int show_bpf_prog(int id, enum bpf_attach_type attach_type,
		jsonw_end_object(json_wtr);
	} else {
		printf("%s%-8u ", level ? "    " : "", info.id);
		if (attach_type < ARRAY_SIZE(attach_type_name))
			printf("%-15s", attach_type_name[attach_type]);
		if (attach_type_str)
			printf("%-15s", attach_type_str);
		else
			printf("type %-10u", attach_type);
		printf(" %-15s %-15s\n", attach_flags_str, prog_name);
+36 −46
Original line number Diff line number Diff line
@@ -31,52 +31,6 @@
#define BPF_FS_MAGIC		0xcafe4a11
#endif

const char * const attach_type_name[__MAX_BPF_ATTACH_TYPE] = {
	[BPF_CGROUP_INET_INGRESS]	= "ingress",
	[BPF_CGROUP_INET_EGRESS]	= "egress",
	[BPF_CGROUP_INET_SOCK_CREATE]	= "sock_create",
	[BPF_CGROUP_INET_SOCK_RELEASE]	= "sock_release",
	[BPF_CGROUP_SOCK_OPS]		= "sock_ops",
	[BPF_CGROUP_DEVICE]		= "device",
	[BPF_CGROUP_INET4_BIND]		= "bind4",
	[BPF_CGROUP_INET6_BIND]		= "bind6",
	[BPF_CGROUP_INET4_CONNECT]	= "connect4",
	[BPF_CGROUP_INET6_CONNECT]	= "connect6",
	[BPF_CGROUP_INET4_POST_BIND]	= "post_bind4",
	[BPF_CGROUP_INET6_POST_BIND]	= "post_bind6",
	[BPF_CGROUP_INET4_GETPEERNAME]	= "getpeername4",
	[BPF_CGROUP_INET6_GETPEERNAME]	= "getpeername6",
	[BPF_CGROUP_INET4_GETSOCKNAME]	= "getsockname4",
	[BPF_CGROUP_INET6_GETSOCKNAME]	= "getsockname6",
	[BPF_CGROUP_UDP4_SENDMSG]	= "sendmsg4",
	[BPF_CGROUP_UDP6_SENDMSG]	= "sendmsg6",
	[BPF_CGROUP_SYSCTL]		= "sysctl",
	[BPF_CGROUP_UDP4_RECVMSG]	= "recvmsg4",
	[BPF_CGROUP_UDP6_RECVMSG]	= "recvmsg6",
	[BPF_CGROUP_GETSOCKOPT]		= "getsockopt",
	[BPF_CGROUP_SETSOCKOPT]		= "setsockopt",
	[BPF_SK_SKB_STREAM_PARSER]	= "sk_skb_stream_parser",
	[BPF_SK_SKB_STREAM_VERDICT]	= "sk_skb_stream_verdict",
	[BPF_SK_SKB_VERDICT]		= "sk_skb_verdict",
	[BPF_SK_MSG_VERDICT]		= "sk_msg_verdict",
	[BPF_LIRC_MODE2]		= "lirc_mode2",
	[BPF_FLOW_DISSECTOR]		= "flow_dissector",
	[BPF_TRACE_RAW_TP]		= "raw_tp",
	[BPF_TRACE_FENTRY]		= "fentry",
	[BPF_TRACE_FEXIT]		= "fexit",
	[BPF_MODIFY_RETURN]		= "mod_ret",
	[BPF_LSM_MAC]			= "lsm_mac",
	[BPF_SK_LOOKUP]			= "sk_lookup",
	[BPF_TRACE_ITER]		= "trace_iter",
	[BPF_XDP_DEVMAP]		= "xdp_devmap",
	[BPF_XDP_CPUMAP]		= "xdp_cpumap",
	[BPF_XDP]			= "xdp",
	[BPF_SK_REUSEPORT_SELECT]	= "sk_skb_reuseport_select",
	[BPF_SK_REUSEPORT_SELECT_OR_MIGRATE]	= "sk_skb_reuseport_select_or_migrate",
	[BPF_PERF_EVENT]		= "perf_event",
	[BPF_TRACE_KPROBE_MULTI]	= "trace_kprobe_multi",
};

void p_err(const char *fmt, ...)
{
	va_list ap;
@@ -1009,3 +963,39 @@ bool equal_fn_for_key_as_id(const void *k1, const void *k2, void *ctx)
{
	return k1 == k2;
}

const char *bpf_attach_type_input_str(enum bpf_attach_type t)
{
	switch (t) {
	case BPF_CGROUP_INET_INGRESS:		return "ingress";
	case BPF_CGROUP_INET_EGRESS:		return "egress";
	case BPF_CGROUP_INET_SOCK_CREATE:	return "sock_create";
	case BPF_CGROUP_INET_SOCK_RELEASE:	return "sock_release";
	case BPF_CGROUP_SOCK_OPS:		return "sock_ops";
	case BPF_CGROUP_DEVICE:			return "device";
	case BPF_CGROUP_INET4_BIND:		return "bind4";
	case BPF_CGROUP_INET6_BIND:		return "bind6";
	case BPF_CGROUP_INET4_CONNECT:		return "connect4";
	case BPF_CGROUP_INET6_CONNECT:		return "connect6";
	case BPF_CGROUP_INET4_POST_BIND:	return "post_bind4";
	case BPF_CGROUP_INET6_POST_BIND:	return "post_bind6";
	case BPF_CGROUP_INET4_GETPEERNAME:	return "getpeername4";
	case BPF_CGROUP_INET6_GETPEERNAME:	return "getpeername6";
	case BPF_CGROUP_INET4_GETSOCKNAME:	return "getsockname4";
	case BPF_CGROUP_INET6_GETSOCKNAME:	return "getsockname6";
	case BPF_CGROUP_UDP4_SENDMSG:		return "sendmsg4";
	case BPF_CGROUP_UDP6_SENDMSG:		return "sendmsg6";
	case BPF_CGROUP_SYSCTL:			return "sysctl";
	case BPF_CGROUP_UDP4_RECVMSG:		return "recvmsg4";
	case BPF_CGROUP_UDP6_RECVMSG:		return "recvmsg6";
	case BPF_CGROUP_GETSOCKOPT:		return "getsockopt";
	case BPF_CGROUP_SETSOCKOPT:		return "setsockopt";
	case BPF_TRACE_RAW_TP:			return "raw_tp";
	case BPF_TRACE_FENTRY:			return "fentry";
	case BPF_TRACE_FEXIT:			return "fexit";
	case BPF_MODIFY_RETURN:			return "mod_ret";
	case BPF_SK_REUSEPORT_SELECT:		return "sk_skb_reuseport_select";
	case BPF_SK_REUSEPORT_SELECT_OR_MIGRATE:	return "sk_skb_reuseport_select_or_migrate";
	default:	return libbpf_bpf_attach_type_str(t);
	}
}
Loading