Skip to main content

ibverbs_rs/ibverbs/
error.rs

1//! Error types — ibverbs operation failure variants.
2
3use nix::libc;
4use std::io;
5use thiserror::Error;
6
7/// A specialized result type for ibverbs operations.
8pub type IbvResult<T> = Result<T, IbvError>;
9
10/// Represents errors that can occur when interacting with the RDMA subsystem.
11///
12/// This enum maps low-level OS/Driver error codes (`errno`) into high-level semantic categories
13/// to help applications decide how to recover (e.g., retrying on resource exhaustion vs. panicking on invalid input).
14#[derive(Debug, Error)]
15pub enum IbvError {
16    /// Maps to `EINVAL`.
17    #[error("Invalid argument: {0}")]
18    InvalidInput(String),
19
20    /// Maps to `ENOMEM`, `EMFILE`, `EAGAIN`.
21    #[error("Resource exhausted: {0}")]
22    Resource(String),
23
24    /// Maps to `EPERM`, `EACCES`.
25    #[error("Permission denied: {0}")]
26    Permission(String),
27
28    /// Maps to `ENOENT`.
29    #[error("Entity not found: {0}")]
30    NotFound(String),
31
32    /// Catch-all for underlying OS or Driver failures that don't fit other categories.
33    /// This wraps the standard `std::io::Error`.
34    #[error("Driver/OS error: {0}")]
35    Driver(io::Error),
36}
37
38impl IbvError {
39    /// Helper to convert a raw `errno` (captured via `io::Error`) into a semantic `IbvError`.
40    pub(crate) fn from_errno_with_msg(errno: i32, msg: impl Into<String>) -> Self {
41        match errno {
42            libc::EINVAL => {
43                IbvError::InvalidInput(format!("{} (driver rejected params)", msg.into()))
44            }
45            libc::ENOMEM => IbvError::Resource(format!("{} (out of memory)", msg.into())),
46            libc::EMFILE => {
47                IbvError::Resource(format!("{} (too many open files/objects)", msg.into()))
48            }
49            libc::EAGAIN => {
50                IbvError::Resource(format!("{} (temporary resource shortage)", msg.into()))
51            }
52            libc::EACCES | libc::EPERM => IbvError::Permission(msg.into()),
53            libc::ENOENT => IbvError::NotFound(msg.into()),
54            _ => IbvError::Driver(io::Error::from_raw_os_error(errno)),
55        }
56    }
57}
58
59#[cfg(test)]
60mod tests {
61    use super::*;
62
63    #[test]
64    fn einval_maps_to_invalid_input() {
65        assert!(matches!(
66            IbvError::from_errno_with_msg(libc::EINVAL, "test"),
67            IbvError::InvalidInput(_)
68        ));
69    }
70
71    #[test]
72    fn enomem_maps_to_resource() {
73        assert!(matches!(
74            IbvError::from_errno_with_msg(libc::ENOMEM, "test"),
75            IbvError::Resource(_)
76        ));
77    }
78
79    #[test]
80    fn emfile_maps_to_resource() {
81        assert!(matches!(
82            IbvError::from_errno_with_msg(libc::EMFILE, "test"),
83            IbvError::Resource(_)
84        ));
85    }
86
87    #[test]
88    fn eagain_maps_to_resource() {
89        assert!(matches!(
90            IbvError::from_errno_with_msg(libc::EAGAIN, "test"),
91            IbvError::Resource(_)
92        ));
93    }
94
95    #[test]
96    fn eacces_maps_to_permission() {
97        let err = IbvError::from_errno_with_msg(libc::EACCES, "test");
98        assert!(matches!(err, IbvError::Permission(_)));
99    }
100
101    #[test]
102    fn eperm_maps_to_permission() {
103        let err = IbvError::from_errno_with_msg(libc::EPERM, "test");
104        assert!(matches!(err, IbvError::Permission(_)));
105    }
106
107    #[test]
108    fn enoent_maps_to_not_found() {
109        let err = IbvError::from_errno_with_msg(libc::ENOENT, "test");
110        assert!(matches!(err, IbvError::NotFound(_)));
111    }
112
113    #[test]
114    fn unknown_errno_maps_to_driver() {
115        let err = IbvError::from_errno_with_msg(libc::EIO, "test");
116        assert!(matches!(err, IbvError::Driver(_)));
117    }
118}