xref: /linux/tools/lib/bpf/skel_internal.h (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
167234743SAlexei Starovoitov /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
267234743SAlexei Starovoitov /* Copyright (c) 2021 Facebook */
367234743SAlexei Starovoitov #ifndef __SKEL_INTERNAL_H
467234743SAlexei Starovoitov #define __SKEL_INTERNAL_H
567234743SAlexei Starovoitov 
66fe65f1bSAlexei Starovoitov #ifdef __KERNEL__
76fe65f1bSAlexei Starovoitov #include <linux/fdtable.h>
86fe65f1bSAlexei Starovoitov #include <linux/mm.h>
96fe65f1bSAlexei Starovoitov #include <linux/mman.h>
106fe65f1bSAlexei Starovoitov #include <linux/slab.h>
116fe65f1bSAlexei Starovoitov #include <linux/bpf.h>
126fe65f1bSAlexei Starovoitov #else
1367234743SAlexei Starovoitov #include <unistd.h>
1467234743SAlexei Starovoitov #include <sys/syscall.h>
1567234743SAlexei Starovoitov #include <sys/mman.h>
166fe65f1bSAlexei Starovoitov #include <stdlib.h>
176fe65f1bSAlexei Starovoitov #include "bpf.h"
186fe65f1bSAlexei Starovoitov #endif
1967234743SAlexei Starovoitov 
20e32cb12fSTiezhu Yang #ifndef __NR_bpf
21e32cb12fSTiezhu Yang # if defined(__mips__) && defined(_ABIO32)
22e32cb12fSTiezhu Yang #  define __NR_bpf 4355
23e32cb12fSTiezhu Yang # elif defined(__mips__) && defined(_ABIN32)
24e32cb12fSTiezhu Yang #  define __NR_bpf 6319
25e32cb12fSTiezhu Yang # elif defined(__mips__) && defined(_ABI64)
26e32cb12fSTiezhu Yang #  define __NR_bpf 5315
27e32cb12fSTiezhu Yang # endif
28e32cb12fSTiezhu Yang #endif
29e32cb12fSTiezhu Yang 
3067234743SAlexei Starovoitov /* This file is a base header for auto-generated *.lskel.h files.
3167234743SAlexei Starovoitov  * Its contents will change and may become part of auto-generation in the future.
3267234743SAlexei Starovoitov  *
3367234743SAlexei Starovoitov  * The layout of bpf_[map|prog]_desc and bpf_loader_ctx is feature dependent
3467234743SAlexei Starovoitov  * and will change from one version of libbpf to another and features
3567234743SAlexei Starovoitov  * requested during loader program generation.
3667234743SAlexei Starovoitov  */
3767234743SAlexei Starovoitov struct bpf_map_desc {
3867234743SAlexei Starovoitov 	/* output of the loader prog */
3967234743SAlexei Starovoitov 	int map_fd;
406fe65f1bSAlexei Starovoitov 	/* input for the loader prog */
416fe65f1bSAlexei Starovoitov 	__u32 max_entries;
426fe65f1bSAlexei Starovoitov 	__aligned_u64 initial_value;
4367234743SAlexei Starovoitov };
4467234743SAlexei Starovoitov struct bpf_prog_desc {
4567234743SAlexei Starovoitov 	int prog_fd;
4667234743SAlexei Starovoitov };
4767234743SAlexei Starovoitov 
486fe65f1bSAlexei Starovoitov enum {
496fe65f1bSAlexei Starovoitov 	BPF_SKEL_KERNEL = (1ULL << 0),
506fe65f1bSAlexei Starovoitov };
516fe65f1bSAlexei Starovoitov 
5267234743SAlexei Starovoitov struct bpf_loader_ctx {
536fe65f1bSAlexei Starovoitov 	__u32 sz;
546fe65f1bSAlexei Starovoitov 	__u32 flags;
5567234743SAlexei Starovoitov 	__u32 log_level;
5667234743SAlexei Starovoitov 	__u32 log_size;
5767234743SAlexei Starovoitov 	__u64 log_buf;
5867234743SAlexei Starovoitov };
5967234743SAlexei Starovoitov 
6067234743SAlexei Starovoitov struct bpf_load_and_run_opts {
6167234743SAlexei Starovoitov 	struct bpf_loader_ctx *ctx;
6267234743SAlexei Starovoitov 	const void *data;
6367234743SAlexei Starovoitov 	const void *insns;
6467234743SAlexei Starovoitov 	__u32 data_sz;
6567234743SAlexei Starovoitov 	__u32 insns_sz;
6667234743SAlexei Starovoitov 	const char *errstr;
6767234743SAlexei Starovoitov };
6867234743SAlexei Starovoitov 
6986f44fceSAlexei Starovoitov long kern_sys_bpf(__u32 cmd, void *attr, __u32 attr_size);
706fe65f1bSAlexei Starovoitov 
skel_sys_bpf(enum bpf_cmd cmd,union bpf_attr * attr,unsigned int size)7167234743SAlexei Starovoitov static inline int skel_sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr,
7267234743SAlexei Starovoitov 			  unsigned int size)
7367234743SAlexei Starovoitov {
746fe65f1bSAlexei Starovoitov #ifdef __KERNEL__
7586f44fceSAlexei Starovoitov 	return kern_sys_bpf(cmd, attr, size);
766fe65f1bSAlexei Starovoitov #else
7767234743SAlexei Starovoitov 	return syscall(__NR_bpf, cmd, attr, size);
786fe65f1bSAlexei Starovoitov #endif
7967234743SAlexei Starovoitov }
8067234743SAlexei Starovoitov 
816fe65f1bSAlexei Starovoitov #ifdef __KERNEL__
close(int fd)826fe65f1bSAlexei Starovoitov static inline int close(int fd)
836fe65f1bSAlexei Starovoitov {
846fe65f1bSAlexei Starovoitov 	return close_fd(fd);
856fe65f1bSAlexei Starovoitov }
866fe65f1bSAlexei Starovoitov 
skel_alloc(size_t size)876fe65f1bSAlexei Starovoitov static inline void *skel_alloc(size_t size)
886fe65f1bSAlexei Starovoitov {
896fe65f1bSAlexei Starovoitov 	struct bpf_loader_ctx *ctx = kzalloc(size, GFP_KERNEL);
906fe65f1bSAlexei Starovoitov 
916fe65f1bSAlexei Starovoitov 	if (!ctx)
926fe65f1bSAlexei Starovoitov 		return NULL;
936fe65f1bSAlexei Starovoitov 	ctx->flags |= BPF_SKEL_KERNEL;
946fe65f1bSAlexei Starovoitov 	return ctx;
956fe65f1bSAlexei Starovoitov }
966fe65f1bSAlexei Starovoitov 
skel_free(const void * p)976fe65f1bSAlexei Starovoitov static inline void skel_free(const void *p)
986fe65f1bSAlexei Starovoitov {
996fe65f1bSAlexei Starovoitov 	kfree(p);
1006fe65f1bSAlexei Starovoitov }
1016fe65f1bSAlexei Starovoitov 
1026fe65f1bSAlexei Starovoitov /* skel->bss/rodata maps are populated the following way:
1036fe65f1bSAlexei Starovoitov  *
1046fe65f1bSAlexei Starovoitov  * For kernel use:
1056fe65f1bSAlexei Starovoitov  * skel_prep_map_data() allocates kernel memory that kernel module can directly access.
1066fe65f1bSAlexei Starovoitov  * Generated lskel stores the pointer in skel->rodata and in skel->maps.rodata.initial_value.
1076fe65f1bSAlexei Starovoitov  * The loader program will perform probe_read_kernel() from maps.rodata.initial_value.
1086fe65f1bSAlexei Starovoitov  * skel_finalize_map_data() sets skel->rodata to point to actual value in a bpf map and
1096fe65f1bSAlexei Starovoitov  * does maps.rodata.initial_value = ~0ULL to signal skel_free_map_data() that kvfree
1106fe65f1bSAlexei Starovoitov  * is not nessary.
1116fe65f1bSAlexei Starovoitov  *
1126fe65f1bSAlexei Starovoitov  * For user space:
1136fe65f1bSAlexei Starovoitov  * skel_prep_map_data() mmaps anon memory into skel->rodata that can be accessed directly.
1146fe65f1bSAlexei Starovoitov  * Generated lskel stores the pointer in skel->rodata and in skel->maps.rodata.initial_value.
1156fe65f1bSAlexei Starovoitov  * The loader program will perform copy_from_user() from maps.rodata.initial_value.
1166fe65f1bSAlexei Starovoitov  * skel_finalize_map_data() remaps bpf array map value from the kernel memory into
1176fe65f1bSAlexei Starovoitov  * skel->rodata address.
1186fe65f1bSAlexei Starovoitov  *
1196fe65f1bSAlexei Starovoitov  * The "bpftool gen skeleton -L" command generates lskel.h that is suitable for
1206fe65f1bSAlexei Starovoitov  * both kernel and user space. The generated loader program does
1216fe65f1bSAlexei Starovoitov  * either bpf_probe_read_kernel() or bpf_copy_from_user() from initial_value
1226fe65f1bSAlexei Starovoitov  * depending on bpf_loader_ctx->flags.
1236fe65f1bSAlexei Starovoitov  */
skel_free_map_data(void * p,__u64 addr,size_t sz)1246fe65f1bSAlexei Starovoitov static inline void skel_free_map_data(void *p, __u64 addr, size_t sz)
1256fe65f1bSAlexei Starovoitov {
1266fe65f1bSAlexei Starovoitov 	if (addr != ~0ULL)
1276fe65f1bSAlexei Starovoitov 		kvfree(p);
1286fe65f1bSAlexei Starovoitov 	/* When addr == ~0ULL the 'p' points to
1296fe65f1bSAlexei Starovoitov 	 * ((struct bpf_array *)map)->value. See skel_finalize_map_data.
1306fe65f1bSAlexei Starovoitov 	 */
1316fe65f1bSAlexei Starovoitov }
1326fe65f1bSAlexei Starovoitov 
skel_prep_map_data(const void * val,size_t mmap_sz,size_t val_sz)1336fe65f1bSAlexei Starovoitov static inline void *skel_prep_map_data(const void *val, size_t mmap_sz, size_t val_sz)
1346fe65f1bSAlexei Starovoitov {
1356fe65f1bSAlexei Starovoitov 	void *addr;
1366fe65f1bSAlexei Starovoitov 
1376fe65f1bSAlexei Starovoitov 	addr = kvmalloc(val_sz, GFP_KERNEL);
1386fe65f1bSAlexei Starovoitov 	if (!addr)
1396fe65f1bSAlexei Starovoitov 		return NULL;
1406fe65f1bSAlexei Starovoitov 	memcpy(addr, val, val_sz);
1416fe65f1bSAlexei Starovoitov 	return addr;
1426fe65f1bSAlexei Starovoitov }
1436fe65f1bSAlexei Starovoitov 
skel_finalize_map_data(__u64 * init_val,size_t mmap_sz,int flags,int fd)1446fe65f1bSAlexei Starovoitov static inline void *skel_finalize_map_data(__u64 *init_val, size_t mmap_sz, int flags, int fd)
1456fe65f1bSAlexei Starovoitov {
1466fe65f1bSAlexei Starovoitov 	struct bpf_map *map;
1476fe65f1bSAlexei Starovoitov 	void *addr = NULL;
1486fe65f1bSAlexei Starovoitov 
1496fe65f1bSAlexei Starovoitov 	kvfree((void *) (long) *init_val);
1506fe65f1bSAlexei Starovoitov 	*init_val = ~0ULL;
1516fe65f1bSAlexei Starovoitov 
1526fe65f1bSAlexei Starovoitov 	/* At this point bpf_load_and_run() finished without error and
1536fe65f1bSAlexei Starovoitov 	 * 'fd' is a valid bpf map FD. All sanity checks below should succeed.
1546fe65f1bSAlexei Starovoitov 	 */
1556fe65f1bSAlexei Starovoitov 	map = bpf_map_get(fd);
1566fe65f1bSAlexei Starovoitov 	if (IS_ERR(map))
1576fe65f1bSAlexei Starovoitov 		return NULL;
1586fe65f1bSAlexei Starovoitov 	if (map->map_type != BPF_MAP_TYPE_ARRAY)
1596fe65f1bSAlexei Starovoitov 		goto out;
1606fe65f1bSAlexei Starovoitov 	addr = ((struct bpf_array *)map)->value;
1616fe65f1bSAlexei Starovoitov 	/* the addr stays valid, since FD is not closed */
1626fe65f1bSAlexei Starovoitov out:
1636fe65f1bSAlexei Starovoitov 	bpf_map_put(map);
1646fe65f1bSAlexei Starovoitov 	return addr;
1656fe65f1bSAlexei Starovoitov }
1666fe65f1bSAlexei Starovoitov 
1676fe65f1bSAlexei Starovoitov #else
1686fe65f1bSAlexei Starovoitov 
skel_alloc(size_t size)1696fe65f1bSAlexei Starovoitov static inline void *skel_alloc(size_t size)
1706fe65f1bSAlexei Starovoitov {
1716fe65f1bSAlexei Starovoitov 	return calloc(1, size);
1726fe65f1bSAlexei Starovoitov }
1736fe65f1bSAlexei Starovoitov 
skel_free(void * p)1746fe65f1bSAlexei Starovoitov static inline void skel_free(void *p)
1756fe65f1bSAlexei Starovoitov {
1766fe65f1bSAlexei Starovoitov 	free(p);
1776fe65f1bSAlexei Starovoitov }
1786fe65f1bSAlexei Starovoitov 
skel_free_map_data(void * p,__u64 addr,size_t sz)1796fe65f1bSAlexei Starovoitov static inline void skel_free_map_data(void *p, __u64 addr, size_t sz)
1806fe65f1bSAlexei Starovoitov {
1816fe65f1bSAlexei Starovoitov 	munmap(p, sz);
1826fe65f1bSAlexei Starovoitov }
1836fe65f1bSAlexei Starovoitov 
skel_prep_map_data(const void * val,size_t mmap_sz,size_t val_sz)1846fe65f1bSAlexei Starovoitov static inline void *skel_prep_map_data(const void *val, size_t mmap_sz, size_t val_sz)
1856fe65f1bSAlexei Starovoitov {
1866fe65f1bSAlexei Starovoitov 	void *addr;
1876fe65f1bSAlexei Starovoitov 
1886fe65f1bSAlexei Starovoitov 	addr = mmap(NULL, mmap_sz, PROT_READ | PROT_WRITE,
1896fe65f1bSAlexei Starovoitov 		    MAP_SHARED | MAP_ANONYMOUS, -1, 0);
1906fe65f1bSAlexei Starovoitov 	if (addr == (void *) -1)
1916fe65f1bSAlexei Starovoitov 		return NULL;
1926fe65f1bSAlexei Starovoitov 	memcpy(addr, val, val_sz);
1936fe65f1bSAlexei Starovoitov 	return addr;
1946fe65f1bSAlexei Starovoitov }
1956fe65f1bSAlexei Starovoitov 
skel_finalize_map_data(__u64 * init_val,size_t mmap_sz,int flags,int fd)1966fe65f1bSAlexei Starovoitov static inline void *skel_finalize_map_data(__u64 *init_val, size_t mmap_sz, int flags, int fd)
1976fe65f1bSAlexei Starovoitov {
1986fe65f1bSAlexei Starovoitov 	void *addr;
1996fe65f1bSAlexei Starovoitov 
2006fe65f1bSAlexei Starovoitov 	addr = mmap((void *) (long) *init_val, mmap_sz, flags, MAP_SHARED | MAP_FIXED, fd, 0);
2016fe65f1bSAlexei Starovoitov 	if (addr == (void *) -1)
2026fe65f1bSAlexei Starovoitov 		return NULL;
2036fe65f1bSAlexei Starovoitov 	return addr;
2046fe65f1bSAlexei Starovoitov }
2056fe65f1bSAlexei Starovoitov #endif
2066fe65f1bSAlexei Starovoitov 
skel_closenz(int fd)20767234743SAlexei Starovoitov static inline int skel_closenz(int fd)
20867234743SAlexei Starovoitov {
20967234743SAlexei Starovoitov 	if (fd > 0)
21067234743SAlexei Starovoitov 		return close(fd);
21167234743SAlexei Starovoitov 	return -EINVAL;
21267234743SAlexei Starovoitov }
21367234743SAlexei Starovoitov 
214e981f41fSAlexei Starovoitov #ifndef offsetofend
215e981f41fSAlexei Starovoitov #define offsetofend(TYPE, MEMBER) \
216e981f41fSAlexei Starovoitov 	(offsetof(TYPE, MEMBER)	+ sizeof((((TYPE *)0)->MEMBER)))
217e981f41fSAlexei Starovoitov #endif
218e981f41fSAlexei Starovoitov 
skel_map_create(enum bpf_map_type map_type,const char * map_name,__u32 key_size,__u32 value_size,__u32 max_entries)219e981f41fSAlexei Starovoitov static inline int skel_map_create(enum bpf_map_type map_type,
220e981f41fSAlexei Starovoitov 				  const char *map_name,
221e981f41fSAlexei Starovoitov 				  __u32 key_size,
222e981f41fSAlexei Starovoitov 				  __u32 value_size,
223e981f41fSAlexei Starovoitov 				  __u32 max_entries)
224e981f41fSAlexei Starovoitov {
225e981f41fSAlexei Starovoitov 	const size_t attr_sz = offsetofend(union bpf_attr, map_extra);
226e981f41fSAlexei Starovoitov 	union bpf_attr attr;
227e981f41fSAlexei Starovoitov 
228e981f41fSAlexei Starovoitov 	memset(&attr, 0, attr_sz);
229e981f41fSAlexei Starovoitov 
230e981f41fSAlexei Starovoitov 	attr.map_type = map_type;
231e981f41fSAlexei Starovoitov 	strncpy(attr.map_name, map_name, sizeof(attr.map_name));
232e981f41fSAlexei Starovoitov 	attr.key_size = key_size;
233e981f41fSAlexei Starovoitov 	attr.value_size = value_size;
234e981f41fSAlexei Starovoitov 	attr.max_entries = max_entries;
235e981f41fSAlexei Starovoitov 
236e981f41fSAlexei Starovoitov 	return skel_sys_bpf(BPF_MAP_CREATE, &attr, attr_sz);
237e981f41fSAlexei Starovoitov }
238e981f41fSAlexei Starovoitov 
skel_map_update_elem(int fd,const void * key,const void * value,__u64 flags)239e981f41fSAlexei Starovoitov static inline int skel_map_update_elem(int fd, const void *key,
240e981f41fSAlexei Starovoitov 				       const void *value, __u64 flags)
241e981f41fSAlexei Starovoitov {
242e981f41fSAlexei Starovoitov 	const size_t attr_sz = offsetofend(union bpf_attr, flags);
243e981f41fSAlexei Starovoitov 	union bpf_attr attr;
244e981f41fSAlexei Starovoitov 
245e981f41fSAlexei Starovoitov 	memset(&attr, 0, attr_sz);
246e981f41fSAlexei Starovoitov 	attr.map_fd = fd;
247e981f41fSAlexei Starovoitov 	attr.key = (long) key;
248e981f41fSAlexei Starovoitov 	attr.value = (long) value;
249e981f41fSAlexei Starovoitov 	attr.flags = flags;
250e981f41fSAlexei Starovoitov 
251e981f41fSAlexei Starovoitov 	return skel_sys_bpf(BPF_MAP_UPDATE_ELEM, &attr, attr_sz);
252e981f41fSAlexei Starovoitov }
253e981f41fSAlexei Starovoitov 
skel_map_delete_elem(int fd,const void * key)254*343949e1SBenjamin Tissoires static inline int skel_map_delete_elem(int fd, const void *key)
255*343949e1SBenjamin Tissoires {
256*343949e1SBenjamin Tissoires 	const size_t attr_sz = offsetofend(union bpf_attr, flags);
257*343949e1SBenjamin Tissoires 	union bpf_attr attr;
258*343949e1SBenjamin Tissoires 
259*343949e1SBenjamin Tissoires 	memset(&attr, 0, attr_sz);
260*343949e1SBenjamin Tissoires 	attr.map_fd = fd;
261*343949e1SBenjamin Tissoires 	attr.key = (long)key;
262*343949e1SBenjamin Tissoires 
263*343949e1SBenjamin Tissoires 	return skel_sys_bpf(BPF_MAP_DELETE_ELEM, &attr, attr_sz);
264*343949e1SBenjamin Tissoires }
265*343949e1SBenjamin Tissoires 
skel_map_get_fd_by_id(__u32 id)266*343949e1SBenjamin Tissoires static inline int skel_map_get_fd_by_id(__u32 id)
267*343949e1SBenjamin Tissoires {
268*343949e1SBenjamin Tissoires 	const size_t attr_sz = offsetofend(union bpf_attr, flags);
269*343949e1SBenjamin Tissoires 	union bpf_attr attr;
270*343949e1SBenjamin Tissoires 
271*343949e1SBenjamin Tissoires 	memset(&attr, 0, attr_sz);
272*343949e1SBenjamin Tissoires 	attr.map_id = id;
273*343949e1SBenjamin Tissoires 
274*343949e1SBenjamin Tissoires 	return skel_sys_bpf(BPF_MAP_GET_FD_BY_ID, &attr, attr_sz);
275*343949e1SBenjamin Tissoires }
276*343949e1SBenjamin Tissoires 
skel_raw_tracepoint_open(const char * name,int prog_fd)277c69f94a3SAlexei Starovoitov static inline int skel_raw_tracepoint_open(const char *name, int prog_fd)
278c69f94a3SAlexei Starovoitov {
279c69f94a3SAlexei Starovoitov 	const size_t attr_sz = offsetofend(union bpf_attr, raw_tracepoint.prog_fd);
280c69f94a3SAlexei Starovoitov 	union bpf_attr attr;
281c69f94a3SAlexei Starovoitov 
282c69f94a3SAlexei Starovoitov 	memset(&attr, 0, attr_sz);
283c69f94a3SAlexei Starovoitov 	attr.raw_tracepoint.name = (long) name;
284c69f94a3SAlexei Starovoitov 	attr.raw_tracepoint.prog_fd = prog_fd;
285c69f94a3SAlexei Starovoitov 
286c69f94a3SAlexei Starovoitov 	return skel_sys_bpf(BPF_RAW_TRACEPOINT_OPEN, &attr, attr_sz);
287c69f94a3SAlexei Starovoitov }
288c69f94a3SAlexei Starovoitov 
skel_link_create(int prog_fd,int target_fd,enum bpf_attach_type attach_type)289c69f94a3SAlexei Starovoitov static inline int skel_link_create(int prog_fd, int target_fd,
290c69f94a3SAlexei Starovoitov 				   enum bpf_attach_type attach_type)
291c69f94a3SAlexei Starovoitov {
292c69f94a3SAlexei Starovoitov 	const size_t attr_sz = offsetofend(union bpf_attr, link_create.iter_info_len);
293c69f94a3SAlexei Starovoitov 	union bpf_attr attr;
294c69f94a3SAlexei Starovoitov 
295c69f94a3SAlexei Starovoitov 	memset(&attr, 0, attr_sz);
296c69f94a3SAlexei Starovoitov 	attr.link_create.prog_fd = prog_fd;
297c69f94a3SAlexei Starovoitov 	attr.link_create.target_fd = target_fd;
298c69f94a3SAlexei Starovoitov 	attr.link_create.attach_type = attach_type;
299c69f94a3SAlexei Starovoitov 
300c69f94a3SAlexei Starovoitov 	return skel_sys_bpf(BPF_LINK_CREATE, &attr, attr_sz);
301c69f94a3SAlexei Starovoitov }
302c69f94a3SAlexei Starovoitov 
3036fe65f1bSAlexei Starovoitov #ifdef __KERNEL__
3046fe65f1bSAlexei Starovoitov #define set_err
3056fe65f1bSAlexei Starovoitov #else
3066fe65f1bSAlexei Starovoitov #define set_err err = -errno
3076fe65f1bSAlexei Starovoitov #endif
3086fe65f1bSAlexei Starovoitov 
bpf_load_and_run(struct bpf_load_and_run_opts * opts)30967234743SAlexei Starovoitov static inline int bpf_load_and_run(struct bpf_load_and_run_opts *opts)
31067234743SAlexei Starovoitov {
311813847a3SAndrii Nakryiko 	const size_t prog_load_attr_sz = offsetofend(union bpf_attr, fd_array);
312813847a3SAndrii Nakryiko 	const size_t test_run_attr_sz = offsetofend(union bpf_attr, test);
31367234743SAlexei Starovoitov 	int map_fd = -1, prog_fd = -1, key = 0, err;
31467234743SAlexei Starovoitov 	union bpf_attr attr;
31567234743SAlexei Starovoitov 
3166fe65f1bSAlexei Starovoitov 	err = map_fd = skel_map_create(BPF_MAP_TYPE_ARRAY, "__loader.map", 4, opts->data_sz, 1);
31767234743SAlexei Starovoitov 	if (map_fd < 0) {
31867234743SAlexei Starovoitov 		opts->errstr = "failed to create loader map";
3196fe65f1bSAlexei Starovoitov 		set_err;
32067234743SAlexei Starovoitov 		goto out;
32167234743SAlexei Starovoitov 	}
32267234743SAlexei Starovoitov 
323e981f41fSAlexei Starovoitov 	err = skel_map_update_elem(map_fd, &key, opts->data, 0);
32467234743SAlexei Starovoitov 	if (err < 0) {
32567234743SAlexei Starovoitov 		opts->errstr = "failed to update loader map";
3266fe65f1bSAlexei Starovoitov 		set_err;
32767234743SAlexei Starovoitov 		goto out;
32867234743SAlexei Starovoitov 	}
32967234743SAlexei Starovoitov 
330813847a3SAndrii Nakryiko 	memset(&attr, 0, prog_load_attr_sz);
33167234743SAlexei Starovoitov 	attr.prog_type = BPF_PROG_TYPE_SYSCALL;
33267234743SAlexei Starovoitov 	attr.insns = (long) opts->insns;
33367234743SAlexei Starovoitov 	attr.insn_cnt = opts->insns_sz / sizeof(struct bpf_insn);
33467234743SAlexei Starovoitov 	attr.license = (long) "Dual BSD/GPL";
33567234743SAlexei Starovoitov 	memcpy(attr.prog_name, "__loader.prog", sizeof("__loader.prog"));
33667234743SAlexei Starovoitov 	attr.fd_array = (long) &map_fd;
33767234743SAlexei Starovoitov 	attr.log_level = opts->ctx->log_level;
33867234743SAlexei Starovoitov 	attr.log_size = opts->ctx->log_size;
33967234743SAlexei Starovoitov 	attr.log_buf = opts->ctx->log_buf;
34067234743SAlexei Starovoitov 	attr.prog_flags = BPF_F_SLEEPABLE;
341813847a3SAndrii Nakryiko 	err = prog_fd = skel_sys_bpf(BPF_PROG_LOAD, &attr, prog_load_attr_sz);
34267234743SAlexei Starovoitov 	if (prog_fd < 0) {
34367234743SAlexei Starovoitov 		opts->errstr = "failed to load loader prog";
3446fe65f1bSAlexei Starovoitov 		set_err;
34567234743SAlexei Starovoitov 		goto out;
34667234743SAlexei Starovoitov 	}
34767234743SAlexei Starovoitov 
348813847a3SAndrii Nakryiko 	memset(&attr, 0, test_run_attr_sz);
34967234743SAlexei Starovoitov 	attr.test.prog_fd = prog_fd;
35067234743SAlexei Starovoitov 	attr.test.ctx_in = (long) opts->ctx;
35167234743SAlexei Starovoitov 	attr.test.ctx_size_in = opts->ctx->sz;
352813847a3SAndrii Nakryiko 	err = skel_sys_bpf(BPF_PROG_RUN, &attr, test_run_attr_sz);
35367234743SAlexei Starovoitov 	if (err < 0 || (int)attr.test.retval < 0) {
35467234743SAlexei Starovoitov 		opts->errstr = "failed to execute loader prog";
355e68ac008SKumar Kartikeya Dwivedi 		if (err < 0) {
3566fe65f1bSAlexei Starovoitov 			set_err;
357e68ac008SKumar Kartikeya Dwivedi 		} else {
35867234743SAlexei Starovoitov 			err = (int)attr.test.retval;
3596fe65f1bSAlexei Starovoitov #ifndef __KERNEL__
360e68ac008SKumar Kartikeya Dwivedi 			errno = -err;
3616fe65f1bSAlexei Starovoitov #endif
362e68ac008SKumar Kartikeya Dwivedi 		}
36367234743SAlexei Starovoitov 		goto out;
36467234743SAlexei Starovoitov 	}
36567234743SAlexei Starovoitov 	err = 0;
36667234743SAlexei Starovoitov out:
36767234743SAlexei Starovoitov 	if (map_fd >= 0)
36867234743SAlexei Starovoitov 		close(map_fd);
36967234743SAlexei Starovoitov 	if (prog_fd >= 0)
37067234743SAlexei Starovoitov 		close(prog_fd);
37167234743SAlexei Starovoitov 	return err;
37267234743SAlexei Starovoitov }
37367234743SAlexei Starovoitov 
37467234743SAlexei Starovoitov #endif
375