Skip to main content

netdev/interface/
state.rs

1use std::fmt;
2use std::str::FromStr;
3
4#[cfg(feature = "serde")]
5use serde::{Deserialize, Serialize};
6
7/// Operational state of a network interface.
8///
9/// This enum models the common states used by Linux and maps equivalent states from
10/// other platforms when possible.
11///
12/// See also: <https://www.kernel.org/doc/Documentation/networking/operstates.txt>
13#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)]
14#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
15pub enum OperState {
16    /// Interface state could not be determined.
17    Unknown,
18    /// Interface is not present.
19    NotPresent,
20    /// Interface is administratively or otherwise down.
21    Down,
22    /// Interface is down because a lower layer is down.
23    LowerLayerDown,
24    /// Interface is in testing state.
25    Testing,
26    /// Interface is dormant.
27    Dormant,
28    /// Interface is operational.
29    Up,
30}
31
32impl OperState {
33    /// Returns the lowercase representation used by Linux `operstate` files.
34    pub fn as_str(&self) -> &'static str {
35        match self {
36            OperState::Unknown => "unknown",
37            OperState::NotPresent => "notpresent",
38            OperState::Down => "down",
39            OperState::LowerLayerDown => "lowerlayerdown",
40            OperState::Testing => "testing",
41            OperState::Dormant => "dormant",
42            OperState::Up => "up",
43        }
44    }
45
46    /// Derives an operational state from raw interface flags.
47    ///
48    /// This is used as a fallback when no dedicated operstate API is available.
49    /// The result is necessarily less precise than native platform state reporting.
50    pub fn from_if_flags(if_flags: u32) -> Self {
51        #[cfg(not(target_os = "windows"))]
52        {
53            if if_flags & super::flags::IFF_UP as u32 != 0 {
54                if if_flags & super::flags::IFF_RUNNING as u32 != 0 {
55                    OperState::Up
56                } else {
57                    OperState::Dormant
58                }
59            } else {
60                OperState::Down
61            }
62        }
63
64        #[cfg(target_os = "windows")]
65        {
66            if if_flags & super::flags::IFF_UP as u32 != 0 {
67                OperState::Up
68            } else {
69                OperState::Down
70            }
71        }
72    }
73}
74
75impl fmt::Display for OperState {
76    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
77        write!(f, "{}", self.as_str())
78    }
79}
80
81impl FromStr for OperState {
82    type Err = ();
83
84    fn from_str(s: &str) -> Result<Self, Self::Err> {
85        match s {
86            "unknown" => Ok(OperState::Unknown),
87            "notpresent" => Ok(OperState::NotPresent),
88            "down" => Ok(OperState::Down),
89            "lowerlayerdown" => Ok(OperState::LowerLayerDown),
90            "testing" => Ok(OperState::Testing),
91            "dormant" => Ok(OperState::Dormant),
92            "up" => Ok(OperState::Up),
93            _ => Err(()),
94        }
95    }
96}
97
98/// Reads the current operational state for the named interface.
99///
100/// This function performs a fresh OS query and does not rely on a previously collected
101/// snapshot.
102pub fn operstate(if_name: &str) -> OperState {
103    #[cfg(target_os = "linux")]
104    {
105        crate::os::linux::state::operstate(if_name)
106    }
107    #[cfg(target_os = "android")]
108    {
109        crate::os::android::state::operstate(if_name)
110    }
111    #[cfg(target_vendor = "apple")]
112    {
113        crate::os::darwin::state::operstate(if_name)
114    }
115    #[cfg(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))]
116    {
117        crate::os::bsd::state::operstate(if_name)
118    }
119    #[cfg(target_os = "illumos")]
120    {
121        crate::os::illumos::state::operstate(if_name)
122    }
123    #[cfg(target_os = "windows")]
124    {
125        crate::os::windows::state::operstate(if_name)
126    }
127}