bpf_feature/
misc.rs

1//! Features for miscellaneous eBPF subsystem properties
2use bpf_rs::{
3    insns::{alu64_imm, exit, jmp32_imm, jmp_imm, mov64_imm, AluOp, JmpOp, Register},
4    libbpf_sys::{bpf_insn, bpf_prog_load, BPF_MAXINSNS},
5    ProgramLicense, ProgramType,
6};
7use nix::{
8    errno::{errno, Errno},
9    unistd,
10};
11use std::ptr;
12
13#[cfg(feature = "serde")]
14use serde::Serialize;
15
16#[derive(Debug)]
17#[cfg_attr(feature = "serde", derive(Serialize))]
18pub struct Misc {
19    pub large_insn_limit: bool,
20    pub bounded_loops: bool,
21    pub isa_v2_ext: bool,
22    pub isa_v3_ext: bool,
23}
24
25impl Misc {
26    fn load_insns(insns: Vec<bpf_insn>) -> bool {
27        Errno::clear();
28
29        let fd = unsafe {
30            bpf_prog_load(
31                ProgramType::SocketFilter.into(),
32                ptr::null(),
33                ProgramLicense::GPL.as_ptr(),
34                insns.as_ptr(),
35                u64::try_from(insns.len()).unwrap_or(0u64),
36                // &load_opts as *const bpf_prog_load_opts,
37                ptr::null(),
38            )
39        };
40
41        let success = fd >= 0 || errno() == 0;
42
43        if fd >= 0 {
44            let _ = unistd::close(fd);
45        }
46
47        success
48    }
49
50    fn probe_large_insn_limit() -> bool {
51        let max_insns = usize::try_from(BPF_MAXINSNS).unwrap();
52        let mut large_insn_prog = vec![mov64_imm(Register::R0, 1); max_insns + 1];
53        large_insn_prog[max_insns] = exit();
54        Self::load_insns(large_insn_prog)
55    }
56
57    fn probe_bounded_loops() -> bool {
58        let insns = vec![
59            mov64_imm(Register::R0, 10),
60            alu64_imm(AluOp::SUB, Register::R0, 1),
61            jmp_imm(JmpOp::JNE, Register::R0, 0, -2),
62            exit(),
63        ];
64        Self::load_insns(insns)
65    }
66
67    fn probe_isa_v2() -> bool {
68        let insns = vec![
69            mov64_imm(Register::R0, 0),
70            jmp_imm(JmpOp::JLT, Register::R0, 0, 1),
71            mov64_imm(Register::R0, 1),
72            exit(),
73        ];
74        Self::load_insns(insns)
75    }
76
77    fn probe_isa_v3() -> bool {
78        let insns = vec![
79            mov64_imm(Register::R0, 0),
80            jmp32_imm(JmpOp::JLT, Register::R0, 0, 1),
81            mov64_imm(Register::R0, 1),
82            exit(),
83        ];
84        Self::load_insns(insns)
85    }
86}
87
88pub fn features() -> Misc {
89    Misc {
90        large_insn_limit: Misc::probe_large_insn_limit(),
91        bounded_loops: Misc::probe_bounded_loops(),
92        isa_v2_ext: Misc::probe_isa_v2(),
93        isa_v3_ext: Misc::probe_isa_v3(),
94    }
95}
96
97#[cfg(test)]
98mod tests {
99    use super::*;
100
101    #[test]
102    fn test_probes() {
103        assert!(Misc::probe_large_insn_limit());
104        assert!(Misc::probe_bounded_loops());
105        assert!(Misc::probe_isa_v2());
106        assert!(Misc::probe_isa_v3());
107    }
108}