sysinfo/common/network.rs
1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::collections::HashMap;
4use std::ffi::OsString;
5use std::fmt;
6use std::net::{AddrParseError, IpAddr};
7use std::num::ParseIntError;
8use std::str::FromStr;
9
10use crate::{Error, NetworkDataInner, NetworksInner};
11
12/// Interacting with network interfaces.
13///
14/// ```no_run
15/// use sysinfo::Networks;
16///
17/// if let Ok(networks) = Networks::new_with_refreshed_list() {
18/// for (interface_name, network) in &networks {
19/// println!("[{}]: {network:?}", interface_name.display());
20/// }
21/// }
22/// ```
23pub struct Networks {
24 pub(crate) inner: NetworksInner,
25}
26
27impl<'a> IntoIterator for &'a Networks {
28 type Item = (&'a OsString, &'a NetworkData);
29 type IntoIter = std::collections::hash_map::Iter<'a, OsString, NetworkData>;
30
31 fn into_iter(self) -> Self::IntoIter {
32 self.iter()
33 }
34}
35
36impl Networks {
37 /// Creates a new empty [`Networks`][crate::Networks] type.
38 ///
39 /// If you want it to be filled directly, take a look at [`Networks::new_with_refreshed_list`].
40 ///
41 /// ```no_run
42 /// use sysinfo::Networks;
43 ///
44 /// if let Ok(mut networks) = Networks::new() {
45 /// networks.refresh(true);
46 /// for (interface_name, network) in &networks {
47 /// println!("[{}]: {network:?}", interface_name.display());
48 /// }
49 /// }
50 /// ```
51 pub fn new() -> Result<Self, Error> {
52 Ok(Self {
53 inner: NetworksInner::new()?,
54 })
55 }
56
57 /// Creates a new [`Networks`][crate::Networks] type with the network interfaces
58 /// list loaded.
59 ///
60 /// ```no_run
61 /// use sysinfo::Networks;
62 ///
63 /// if let Ok(networks) = Networks::new_with_refreshed_list() {
64 /// for network in &networks {
65 /// println!("{network:?}");
66 /// }
67 /// }
68 /// ```
69 pub fn new_with_refreshed_list() -> Result<Self, Error> {
70 let mut networks = Self::new()?;
71 networks.refresh(false);
72 Ok(networks)
73 }
74
75 /// Refreshes the network interfaces.
76 ///
77 /// ```no_run
78 /// use sysinfo::Networks;
79 ///
80 /// if let Ok(mut networks) = Networks::new_with_refreshed_list() {
81 /// // Wait some time...? Then refresh the data of each network.
82 /// networks.refresh(true);
83 /// }
84 /// ```
85 pub fn refresh(&mut self, remove_not_listed_interfaces: bool) {
86 // Most supported system first list all interfaces, then `retain` only the one that got
87 // refreshed, then get data for each interface. So sadly, we can't do the cleanup here...
88 self.inner.refresh(remove_not_listed_interfaces);
89 }
90}
91
92impl std::ops::Deref for Networks {
93 type Target = HashMap<OsString, NetworkData>;
94
95 fn deref(&self) -> &Self::Target {
96 self.inner.list()
97 }
98}
99
100/// Getting volume of received and transmitted data.
101///
102/// ```no_run
103/// use sysinfo::Networks;
104///
105/// if let Ok(networks) = Networks::new_with_refreshed_list() {
106/// for (interface_name, network) in &networks {
107/// println!("[{}] {network:?}", interface_name.display());
108/// }
109/// }
110/// ```
111pub struct NetworkData {
112 pub(crate) inner: NetworkDataInner,
113}
114
115impl NetworkData {
116 /// Returns the number of received bytes since the last refresh.
117 ///
118 /// If you want the total number of bytes received, take a look at the
119 /// [`total_received`](NetworkData::total_received) method.
120 ///
121 /// ```no_run
122 /// use sysinfo::Networks;
123 /// use std::{thread, time};
124 ///
125 /// if let Ok(mut networks) = Networks::new_with_refreshed_list() {
126 /// // Waiting a bit to get data from network...
127 /// thread::sleep(time::Duration::from_millis(10));
128 /// // Refreshing again to generate diff.
129 /// networks.refresh(true);
130 ///
131 /// for (interface_name, network) in &networks {
132 /// println!("in: {} B", network.received());
133 /// }
134 /// }
135 /// ```
136 pub fn received(&self) -> u64 {
137 self.inner.received()
138 }
139
140 /// Returns the total number of received bytes.
141 ///
142 /// If you want the amount of received bytes since the last refresh, take a look at the
143 /// [`received`](NetworkData::received) method.
144 ///
145 /// ```no_run
146 /// use sysinfo::Networks;
147 ///
148 /// if let Ok(networks) = Networks::new_with_refreshed_list() {
149 /// for (interface_name, network) in &networks {
150 /// println!("in: {} B", network.total_received());
151 /// }
152 /// }
153 /// ```
154 pub fn total_received(&self) -> u64 {
155 self.inner.total_received()
156 }
157
158 /// Returns the number of transmitted bytes since the last refresh.
159 ///
160 /// If you want the total number of bytes transmitted, take a look at the
161 /// [`total_transmitted`](NetworkData::total_transmitted) method.
162 ///
163 /// ```no_run
164 /// use sysinfo::Networks;
165 /// use std::{thread, time};
166 ///
167 /// if let Ok(mut networks) = Networks::new_with_refreshed_list() {
168 /// // Waiting a bit to get data from network...
169 /// thread::sleep(time::Duration::from_millis(10));
170 /// // Refreshing again to generate diff.
171 /// networks.refresh(true);
172 ///
173 /// for (interface_name, network) in &networks {
174 /// println!("out: {} B", network.transmitted());
175 /// }
176 /// }
177 /// ```
178 pub fn transmitted(&self) -> u64 {
179 self.inner.transmitted()
180 }
181
182 /// Returns the total number of transmitted bytes.
183 ///
184 /// If you want the amount of transmitted bytes since the last refresh, take a look at the
185 /// [`transmitted`](NetworkData::transmitted) method.
186 ///
187 /// ```no_run
188 /// use sysinfo::Networks;
189 ///
190 /// if let Ok(networks) = Networks::new_with_refreshed_list() {
191 /// for (interface_name, network) in &networks {
192 /// println!("out: {} B", network.total_transmitted());
193 /// }
194 /// }
195 /// ```
196 pub fn total_transmitted(&self) -> u64 {
197 self.inner.total_transmitted()
198 }
199
200 /// Returns the number of incoming packets since the last refresh.
201 ///
202 /// If you want the total number of packets received, take a look at the
203 /// [`total_packets_received`](NetworkData::total_packets_received) method.
204 ///
205 /// ```no_run
206 /// use sysinfo::Networks;
207 /// use std::{thread, time};
208 ///
209 /// if let Ok(mut networks) = Networks::new_with_refreshed_list() {
210 /// // Waiting a bit to get data from network...
211 /// thread::sleep(time::Duration::from_millis(10));
212 /// // Refreshing again to generate diff.
213 /// networks.refresh(true);
214 ///
215 /// for (interface_name, network) in &networks {
216 /// println!("in: {}", network.packets_received());
217 /// }
218 /// }
219 /// ```
220 pub fn packets_received(&self) -> u64 {
221 self.inner.packets_received()
222 }
223
224 /// Returns the total number of incoming packets.
225 ///
226 /// If you want the amount of received packets since the last refresh, take a look at the
227 /// [`packets_received`](NetworkData::packets_received) method.
228 ///
229 /// ```no_run
230 /// use sysinfo::Networks;
231 ///
232 /// if let Ok(networks) = Networks::new_with_refreshed_list() {
233 /// for (interface_name, network) in &networks {
234 /// println!("in: {}", network.total_packets_received());
235 /// }
236 /// }
237 /// ```
238 pub fn total_packets_received(&self) -> u64 {
239 self.inner.total_packets_received()
240 }
241
242 /// Returns the number of outcoming packets since the last refresh.
243 ///
244 /// If you want the total number of packets transmitted, take a look at the
245 /// [`total_packets_transmitted`](NetworkData::total_packets_transmitted) method.
246 ///
247 /// ```no_run
248 /// use sysinfo::Networks;
249 /// use std::{thread, time};
250 ///
251 /// if let Ok(mut networks) = Networks::new_with_refreshed_list() {
252 /// // Waiting a bit to get data from network...
253 /// thread::sleep(time::Duration::from_millis(10));
254 /// // Refreshing again to generate diff.
255 /// networks.refresh(true);
256 ///
257 /// for (interface_name, network) in &networks {
258 /// println!("out: {}", network.packets_transmitted());
259 /// }
260 /// }
261 /// ```
262 pub fn packets_transmitted(&self) -> u64 {
263 self.inner.packets_transmitted()
264 }
265
266 /// Returns the total number of outcoming packets.
267 ///
268 /// If you want the amount of transmitted packets since the last refresh, take a look at the
269 /// [`packets_transmitted`](NetworkData::packets_transmitted) method.
270 ///
271 /// ```no_run
272 /// use sysinfo::Networks;
273 ///
274 /// if let Ok(networks) = Networks::new_with_refreshed_list() {
275 /// for (interface_name, network) in &networks {
276 /// println!("out: {}", network.total_packets_transmitted());
277 /// }
278 /// }
279 /// ```
280 pub fn total_packets_transmitted(&self) -> u64 {
281 self.inner.total_packets_transmitted()
282 }
283
284 /// Returns the number of incoming errors since the last refresh.
285 ///
286 /// If you want the total number of errors on received packets, take a look at the
287 /// [`total_errors_on_received`](NetworkData::total_errors_on_received) method.
288 ///
289 /// ```no_run
290 /// use sysinfo::Networks;
291 /// use std::{thread, time};
292 ///
293 /// if let Ok(mut networks) = Networks::new_with_refreshed_list() {
294 /// // Waiting a bit to get data from network...
295 /// thread::sleep(time::Duration::from_millis(10));
296 /// // Refreshing again to generate diff.
297 /// networks.refresh(true);
298 ///
299 /// for (interface_name, network) in &networks {
300 /// println!("in: {}", network.errors_on_received());
301 /// }
302 /// }
303 /// ```
304 pub fn errors_on_received(&self) -> u64 {
305 self.inner.errors_on_received()
306 }
307
308 /// Returns the total number of incoming errors.
309 ///
310 /// If you want the amount of errors on received packets since the last refresh, take a look at
311 /// the [`errors_on_received`](NetworkData::errors_on_received) method.
312 ///
313 /// ```no_run
314 /// use sysinfo::Networks;
315 ///
316 /// if let Ok(networks) = Networks::new_with_refreshed_list() {
317 /// for (interface_name, network) in &networks {
318 /// println!("in: {}", network.total_errors_on_received());
319 /// }
320 /// }
321 /// ```
322 pub fn total_errors_on_received(&self) -> u64 {
323 self.inner.total_errors_on_received()
324 }
325
326 /// Returns the number of outcoming errors since the last refresh.
327 ///
328 /// If you want the total number of errors on transmitted packets, take a look at the
329 /// [`total_errors_on_transmitted`](NetworkData::total_errors_on_transmitted) method.
330 ///
331 /// ```no_run
332 /// use sysinfo::Networks;
333 /// use std::{thread, time};
334 ///
335 /// if let Ok(mut networks) = Networks::new_with_refreshed_list() {
336 /// // Waiting a bit to get data from network...
337 /// thread::sleep(time::Duration::from_millis(10));
338 /// // Refreshing again to generate diff.
339 /// networks.refresh(true);
340 ///
341 /// for (interface_name, network) in &networks {
342 /// println!("out: {}", network.errors_on_transmitted());
343 /// }
344 /// }
345 /// ```
346 pub fn errors_on_transmitted(&self) -> u64 {
347 self.inner.errors_on_transmitted()
348 }
349
350 /// Returns the total number of outcoming errors.
351 ///
352 /// If you want the amount of errors on transmitted packets since the last refresh, take a look at
353 /// the [`errors_on_transmitted`](NetworkData::errors_on_transmitted) method.
354 ///
355 /// ```no_run
356 /// use sysinfo::Networks;
357 ///
358 /// if let Ok(networks) = Networks::new_with_refreshed_list() {
359 /// for (interface_name, network) in &networks {
360 /// println!("out: {}", network.total_errors_on_transmitted());
361 /// }
362 /// }
363 /// ```
364 pub fn total_errors_on_transmitted(&self) -> u64 {
365 self.inner.total_errors_on_transmitted()
366 }
367
368 /// Returns the MAC address associated to current interface.
369 ///
370 /// ```no_run
371 /// use sysinfo::Networks;
372 ///
373 /// if let Ok(mut networks) = Networks::new_with_refreshed_list() {
374 /// for (interface_name, network) in &networks {
375 /// println!("MAC address: {}", network.mac_address());
376 /// }
377 /// }
378 /// ```
379 pub fn mac_address(&self) -> MacAddr {
380 self.inner.mac_address()
381 }
382
383 /// Returns the Ip Networks associated to current interface.
384 ///
385 /// ```no_run
386 /// use sysinfo::Networks;
387 ///
388 /// if let Ok(mut networks) = Networks::new_with_refreshed_list() {
389 /// for (interface_name, network) in &networks {
390 /// println!("Ip Networks: {:?}", network.ip_networks());
391 /// }
392 /// }
393 /// ```
394 pub fn ip_networks(&self) -> &[IpNetwork] {
395 self.inner.ip_networks()
396 }
397
398 /// Returns the Maximum Transfer Unit (MTU) of the interface.
399 ///
400 /// ```no_run
401 /// use sysinfo::Networks;
402 ///
403 /// if let Ok(mut networks) = Networks::new_with_refreshed_list() {
404 /// for (interface_name, network) in &networks {
405 /// println!("mtu: {}", network.mtu());
406 /// }
407 /// }
408 /// ```
409 pub fn mtu(&self) -> u64 {
410 self.inner.mtu()
411 }
412
413 /// Returns the transmit link speed of the interface in bits per second.
414 ///
415 /// For Ethernet interfaces, this is the negotiated link speed.
416 ///
417 /// For Wi-Fi interfaces, this is the link speed reported by the OS.
418 ///
419 /// Returns the same value as [Self::receive_link_speed] on Unix systems.
420 ///
421 /// Returns `None` when the link speed is not available.
422 /// For example, when the interface is down or when the driver does not provide a link speed.
423 ///
424 /// ```no_run
425 /// use sysinfo::Networks;
426 ///
427 /// if let Ok(mut networks) = Networks::new_with_refreshed_list() {
428 /// for (interface_name, network) in &networks {
429 /// println!("transmit link speed: {:?}", network.transmit_link_speed());
430 /// }
431 /// }
432 /// ```
433 pub fn transmit_link_speed(&self) -> Option<u64> {
434 self.inner.transmit_link_speed()
435 }
436
437 /// Returns the receive link speed of the interface in bits per second.
438 ///
439 /// For Ethernet interfaces, this is the negotiated link speed.
440 ///
441 /// For Wi-Fi interfaces, this is the link speed reported by the OS.
442 ///
443 /// Returns the same value as [Self::transmit_link_speed] on Unix systems.
444 ///
445 /// Returns `None` when the link speed is not available.
446 /// For example, when the interface is down or when the driver does not provide a link speed.
447 ///
448 /// ```no_run
449 /// use sysinfo::Networks;
450 ///
451 /// if let Ok(mut networks) = Networks::new_with_refreshed_list() {
452 /// for (interface_name, network) in &networks {
453 /// println!("receive link speed: {:?}", network.receive_link_speed());
454 /// }
455 /// }
456 /// ```
457 pub fn receive_link_speed(&self) -> Option<u64> {
458 self.inner.receive_link_speed()
459 }
460
461 /// Returns the operational state of the interface.
462 ///
463 /// The operational state indicates whether the interface is able to pass packets or not.
464 /// For details on the individual states see the documentation of the [`InterfaceOperationalState`] enum and its variants.
465 ///
466 /// ```no_run
467 /// use sysinfo::Networks;
468 ///
469 /// if let Ok(mut networks) = Networks::new_with_refreshed_list() {
470 /// for (interface_name, network) in &networks {
471 /// println!("operational state: {}", network.operational_state());
472 /// }
473 /// }
474 /// ```
475 pub fn operational_state(&self) -> InterfaceOperationalState {
476 self.inner.operational_state()
477 }
478}
479
480/// MAC address for network interface.
481///
482/// It is returned by [`NetworkData::mac_address`][crate::NetworkData::mac_address].
483#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
484#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
485pub struct MacAddr(pub [u8; 6]);
486
487impl MacAddr {
488 /// A `MacAddr` with all bytes set to `0`.
489 pub const UNSPECIFIED: Self = MacAddr([0; 6]);
490
491 /// Checks if this `MacAddr` has all bytes equal to `0`.
492 pub fn is_unspecified(&self) -> bool {
493 self == &MacAddr::UNSPECIFIED
494 }
495}
496
497impl fmt::Display for MacAddr {
498 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
499 let data = &self.0;
500 write!(
501 f,
502 "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
503 data[0], data[1], data[2], data[3], data[4], data[5],
504 )
505 }
506}
507
508/// Error type returned from `MacAddr::from_str` implementation.
509#[derive(Debug, Clone, PartialEq, Eq)]
510pub enum MacAddrFromStrError {
511 /// A number is not in hexadecimal format.
512 IntError(ParseIntError),
513 /// Input is not of format `{02X}:{02X}:{02X}:{02X}:{02X}:{02X}`.
514 InvalidAddrFormat,
515}
516
517impl FromStr for MacAddr {
518 type Err = MacAddrFromStrError;
519
520 fn from_str(s: &str) -> Result<Self, Self::Err> {
521 let mut parts = s
522 .split(':')
523 .map(|s| u8::from_str_radix(s, 16).map_err(MacAddrFromStrError::IntError));
524
525 let Some(data0) = parts.next() else {
526 return Err(MacAddrFromStrError::InvalidAddrFormat);
527 };
528 let Some(data1) = parts.next() else {
529 return Err(MacAddrFromStrError::InvalidAddrFormat);
530 };
531 let Some(data2) = parts.next() else {
532 return Err(MacAddrFromStrError::InvalidAddrFormat);
533 };
534 let Some(data3) = parts.next() else {
535 return Err(MacAddrFromStrError::InvalidAddrFormat);
536 };
537 let Some(data4) = parts.next() else {
538 return Err(MacAddrFromStrError::InvalidAddrFormat);
539 };
540 let Some(data5) = parts.next() else {
541 return Err(MacAddrFromStrError::InvalidAddrFormat);
542 };
543
544 if parts.next().is_some() {
545 return Err(MacAddrFromStrError::InvalidAddrFormat);
546 }
547
548 Ok(MacAddr([data0?, data1?, data2?, data3?, data4?, data5?]))
549 }
550}
551
552impl core::fmt::Display for MacAddrFromStrError {
553 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
554 match self {
555 Self::IntError(error) => write!(f, "a number is not in hexadecimal format: {error}"),
556 Self::InvalidAddrFormat => f.write_str("invalid address format"),
557 }
558 }
559}
560
561impl core::error::Error for MacAddrFromStrError {}
562
563/// IP networks address for network interface.
564///
565/// It is returned by [`NetworkData::ip_networks`][crate::NetworkData::ip_networks].
566#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
567#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
568pub struct IpNetwork {
569 /// The IP of the network interface.
570 pub addr: IpAddr,
571 /// The netmask, prefix of the IP address.
572 pub prefix: u8,
573}
574
575impl fmt::Display for IpNetwork {
576 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
577 write!(f, "{}/{}", self.addr, self.prefix)
578 }
579}
580
581/// Error type returned from `MacAddr::from_str` implementation.
582#[derive(Debug, Clone, PartialEq, Eq)]
583pub enum IpNetworkFromStrError {
584 /// Prefix is not an integer.
585 PrefixError(ParseIntError),
586 /// Failed to parse IP address.
587 AddrParseError(AddrParseError),
588 /// Input is not of format `[IP address]/[number]`.
589 InvalidAddrFormat,
590}
591
592impl FromStr for IpNetwork {
593 type Err = IpNetworkFromStrError;
594
595 #[allow(clippy::from_str_radix_10)]
596 fn from_str(s: &str) -> Result<Self, Self::Err> {
597 let mut parts = s.split('/');
598
599 let Some(addr) = parts.next() else {
600 return Err(IpNetworkFromStrError::InvalidAddrFormat);
601 };
602 let Some(prefix) = parts.next() else {
603 return Err(IpNetworkFromStrError::InvalidAddrFormat);
604 };
605 if parts.next().is_some() {
606 return Err(IpNetworkFromStrError::InvalidAddrFormat);
607 }
608
609 Ok(IpNetwork {
610 addr: IpAddr::from_str(addr).map_err(IpNetworkFromStrError::AddrParseError)?,
611 prefix: u8::from_str_radix(prefix, 10).map_err(IpNetworkFromStrError::PrefixError)?,
612 })
613 }
614}
615
616impl core::fmt::Display for IpNetworkFromStrError {
617 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
618 match self {
619 Self::PrefixError(error) => write!(f, "prefix is not an integer: {error}"),
620 Self::AddrParseError(error) => write!(f, "failed to parse IP address: {error}"),
621 Self::InvalidAddrFormat => {
622 f.write_str("invalid address format, should `[IP address]/[number]`")
623 }
624 }
625 }
626}
627
628impl core::error::Error for IpNetworkFromStrError {}
629
630/// The operational state of some interface based on `IfOperStatus`
631/// from [RFC2863].
632///
633/// Not all states are supported by all systems.
634///
635/// If you want to only distinguish between potentially operational and not operational you
636/// likely want to:
637/// - treat [`Up`][Self::Up], [`Dormant`][Self::Dormant] and [`Unknown`][Self::Unknown] as potentially operational
638/// - treat [`Down`][Self::Down], [`Testing`][Self::Testing], [`NotPresent`][Self::NotPresent] and [`LowerLayerDown`][Self::LowerLayerDown] as not operational
639///
640/// [RFC2863]: https://datatracker.ietf.org/doc/html/rfc2863#section-3.1.12
641///
642// windows: https://learn.microsoft.com/en-us/dotnet/api/system.net.networkinformation.operationalstatus?view=net-10.0
643// linux: https://docs.kernel.org/networking/operstates.html#tlv-ifla-operstate
644// discriminants based on windows
645#[non_exhaustive]
646#[derive(Debug, Clone, Copy, PartialEq, Eq)]
647pub enum InterfaceOperationalState {
648 #[doc(hidden)]
649 #[non_exhaustive]
650 /// InterfaceOperationalState is unsupported or had an unrecognized value
651 Other,
652 /// The interface is able to pass packets.
653 Up = 1,
654 /// The interface is unable to pass packets.
655 ///
656 /// ## Examples
657 /// - an error condition has occurred
658 /// - the interface is disabled
659 Down = 2,
660 /// The interface is unable to pass packets.
661 /// The interface is performing some test(s).
662 /// Presumably it will change into another appropriate state once testing completes.
663 ///
664 /// ## Examples
665 /// - driver self-test
666 /// - media (e.g. cable) test
667 Testing = 3,
668 /// The state of the interface is unknown.
669 /// The interface may or may not be usable.
670 ///
671 /// ## Examples
672 /// - on linux the loopback interface (localhost, 127.0.0.1/8, ::1/128) typically has this state
673 Unknown = 4,
674 /// The interface is unable to pass packets.
675 /// It is in a "pending state" waiting for some external event.
676 /// When the event occurs the interface will prusumably change into the `Up`` state.
677 ///
678 /// ## Examples
679 /// - an "on-demand" interface might be waiting for a package in the transmit queue to establish a connection.
680 /// - an interface might be waiting for the remote system to establish a connection
681 /// - waiting for 802.1X protocol to establish a connection
682 Dormant = 5,
683 /// The interface is unable to pass packets.
684 /// A (hardware) component is not present.
685 ///
686 /// This is a refinement on `Down`.
687 ///
688 /// ## Examples
689 /// - hot-swap module is currently not installed
690 /// - pre-configured interface is not yet installed
691 /// - an interface has been removed but is still configured
692 NotPresent = 6,
693 /// The interface is unable to pass packets.
694 /// This interface depends on one or more interfaces and at least one of these interfaces prevents this interface from being `Up`.
695 ///
696 /// This is a refinement on `Down`.
697 ///
698 /// ## Examples
699 /// - a VPN interface depends on any physical interface being up but the physical interface is testing the cable to determine the available speed
700 /// - a single virtual interface that aggregates multiple physical interfaces but all physical interfaces are down
701 LowerLayerDown = 7,
702}
703
704impl fmt::Display for InterfaceOperationalState {
705 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
706 // see /sys/class/net/<iface>/operstate section at https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-class-net
707 f.write_str(match self {
708 InterfaceOperationalState::Other => "other",
709 InterfaceOperationalState::Up => "up",
710 InterfaceOperationalState::Down => "down",
711 InterfaceOperationalState::Testing => "testing",
712 InterfaceOperationalState::Unknown => "unknown",
713 InterfaceOperationalState::Dormant => "dormant",
714 InterfaceOperationalState::NotPresent => "notpresent",
715 InterfaceOperationalState::LowerLayerDown => "lowerlayerdown",
716 })
717 }
718}
719
720#[cfg(test)]
721mod tests {
722 use crate::*;
723 use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
724 use std::str::FromStr;
725
726 // Ensure that the `Display` and `Debug` traits are implemented on the `MacAddr` struct
727 #[test]
728 fn check_display_impl_mac_address() {
729 println!(
730 "{} {:?}",
731 MacAddr([0x1, 0x2, 0x3, 0x4, 0x5, 0x6]),
732 MacAddr([0xa, 0xb, 0xc, 0xd, 0xe, 0xf])
733 );
734 }
735
736 #[test]
737 fn check_mac_address_is_unspecified_true() {
738 assert!(MacAddr::UNSPECIFIED.is_unspecified());
739 assert!(MacAddr([0; 6]).is_unspecified());
740 }
741
742 #[test]
743 fn check_mac_address_is_unspecified_false() {
744 assert!(!MacAddr([1, 2, 3, 4, 5, 6]).is_unspecified());
745 }
746
747 #[test]
748 fn check_mac_address_conversions() {
749 let mac = MacAddr([0xa, 0xb, 0xc, 0xd, 0xe, 0xf]);
750
751 let mac_s = mac.to_string();
752 assert_eq!("0a:0b:0c:0d:0e:0f", mac_s);
753 assert_eq!(Ok(mac), MacAddr::from_str(&mac_s));
754
755 assert_eq!(
756 MacAddr::from_str("0a:0b:0c:0d:0e:0f:01"),
757 Err(MacAddrFromStrError::InvalidAddrFormat)
758 );
759 assert_eq!(
760 MacAddr::from_str("0a:0b:0c:0d:0e"),
761 Err(MacAddrFromStrError::InvalidAddrFormat)
762 );
763 }
764
765 // Ensure that the `Display` and `Debug` traits are implemented on the `IpNetwork` struct
766 #[test]
767 fn check_display_impl_ip_network_ipv4() {
768 println!(
769 "{} {:?}",
770 IpNetwork {
771 addr: IpAddr::from(Ipv4Addr::new(1, 2, 3, 4)),
772 prefix: 3
773 },
774 IpNetwork {
775 addr: IpAddr::from(Ipv4Addr::new(255, 255, 255, 0)),
776 prefix: 21
777 }
778 );
779 }
780
781 #[test]
782 fn check_display_impl_ip_network_ipv6() {
783 println!(
784 "{} {:?}",
785 IpNetwork {
786 addr: IpAddr::from(Ipv6Addr::new(0xffff, 0xaabb, 00, 0, 0, 0x000c, 11, 21)),
787 prefix: 127
788 },
789 IpNetwork {
790 addr: IpAddr::from(Ipv6Addr::new(0xffcc, 0, 0, 0xffcc, 0, 0xffff, 0, 0xccaa)),
791 prefix: 120
792 }
793 )
794 }
795
796 #[test]
797 fn check_ip_networks() {
798 let networks = check_unsupported!(Networks::new_with_refreshed_list());
799 if networks.iter().any(|(_, n)| !n.ip_networks().is_empty()) {
800 return;
801 }
802 panic!("Networks should have at least one IP network ");
803 }
804
805 #[test]
806 fn check_ip_network_conversions() {
807 let addr = IpNetwork {
808 addr: IpAddr::from(Ipv6Addr::new(0xff, 0xa, 0x8, 0x12, 0x7, 0xc, 0xa, 0xb)),
809 prefix: 12,
810 };
811
812 let addr_s = addr.to_string();
813 assert_eq!("ff:a:8:12:7:c:a:b/12", addr_s);
814 assert_eq!(Ok(addr), IpNetwork::from_str(&addr_s));
815
816 let addr = IpNetwork {
817 addr: IpAddr::from(Ipv4Addr::new(255, 255, 255, 0)),
818 prefix: 21,
819 };
820
821 let addr_s = addr.to_string();
822 assert_eq!("255.255.255.0/21", addr_s);
823 assert_eq!(Ok(addr), IpNetwork::from_str(&addr_s));
824
825 assert_eq!(
826 IpNetwork::from_str("ff:a:8:12:7:c:a:b"),
827 Err(IpNetworkFromStrError::InvalidAddrFormat)
828 );
829 assert_eq!(
830 IpNetwork::from_str("ff:a:8:12:7:c:a:b/12/12"),
831 Err(IpNetworkFromStrError::InvalidAddrFormat)
832 );
833 match IpNetwork::from_str("0a:0b:0c:0d:0e/12") {
834 Err(IpNetworkFromStrError::AddrParseError(_)) => {}
835 x => panic!("expected `IpNetworkFromStrError::AddrParseError`, found {x:?}"),
836 }
837 }
838}