| author | |
| committer | |
| log | 0fa3cfdb4aa04bf92c5d9344cd4d265ccb40e0dc |
| tree | 0fe31975cdd13b41adf998308258604225a86a13 |
| parent | 9605e5363b22874550687f5f96dc6cc8bf462115 |
| signature |
* moved bpf syscall, added some bpf instructions and tests
* had to move bpf out of bits so that a freestanding target could import it
* removed line
* fixed imports4 files changed, 974 insertions(+), 976 deletions(-)
lib/std/os/bits/linux.zig-1| ... | @@ -24,7 +24,6 @@ pub usingnamespace switch (builtin.arch) { | ... | @@ -24,7 +24,6 @@ pub usingnamespace switch (builtin.arch) { |
| 24 | }; | 24 | }; |
| 25 | 25 | ||
| 26 | pub usingnamespace @import("linux/netlink.zig"); | 26 | pub usingnamespace @import("linux/netlink.zig"); |
| 27 | pub const BPF = @import("linux/bpf.zig"); | ||
| 28 | 27 | ||
| 29 | const is_mips = builtin.arch.isMIPS(); | 28 | const is_mips = builtin.arch.isMIPS(); |
| 30 | 29 |
lib/std/os/bits/linux/bpf.zig deleted-975| ... | @@ -1,975 +0,0 @@ | ||
| 1 | // SPDX-License-Identifier: MIT | ||
| 2 | // Copyright (c) 2015-2020 Zig Contributors | ||
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | ||
| 4 | // The MIT license requires this copyright notice to be included in all copies | ||
| 5 | // and substantial portions of the software. | ||
| 6 | usingnamespace std.os; | ||
| 7 | const std = @import("../../../std.zig"); | ||
| 8 | const expectEqual = std.testing.expectEqual; | ||
| 9 | const fd_t = std.os.fd_t; | ||
| 10 | const pid_t = std.os.pid_t; | ||
| 11 | |||
| 12 | // instruction classes | ||
| 13 | pub const LD = 0x00; | ||
| 14 | pub const LDX = 0x01; | ||
| 15 | pub const ST = 0x02; | ||
| 16 | pub const STX = 0x03; | ||
| 17 | pub const ALU = 0x04; | ||
| 18 | pub const JMP = 0x05; | ||
| 19 | pub const RET = 0x06; | ||
| 20 | pub const MISC = 0x07; | ||
| 21 | |||
| 22 | /// 32-bit | ||
| 23 | pub const W = 0x00; | ||
| 24 | /// 16-bit | ||
| 25 | pub const H = 0x08; | ||
| 26 | /// 8-bit | ||
| 27 | pub const B = 0x10; | ||
| 28 | /// 64-bit | ||
| 29 | pub const DW = 0x18; | ||
| 30 | |||
| 31 | pub const IMM = 0x00; | ||
| 32 | pub const ABS = 0x20; | ||
| 33 | pub const IND = 0x40; | ||
| 34 | pub const MEM = 0x60; | ||
| 35 | pub const LEN = 0x80; | ||
| 36 | pub const MSH = 0xa0; | ||
| 37 | |||
| 38 | // alu fields | ||
| 39 | pub const ADD = 0x00; | ||
| 40 | pub const SUB = 0x10; | ||
| 41 | pub const MUL = 0x20; | ||
| 42 | pub const DIV = 0x30; | ||
| 43 | pub const OR = 0x40; | ||
| 44 | pub const AND = 0x50; | ||
| 45 | pub const LSH = 0x60; | ||
| 46 | pub const RSH = 0x70; | ||
| 47 | pub const NEG = 0x80; | ||
| 48 | pub const MOD = 0x90; | ||
| 49 | pub const XOR = 0xa0; | ||
| 50 | |||
| 51 | // jmp fields | ||
| 52 | pub const JA = 0x00; | ||
| 53 | pub const JEQ = 0x10; | ||
| 54 | pub const JGT = 0x20; | ||
| 55 | pub const JGE = 0x30; | ||
| 56 | pub const JSET = 0x40; | ||
| 57 | |||
| 58 | //#define BPF_SRC(code) ((code) & 0x08) | ||
| 59 | pub const K = 0x00; | ||
| 60 | pub const X = 0x08; | ||
| 61 | |||
| 62 | pub const MAXINSNS = 4096; | ||
| 63 | |||
| 64 | // instruction classes | ||
| 65 | /// jmp mode in word width | ||
| 66 | pub const JMP32 = 0x06; | ||
| 67 | /// alu mode in double word width | ||
| 68 | pub const ALU64 = 0x07; | ||
| 69 | |||
| 70 | // ld/ldx fields | ||
| 71 | /// exclusive add | ||
| 72 | pub const XADD = 0xc0; | ||
| 73 | |||
| 74 | // alu/jmp fields | ||
| 75 | /// mov reg to reg | ||
| 76 | pub const MOV = 0xb0; | ||
| 77 | /// sign extending arithmetic shift right */ | ||
| 78 | pub const ARSH = 0xc0; | ||
| 79 | |||
| 80 | // change endianness of a register | ||
| 81 | /// flags for endianness conversion: | ||
| 82 | pub const END = 0xd0; | ||
| 83 | /// convert to little-endian */ | ||
| 84 | pub const TO_LE = 0x00; | ||
| 85 | /// convert to big-endian | ||
| 86 | pub const TO_BE = 0x08; | ||
| 87 | pub const FROM_LE = TO_LE; | ||
| 88 | pub const FROM_BE = TO_BE; | ||
| 89 | |||
| 90 | // jmp encodings | ||
| 91 | /// jump != * | ||
| 92 | pub const JNE = 0x50; | ||
| 93 | /// LT is unsigned, '<' | ||
| 94 | pub const JLT = 0xa0; | ||
| 95 | /// LE is unsigned, '<=' * | ||
| 96 | pub const JLE = 0xb0; | ||
| 97 | /// SGT is signed '>', GT in x86 | ||
| 98 | pub const JSGT = 0x60; | ||
| 99 | /// SGE is signed '>=', GE in x86 | ||
| 100 | pub const JSGE = 0x70; | ||
| 101 | /// SLT is signed, '<' | ||
| 102 | pub const JSLT = 0xc0; | ||
| 103 | /// SLE is signed, '<=' | ||
| 104 | pub const JSLE = 0xd0; | ||
| 105 | /// function call | ||
| 106 | pub const CALL = 0x80; | ||
| 107 | /// function return | ||
| 108 | pub const EXIT = 0x90; | ||
| 109 | |||
| 110 | /// Flag for prog_attach command. If a sub-cgroup installs some bpf program, the | ||
| 111 | /// program in this cgroup yields to sub-cgroup program. | ||
| 112 | pub const F_ALLOW_OVERRIDE = 0x1; | ||
| 113 | /// Flag for prog_attach command. If a sub-cgroup installs some bpf program, | ||
| 114 | /// that cgroup program gets run in addition to the program in this cgroup. | ||
| 115 | pub const F_ALLOW_MULTI = 0x2; | ||
| 116 | /// Flag for prog_attach command. | ||
| 117 | pub const F_REPLACE = 0x4; | ||
| 118 | |||
| 119 | /// If BPF_F_STRICT_ALIGNMENT is used in BPF_PROG_LOAD command, the verifier | ||
| 120 | /// will perform strict alignment checking as if the kernel has been built with | ||
| 121 | /// CONFIG_EFFICIENT_UNALIGNED_ACCESS not set, and NET_IP_ALIGN defined to 2. | ||
| 122 | pub const F_STRICT_ALIGNMENT = 0x1; | ||
| 123 | |||
| 124 | /// If BPF_F_ANY_ALIGNMENT is used in BPF_PROF_LOAD command, the verifier will | ||
| 125 | /// allow any alignment whatsoever. On platforms with strict alignment | ||
| 126 | /// requirements for loads ands stores (such as sparc and mips) the verifier | ||
| 127 | /// validates that all loads and stores provably follow this requirement. This | ||
| 128 | /// flag turns that checking and enforcement off. | ||
| 129 | /// | ||
| 130 | /// It is mostly used for testing when we want to validate the context and | ||
| 131 | /// memory access aspects of the verifier, but because of an unaligned access | ||
| 132 | /// the alignment check would trigger before the one we are interested in. | ||
| 133 | pub const F_ANY_ALIGNMENT = 0x2; | ||
| 134 | |||
| 135 | /// BPF_F_TEST_RND_HI32 is used in BPF_PROG_LOAD command for testing purpose. | ||
| 136 | /// Verifier does sub-register def/use analysis and identifies instructions | ||
| 137 | /// whose def only matters for low 32-bit, high 32-bit is never referenced later | ||
| 138 | /// through implicit zero extension. Therefore verifier notifies JIT back-ends | ||
| 139 | /// that it is safe to ignore clearing high 32-bit for these instructions. This | ||
| 140 | /// saves some back-ends a lot of code-gen. However such optimization is not | ||
| 141 | /// necessary on some arches, for example x86_64, arm64 etc, whose JIT back-ends | ||
| 142 | /// hence hasn't used verifier's analysis result. But, we really want to have a | ||
| 143 | /// way to be able to verify the correctness of the described optimization on | ||
| 144 | /// x86_64 on which testsuites are frequently exercised. | ||
| 145 | /// | ||
| 146 | /// So, this flag is introduced. Once it is set, verifier will randomize high | ||
| 147 | /// 32-bit for those instructions who has been identified as safe to ignore | ||
| 148 | /// them. Then, if verifier is not doing correct analysis, such randomization | ||
| 149 | /// will regress tests to expose bugs. | ||
| 150 | pub const F_TEST_RND_HI32 = 0x4; | ||
| 151 | |||
| 152 | /// When BPF ldimm64's insn[0].src_reg != 0 then this can have two extensions: | ||
| 153 | /// insn[0].src_reg: BPF_PSEUDO_MAP_FD BPF_PSEUDO_MAP_VALUE | ||
| 154 | /// insn[0].imm: map fd map fd | ||
| 155 | /// insn[1].imm: 0 offset into value | ||
| 156 | /// insn[0].off: 0 0 | ||
| 157 | /// insn[1].off: 0 0 | ||
| 158 | /// ldimm64 rewrite: address of map address of map[0]+offset | ||
| 159 | /// verifier type: CONST_PTR_TO_MAP PTR_TO_MAP_VALUE | ||
| 160 | pub const PSEUDO_MAP_FD = 1; | ||
| 161 | pub const PSEUDO_MAP_VALUE = 2; | ||
| 162 | |||
| 163 | /// when bpf_call->src_reg == BPF_PSEUDO_CALL, bpf_call->imm == pc-relative | ||
| 164 | /// offset to another bpf function | ||
| 165 | pub const PSEUDO_CALL = 1; | ||
| 166 | |||
| 167 | /// flag for BPF_MAP_UPDATE_ELEM command. create new element or update existing | ||
| 168 | pub const ANY = 0; | ||
| 169 | /// flag for BPF_MAP_UPDATE_ELEM command. create new element if it didn't exist | ||
| 170 | pub const NOEXIST = 1; | ||
| 171 | /// flag for BPF_MAP_UPDATE_ELEM command. update existing element | ||
| 172 | pub const EXIST = 2; | ||
| 173 | /// flag for BPF_MAP_UPDATE_ELEM command. spin_lock-ed map_lookup/map_update | ||
| 174 | pub const F_LOCK = 4; | ||
| 175 | |||
| 176 | /// flag for BPF_MAP_CREATE command */ | ||
| 177 | pub const BPF_F_NO_PREALLOC = 0x1; | ||
| 178 | /// flag for BPF_MAP_CREATE command. Instead of having one common LRU list in | ||
| 179 | /// the BPF_MAP_TYPE_LRU_[PERCPU_]HASH map, use a percpu LRU list which can | ||
| 180 | /// scale and perform better. Note, the LRU nodes (including free nodes) cannot | ||
| 181 | /// be moved across different LRU lists. | ||
| 182 | pub const BPF_F_NO_COMMON_LRU = 0x2; | ||
| 183 | /// flag for BPF_MAP_CREATE command. Specify numa node during map creation | ||
| 184 | pub const BPF_F_NUMA_NODE = 0x4; | ||
| 185 | /// flag for BPF_MAP_CREATE command. Flags for BPF object read access from | ||
| 186 | /// syscall side | ||
| 187 | pub const BPF_F_RDONLY = 0x8; | ||
| 188 | /// flag for BPF_MAP_CREATE command. Flags for BPF object write access from | ||
| 189 | /// syscall side | ||
| 190 | pub const BPF_F_WRONLY = 0x10; | ||
| 191 | /// flag for BPF_MAP_CREATE command. Flag for stack_map, store build_id+offset | ||
| 192 | /// instead of pointer | ||
| 193 | pub const BPF_F_STACK_BUILD_ID = 0x20; | ||
| 194 | /// flag for BPF_MAP_CREATE command. Zero-initialize hash function seed. This | ||
| 195 | /// should only be used for testing. | ||
| 196 | pub const BPF_F_ZERO_SEED = 0x40; | ||
| 197 | /// flag for BPF_MAP_CREATE command Flags for accessing BPF object from program | ||
| 198 | /// side. | ||
| 199 | pub const BPF_F_RDONLY_PROG = 0x80; | ||
| 200 | /// flag for BPF_MAP_CREATE command. Flags for accessing BPF object from program | ||
| 201 | /// side. | ||
| 202 | pub const BPF_F_WRONLY_PROG = 0x100; | ||
| 203 | /// flag for BPF_MAP_CREATE command. Clone map from listener for newly accepted | ||
| 204 | /// socket | ||
| 205 | pub const BPF_F_CLONE = 0x200; | ||
| 206 | /// flag for BPF_MAP_CREATE command. Enable memory-mapping BPF map | ||
| 207 | pub const BPF_F_MMAPABLE = 0x400; | ||
| 208 | |||
| 209 | /// These values correspond to "syscalls" within the BPF program's environment | ||
| 210 | pub const Helper = enum(i32) { | ||
| 211 | unspec, | ||
| 212 | map_lookup_elem, | ||
| 213 | map_update_elem, | ||
| 214 | map_delete_elem, | ||
| 215 | probe_read, | ||
| 216 | ktime_get_ns, | ||
| 217 | trace_printk, | ||
| 218 | get_prandom_u32, | ||
| 219 | get_smp_processor_id, | ||
| 220 | skb_store_bytes, | ||
| 221 | l3_csum_replace, | ||
| 222 | l4_csum_replace, | ||
| 223 | tail_call, | ||
| 224 | clone_redirect, | ||
| 225 | get_current_pid_tgid, | ||
| 226 | get_current_uid_gid, | ||
| 227 | get_current_comm, | ||
| 228 | get_cgroup_classid, | ||
| 229 | skb_vlan_push, | ||
| 230 | skb_vlan_pop, | ||
| 231 | skb_get_tunnel_key, | ||
| 232 | skb_set_tunnel_key, | ||
| 233 | perf_event_read, | ||
| 234 | redirect, | ||
| 235 | get_route_realm, | ||
| 236 | perf_event_output, | ||
| 237 | skb_load_bytes, | ||
| 238 | get_stackid, | ||
| 239 | csum_diff, | ||
| 240 | skb_get_tunnel_opt, | ||
| 241 | skb_set_tunnel_opt, | ||
| 242 | skb_change_proto, | ||
| 243 | skb_change_type, | ||
| 244 | skb_under_cgroup, | ||
| 245 | get_hash_recalc, | ||
| 246 | get_current_task, | ||
| 247 | probe_write_user, | ||
| 248 | current_task_under_cgroup, | ||
| 249 | skb_change_tail, | ||
| 250 | skb_pull_data, | ||
| 251 | csum_update, | ||
| 252 | set_hash_invalid, | ||
| 253 | get_numa_node_id, | ||
| 254 | skb_change_head, | ||
| 255 | xdp_adjust_head, | ||
| 256 | probe_read_str, | ||
| 257 | get_socket_cookie, | ||
| 258 | get_socket_uid, | ||
| 259 | set_hash, | ||
| 260 | setsockopt, | ||
| 261 | skb_adjust_room, | ||
| 262 | redirect_map, | ||
| 263 | sk_redirect_map, | ||
| 264 | sock_map_update, | ||
| 265 | xdp_adjust_meta, | ||
| 266 | perf_event_read_value, | ||
| 267 | perf_prog_read_value, | ||
| 268 | getsockopt, | ||
| 269 | override_return, | ||
| 270 | sock_ops_cb_flags_set, | ||
| 271 | msg_redirect_map, | ||
| 272 | msg_apply_bytes, | ||
| 273 | msg_cork_bytes, | ||
| 274 | msg_pull_data, | ||
| 275 | bind, | ||
| 276 | xdp_adjust_tail, | ||
| 277 | skb_get_xfrm_state, | ||
| 278 | get_stack, | ||
| 279 | skb_load_bytes_relative, | ||
| 280 | fib_lookup, | ||
| 281 | sock_hash_update, | ||
| 282 | msg_redirect_hash, | ||
| 283 | sk_redirect_hash, | ||
| 284 | lwt_push_encap, | ||
| 285 | lwt_seg6_store_bytes, | ||
| 286 | lwt_seg6_adjust_srh, | ||
| 287 | lwt_seg6_action, | ||
| 288 | rc_repeat, | ||
| 289 | rc_keydown, | ||
| 290 | skb_cgroup_id, | ||
| 291 | get_current_cgroup_id, | ||
| 292 | get_local_storage, | ||
| 293 | sk_select_reuseport, | ||
| 294 | skb_ancestor_cgroup_id, | ||
| 295 | sk_lookup_tcp, | ||
| 296 | sk_lookup_udp, | ||
| 297 | sk_release, | ||
| 298 | map_push_elem, | ||
| 299 | map_pop_elem, | ||
| 300 | map_peek_elem, | ||
| 301 | msg_push_data, | ||
| 302 | msg_pop_data, | ||
| 303 | rc_pointer_rel, | ||
| 304 | spin_lock, | ||
| 305 | spin_unlock, | ||
| 306 | sk_fullsock, | ||
| 307 | tcp_sock, | ||
| 308 | skb_ecn_set_ce, | ||
| 309 | get_listener_sock, | ||
| 310 | skc_lookup_tcp, | ||
| 311 | tcp_check_syncookie, | ||
| 312 | sysctl_get_name, | ||
| 313 | sysctl_get_current_value, | ||
| 314 | sysctl_get_new_value, | ||
| 315 | sysctl_set_new_value, | ||
| 316 | strtol, | ||
| 317 | strtoul, | ||
| 318 | sk_storage_get, | ||
| 319 | sk_storage_delete, | ||
| 320 | send_signal, | ||
| 321 | tcp_gen_syncookie, | ||
| 322 | skb_output, | ||
| 323 | probe_read_user, | ||
| 324 | probe_read_kernel, | ||
| 325 | probe_read_user_str, | ||
| 326 | probe_read_kernel_str, | ||
| 327 | tcp_send_ack, | ||
| 328 | send_signal_thread, | ||
| 329 | jiffies64, | ||
| 330 | _, | ||
| 331 | }; | ||
| 332 | |||
| 333 | /// a single BPF instruction | ||
| 334 | pub const Insn = packed struct { | ||
| 335 | code: u8, | ||
| 336 | dst: u4, | ||
| 337 | src: u4, | ||
| 338 | off: i16, | ||
| 339 | imm: i32, | ||
| 340 | |||
| 341 | /// r0 - r9 are general purpose 64-bit registers, r10 points to the stack | ||
| 342 | /// frame | ||
| 343 | pub const Reg = packed enum(u4) { r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10 }; | ||
| 344 | const Source = packed enum(u1) { reg, imm }; | ||
| 345 | const AluOp = packed enum(u8) { | ||
| 346 | add = ADD, | ||
| 347 | sub = SUB, | ||
| 348 | mul = MUL, | ||
| 349 | div = DIV, | ||
| 350 | op_or = OR, | ||
| 351 | op_and = AND, | ||
| 352 | lsh = LSH, | ||
| 353 | rsh = RSH, | ||
| 354 | neg = NEG, | ||
| 355 | mod = MOD, | ||
| 356 | xor = XOR, | ||
| 357 | mov = MOV, | ||
| 358 | }; | ||
| 359 | |||
| 360 | pub const Size = packed enum(u8) { | ||
| 361 | byte = B, | ||
| 362 | half_word = H, | ||
| 363 | word = W, | ||
| 364 | double_word = DW, | ||
| 365 | }; | ||
| 366 | |||
| 367 | const JmpOp = packed enum(u8) { | ||
| 368 | ja = JA, | ||
| 369 | jeq = JEQ, | ||
| 370 | jgt = JGT, | ||
| 371 | jge = JGE, | ||
| 372 | jset = JSET, | ||
| 373 | }; | ||
| 374 | |||
| 375 | const ImmOrReg = union(Source) { | ||
| 376 | imm: i32, | ||
| 377 | reg: Reg, | ||
| 378 | }; | ||
| 379 | |||
| 380 | fn imm_reg(code: u8, dst: Reg, src: anytype, off: i16) Insn { | ||
| 381 | const imm_or_reg = if (@typeInfo(@TypeOf(src)) == .EnumLiteral) | ||
| 382 | ImmOrReg{ .reg = @as(Reg, src) } | ||
| 383 | else | ||
| 384 | ImmOrReg{ .imm = src }; | ||
| 385 | |||
| 386 | const src_type = switch (imm_or_reg) { | ||
| 387 | .imm => K, | ||
| 388 | .reg => X, | ||
| 389 | }; | ||
| 390 | |||
| 391 | return Insn{ | ||
| 392 | .code = code | src_type, | ||
| 393 | .dst = @enumToInt(dst), | ||
| 394 | .src = switch (imm_or_reg) { | ||
| 395 | .imm => 0, | ||
| 396 | .reg => |r| @enumToInt(r), | ||
| 397 | }, | ||
| 398 | .off = off, | ||
| 399 | .imm = switch (imm_or_reg) { | ||
| 400 | .imm => |i| i, | ||
| 401 | .reg => 0, | ||
| 402 | }, | ||
| 403 | }; | ||
| 404 | } | ||
| 405 | |||
| 406 | fn alu(comptime width: comptime_int, op: AluOp, dst: Reg, src: anytype) Insn { | ||
| 407 | const width_bitfield = switch (width) { | ||
| 408 | 32 => ALU, | ||
| 409 | 64 => ALU64, | ||
| 410 | else => @compileError("width must be 32 or 64"), | ||
| 411 | }; | ||
| 412 | |||
| 413 | return imm_reg(width_bitfield | @enumToInt(op), dst, src, 0); | ||
| 414 | } | ||
| 415 | |||
| 416 | pub fn mov(dst: Reg, src: anytype) Insn { | ||
| 417 | return alu(64, .mov, dst, src); | ||
| 418 | } | ||
| 419 | |||
| 420 | pub fn add(dst: Reg, src: anytype) Insn { | ||
| 421 | return alu(64, .add, dst, src); | ||
| 422 | } | ||
| 423 | |||
| 424 | fn jmp(op: JmpOp, dst: Reg, src: anytype, off: i16) Insn { | ||
| 425 | return imm_reg(JMP | @enumToInt(op), dst, src, off); | ||
| 426 | } | ||
| 427 | |||
| 428 | pub fn jeq(dst: Reg, src: anytype, off: i16) Insn { | ||
| 429 | return jmp(.jeq, dst, src, off); | ||
| 430 | } | ||
| 431 | |||
| 432 | pub fn stx_mem(size: Size, dst: Reg, src: Reg, off: i16) Insn { | ||
| 433 | return Insn{ | ||
| 434 | .code = STX | @enumToInt(size) | MEM, | ||
| 435 | .dst = @enumToInt(dst), | ||
| 436 | .src = @enumToInt(src), | ||
| 437 | .off = off, | ||
| 438 | .imm = 0, | ||
| 439 | }; | ||
| 440 | } | ||
| 441 | |||
| 442 | pub fn xadd(dst: Reg, src: Reg) Insn { | ||
| 443 | return Insn{ | ||
| 444 | .code = STX | XADD | DW, | ||
| 445 | .dst = @enumToInt(dst), | ||
| 446 | .src = @enumToInt(src), | ||
| 447 | .off = 0, | ||
| 448 | .imm = 0, | ||
| 449 | }; | ||
| 450 | } | ||
| 451 | |||
| 452 | /// direct packet access, R0 = *(uint *)(skb->data + imm32) | ||
| 453 | pub fn ld_abs(size: Size, imm: i32) Insn { | ||
| 454 | return Insn{ | ||
| 455 | .code = LD | @enumToInt(size) | ABS, | ||
| 456 | .dst = 0, | ||
| 457 | .src = 0, | ||
| 458 | .off = 0, | ||
| 459 | .imm = imm, | ||
| 460 | }; | ||
| 461 | } | ||
| 462 | |||
| 463 | fn ld_imm_impl1(dst: Reg, src: Reg, imm: u64) Insn { | ||
| 464 | return Insn{ | ||
| 465 | .code = LD | DW | IMM, | ||
| 466 | .dst = @enumToInt(dst), | ||
| 467 | .src = @enumToInt(src), | ||
| 468 | .off = 0, | ||
| 469 | .imm = @intCast(i32, @truncate(u32, imm)), | ||
| 470 | }; | ||
| 471 | } | ||
| 472 | |||
| 473 | fn ld_imm_impl2(imm: u64) Insn { | ||
| 474 | return Insn{ | ||
| 475 | .code = 0, | ||
| 476 | .dst = 0, | ||
| 477 | .src = 0, | ||
| 478 | .off = 0, | ||
| 479 | .imm = @intCast(i32, @truncate(u32, imm >> 32)), | ||
| 480 | }; | ||
| 481 | } | ||
| 482 | |||
| 483 | pub fn ld_map_fd1(dst: Reg, map_fd: fd_t) Insn { | ||
| 484 | return ld_imm_impl1(dst, @intToEnum(Reg, PSEUDO_MAP_FD), @intCast(u64, map_fd)); | ||
| 485 | } | ||
| 486 | |||
| 487 | pub fn ld_map_fd2(map_fd: fd_t) Insn { | ||
| 488 | return ld_imm_impl2(@intCast(u64, map_fd)); | ||
| 489 | } | ||
| 490 | |||
| 491 | pub fn call(helper: Helper) Insn { | ||
| 492 | return Insn{ | ||
| 493 | .code = JMP | CALL, | ||
| 494 | .dst = 0, | ||
| 495 | .src = 0, | ||
| 496 | .off = 0, | ||
| 497 | .imm = @enumToInt(helper), | ||
| 498 | }; | ||
| 499 | } | ||
| 500 | |||
| 501 | /// exit BPF program | ||
| 502 | pub fn exit() Insn { | ||
| 503 | return Insn{ | ||
| 504 | .code = JMP | EXIT, | ||
| 505 | .dst = 0, | ||
| 506 | .src = 0, | ||
| 507 | .off = 0, | ||
| 508 | .imm = 0, | ||
| 509 | }; | ||
| 510 | } | ||
| 511 | }; | ||
| 512 | |||
| 513 | fn expect_insn(insn: Insn, val: u64) void { | ||
| 514 | expectEqual(@bitCast(u64, insn), val); | ||
| 515 | } | ||
| 516 | |||
| 517 | test "insn bitsize" { | ||
| 518 | expectEqual(@bitSizeOf(Insn), 64); | ||
| 519 | } | ||
| 520 | |||
| 521 | // mov instructions | ||
| 522 | test "mov imm" { | ||
| 523 | expect_insn(Insn.mov(.r1, 1), 0x00000001000001b7); | ||
| 524 | } | ||
| 525 | |||
| 526 | test "mov reg" { | ||
| 527 | expect_insn(Insn.mov(.r6, .r1), 0x00000000000016bf); | ||
| 528 | } | ||
| 529 | |||
| 530 | // alu instructions | ||
| 531 | test "add imm" { | ||
| 532 | expect_insn(Insn.add(.r2, -4), 0xfffffffc00000207); | ||
| 533 | } | ||
| 534 | |||
| 535 | // ld instructions | ||
| 536 | test "ld_abs" { | ||
| 537 | expect_insn(Insn.ld_abs(.byte, 42), 0x0000002a00000030); | ||
| 538 | } | ||
| 539 | |||
| 540 | test "ld_map_fd" { | ||
| 541 | expect_insn(Insn.ld_map_fd1(.r1, 42), 0x0000002a00001118); | ||
| 542 | expect_insn(Insn.ld_map_fd2(42), 0x0000000000000000); | ||
| 543 | } | ||
| 544 | |||
| 545 | // st instructions | ||
| 546 | test "stx_mem" { | ||
| 547 | expect_insn(Insn.stx_mem(.word, .r10, .r0, -4), 0x00000000fffc0a63); | ||
| 548 | } | ||
| 549 | |||
| 550 | test "xadd" { | ||
| 551 | expect_insn(Insn.xadd(.r0, .r1), 0x00000000000010db); | ||
| 552 | } | ||
| 553 | |||
| 554 | // jmp instructions | ||
| 555 | test "jeq imm" { | ||
| 556 | expect_insn(Insn.jeq(.r0, 0, 2), 0x0000000000020015); | ||
| 557 | } | ||
| 558 | |||
| 559 | // other instructions | ||
| 560 | test "call" { | ||
| 561 | expect_insn(Insn.call(.map_lookup_elem), 0x0000000100000085); | ||
| 562 | } | ||
| 563 | |||
| 564 | test "exit" { | ||
| 565 | expect_insn(Insn.exit(), 0x0000000000000095); | ||
| 566 | } | ||
| 567 | |||
| 568 | pub const Cmd = extern enum(usize) { | ||
| 569 | map_create, | ||
| 570 | map_lookup_elem, | ||
| 571 | map_update_elem, | ||
| 572 | map_delete_elem, | ||
| 573 | map_get_next_key, | ||
| 574 | prog_load, | ||
| 575 | obj_pin, | ||
| 576 | obj_get, | ||
| 577 | prog_attach, | ||
| 578 | prog_detach, | ||
| 579 | prog_test_run, | ||
| 580 | prog_get_next_id, | ||
| 581 | map_get_next_id, | ||
| 582 | prog_get_fd_by_id, | ||
| 583 | map_get_fd_by_id, | ||
| 584 | obj_get_info_by_fd, | ||
| 585 | prog_query, | ||
| 586 | raw_tracepoint_open, | ||
| 587 | btf_load, | ||
| 588 | btf_get_fd_by_id, | ||
| 589 | task_fd_query, | ||
| 590 | map_lookup_and_delete_elem, | ||
| 591 | map_freeze, | ||
| 592 | btf_get_next_id, | ||
| 593 | map_lookup_batch, | ||
| 594 | map_lookup_and_delete_batch, | ||
| 595 | map_update_batch, | ||
| 596 | map_delete_batch, | ||
| 597 | link_create, | ||
| 598 | link_update, | ||
| 599 | link_get_fd_by_id, | ||
| 600 | link_get_next_id, | ||
| 601 | enable_stats, | ||
| 602 | iter_create, | ||
| 603 | link_detach, | ||
| 604 | _, | ||
| 605 | }; | ||
| 606 | |||
| 607 | pub const MapType = extern enum(u32) { | ||
| 608 | unspec, | ||
| 609 | hash, | ||
| 610 | array, | ||
| 611 | prog_array, | ||
| 612 | perf_event_array, | ||
| 613 | percpu_hash, | ||
| 614 | percpu_array, | ||
| 615 | stack_trace, | ||
| 616 | cgroup_array, | ||
| 617 | lru_hash, | ||
| 618 | lru_percpu_hash, | ||
| 619 | lpm_trie, | ||
| 620 | array_of_maps, | ||
| 621 | hash_of_maps, | ||
| 622 | devmap, | ||
| 623 | sockmap, | ||
| 624 | cpumap, | ||
| 625 | xskmap, | ||
| 626 | sockhash, | ||
| 627 | cgroup_storage, | ||
| 628 | reuseport_sockarray, | ||
| 629 | percpu_cgroup_storage, | ||
| 630 | queue, | ||
| 631 | stack, | ||
| 632 | sk_storage, | ||
| 633 | devmap_hash, | ||
| 634 | struct_ops, | ||
| 635 | ringbuf, | ||
| 636 | _, | ||
| 637 | }; | ||
| 638 | |||
| 639 | pub const ProgType = extern enum(u32) { | ||
| 640 | unspec, | ||
| 641 | socket_filter, | ||
| 642 | kprobe, | ||
| 643 | sched_cls, | ||
| 644 | sched_act, | ||
| 645 | tracepoint, | ||
| 646 | xdp, | ||
| 647 | perf_event, | ||
| 648 | cgroup_skb, | ||
| 649 | cgroup_sock, | ||
| 650 | lwt_in, | ||
| 651 | lwt_out, | ||
| 652 | lwt_xmit, | ||
| 653 | sock_ops, | ||
| 654 | sk_skb, | ||
| 655 | cgroup_device, | ||
| 656 | sk_msg, | ||
| 657 | raw_tracepoint, | ||
| 658 | cgroup_sock_addr, | ||
| 659 | lwt_seg6local, | ||
| 660 | lirc_mode2, | ||
| 661 | sk_reuseport, | ||
| 662 | flow_dissector, | ||
| 663 | cgroup_sysctl, | ||
| 664 | raw_tracepoint_writable, | ||
| 665 | cgroup_sockopt, | ||
| 666 | tracing, | ||
| 667 | struct_ops, | ||
| 668 | ext, | ||
| 669 | lsm, | ||
| 670 | sk_lookup, | ||
| 671 | }; | ||
| 672 | |||
| 673 | pub const AttachType = extern enum(u32) { | ||
| 674 | cgroup_inet_ingress, | ||
| 675 | cgroup_inet_egress, | ||
| 676 | cgroup_inet_sock_create, | ||
| 677 | cgroup_sock_ops, | ||
| 678 | sk_skb_stream_parser, | ||
| 679 | sk_skb_stream_verdict, | ||
| 680 | cgroup_device, | ||
| 681 | sk_msg_verdict, | ||
| 682 | cgroup_inet4_bind, | ||
| 683 | cgroup_inet6_bind, | ||
| 684 | cgroup_inet4_connect, | ||
| 685 | cgroup_inet6_connect, | ||
| 686 | cgroup_inet4_post_bind, | ||
| 687 | cgroup_inet6_post_bind, | ||
| 688 | cgroup_udp4_sendmsg, | ||
| 689 | cgroup_udp6_sendmsg, | ||
| 690 | lirc_mode2, | ||
| 691 | flow_dissector, | ||
| 692 | cgroup_sysctl, | ||
| 693 | cgroup_udp4_recvmsg, | ||
| 694 | cgroup_udp6_recvmsg, | ||
| 695 | cgroup_getsockopt, | ||
| 696 | cgroup_setsockopt, | ||
| 697 | trace_raw_tp, | ||
| 698 | trace_fentry, | ||
| 699 | trace_fexit, | ||
| 700 | modify_return, | ||
| 701 | lsm_mac, | ||
| 702 | trace_iter, | ||
| 703 | cgroup_inet4_getpeername, | ||
| 704 | cgroup_inet6_getpeername, | ||
| 705 | cgroup_inet4_getsockname, | ||
| 706 | cgroup_inet6_getsockname, | ||
| 707 | xdp_devmap, | ||
| 708 | cgroup_inet_sock_release, | ||
| 709 | xdp_cpumap, | ||
| 710 | sk_lookup, | ||
| 711 | xdp, | ||
| 712 | _, | ||
| 713 | }; | ||
| 714 | |||
| 715 | const obj_name_len = 16; | ||
| 716 | /// struct used by Cmd.map_create command | ||
| 717 | pub const MapCreateAttr = extern struct { | ||
| 718 | /// one of MapType | ||
| 719 | map_type: u32, | ||
| 720 | /// size of key in bytes | ||
| 721 | key_size: u32, | ||
| 722 | /// size of value in bytes | ||
| 723 | value_size: u32, | ||
| 724 | /// max number of entries in a map | ||
| 725 | max_entries: u32, | ||
| 726 | /// .map_create related flags | ||
| 727 | map_flags: u32, | ||
| 728 | /// fd pointing to the inner map | ||
| 729 | inner_map_fd: fd_t, | ||
| 730 | /// numa node (effective only if MapCreateFlags.numa_node is set) | ||
| 731 | numa_node: u32, | ||
| 732 | map_name: [obj_name_len]u8, | ||
| 733 | /// ifindex of netdev to create on | ||
| 734 | map_ifindex: u32, | ||
| 735 | /// fd pointing to a BTF type data | ||
| 736 | btf_fd: fd_t, | ||
| 737 | /// BTF type_id of the key | ||
| 738 | btf_key_type_id: u32, | ||
| 739 | /// BTF type_id of the value | ||
| 740 | bpf_value_type_id: u32, | ||
| 741 | /// BTF type_id of a kernel struct stored as the map value | ||
| 742 | btf_vmlinux_value_type_id: u32, | ||
| 743 | }; | ||
| 744 | |||
| 745 | /// struct used by Cmd.map_*_elem commands | ||
| 746 | pub const MapElemAttr = extern struct { | ||
| 747 | map_fd: fd_t, | ||
| 748 | key: u64, | ||
| 749 | result: extern union { | ||
| 750 | value: u64, | ||
| 751 | next_key: u64, | ||
| 752 | }, | ||
| 753 | flags: u64, | ||
| 754 | }; | ||
| 755 | |||
| 756 | /// struct used by Cmd.map_*_batch commands | ||
| 757 | pub const MapBatchAttr = extern struct { | ||
| 758 | /// start batch, NULL to start from beginning | ||
| 759 | in_batch: u64, | ||
| 760 | /// output: next start batch | ||
| 761 | out_batch: u64, | ||
| 762 | keys: u64, | ||
| 763 | values: u64, | ||
| 764 | /// input/output: | ||
| 765 | /// input: # of key/value elements | ||
| 766 | /// output: # of filled elements | ||
| 767 | count: u32, | ||
| 768 | map_fd: fd_t, | ||
| 769 | elem_flags: u64, | ||
| 770 | flags: u64, | ||
| 771 | }; | ||
| 772 | |||
| 773 | /// struct used by Cmd.prog_load command | ||
| 774 | pub const ProgLoadAttr = extern struct { | ||
| 775 | /// one of ProgType | ||
| 776 | prog_type: u32, | ||
| 777 | insn_cnt: u32, | ||
| 778 | insns: u64, | ||
| 779 | license: u64, | ||
| 780 | /// verbosity level of verifier | ||
| 781 | log_level: u32, | ||
| 782 | /// size of user buffer | ||
| 783 | log_size: u32, | ||
| 784 | /// user supplied buffer | ||
| 785 | log_buf: u64, | ||
| 786 | /// not used | ||
| 787 | kern_version: u32, | ||
| 788 | prog_flags: u32, | ||
| 789 | prog_name: [obj_name_len]u8, | ||
| 790 | /// ifindex of netdev to prep for. For some prog types expected attach | ||
| 791 | /// type must be known at load time to verify attach type specific parts | ||
| 792 | /// of prog (context accesses, allowed helpers, etc). | ||
| 793 | prog_ifindex: u32, | ||
| 794 | expected_attach_type: u32, | ||
| 795 | /// fd pointing to BTF type data | ||
| 796 | prog_btf_fd: fd_t, | ||
| 797 | /// userspace bpf_func_info size | ||
| 798 | func_info_rec_size: u32, | ||
| 799 | func_info: u64, | ||
| 800 | /// number of bpf_func_info records | ||
| 801 | func_info_cnt: u32, | ||
| 802 | /// userspace bpf_line_info size | ||
| 803 | line_info_rec_size: u32, | ||
| 804 | line_info: u64, | ||
| 805 | /// number of bpf_line_info records | ||
| 806 | line_info_cnt: u32, | ||
| 807 | /// in-kernel BTF type id to attach to | ||
| 808 | attact_btf_id: u32, | ||
| 809 | /// 0 to attach to vmlinux | ||
| 810 | attach_prog_id: u32, | ||
| 811 | }; | ||
| 812 | |||
| 813 | /// struct used by Cmd.obj_* commands | ||
| 814 | pub const ObjAttr = extern struct { | ||
| 815 | pathname: u64, | ||
| 816 | bpf_fd: fd_t, | ||
| 817 | file_flags: u32, | ||
| 818 | }; | ||
| 819 | |||
| 820 | /// struct used by Cmd.prog_attach/detach commands | ||
| 821 | pub const ProgAttachAttr = extern struct { | ||
| 822 | /// container object to attach to | ||
| 823 | target_fd: fd_t, | ||
| 824 | /// eBPF program to attach | ||
| 825 | attach_bpf_fd: fd_t, | ||
| 826 | attach_type: u32, | ||
| 827 | attach_flags: u32, | ||
| 828 | // TODO: BPF_F_REPLACE flags | ||
| 829 | /// previously attached eBPF program to replace if .replace is used | ||
| 830 | replace_bpf_fd: fd_t, | ||
| 831 | }; | ||
| 832 | |||
| 833 | /// struct used by Cmd.prog_test_run command | ||
| 834 | pub const TestAttr = extern struct { | ||
| 835 | prog_fd: fd_t, | ||
| 836 | retval: u32, | ||
| 837 | /// input: len of data_in | ||
| 838 | data_size_in: u32, | ||
| 839 | /// input/output: len of data_out. returns ENOSPC if data_out is too small. | ||
| 840 | data_size_out: u32, | ||
| 841 | data_in: u64, | ||
| 842 | data_out: u64, | ||
| 843 | repeat: u32, | ||
| 844 | duration: u32, | ||
| 845 | /// input: len of ctx_in | ||
| 846 | ctx_size_in: u32, | ||
| 847 | /// input/output: len of ctx_out. returns ENOSPC if ctx_out is too small. | ||
| 848 | ctx_size_out: u32, | ||
| 849 | ctx_in: u64, | ||
| 850 | ctx_out: u64, | ||
| 851 | }; | ||
| 852 | |||
| 853 | /// struct used by Cmd.*_get_*_id commands | ||
| 854 | pub const GetIdAttr = extern struct { | ||
| 855 | id: extern union { | ||
| 856 | start_id: u32, | ||
| 857 | prog_id: u32, | ||
| 858 | map_id: u32, | ||
| 859 | btf_id: u32, | ||
| 860 | link_id: u32, | ||
| 861 | }, | ||
| 862 | next_id: u32, | ||
| 863 | open_flags: u32, | ||
| 864 | }; | ||
| 865 | |||
| 866 | /// struct used by Cmd.obj_get_info_by_fd command | ||
| 867 | pub const InfoAttr = extern struct { | ||
| 868 | bpf_fd: fd_t, | ||
| 869 | info_len: u32, | ||
| 870 | info: u64, | ||
| 871 | }; | ||
| 872 | |||
| 873 | /// struct used by Cmd.prog_query command | ||
| 874 | pub const QueryAttr = extern struct { | ||
| 875 | /// container object to query | ||
| 876 | target_fd: fd_t, | ||
| 877 | attach_type: u32, | ||
| 878 | query_flags: u32, | ||
| 879 | attach_flags: u32, | ||
| 880 | prog_ids: u64, | ||
| 881 | prog_cnt: u32, | ||
| 882 | }; | ||
| 883 | |||
| 884 | /// struct used by Cmd.raw_tracepoint_open command | ||
| 885 | pub const RawTracepointAttr = extern struct { | ||
| 886 | name: u64, | ||
| 887 | prog_fd: fd_t, | ||
| 888 | }; | ||
| 889 | |||
| 890 | /// struct used by Cmd.btf_load command | ||
| 891 | pub const BtfLoadAttr = extern struct { | ||
| 892 | btf: u64, | ||
| 893 | btf_log_buf: u64, | ||
| 894 | btf_size: u32, | ||
| 895 | btf_log_size: u32, | ||
| 896 | btf_log_level: u32, | ||
| 897 | }; | ||
| 898 | |||
| 899 | pub const TaskFdQueryAttr = extern struct { | ||
| 900 | /// input: pid | ||
| 901 | pid: pid_t, | ||
| 902 | /// input: fd | ||
| 903 | fd: fd_t, | ||
| 904 | /// input: flags | ||
| 905 | flags: u32, | ||
| 906 | /// input/output: buf len | ||
| 907 | buf_len: u32, | ||
| 908 | /// input/output: | ||
| 909 | /// tp_name for tracepoint | ||
| 910 | /// symbol for kprobe | ||
| 911 | /// filename for uprobe | ||
| 912 | buf: u64, | ||
| 913 | /// output: prod_id | ||
| 914 | prog_id: u32, | ||
| 915 | /// output: BPF_FD_TYPE | ||
| 916 | fd_type: u32, | ||
| 917 | /// output: probe_offset | ||
| 918 | probe_offset: u64, | ||
| 919 | /// output: probe_addr | ||
| 920 | probe_addr: u64, | ||
| 921 | }; | ||
| 922 | |||
| 923 | /// struct used by Cmd.link_create command | ||
| 924 | pub const LinkCreateAttr = extern struct { | ||
| 925 | /// eBPF program to attach | ||
| 926 | prog_fd: fd_t, | ||
| 927 | /// object to attach to | ||
| 928 | target_fd: fd_t, | ||
| 929 | attach_type: u32, | ||
| 930 | /// extra flags | ||
| 931 | flags: u32, | ||
| 932 | }; | ||
| 933 | |||
| 934 | /// struct used by Cmd.link_update command | ||
| 935 | pub const LinkUpdateAttr = extern struct { | ||
| 936 | link_fd: fd_t, | ||
| 937 | /// new program to update link with | ||
| 938 | new_prog_fd: fd_t, | ||
| 939 | /// extra flags | ||
| 940 | flags: u32, | ||
| 941 | /// expected link's program fd, it is specified only if BPF_F_REPLACE is | ||
| 942 | /// set in flags | ||
| 943 | old_prog_fd: fd_t, | ||
| 944 | }; | ||
| 945 | |||
| 946 | /// struct used by Cmd.enable_stats command | ||
| 947 | pub const EnableStatsAttr = extern struct { | ||
| 948 | type: u32, | ||
| 949 | }; | ||
| 950 | |||
| 951 | /// struct used by Cmd.iter_create command | ||
| 952 | pub const IterCreateAttr = extern struct { | ||
| 953 | link_fd: fd_t, | ||
| 954 | flags: u32, | ||
| 955 | }; | ||
| 956 | |||
| 957 | pub const Attr = extern union { | ||
| 958 | map_create: MapCreateAttr, | ||
| 959 | map_elem: MapElemAttr, | ||
| 960 | map_batch: MapBatchAttr, | ||
| 961 | prog_load: ProgLoadAttr, | ||
| 962 | obj: ObjAttr, | ||
| 963 | prog_attach: ProgAttachAttr, | ||
| 964 | test_run: TestRunAttr, | ||
| 965 | get_id: GetIdAttr, | ||
| 966 | info: InfoAttr, | ||
| 967 | query: QueryAttr, | ||
| 968 | raw_tracepoint: RawTracepointAttr, | ||
| 969 | btf_load: BtfLoadAttr, | ||
| 970 | task_fd_query: TaskFdQueryAttr, | ||
| 971 | link_create: LinkCreateAttr, | ||
| 972 | link_update: LinkUpdateAttr, | ||
| 973 | enable_stats: EnableStatsAttr, | ||
| 974 | iter_create: IterCreateAttr, | ||
| 975 | }; | ||
lib/std/os/linux.zig+1| ... | @@ -29,6 +29,7 @@ pub usingnamespace switch (builtin.arch) { | ... | @@ -29,6 +29,7 @@ pub usingnamespace switch (builtin.arch) { |
| 29 | }; | 29 | }; |
| 30 | pub usingnamespace @import("bits.zig"); | 30 | pub usingnamespace @import("bits.zig"); |
| 31 | pub const tls = @import("linux/tls.zig"); | 31 | pub const tls = @import("linux/tls.zig"); |
| 32 | pub const BPF = @import("linux/bpf.zig"); | ||
| 32 | 33 | ||
| 33 | /// Set by startup code, used by `getauxval`. | 34 | /// Set by startup code, used by `getauxval`. |
| 34 | pub var elf_aux_maybe: ?[*]std.elf.Auxv = null; | 35 | pub var elf_aux_maybe: ?[*]std.elf.Auxv = null; |
lib/std/os/linux/bpf.zig created+973| ... | @@ -0,0 +1,973 @@ | ||
| 1 | // SPDX-License-Identifier: MIT | ||
| 2 | // Copyright (c) 2015-2020 Zig Contributors | ||
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | ||
| 4 | // The MIT license requires this copyright notice to be included in all copies | ||
| 5 | // and substantial portions of the software. | ||
| 6 | usingnamespace std.os; | ||
| 7 | const std = @import("../../std.zig"); | ||
| 8 | const expectEqual = std.testing.expectEqual; | ||
| 9 | |||
| 10 | // instruction classes | ||
| 11 | pub const LD = 0x00; | ||
| 12 | pub const LDX = 0x01; | ||
| 13 | pub const ST = 0x02; | ||
| 14 | pub const STX = 0x03; | ||
| 15 | pub const ALU = 0x04; | ||
| 16 | pub const JMP = 0x05; | ||
| 17 | pub const RET = 0x06; | ||
| 18 | pub const MISC = 0x07; | ||
| 19 | |||
| 20 | /// 32-bit | ||
| 21 | pub const W = 0x00; | ||
| 22 | /// 16-bit | ||
| 23 | pub const H = 0x08; | ||
| 24 | /// 8-bit | ||
| 25 | pub const B = 0x10; | ||
| 26 | /// 64-bit | ||
| 27 | pub const DW = 0x18; | ||
| 28 | |||
| 29 | pub const IMM = 0x00; | ||
| 30 | pub const ABS = 0x20; | ||
| 31 | pub const IND = 0x40; | ||
| 32 | pub const MEM = 0x60; | ||
| 33 | pub const LEN = 0x80; | ||
| 34 | pub const MSH = 0xa0; | ||
| 35 | |||
| 36 | // alu fields | ||
| 37 | pub const ADD = 0x00; | ||
| 38 | pub const SUB = 0x10; | ||
| 39 | pub const MUL = 0x20; | ||
| 40 | pub const DIV = 0x30; | ||
| 41 | pub const OR = 0x40; | ||
| 42 | pub const AND = 0x50; | ||
| 43 | pub const LSH = 0x60; | ||
| 44 | pub const RSH = 0x70; | ||
| 45 | pub const NEG = 0x80; | ||
| 46 | pub const MOD = 0x90; | ||
| 47 | pub const XOR = 0xa0; | ||
| 48 | |||
| 49 | // jmp fields | ||
| 50 | pub const JA = 0x00; | ||
| 51 | pub const JEQ = 0x10; | ||
| 52 | pub const JGT = 0x20; | ||
| 53 | pub const JGE = 0x30; | ||
| 54 | pub const JSET = 0x40; | ||
| 55 | |||
| 56 | //#define BPF_SRC(code) ((code) & 0x08) | ||
| 57 | pub const K = 0x00; | ||
| 58 | pub const X = 0x08; | ||
| 59 | |||
| 60 | pub const MAXINSNS = 4096; | ||
| 61 | |||
| 62 | // instruction classes | ||
| 63 | /// jmp mode in word width | ||
| 64 | pub const JMP32 = 0x06; | ||
| 65 | /// alu mode in double word width | ||
| 66 | pub const ALU64 = 0x07; | ||
| 67 | |||
| 68 | // ld/ldx fields | ||
| 69 | /// exclusive add | ||
| 70 | pub const XADD = 0xc0; | ||
| 71 | |||
| 72 | // alu/jmp fields | ||
| 73 | /// mov reg to reg | ||
| 74 | pub const MOV = 0xb0; | ||
| 75 | /// sign extending arithmetic shift right */ | ||
| 76 | pub const ARSH = 0xc0; | ||
| 77 | |||
| 78 | // change endianness of a register | ||
| 79 | /// flags for endianness conversion: | ||
| 80 | pub const END = 0xd0; | ||
| 81 | /// convert to little-endian */ | ||
| 82 | pub const TO_LE = 0x00; | ||
| 83 | /// convert to big-endian | ||
| 84 | pub const TO_BE = 0x08; | ||
| 85 | pub const FROM_LE = TO_LE; | ||
| 86 | pub const FROM_BE = TO_BE; | ||
| 87 | |||
| 88 | // jmp encodings | ||
| 89 | /// jump != * | ||
| 90 | pub const JNE = 0x50; | ||
| 91 | /// LT is unsigned, '<' | ||
| 92 | pub const JLT = 0xa0; | ||
| 93 | /// LE is unsigned, '<=' * | ||
| 94 | pub const JLE = 0xb0; | ||
| 95 | /// SGT is signed '>', GT in x86 | ||
| 96 | pub const JSGT = 0x60; | ||
| 97 | /// SGE is signed '>=', GE in x86 | ||
| 98 | pub const JSGE = 0x70; | ||
| 99 | /// SLT is signed, '<' | ||
| 100 | pub const JSLT = 0xc0; | ||
| 101 | /// SLE is signed, '<=' | ||
| 102 | pub const JSLE = 0xd0; | ||
| 103 | /// function call | ||
| 104 | pub const CALL = 0x80; | ||
| 105 | /// function return | ||
| 106 | pub const EXIT = 0x90; | ||
| 107 | |||
| 108 | /// Flag for prog_attach command. If a sub-cgroup installs some bpf program, the | ||
| 109 | /// program in this cgroup yields to sub-cgroup program. | ||
| 110 | pub const F_ALLOW_OVERRIDE = 0x1; | ||
| 111 | /// Flag for prog_attach command. If a sub-cgroup installs some bpf program, | ||
| 112 | /// that cgroup program gets run in addition to the program in this cgroup. | ||
| 113 | pub const F_ALLOW_MULTI = 0x2; | ||
| 114 | /// Flag for prog_attach command. | ||
| 115 | pub const F_REPLACE = 0x4; | ||
| 116 | |||
| 117 | /// If BPF_F_STRICT_ALIGNMENT is used in BPF_PROG_LOAD command, the verifier | ||
| 118 | /// will perform strict alignment checking as if the kernel has been built with | ||
| 119 | /// CONFIG_EFFICIENT_UNALIGNED_ACCESS not set, and NET_IP_ALIGN defined to 2. | ||
| 120 | pub const F_STRICT_ALIGNMENT = 0x1; | ||
| 121 | |||
| 122 | /// If BPF_F_ANY_ALIGNMENT is used in BPF_PROF_LOAD command, the verifier will | ||
| 123 | /// allow any alignment whatsoever. On platforms with strict alignment | ||
| 124 | /// requirements for loads ands stores (such as sparc and mips) the verifier | ||
| 125 | /// validates that all loads and stores provably follow this requirement. This | ||
| 126 | /// flag turns that checking and enforcement off. | ||
| 127 | /// | ||
| 128 | /// It is mostly used for testing when we want to validate the context and | ||
| 129 | /// memory access aspects of the verifier, but because of an unaligned access | ||
| 130 | /// the alignment check would trigger before the one we are interested in. | ||
| 131 | pub const F_ANY_ALIGNMENT = 0x2; | ||
| 132 | |||
| 133 | /// BPF_F_TEST_RND_HI32 is used in BPF_PROG_LOAD command for testing purpose. | ||
| 134 | /// Verifier does sub-register def/use analysis and identifies instructions | ||
| 135 | /// whose def only matters for low 32-bit, high 32-bit is never referenced later | ||
| 136 | /// through implicit zero extension. Therefore verifier notifies JIT back-ends | ||
| 137 | /// that it is safe to ignore clearing high 32-bit for these instructions. This | ||
| 138 | /// saves some back-ends a lot of code-gen. However such optimization is not | ||
| 139 | /// necessary on some arches, for example x86_64, arm64 etc, whose JIT back-ends | ||
| 140 | /// hence hasn't used verifier's analysis result. But, we really want to have a | ||
| 141 | /// way to be able to verify the correctness of the described optimization on | ||
| 142 | /// x86_64 on which testsuites are frequently exercised. | ||
| 143 | /// | ||
| 144 | /// So, this flag is introduced. Once it is set, verifier will randomize high | ||
| 145 | /// 32-bit for those instructions who has been identified as safe to ignore | ||
| 146 | /// them. Then, if verifier is not doing correct analysis, such randomization | ||
| 147 | /// will regress tests to expose bugs. | ||
| 148 | pub const F_TEST_RND_HI32 = 0x4; | ||
| 149 | |||
| 150 | /// When BPF ldimm64's insn[0].src_reg != 0 then this can have two extensions: | ||
| 151 | /// insn[0].src_reg: BPF_PSEUDO_MAP_FD BPF_PSEUDO_MAP_VALUE | ||
| 152 | /// insn[0].imm: map fd map fd | ||
| 153 | /// insn[1].imm: 0 offset into value | ||
| 154 | /// insn[0].off: 0 0 | ||
| 155 | /// insn[1].off: 0 0 | ||
| 156 | /// ldimm64 rewrite: address of map address of map[0]+offset | ||
| 157 | /// verifier type: CONST_PTR_TO_MAP PTR_TO_MAP_VALUE | ||
| 158 | pub const PSEUDO_MAP_FD = 1; | ||
| 159 | pub const PSEUDO_MAP_VALUE = 2; | ||
| 160 | |||
| 161 | /// when bpf_call->src_reg == BPF_PSEUDO_CALL, bpf_call->imm == pc-relative | ||
| 162 | /// offset to another bpf function | ||
| 163 | pub const PSEUDO_CALL = 1; | ||
| 164 | |||
| 165 | /// flag for BPF_MAP_UPDATE_ELEM command. create new element or update existing | ||
| 166 | pub const ANY = 0; | ||
| 167 | /// flag for BPF_MAP_UPDATE_ELEM command. create new element if it didn't exist | ||
| 168 | pub const NOEXIST = 1; | ||
| 169 | /// flag for BPF_MAP_UPDATE_ELEM command. update existing element | ||
| 170 | pub const EXIST = 2; | ||
| 171 | /// flag for BPF_MAP_UPDATE_ELEM command. spin_lock-ed map_lookup/map_update | ||
| 172 | pub const F_LOCK = 4; | ||
| 173 | |||
| 174 | /// flag for BPF_MAP_CREATE command */ | ||
| 175 | pub const BPF_F_NO_PREALLOC = 0x1; | ||
| 176 | /// flag for BPF_MAP_CREATE command. Instead of having one common LRU list in | ||
| 177 | /// the BPF_MAP_TYPE_LRU_[PERCPU_]HASH map, use a percpu LRU list which can | ||
| 178 | /// scale and perform better. Note, the LRU nodes (including free nodes) cannot | ||
| 179 | /// be moved across different LRU lists. | ||
| 180 | pub const BPF_F_NO_COMMON_LRU = 0x2; | ||
| 181 | /// flag for BPF_MAP_CREATE command. Specify numa node during map creation | ||
| 182 | pub const BPF_F_NUMA_NODE = 0x4; | ||
| 183 | /// flag for BPF_MAP_CREATE command. Flags for BPF object read access from | ||
| 184 | /// syscall side | ||
| 185 | pub const BPF_F_RDONLY = 0x8; | ||
| 186 | /// flag for BPF_MAP_CREATE command. Flags for BPF object write access from | ||
| 187 | /// syscall side | ||
| 188 | pub const BPF_F_WRONLY = 0x10; | ||
| 189 | /// flag for BPF_MAP_CREATE command. Flag for stack_map, store build_id+offset | ||
| 190 | /// instead of pointer | ||
| 191 | pub const BPF_F_STACK_BUILD_ID = 0x20; | ||
| 192 | /// flag for BPF_MAP_CREATE command. Zero-initialize hash function seed. This | ||
| 193 | /// should only be used for testing. | ||
| 194 | pub const BPF_F_ZERO_SEED = 0x40; | ||
| 195 | /// flag for BPF_MAP_CREATE command Flags for accessing BPF object from program | ||
| 196 | /// side. | ||
| 197 | pub const BPF_F_RDONLY_PROG = 0x80; | ||
| 198 | /// flag for BPF_MAP_CREATE command. Flags for accessing BPF object from program | ||
| 199 | /// side. | ||
| 200 | pub const BPF_F_WRONLY_PROG = 0x100; | ||
| 201 | /// flag for BPF_MAP_CREATE command. Clone map from listener for newly accepted | ||
| 202 | /// socket | ||
| 203 | pub const BPF_F_CLONE = 0x200; | ||
| 204 | /// flag for BPF_MAP_CREATE command. Enable memory-mapping BPF map | ||
| 205 | pub const BPF_F_MMAPABLE = 0x400; | ||
| 206 | |||
| 207 | /// These values correspond to "syscalls" within the BPF program's environment | ||
| 208 | pub const Helper = enum(i32) { | ||
| 209 | unspec, | ||
| 210 | map_lookup_elem, | ||
| 211 | map_update_elem, | ||
| 212 | map_delete_elem, | ||
| 213 | probe_read, | ||
| 214 | ktime_get_ns, | ||
| 215 | trace_printk, | ||
| 216 | get_prandom_u32, | ||
| 217 | get_smp_processor_id, | ||
| 218 | skb_store_bytes, | ||
| 219 | l3_csum_replace, | ||
| 220 | l4_csum_replace, | ||
| 221 | tail_call, | ||
| 222 | clone_redirect, | ||
| 223 | get_current_pid_tgid, | ||
| 224 | get_current_uid_gid, | ||
| 225 | get_current_comm, | ||
| 226 | get_cgroup_classid, | ||
| 227 | skb_vlan_push, | ||
| 228 | skb_vlan_pop, | ||
| 229 | skb_get_tunnel_key, | ||
| 230 | skb_set_tunnel_key, | ||
| 231 | perf_event_read, | ||
| 232 | redirect, | ||
| 233 | get_route_realm, | ||
| 234 | perf_event_output, | ||
| 235 | skb_load_bytes, | ||
| 236 | get_stackid, | ||
| 237 | csum_diff, | ||
| 238 | skb_get_tunnel_opt, | ||
| 239 | skb_set_tunnel_opt, | ||
| 240 | skb_change_proto, | ||
| 241 | skb_change_type, | ||
| 242 | skb_under_cgroup, | ||
| 243 | get_hash_recalc, | ||
| 244 | get_current_task, | ||
| 245 | probe_write_user, | ||
| 246 | current_task_under_cgroup, | ||
| 247 | skb_change_tail, | ||
| 248 | skb_pull_data, | ||
| 249 | csum_update, | ||
| 250 | set_hash_invalid, | ||
| 251 | get_numa_node_id, | ||
| 252 | skb_change_head, | ||
| 253 | xdp_adjust_head, | ||
| 254 | probe_read_str, | ||
| 255 | get_socket_cookie, | ||
| 256 | get_socket_uid, | ||
| 257 | set_hash, | ||
| 258 | setsockopt, | ||
| 259 | skb_adjust_room, | ||
| 260 | redirect_map, | ||
| 261 | sk_redirect_map, | ||
| 262 | sock_map_update, | ||
| 263 | xdp_adjust_meta, | ||
| 264 | perf_event_read_value, | ||
| 265 | perf_prog_read_value, | ||
| 266 | getsockopt, | ||
| 267 | override_return, | ||
| 268 | sock_ops_cb_flags_set, | ||
| 269 | msg_redirect_map, | ||
| 270 | msg_apply_bytes, | ||
| 271 | msg_cork_bytes, | ||
| 272 | msg_pull_data, | ||
| 273 | bind, | ||
| 274 | xdp_adjust_tail, | ||
| 275 | skb_get_xfrm_state, | ||
| 276 | get_stack, | ||
| 277 | skb_load_bytes_relative, | ||
| 278 | fib_lookup, | ||
| 279 | sock_hash_update, | ||
| 280 | msg_redirect_hash, | ||
| 281 | sk_redirect_hash, | ||
| 282 | lwt_push_encap, | ||
| 283 | lwt_seg6_store_bytes, | ||
| 284 | lwt_seg6_adjust_srh, | ||
| 285 | lwt_seg6_action, | ||
| 286 | rc_repeat, | ||
| 287 | rc_keydown, | ||
| 288 | skb_cgroup_id, | ||
| 289 | get_current_cgroup_id, | ||
| 290 | get_local_storage, | ||
| 291 | sk_select_reuseport, | ||
| 292 | skb_ancestor_cgroup_id, | ||
| 293 | sk_lookup_tcp, | ||
| 294 | sk_lookup_udp, | ||
| 295 | sk_release, | ||
| 296 | map_push_elem, | ||
| 297 | map_pop_elem, | ||
| 298 | map_peek_elem, | ||
| 299 | msg_push_data, | ||
| 300 | msg_pop_data, | ||
| 301 | rc_pointer_rel, | ||
| 302 | spin_lock, | ||
| 303 | spin_unlock, | ||
| 304 | sk_fullsock, | ||
| 305 | tcp_sock, | ||
| 306 | skb_ecn_set_ce, | ||
| 307 | get_listener_sock, | ||
| 308 | skc_lookup_tcp, | ||
| 309 | tcp_check_syncookie, | ||
| 310 | sysctl_get_name, | ||
| 311 | sysctl_get_current_value, | ||
| 312 | sysctl_get_new_value, | ||
| 313 | sysctl_set_new_value, | ||
| 314 | strtol, | ||
| 315 | strtoul, | ||
| 316 | sk_storage_get, | ||
| 317 | sk_storage_delete, | ||
| 318 | send_signal, | ||
| 319 | tcp_gen_syncookie, | ||
| 320 | skb_output, | ||
| 321 | probe_read_user, | ||
| 322 | probe_read_kernel, | ||
| 323 | probe_read_user_str, | ||
| 324 | probe_read_kernel_str, | ||
| 325 | tcp_send_ack, | ||
| 326 | send_signal_thread, | ||
| 327 | jiffies64, | ||
| 328 | _, | ||
| 329 | }; | ||
| 330 | |||
| 331 | /// a single BPF instruction | ||
| 332 | pub const Insn = packed struct { | ||
| 333 | code: u8, | ||
| 334 | dst: u4, | ||
| 335 | src: u4, | ||
| 336 | off: i16, | ||
| 337 | imm: i32, | ||
| 338 | |||
| 339 | /// r0 - r9 are general purpose 64-bit registers, r10 points to the stack | ||
| 340 | /// frame | ||
| 341 | pub const Reg = packed enum(u4) { r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10 }; | ||
| 342 | const Source = packed enum(u1) { reg, imm }; | ||
| 343 | const AluOp = packed enum(u8) { | ||
| 344 | add = ADD, | ||
| 345 | sub = SUB, | ||
| 346 | mul = MUL, | ||
| 347 | div = DIV, | ||
| 348 | op_or = OR, | ||
| 349 | op_and = AND, | ||
| 350 | lsh = LSH, | ||
| 351 | rsh = RSH, | ||
| 352 | neg = NEG, | ||
| 353 | mod = MOD, | ||
| 354 | xor = XOR, | ||
| 355 | mov = MOV, | ||
| 356 | }; | ||
| 357 | |||
| 358 | pub const Size = packed enum(u8) { | ||
| 359 | byte = B, | ||
| 360 | half_word = H, | ||
| 361 | word = W, | ||
| 362 | double_word = DW, | ||
| 363 | }; | ||
| 364 | |||
| 365 | const JmpOp = packed enum(u8) { | ||
| 366 | ja = JA, | ||
| 367 | jeq = JEQ, | ||
| 368 | jgt = JGT, | ||
| 369 | jge = JGE, | ||
| 370 | jset = JSET, | ||
| 371 | }; | ||
| 372 | |||
| 373 | const ImmOrReg = union(Source) { | ||
| 374 | imm: i32, | ||
| 375 | reg: Reg, | ||
| 376 | }; | ||
| 377 | |||
| 378 | fn imm_reg(code: u8, dst: Reg, src: anytype, off: i16) Insn { | ||
| 379 | const imm_or_reg = if (@typeInfo(@TypeOf(src)) == .EnumLiteral) | ||
| 380 | ImmOrReg{ .reg = @as(Reg, src) } | ||
| 381 | else | ||
| 382 | ImmOrReg{ .imm = src }; | ||
| 383 | |||
| 384 | const src_type = switch (imm_or_reg) { | ||
| 385 | .imm => K, | ||
| 386 | .reg => X, | ||
| 387 | }; | ||
| 388 | |||
| 389 | return Insn{ | ||
| 390 | .code = code | src_type, | ||
| 391 | .dst = @enumToInt(dst), | ||
| 392 | .src = switch (imm_or_reg) { | ||
| 393 | .imm => 0, | ||
| 394 | .reg => |r| @enumToInt(r), | ||
| 395 | }, | ||
| 396 | .off = off, | ||
| 397 | .imm = switch (imm_or_reg) { | ||
| 398 | .imm => |i| i, | ||
| 399 | .reg => 0, | ||
| 400 | }, | ||
| 401 | }; | ||
| 402 | } | ||
| 403 | |||
| 404 | fn alu(comptime width: comptime_int, op: AluOp, dst: Reg, src: anytype) Insn { | ||
| 405 | const width_bitfield = switch (width) { | ||
| 406 | 32 => ALU, | ||
| 407 | 64 => ALU64, | ||
| 408 | else => @compileError("width must be 32 or 64"), | ||
| 409 | }; | ||
| 410 | |||
| 411 | return imm_reg(width_bitfield | @enumToInt(op), dst, src, 0); | ||
| 412 | } | ||
| 413 | |||
| 414 | pub fn mov(dst: Reg, src: anytype) Insn { | ||
| 415 | return alu(64, .mov, dst, src); | ||
| 416 | } | ||
| 417 | |||
| 418 | pub fn add(dst: Reg, src: anytype) Insn { | ||
| 419 | return alu(64, .add, dst, src); | ||
| 420 | } | ||
| 421 | |||
| 422 | fn jmp(op: JmpOp, dst: Reg, src: anytype, off: i16) Insn { | ||
| 423 | return imm_reg(JMP | @enumToInt(op), dst, src, off); | ||
| 424 | } | ||
| 425 | |||
| 426 | pub fn jeq(dst: Reg, src: anytype, off: i16) Insn { | ||
| 427 | return jmp(.jeq, dst, src, off); | ||
| 428 | } | ||
| 429 | |||
| 430 | pub fn stx_mem(size: Size, dst: Reg, src: Reg, off: i16) Insn { | ||
| 431 | return Insn{ | ||
| 432 | .code = STX | @enumToInt(size) | MEM, | ||
| 433 | .dst = @enumToInt(dst), | ||
| 434 | .src = @enumToInt(src), | ||
| 435 | .off = off, | ||
| 436 | .imm = 0, | ||
| 437 | }; | ||
| 438 | } | ||
| 439 | |||
| 440 | pub fn xadd(dst: Reg, src: Reg) Insn { | ||
| 441 | return Insn{ | ||
| 442 | .code = STX | XADD | DW, | ||
| 443 | .dst = @enumToInt(dst), | ||
| 444 | .src = @enumToInt(src), | ||
| 445 | .off = 0, | ||
| 446 | .imm = 0, | ||
| 447 | }; | ||
| 448 | } | ||
| 449 | |||
| 450 | /// direct packet access, R0 = *(uint *)(skb->data + imm32) | ||
| 451 | pub fn ld_abs(size: Size, imm: i32) Insn { | ||
| 452 | return Insn{ | ||
| 453 | .code = LD | @enumToInt(size) | ABS, | ||
| 454 | .dst = 0, | ||
| 455 | .src = 0, | ||
| 456 | .off = 0, | ||
| 457 | .imm = imm, | ||
| 458 | }; | ||
| 459 | } | ||
| 460 | |||
| 461 | fn ld_imm_impl1(dst: Reg, src: Reg, imm: u64) Insn { | ||
| 462 | return Insn{ | ||
| 463 | .code = LD | DW | IMM, | ||
| 464 | .dst = @enumToInt(dst), | ||
| 465 | .src = @enumToInt(src), | ||
| 466 | .off = 0, | ||
| 467 | .imm = @intCast(i32, @truncate(u32, imm)), | ||
| 468 | }; | ||
| 469 | } | ||
| 470 | |||
| 471 | fn ld_imm_impl2(imm: u64) Insn { | ||
| 472 | return Insn{ | ||
| 473 | .code = 0, | ||
| 474 | .dst = 0, | ||
| 475 | .src = 0, | ||
| 476 | .off = 0, | ||
| 477 | .imm = @intCast(i32, @truncate(u32, imm >> 32)), | ||
| 478 | }; | ||
| 479 | } | ||
| 480 | |||
| 481 | pub fn ld_map_fd1(dst: Reg, map_fd: fd_t) Insn { | ||
| 482 | return ld_imm_impl1(dst, @intToEnum(Reg, PSEUDO_MAP_FD), @intCast(u64, map_fd)); | ||
| 483 | } | ||
| 484 | |||
| 485 | pub fn ld_map_fd2(map_fd: fd_t) Insn { | ||
| 486 | return ld_imm_impl2(@intCast(u64, map_fd)); | ||
| 487 | } | ||
| 488 | |||
| 489 | pub fn call(helper: Helper) Insn { | ||
| 490 | return Insn{ | ||
| 491 | .code = JMP | CALL, | ||
| 492 | .dst = 0, | ||
| 493 | .src = 0, | ||
| 494 | .off = 0, | ||
| 495 | .imm = @enumToInt(helper), | ||
| 496 | }; | ||
| 497 | } | ||
| 498 | |||
| 499 | /// exit BPF program | ||
| 500 | pub fn exit() Insn { | ||
| 501 | return Insn{ | ||
| 502 | .code = JMP | EXIT, | ||
| 503 | .dst = 0, | ||
| 504 | .src = 0, | ||
| 505 | .off = 0, | ||
| 506 | .imm = 0, | ||
| 507 | }; | ||
| 508 | } | ||
| 509 | }; | ||
| 510 | |||
| 511 | fn expect_insn(insn: Insn, val: u64) void { | ||
| 512 | expectEqual(@bitCast(u64, insn), val); | ||
| 513 | } | ||
| 514 | |||
| 515 | test "insn bitsize" { | ||
| 516 | expectEqual(@bitSizeOf(Insn), 64); | ||
| 517 | } | ||
| 518 | |||
| 519 | // mov instructions | ||
| 520 | test "mov imm" { | ||
| 521 | expect_insn(Insn.mov(.r1, 1), 0x00000001000001b7); | ||
| 522 | } | ||
| 523 | |||
| 524 | test "mov reg" { | ||
| 525 | expect_insn(Insn.mov(.r6, .r1), 0x00000000000016bf); | ||
| 526 | } | ||
| 527 | |||
| 528 | // alu instructions | ||
| 529 | test "add imm" { | ||
| 530 | expect_insn(Insn.add(.r2, -4), 0xfffffffc00000207); | ||
| 531 | } | ||
| 532 | |||
| 533 | // ld instructions | ||
| 534 | test "ld_abs" { | ||
| 535 | expect_insn(Insn.ld_abs(.byte, 42), 0x0000002a00000030); | ||
| 536 | } | ||
| 537 | |||
| 538 | test "ld_map_fd" { | ||
| 539 | expect_insn(Insn.ld_map_fd1(.r1, 42), 0x0000002a00001118); | ||
| 540 | expect_insn(Insn.ld_map_fd2(42), 0x0000000000000000); | ||
| 541 | } | ||
| 542 | |||
| 543 | // st instructions | ||
| 544 | test "stx_mem" { | ||
| 545 | expect_insn(Insn.stx_mem(.word, .r10, .r0, -4), 0x00000000fffc0a63); | ||
| 546 | } | ||
| 547 | |||
| 548 | test "xadd" { | ||
| 549 | expect_insn(Insn.xadd(.r0, .r1), 0x00000000000010db); | ||
| 550 | } | ||
| 551 | |||
| 552 | // jmp instructions | ||
| 553 | test "jeq imm" { | ||
| 554 | expect_insn(Insn.jeq(.r0, 0, 2), 0x0000000000020015); | ||
| 555 | } | ||
| 556 | |||
| 557 | // other instructions | ||
| 558 | test "call" { | ||
| 559 | expect_insn(Insn.call(.map_lookup_elem), 0x0000000100000085); | ||
| 560 | } | ||
| 561 | |||
| 562 | test "exit" { | ||
| 563 | expect_insn(Insn.exit(), 0x0000000000000095); | ||
| 564 | } | ||
| 565 | |||
| 566 | pub const Cmd = extern enum(usize) { | ||
| 567 | map_create, | ||
| 568 | map_lookup_elem, | ||
| 569 | map_update_elem, | ||
| 570 | map_delete_elem, | ||
| 571 | map_get_next_key, | ||
| 572 | prog_load, | ||
| 573 | obj_pin, | ||
| 574 | obj_get, | ||
| 575 | prog_attach, | ||
| 576 | prog_detach, | ||
| 577 | prog_test_run, | ||
| 578 | prog_get_next_id, | ||
| 579 | map_get_next_id, | ||
| 580 | prog_get_fd_by_id, | ||
| 581 | map_get_fd_by_id, | ||
| 582 | obj_get_info_by_fd, | ||
| 583 | prog_query, | ||
| 584 | raw_tracepoint_open, | ||
| 585 | btf_load, | ||
| 586 | btf_get_fd_by_id, | ||
| 587 | task_fd_query, | ||
| 588 | map_lookup_and_delete_elem, | ||
| 589 | map_freeze, | ||
| 590 | btf_get_next_id, | ||
| 591 | map_lookup_batch, | ||
| 592 | map_lookup_and_delete_batch, | ||
| 593 | map_update_batch, | ||
| 594 | map_delete_batch, | ||
| 595 | link_create, | ||
| 596 | link_update, | ||
| 597 | link_get_fd_by_id, | ||
| 598 | link_get_next_id, | ||
| 599 | enable_stats, | ||
| 600 | iter_create, | ||
| 601 | link_detach, | ||
| 602 | _, | ||
| 603 | }; | ||
| 604 | |||
| 605 | pub const MapType = extern enum(u32) { | ||
| 606 | unspec, | ||
| 607 | hash, | ||
| 608 | array, | ||
| 609 | prog_array, | ||
| 610 | perf_event_array, | ||
| 611 | percpu_hash, | ||
| 612 | percpu_array, | ||
| 613 | stack_trace, | ||
| 614 | cgroup_array, | ||
| 615 | lru_hash, | ||
| 616 | lru_percpu_hash, | ||
| 617 | lpm_trie, | ||
| 618 | array_of_maps, | ||
| 619 | hash_of_maps, | ||
| 620 | devmap, | ||
| 621 | sockmap, | ||
| 622 | cpumap, | ||
| 623 | xskmap, | ||
| 624 | sockhash, | ||
| 625 | cgroup_storage, | ||
| 626 | reuseport_sockarray, | ||
| 627 | percpu_cgroup_storage, | ||
| 628 | queue, | ||
| 629 | stack, | ||
| 630 | sk_storage, | ||
| 631 | devmap_hash, | ||
| 632 | struct_ops, | ||
| 633 | ringbuf, | ||
| 634 | _, | ||
| 635 | }; | ||
| 636 | |||
| 637 | pub const ProgType = extern enum(u32) { | ||
| 638 | unspec, | ||
| 639 | socket_filter, | ||
| 640 | kprobe, | ||
| 641 | sched_cls, | ||
| 642 | sched_act, | ||
| 643 | tracepoint, | ||
| 644 | xdp, | ||
| 645 | perf_event, | ||
| 646 | cgroup_skb, | ||
| 647 | cgroup_sock, | ||
| 648 | lwt_in, | ||
| 649 | lwt_out, | ||
| 650 | lwt_xmit, | ||
| 651 | sock_ops, | ||
| 652 | sk_skb, | ||
| 653 | cgroup_device, | ||
| 654 | sk_msg, | ||
| 655 | raw_tracepoint, | ||
| 656 | cgroup_sock_addr, | ||
| 657 | lwt_seg6local, | ||
| 658 | lirc_mode2, | ||
| 659 | sk_reuseport, | ||
| 660 | flow_dissector, | ||
| 661 | cgroup_sysctl, | ||
| 662 | raw_tracepoint_writable, | ||
| 663 | cgroup_sockopt, | ||
| 664 | tracing, | ||
| 665 | struct_ops, | ||
| 666 | ext, | ||
| 667 | lsm, | ||
| 668 | sk_lookup, | ||
| 669 | }; | ||
| 670 | |||
| 671 | pub const AttachType = extern enum(u32) { | ||
| 672 | cgroup_inet_ingress, | ||
| 673 | cgroup_inet_egress, | ||
| 674 | cgroup_inet_sock_create, | ||
| 675 | cgroup_sock_ops, | ||
| 676 | sk_skb_stream_parser, | ||
| 677 | sk_skb_stream_verdict, | ||
| 678 | cgroup_device, | ||
| 679 | sk_msg_verdict, | ||
| 680 | cgroup_inet4_bind, | ||
| 681 | cgroup_inet6_bind, | ||
| 682 | cgroup_inet4_connect, | ||
| 683 | cgroup_inet6_connect, | ||
| 684 | cgroup_inet4_post_bind, | ||
| 685 | cgroup_inet6_post_bind, | ||
| 686 | cgroup_udp4_sendmsg, | ||
| 687 | cgroup_udp6_sendmsg, | ||
| 688 | lirc_mode2, | ||
| 689 | flow_dissector, | ||
| 690 | cgroup_sysctl, | ||
| 691 | cgroup_udp4_recvmsg, | ||
| 692 | cgroup_udp6_recvmsg, | ||
| 693 | cgroup_getsockopt, | ||
| 694 | cgroup_setsockopt, | ||
| 695 | trace_raw_tp, | ||
| 696 | trace_fentry, | ||
| 697 | trace_fexit, | ||
| 698 | modify_return, | ||
| 699 | lsm_mac, | ||
| 700 | trace_iter, | ||
| 701 | cgroup_inet4_getpeername, | ||
| 702 | cgroup_inet6_getpeername, | ||
| 703 | cgroup_inet4_getsockname, | ||
| 704 | cgroup_inet6_getsockname, | ||
| 705 | xdp_devmap, | ||
| 706 | cgroup_inet_sock_release, | ||
| 707 | xdp_cpumap, | ||
| 708 | sk_lookup, | ||
| 709 | xdp, | ||
| 710 | _, | ||
| 711 | }; | ||
| 712 | |||
| 713 | const obj_name_len = 16; | ||
| 714 | /// struct used by Cmd.map_create command | ||
| 715 | pub const MapCreateAttr = extern struct { | ||
| 716 | /// one of MapType | ||
| 717 | map_type: u32, | ||
| 718 | /// size of key in bytes | ||
| 719 | key_size: u32, | ||
| 720 | /// size of value in bytes | ||
| 721 | value_size: u32, | ||
| 722 | /// max number of entries in a map | ||
| 723 | max_entries: u32, | ||
| 724 | /// .map_create related flags | ||
| 725 | map_flags: u32, | ||
| 726 | /// fd pointing to the inner map | ||
| 727 | inner_map_fd: fd_t, | ||
| 728 | /// numa node (effective only if MapCreateFlags.numa_node is set) | ||
| 729 | numa_node: u32, | ||
| 730 | map_name: [obj_name_len]u8, | ||
| 731 | /// ifindex of netdev to create on | ||
| 732 | map_ifindex: u32, | ||
| 733 | /// fd pointing to a BTF type data | ||
| 734 | btf_fd: fd_t, | ||
| 735 | /// BTF type_id of the key | ||
| 736 | btf_key_type_id: u32, | ||
| 737 | /// BTF type_id of the value | ||
| 738 | bpf_value_type_id: u32, | ||
| 739 | /// BTF type_id of a kernel struct stored as the map value | ||
| 740 | btf_vmlinux_value_type_id: u32, | ||
| 741 | }; | ||
| 742 | |||
| 743 | /// struct used by Cmd.map_*_elem commands | ||
| 744 | pub const MapElemAttr = extern struct { | ||
| 745 | map_fd: fd_t, | ||
| 746 | key: u64, | ||
| 747 | result: extern union { | ||
| 748 | value: u64, | ||
| 749 | next_key: u64, | ||
| 750 | }, | ||
| 751 | flags: u64, | ||
| 752 | }; | ||
| 753 | |||
| 754 | /// struct used by Cmd.map_*_batch commands | ||
| 755 | pub const MapBatchAttr = extern struct { | ||
| 756 | /// start batch, NULL to start from beginning | ||
| 757 | in_batch: u64, | ||
| 758 | /// output: next start batch | ||
| 759 | out_batch: u64, | ||
| 760 | keys: u64, | ||
| 761 | values: u64, | ||
| 762 | /// input/output: | ||
| 763 | /// input: # of key/value elements | ||
| 764 | /// output: # of filled elements | ||
| 765 | count: u32, | ||
| 766 | map_fd: fd_t, | ||
| 767 | elem_flags: u64, | ||
| 768 | flags: u64, | ||
| 769 | }; | ||
| 770 | |||
| 771 | /// struct used by Cmd.prog_load command | ||
| 772 | pub const ProgLoadAttr = extern struct { | ||
| 773 | /// one of ProgType | ||
| 774 | prog_type: u32, | ||
| 775 | insn_cnt: u32, | ||
| 776 | insns: u64, | ||
| 777 | license: u64, | ||
| 778 | /// verbosity level of verifier | ||
| 779 | log_level: u32, | ||
| 780 | /// size of user buffer | ||
| 781 | log_size: u32, | ||
| 782 | /// user supplied buffer | ||
| 783 | log_buf: u64, | ||
| 784 | /// not used | ||
| 785 | kern_version: u32, | ||
| 786 | prog_flags: u32, | ||
| 787 | prog_name: [obj_name_len]u8, | ||
| 788 | /// ifindex of netdev to prep for. For some prog types expected attach | ||
| 789 | /// type must be known at load time to verify attach type specific parts | ||
| 790 | /// of prog (context accesses, allowed helpers, etc). | ||
| 791 | prog_ifindex: u32, | ||
| 792 | expected_attach_type: u32, | ||
| 793 | /// fd pointing to BTF type data | ||
| 794 | prog_btf_fd: fd_t, | ||
| 795 | /// userspace bpf_func_info size | ||
| 796 | func_info_rec_size: u32, | ||
| 797 | func_info: u64, | ||
| 798 | /// number of bpf_func_info records | ||
| 799 | func_info_cnt: u32, | ||
| 800 | /// userspace bpf_line_info size | ||
| 801 | line_info_rec_size: u32, | ||
| 802 | line_info: u64, | ||
| 803 | /// number of bpf_line_info records | ||
| 804 | line_info_cnt: u32, | ||
| 805 | /// in-kernel BTF type id to attach to | ||
| 806 | attact_btf_id: u32, | ||
| 807 | /// 0 to attach to vmlinux | ||
| 808 | attach_prog_id: u32, | ||
| 809 | }; | ||
| 810 | |||
| 811 | /// struct used by Cmd.obj_* commands | ||
| 812 | pub const ObjAttr = extern struct { | ||
| 813 | pathname: u64, | ||
| 814 | bpf_fd: fd_t, | ||
| 815 | file_flags: u32, | ||
| 816 | }; | ||
| 817 | |||
| 818 | /// struct used by Cmd.prog_attach/detach commands | ||
| 819 | pub const ProgAttachAttr = extern struct { | ||
| 820 | /// container object to attach to | ||
| 821 | target_fd: fd_t, | ||
| 822 | /// eBPF program to attach | ||
| 823 | attach_bpf_fd: fd_t, | ||
| 824 | attach_type: u32, | ||
| 825 | attach_flags: u32, | ||
| 826 | // TODO: BPF_F_REPLACE flags | ||
| 827 | /// previously attached eBPF program to replace if .replace is used | ||
| 828 | replace_bpf_fd: fd_t, | ||
| 829 | }; | ||
| 830 | |||
| 831 | /// struct used by Cmd.prog_test_run command | ||
| 832 | pub const TestAttr = extern struct { | ||
| 833 | prog_fd: fd_t, | ||
| 834 | retval: u32, | ||
| 835 | /// input: len of data_in | ||
| 836 | data_size_in: u32, | ||
| 837 | /// input/output: len of data_out. returns ENOSPC if data_out is too small. | ||
| 838 | data_size_out: u32, | ||
| 839 | data_in: u64, | ||
| 840 | data_out: u64, | ||
| 841 | repeat: u32, | ||
| 842 | duration: u32, | ||
| 843 | /// input: len of ctx_in | ||
| 844 | ctx_size_in: u32, | ||
| 845 | /// input/output: len of ctx_out. returns ENOSPC if ctx_out is too small. | ||
| 846 | ctx_size_out: u32, | ||
| 847 | ctx_in: u64, | ||
| 848 | ctx_out: u64, | ||
| 849 | }; | ||
| 850 | |||
| 851 | /// struct used by Cmd.*_get_*_id commands | ||
| 852 | pub const GetIdAttr = extern struct { | ||
| 853 | id: extern union { | ||
| 854 | start_id: u32, | ||
| 855 | prog_id: u32, | ||
| 856 | map_id: u32, | ||
| 857 | btf_id: u32, | ||
| 858 | link_id: u32, | ||
| 859 | }, | ||
| 860 | next_id: u32, | ||
| 861 | open_flags: u32, | ||
| 862 | }; | ||
| 863 | |||
| 864 | /// struct used by Cmd.obj_get_info_by_fd command | ||
| 865 | pub const InfoAttr = extern struct { | ||
| 866 | bpf_fd: fd_t, | ||
| 867 | info_len: u32, | ||
| 868 | info: u64, | ||
| 869 | }; | ||
| 870 | |||
| 871 | /// struct used by Cmd.prog_query command | ||
| 872 | pub const QueryAttr = extern struct { | ||
| 873 | /// container object to query | ||
| 874 | target_fd: fd_t, | ||
| 875 | attach_type: u32, | ||
| 876 | query_flags: u32, | ||
| 877 | attach_flags: u32, | ||
| 878 | prog_ids: u64, | ||
| 879 | prog_cnt: u32, | ||
| 880 | }; | ||
| 881 | |||
| 882 | /// struct used by Cmd.raw_tracepoint_open command | ||
| 883 | pub const RawTracepointAttr = extern struct { | ||
| 884 | name: u64, | ||
| 885 | prog_fd: fd_t, | ||
| 886 | }; | ||
| 887 | |||
| 888 | /// struct used by Cmd.btf_load command | ||
| 889 | pub const BtfLoadAttr = extern struct { | ||
| 890 | btf: u64, | ||
| 891 | btf_log_buf: u64, | ||
| 892 | btf_size: u32, | ||
| 893 | btf_log_size: u32, | ||
| 894 | btf_log_level: u32, | ||
| 895 | }; | ||
| 896 | |||
| 897 | pub const TaskFdQueryAttr = extern struct { | ||
| 898 | /// input: pid | ||
| 899 | pid: pid_t, | ||
| 900 | /// input: fd | ||
| 901 | fd: fd_t, | ||
| 902 | /// input: flags | ||
| 903 | flags: u32, | ||
| 904 | /// input/output: buf len | ||
| 905 | buf_len: u32, | ||
| 906 | /// input/output: | ||
| 907 | /// tp_name for tracepoint | ||
| 908 | /// symbol for kprobe | ||
| 909 | /// filename for uprobe | ||
| 910 | buf: u64, | ||
| 911 | /// output: prod_id | ||
| 912 | prog_id: u32, | ||
| 913 | /// output: BPF_FD_TYPE | ||
| 914 | fd_type: u32, | ||
| 915 | /// output: probe_offset | ||
| 916 | probe_offset: u64, | ||
| 917 | /// output: probe_addr | ||
| 918 | probe_addr: u64, | ||
| 919 | }; | ||
| 920 | |||
| 921 | /// struct used by Cmd.link_create command | ||
| 922 | pub const LinkCreateAttr = extern struct { | ||
| 923 | /// eBPF program to attach | ||
| 924 | prog_fd: fd_t, | ||
| 925 | /// object to attach to | ||
| 926 | target_fd: fd_t, | ||
| 927 | attach_type: u32, | ||
| 928 | /// extra flags | ||
| 929 | flags: u32, | ||
| 930 | }; | ||
| 931 | |||
| 932 | /// struct used by Cmd.link_update command | ||
| 933 | pub const LinkUpdateAttr = extern struct { | ||
| 934 | link_fd: fd_t, | ||
| 935 | /// new program to update link with | ||
| 936 | new_prog_fd: fd_t, | ||
| 937 | /// extra flags | ||
| 938 | flags: u32, | ||
| 939 | /// expected link's program fd, it is specified only if BPF_F_REPLACE is | ||
| 940 | /// set in flags | ||
| 941 | old_prog_fd: fd_t, | ||
| 942 | }; | ||
| 943 | |||
| 944 | /// struct used by Cmd.enable_stats command | ||
| 945 | pub const EnableStatsAttr = extern struct { | ||
| 946 | type: u32, | ||
| 947 | }; | ||
| 948 | |||
| 949 | /// struct used by Cmd.iter_create command | ||
| 950 | pub const IterCreateAttr = extern struct { | ||
| 951 | link_fd: fd_t, | ||
| 952 | flags: u32, | ||
| 953 | }; | ||
| 954 | |||
| 955 | pub const Attr = extern union { | ||
| 956 | map_create: MapCreateAttr, | ||
| 957 | map_elem: MapElemAttr, | ||
| 958 | map_batch: MapBatchAttr, | ||
| 959 | prog_load: ProgLoadAttr, | ||
| 960 | obj: ObjAttr, | ||
| 961 | prog_attach: ProgAttachAttr, | ||
| 962 | test_run: TestRunAttr, | ||
| 963 | get_id: GetIdAttr, | ||
| 964 | info: InfoAttr, | ||
| 965 | query: QueryAttr, | ||
| 966 | raw_tracepoint: RawTracepointAttr, | ||
| 967 | btf_load: BtfLoadAttr, | ||
| 968 | task_fd_query: TaskFdQueryAttr, | ||
| 969 | link_create: LinkCreateAttr, | ||
| 970 | link_update: LinkUpdateAttr, | ||
| 971 | enable_stats: EnableStatsAttr, | ||
| 972 | iter_create: IterCreateAttr, | ||
| 973 | }; | ||