monitord/
varlink_networkd.rs1use std::str::FromStr;
11
12use tracing::debug;
13
14use crate::networkd::{
15 AddressState, AdminState, BoolState, CarrierState, InterfaceState, NetworkdState, OperState,
16};
17use crate::varlink::network::{Interface, Network};
18
19pub use crate::varlink::network::NETWORK_SOCKET_PATH;
20
21fn map_interface(iface: &Interface) -> InterfaceState {
23 let address_state = AddressState::from_str(&iface.address_state).unwrap_or_else(|_| {
24 debug!("Unknown address_state value: {:?}", iface.address_state);
25 AddressState::unknown
26 });
27 let admin_state = AdminState::from_str(&iface.administrative_state).unwrap_or_else(|_| {
28 debug!(
29 "Unknown administrative_state value: {:?}",
30 iface.administrative_state
31 );
32 AdminState::unknown
33 });
34 let carrier_state = CarrierState::from_str(&iface.carrier_state).unwrap_or_else(|_| {
35 debug!("Unknown carrier_state value: {:?}", iface.carrier_state);
36 CarrierState::unknown
37 });
38 let ipv4_address_state =
39 AddressState::from_str(&iface.ipv4_address_state).unwrap_or_else(|_| {
40 debug!(
41 "Unknown ipv4_address_state value: {:?}",
42 iface.ipv4_address_state
43 );
44 AddressState::unknown
45 });
46 let ipv6_address_state =
47 AddressState::from_str(&iface.ipv6_address_state).unwrap_or_else(|_| {
48 debug!(
49 "Unknown ipv6_address_state value: {:?}",
50 iface.ipv6_address_state
51 );
52 AddressState::unknown
53 });
54 let oper_state = OperState::from_str(&iface.operational_state).unwrap_or_else(|_| {
55 debug!(
56 "Unknown operational_state value: {:?}",
57 iface.operational_state
58 );
59 OperState::unknown
60 });
61 let required_for_online = match iface.required_for_online {
62 Some(true) => BoolState::True,
63 Some(false) => BoolState::False,
64 None => BoolState::unknown,
65 };
66 let network_file = iface.network_file.clone().unwrap_or_default();
67
68 InterfaceState {
69 address_state,
70 admin_state,
71 carrier_state,
72 ipv4_address_state,
73 ipv6_address_state,
74 name: iface.name.clone(),
75 network_file,
76 oper_state,
77 required_for_online,
78 }
79}
80
81pub async fn get_networkd_state(socket_path: &str) -> anyhow::Result<NetworkdState> {
94 let mut conn = zlink::unix::connect(socket_path).await?;
95 let result = conn.describe().await?;
96 match result {
97 Ok(output) => {
98 let mut interfaces_state = Vec::new();
99 let mut managed_interfaces: u64 = 0;
100 for iface in output.interfaces.unwrap_or_default() {
101 if iface.network_file.is_none() {
104 continue;
105 }
106 managed_interfaces += 1;
107 interfaces_state.push(map_interface(&iface));
108 }
109 Ok(NetworkdState {
110 interfaces_state,
111 managed_interfaces,
112 })
113 }
114 Err(e) => Err(anyhow::anyhow!("io.systemd.Network.Describe error: {}", e)),
115 }
116}
117
118#[cfg(test)]
119mod tests {
120 use super::*;
121
122 #[test]
123 fn test_map_interface_full() {
124 let iface = Interface {
125 index: 2,
126 name: "eth0".to_string(),
127 administrative_state: "configured".to_string(),
128 operational_state: "routable".to_string(),
129 carrier_state: "carrier".to_string(),
130 address_state: "routable".to_string(),
131 ipv4_address_state: "degraded".to_string(),
132 ipv6_address_state: "routable".to_string(),
133 online_state: Some("online".to_string()),
134 network_file: Some("/etc/systemd/network/69-eno4.network".to_string()),
135 required_for_online: Some(true),
136 };
137 let state = map_interface(&iface);
138 assert_eq!(state.name, "eth0");
139 assert_eq!(state.admin_state, AdminState::configured);
140 assert_eq!(state.oper_state, OperState::routable);
141 assert_eq!(state.carrier_state, CarrierState::carrier);
142 assert_eq!(state.address_state, AddressState::routable);
143 assert_eq!(state.ipv4_address_state, AddressState::degraded);
144 assert_eq!(state.ipv6_address_state, AddressState::routable);
145 assert_eq!(state.required_for_online, BoolState::True);
146 assert_eq!(
147 state.network_file,
148 "/etc/systemd/network/69-eno4.network".to_string()
149 );
150 }
151
152 #[test]
153 fn test_map_interface_unknown_states() {
154 let iface = Interface {
155 index: 3,
156 name: "wg0".to_string(),
157 administrative_state: "initialized".to_string(), operational_state: "unknown-oper".to_string(),
159 carrier_state: "no-carrier".to_string(),
160 address_state: "off".to_string(),
161 ipv4_address_state: "off".to_string(),
162 ipv6_address_state: "off".to_string(),
163 online_state: None,
164 network_file: Some("/etc/systemd/network/wg0.network".to_string()),
165 required_for_online: Some(false),
166 };
167 let state = map_interface(&iface);
168 assert_eq!(state.admin_state, AdminState::unknown);
169 assert_eq!(state.oper_state, OperState::unknown);
170 assert_eq!(state.carrier_state, CarrierState::no_carrier);
171 assert_eq!(state.address_state, AddressState::off);
172 assert_eq!(state.required_for_online, BoolState::False);
173 }
174
175 #[test]
176 fn test_map_interface_no_required_for_online() {
177 let iface = Interface {
178 index: 1,
179 name: "lo".to_string(),
180 administrative_state: "unmanaged".to_string(),
181 operational_state: "carrier".to_string(),
182 carrier_state: "carrier".to_string(),
183 address_state: "degraded".to_string(),
184 ipv4_address_state: "degraded".to_string(),
185 ipv6_address_state: "degraded".to_string(),
186 online_state: None,
187 network_file: None,
188 required_for_online: None,
189 };
190 let state = map_interface(&iface);
191 assert_eq!(state.required_for_online, BoolState::unknown);
192 assert_eq!(state.network_file, "");
193 }
194}