s2n_quic_platform/bpf/
instruction.rs

1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4use core::{fmt, marker::PhantomData, ops};
5use libc::sock_filter;
6
7pub trait Dialect: Sized {
8    const MAX_INSTRUCTIONS: usize;
9    const SOCKOPT: libc::c_int;
10
11    fn debug(instruction: &Instruction<Self>, f: &mut fmt::Formatter) -> fmt::Result;
12    fn display(
13        instruction: &Instruction<Self>,
14        f: &mut fmt::Formatter,
15        idx: Option<usize>,
16    ) -> fmt::Result;
17}
18
19#[derive(Clone, Copy)]
20#[repr(transparent)]
21pub struct Instruction<D: Dialect>(sock_filter, PhantomData<D>);
22
23impl<D: Dialect> ops::Deref for Instruction<D> {
24    type Target = sock_filter;
25
26    #[inline]
27    fn deref(&self) -> &Self::Target {
28        &self.0
29    }
30}
31
32impl<D: Dialect> fmt::Debug for Instruction<D> {
33    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
34        D::debug(self, f)
35    }
36}
37
38impl<D: Dialect> fmt::Display for Instruction<D> {
39    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
40        if f.alternate() {
41            // write the C literal format if requested
42            let k_prefix = if self.k == 0 { "00" } else { "0x" };
43            write!(
44                f,
45                "{{ 0x{:0>2x}, {:>2}, {:>2}, {k_prefix}{:0>8x} }}",
46                self.code, self.jt, self.jf, self.k
47            )
48        } else {
49            D::display(self, f, None)
50        }
51    }
52}
53
54macro_rules! define {
55    (#[mask($mask:literal)]
56     pub enum $ty:ident {
57        $(
58            $OP:ident = $value:literal
59        ),*
60        $(,)?
61    }) => {
62        #[repr(u16)]
63        #[derive(Copy, Clone, Debug)]
64        #[allow(clippy::upper_case_acronyms, non_camel_case_types)]
65        pub enum $ty {
66            $(
67                $OP = $value,
68            )*
69        }
70
71        impl core::fmt::Display for $ty {
72            #[inline]
73            fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
74                self.to_str().fmt(f)
75            }
76        }
77
78        impl $ty {
79            #[inline]
80            pub fn decode(op: u16) -> Self {
81                match op & $mask {
82                    $(
83                        op if op == $value => Self::$OP,
84                    )*
85                    _ => unreachable!(),
86                }
87            }
88
89            #[inline]
90            pub const fn to_str(self) -> &'static str {
91                match self {
92                    $(
93                        Self::$OP => stringify!($OP),
94                    )*
95                }
96            }
97        }
98    }
99}
100
101impl<D: Dialect> Instruction<D> {
102    pub const fn raw(code: u16, jt: u8, jf: u8, k: u32) -> Self {
103        Instruction(libc::sock_filter { code, jt, jf, k }, PhantomData)
104    }
105}