diff options
Diffstat (limited to 'tools/lib/bpf')
| -rw-r--r-- | tools/lib/bpf/Build | 2 | ||||
| -rw-r--r-- | tools/lib/bpf/Makefile | 5 | ||||
| -rw-r--r-- | tools/lib/bpf/bpf.c | 143 | ||||
| -rw-r--r-- | tools/lib/bpf/bpf.h | 131 | ||||
| -rw-r--r-- | tools/lib/bpf/btf.c | 2 | ||||
| -rw-r--r-- | tools/lib/bpf/btf.h | 30 | ||||
| -rw-r--r-- | tools/lib/bpf/libbpf.c | 284 | ||||
| -rw-r--r-- | tools/lib/bpf/libbpf.h | 222 | ||||
| -rw-r--r-- | tools/lib/bpf/libbpf_errno.c | 16 | ||||
| -rw-r--r-- | tools/lib/bpf/netlink.c | 337 | ||||
| -rw-r--r-- | tools/lib/bpf/nlattr.c | 90 | ||||
| -rw-r--r-- | tools/lib/bpf/nlattr.h | 82 | ||||
| -rw-r--r-- | tools/lib/bpf/str_error.c | 18 | ||||
| -rw-r--r-- | tools/lib/bpf/str_error.h | 6 | 
14 files changed, 863 insertions, 505 deletions
diff --git a/tools/lib/bpf/Build b/tools/lib/bpf/Build index 13a861135127..7bc31c905018 100644 --- a/tools/lib/bpf/Build +++ b/tools/lib/bpf/Build @@ -1 +1 @@ -libbpf-y := libbpf.o bpf.o nlattr.o btf.o libbpf_errno.o +libbpf-y := libbpf.o bpf.o nlattr.o btf.o libbpf_errno.o str_error.o netlink.o diff --git a/tools/lib/bpf/Makefile b/tools/lib/bpf/Makefile index d49902e818b5..425b480bda75 100644 --- a/tools/lib/bpf/Makefile +++ b/tools/lib/bpf/Makefile @@ -1,4 +1,4 @@ -# SPDX-License-Identifier: GPL-2.0 +# SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)  # Most of this file is copied from tools/lib/traceevent/Makefile  BPF_VERSION = 0 @@ -69,7 +69,7 @@ FEATURE_USER = .libbpf  FEATURE_TESTS = libelf libelf-mmap bpf reallocarray  FEATURE_DISPLAY = libelf bpf -INCLUDES = -I. -I$(srctree)/tools/include -I$(srctree)/tools/arch/$(ARCH)/include/uapi -I$(srctree)/tools/include/uapi -I$(srctree)/tools/perf +INCLUDES = -I. -I$(srctree)/tools/include -I$(srctree)/tools/arch/$(ARCH)/include/uapi -I$(srctree)/tools/include/uapi  FEATURE_CHECK_CFLAGS-bpf = $(INCLUDES)  check_feat := 1 @@ -125,6 +125,7 @@ override CFLAGS += $(EXTRA_WARNINGS)  override CFLAGS += -Werror -Wall  override CFLAGS += -fPIC  override CFLAGS += $(INCLUDES) +override CFLAGS += -fvisibility=hidden  ifeq ($(VERBOSE),1)    Q = diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c index 60aa4ca8b2c5..03f9bcc4ef50 100644 --- a/tools/lib/bpf/bpf.c +++ b/tools/lib/bpf/bpf.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1 +// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)  /*   * common eBPF ELF operations. @@ -28,16 +28,8 @@  #include <linux/bpf.h>  #include "bpf.h"  #include "libbpf.h" -#include "nlattr.h" -#include <linux/rtnetlink.h> -#include <linux/if_link.h> -#include <sys/socket.h>  #include <errno.h> -#ifndef SOL_NETLINK -#define SOL_NETLINK 270 -#endif -  /*   * When building perf, unistd.h is overridden. __NR_bpf is   * required to be defined explicitly. @@ -286,6 +278,18 @@ int bpf_map_lookup_elem(int fd, const void *key, void *value)  	return sys_bpf(BPF_MAP_LOOKUP_ELEM, &attr, sizeof(attr));  } +int bpf_map_lookup_and_delete_elem(int fd, const void *key, void *value) +{ +	union bpf_attr attr; + +	bzero(&attr, sizeof(attr)); +	attr.map_fd = fd; +	attr.key = ptr_to_u64(key); +	attr.value = ptr_to_u64(value); + +	return sys_bpf(BPF_MAP_LOOKUP_AND_DELETE_ELEM, &attr, sizeof(attr)); +} +  int bpf_map_delete_elem(int fd, const void *key)  {  	union bpf_attr attr; @@ -499,127 +503,6 @@ int bpf_raw_tracepoint_open(const char *name, int prog_fd)  	return sys_bpf(BPF_RAW_TRACEPOINT_OPEN, &attr, sizeof(attr));  } -int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags) -{ -	struct sockaddr_nl sa; -	int sock, seq = 0, len, ret = -1; -	char buf[4096]; -	struct nlattr *nla, *nla_xdp; -	struct { -		struct nlmsghdr  nh; -		struct ifinfomsg ifinfo; -		char             attrbuf[64]; -	} req; -	struct nlmsghdr *nh; -	struct nlmsgerr *err; -	socklen_t addrlen; -	int one = 1; - -	memset(&sa, 0, sizeof(sa)); -	sa.nl_family = AF_NETLINK; - -	sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); -	if (sock < 0) { -		return -errno; -	} - -	if (setsockopt(sock, SOL_NETLINK, NETLINK_EXT_ACK, -		       &one, sizeof(one)) < 0) { -		fprintf(stderr, "Netlink error reporting not supported\n"); -	} - -	if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) { -		ret = -errno; -		goto cleanup; -	} - -	addrlen = sizeof(sa); -	if (getsockname(sock, (struct sockaddr *)&sa, &addrlen) < 0) { -		ret = -errno; -		goto cleanup; -	} - -	if (addrlen != sizeof(sa)) { -		ret = -LIBBPF_ERRNO__INTERNAL; -		goto cleanup; -	} - -	memset(&req, 0, sizeof(req)); -	req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); -	req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; -	req.nh.nlmsg_type = RTM_SETLINK; -	req.nh.nlmsg_pid = 0; -	req.nh.nlmsg_seq = ++seq; -	req.ifinfo.ifi_family = AF_UNSPEC; -	req.ifinfo.ifi_index = ifindex; - -	/* started nested attribute for XDP */ -	nla = (struct nlattr *)(((char *)&req) -				+ NLMSG_ALIGN(req.nh.nlmsg_len)); -	nla->nla_type = NLA_F_NESTED | IFLA_XDP; -	nla->nla_len = NLA_HDRLEN; - -	/* add XDP fd */ -	nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len); -	nla_xdp->nla_type = IFLA_XDP_FD; -	nla_xdp->nla_len = NLA_HDRLEN + sizeof(int); -	memcpy((char *)nla_xdp + NLA_HDRLEN, &fd, sizeof(fd)); -	nla->nla_len += nla_xdp->nla_len; - -	/* if user passed in any flags, add those too */ -	if (flags) { -		nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len); -		nla_xdp->nla_type = IFLA_XDP_FLAGS; -		nla_xdp->nla_len = NLA_HDRLEN + sizeof(flags); -		memcpy((char *)nla_xdp + NLA_HDRLEN, &flags, sizeof(flags)); -		nla->nla_len += nla_xdp->nla_len; -	} - -	req.nh.nlmsg_len += NLA_ALIGN(nla->nla_len); - -	if (send(sock, &req, req.nh.nlmsg_len, 0) < 0) { -		ret = -errno; -		goto cleanup; -	} - -	len = recv(sock, buf, sizeof(buf), 0); -	if (len < 0) { -		ret = -errno; -		goto cleanup; -	} - -	for (nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, len); -	     nh = NLMSG_NEXT(nh, len)) { -		if (nh->nlmsg_pid != sa.nl_pid) { -			ret = -LIBBPF_ERRNO__WRNGPID; -			goto cleanup; -		} -		if (nh->nlmsg_seq != seq) { -			ret = -LIBBPF_ERRNO__INVSEQ; -			goto cleanup; -		} -		switch (nh->nlmsg_type) { -		case NLMSG_ERROR: -			err = (struct nlmsgerr *)NLMSG_DATA(nh); -			if (!err->error) -				continue; -			ret = err->error; -			nla_dump_errormsg(nh); -			goto cleanup; -		case NLMSG_DONE: -			break; -		default: -			break; -		} -	} - -	ret = 0; - -cleanup: -	close(sock); -	return ret; -} -  int bpf_load_btf(void *btf, __u32 btf_size, char *log_buf, __u32 log_buf_size,  		 bool do_log)  { diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h index 6f38164b2618..26a51538213c 100644 --- a/tools/lib/bpf/bpf.h +++ b/tools/lib/bpf/bpf.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1 */ +/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */  /*   * common eBPF ELF operations. @@ -20,13 +20,17 @@   * You should have received a copy of the GNU Lesser General Public   * License along with this program; if not,  see <http://www.gnu.org/licenses>   */ -#ifndef __BPF_BPF_H -#define __BPF_BPF_H +#ifndef __LIBBPF_BPF_H +#define __LIBBPF_BPF_H  #include <linux/bpf.h>  #include <stdbool.h>  #include <stddef.h> +#ifndef LIBBPF_API +#define LIBBPF_API __attribute__((visibility("default"))) +#endif +  struct bpf_create_map_attr {  	const char *name;  	enum bpf_map_type map_type; @@ -42,21 +46,24 @@ struct bpf_create_map_attr {  	__u32 inner_map_fd;  }; -int bpf_create_map_xattr(const struct bpf_create_map_attr *create_attr); -int bpf_create_map_node(enum bpf_map_type map_type, const char *name, -			int key_size, int value_size, int max_entries, -			__u32 map_flags, int node); -int bpf_create_map_name(enum bpf_map_type map_type, const char *name, -			int key_size, int value_size, int max_entries, -			__u32 map_flags); -int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size, -		   int max_entries, __u32 map_flags); -int bpf_create_map_in_map_node(enum bpf_map_type map_type, const char *name, -			       int key_size, int inner_map_fd, int max_entries, -			       __u32 map_flags, int node); -int bpf_create_map_in_map(enum bpf_map_type map_type, const char *name, -			  int key_size, int inner_map_fd, int max_entries, -			  __u32 map_flags); +LIBBPF_API int +bpf_create_map_xattr(const struct bpf_create_map_attr *create_attr); +LIBBPF_API int bpf_create_map_node(enum bpf_map_type map_type, const char *name, +				   int key_size, int value_size, +				   int max_entries, __u32 map_flags, int node); +LIBBPF_API int bpf_create_map_name(enum bpf_map_type map_type, const char *name, +				   int key_size, int value_size, +				   int max_entries, __u32 map_flags); +LIBBPF_API int bpf_create_map(enum bpf_map_type map_type, int key_size, +			      int value_size, int max_entries, __u32 map_flags); +LIBBPF_API int bpf_create_map_in_map_node(enum bpf_map_type map_type, +					  const char *name, int key_size, +					  int inner_map_fd, int max_entries, +					  __u32 map_flags, int node); +LIBBPF_API int bpf_create_map_in_map(enum bpf_map_type map_type, +				     const char *name, int key_size, +				     int inner_map_fd, int max_entries, +				     __u32 map_flags);  struct bpf_load_program_attr {  	enum bpf_prog_type prog_type; @@ -69,46 +76,56 @@ struct bpf_load_program_attr {  	__u32 prog_ifindex;  }; +/* Flags to direct loading requirements */ +#define MAPS_RELAX_COMPAT	0x01 +  /* Recommend log buffer size */  #define BPF_LOG_BUF_SIZE (256 * 1024) -int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr, -			   char *log_buf, size_t log_buf_sz); -int bpf_load_program(enum bpf_prog_type type, const struct bpf_insn *insns, -		     size_t insns_cnt, const char *license, -		     __u32 kern_version, char *log_buf, -		     size_t log_buf_sz); -int bpf_verify_program(enum bpf_prog_type type, const struct bpf_insn *insns, -		       size_t insns_cnt, int strict_alignment, -		       const char *license, __u32 kern_version, -		       char *log_buf, size_t log_buf_sz, int log_level); +LIBBPF_API int +bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr, +		       char *log_buf, size_t log_buf_sz); +LIBBPF_API int bpf_load_program(enum bpf_prog_type type, +				const struct bpf_insn *insns, size_t insns_cnt, +				const char *license, __u32 kern_version, +				char *log_buf, size_t log_buf_sz); +LIBBPF_API int bpf_verify_program(enum bpf_prog_type type, +				  const struct bpf_insn *insns, +				  size_t insns_cnt, int strict_alignment, +				  const char *license, __u32 kern_version, +				  char *log_buf, size_t log_buf_sz, +				  int log_level); -int bpf_map_update_elem(int fd, const void *key, const void *value, -			__u64 flags); +LIBBPF_API int bpf_map_update_elem(int fd, const void *key, const void *value, +				   __u64 flags); -int bpf_map_lookup_elem(int fd, const void *key, void *value); -int bpf_map_delete_elem(int fd, const void *key); -int bpf_map_get_next_key(int fd, const void *key, void *next_key); -int bpf_obj_pin(int fd, const char *pathname); -int bpf_obj_get(const char *pathname); -int bpf_prog_attach(int prog_fd, int attachable_fd, enum bpf_attach_type type, -		    unsigned int flags); -int bpf_prog_detach(int attachable_fd, enum bpf_attach_type type); -int bpf_prog_detach2(int prog_fd, int attachable_fd, enum bpf_attach_type type); -int bpf_prog_test_run(int prog_fd, int repeat, void *data, __u32 size, -		      void *data_out, __u32 *size_out, __u32 *retval, -		      __u32 *duration); -int bpf_prog_get_next_id(__u32 start_id, __u32 *next_id); -int bpf_map_get_next_id(__u32 start_id, __u32 *next_id); -int bpf_prog_get_fd_by_id(__u32 id); -int bpf_map_get_fd_by_id(__u32 id); -int bpf_btf_get_fd_by_id(__u32 id); -int bpf_obj_get_info_by_fd(int prog_fd, void *info, __u32 *info_len); -int bpf_prog_query(int target_fd, enum bpf_attach_type type, __u32 query_flags, -		   __u32 *attach_flags, __u32 *prog_ids, __u32 *prog_cnt); -int bpf_raw_tracepoint_open(const char *name, int prog_fd); -int bpf_load_btf(void *btf, __u32 btf_size, char *log_buf, __u32 log_buf_size, -		 bool do_log); -int bpf_task_fd_query(int pid, int fd, __u32 flags, char *buf, __u32 *buf_len, -		      __u32 *prog_id, __u32 *fd_type, __u64 *probe_offset, -		      __u64 *probe_addr); -#endif +LIBBPF_API int bpf_map_lookup_elem(int fd, const void *key, void *value); +LIBBPF_API int bpf_map_lookup_and_delete_elem(int fd, const void *key, +					      void *value); +LIBBPF_API int bpf_map_delete_elem(int fd, const void *key); +LIBBPF_API int bpf_map_get_next_key(int fd, const void *key, void *next_key); +LIBBPF_API int bpf_obj_pin(int fd, const char *pathname); +LIBBPF_API int bpf_obj_get(const char *pathname); +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); +LIBBPF_API int bpf_prog_test_run(int prog_fd, int repeat, void *data, +				 __u32 size, void *data_out, __u32 *size_out, +				 __u32 *retval, __u32 *duration); +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_prog_get_fd_by_id(__u32 id); +LIBBPF_API int bpf_map_get_fd_by_id(__u32 id); +LIBBPF_API int bpf_btf_get_fd_by_id(__u32 id); +LIBBPF_API int bpf_obj_get_info_by_fd(int prog_fd, void *info, __u32 *info_len); +LIBBPF_API int bpf_prog_query(int target_fd, enum bpf_attach_type type, +			      __u32 query_flags, __u32 *attach_flags, +			      __u32 *prog_ids, __u32 *prog_cnt); +LIBBPF_API int bpf_raw_tracepoint_open(const char *name, int prog_fd); +LIBBPF_API int bpf_load_btf(void *btf, __u32 btf_size, char *log_buf, +			    __u32 log_buf_size, bool do_log); +LIBBPF_API int bpf_task_fd_query(int pid, int fd, __u32 flags, char *buf, +				 __u32 *buf_len, __u32 *prog_id, __u32 *fd_type, +				 __u64 *probe_offset, __u64 *probe_addr); +#endif /* __LIBBPF_BPF_H */ diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c index cf94b0770522..449591aa9900 100644 --- a/tools/lib/bpf/btf.c +++ b/tools/lib/bpf/btf.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1 +// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)  /* Copyright (c) 2018 Facebook */  #include <stdlib.h> diff --git a/tools/lib/bpf/btf.h b/tools/lib/bpf/btf.h index 4897e0724d4e..b77e7080f7e7 100644 --- a/tools/lib/bpf/btf.h +++ b/tools/lib/bpf/btf.h @@ -1,11 +1,15 @@ -/* SPDX-License-Identifier: LGPL-2.1 */ +/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */  /* Copyright (c) 2018 Facebook */ -#ifndef __BPF_BTF_H -#define __BPF_BTF_H +#ifndef __LIBBPF_BTF_H +#define __LIBBPF_BTF_H  #include <linux/types.h> +#ifndef LIBBPF_API +#define LIBBPF_API __attribute__((visibility("default"))) +#endif +  #define BTF_ELF_SEC ".BTF"  struct btf; @@ -14,13 +18,15 @@ struct btf_type;  typedef int (*btf_print_fn_t)(const char *, ...)  	__attribute__((format(printf, 1, 2))); -void btf__free(struct btf *btf); -struct btf *btf__new(__u8 *data, __u32 size, btf_print_fn_t err_log); -__s32 btf__find_by_name(const struct btf *btf, const char *type_name); -const struct btf_type *btf__type_by_id(const struct btf *btf, __u32 id); -__s64 btf__resolve_size(const struct btf *btf, __u32 type_id); -int btf__resolve_type(const struct btf *btf, __u32 type_id); -int btf__fd(const struct btf *btf); -const char *btf__name_by_offset(const struct btf *btf, __u32 offset); +LIBBPF_API void btf__free(struct btf *btf); +LIBBPF_API struct btf *btf__new(__u8 *data, __u32 size, btf_print_fn_t err_log); +LIBBPF_API __s32 btf__find_by_name(const struct btf *btf, +				   const char *type_name); +LIBBPF_API const struct btf_type *btf__type_by_id(const struct btf *btf, +						  __u32 id); +LIBBPF_API __s64 btf__resolve_size(const struct btf *btf, __u32 type_id); +LIBBPF_API int btf__resolve_type(const struct btf *btf, __u32 type_id); +LIBBPF_API int btf__fd(const struct btf *btf); +LIBBPF_API const char *btf__name_by_offset(const struct btf *btf, __u32 offset); -#endif +#endif /* __LIBBPF_BTF_H */ diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 2abd0f112627..b607be7236d3 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1 +// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)  /*   * Common eBPF ELF object loading operations. @@ -7,19 +7,6 @@   * Copyright (C) 2015 Wang Nan <wangnan0@huawei.com>   * Copyright (C) 2015 Huawei Inc.   * Copyright (C) 2017 Nicira, Inc. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License (not later!) - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not,  see <http://www.gnu.org/licenses>   */  #define _GNU_SOURCE @@ -32,7 +19,6 @@  #include <unistd.h>  #include <fcntl.h>  #include <errno.h> -#include <perf-sys.h>  #include <asm/unistd.h>  #include <linux/err.h>  #include <linux/kernel.h> @@ -40,6 +26,8 @@  #include <linux/btf.h>  #include <linux/list.h>  #include <linux/limits.h> +#include <linux/perf_event.h> +#include <linux/ring_buffer.h>  #include <sys/stat.h>  #include <sys/types.h>  #include <sys/vfs.h> @@ -50,6 +38,7 @@  #include "libbpf.h"  #include "bpf.h"  #include "btf.h" +#include "str_error.h"  #ifndef EM_BPF  #define EM_BPF 247 @@ -181,7 +170,7 @@ static LIST_HEAD(bpf_objects_list);  struct bpf_object {  	char license[64]; -	u32 kern_version; +	__u32 kern_version;  	struct bpf_program *programs;  	size_t nr_programs; @@ -227,7 +216,7 @@ struct bpf_object {  };  #define obj_elf_valid(o)	((o)->efile.elf) -static void bpf_program__unload(struct bpf_program *prog) +void bpf_program__unload(struct bpf_program *prog)  {  	int i; @@ -469,7 +458,8 @@ static int bpf_object__elf_init(struct bpf_object *obj)  		obj->efile.fd = open(obj->path, O_RDONLY);  		if (obj->efile.fd < 0) {  			char errmsg[STRERR_BUFSIZE]; -			char *cp = strerror_r(errno, errmsg, sizeof(errmsg)); +			char *cp = libbpf_strerror_r(errno, errmsg, +						     sizeof(errmsg));  			pr_warning("failed to open %s: %s\n", obj->path, cp);  			return -errno; @@ -551,7 +541,7 @@ static int  bpf_object__init_kversion(struct bpf_object *obj,  			  void *data, size_t size)  { -	u32 kver; +	__u32 kver;  	if (size != sizeof(kver)) {  		pr_warning("invalid kver section in %s\n", obj->path); @@ -573,8 +563,9 @@ static int compare_bpf_map(const void *_a, const void *_b)  }  static int -bpf_object__init_maps(struct bpf_object *obj) +bpf_object__init_maps(struct bpf_object *obj, int flags)  { +	bool strict = !(flags & MAPS_RELAX_COMPAT);  	int i, map_idx, map_def_sz, nr_maps = 0;  	Elf_Scn *scn;  	Elf_Data *data; @@ -696,7 +687,8 @@ bpf_object__init_maps(struct bpf_object *obj)  						   "has unrecognized, non-zero "  						   "options\n",  						   obj->path, map_name); -					return -EINVAL; +					if (strict) +						return -EINVAL;  				}  			}  			memcpy(&obj->maps[map_idx].def, def, @@ -727,7 +719,7 @@ static bool section_have_execinstr(struct bpf_object *obj, int idx)  	return false;  } -static int bpf_object__elf_collect(struct bpf_object *obj) +static int bpf_object__elf_collect(struct bpf_object *obj, int flags)  {  	Elf *elf = obj->efile.elf;  	GElf_Ehdr *ep = &obj->efile.ehdr; @@ -810,8 +802,8 @@ static int bpf_object__elf_collect(struct bpf_object *obj)  						      data->d_size, name, idx);  			if (err) {  				char errmsg[STRERR_BUFSIZE]; -				char *cp = strerror_r(-err, errmsg, -						      sizeof(errmsg)); +				char *cp = libbpf_strerror_r(-err, errmsg, +							     sizeof(errmsg));  				pr_warning("failed to alloc program %s (%s): %s",  					   name, obj->path, cp); @@ -854,7 +846,7 @@ static int bpf_object__elf_collect(struct bpf_object *obj)  		return LIBBPF_ERRNO__FORMAT;  	}  	if (obj->efile.maps_shndx >= 0) { -		err = bpf_object__init_maps(obj); +		err = bpf_object__init_maps(obj, flags);  		if (err)  			goto out;  	} @@ -1140,7 +1132,7 @@ bpf_object__create_maps(struct bpf_object *obj)  		*pfd = bpf_create_map_xattr(&create_attr);  		if (*pfd < 0 && create_attr.btf_key_type_id) { -			cp = strerror_r(errno, errmsg, sizeof(errmsg)); +			cp = libbpf_strerror_r(errno, errmsg, sizeof(errmsg));  			pr_warning("Error in bpf_create_map_xattr(%s):%s(%d). Retrying without BTF.\n",  				   map->name, cp, errno);  			create_attr.btf_fd = 0; @@ -1155,7 +1147,7 @@ bpf_object__create_maps(struct bpf_object *obj)  			size_t j;  			err = *pfd; -			cp = strerror_r(errno, errmsg, sizeof(errmsg)); +			cp = libbpf_strerror_r(errno, errmsg, sizeof(errmsg));  			pr_warning("failed to create map (name: '%s'): %s\n",  				   map->name, cp);  			for (j = 0; j < i; j++) @@ -1306,7 +1298,7 @@ static int bpf_object__collect_reloc(struct bpf_object *obj)  static int  load_program(enum bpf_prog_type type, enum bpf_attach_type expected_attach_type,  	     const char *name, struct bpf_insn *insns, int insns_cnt, -	     char *license, u32 kern_version, int *pfd, int prog_ifindex) +	     char *license, __u32 kern_version, int *pfd, int prog_ifindex)  {  	struct bpf_load_program_attr load_attr;  	char *cp, errmsg[STRERR_BUFSIZE]; @@ -1339,7 +1331,7 @@ load_program(enum bpf_prog_type type, enum bpf_attach_type expected_attach_type,  	}  	ret = -LIBBPF_ERRNO__LOAD; -	cp = strerror_r(errno, errmsg, sizeof(errmsg)); +	cp = libbpf_strerror_r(errno, errmsg, sizeof(errmsg));  	pr_warning("load bpf program failed: %s\n", cp);  	if (log_buf && log_buf[0] != '\0') { @@ -1375,9 +1367,9 @@ out:  	return ret;  } -static int +int  bpf_program__load(struct bpf_program *prog, -		  char *license, u32 kern_version) +		  char *license, __u32 kern_version)  {  	int err = 0, fd, i; @@ -1502,6 +1494,7 @@ static bool bpf_prog_type__needs_kver(enum bpf_prog_type type)  	case BPF_PROG_TYPE_CGROUP_SOCK_ADDR:  	case BPF_PROG_TYPE_LIRC_MODE2:  	case BPF_PROG_TYPE_SK_REUSEPORT: +	case BPF_PROG_TYPE_FLOW_DISSECTOR:  		return false;  	case BPF_PROG_TYPE_UNSPEC:  	case BPF_PROG_TYPE_KPROBE: @@ -1525,7 +1518,7 @@ static int bpf_object__validate(struct bpf_object *obj, bool needs_kver)  static struct bpf_object *  __bpf_object__open(const char *path, void *obj_buf, size_t obj_buf_sz, -		   bool needs_kver) +		   bool needs_kver, int flags)  {  	struct bpf_object *obj;  	int err; @@ -1541,7 +1534,7 @@ __bpf_object__open(const char *path, void *obj_buf, size_t obj_buf_sz,  	CHECK_ERR(bpf_object__elf_init(obj), err, out);  	CHECK_ERR(bpf_object__check_endianness(obj), err, out); -	CHECK_ERR(bpf_object__elf_collect(obj), err, out); +	CHECK_ERR(bpf_object__elf_collect(obj, flags), err, out);  	CHECK_ERR(bpf_object__collect_reloc(obj), err, out);  	CHECK_ERR(bpf_object__validate(obj, needs_kver), err, out); @@ -1552,7 +1545,8 @@ out:  	return ERR_PTR(err);  } -struct bpf_object *bpf_object__open_xattr(struct bpf_object_open_attr *attr) +struct bpf_object *__bpf_object__open_xattr(struct bpf_object_open_attr *attr, +					    int flags)  {  	/* param validation */  	if (!attr->file) @@ -1561,7 +1555,13 @@ struct bpf_object *bpf_object__open_xattr(struct bpf_object_open_attr *attr)  	pr_debug("loading %s\n", attr->file);  	return __bpf_object__open(attr->file, NULL, 0, -				  bpf_prog_type__needs_kver(attr->prog_type)); +				  bpf_prog_type__needs_kver(attr->prog_type), +				  flags); +} + +struct bpf_object *bpf_object__open_xattr(struct bpf_object_open_attr *attr) +{ +	return __bpf_object__open_xattr(attr, 0);  }  struct bpf_object *bpf_object__open(const char *path) @@ -1594,7 +1594,7 @@ struct bpf_object *bpf_object__open_buffer(void *obj_buf,  	pr_debug("loading object '%s' from buffer\n",  		 name); -	return __bpf_object__open(name, obj_buf, obj_buf_sz, true); +	return __bpf_object__open(name, obj_buf, obj_buf_sz, true, true);  }  int bpf_object__unload(struct bpf_object *obj) @@ -1654,7 +1654,7 @@ static int check_path(const char *path)  	dir = dirname(dname);  	if (statfs(dir, &st_fs)) { -		cp = strerror_r(errno, errmsg, sizeof(errmsg)); +		cp = libbpf_strerror_r(errno, errmsg, sizeof(errmsg));  		pr_warning("failed to statfs %s: %s\n", dir, cp);  		err = -errno;  	} @@ -1690,7 +1690,7 @@ int bpf_program__pin_instance(struct bpf_program *prog, const char *path,  	}  	if (bpf_obj_pin(prog->instances.fds[instance], path)) { -		cp = strerror_r(errno, errmsg, sizeof(errmsg)); +		cp = libbpf_strerror_r(errno, errmsg, sizeof(errmsg));  		pr_warning("failed to pin program: %s\n", cp);  		return -errno;  	} @@ -1708,7 +1708,7 @@ static int make_dir(const char *path)  		err = -errno;  	if (err) { -		cp = strerror_r(-err, errmsg, sizeof(errmsg)); +		cp = libbpf_strerror_r(-err, errmsg, sizeof(errmsg));  		pr_warning("failed to mkdir %s: %s\n", path, cp);  	}  	return err; @@ -1770,7 +1770,7 @@ int bpf_map__pin(struct bpf_map *map, const char *path)  	}  	if (bpf_obj_pin(map->fd, path)) { -		cp = strerror_r(errno, errmsg, sizeof(errmsg)); +		cp = libbpf_strerror_r(errno, errmsg, sizeof(errmsg));  		pr_warning("failed to pin map: %s\n", cp);  		return -errno;  	} @@ -2084,57 +2084,90 @@ void bpf_program__set_expected_attach_type(struct bpf_program *prog,  	prog->expected_attach_type = type;  } -#define BPF_PROG_SEC_FULL(string, ptype, atype) \ -	{ string, sizeof(string) - 1, ptype, atype } +#define BPF_PROG_SEC_IMPL(string, ptype, eatype, atype) \ +	{ string, sizeof(string) - 1, ptype, eatype, atype } -#define BPF_PROG_SEC(string, ptype) BPF_PROG_SEC_FULL(string, ptype, 0) +/* Programs that can NOT be attached. */ +#define BPF_PROG_SEC(string, ptype) BPF_PROG_SEC_IMPL(string, ptype, 0, -EINVAL) -#define BPF_S_PROG_SEC(string, ptype) \ -	BPF_PROG_SEC_FULL(string, BPF_PROG_TYPE_CGROUP_SOCK, ptype) +/* Programs that can be attached. */ +#define BPF_APROG_SEC(string, ptype, atype) \ +	BPF_PROG_SEC_IMPL(string, ptype, 0, atype) -#define BPF_SA_PROG_SEC(string, ptype) \ -	BPF_PROG_SEC_FULL(string, BPF_PROG_TYPE_CGROUP_SOCK_ADDR, ptype) +/* Programs that must specify expected attach type at load time. */ +#define BPF_EAPROG_SEC(string, ptype, eatype) \ +	BPF_PROG_SEC_IMPL(string, ptype, eatype, eatype) + +/* Programs that can be attached but attach type can't be identified by section + * name. Kept for backward compatibility. + */ +#define BPF_APROG_COMPAT(string, ptype) BPF_PROG_SEC(string, ptype)  static const struct {  	const char *sec;  	size_t len;  	enum bpf_prog_type prog_type;  	enum bpf_attach_type expected_attach_type; +	enum bpf_attach_type attach_type;  } section_names[] = { -	BPF_PROG_SEC("socket",		BPF_PROG_TYPE_SOCKET_FILTER), -	BPF_PROG_SEC("kprobe/",		BPF_PROG_TYPE_KPROBE), -	BPF_PROG_SEC("kretprobe/",	BPF_PROG_TYPE_KPROBE), -	BPF_PROG_SEC("classifier",	BPF_PROG_TYPE_SCHED_CLS), -	BPF_PROG_SEC("action",		BPF_PROG_TYPE_SCHED_ACT), -	BPF_PROG_SEC("tracepoint/",	BPF_PROG_TYPE_TRACEPOINT), -	BPF_PROG_SEC("raw_tracepoint/",	BPF_PROG_TYPE_RAW_TRACEPOINT), -	BPF_PROG_SEC("xdp",		BPF_PROG_TYPE_XDP), -	BPF_PROG_SEC("perf_event",	BPF_PROG_TYPE_PERF_EVENT), -	BPF_PROG_SEC("cgroup/skb",	BPF_PROG_TYPE_CGROUP_SKB), -	BPF_PROG_SEC("cgroup/sock",	BPF_PROG_TYPE_CGROUP_SOCK), -	BPF_PROG_SEC("cgroup/dev",	BPF_PROG_TYPE_CGROUP_DEVICE), -	BPF_PROG_SEC("lwt_in",		BPF_PROG_TYPE_LWT_IN), -	BPF_PROG_SEC("lwt_out",		BPF_PROG_TYPE_LWT_OUT), -	BPF_PROG_SEC("lwt_xmit",	BPF_PROG_TYPE_LWT_XMIT), -	BPF_PROG_SEC("lwt_seg6local",	BPF_PROG_TYPE_LWT_SEG6LOCAL), -	BPF_PROG_SEC("sockops",		BPF_PROG_TYPE_SOCK_OPS), -	BPF_PROG_SEC("sk_skb",		BPF_PROG_TYPE_SK_SKB), -	BPF_PROG_SEC("sk_msg",		BPF_PROG_TYPE_SK_MSG), -	BPF_PROG_SEC("lirc_mode2",	BPF_PROG_TYPE_LIRC_MODE2), -	BPF_SA_PROG_SEC("cgroup/bind4",	BPF_CGROUP_INET4_BIND), -	BPF_SA_PROG_SEC("cgroup/bind6",	BPF_CGROUP_INET6_BIND), -	BPF_SA_PROG_SEC("cgroup/connect4", BPF_CGROUP_INET4_CONNECT), -	BPF_SA_PROG_SEC("cgroup/connect6", BPF_CGROUP_INET6_CONNECT), -	BPF_SA_PROG_SEC("cgroup/sendmsg4", BPF_CGROUP_UDP4_SENDMSG), -	BPF_SA_PROG_SEC("cgroup/sendmsg6", BPF_CGROUP_UDP6_SENDMSG), -	BPF_S_PROG_SEC("cgroup/post_bind4", BPF_CGROUP_INET4_POST_BIND), -	BPF_S_PROG_SEC("cgroup/post_bind6", BPF_CGROUP_INET6_POST_BIND), +	BPF_PROG_SEC("socket",			BPF_PROG_TYPE_SOCKET_FILTER), +	BPF_PROG_SEC("kprobe/",			BPF_PROG_TYPE_KPROBE), +	BPF_PROG_SEC("kretprobe/",		BPF_PROG_TYPE_KPROBE), +	BPF_PROG_SEC("classifier",		BPF_PROG_TYPE_SCHED_CLS), +	BPF_PROG_SEC("action",			BPF_PROG_TYPE_SCHED_ACT), +	BPF_PROG_SEC("tracepoint/",		BPF_PROG_TYPE_TRACEPOINT), +	BPF_PROG_SEC("raw_tracepoint/",		BPF_PROG_TYPE_RAW_TRACEPOINT), +	BPF_PROG_SEC("xdp",			BPF_PROG_TYPE_XDP), +	BPF_PROG_SEC("perf_event",		BPF_PROG_TYPE_PERF_EVENT), +	BPF_PROG_SEC("lwt_in",			BPF_PROG_TYPE_LWT_IN), +	BPF_PROG_SEC("lwt_out",			BPF_PROG_TYPE_LWT_OUT), +	BPF_PROG_SEC("lwt_xmit",		BPF_PROG_TYPE_LWT_XMIT), +	BPF_PROG_SEC("lwt_seg6local",		BPF_PROG_TYPE_LWT_SEG6LOCAL), +	BPF_APROG_SEC("cgroup_skb/ingress",	BPF_PROG_TYPE_CGROUP_SKB, +						BPF_CGROUP_INET_INGRESS), +	BPF_APROG_SEC("cgroup_skb/egress",	BPF_PROG_TYPE_CGROUP_SKB, +						BPF_CGROUP_INET_EGRESS), +	BPF_APROG_COMPAT("cgroup/skb",		BPF_PROG_TYPE_CGROUP_SKB), +	BPF_APROG_SEC("cgroup/sock",		BPF_PROG_TYPE_CGROUP_SOCK, +						BPF_CGROUP_INET_SOCK_CREATE), +	BPF_EAPROG_SEC("cgroup/post_bind4",	BPF_PROG_TYPE_CGROUP_SOCK, +						BPF_CGROUP_INET4_POST_BIND), +	BPF_EAPROG_SEC("cgroup/post_bind6",	BPF_PROG_TYPE_CGROUP_SOCK, +						BPF_CGROUP_INET6_POST_BIND), +	BPF_APROG_SEC("cgroup/dev",		BPF_PROG_TYPE_CGROUP_DEVICE, +						BPF_CGROUP_DEVICE), +	BPF_APROG_SEC("sockops",		BPF_PROG_TYPE_SOCK_OPS, +						BPF_CGROUP_SOCK_OPS), +	BPF_APROG_SEC("sk_skb/stream_parser",	BPF_PROG_TYPE_SK_SKB, +						BPF_SK_SKB_STREAM_PARSER), +	BPF_APROG_SEC("sk_skb/stream_verdict",	BPF_PROG_TYPE_SK_SKB, +						BPF_SK_SKB_STREAM_VERDICT), +	BPF_APROG_COMPAT("sk_skb",		BPF_PROG_TYPE_SK_SKB), +	BPF_APROG_SEC("sk_msg",			BPF_PROG_TYPE_SK_MSG, +						BPF_SK_MSG_VERDICT), +	BPF_APROG_SEC("lirc_mode2",		BPF_PROG_TYPE_LIRC_MODE2, +						BPF_LIRC_MODE2), +	BPF_APROG_SEC("flow_dissector",		BPF_PROG_TYPE_FLOW_DISSECTOR, +						BPF_FLOW_DISSECTOR), +	BPF_EAPROG_SEC("cgroup/bind4",		BPF_PROG_TYPE_CGROUP_SOCK_ADDR, +						BPF_CGROUP_INET4_BIND), +	BPF_EAPROG_SEC("cgroup/bind6",		BPF_PROG_TYPE_CGROUP_SOCK_ADDR, +						BPF_CGROUP_INET6_BIND), +	BPF_EAPROG_SEC("cgroup/connect4",	BPF_PROG_TYPE_CGROUP_SOCK_ADDR, +						BPF_CGROUP_INET4_CONNECT), +	BPF_EAPROG_SEC("cgroup/connect6",	BPF_PROG_TYPE_CGROUP_SOCK_ADDR, +						BPF_CGROUP_INET6_CONNECT), +	BPF_EAPROG_SEC("cgroup/sendmsg4",	BPF_PROG_TYPE_CGROUP_SOCK_ADDR, +						BPF_CGROUP_UDP4_SENDMSG), +	BPF_EAPROG_SEC("cgroup/sendmsg6",	BPF_PROG_TYPE_CGROUP_SOCK_ADDR, +						BPF_CGROUP_UDP6_SENDMSG),  }; +#undef BPF_PROG_SEC_IMPL  #undef BPF_PROG_SEC -#undef BPF_PROG_SEC_FULL -#undef BPF_S_PROG_SEC -#undef BPF_SA_PROG_SEC +#undef BPF_APROG_SEC +#undef BPF_EAPROG_SEC +#undef BPF_APROG_COMPAT  int libbpf_prog_type_by_name(const char *name, enum bpf_prog_type *prog_type,  			     enum bpf_attach_type *expected_attach_type) @@ -2154,6 +2187,25 @@ int libbpf_prog_type_by_name(const char *name, enum bpf_prog_type *prog_type,  	return -EINVAL;  } +int libbpf_attach_type_by_name(const char *name, +			       enum bpf_attach_type *attach_type) +{ +	int i; + +	if (!name) +		return -EINVAL; + +	for (i = 0; i < ARRAY_SIZE(section_names); i++) { +		if (strncmp(name, section_names[i].sec, section_names[i].len)) +			continue; +		if (section_names[i].attach_type == -EINVAL) +			return -EINVAL; +		*attach_type = section_names[i].attach_type; +		return 0; +	} +	return -EINVAL; +} +  static int  bpf_program__identify_section(struct bpf_program *prog,  			      enum bpf_prog_type *prog_type, @@ -2336,7 +2388,7 @@ int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr,  		bpf_program__set_expected_attach_type(prog,  						      expected_attach_type); -		if (!bpf_program__is_function_storage(prog, obj) && !first_prog) +		if (!first_prog)  			first_prog = prog;  	} @@ -2363,61 +2415,49 @@ int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr,  }  enum bpf_perf_event_ret -bpf_perf_event_read_simple(void *mem, unsigned long size, -			   unsigned long page_size, void **buf, size_t *buf_len, -			   bpf_perf_event_print_t fn, void *priv) +bpf_perf_event_read_simple(void *mmap_mem, size_t mmap_size, size_t page_size, +			   void **copy_mem, size_t *copy_size, +			   bpf_perf_event_print_t fn, void *private_data)  { -	volatile struct perf_event_mmap_page *header = mem; +	struct perf_event_mmap_page *header = mmap_mem; +	__u64 data_head = ring_buffer_read_head(header);  	__u64 data_tail = header->data_tail; -	__u64 data_head = header->data_head; -	int ret = LIBBPF_PERF_EVENT_ERROR; -	void *base, *begin, *end; - -	asm volatile("" ::: "memory"); /* in real code it should be smp_rmb() */ -	if (data_head == data_tail) -		return LIBBPF_PERF_EVENT_CONT; - -	base = ((char *)header) + page_size; - -	begin = base + data_tail % size; -	end = base + data_head % size; - -	while (begin != end) { -		struct perf_event_header *ehdr; - -		ehdr = begin; -		if (begin + ehdr->size > base + size) { -			long len = base + size - begin; - -			if (*buf_len < ehdr->size) { -				free(*buf); -				*buf = malloc(ehdr->size); -				if (!*buf) { +	void *base = ((__u8 *)header) + page_size; +	int ret = LIBBPF_PERF_EVENT_CONT; +	struct perf_event_header *ehdr; +	size_t ehdr_size; + +	while (data_head != data_tail) { +		ehdr = base + (data_tail & (mmap_size - 1)); +		ehdr_size = ehdr->size; + +		if (((void *)ehdr) + ehdr_size > base + mmap_size) { +			void *copy_start = ehdr; +			size_t len_first = base + mmap_size - copy_start; +			size_t len_secnd = ehdr_size - len_first; + +			if (*copy_size < ehdr_size) { +				free(*copy_mem); +				*copy_mem = malloc(ehdr_size); +				if (!*copy_mem) { +					*copy_size = 0;  					ret = LIBBPF_PERF_EVENT_ERROR;  					break;  				} -				*buf_len = ehdr->size; +				*copy_size = ehdr_size;  			} -			memcpy(*buf, begin, len); -			memcpy(*buf + len, base, ehdr->size - len); -			ehdr = (void *)*buf; -			begin = base + ehdr->size - len; -		} else if (begin + ehdr->size == base + size) { -			begin = base; -		} else { -			begin += ehdr->size; +			memcpy(*copy_mem, copy_start, len_first); +			memcpy(*copy_mem + len_first, base, len_secnd); +			ehdr = *copy_mem;  		} -		ret = fn(ehdr, priv); +		ret = fn(ehdr, private_data); +		data_tail += ehdr_size;  		if (ret != LIBBPF_PERF_EVENT_CONT)  			break; - -		data_tail += ehdr->size;  	} -	__sync_synchronize(); /* smp_mb() */ -	header->data_tail = data_tail; - +	ring_buffer_write_tail(header, data_tail);  	return ret;  } diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index 96c55fac54c3..1f3468dad8b2 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1 */ +/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */  /*   * Common eBPF ELF object loading operations. @@ -6,22 +6,9 @@   * Copyright (C) 2013-2015 Alexei Starovoitov <ast@kernel.org>   * Copyright (C) 2015 Wang Nan <wangnan0@huawei.com>   * Copyright (C) 2015 Huawei Inc. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License (not later!) - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not,  see <http://www.gnu.org/licenses>   */ -#ifndef __BPF_LIBBPF_H -#define __BPF_LIBBPF_H +#ifndef __LIBBPF_LIBBPF_H +#define __LIBBPF_LIBBPF_H  #include <stdio.h>  #include <stdint.h> @@ -29,6 +16,10 @@  #include <sys/types.h>  // for size_t  #include <linux/bpf.h> +#ifndef LIBBPF_API +#define LIBBPF_API __attribute__((visibility("default"))) +#endif +  enum libbpf_errno {  	__LIBBPF_ERRNO__START = 4000, @@ -46,10 +37,11 @@ enum libbpf_errno {  	LIBBPF_ERRNO__PROGTYPE,	/* Kernel doesn't support this program type */  	LIBBPF_ERRNO__WRNGPID,	/* Wrong pid in netlink message */  	LIBBPF_ERRNO__INVSEQ,	/* Invalid netlink sequence */ +	LIBBPF_ERRNO__NLPARSE,	/* netlink parsing error */  	__LIBBPF_ERRNO__END,  }; -int libbpf_strerror(int err, char *buf, size_t size); +LIBBPF_API int libbpf_strerror(int err, char *buf, size_t size);  /*   * __printf is defined in include/linux/compiler-gcc.h. However, @@ -59,9 +51,9 @@ int libbpf_strerror(int err, char *buf, size_t size);  typedef int (*libbpf_print_fn_t)(const char *, ...)  	__attribute__((format(printf, 1, 2))); -void libbpf_set_print(libbpf_print_fn_t warn, -		      libbpf_print_fn_t info, -		      libbpf_print_fn_t debug); +LIBBPF_API void libbpf_set_print(libbpf_print_fn_t warn, +				 libbpf_print_fn_t info, +				 libbpf_print_fn_t debug);  /* Hide internal to user */  struct bpf_object; @@ -71,25 +63,28 @@ struct bpf_object_open_attr {  	enum bpf_prog_type prog_type;  }; -struct bpf_object *bpf_object__open(const char *path); -struct bpf_object *bpf_object__open_xattr(struct bpf_object_open_attr *attr); -struct bpf_object *bpf_object__open_buffer(void *obj_buf, -					   size_t obj_buf_sz, -					   const char *name); -int bpf_object__pin(struct bpf_object *object, const char *path); -void bpf_object__close(struct bpf_object *object); +LIBBPF_API struct bpf_object *bpf_object__open(const char *path); +LIBBPF_API struct bpf_object * +bpf_object__open_xattr(struct bpf_object_open_attr *attr); +struct bpf_object *__bpf_object__open_xattr(struct bpf_object_open_attr *attr, +					    int flags); +LIBBPF_API struct bpf_object *bpf_object__open_buffer(void *obj_buf, +						      size_t obj_buf_sz, +						      const char *name); +LIBBPF_API int bpf_object__pin(struct bpf_object *object, const char *path); +LIBBPF_API void bpf_object__close(struct bpf_object *object);  /* Load/unload object into/from kernel */ -int bpf_object__load(struct bpf_object *obj); -int bpf_object__unload(struct bpf_object *obj); -const char *bpf_object__name(struct bpf_object *obj); -unsigned int bpf_object__kversion(struct bpf_object *obj); -int bpf_object__btf_fd(const struct bpf_object *obj); +LIBBPF_API int bpf_object__load(struct bpf_object *obj); +LIBBPF_API int bpf_object__unload(struct bpf_object *obj); +LIBBPF_API const char *bpf_object__name(struct bpf_object *obj); +LIBBPF_API unsigned int bpf_object__kversion(struct bpf_object *obj); +LIBBPF_API int bpf_object__btf_fd(const struct bpf_object *obj); -struct bpf_program * +LIBBPF_API struct bpf_program *  bpf_object__find_program_by_title(struct bpf_object *obj, const char *title); -struct bpf_object *bpf_object__next(struct bpf_object *prev); +LIBBPF_API struct bpf_object *bpf_object__next(struct bpf_object *prev);  #define bpf_object__for_each_safe(pos, tmp)			\  	for ((pos) = bpf_object__next(NULL),		\  		(tmp) = bpf_object__next(pos);		\ @@ -97,17 +92,20 @@ struct bpf_object *bpf_object__next(struct bpf_object *prev);  	     (pos) = (tmp), (tmp) = bpf_object__next(tmp))  typedef void (*bpf_object_clear_priv_t)(struct bpf_object *, void *); -int bpf_object__set_priv(struct bpf_object *obj, void *priv, -			 bpf_object_clear_priv_t clear_priv); -void *bpf_object__priv(struct bpf_object *prog); +LIBBPF_API int bpf_object__set_priv(struct bpf_object *obj, void *priv, +				    bpf_object_clear_priv_t clear_priv); +LIBBPF_API void *bpf_object__priv(struct bpf_object *prog); -int libbpf_prog_type_by_name(const char *name, enum bpf_prog_type *prog_type, -			     enum bpf_attach_type *expected_attach_type); +LIBBPF_API int +libbpf_prog_type_by_name(const char *name, enum bpf_prog_type *prog_type, +			 enum bpf_attach_type *expected_attach_type); +LIBBPF_API int libbpf_attach_type_by_name(const char *name, +					  enum bpf_attach_type *attach_type);  /* Accessors of bpf_program */  struct bpf_program; -struct bpf_program *bpf_program__next(struct bpf_program *prog, -				      struct bpf_object *obj); +LIBBPF_API struct bpf_program *bpf_program__next(struct bpf_program *prog, +						 struct bpf_object *obj);  #define bpf_object__for_each_program(pos, obj)		\  	for ((pos) = bpf_program__next(NULL, (obj));	\ @@ -117,18 +115,24 @@ struct bpf_program *bpf_program__next(struct bpf_program *prog,  typedef void (*bpf_program_clear_priv_t)(struct bpf_program *,  					 void *); -int bpf_program__set_priv(struct bpf_program *prog, void *priv, -			  bpf_program_clear_priv_t clear_priv); +LIBBPF_API int bpf_program__set_priv(struct bpf_program *prog, void *priv, +				     bpf_program_clear_priv_t clear_priv); -void *bpf_program__priv(struct bpf_program *prog); -void bpf_program__set_ifindex(struct bpf_program *prog, __u32 ifindex); +LIBBPF_API void *bpf_program__priv(struct bpf_program *prog); +LIBBPF_API void bpf_program__set_ifindex(struct bpf_program *prog, +					 __u32 ifindex); -const char *bpf_program__title(struct bpf_program *prog, bool needs_copy); +LIBBPF_API const char *bpf_program__title(struct bpf_program *prog, +					  bool needs_copy); -int bpf_program__fd(struct bpf_program *prog); -int bpf_program__pin_instance(struct bpf_program *prog, const char *path, -			      int instance); -int bpf_program__pin(struct bpf_program *prog, const char *path); +LIBBPF_API int bpf_program__load(struct bpf_program *prog, char *license, +				 __u32 kern_version); +LIBBPF_API int bpf_program__fd(struct bpf_program *prog); +LIBBPF_API int bpf_program__pin_instance(struct bpf_program *prog, +					 const char *path, +					 int instance); +LIBBPF_API int bpf_program__pin(struct bpf_program *prog, const char *path); +LIBBPF_API void bpf_program__unload(struct bpf_program *prog);  struct bpf_insn; @@ -189,34 +193,36 @@ typedef int (*bpf_program_prep_t)(struct bpf_program *prog, int n,  				  struct bpf_insn *insns, int insns_cnt,  				  struct bpf_prog_prep_result *res); -int bpf_program__set_prep(struct bpf_program *prog, int nr_instance, -			  bpf_program_prep_t prep); +LIBBPF_API int bpf_program__set_prep(struct bpf_program *prog, int nr_instance, +				     bpf_program_prep_t prep); -int bpf_program__nth_fd(struct bpf_program *prog, int n); +LIBBPF_API int bpf_program__nth_fd(struct bpf_program *prog, int n);  /*   * Adjust type of BPF program. Default is kprobe.   */ -int bpf_program__set_socket_filter(struct bpf_program *prog); -int bpf_program__set_tracepoint(struct bpf_program *prog); -int bpf_program__set_raw_tracepoint(struct bpf_program *prog); -int bpf_program__set_kprobe(struct bpf_program *prog); -int bpf_program__set_sched_cls(struct bpf_program *prog); -int bpf_program__set_sched_act(struct bpf_program *prog); -int bpf_program__set_xdp(struct bpf_program *prog); -int bpf_program__set_perf_event(struct bpf_program *prog); -void bpf_program__set_type(struct bpf_program *prog, enum bpf_prog_type type); -void bpf_program__set_expected_attach_type(struct bpf_program *prog, -					   enum bpf_attach_type type); - -bool bpf_program__is_socket_filter(struct bpf_program *prog); -bool bpf_program__is_tracepoint(struct bpf_program *prog); -bool bpf_program__is_raw_tracepoint(struct bpf_program *prog); -bool bpf_program__is_kprobe(struct bpf_program *prog); -bool bpf_program__is_sched_cls(struct bpf_program *prog); -bool bpf_program__is_sched_act(struct bpf_program *prog); -bool bpf_program__is_xdp(struct bpf_program *prog); -bool bpf_program__is_perf_event(struct bpf_program *prog); +LIBBPF_API int bpf_program__set_socket_filter(struct bpf_program *prog); +LIBBPF_API int bpf_program__set_tracepoint(struct bpf_program *prog); +LIBBPF_API int bpf_program__set_raw_tracepoint(struct bpf_program *prog); +LIBBPF_API int bpf_program__set_kprobe(struct bpf_program *prog); +LIBBPF_API int bpf_program__set_sched_cls(struct bpf_program *prog); +LIBBPF_API int bpf_program__set_sched_act(struct bpf_program *prog); +LIBBPF_API int bpf_program__set_xdp(struct bpf_program *prog); +LIBBPF_API int bpf_program__set_perf_event(struct bpf_program *prog); +LIBBPF_API void bpf_program__set_type(struct bpf_program *prog, +				      enum bpf_prog_type type); +LIBBPF_API void +bpf_program__set_expected_attach_type(struct bpf_program *prog, +				      enum bpf_attach_type type); + +LIBBPF_API bool bpf_program__is_socket_filter(struct bpf_program *prog); +LIBBPF_API bool bpf_program__is_tracepoint(struct bpf_program *prog); +LIBBPF_API bool bpf_program__is_raw_tracepoint(struct bpf_program *prog); +LIBBPF_API bool bpf_program__is_kprobe(struct bpf_program *prog); +LIBBPF_API bool bpf_program__is_sched_cls(struct bpf_program *prog); +LIBBPF_API bool bpf_program__is_sched_act(struct bpf_program *prog); +LIBBPF_API bool bpf_program__is_xdp(struct bpf_program *prog); +LIBBPF_API bool bpf_program__is_perf_event(struct bpf_program *prog);  /*   * No need for __attribute__((packed)), all members of 'bpf_map_def' @@ -237,39 +243,39 @@ struct bpf_map_def {   * so no need to worry about a name clash.   */  struct bpf_map; -struct bpf_map * +LIBBPF_API struct bpf_map *  bpf_object__find_map_by_name(struct bpf_object *obj, const char *name);  /*   * Get bpf_map through the offset of corresponding struct bpf_map_def   * in the BPF object file.   */ -struct bpf_map * +LIBBPF_API struct bpf_map *  bpf_object__find_map_by_offset(struct bpf_object *obj, size_t offset); -struct bpf_map * +LIBBPF_API struct bpf_map *  bpf_map__next(struct bpf_map *map, struct bpf_object *obj);  #define bpf_map__for_each(pos, obj)		\  	for ((pos) = bpf_map__next(NULL, (obj));	\  	     (pos) != NULL;				\  	     (pos) = bpf_map__next((pos), (obj))) -int bpf_map__fd(struct bpf_map *map); -const struct bpf_map_def *bpf_map__def(struct bpf_map *map); -const char *bpf_map__name(struct bpf_map *map); -__u32 bpf_map__btf_key_type_id(const struct bpf_map *map); -__u32 bpf_map__btf_value_type_id(const struct bpf_map *map); +LIBBPF_API int bpf_map__fd(struct bpf_map *map); +LIBBPF_API const struct bpf_map_def *bpf_map__def(struct bpf_map *map); +LIBBPF_API const char *bpf_map__name(struct bpf_map *map); +LIBBPF_API __u32 bpf_map__btf_key_type_id(const struct bpf_map *map); +LIBBPF_API __u32 bpf_map__btf_value_type_id(const struct bpf_map *map);  typedef void (*bpf_map_clear_priv_t)(struct bpf_map *, void *); -int bpf_map__set_priv(struct bpf_map *map, void *priv, -		      bpf_map_clear_priv_t clear_priv); -void *bpf_map__priv(struct bpf_map *map); -int bpf_map__reuse_fd(struct bpf_map *map, int fd); -bool bpf_map__is_offload_neutral(struct bpf_map *map); -void bpf_map__set_ifindex(struct bpf_map *map, __u32 ifindex); -int bpf_map__pin(struct bpf_map *map, const char *path); +LIBBPF_API int bpf_map__set_priv(struct bpf_map *map, void *priv, +				 bpf_map_clear_priv_t clear_priv); +LIBBPF_API void *bpf_map__priv(struct bpf_map *map); +LIBBPF_API int bpf_map__reuse_fd(struct bpf_map *map, int fd); +LIBBPF_API bool bpf_map__is_offload_neutral(struct bpf_map *map); +LIBBPF_API void bpf_map__set_ifindex(struct bpf_map *map, __u32 ifindex); +LIBBPF_API int bpf_map__pin(struct bpf_map *map, const char *path); -long libbpf_get_error(const void *ptr); +LIBBPF_API long libbpf_get_error(const void *ptr);  struct bpf_prog_load_attr {  	const char *file; @@ -278,12 +284,12 @@ struct bpf_prog_load_attr {  	int ifindex;  }; -int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr, -			struct bpf_object **pobj, int *prog_fd); -int bpf_prog_load(const char *file, enum bpf_prog_type type, -		  struct bpf_object **pobj, int *prog_fd); +LIBBPF_API int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr, +				   struct bpf_object **pobj, int *prog_fd); +LIBBPF_API int bpf_prog_load(const char *file, enum bpf_prog_type type, +			     struct bpf_object **pobj, int *prog_fd); -int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags); +LIBBPF_API int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags);  enum bpf_perf_event_ret {  	LIBBPF_PERF_EVENT_DONE	= 0, @@ -291,10 +297,24 @@ enum bpf_perf_event_ret {  	LIBBPF_PERF_EVENT_CONT	= -2,  }; -typedef enum bpf_perf_event_ret (*bpf_perf_event_print_t)(void *event, -							  void *priv); -int bpf_perf_event_read_simple(void *mem, unsigned long size, -			       unsigned long page_size, -			       void **buf, size_t *buf_len, -			       bpf_perf_event_print_t fn, void *priv); -#endif +struct perf_event_header; +typedef enum bpf_perf_event_ret +	(*bpf_perf_event_print_t)(struct perf_event_header *hdr, +				  void *private_data); +LIBBPF_API enum bpf_perf_event_ret +bpf_perf_event_read_simple(void *mmap_mem, size_t mmap_size, size_t page_size, +			   void **copy_mem, size_t *copy_size, +			   bpf_perf_event_print_t fn, void *private_data); + +struct nlattr; +typedef int (*libbpf_dump_nlmsg_t)(void *cookie, void *msg, struct nlattr **tb); +int libbpf_netlink_open(unsigned int *nl_pid); +int libbpf_nl_get_link(int sock, unsigned int nl_pid, +		       libbpf_dump_nlmsg_t dump_link_nlmsg, void *cookie); +int libbpf_nl_get_class(int sock, unsigned int nl_pid, int ifindex, +			libbpf_dump_nlmsg_t dump_class_nlmsg, void *cookie); +int libbpf_nl_get_qdisc(int sock, unsigned int nl_pid, int ifindex, +			libbpf_dump_nlmsg_t dump_qdisc_nlmsg, void *cookie); +int libbpf_nl_get_filter(int sock, unsigned int nl_pid, int ifindex, int handle, +			 libbpf_dump_nlmsg_t dump_filter_nlmsg, void *cookie); +#endif /* __LIBBPF_LIBBPF_H */ diff --git a/tools/lib/bpf/libbpf_errno.c b/tools/lib/bpf/libbpf_errno.c index d9ba851bd7f9..d83b17f8435c 100644 --- a/tools/lib/bpf/libbpf_errno.c +++ b/tools/lib/bpf/libbpf_errno.c @@ -1,23 +1,10 @@ -// SPDX-License-Identifier: LGPL-2.1 +// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)  /*   * Copyright (C) 2013-2015 Alexei Starovoitov <ast@kernel.org>   * Copyright (C) 2015 Wang Nan <wangnan0@huawei.com>   * Copyright (C) 2015 Huawei Inc.   * Copyright (C) 2017 Nicira, Inc. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License (not later!) - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not,  see <http://www.gnu.org/licenses>   */  #include <stdio.h> @@ -42,6 +29,7 @@ static const char *libbpf_strerror_table[NR_ERRNO] = {  	[ERRCODE_OFFSET(PROGTYPE)]	= "Kernel doesn't support this program type",  	[ERRCODE_OFFSET(WRNGPID)]	= "Wrong pid in netlink message",  	[ERRCODE_OFFSET(INVSEQ)]	= "Invalid netlink sequence", +	[ERRCODE_OFFSET(NLPARSE)]	= "Incorrect netlink message parsing",  };  int libbpf_strerror(int err, char *buf, size_t size) diff --git a/tools/lib/bpf/netlink.c b/tools/lib/bpf/netlink.c new file mode 100644 index 000000000000..0ce67aea8f3b --- /dev/null +++ b/tools/lib/bpf/netlink.c @@ -0,0 +1,337 @@ +// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) +/* Copyright (c) 2018 Facebook */ + +#include <stdlib.h> +#include <memory.h> +#include <unistd.h> +#include <linux/bpf.h> +#include <linux/rtnetlink.h> +#include <sys/socket.h> +#include <errno.h> +#include <time.h> + +#include "bpf.h" +#include "libbpf.h" +#include "nlattr.h" + +#ifndef SOL_NETLINK +#define SOL_NETLINK 270 +#endif + +typedef int (*__dump_nlmsg_t)(struct nlmsghdr *nlmsg, libbpf_dump_nlmsg_t, +			      void *cookie); + +int libbpf_netlink_open(__u32 *nl_pid) +{ +	struct sockaddr_nl sa; +	socklen_t addrlen; +	int one = 1, ret; +	int sock; + +	memset(&sa, 0, sizeof(sa)); +	sa.nl_family = AF_NETLINK; + +	sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); +	if (sock < 0) +		return -errno; + +	if (setsockopt(sock, SOL_NETLINK, NETLINK_EXT_ACK, +		       &one, sizeof(one)) < 0) { +		fprintf(stderr, "Netlink error reporting not supported\n"); +	} + +	if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) { +		ret = -errno; +		goto cleanup; +	} + +	addrlen = sizeof(sa); +	if (getsockname(sock, (struct sockaddr *)&sa, &addrlen) < 0) { +		ret = -errno; +		goto cleanup; +	} + +	if (addrlen != sizeof(sa)) { +		ret = -LIBBPF_ERRNO__INTERNAL; +		goto cleanup; +	} + +	*nl_pid = sa.nl_pid; +	return sock; + +cleanup: +	close(sock); +	return ret; +} + +static int bpf_netlink_recv(int sock, __u32 nl_pid, int seq, +			    __dump_nlmsg_t _fn, libbpf_dump_nlmsg_t fn, +			    void *cookie) +{ +	bool multipart = true; +	struct nlmsgerr *err; +	struct nlmsghdr *nh; +	char buf[4096]; +	int len, ret; + +	while (multipart) { +		multipart = false; +		len = recv(sock, buf, sizeof(buf), 0); +		if (len < 0) { +			ret = -errno; +			goto done; +		} + +		if (len == 0) +			break; + +		for (nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, len); +		     nh = NLMSG_NEXT(nh, len)) { +			if (nh->nlmsg_pid != nl_pid) { +				ret = -LIBBPF_ERRNO__WRNGPID; +				goto done; +			} +			if (nh->nlmsg_seq != seq) { +				ret = -LIBBPF_ERRNO__INVSEQ; +				goto done; +			} +			if (nh->nlmsg_flags & NLM_F_MULTI) +				multipart = true; +			switch (nh->nlmsg_type) { +			case NLMSG_ERROR: +				err = (struct nlmsgerr *)NLMSG_DATA(nh); +				if (!err->error) +					continue; +				ret = err->error; +				libbpf_nla_dump_errormsg(nh); +				goto done; +			case NLMSG_DONE: +				return 0; +			default: +				break; +			} +			if (_fn) { +				ret = _fn(nh, fn, cookie); +				if (ret) +					return ret; +			} +		} +	} +	ret = 0; +done: +	return ret; +} + +int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags) +{ +	int sock, seq = 0, ret; +	struct nlattr *nla, *nla_xdp; +	struct { +		struct nlmsghdr  nh; +		struct ifinfomsg ifinfo; +		char             attrbuf[64]; +	} req; +	__u32 nl_pid; + +	sock = libbpf_netlink_open(&nl_pid); +	if (sock < 0) +		return sock; + +	memset(&req, 0, sizeof(req)); +	req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); +	req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; +	req.nh.nlmsg_type = RTM_SETLINK; +	req.nh.nlmsg_pid = 0; +	req.nh.nlmsg_seq = ++seq; +	req.ifinfo.ifi_family = AF_UNSPEC; +	req.ifinfo.ifi_index = ifindex; + +	/* started nested attribute for XDP */ +	nla = (struct nlattr *)(((char *)&req) +				+ NLMSG_ALIGN(req.nh.nlmsg_len)); +	nla->nla_type = NLA_F_NESTED | IFLA_XDP; +	nla->nla_len = NLA_HDRLEN; + +	/* add XDP fd */ +	nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len); +	nla_xdp->nla_type = IFLA_XDP_FD; +	nla_xdp->nla_len = NLA_HDRLEN + sizeof(int); +	memcpy((char *)nla_xdp + NLA_HDRLEN, &fd, sizeof(fd)); +	nla->nla_len += nla_xdp->nla_len; + +	/* if user passed in any flags, add those too */ +	if (flags) { +		nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len); +		nla_xdp->nla_type = IFLA_XDP_FLAGS; +		nla_xdp->nla_len = NLA_HDRLEN + sizeof(flags); +		memcpy((char *)nla_xdp + NLA_HDRLEN, &flags, sizeof(flags)); +		nla->nla_len += nla_xdp->nla_len; +	} + +	req.nh.nlmsg_len += NLA_ALIGN(nla->nla_len); + +	if (send(sock, &req, req.nh.nlmsg_len, 0) < 0) { +		ret = -errno; +		goto cleanup; +	} +	ret = bpf_netlink_recv(sock, nl_pid, seq, NULL, NULL, NULL); + +cleanup: +	close(sock); +	return ret; +} + +static int __dump_link_nlmsg(struct nlmsghdr *nlh, +			     libbpf_dump_nlmsg_t dump_link_nlmsg, void *cookie) +{ +	struct nlattr *tb[IFLA_MAX + 1], *attr; +	struct ifinfomsg *ifi = NLMSG_DATA(nlh); +	int len; + +	len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*ifi)); +	attr = (struct nlattr *) ((void *) ifi + NLMSG_ALIGN(sizeof(*ifi))); +	if (libbpf_nla_parse(tb, IFLA_MAX, attr, len, NULL) != 0) +		return -LIBBPF_ERRNO__NLPARSE; + +	return dump_link_nlmsg(cookie, ifi, tb); +} + +int libbpf_nl_get_link(int sock, unsigned int nl_pid, +		       libbpf_dump_nlmsg_t dump_link_nlmsg, void *cookie) +{ +	struct { +		struct nlmsghdr nlh; +		struct ifinfomsg ifm; +	} req = { +		.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)), +		.nlh.nlmsg_type = RTM_GETLINK, +		.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST, +		.ifm.ifi_family = AF_PACKET, +	}; +	int seq = time(NULL); + +	req.nlh.nlmsg_seq = seq; +	if (send(sock, &req, req.nlh.nlmsg_len, 0) < 0) +		return -errno; + +	return bpf_netlink_recv(sock, nl_pid, seq, __dump_link_nlmsg, +				dump_link_nlmsg, cookie); +} + +static int __dump_class_nlmsg(struct nlmsghdr *nlh, +			      libbpf_dump_nlmsg_t dump_class_nlmsg, +			      void *cookie) +{ +	struct nlattr *tb[TCA_MAX + 1], *attr; +	struct tcmsg *t = NLMSG_DATA(nlh); +	int len; + +	len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*t)); +	attr = (struct nlattr *) ((void *) t + NLMSG_ALIGN(sizeof(*t))); +	if (libbpf_nla_parse(tb, TCA_MAX, attr, len, NULL) != 0) +		return -LIBBPF_ERRNO__NLPARSE; + +	return dump_class_nlmsg(cookie, t, tb); +} + +int libbpf_nl_get_class(int sock, unsigned int nl_pid, int ifindex, +			libbpf_dump_nlmsg_t dump_class_nlmsg, void *cookie) +{ +	struct { +		struct nlmsghdr nlh; +		struct tcmsg t; +	} req = { +		.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)), +		.nlh.nlmsg_type = RTM_GETTCLASS, +		.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST, +		.t.tcm_family = AF_UNSPEC, +		.t.tcm_ifindex = ifindex, +	}; +	int seq = time(NULL); + +	req.nlh.nlmsg_seq = seq; +	if (send(sock, &req, req.nlh.nlmsg_len, 0) < 0) +		return -errno; + +	return bpf_netlink_recv(sock, nl_pid, seq, __dump_class_nlmsg, +				dump_class_nlmsg, cookie); +} + +static int __dump_qdisc_nlmsg(struct nlmsghdr *nlh, +			      libbpf_dump_nlmsg_t dump_qdisc_nlmsg, +			      void *cookie) +{ +	struct nlattr *tb[TCA_MAX + 1], *attr; +	struct tcmsg *t = NLMSG_DATA(nlh); +	int len; + +	len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*t)); +	attr = (struct nlattr *) ((void *) t + NLMSG_ALIGN(sizeof(*t))); +	if (libbpf_nla_parse(tb, TCA_MAX, attr, len, NULL) != 0) +		return -LIBBPF_ERRNO__NLPARSE; + +	return dump_qdisc_nlmsg(cookie, t, tb); +} + +int libbpf_nl_get_qdisc(int sock, unsigned int nl_pid, int ifindex, +			libbpf_dump_nlmsg_t dump_qdisc_nlmsg, void *cookie) +{ +	struct { +		struct nlmsghdr nlh; +		struct tcmsg t; +	} req = { +		.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)), +		.nlh.nlmsg_type = RTM_GETQDISC, +		.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST, +		.t.tcm_family = AF_UNSPEC, +		.t.tcm_ifindex = ifindex, +	}; +	int seq = time(NULL); + +	req.nlh.nlmsg_seq = seq; +	if (send(sock, &req, req.nlh.nlmsg_len, 0) < 0) +		return -errno; + +	return bpf_netlink_recv(sock, nl_pid, seq, __dump_qdisc_nlmsg, +				dump_qdisc_nlmsg, cookie); +} + +static int __dump_filter_nlmsg(struct nlmsghdr *nlh, +			       libbpf_dump_nlmsg_t dump_filter_nlmsg, +			       void *cookie) +{ +	struct nlattr *tb[TCA_MAX + 1], *attr; +	struct tcmsg *t = NLMSG_DATA(nlh); +	int len; + +	len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*t)); +	attr = (struct nlattr *) ((void *) t + NLMSG_ALIGN(sizeof(*t))); +	if (libbpf_nla_parse(tb, TCA_MAX, attr, len, NULL) != 0) +		return -LIBBPF_ERRNO__NLPARSE; + +	return dump_filter_nlmsg(cookie, t, tb); +} + +int libbpf_nl_get_filter(int sock, unsigned int nl_pid, int ifindex, int handle, +			 libbpf_dump_nlmsg_t dump_filter_nlmsg, void *cookie) +{ +	struct { +		struct nlmsghdr nlh; +		struct tcmsg t; +	} req = { +		.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)), +		.nlh.nlmsg_type = RTM_GETTFILTER, +		.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST, +		.t.tcm_family = AF_UNSPEC, +		.t.tcm_ifindex = ifindex, +		.t.tcm_parent = handle, +	}; +	int seq = time(NULL); + +	req.nlh.nlmsg_seq = seq; +	if (send(sock, &req, req.nlh.nlmsg_len, 0) < 0) +		return -errno; + +	return bpf_netlink_recv(sock, nl_pid, seq, __dump_filter_nlmsg, +				dump_filter_nlmsg, cookie); +} diff --git a/tools/lib/bpf/nlattr.c b/tools/lib/bpf/nlattr.c index 4719434278b2..1e69c0c8d413 100644 --- a/tools/lib/bpf/nlattr.c +++ b/tools/lib/bpf/nlattr.c @@ -1,13 +1,8 @@ -// SPDX-License-Identifier: LGPL-2.1 +// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)  /*   * NETLINK      Netlink attributes   * - *	This library is free software; you can redistribute it and/or - *	modify it under the terms of the GNU Lesser General Public - *	License as published by the Free Software Foundation version 2.1 - *	of the License. - *   * Copyright (c) 2003-2013 Thomas Graf <tgraf@suug.ch>   */ @@ -17,20 +12,15 @@  #include <string.h>  #include <stdio.h> -static uint16_t nla_attr_minlen[NLA_TYPE_MAX+1] = { -	[NLA_U8]	= sizeof(uint8_t), -	[NLA_U16]	= sizeof(uint16_t), -	[NLA_U32]	= sizeof(uint32_t), -	[NLA_U64]	= sizeof(uint64_t), -	[NLA_STRING]	= 1, -	[NLA_FLAG]	= 0, +static uint16_t nla_attr_minlen[LIBBPF_NLA_TYPE_MAX+1] = { +	[LIBBPF_NLA_U8]		= sizeof(uint8_t), +	[LIBBPF_NLA_U16]	= sizeof(uint16_t), +	[LIBBPF_NLA_U32]	= sizeof(uint32_t), +	[LIBBPF_NLA_U64]	= sizeof(uint64_t), +	[LIBBPF_NLA_STRING]	= 1, +	[LIBBPF_NLA_FLAG]	= 0,  }; -static int nla_len(const struct nlattr *nla) -{ -	return nla->nla_len - NLA_HDRLEN; -} -  static struct nlattr *nla_next(const struct nlattr *nla, int *remaining)  {  	int totlen = NLA_ALIGN(nla->nla_len); @@ -46,20 +36,15 @@ static int nla_ok(const struct nlattr *nla, int remaining)  	       nla->nla_len <= remaining;  } -static void *nla_data(const struct nlattr *nla) -{ -	return (char *) nla + NLA_HDRLEN; -} -  static int nla_type(const struct nlattr *nla)  {  	return nla->nla_type & NLA_TYPE_MASK;  }  static int validate_nla(struct nlattr *nla, int maxtype, -			struct nla_policy *policy) +			struct libbpf_nla_policy *policy)  { -	struct nla_policy *pt; +	struct libbpf_nla_policy *pt;  	unsigned int minlen = 0;  	int type = nla_type(nla); @@ -68,23 +53,24 @@ static int validate_nla(struct nlattr *nla, int maxtype,  	pt = &policy[type]; -	if (pt->type > NLA_TYPE_MAX) +	if (pt->type > LIBBPF_NLA_TYPE_MAX)  		return 0;  	if (pt->minlen)  		minlen = pt->minlen; -	else if (pt->type != NLA_UNSPEC) +	else if (pt->type != LIBBPF_NLA_UNSPEC)  		minlen = nla_attr_minlen[pt->type]; -	if (nla_len(nla) < minlen) +	if (libbpf_nla_len(nla) < minlen)  		return -1; -	if (pt->maxlen && nla_len(nla) > pt->maxlen) +	if (pt->maxlen && libbpf_nla_len(nla) > pt->maxlen)  		return -1; -	if (pt->type == NLA_STRING) { -		char *data = nla_data(nla); -		if (data[nla_len(nla) - 1] != '\0') +	if (pt->type == LIBBPF_NLA_STRING) { +		char *data = libbpf_nla_data(nla); + +		if (data[libbpf_nla_len(nla) - 1] != '\0')  			return -1;  	} @@ -114,15 +100,15 @@ static inline int nlmsg_len(const struct nlmsghdr *nlh)   * @see nla_validate   * @return 0 on success or a negative error code.   */ -static int nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head, int len, -		     struct nla_policy *policy) +int libbpf_nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head, +		     int len, struct libbpf_nla_policy *policy)  {  	struct nlattr *nla;  	int rem, err;  	memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1)); -	nla_for_each_attr(nla, head, len, rem) { +	libbpf_nla_for_each_attr(nla, head, len, rem) {  		int type = nla_type(nla);  		if (type > maxtype) @@ -146,12 +132,33 @@ errout:  	return err;  } +/** + * Create attribute index based on nested attribute + * @arg tb              Index array to be filled (maxtype+1 elements). + * @arg maxtype         Maximum attribute type expected and accepted. + * @arg nla             Nested Attribute. + * @arg policy          Attribute validation policy. + * + * Feeds the stream of attributes nested into the specified attribute + * to libbpf_nla_parse(). + * + * @see libbpf_nla_parse + * @return 0 on success or a negative error code. + */ +int libbpf_nla_parse_nested(struct nlattr *tb[], int maxtype, +			    struct nlattr *nla, +			    struct libbpf_nla_policy *policy) +{ +	return libbpf_nla_parse(tb, maxtype, libbpf_nla_data(nla), +				libbpf_nla_len(nla), policy); +} +  /* dump netlink extended ack error message */ -int nla_dump_errormsg(struct nlmsghdr *nlh) +int libbpf_nla_dump_errormsg(struct nlmsghdr *nlh)  { -	struct nla_policy extack_policy[NLMSGERR_ATTR_MAX + 1] = { -		[NLMSGERR_ATTR_MSG]	= { .type = NLA_STRING }, -		[NLMSGERR_ATTR_OFFS]	= { .type = NLA_U32 }, +	struct libbpf_nla_policy extack_policy[NLMSGERR_ATTR_MAX + 1] = { +		[NLMSGERR_ATTR_MSG]	= { .type = LIBBPF_NLA_STRING }, +		[NLMSGERR_ATTR_OFFS]	= { .type = LIBBPF_NLA_U32 },  	};  	struct nlattr *tb[NLMSGERR_ATTR_MAX + 1], *attr;  	struct nlmsgerr *err; @@ -172,14 +179,15 @@ int nla_dump_errormsg(struct nlmsghdr *nlh)  	attr = (struct nlattr *) ((void *) err + hlen);  	alen = nlh->nlmsg_len - hlen; -	if (nla_parse(tb, NLMSGERR_ATTR_MAX, attr, alen, extack_policy) != 0) { +	if (libbpf_nla_parse(tb, NLMSGERR_ATTR_MAX, attr, alen, +			     extack_policy) != 0) {  		fprintf(stderr,  			"Failed to parse extended error attributes\n");  		return 0;  	}  	if (tb[NLMSGERR_ATTR_MSG]) -		errmsg = (char *) nla_data(tb[NLMSGERR_ATTR_MSG]); +		errmsg = (char *) libbpf_nla_data(tb[NLMSGERR_ATTR_MSG]);  	fprintf(stderr, "Kernel error message: %s\n", errmsg); diff --git a/tools/lib/bpf/nlattr.h b/tools/lib/bpf/nlattr.h index 931a71f68f93..6cc3ac91690f 100644 --- a/tools/lib/bpf/nlattr.h +++ b/tools/lib/bpf/nlattr.h @@ -1,18 +1,13 @@ -/* SPDX-License-Identifier: LGPL-2.1 */ +/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */  /*   * NETLINK      Netlink attributes   * - *	This library is free software; you can redistribute it and/or - *	modify it under the terms of the GNU Lesser General Public - *	License as published by the Free Software Foundation version 2.1 - *	of the License. - *   * Copyright (c) 2003-2013 Thomas Graf <tgraf@suug.ch>   */ -#ifndef __NLATTR_H -#define __NLATTR_H +#ifndef __LIBBPF_NLATTR_H +#define __LIBBPF_NLATTR_H  #include <stdint.h>  #include <linux/netlink.h> @@ -23,19 +18,19 @@   * Standard attribute types to specify validation policy   */  enum { -	NLA_UNSPEC,	/**< Unspecified type, binary data chunk */ -	NLA_U8,		/**< 8 bit integer */ -	NLA_U16,	/**< 16 bit integer */ -	NLA_U32,	/**< 32 bit integer */ -	NLA_U64,	/**< 64 bit integer */ -	NLA_STRING,	/**< NUL terminated character string */ -	NLA_FLAG,	/**< Flag */ -	NLA_MSECS,	/**< Micro seconds (64bit) */ -	NLA_NESTED,	/**< Nested attributes */ -	__NLA_TYPE_MAX, +	LIBBPF_NLA_UNSPEC,	/**< Unspecified type, binary data chunk */ +	LIBBPF_NLA_U8,		/**< 8 bit integer */ +	LIBBPF_NLA_U16,		/**< 16 bit integer */ +	LIBBPF_NLA_U32,		/**< 32 bit integer */ +	LIBBPF_NLA_U64,		/**< 64 bit integer */ +	LIBBPF_NLA_STRING,	/**< NUL terminated character string */ +	LIBBPF_NLA_FLAG,	/**< Flag */ +	LIBBPF_NLA_MSECS,	/**< Micro seconds (64bit) */ +	LIBBPF_NLA_NESTED,	/**< Nested attributes */ +	__LIBBPF_NLA_TYPE_MAX,  }; -#define NLA_TYPE_MAX (__NLA_TYPE_MAX - 1) +#define LIBBPF_NLA_TYPE_MAX (__LIBBPF_NLA_TYPE_MAX - 1)  /**   * @ingroup attr @@ -43,8 +38,8 @@ enum {   *   * See section @core_doc{core_attr_parse,Attribute Parsing} for more details.   */ -struct nla_policy { -	/** Type of attribute or NLA_UNSPEC */ +struct libbpf_nla_policy { +	/** Type of attribute or LIBBPF_NLA_UNSPEC */  	uint16_t	type;  	/** Minimal length of payload required */ @@ -62,11 +57,50 @@ struct nla_policy {   * @arg len	length of attribute stream   * @arg rem	initialized to len, holds bytes currently remaining in stream   */ -#define nla_for_each_attr(pos, head, len, rem) \ +#define libbpf_nla_for_each_attr(pos, head, len, rem) \  	for (pos = head, rem = len; \  	     nla_ok(pos, rem); \  	     pos = nla_next(pos, &(rem))) -int nla_dump_errormsg(struct nlmsghdr *nlh); +/** + * libbpf_nla_data - head of payload + * @nla: netlink attribute + */ +static inline void *libbpf_nla_data(const struct nlattr *nla) +{ +	return (char *) nla + NLA_HDRLEN; +} + +static inline uint8_t libbpf_nla_getattr_u8(const struct nlattr *nla) +{ +	return *(uint8_t *)libbpf_nla_data(nla); +} + +static inline uint32_t libbpf_nla_getattr_u32(const struct nlattr *nla) +{ +	return *(uint32_t *)libbpf_nla_data(nla); +} + +static inline const char *libbpf_nla_getattr_str(const struct nlattr *nla) +{ +	return (const char *)libbpf_nla_data(nla); +} + +/** + * libbpf_nla_len - length of payload + * @nla: netlink attribute + */ +static inline int libbpf_nla_len(const struct nlattr *nla) +{ +	return nla->nla_len - NLA_HDRLEN; +} + +int libbpf_nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head, +		     int len, struct libbpf_nla_policy *policy); +int libbpf_nla_parse_nested(struct nlattr *tb[], int maxtype, +			    struct nlattr *nla, +			    struct libbpf_nla_policy *policy); + +int libbpf_nla_dump_errormsg(struct nlmsghdr *nlh); -#endif /* __NLATTR_H */ +#endif /* __LIBBPF_NLATTR_H */ diff --git a/tools/lib/bpf/str_error.c b/tools/lib/bpf/str_error.c new file mode 100644 index 000000000000..00e48ac5b806 --- /dev/null +++ b/tools/lib/bpf/str_error.c @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) +#undef _GNU_SOURCE +#include <string.h> +#include <stdio.h> +#include "str_error.h" + +/* + * Wrapper to allow for building in non-GNU systems such as Alpine Linux's musl + * libc, while checking strerror_r() return to avoid having to check this in + * all places calling it. + */ +char *libbpf_strerror_r(int err, char *dst, int len) +{ +	int ret = strerror_r(err, dst, len); +	if (ret) +		snprintf(dst, len, "ERROR: strerror_r(%d)=%d", err, ret); +	return dst; +} diff --git a/tools/lib/bpf/str_error.h b/tools/lib/bpf/str_error.h new file mode 100644 index 000000000000..a139334d57b6 --- /dev/null +++ b/tools/lib/bpf/str_error.h @@ -0,0 +1,6 @@ +/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ +#ifndef __LIBBPF_STR_ERROR_H +#define __LIBBPF_STR_ERROR_H + +char *libbpf_strerror_r(int err, char *dst, int len); +#endif /* __LIBBPF_STR_ERROR_H */  | 
