1 // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
2 /* Copyright (c) 2019 Netronome Systems, Inc. */
10 #include <sys/utsname.h>
12 #include <linux/btf.h>
13 #include <linux/filter.h>
14 #include <linux/kernel.h>
18 #include "libbpf_internal.h"
20 static bool grep(const char *buffer
, const char *pattern
)
22 return !!strstr(buffer
, pattern
);
25 static int get_vendor_id(int ifindex
)
27 char ifname
[IF_NAMESIZE
], path
[64], buf
[8];
31 if (!if_indextoname(ifindex
, ifname
))
34 snprintf(path
, sizeof(path
), "/sys/class/net/%s/device/vendor", ifname
);
36 fd
= open(path
, O_RDONLY
);
40 len
= read(fd
, buf
, sizeof(buf
));
44 if (len
>= (ssize_t
)sizeof(buf
))
48 return strtol(buf
, NULL
, 0);
51 static int get_kernel_version(void)
53 int version
, subversion
, patchlevel
;
56 /* Return 0 on failure, and attempt to probe with empty kversion */
60 if (sscanf(utsn
.release
, "%d.%d.%d",
61 &version
, &subversion
, &patchlevel
) != 3)
64 return (version
<< 16) + (subversion
<< 8) + patchlevel
;
68 probe_load(enum bpf_prog_type prog_type
, const struct bpf_insn
*insns
,
69 size_t insns_cnt
, char *buf
, size_t buf_len
, __u32 ifindex
)
71 struct bpf_load_program_attr xattr
= {};
75 case BPF_PROG_TYPE_CGROUP_SOCK_ADDR
:
76 xattr
.expected_attach_type
= BPF_CGROUP_INET4_CONNECT
;
78 case BPF_PROG_TYPE_SK_LOOKUP
:
79 xattr
.expected_attach_type
= BPF_SK_LOOKUP
;
81 case BPF_PROG_TYPE_KPROBE
:
82 xattr
.kern_version
= get_kernel_version();
84 case BPF_PROG_TYPE_UNSPEC
:
85 case BPF_PROG_TYPE_SOCKET_FILTER
:
86 case BPF_PROG_TYPE_SCHED_CLS
:
87 case BPF_PROG_TYPE_SCHED_ACT
:
88 case BPF_PROG_TYPE_TRACEPOINT
:
89 case BPF_PROG_TYPE_XDP
:
90 case BPF_PROG_TYPE_PERF_EVENT
:
91 case BPF_PROG_TYPE_CGROUP_SKB
:
92 case BPF_PROG_TYPE_CGROUP_SOCK
:
93 case BPF_PROG_TYPE_LWT_IN
:
94 case BPF_PROG_TYPE_LWT_OUT
:
95 case BPF_PROG_TYPE_LWT_XMIT
:
96 case BPF_PROG_TYPE_SOCK_OPS
:
97 case BPF_PROG_TYPE_SK_SKB
:
98 case BPF_PROG_TYPE_CGROUP_DEVICE
:
99 case BPF_PROG_TYPE_SK_MSG
:
100 case BPF_PROG_TYPE_RAW_TRACEPOINT
:
101 case BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE
:
102 case BPF_PROG_TYPE_LWT_SEG6LOCAL
:
103 case BPF_PROG_TYPE_LIRC_MODE2
:
104 case BPF_PROG_TYPE_SK_REUSEPORT
:
105 case BPF_PROG_TYPE_FLOW_DISSECTOR
:
106 case BPF_PROG_TYPE_CGROUP_SYSCTL
:
107 case BPF_PROG_TYPE_CGROUP_SOCKOPT
:
108 case BPF_PROG_TYPE_TRACING
:
109 case BPF_PROG_TYPE_STRUCT_OPS
:
110 case BPF_PROG_TYPE_EXT
:
111 case BPF_PROG_TYPE_LSM
:
116 xattr
.prog_type
= prog_type
;
118 xattr
.insns_cnt
= insns_cnt
;
119 xattr
.license
= "GPL";
120 xattr
.prog_ifindex
= ifindex
;
122 fd
= bpf_load_program_xattr(&xattr
, buf
, buf_len
);
127 bool bpf_probe_prog_type(enum bpf_prog_type prog_type
, __u32 ifindex
)
129 struct bpf_insn insns
[2] = {
130 BPF_MOV64_IMM(BPF_REG_0
, 0),
134 if (ifindex
&& prog_type
== BPF_PROG_TYPE_SCHED_CLS
)
135 /* nfp returns -EINVAL on exit(0) with TC offload */
139 probe_load(prog_type
, insns
, ARRAY_SIZE(insns
), NULL
, 0, ifindex
);
141 return errno
!= EINVAL
&& errno
!= EOPNOTSUPP
;
144 int libbpf__load_raw_btf(const char *raw_types
, size_t types_len
,
145 const char *str_sec
, size_t str_len
)
147 struct btf_header hdr
= {
149 .version
= BTF_VERSION
,
150 .hdr_len
= sizeof(struct btf_header
),
151 .type_len
= types_len
,
152 .str_off
= types_len
,
158 btf_len
= hdr
.hdr_len
+ hdr
.type_len
+ hdr
.str_len
;
159 raw_btf
= malloc(btf_len
);
163 memcpy(raw_btf
, &hdr
, sizeof(hdr
));
164 memcpy(raw_btf
+ hdr
.hdr_len
, raw_types
, hdr
.type_len
);
165 memcpy(raw_btf
+ hdr
.hdr_len
+ hdr
.type_len
, str_sec
, hdr
.str_len
);
167 btf_fd
= bpf_load_btf(raw_btf
, btf_len
, NULL
, 0, false);
173 static int load_local_storage_btf(void)
175 const char strs
[] = "\0bpf_spin_lock\0val\0cnt\0l";
176 /* struct bpf_spin_lock {
181 * struct bpf_spin_lock l;
186 BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED
, 0, 32, 4), /* [1] */
187 /* struct bpf_spin_lock */ /* [2] */
188 BTF_TYPE_ENC(1, BTF_INFO_ENC(BTF_KIND_STRUCT
, 0, 1), 4),
189 BTF_MEMBER_ENC(15, 1, 0), /* int val; */
190 /* struct val */ /* [3] */
191 BTF_TYPE_ENC(15, BTF_INFO_ENC(BTF_KIND_STRUCT
, 0, 2), 8),
192 BTF_MEMBER_ENC(19, 1, 0), /* int cnt; */
193 BTF_MEMBER_ENC(23, 2, 32),/* struct bpf_spin_lock l; */
196 return libbpf__load_raw_btf((char *)types
, sizeof(types
),
200 bool bpf_probe_map_type(enum bpf_map_type map_type
, __u32 ifindex
)
202 int key_size
, value_size
, max_entries
, map_flags
;
203 __u32 btf_key_type_id
= 0, btf_value_type_id
= 0;
204 struct bpf_create_map_attr attr
= {};
205 int fd
= -1, btf_fd
= -1, fd_inner
;
207 key_size
= sizeof(__u32
);
208 value_size
= sizeof(__u32
);
213 case BPF_MAP_TYPE_STACK_TRACE
:
214 value_size
= sizeof(__u64
);
216 case BPF_MAP_TYPE_LPM_TRIE
:
217 key_size
= sizeof(__u64
);
218 value_size
= sizeof(__u64
);
219 map_flags
= BPF_F_NO_PREALLOC
;
221 case BPF_MAP_TYPE_CGROUP_STORAGE
:
222 case BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE
:
223 key_size
= sizeof(struct bpf_cgroup_storage_key
);
224 value_size
= sizeof(__u64
);
227 case BPF_MAP_TYPE_QUEUE
:
228 case BPF_MAP_TYPE_STACK
:
231 case BPF_MAP_TYPE_SK_STORAGE
:
232 case BPF_MAP_TYPE_INODE_STORAGE
:
233 case BPF_MAP_TYPE_TASK_STORAGE
:
235 btf_value_type_id
= 3;
238 map_flags
= BPF_F_NO_PREALLOC
;
239 btf_fd
= load_local_storage_btf();
243 case BPF_MAP_TYPE_RINGBUF
:
248 case BPF_MAP_TYPE_UNSPEC
:
249 case BPF_MAP_TYPE_HASH
:
250 case BPF_MAP_TYPE_ARRAY
:
251 case BPF_MAP_TYPE_PROG_ARRAY
:
252 case BPF_MAP_TYPE_PERF_EVENT_ARRAY
:
253 case BPF_MAP_TYPE_PERCPU_HASH
:
254 case BPF_MAP_TYPE_PERCPU_ARRAY
:
255 case BPF_MAP_TYPE_CGROUP_ARRAY
:
256 case BPF_MAP_TYPE_LRU_HASH
:
257 case BPF_MAP_TYPE_LRU_PERCPU_HASH
:
258 case BPF_MAP_TYPE_ARRAY_OF_MAPS
:
259 case BPF_MAP_TYPE_HASH_OF_MAPS
:
260 case BPF_MAP_TYPE_DEVMAP
:
261 case BPF_MAP_TYPE_DEVMAP_HASH
:
262 case BPF_MAP_TYPE_SOCKMAP
:
263 case BPF_MAP_TYPE_CPUMAP
:
264 case BPF_MAP_TYPE_XSKMAP
:
265 case BPF_MAP_TYPE_SOCKHASH
:
266 case BPF_MAP_TYPE_REUSEPORT_SOCKARRAY
:
267 case BPF_MAP_TYPE_STRUCT_OPS
:
272 if (map_type
== BPF_MAP_TYPE_ARRAY_OF_MAPS
||
273 map_type
== BPF_MAP_TYPE_HASH_OF_MAPS
) {
274 /* TODO: probe for device, once libbpf has a function to create
275 * map-in-map for offload
280 fd_inner
= bpf_create_map(BPF_MAP_TYPE_HASH
,
281 sizeof(__u32
), sizeof(__u32
), 1, 0);
284 fd
= bpf_create_map_in_map(map_type
, NULL
, sizeof(__u32
),
288 /* Note: No other restriction on map type probes for offload */
289 attr
.map_type
= map_type
;
290 attr
.key_size
= key_size
;
291 attr
.value_size
= value_size
;
292 attr
.max_entries
= max_entries
;
293 attr
.map_flags
= map_flags
;
294 attr
.map_ifindex
= ifindex
;
296 attr
.btf_fd
= btf_fd
;
297 attr
.btf_key_type_id
= btf_key_type_id
;
298 attr
.btf_value_type_id
= btf_value_type_id
;
301 fd
= bpf_create_map_xattr(&attr
);
311 bool bpf_probe_helper(enum bpf_func_id id
, enum bpf_prog_type prog_type
,
314 struct bpf_insn insns
[2] = {
321 probe_load(prog_type
, insns
, ARRAY_SIZE(insns
), buf
, sizeof(buf
),
323 res
= !grep(buf
, "invalid func ") && !grep(buf
, "unknown func ");
326 switch (get_vendor_id(ifindex
)) {
327 case 0x19ee: /* Netronome specific */
328 res
= res
&& !grep(buf
, "not supported by FW") &&
329 !grep(buf
, "unsupported function id");
340 * Probe for availability of kernel commit (5.3):
342 * c04c0d2b968a ("bpf: increase complexity limit and maximum program size")
344 bool bpf_probe_large_insn_limit(__u32 ifindex
)
346 struct bpf_insn insns
[BPF_MAXINSNS
+ 1];
349 for (i
= 0; i
< BPF_MAXINSNS
; i
++)
350 insns
[i
] = BPF_MOV64_IMM(BPF_REG_0
, 1);
351 insns
[BPF_MAXINSNS
] = BPF_EXIT_INSN();
354 probe_load(BPF_PROG_TYPE_SCHED_CLS
, insns
, ARRAY_SIZE(insns
), NULL
, 0,
357 return errno
!= E2BIG
&& errno
!= EINVAL
;