xref: /linux/tools/lib/bpf/skel_internal.h (revision 6fe65f1b4db3fff305896e997c2804b7b42236ce)
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 
6*6fe65f1bSAlexei Starovoitov #ifdef __KERNEL__
7*6fe65f1bSAlexei Starovoitov #include <linux/fdtable.h>
8*6fe65f1bSAlexei Starovoitov #include <linux/mm.h>
9*6fe65f1bSAlexei Starovoitov #include <linux/mman.h>
10*6fe65f1bSAlexei Starovoitov #include <linux/slab.h>
11*6fe65f1bSAlexei Starovoitov #include <linux/bpf.h>
12*6fe65f1bSAlexei Starovoitov #else
1367234743SAlexei Starovoitov #include <unistd.h>
1467234743SAlexei Starovoitov #include <sys/syscall.h>
1567234743SAlexei Starovoitov #include <sys/mman.h>
16*6fe65f1bSAlexei Starovoitov #include <stdlib.h>
17*6fe65f1bSAlexei Starovoitov #include "bpf.h"
18*6fe65f1bSAlexei 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;
40*6fe65f1bSAlexei Starovoitov 	/* input for the loader prog */
41*6fe65f1bSAlexei Starovoitov 	__u32 max_entries;
42*6fe65f1bSAlexei Starovoitov 	__aligned_u64 initial_value;
4367234743SAlexei Starovoitov };
4467234743SAlexei Starovoitov struct bpf_prog_desc {
4567234743SAlexei Starovoitov 	int prog_fd;
4667234743SAlexei Starovoitov };
4767234743SAlexei Starovoitov 
48*6fe65f1bSAlexei Starovoitov enum {
49*6fe65f1bSAlexei Starovoitov 	BPF_SKEL_KERNEL = (1ULL << 0),
50*6fe65f1bSAlexei Starovoitov };
51*6fe65f1bSAlexei Starovoitov 
5267234743SAlexei Starovoitov struct bpf_loader_ctx {
53*6fe65f1bSAlexei Starovoitov 	__u32 sz;
54*6fe65f1bSAlexei 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 
69*6fe65f1bSAlexei Starovoitov long bpf_sys_bpf(__u32 cmd, void *attr, __u32 attr_size);
70*6fe65f1bSAlexei Starovoitov 
7167234743SAlexei Starovoitov static inline int skel_sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr,
7267234743SAlexei Starovoitov 			  unsigned int size)
7367234743SAlexei Starovoitov {
74*6fe65f1bSAlexei Starovoitov #ifdef __KERNEL__
75*6fe65f1bSAlexei Starovoitov 	return bpf_sys_bpf(cmd, attr, size);
76*6fe65f1bSAlexei Starovoitov #else
7767234743SAlexei Starovoitov 	return syscall(__NR_bpf, cmd, attr, size);
78*6fe65f1bSAlexei Starovoitov #endif
7967234743SAlexei Starovoitov }
8067234743SAlexei Starovoitov 
81*6fe65f1bSAlexei Starovoitov #ifdef __KERNEL__
82*6fe65f1bSAlexei Starovoitov static inline int close(int fd)
83*6fe65f1bSAlexei Starovoitov {
84*6fe65f1bSAlexei Starovoitov 	return close_fd(fd);
85*6fe65f1bSAlexei Starovoitov }
86*6fe65f1bSAlexei Starovoitov 
87*6fe65f1bSAlexei Starovoitov static inline void *skel_alloc(size_t size)
88*6fe65f1bSAlexei Starovoitov {
89*6fe65f1bSAlexei Starovoitov 	struct bpf_loader_ctx *ctx = kzalloc(size, GFP_KERNEL);
90*6fe65f1bSAlexei Starovoitov 
91*6fe65f1bSAlexei Starovoitov 	if (!ctx)
92*6fe65f1bSAlexei Starovoitov 		return NULL;
93*6fe65f1bSAlexei Starovoitov 	ctx->flags |= BPF_SKEL_KERNEL;
94*6fe65f1bSAlexei Starovoitov 	return ctx;
95*6fe65f1bSAlexei Starovoitov }
96*6fe65f1bSAlexei Starovoitov 
97*6fe65f1bSAlexei Starovoitov static inline void skel_free(const void *p)
98*6fe65f1bSAlexei Starovoitov {
99*6fe65f1bSAlexei Starovoitov 	kfree(p);
100*6fe65f1bSAlexei Starovoitov }
101*6fe65f1bSAlexei Starovoitov 
102*6fe65f1bSAlexei Starovoitov /* skel->bss/rodata maps are populated the following way:
103*6fe65f1bSAlexei Starovoitov  *
104*6fe65f1bSAlexei Starovoitov  * For kernel use:
105*6fe65f1bSAlexei Starovoitov  * skel_prep_map_data() allocates kernel memory that kernel module can directly access.
106*6fe65f1bSAlexei Starovoitov  * Generated lskel stores the pointer in skel->rodata and in skel->maps.rodata.initial_value.
107*6fe65f1bSAlexei Starovoitov  * The loader program will perform probe_read_kernel() from maps.rodata.initial_value.
108*6fe65f1bSAlexei Starovoitov  * skel_finalize_map_data() sets skel->rodata to point to actual value in a bpf map and
109*6fe65f1bSAlexei Starovoitov  * does maps.rodata.initial_value = ~0ULL to signal skel_free_map_data() that kvfree
110*6fe65f1bSAlexei Starovoitov  * is not nessary.
111*6fe65f1bSAlexei Starovoitov  *
112*6fe65f1bSAlexei Starovoitov  * For user space:
113*6fe65f1bSAlexei Starovoitov  * skel_prep_map_data() mmaps anon memory into skel->rodata that can be accessed directly.
114*6fe65f1bSAlexei Starovoitov  * Generated lskel stores the pointer in skel->rodata and in skel->maps.rodata.initial_value.
115*6fe65f1bSAlexei Starovoitov  * The loader program will perform copy_from_user() from maps.rodata.initial_value.
116*6fe65f1bSAlexei Starovoitov  * skel_finalize_map_data() remaps bpf array map value from the kernel memory into
117*6fe65f1bSAlexei Starovoitov  * skel->rodata address.
118*6fe65f1bSAlexei Starovoitov  *
119*6fe65f1bSAlexei Starovoitov  * The "bpftool gen skeleton -L" command generates lskel.h that is suitable for
120*6fe65f1bSAlexei Starovoitov  * both kernel and user space. The generated loader program does
121*6fe65f1bSAlexei Starovoitov  * either bpf_probe_read_kernel() or bpf_copy_from_user() from initial_value
122*6fe65f1bSAlexei Starovoitov  * depending on bpf_loader_ctx->flags.
123*6fe65f1bSAlexei Starovoitov  */
124*6fe65f1bSAlexei Starovoitov static inline void skel_free_map_data(void *p, __u64 addr, size_t sz)
125*6fe65f1bSAlexei Starovoitov {
126*6fe65f1bSAlexei Starovoitov 	if (addr != ~0ULL)
127*6fe65f1bSAlexei Starovoitov 		kvfree(p);
128*6fe65f1bSAlexei Starovoitov 	/* When addr == ~0ULL the 'p' points to
129*6fe65f1bSAlexei Starovoitov 	 * ((struct bpf_array *)map)->value. See skel_finalize_map_data.
130*6fe65f1bSAlexei Starovoitov 	 */
131*6fe65f1bSAlexei Starovoitov }
132*6fe65f1bSAlexei Starovoitov 
133*6fe65f1bSAlexei Starovoitov static inline void *skel_prep_map_data(const void *val, size_t mmap_sz, size_t val_sz)
134*6fe65f1bSAlexei Starovoitov {
135*6fe65f1bSAlexei Starovoitov 	void *addr;
136*6fe65f1bSAlexei Starovoitov 
137*6fe65f1bSAlexei Starovoitov 	addr = kvmalloc(val_sz, GFP_KERNEL);
138*6fe65f1bSAlexei Starovoitov 	if (!addr)
139*6fe65f1bSAlexei Starovoitov 		return NULL;
140*6fe65f1bSAlexei Starovoitov 	memcpy(addr, val, val_sz);
141*6fe65f1bSAlexei Starovoitov 	return addr;
142*6fe65f1bSAlexei Starovoitov }
143*6fe65f1bSAlexei Starovoitov 
144*6fe65f1bSAlexei Starovoitov static inline void *skel_finalize_map_data(__u64 *init_val, size_t mmap_sz, int flags, int fd)
145*6fe65f1bSAlexei Starovoitov {
146*6fe65f1bSAlexei Starovoitov 	struct bpf_map *map;
147*6fe65f1bSAlexei Starovoitov 	void *addr = NULL;
148*6fe65f1bSAlexei Starovoitov 
149*6fe65f1bSAlexei Starovoitov 	kvfree((void *) (long) *init_val);
150*6fe65f1bSAlexei Starovoitov 	*init_val = ~0ULL;
151*6fe65f1bSAlexei Starovoitov 
152*6fe65f1bSAlexei Starovoitov 	/* At this point bpf_load_and_run() finished without error and
153*6fe65f1bSAlexei Starovoitov 	 * 'fd' is a valid bpf map FD. All sanity checks below should succeed.
154*6fe65f1bSAlexei Starovoitov 	 */
155*6fe65f1bSAlexei Starovoitov 	map = bpf_map_get(fd);
156*6fe65f1bSAlexei Starovoitov 	if (IS_ERR(map))
157*6fe65f1bSAlexei Starovoitov 		return NULL;
158*6fe65f1bSAlexei Starovoitov 	if (map->map_type != BPF_MAP_TYPE_ARRAY)
159*6fe65f1bSAlexei Starovoitov 		goto out;
160*6fe65f1bSAlexei Starovoitov 	addr = ((struct bpf_array *)map)->value;
161*6fe65f1bSAlexei Starovoitov 	/* the addr stays valid, since FD is not closed */
162*6fe65f1bSAlexei Starovoitov out:
163*6fe65f1bSAlexei Starovoitov 	bpf_map_put(map);
164*6fe65f1bSAlexei Starovoitov 	return addr;
165*6fe65f1bSAlexei Starovoitov }
166*6fe65f1bSAlexei Starovoitov 
167*6fe65f1bSAlexei Starovoitov #else
168*6fe65f1bSAlexei Starovoitov 
169*6fe65f1bSAlexei Starovoitov static inline void *skel_alloc(size_t size)
170*6fe65f1bSAlexei Starovoitov {
171*6fe65f1bSAlexei Starovoitov 	return calloc(1, size);
172*6fe65f1bSAlexei Starovoitov }
173*6fe65f1bSAlexei Starovoitov 
174*6fe65f1bSAlexei Starovoitov static inline void skel_free(void *p)
175*6fe65f1bSAlexei Starovoitov {
176*6fe65f1bSAlexei Starovoitov 	free(p);
177*6fe65f1bSAlexei Starovoitov }
178*6fe65f1bSAlexei Starovoitov 
179*6fe65f1bSAlexei Starovoitov static inline void skel_free_map_data(void *p, __u64 addr, size_t sz)
180*6fe65f1bSAlexei Starovoitov {
181*6fe65f1bSAlexei Starovoitov 	munmap(p, sz);
182*6fe65f1bSAlexei Starovoitov }
183*6fe65f1bSAlexei Starovoitov 
184*6fe65f1bSAlexei Starovoitov static inline void *skel_prep_map_data(const void *val, size_t mmap_sz, size_t val_sz)
185*6fe65f1bSAlexei Starovoitov {
186*6fe65f1bSAlexei Starovoitov 	void *addr;
187*6fe65f1bSAlexei Starovoitov 
188*6fe65f1bSAlexei Starovoitov 	addr = mmap(NULL, mmap_sz, PROT_READ | PROT_WRITE,
189*6fe65f1bSAlexei Starovoitov 		    MAP_SHARED | MAP_ANONYMOUS, -1, 0);
190*6fe65f1bSAlexei Starovoitov 	if (addr == (void *) -1)
191*6fe65f1bSAlexei Starovoitov 		return NULL;
192*6fe65f1bSAlexei Starovoitov 	memcpy(addr, val, val_sz);
193*6fe65f1bSAlexei Starovoitov 	return addr;
194*6fe65f1bSAlexei Starovoitov }
195*6fe65f1bSAlexei Starovoitov 
196*6fe65f1bSAlexei Starovoitov static inline void *skel_finalize_map_data(__u64 *init_val, size_t mmap_sz, int flags, int fd)
197*6fe65f1bSAlexei Starovoitov {
198*6fe65f1bSAlexei Starovoitov 	void *addr;
199*6fe65f1bSAlexei Starovoitov 
200*6fe65f1bSAlexei Starovoitov 	addr = mmap((void *) (long) *init_val, mmap_sz, flags, MAP_SHARED | MAP_FIXED, fd, 0);
201*6fe65f1bSAlexei Starovoitov 	if (addr == (void *) -1)
202*6fe65f1bSAlexei Starovoitov 		return NULL;
203*6fe65f1bSAlexei Starovoitov 	return addr;
204*6fe65f1bSAlexei Starovoitov }
205*6fe65f1bSAlexei Starovoitov #endif
206*6fe65f1bSAlexei Starovoitov 
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 
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 
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 
254c69f94a3SAlexei Starovoitov static inline int skel_raw_tracepoint_open(const char *name, int prog_fd)
255c69f94a3SAlexei Starovoitov {
256c69f94a3SAlexei Starovoitov 	const size_t attr_sz = offsetofend(union bpf_attr, raw_tracepoint.prog_fd);
257c69f94a3SAlexei Starovoitov 	union bpf_attr attr;
258c69f94a3SAlexei Starovoitov 
259c69f94a3SAlexei Starovoitov 	memset(&attr, 0, attr_sz);
260c69f94a3SAlexei Starovoitov 	attr.raw_tracepoint.name = (long) name;
261c69f94a3SAlexei Starovoitov 	attr.raw_tracepoint.prog_fd = prog_fd;
262c69f94a3SAlexei Starovoitov 
263c69f94a3SAlexei Starovoitov 	return skel_sys_bpf(BPF_RAW_TRACEPOINT_OPEN, &attr, attr_sz);
264c69f94a3SAlexei Starovoitov }
265c69f94a3SAlexei Starovoitov 
266c69f94a3SAlexei Starovoitov static inline int skel_link_create(int prog_fd, int target_fd,
267c69f94a3SAlexei Starovoitov 				   enum bpf_attach_type attach_type)
268c69f94a3SAlexei Starovoitov {
269c69f94a3SAlexei Starovoitov 	const size_t attr_sz = offsetofend(union bpf_attr, link_create.iter_info_len);
270c69f94a3SAlexei Starovoitov 	union bpf_attr attr;
271c69f94a3SAlexei Starovoitov 
272c69f94a3SAlexei Starovoitov 	memset(&attr, 0, attr_sz);
273c69f94a3SAlexei Starovoitov 	attr.link_create.prog_fd = prog_fd;
274c69f94a3SAlexei Starovoitov 	attr.link_create.target_fd = target_fd;
275c69f94a3SAlexei Starovoitov 	attr.link_create.attach_type = attach_type;
276c69f94a3SAlexei Starovoitov 
277c69f94a3SAlexei Starovoitov 	return skel_sys_bpf(BPF_LINK_CREATE, &attr, attr_sz);
278c69f94a3SAlexei Starovoitov }
279c69f94a3SAlexei Starovoitov 
280*6fe65f1bSAlexei Starovoitov #ifdef __KERNEL__
281*6fe65f1bSAlexei Starovoitov #define set_err
282*6fe65f1bSAlexei Starovoitov #else
283*6fe65f1bSAlexei Starovoitov #define set_err err = -errno
284*6fe65f1bSAlexei Starovoitov #endif
285*6fe65f1bSAlexei Starovoitov 
28667234743SAlexei Starovoitov static inline int bpf_load_and_run(struct bpf_load_and_run_opts *opts)
28767234743SAlexei Starovoitov {
28867234743SAlexei Starovoitov 	int map_fd = -1, prog_fd = -1, key = 0, err;
28967234743SAlexei Starovoitov 	union bpf_attr attr;
29067234743SAlexei Starovoitov 
291*6fe65f1bSAlexei Starovoitov 	err = map_fd = skel_map_create(BPF_MAP_TYPE_ARRAY, "__loader.map", 4, opts->data_sz, 1);
29267234743SAlexei Starovoitov 	if (map_fd < 0) {
29367234743SAlexei Starovoitov 		opts->errstr = "failed to create loader map";
294*6fe65f1bSAlexei Starovoitov 		set_err;
29567234743SAlexei Starovoitov 		goto out;
29667234743SAlexei Starovoitov 	}
29767234743SAlexei Starovoitov 
298e981f41fSAlexei Starovoitov 	err = skel_map_update_elem(map_fd, &key, opts->data, 0);
29967234743SAlexei Starovoitov 	if (err < 0) {
30067234743SAlexei Starovoitov 		opts->errstr = "failed to update loader map";
301*6fe65f1bSAlexei Starovoitov 		set_err;
30267234743SAlexei Starovoitov 		goto out;
30367234743SAlexei Starovoitov 	}
30467234743SAlexei Starovoitov 
30567234743SAlexei Starovoitov 	memset(&attr, 0, sizeof(attr));
30667234743SAlexei Starovoitov 	attr.prog_type = BPF_PROG_TYPE_SYSCALL;
30767234743SAlexei Starovoitov 	attr.insns = (long) opts->insns;
30867234743SAlexei Starovoitov 	attr.insn_cnt = opts->insns_sz / sizeof(struct bpf_insn);
30967234743SAlexei Starovoitov 	attr.license = (long) "Dual BSD/GPL";
31067234743SAlexei Starovoitov 	memcpy(attr.prog_name, "__loader.prog", sizeof("__loader.prog"));
31167234743SAlexei Starovoitov 	attr.fd_array = (long) &map_fd;
31267234743SAlexei Starovoitov 	attr.log_level = opts->ctx->log_level;
31367234743SAlexei Starovoitov 	attr.log_size = opts->ctx->log_size;
31467234743SAlexei Starovoitov 	attr.log_buf = opts->ctx->log_buf;
31567234743SAlexei Starovoitov 	attr.prog_flags = BPF_F_SLEEPABLE;
316*6fe65f1bSAlexei Starovoitov 	err = prog_fd = skel_sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
31767234743SAlexei Starovoitov 	if (prog_fd < 0) {
31867234743SAlexei Starovoitov 		opts->errstr = "failed to load loader prog";
319*6fe65f1bSAlexei Starovoitov 		set_err;
32067234743SAlexei Starovoitov 		goto out;
32167234743SAlexei Starovoitov 	}
32267234743SAlexei Starovoitov 
32367234743SAlexei Starovoitov 	memset(&attr, 0, sizeof(attr));
32467234743SAlexei Starovoitov 	attr.test.prog_fd = prog_fd;
32567234743SAlexei Starovoitov 	attr.test.ctx_in = (long) opts->ctx;
32667234743SAlexei Starovoitov 	attr.test.ctx_size_in = opts->ctx->sz;
3275d67f349SAlexei Starovoitov 	err = skel_sys_bpf(BPF_PROG_RUN, &attr, sizeof(attr));
32867234743SAlexei Starovoitov 	if (err < 0 || (int)attr.test.retval < 0) {
32967234743SAlexei Starovoitov 		opts->errstr = "failed to execute loader prog";
330e68ac008SKumar Kartikeya Dwivedi 		if (err < 0) {
331*6fe65f1bSAlexei Starovoitov 			set_err;
332e68ac008SKumar Kartikeya Dwivedi 		} else {
33367234743SAlexei Starovoitov 			err = (int)attr.test.retval;
334*6fe65f1bSAlexei Starovoitov #ifndef __KERNEL__
335e68ac008SKumar Kartikeya Dwivedi 			errno = -err;
336*6fe65f1bSAlexei Starovoitov #endif
337e68ac008SKumar Kartikeya Dwivedi 		}
33867234743SAlexei Starovoitov 		goto out;
33967234743SAlexei Starovoitov 	}
34067234743SAlexei Starovoitov 	err = 0;
34167234743SAlexei Starovoitov out:
34267234743SAlexei Starovoitov 	if (map_fd >= 0)
34367234743SAlexei Starovoitov 		close(map_fd);
34467234743SAlexei Starovoitov 	if (prog_fd >= 0)
34567234743SAlexei Starovoitov 		close(prog_fd);
34667234743SAlexei Starovoitov 	return err;
34767234743SAlexei Starovoitov }
34867234743SAlexei Starovoitov 
34967234743SAlexei Starovoitov #endif
350