ebpf/
api.rs

1// Copyright 2024 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
6
7/// The stack size in bytes
8pub const BPF_STACK_SIZE: usize = 512;
9
10/// The maximum number of instructions in an ebpf program
11pub const BPF_MAX_INSTS: usize = 65536;
12
13/// The number of registers
14pub const REGISTER_COUNT: u8 = 11;
15
16/// The number of general r/w registers.
17pub const GENERAL_REGISTER_COUNT: u8 = 10;
18
19#[derive(Clone, Copy, Debug, Eq, PartialEq)]
20pub enum DataWidth {
21    U8,
22    U16,
23    U32,
24    U64,
25}
26
27/// The different data width used by ebpf
28impl DataWidth {
29    pub fn bits(&self) -> usize {
30        match self {
31            Self::U8 => 8,
32            Self::U16 => 16,
33            Self::U32 => 32,
34            Self::U64 => 64,
35        }
36    }
37
38    pub fn bytes(&self) -> usize {
39        match self {
40            Self::U8 => 1,
41            Self::U16 => 2,
42            Self::U32 => 4,
43            Self::U64 => 8,
44        }
45    }
46
47    pub fn str(&self) -> &'static str {
48        match self {
49            Self::U8 => "b",
50            Self::U16 => "h",
51            Self::U32 => "w",
52            Self::U64 => "dw",
53        }
54    }
55
56    pub fn instruction_bits(&self) -> u8 {
57        match self {
58            Self::U8 => BPF_B,
59            Self::U16 => BPF_H,
60            Self::U32 => BPF_W,
61            Self::U64 => BPF_DW,
62        }
63    }
64}
65
66/// Represents a single eBPF instruction. The internal layout matches the
67/// layout of the `bpf_insn` struct in `linux_uapi`. It's used instead of
68/// `bpf_insn` as it allows more efficient access to `dst_reg` and `src_reg`
69/// fields compared to the accessors generated by bindgen.
70#[repr(transparent)]
71#[derive(Copy, Clone, Eq, PartialEq, FromBytes, IntoBytes, KnownLayout, Immutable)]
72pub struct EbpfInstruction(u64);
73
74impl std::fmt::Debug for EbpfInstruction {
75    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
76        f.debug_struct("EbpfInstruction")
77            .field("code", &self.code())
78            .field("dst", &self.dst_reg())
79            .field("src", &self.src_reg())
80            .field("offset", &self.offset())
81            .field("imm", &self.imm())
82            .finish()
83    }
84}
85
86impl From<u64> for EbpfInstruction {
87    fn from(value: u64) -> Self {
88        Self(value)
89    }
90}
91
92// This implementation is valid only on little-endian architectures.
93#[cfg(target_endian = "little")]
94impl EbpfInstruction {
95    pub fn new(code: u8, dst: u8, src: u8, offset: i16, imm: i32) -> Self {
96        assert!(dst < 16);
97        assert!(src < 16);
98
99        Self(
100            (code as u64)
101                | (dst as u64) << 8
102                | (src as u64) << 12
103                | (offset as u16 as u64) << 16
104                | (imm as u32 as u64) << 32,
105        )
106    }
107
108    #[inline(always)]
109    pub fn code(&self) -> u8 {
110        self.0 as u8
111    }
112
113    pub fn set_code(&mut self, code: u8) {
114        *self = EbpfInstruction((self.0 & !0x00ff) | code as u64)
115    }
116
117    #[inline(always)]
118    pub fn dst_reg(&self) -> u8 {
119        ((self.0 & 0x0f00) >> 8) as u8
120    }
121
122    pub fn set_dst_reg(&mut self, dst_reg: u8) {
123        assert!(dst_reg < 16);
124        *self = EbpfInstruction((self.0 & !0x0f00) | ((dst_reg as u64) << 8))
125    }
126
127    #[inline(always)]
128    pub fn src_reg(&self) -> u8 {
129        ((self.0 & 0xf000) >> 12) as u8
130    }
131
132    pub fn set_src_reg(&mut self, src_reg: u8) {
133        assert!(src_reg < 16);
134        *self = EbpfInstruction((self.0 & !0xf000) | ((src_reg as u64) << 12))
135    }
136
137    #[inline(always)]
138    pub fn offset(&self) -> i16 {
139        (self.0 >> 16) as u16 as i16
140    }
141
142    pub fn set_offset(&mut self, offset: i16) {
143        *self = EbpfInstruction((self.0 & !0xffff_0000) | ((offset as u16 as u64) << 16))
144    }
145
146    #[inline(always)]
147    pub fn imm(&self) -> i32 {
148        (self.0 >> 32 as u32) as i32
149    }
150
151    pub fn set_imm(&mut self, imm: i32) {
152        *self = EbpfInstruction((self.0 & 0xffff_ffff) | ((imm as u32 as u64) << 32))
153    }
154}
155
156// The different operation types
157pub const BPF_LD: u8 = linux_uapi::BPF_LD as u8;
158pub const BPF_LDX: u8 = linux_uapi::BPF_LDX as u8;
159pub const BPF_ST: u8 = linux_uapi::BPF_ST as u8;
160pub const BPF_STX: u8 = linux_uapi::BPF_STX as u8;
161pub const BPF_ALU: u8 = linux_uapi::BPF_ALU as u8;
162pub const BPF_JMP: u8 = linux_uapi::BPF_JMP as u8;
163pub const BPF_JMP32: u8 = linux_uapi::BPF_JMP32 as u8;
164pub const BPF_ALU64: u8 = linux_uapi::BPF_ALU64 as u8;
165pub const BPF_CLS_MASK: u8 =
166    BPF_LD | BPF_LDX | BPF_ST | BPF_STX | BPF_ALU | BPF_JMP | BPF_JMP | BPF_JMP32 | BPF_ALU64;
167
168// The mask for the sub operation
169pub const BPF_SUB_OP_MASK: u8 = 0xf0;
170
171// The mask for the imm vs src register
172pub const BPF_SRC_REG: u8 = linux_uapi::BPF_X as u8;
173pub const BPF_SRC_IMM: u8 = linux_uapi::BPF_K as u8;
174pub const BPF_SRC_MASK: u8 = BPF_SRC_REG | BPF_SRC_IMM;
175
176// The mods for the load/store
177// The instruction code for immediate loads
178pub const BPF_IMM: u8 = linux_uapi::BPF_IMM as u8;
179pub const BPF_MEM: u8 = linux_uapi::BPF_MEM as u8;
180pub const BPF_ATOMIC: u8 = linux_uapi::BPF_ATOMIC as u8;
181pub const BPF_ABS: u8 = linux_uapi::BPF_ABS as u8;
182pub const BPF_IND: u8 = linux_uapi::BPF_IND as u8;
183pub const BPF_LOAD_STORE_MASK: u8 = BPF_IMM | BPF_MEM | BPF_ATOMIC | BPF_ABS | BPF_IND;
184
185// The mask for the swap operations
186pub const BPF_TO_BE: u8 = linux_uapi::BPF_TO_BE as u8;
187pub const BPF_TO_LE: u8 = linux_uapi::BPF_TO_LE as u8;
188pub const BPF_END_TYPE_MASK: u8 = BPF_TO_BE | BPF_TO_LE;
189
190// The different size value
191pub const BPF_B: u8 = linux_uapi::BPF_B as u8;
192pub const BPF_H: u8 = linux_uapi::BPF_H as u8;
193pub const BPF_W: u8 = linux_uapi::BPF_W as u8;
194pub const BPF_DW: u8 = linux_uapi::BPF_DW as u8;
195pub const BPF_SIZE_MASK: u8 = BPF_B | BPF_H | BPF_W | BPF_DW;
196
197// The different alu operations
198pub const BPF_ADD: u8 = linux_uapi::BPF_ADD as u8;
199pub const BPF_SUB: u8 = linux_uapi::BPF_SUB as u8;
200pub const BPF_MUL: u8 = linux_uapi::BPF_MUL as u8;
201pub const BPF_DIV: u8 = linux_uapi::BPF_DIV as u8;
202pub const BPF_OR: u8 = linux_uapi::BPF_OR as u8;
203pub const BPF_AND: u8 = linux_uapi::BPF_AND as u8;
204pub const BPF_LSH: u8 = linux_uapi::BPF_LSH as u8;
205pub const BPF_RSH: u8 = linux_uapi::BPF_RSH as u8;
206pub const BPF_NEG: u8 = linux_uapi::BPF_NEG as u8;
207pub const BPF_MOD: u8 = linux_uapi::BPF_MOD as u8;
208pub const BPF_XOR: u8 = linux_uapi::BPF_XOR as u8;
209pub const BPF_MOV: u8 = linux_uapi::BPF_MOV as u8;
210pub const BPF_ARSH: u8 = linux_uapi::BPF_ARSH as u8;
211pub const BPF_END: u8 = linux_uapi::BPF_END as u8;
212
213// The different jump operation
214pub const BPF_JA: u8 = linux_uapi::BPF_JA as u8;
215pub const BPF_JEQ: u8 = linux_uapi::BPF_JEQ as u8;
216pub const BPF_JGT: u8 = linux_uapi::BPF_JGT as u8;
217pub const BPF_JGE: u8 = linux_uapi::BPF_JGE as u8;
218pub const BPF_JSET: u8 = linux_uapi::BPF_JSET as u8;
219pub const BPF_JNE: u8 = linux_uapi::BPF_JNE as u8;
220pub const BPF_JSGT: u8 = linux_uapi::BPF_JSGT as u8;
221pub const BPF_JSGE: u8 = linux_uapi::BPF_JSGE as u8;
222pub const BPF_CALL: u8 = linux_uapi::BPF_CALL as u8;
223pub const BPF_EXIT: u8 = linux_uapi::BPF_EXIT as u8;
224pub const BPF_JLT: u8 = linux_uapi::BPF_JLT as u8;
225pub const BPF_JLE: u8 = linux_uapi::BPF_JLE as u8;
226pub const BPF_JSLT: u8 = linux_uapi::BPF_JSLT as u8;
227pub const BPF_JSLE: u8 = linux_uapi::BPF_JSLE as u8;
228
229// Specific atomic operation
230pub const BPF_FETCH: u8 = linux_uapi::BPF_FETCH as u8;
231pub const BPF_XCHG: u8 = linux_uapi::BPF_XCHG as u8;
232pub const BPF_CMPXCHG: u8 = linux_uapi::BPF_CMPXCHG as u8;
233
234// The load double operation that allows to write 64 bits into a register.
235pub const BPF_LDDW: u8 = BPF_LD | BPF_DW;
236
237// cBPF-specific constants.
238pub const BPF_LEN: u8 = linux_uapi::BPF_LEN as u8;
239pub const BPF_MISC: u8 = linux_uapi::BPF_MISC as u8;
240pub const BPF_RET: u8 = linux_uapi::BPF_RET as u8;
241pub const BPF_MSH: u8 = linux_uapi::BPF_MSH as u8;
242pub const BPF_A: u8 = linux_uapi::BPF_A as u8;
243pub const BPF_K: u8 = linux_uapi::BPF_K as u8;
244pub const BPF_X: u8 = linux_uapi::BPF_X as u8;
245pub const BPF_TXA: u8 = linux_uapi::BPF_TXA as u8;
246pub const BPF_TAX: u8 = linux_uapi::BPF_TAX as u8;
247
248// Values that can be used in src reg with the `ldimm64`. These instructions
249// should be updated when the program is linked.
250pub const BPF_PSEUDO_MAP_FD: u8 = linux_uapi::BPF_PSEUDO_MAP_FD as u8;
251pub const BPF_PSEUDO_MAP_IDX: u8 = linux_uapi::BPF_PSEUDO_MAP_IDX as u8;
252pub const BPF_PSEUDO_MAP_VALUE: u8 = linux_uapi::BPF_PSEUDO_MAP_VALUE as u8;
253pub const BPF_PSEUDO_MAP_IDX_VALUE: u8 = linux_uapi::BPF_PSEUDO_MAP_IDX_VALUE as u8;
254pub const BPF_PSEUDO_BTF_ID: u8 = linux_uapi::BPF_PSEUDO_BTF_ID as u8;
255pub const BPF_PSEUDO_FUNC: u8 = linux_uapi::BPF_PSEUDO_FUNC as u8;
256
257// Values that can be used in src reg with the `call` instruction. These
258// instructions should be updated when the program is linked.
259pub const BPF_PSEUDO_CALL: u8 = linux_uapi::BPF_PSEUDO_CALL as u8;
260pub const BPF_PSEUDO_KFUNC_CALL: u8 = linux_uapi::BPF_PSEUDO_KFUNC_CALL as u8;
261
262pub type CbpfInstruction = linux_uapi::sock_filter;
263pub type EbpfMapType = linux_uapi::bpf_map_type;