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(
94 endpoint: &crate::varlink::endpoint::VarlinkEndpoint,
95) -> anyhow::Result<NetworkdState> {
96 let mut conn = endpoint.connect().await?;
97 let result = conn.describe().await?;
98 match result {
99 Ok(output) => {
100 let mut interfaces_state = Vec::new();
101 let mut managed_interfaces: u64 = 0;
102 for iface in output.interfaces.unwrap_or_default() {
103 if iface.network_file.is_none() {
106 continue;
107 }
108 managed_interfaces += 1;
109 interfaces_state.push(map_interface(&iface));
110 }
111 Ok(NetworkdState {
112 interfaces_state,
113 managed_interfaces,
114 })
115 }
116 Err(e) => Err(anyhow::anyhow!("io.systemd.Network.Describe error: {}", e)),
117 }
118}
119
120#[cfg(test)]
121mod tests {
122 use super::*;
123
124 #[test]
125 fn test_map_interface_full() {
126 let iface = Interface {
127 index: 2,
128 name: "eth0".to_string(),
129 administrative_state: "configured".to_string(),
130 operational_state: "routable".to_string(),
131 carrier_state: "carrier".to_string(),
132 address_state: "routable".to_string(),
133 ipv4_address_state: "degraded".to_string(),
134 ipv6_address_state: "routable".to_string(),
135 online_state: Some("online".to_string()),
136 network_file: Some("/etc/systemd/network/69-eno4.network".to_string()),
137 required_for_online: Some(true),
138 };
139 let state = map_interface(&iface);
140 assert_eq!(state.name, "eth0");
141 assert_eq!(state.admin_state, AdminState::configured);
142 assert_eq!(state.oper_state, OperState::routable);
143 assert_eq!(state.carrier_state, CarrierState::carrier);
144 assert_eq!(state.address_state, AddressState::routable);
145 assert_eq!(state.ipv4_address_state, AddressState::degraded);
146 assert_eq!(state.ipv6_address_state, AddressState::routable);
147 assert_eq!(state.required_for_online, BoolState::True);
148 assert_eq!(
149 state.network_file,
150 "/etc/systemd/network/69-eno4.network".to_string()
151 );
152 }
153
154 #[test]
155 fn test_map_interface_unknown_states() {
156 let iface = Interface {
157 index: 3,
158 name: "wg0".to_string(),
159 administrative_state: "initialized".to_string(), operational_state: "unknown-oper".to_string(),
161 carrier_state: "no-carrier".to_string(),
162 address_state: "off".to_string(),
163 ipv4_address_state: "off".to_string(),
164 ipv6_address_state: "off".to_string(),
165 online_state: None,
166 network_file: Some("/etc/systemd/network/wg0.network".to_string()),
167 required_for_online: Some(false),
168 };
169 let state = map_interface(&iface);
170 assert_eq!(state.admin_state, AdminState::unknown);
171 assert_eq!(state.oper_state, OperState::unknown);
172 assert_eq!(state.carrier_state, CarrierState::no_carrier);
173 assert_eq!(state.address_state, AddressState::off);
174 assert_eq!(state.required_for_online, BoolState::False);
175 }
176
177 #[test]
178 fn test_map_interface_no_required_for_online() {
179 let iface = Interface {
180 index: 1,
181 name: "lo".to_string(),
182 administrative_state: "unmanaged".to_string(),
183 operational_state: "carrier".to_string(),
184 carrier_state: "carrier".to_string(),
185 address_state: "degraded".to_string(),
186 ipv4_address_state: "degraded".to_string(),
187 ipv6_address_state: "degraded".to_string(),
188 online_state: None,
189 network_file: None,
190 required_for_online: None,
191 };
192 let state = map_interface(&iface);
193 assert_eq!(state.required_for_online, BoolState::unknown);
194 assert_eq!(state.network_file, "");
195 }
196}