s2n_quic_platform/bpf/
ebpf.rs

1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4use core::fmt;
5
6pub use super::common::*;
7pub type Instruction = super::Instruction<Ebpf>;
8pub type Program<'a> = super::Program<'a, Ebpf>;
9
10pub struct Ebpf;
11
12impl super::instruction::Dialect for Ebpf {
13    const MAX_INSTRUCTIONS: usize = u16::MAX as _;
14    const SOCKOPT: libc::c_int = libc::SO_ATTACH_REUSEPORT_EBPF as _;
15
16    fn debug(i: &Instruction, f: &mut fmt::Formatter) -> fmt::Result {
17        let code = i.code;
18        let k = i.k;
19        let jt = i.jt;
20        let jf = i.jf;
21        let alt = f.alternate();
22
23        let mut f = f.debug_struct("Instruction");
24        let class = Class::decode(code);
25
26        if alt {
27            f.field("code", &code).field("jt", &jt).field("jf", &jf);
28        }
29
30        f.field("class", &class);
31
32        match class {
33            Class::ALU => {
34                f.field("op", &Alu::decode(code));
35            }
36            Class::JMP | Class::JMP32 => {
37                f.field("op", &Jump::decode(code));
38            }
39            Class::LD | Class::LDX => {
40                f.field("size", &Size::decode(code))
41                    .field("mode", &Mode::decode(code));
42            }
43            // TODO other classes
44            _ => {}
45        }
46
47        if jt > 0 {
48            f.field("jt", &jt);
49        }
50
51        if jf > 0 {
52            f.field("jf", &jf);
53        }
54
55        f.field("k", &k).finish()
56    }
57
58    fn display(i: &Instruction, f: &mut fmt::Formatter, line: Option<usize>) -> fmt::Result {
59        let code = i.code;
60        let k = i.k;
61        let jt = i.jt;
62        let jf = i.jf;
63
64        if let Some(line) = line {
65            write!(f, "l{line:<4}: ")?;
66        }
67
68        let class = Class::decode(code);
69
70        match class {
71            Class::LD | Class::LDX => {
72                let size = Size::decode(code).suffix();
73                let mode = Mode::decode(code);
74
75                match mode {
76                    Mode::IMM => return write!(f, "{class}{size} #{k}"),
77                    Mode::ABS => {
78                        let prefix = if k == 0 { "" } else { "0x" };
79                        return if let Some(info) = super::ancillary::lookup(k) {
80                            write!(
81                                f,
82                                "{class}{size} {} ; [{prefix}{k:x}] // {}",
83                                info.extension, info.capi
84                            )
85                        } else {
86                            write!(f, "{class}{size} [{prefix}{k:x}]")
87                        };
88                    }
89                    _ => {}
90                }
91            }
92            Class::ALU => {
93                let op = Alu::decode(code);
94                let source = Source::decode(code);
95
96                return match source {
97                    Source::K => write!(f, "{op} #{k}"),
98                    Source::X => write!(f, "{op} x"),
99                };
100            }
101            Class::JMP | Class::JMP32 => {
102                let op = Jump::decode(code);
103                let source = Source::decode(code);
104
105                match source {
106                    Source::K => write!(f, "{op} #{k}")?,
107                    Source::X => write!(f, "{op} x")?,
108                }
109
110                if let Some(line) = line {
111                    let line = line + 1;
112                    let jt = line + jt as usize;
113                    let jf = line + jf as usize;
114                    write!(f, ",l{jt},l{jf}")?
115                } else {
116                    write!(f, ",{jt},{jf}")?
117                }
118
119                return Ok(());
120            }
121            _ => {}
122        }
123
124        write!(f, "<unknown instruction {i:?}>")
125    }
126}
127
128// https://www.kernel.org/doc/html/next/bpf/instruction-set.html#instruction-classes
129define!(
130    #[mask(0x07)]
131    pub enum Class {
132        LD = 0x00,
133        LDX = 0x01,
134        ST = 0x02,
135        STX = 0x03,
136        ALU = 0x04,
137        JMP = 0x05,
138        JMP32 = 0x06,
139        ALU64 = 0x07,
140    }
141);
142
143// https://www.kernel.org/doc/html/next/bpf/instruction-set.html#load-and-store-instructions
144define!(
145    #[mask(0x18)]
146    pub enum Size {
147        // word (4 bytes)
148        W = 0x00,
149        // half word (2 bytes)
150        H = 0x08,
151        // byte
152        B = 0x10,
153        // double word (8 bytes)
154        DW = 0x18,
155    }
156);
157
158impl Size {
159    #[inline]
160    pub const fn suffix(self) -> &'static str {
161        match self {
162            Self::W => "",
163            Self::H => "H",
164            Self::B => "B",
165            Self::DW => "DW",
166        }
167    }
168}
169
170// https://www.kernel.org/doc/html/next/bpf/instruction-set.html#load-and-store-instructions
171define!(
172    #[mask(0xe0)]
173    pub enum Mode {
174        IMM = 0x00,
175        ABS = 0x20,
176        IND = 0x40,
177        MEM = 0x60,
178        ATOMIC = 0xc0,
179    }
180);
181
182// https://www.kernel.org/doc/html/next/bpf/instruction-set.html#arithmetic-instructions
183define!(
184    #[mask(0xf0)]
185    pub enum Alu {
186        ADD = 0x00,
187        SUB = 0x10,
188        MUL = 0x20,
189        DIV = 0x30,
190        OR = 0x40,
191        AND = 0x50,
192        LSH = 0x60,
193        RSH = 0x70,
194        NEG = 0x80,
195        MOD = 0x90,
196        XOR = 0xa0,
197        MOV = 0xb0,
198        ARSH = 0xc0,
199        END = 0xd0,
200    }
201);
202
203// https://www.kernel.org/doc/html/next/bpf/instruction-set.html#jump-instructions
204define!(
205    #[mask(0xf0)]
206    pub enum Jump {
207        JA = 0x00,
208        JEQ = 0x10,
209        JGT = 0x20,
210        JGE = 0x30,
211        JSET = 0x40,
212        JNE = 0x50,
213        JSGET = 0x60,
214        JSGE = 0x70,
215        CALL = 0x80,
216        EXIT = 0x90,
217        JLT = 0xa0,
218        JLE = 0xb0,
219        JSLT = 0xc0,
220        JSLE = 0xd0,
221    }
222);
223
224// https://www.kernel.org/doc/html/next/bpf/instruction-set.html#byte-swap-instructions
225define!(
226    #[mask(0x0f)]
227    pub enum Swap {
228        TO_LE = 0x00,
229        TO_BE = 0x08,
230    }
231);
232
233impl_ops!();
234
235pub const fn len() -> K {
236    // still need to figure out what the API is for eBPF - cBPF has a dedicated Mode
237    todo!()
238}