1use std::fmt;
2
3use net_lattice_core::Id;
4
5use crate::mac::MacAddress;
6
7pub type InterfaceId = Id<Interface>;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
18#[non_exhaustive]
19pub enum InterfaceKind {
20 Ethernet,
22 Wireless,
24 Loopback,
26 PointToPoint,
28 Bridge,
30 Other(u32),
33}
34
35impl fmt::Display for InterfaceKind {
36 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37 match self {
38 InterfaceKind::Ethernet => write!(f, "ethernet"),
39 InterfaceKind::Wireless => write!(f, "wireless"),
40 InterfaceKind::Loopback => write!(f, "loopback"),
41 InterfaceKind::PointToPoint => write!(f, "point-to-point"),
42 InterfaceKind::Bridge => write!(f, "bridge"),
43 InterfaceKind::Other(code) => write!(f, "other({code})"),
44 }
45 }
46}
47
48#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
54#[non_exhaustive]
55pub enum AdminState {
56 Up,
57 Down,
58 Unknown,
61}
62
63#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
65#[non_exhaustive]
66pub enum OperationalState {
67 Up,
68 Down,
69 NoCarrier,
71 Unknown,
73}
74
75#[derive(Debug, Clone, PartialEq, Eq, Hash)]
85#[non_exhaustive]
86pub struct Interface {
87 pub id: InterfaceId,
88 pub index: u32,
93 pub name: String,
94 pub kind: InterfaceKind,
95 pub mac: Option<MacAddress>,
96 pub mtu: Option<u32>,
97 pub admin_state: AdminState,
98 pub operational_state: OperationalState,
99}
100
101impl Interface {
102 pub fn new(id: InterfaceId, index: u32, name: impl Into<String>, kind: InterfaceKind) -> Self {
103 Self {
104 id,
105 index,
106 name: name.into(),
107 kind,
108 mac: None,
109 mtu: None,
110 admin_state: AdminState::Unknown,
111 operational_state: OperationalState::Unknown,
112 }
113 }
114
115 pub fn with_mac(mut self, mac: MacAddress) -> Self {
116 self.mac = Some(mac);
117 self
118 }
119
120 pub fn with_mtu(mut self, mtu: u32) -> Self {
121 self.mtu = Some(mtu);
122 self
123 }
124
125 pub fn with_admin_state(mut self, state: AdminState) -> Self {
126 self.admin_state = state;
127 self
128 }
129
130 pub fn with_operational_state(mut self, state: OperationalState) -> Self {
131 self.operational_state = state;
132 self
133 }
134}
135
136#[cfg(test)]
137mod tests {
138 use super::*;
139
140 #[test]
141 fn new_interface_has_no_optional_fields() {
142 let iface = Interface::new(InterfaceId::new(1), 1, "eth0", InterfaceKind::Ethernet);
143 assert!(iface.mac.is_none());
144 assert!(iface.mtu.is_none());
145 assert_eq!(iface.admin_state, AdminState::Unknown);
146 assert_eq!(iface.operational_state, OperationalState::Unknown);
147 }
148
149 #[test]
150 fn builder_methods_set_optional_fields() {
151 let mac = MacAddress::new([0x02, 0x00, 0x00, 0x00, 0x00, 0x01]);
152 let iface = Interface::new(InterfaceId::new(1), 1, "eth0", InterfaceKind::Ethernet)
153 .with_mac(mac)
154 .with_mtu(1500)
155 .with_admin_state(AdminState::Up)
156 .with_operational_state(OperationalState::Up);
157 assert_eq!(iface.mac, Some(mac));
158 assert_eq!(iface.mtu, Some(1500));
159 assert_eq!(iface.admin_state, AdminState::Up);
160 assert_eq!(iface.operational_state, OperationalState::Up);
161 }
162
163 #[test]
164 fn kind_displays() {
165 assert_eq!(InterfaceKind::Ethernet.to_string(), "ethernet");
166 assert_eq!(InterfaceKind::Wireless.to_string(), "wireless");
167 assert_eq!(InterfaceKind::Loopback.to_string(), "loopback");
168 assert_eq!(InterfaceKind::PointToPoint.to_string(), "point-to-point");
169 assert_eq!(InterfaceKind::Bridge.to_string(), "bridge");
170 assert_eq!(InterfaceKind::Other(42).to_string(), "other(42)");
171 }
172}