1use 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 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}