authorgravatar for mattnite@protonmail.comMatthew Knight <mattnite@protonmail.com> 2020-08-17 19:17:04-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-08-17 22:17:04-04:00
logd605af511a9af5d987a9e2276c2ed9a1b4e951c7
treecb7205544dc3256e68b6baf960b728b31d322eeb
parente26dda5308d5c853d195b65558454db4058ff218
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

added bpf() syscall and some supporting structs (#6061)

* added bpf syscall and some supporting structs * moved bpf to bits and added flags

2 files changed, 607 insertions(+), 0 deletions(-)

lib/std/os/bits/linux.zig+1
...@@ -19,6 +19,7 @@ pub usingnamespace switch (builtin.arch) {...@@ -19,6 +19,7 @@ pub usingnamespace switch (builtin.arch) {
19};19};
2020
21pub usingnamespace @import("linux/netlink.zig");21pub usingnamespace @import("linux/netlink.zig");
22pub const bpf = @import("linux/bpf.zig");
2223
23const is_mips = builtin.arch.isMIPS();24const is_mips = builtin.arch.isMIPS();
2425
lib/std/os/bits/linux/bpf.zig created+606
...@@ -0,0 +1,606 @@
1usingnamespace std.os;
2const std = @import("../../../std.zig");
3
4// instruction classes
5/// jmp mode in word width
6pub const JMP32 = 0x06;
7/// alu mode in double word width
8pub const ALU64 = 0x07;
9
10// ld/ldx fields
11/// double word (64-bit)
12pub const DW = 0x18;
13/// exclusive add
14pub const XADD = 0xc0;
15
16// alu/jmp fields
17/// mov reg to reg
18pub const MOV = 0xb0;
19/// sign extending arithmetic shift right */
20pub const ARSH = 0xc0;
21
22// change endianness of a register
23/// flags for endianness conversion:
24pub const END = 0xd0;
25/// convert to little-endian */
26pub const TO_LE = 0x00;
27/// convert to big-endian
28pub const TO_BE = 0x08;
29pub const FROM_LE = TO_LE;
30pub const FROM_BE = TO_BE;
31
32// jmp encodings
33/// jump != *
34pub const JNE = 0x50;
35/// LT is unsigned, '<'
36pub const JLT = 0xa0;
37/// LE is unsigned, '<=' *
38pub const JLE = 0xb0;
39/// SGT is signed '>', GT in x86
40pub const JSGT = 0x60;
41/// SGE is signed '>=', GE in x86
42pub const JSGE = 0x70;
43/// SLT is signed, '<'
44pub const JSLT = 0xc0;
45/// SLE is signed, '<='
46pub const JSLE = 0xd0;
47/// function call
48pub const CALL = 0x80;
49/// function return
50pub const EXIT = 0x90;
51
52/// Flag for prog_attach command. If a sub-cgroup installs some bpf program, the
53/// program in this cgroup yields to sub-cgroup program.
54pub const F_ALLOW_OVERRIDE = 0x1;
55/// Flag for prog_attach command. If a sub-cgroup installs some bpf program,
56/// that cgroup program gets run in addition to the program in this cgroup.
57pub const F_ALLOW_MULTI = 0x2;
58/// Flag for prog_attach command.
59pub const F_REPLACE = 0x4;
60
61/// If BPF_F_STRICT_ALIGNMENT is used in BPF_PROG_LOAD command, the verifier
62/// will perform strict alignment checking as if the kernel has been built with
63/// CONFIG_EFFICIENT_UNALIGNED_ACCESS not set, and NET_IP_ALIGN defined to 2.
64pub const F_STRICT_ALIGNMENT = 0x1;
65
66/// If BPF_F_ANY_ALIGNMENT is used in BPF_PROF_LOAD command, the verifier will
67/// allow any alignment whatsoever. On platforms with strict alignment
68/// requirements for loads ands stores (such as sparc and mips) the verifier
69/// validates that all loads and stores provably follow this requirement. This
70/// flag turns that checking and enforcement off.
71///
72/// It is mostly used for testing when we want to validate the context and
73/// memory access aspects of the verifier, but because of an unaligned access
74/// the alignment check would trigger before the one we are interested in.
75pub const F_ANY_ALIGNMENT = 0x2;
76
77/// BPF_F_TEST_RND_HI32 is used in BPF_PROG_LOAD command for testing purpose.
78/// Verifier does sub-register def/use analysis and identifies instructions
79/// whose def only matters for low 32-bit, high 32-bit is never referenced later
80/// through implicit zero extension. Therefore verifier notifies JIT back-ends
81/// that it is safe to ignore clearing high 32-bit for these instructions. This
82/// saves some back-ends a lot of code-gen. However such optimization is not
83/// necessary on some arches, for example x86_64, arm64 etc, whose JIT back-ends
84/// hence hasn't used verifier's analysis result. But, we really want to have a
85/// way to be able to verify the correctness of the described optimization on
86/// x86_64 on which testsuites are frequently exercised.
87///
88/// So, this flag is introduced. Once it is set, verifier will randomize high
89/// 32-bit for those instructions who has been identified as safe to ignore
90/// them. Then, if verifier is not doing correct analysis, such randomization
91/// will regress tests to expose bugs.
92pub const F_TEST_RND_HI32 = 0x4;
93
94/// When BPF ldimm64's insn[0].src_reg != 0 then this can have two extensions:
95/// insn[0].src_reg: BPF_PSEUDO_MAP_FD BPF_PSEUDO_MAP_VALUE
96/// insn[0].imm: map fd map fd
97/// insn[1].imm: 0 offset into value
98/// insn[0].off: 0 0
99/// insn[1].off: 0 0
100/// ldimm64 rewrite: address of map address of map[0]+offset
101/// verifier type: CONST_PTR_TO_MAP PTR_TO_MAP_VALUE
102pub const PSEUDO_MAP_FD = 1;
103pub const PSEUDO_MAP_VALUE = 2;
104
105/// when bpf_call->src_reg == BPF_PSEUDO_CALL, bpf_call->imm == pc-relative
106/// offset to another bpf function
107pub const PSEUDO_CALL = 1;
108
109/// flag for BPF_MAP_UPDATE_ELEM command. create new element or update existing
110pub const ANY = 0;
111/// flag for BPF_MAP_UPDATE_ELEM command. create new element if it didn't exist
112pub const NOEXIST = 1;
113/// flag for BPF_MAP_UPDATE_ELEM command. update existing element
114pub const EXIST = 2;
115/// flag for BPF_MAP_UPDATE_ELEM command. spin_lock-ed map_lookup/map_update
116pub const F_LOCK = 4;
117
118/// flag for BPF_MAP_CREATE command */
119pub const BPF_F_NO_PREALLOC = 0x1;
120/// flag for BPF_MAP_CREATE command. Instead of having one common LRU list in
121/// the BPF_MAP_TYPE_LRU_[PERCPU_]HASH map, use a percpu LRU list which can
122/// scale and perform better. Note, the LRU nodes (including free nodes) cannot
123/// be moved across different LRU lists.
124pub const BPF_F_NO_COMMON_LRU = 0x2;
125/// flag for BPF_MAP_CREATE command. Specify numa node during map creation
126pub const BPF_F_NUMA_NODE = 0x4;
127/// flag for BPF_MAP_CREATE command. Flags for BPF object read access from
128/// syscall side
129pub const BPF_F_RDONLY = 0x8;
130/// flag for BPF_MAP_CREATE command. Flags for BPF object write access from
131/// syscall side
132pub const BPF_F_WRONLY = 0x10;
133/// flag for BPF_MAP_CREATE command. Flag for stack_map, store build_id+offset
134/// instead of pointer
135pub const BPF_F_STACK_BUILD_ID = 0x20;
136/// flag for BPF_MAP_CREATE command. Zero-initialize hash function seed. This
137/// should only be used for testing.
138pub const BPF_F_ZERO_SEED = 0x40;
139/// flag for BPF_MAP_CREATE command Flags for accessing BPF object from program
140/// side.
141pub const BPF_F_RDONLY_PROG = 0x80;
142/// flag for BPF_MAP_CREATE command. Flags for accessing BPF object from program
143/// side.
144pub const BPF_F_WRONLY_PROG = 0x100;
145/// flag for BPF_MAP_CREATE command. Clone map from listener for newly accepted
146/// socket
147pub const BPF_F_CLONE = 0x200;
148/// flag for BPF_MAP_CREATE command. Enable memory-mapping BPF map
149pub const BPF_F_MMAPABLE = 0x400;
150
151/// a single BPF instruction
152pub const Insn = packed struct {
153 code: u8,
154 dst: u4,
155 src: u4,
156 off: i16,
157 imm: i32,
158
159 /// r0 - r9 are general purpose 64-bit registers, r10 points to the stack
160 /// frame
161 pub const Reg = enum(u4) {
162 r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10
163 };
164
165 const alu = 0x04;
166 const jmp = 0x05;
167 const mov = 0xb0;
168 const k = 0;
169 const exit_code = 0x90;
170
171 // TODO: implement more factory functions for the other instructions
172 /// load immediate value into a register
173 pub fn load_imm(dst: Reg, imm: i32) Insn {
174 return Insn{
175 .code = alu | mov | k,
176 .dst = @enumToInt(dst),
177 .src = 0,
178 .off = 0,
179 .imm = imm,
180 };
181 }
182
183 /// exit BPF program
184 pub fn exit() Insn {
185 return Insn{
186 .code = jmp | exit_code,
187 .dst = 0,
188 .src = 0,
189 .off = 0,
190 .imm = 0,
191 };
192 }
193};
194
195pub const Cmd = extern enum(usize) {
196 map_create,
197 map_lookup_elem,
198 map_update_elem,
199 map_delete_elem,
200 map_get_next_key,
201 prog_load,
202 obj_pin,
203 obj_get,
204 prog_attach,
205 prog_detach,
206 prog_test_run,
207 prog_get_next_id,
208 map_get_next_id,
209 prog_get_fd_by_id,
210 map_get_fd_by_id,
211 obj_get_info_by_fd,
212 prog_query,
213 raw_tracepoint_open,
214 btf_load,
215 btf_get_fd_by_id,
216 task_fd_query,
217 map_lookup_and_delete_elem,
218 map_freeze,
219 btf_get_next_id,
220 map_lookup_batch,
221 map_lookup_and_delete_batch,
222 map_update_batch,
223 map_delete_batch,
224 link_create,
225 link_update,
226 link_get_fd_by_id,
227 link_get_next_id,
228 enable_stats,
229 iter_create,
230 link_detach,
231 _,
232};
233
234pub const MapType = extern enum(u32) {
235 unspec,
236 hash,
237 array,
238 prog_array,
239 perf_event_array,
240 percpu_hash,
241 percpu_array,
242 stack_trace,
243 cgroup_array,
244 lru_hash,
245 lru_percpu_hash,
246 lpm_trie,
247 array_of_maps,
248 hash_of_maps,
249 devmap,
250 sockmap,
251 cpumap,
252 xskmap,
253 sockhash,
254 cgroup_storage,
255 reuseport_sockarray,
256 percpu_cgroup_storage,
257 queue,
258 stack,
259 sk_storage,
260 devmap_hash,
261 struct_ops,
262 ringbuf,
263 _,
264};
265
266pub const ProgType = extern enum(u32) {
267 unspec,
268 socket_filter,
269 kprobe,
270 sched_cls,
271 sched_act,
272 tracepoint,
273 xdp,
274 perf_event,
275 cgroup_skb,
276 cgroup_sock,
277 lwt_in,
278 lwt_out,
279 lwt_xmit,
280 sock_ops,
281 sk_skb,
282 cgroup_device,
283 sk_msg,
284 raw_tracepoint,
285 cgroup_sock_addr,
286 lwt_seg6local,
287 lirc_mode2,
288 sk_reuseport,
289 flow_dissector,
290 cgroup_sysctl,
291 raw_tracepoint_writable,
292 cgroup_sockopt,
293 tracing,
294 struct_ops,
295 ext,
296 lsm,
297 sk_lookup,
298};
299
300pub const AttachType = extern enum(u32) {
301 cgroup_inet_ingress,
302 cgroup_inet_egress,
303 cgroup_inet_sock_create,
304 cgroup_sock_ops,
305 sk_skb_stream_parser,
306 sk_skb_stream_verdict,
307 cgroup_device,
308 sk_msg_verdict,
309 cgroup_inet4_bind,
310 cgroup_inet6_bind,
311 cgroup_inet4_connect,
312 cgroup_inet6_connect,
313 cgroup_inet4_post_bind,
314 cgroup_inet6_post_bind,
315 cgroup_udp4_sendmsg,
316 cgroup_udp6_sendmsg,
317 lirc_mode2,
318 flow_dissector,
319 cgroup_sysctl,
320 cgroup_udp4_recvmsg,
321 cgroup_udp6_recvmsg,
322 cgroup_getsockopt,
323 cgroup_setsockopt,
324 trace_raw_tp,
325 trace_fentry,
326 trace_fexit,
327 modify_return,
328 lsm_mac,
329 trace_iter,
330 cgroup_inet4_getpeername,
331 cgroup_inet6_getpeername,
332 cgroup_inet4_getsockname,
333 cgroup_inet6_getsockname,
334 xdp_devmap,
335 cgroup_inet_sock_release,
336 xdp_cpumap,
337 sk_lookup,
338 xdp,
339 _,
340};
341
342const obj_name_len = 16;
343/// struct used by Cmd.map_create command
344pub const MapCreateAttr = extern struct {
345 /// one of MapType
346 map_type: u32,
347 /// size of key in bytes
348 key_size: u32,
349 /// size of value in bytes
350 value_size: u32,
351 /// max number of entries in a map
352 max_entries: u32,
353 /// .map_create related flags
354 map_flags: u32,
355 /// fd pointing to the inner map
356 inner_map_fd: fd_t,
357 /// numa node (effective only if MapCreateFlags.numa_node is set)
358 numa_node: u32,
359 map_name: [obj_name_len]u8,
360 /// ifindex of netdev to create on
361 map_ifindex: u32,
362 /// fd pointing to a BTF type data
363 btf_fd: fd_t,
364 /// BTF type_id of the key
365 btf_key_type_id: u32,
366 /// BTF type_id of the value
367 bpf_value_type_id: u32,
368 /// BTF type_id of a kernel struct stored as the map value
369 btf_vmlinux_value_type_id: u32,
370};
371
372/// struct used by Cmd.map_*_elem commands
373pub const MapElemAttr = extern struct {
374 map_fd: fd_t,
375 key: u64,
376 result: extern union {
377 value: u64,
378 next_key: u64,
379 },
380 flags: u64,
381};
382
383/// struct used by Cmd.map_*_batch commands
384pub const MapBatchAttr = extern struct {
385 /// start batch, NULL to start from beginning
386 in_batch: u64,
387 /// output: next start batch
388 out_batch: u64,
389 keys: u64,
390 values: u64,
391 /// input/output:
392 /// input: # of key/value elements
393 /// output: # of filled elements
394 count: u32,
395 map_fd: fd_t,
396 elem_flags: u64,
397 flags: u64,
398};
399
400/// struct used by Cmd.prog_load command
401pub const ProgLoadAttr = extern struct {
402 /// one of ProgType
403 prog_type: u32,
404 insn_cnt: u32,
405 insns: u64,
406 license: u64,
407 /// verbosity level of verifier
408 log_level: u32,
409 /// size of user buffer
410 log_size: u32,
411 /// user supplied buffer
412 log_buf: u64,
413 /// not used
414 kern_version: u32,
415 prog_flags: u32,
416 prog_name: [obj_name_len]u8,
417 /// ifindex of netdev to prep for. For some prog types expected attach
418 /// type must be known at load time to verify attach type specific parts
419 /// of prog (context accesses, allowed helpers, etc).
420 prog_ifindex: u32,
421 expected_attach_type: u32,
422 /// fd pointing to BTF type data
423 prog_btf_fd: fd_t,
424 /// userspace bpf_func_info size
425 func_info_rec_size: u32,
426 func_info: u64,
427 /// number of bpf_func_info records
428 func_info_cnt: u32,
429 /// userspace bpf_line_info size
430 line_info_rec_size: u32,
431 line_info: u64,
432 /// number of bpf_line_info records
433 line_info_cnt: u32,
434 /// in-kernel BTF type id to attach to
435 attact_btf_id: u32,
436 /// 0 to attach to vmlinux
437 attach_prog_id: u32,
438};
439
440/// struct used by Cmd.obj_* commands
441pub const ObjAttr = extern struct {
442 pathname: u64,
443 bpf_fd: fd_t,
444 file_flags: u32,
445};
446
447/// struct used by Cmd.prog_attach/detach commands
448pub const ProgAttachAttr = extern struct {
449 /// container object to attach to
450 target_fd: fd_t,
451 /// eBPF program to attach
452 attach_bpf_fd: fd_t,
453 attach_type: u32,
454 attach_flags: u32,
455 // TODO: BPF_F_REPLACE flags
456 /// previously attached eBPF program to replace if .replace is used
457 replace_bpf_fd: fd_t,
458};
459
460/// struct used by Cmd.prog_test_run command
461pub const TestAttr = extern struct {
462 prog_fd: fd_t,
463 retval: u32,
464 /// input: len of data_in
465 data_size_in: u32,
466 /// input/output: len of data_out. returns ENOSPC if data_out is too small.
467 data_size_out: u32,
468 data_in: u64,
469 data_out: u64,
470 repeat: u32,
471 duration: u32,
472 /// input: len of ctx_in
473 ctx_size_in: u32,
474 /// input/output: len of ctx_out. returns ENOSPC if ctx_out is too small.
475 ctx_size_out: u32,
476 ctx_in: u64,
477 ctx_out: u64,
478};
479
480/// struct used by Cmd.*_get_*_id commands
481pub const GetIdAttr = extern struct {
482 id: extern union {
483 start_id: u32,
484 prog_id: u32,
485 map_id: u32,
486 btf_id: u32,
487 link_id: u32,
488 },
489 next_id: u32,
490 open_flags: u32,
491};
492
493/// struct used by Cmd.obj_get_info_by_fd command
494pub const InfoAttr = extern struct {
495 bpf_fd: fd_t,
496 info_len: u32,
497 info: u64,
498};
499
500/// struct used by Cmd.prog_query command
501pub const QueryAttr = extern struct {
502 /// container object to query
503 target_fd: fd_t,
504 attach_type: u32,
505 query_flags: u32,
506 attach_flags: u32,
507 prog_ids: u64,
508 prog_cnt: u32,
509};
510
511/// struct used by Cmd.raw_tracepoint_open command
512pub const RawTracepointAttr = extern struct {
513 name: u64,
514 prog_fd: fd_t,
515};
516
517/// struct used by Cmd.btf_load command
518pub const BtfLoadAttr = extern struct {
519 btf: u64,
520 btf_log_buf: u64,
521 btf_size: u32,
522 btf_log_size: u32,
523 btf_log_level: u32,
524};
525
526pub const TaskFdQueryAttr = extern struct {
527 /// input: pid
528 pid: pid_t,
529 /// input: fd
530 fd: fd_t,
531 /// input: flags
532 flags: u32,
533 /// input/output: buf len
534 buf_len: u32,
535 /// input/output:
536 /// tp_name for tracepoint
537 /// symbol for kprobe
538 /// filename for uprobe
539 buf: u64,
540 /// output: prod_id
541 prog_id: u32,
542 /// output: BPF_FD_TYPE
543 fd_type: u32,
544 /// output: probe_offset
545 probe_offset: u64,
546 /// output: probe_addr
547 probe_addr: u64,
548};
549
550/// struct used by Cmd.link_create command
551pub const LinkCreateAttr = extern struct {
552 /// eBPF program to attach
553 prog_fd: fd_t,
554 /// object to attach to
555 target_fd: fd_t,
556 attach_type: u32,
557 /// extra flags
558 flags: u32,
559};
560
561/// struct used by Cmd.link_update command
562pub const LinkUpdateAttr = extern struct {
563 link_fd: fd_t,
564 /// new program to update link with
565 new_prog_fd: fd_t,
566 /// extra flags
567 flags: u32,
568 /// expected link's program fd, it is specified only if BPF_F_REPLACE is
569 /// set in flags
570 old_prog_fd: fd_t,
571};
572
573/// struct used by Cmd.enable_stats command
574pub const EnableStatsAttr = extern struct {
575 type: u32,
576};
577
578/// struct used by Cmd.iter_create command
579pub const IterCreateAttr = extern struct {
580 link_fd: fd_t,
581 flags: u32,
582};
583
584pub const Attr = extern union {
585 map_create: MapCreateAttr,
586 map_elem: MapElemAttr,
587 map_batch: MapBatchAttr,
588 prog_load: ProgLoadAttr,
589 obj: ObjAttr,
590 prog_attach: ProgAttachAttr,
591 test_run: TestRunAttr,
592 get_id: GetIdAttr,
593 info: InfoAttr,
594 query: QueryAttr,
595 raw_tracepoint: RawTracepointAttr,
596 btf_load: BtfLoadAttr,
597 task_fd_query: TaskFdQueryAttr,
598 link_create: LinkCreateAttr,
599 link_update: LinkUpdateAttr,
600 enable_stats: EnableStatsAttr,
601 iter_create: IterCreateAttr,
602};
603
604pub fn bpf(cmd: Cmd, attr: *Attr, size: u32) usize {
605 return syscall3(.bpf, @enumToInt(cmd), @ptrToInt(attr), size);
606}