wireshift_uring/
capabilities.rs1use std::os::fd::AsRawFd;
4use std::sync::OnceLock;
5use io_uring::IoUring;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
9#[allow(clippy::struct_excessive_bools)]
10pub struct UringCapabilities {
11 pub read: bool,
13 pub write: bool,
15 pub fsync: bool,
17 pub poll_add: bool,
19 pub accept: bool,
21 pub openat: bool,
23 pub close: bool,
25 pub provide_buffers: bool,
27 pub send_zc: bool,
29}
30
31static CAPABILITIES: OnceLock<UringCapabilities> = OnceLock::new();
32
33const PROBE_OPS: usize = 64;
34const IO_URING_OP_SUPPORTED: u16 = 1;
35const IORING_REGISTER_PROBE: libc::c_uint = 8;
36const IORING_OP_POLL_ADD: u32 = 6;
37const IORING_OP_ACCEPT: u32 = 13;
38const IORING_OP_OPENAT: u32 = 18;
39const IORING_OP_CLOSE: u32 = 19;
40const IORING_OP_READ: u32 = 22;
41const IORING_OP_WRITE: u32 = 23;
42const IORING_OP_PROVIDE_BUFFERS: u32 = 31;
43const IORING_OP_SEND_ZC: u32 = 47;
44const IORING_OP_FSYNC: u32 = 3;
45
46#[must_use]
49pub fn probe_capabilities() -> UringCapabilities {
50 *CAPABILITIES.get_or_init(|| {
51 let Ok(ring) = IoUring::new(8) else {
52 return UringCapabilities::default();
53 };
54
55 let mut bytes = vec![0u8; 1024];
56
57 let rc = unsafe {
58 libc::syscall(
59 libc::SYS_io_uring_register,
60 ring.as_raw_fd(),
61 IORING_REGISTER_PROBE,
62 bytes.as_mut_ptr() as *mut libc::c_void,
63 64 as libc::c_uint,
64 )
65 };
66 if rc < 0 {
67 return UringCapabilities::default();
68 }
69
70 let last = usize::from(bytes[0]);
71 let ops_len = usize::from(bytes[1]).min(PROBE_OPS);
72 let supported = |opcode: u32| -> bool {
73 let opcode = opcode as usize;
74 if opcode >= ops_len || opcode > last {
75 return false;
76 }
77 let offset = 8 + opcode * 8 + 2;
78 let flags = u16::from_ne_bytes([bytes[offset], bytes[offset + 1]]);
79 (flags & IO_URING_OP_SUPPORTED) != 0
80 };
81
82 UringCapabilities {
83 read: supported(IORING_OP_READ),
84 write: supported(IORING_OP_WRITE),
85 fsync: supported(IORING_OP_FSYNC),
86 poll_add: supported(IORING_OP_POLL_ADD),
87 accept: supported(IORING_OP_ACCEPT),
88 openat: supported(IORING_OP_OPENAT),
89 close: supported(IORING_OP_CLOSE),
90 provide_buffers: supported(IORING_OP_PROVIDE_BUFFERS),
91 send_zc: supported(IORING_OP_SEND_ZC),
92 }
93 })
94}