1use fidl_fuchsia_net_routes_ext as froutes_ext;
10use net_types::Witness as _;
11use net_types::ip::IpAddress as _;
12use thiserror::Error;
13
14#[derive(serde::Serialize, Ord, PartialOrd, Eq, PartialEq)]
15pub(crate) struct Subnet<T> {
16 pub(crate) addr: T,
17 pub(crate) prefix_len: u8,
18}
19
20impl From<fidl_fuchsia_net_ext::Subnet> for Subnet<std::net::IpAddr> {
21 fn from(ext: fidl_fuchsia_net_ext::Subnet) -> Subnet<std::net::IpAddr> {
22 let fidl_fuchsia_net_ext::Subnet {
23 addr: fidl_fuchsia_net_ext::IpAddress(addr),
24 prefix_len,
25 } = ext;
26 Subnet { addr, prefix_len }
27 }
28}
29
30impl<A: net_types::ip::IpAddress> From<net_types::ip::Subnet<A>> for Subnet<std::net::IpAddr> {
31 fn from(sub: net_types::ip::Subnet<A>) -> Subnet<std::net::IpAddr> {
32 let addr = sub.network().to_ip_addr().into();
33 let prefix_len = sub.prefix();
34 Subnet { addr, prefix_len }
35 }
36}
37
38#[derive(serde::Serialize, Ord, PartialOrd, Eq, PartialEq)]
39pub(crate) enum AddressAssignmentState {
40 Tentative,
41 Assigned,
42 Unavailable,
43}
44
45impl From<fidl_fuchsia_net_interfaces::AddressAssignmentState> for AddressAssignmentState {
46 fn from(value: fidl_fuchsia_net_interfaces::AddressAssignmentState) -> Self {
47 match value {
48 fidl_fuchsia_net_interfaces::AddressAssignmentState::Tentative => Self::Tentative,
49 fidl_fuchsia_net_interfaces::AddressAssignmentState::Assigned => Self::Assigned,
50 fidl_fuchsia_net_interfaces::AddressAssignmentState::Unavailable => Self::Unavailable,
51 }
52 }
53}
54
55#[derive(serde::Serialize, Ord, PartialOrd, Eq, PartialEq)]
56pub(crate) struct Address<I> {
57 #[serde(flatten)]
58 pub(crate) subnet: Subnet<I>,
59 pub(crate) valid_until: Option<i64>,
60 pub(crate) assignment_state: AddressAssignmentState,
61}
62
63impl<I> Address<I> {
64 fn map<I2, F: Fn(I) -> I2>(self, f: F) -> Address<I2> {
65 let Self { subnet: Subnet { addr, prefix_len }, valid_until, assignment_state } = self;
66 Address { subnet: Subnet { addr: f(addr), prefix_len }, valid_until, assignment_state }
67 }
68}
69
70#[derive(serde::Serialize)]
71pub(crate) struct Addresses {
72 pub(crate) ipv4: Vec<Address<std::net::Ipv4Addr>>,
73 pub(crate) ipv6: Vec<Address<std::net::Ipv6Addr>>,
74}
75
76impl Addresses {
77 pub(crate) fn all_addresses(self) -> impl Iterator<Item = Address<std::net::IpAddr>> {
78 let Self { ipv4, ipv6 } = self;
79 ipv4.into_iter()
80 .map(|a| a.map(Into::into))
81 .chain(ipv6.into_iter().map(|a| a.map(Into::into)))
82 }
83}
84
85impl<
86 I: Iterator<
87 Item = fidl_fuchsia_net_interfaces_ext::Address<
88 fidl_fuchsia_net_interfaces_ext::AllInterest,
89 >,
90 >,
91> From<I> for Addresses
92{
93 fn from(addresses: I) -> Addresses {
94 use itertools::Itertools as _;
95
96 let (mut ipv4, mut ipv6): (Vec<_>, Vec<_>) = addresses.into_iter().partition_map(
97 |fidl_fuchsia_net_interfaces_ext::Address {
98 addr,
99 valid_until,
100 assignment_state,
101 preferred_lifetime_info: _,
103 }| {
104 let fidl_fuchsia_net_ext::Subnet {
105 addr: fidl_fuchsia_net_ext::IpAddress(addr),
106 prefix_len,
107 } = addr.into();
108 let assignment_state = assignment_state.into();
109
110 fn new_address<I>(
111 addr: I,
112 prefix_len: u8,
113 valid_until: fidl_fuchsia_net_interfaces_ext::PositiveMonotonicInstant,
114 assignment_state: AddressAssignmentState,
115 ) -> Address<I> {
116 let valid_until =
117 (!valid_until.is_infinite()).then_some(valid_until.into_nanos());
118 Address { subnet: Subnet { addr, prefix_len }, valid_until, assignment_state }
119 }
120 match addr {
121 std::net::IpAddr::V4(addr) => itertools::Either::Left(new_address(
122 addr,
123 prefix_len,
124 valid_until,
125 assignment_state,
126 )),
127 std::net::IpAddr::V6(addr) => itertools::Either::Right(new_address(
128 addr,
129 prefix_len,
130 valid_until,
131 assignment_state,
132 )),
133 }
134 },
135 );
136 ipv4.sort();
137 ipv6.sort();
138 Addresses { ipv4, ipv6 }
139 }
140}
141
142#[derive(serde::Serialize)]
143pub(crate) enum DeviceClass {
144 Loopback,
145 Blackhole,
146 Virtual,
147 Ethernet,
148 WlanClient,
149 Ppp,
150 Bridge,
151 WlanAp,
152 Lowpan,
153}
154
155impl From<fidl_fuchsia_net_interfaces_ext::PortClass> for DeviceClass {
156 fn from(port_class: fidl_fuchsia_net_interfaces_ext::PortClass) -> Self {
157 match port_class {
158 fidl_fuchsia_net_interfaces_ext::PortClass::Loopback => Self::Loopback,
159 fidl_fuchsia_net_interfaces_ext::PortClass::Blackhole => Self::Blackhole,
160 fidl_fuchsia_net_interfaces_ext::PortClass::Virtual => Self::Virtual,
161 fidl_fuchsia_net_interfaces_ext::PortClass::Ethernet => Self::Ethernet,
162 fidl_fuchsia_net_interfaces_ext::PortClass::WlanClient => Self::WlanClient,
163 fidl_fuchsia_net_interfaces_ext::PortClass::WlanAp => Self::WlanAp,
164 fidl_fuchsia_net_interfaces_ext::PortClass::Ppp => Self::Ppp,
165 fidl_fuchsia_net_interfaces_ext::PortClass::Bridge => Self::Bridge,
166 fidl_fuchsia_net_interfaces_ext::PortClass::Lowpan => Self::Lowpan,
167 }
168 }
169}
170
171#[derive(serde::Serialize)]
172pub(crate) struct InterfaceView {
174 pub(crate) nicid: u64,
175 pub(crate) name: String,
176 pub(crate) device_class: DeviceClass,
177 pub(crate) online: bool,
178 pub(crate) addresses: Addresses,
179 pub(crate) has_default_ipv4_route: bool,
180 pub(crate) has_default_ipv6_route: bool,
181 pub(crate) mac: Option<fidl_fuchsia_net_ext::MacAddress>,
182 pub(crate) port_identity_koid: Option<zx_types::zx_koid_t>,
183}
184
185impl
186 From<(
187 fidl_fuchsia_net_interfaces_ext::Properties<fidl_fuchsia_net_interfaces_ext::AllInterest>,
188 Option<fidl_fuchsia_net::MacAddress>,
189 )> for InterfaceView
190{
191 fn from(
192 t: (
193 fidl_fuchsia_net_interfaces_ext::Properties<
194 fidl_fuchsia_net_interfaces_ext::AllInterest,
195 >,
196 Option<fidl_fuchsia_net::MacAddress>,
197 ),
198 ) -> InterfaceView {
199 let (
200 fidl_fuchsia_net_interfaces_ext::Properties {
201 id,
202 name,
203 port_class,
204 online,
205 addresses,
206 has_default_ipv4_route,
207 has_default_ipv6_route,
208 port_identity_koid,
209 },
210 mac,
211 ) = t;
212 InterfaceView {
213 nicid: id.get(),
214 name,
215 device_class: port_class.into(),
216 online,
217 addresses: addresses.into_iter().into(),
218 has_default_ipv4_route,
219 has_default_ipv6_route,
220 mac: mac.map(Into::into),
221 port_identity_koid: port_identity_koid.map(|e| e.raw_koid()),
222 }
223 }
224}
225
226#[derive(serde::Serialize, Ord, PartialOrd, Eq, PartialEq)]
227pub struct ForwardingEntry {
229 #[serde(rename = "destination")]
230 subnet: Subnet<std::net::IpAddr>,
231 #[serde(rename = "nicid")]
232 device_id: u64,
233 #[serde(rename = "gateway")]
234 next_hop: Option<std::net::IpAddr>,
235 metric: u32,
236 table_id: u32,
237}
238
239#[derive(Debug, Error)]
242pub enum ForwardingEntryConversionError {
243 #[error("the route's action was unknown")]
244 UnknownRouteAction,
245}
246
247impl<I: net_types::ip::Ip> TryFrom<froutes_ext::InstalledRoute<I>> for ForwardingEntry {
248 type Error = ForwardingEntryConversionError;
249 fn try_from(route: froutes_ext::InstalledRoute<I>) -> Result<Self, Self::Error> {
250 let froutes_ext::InstalledRoute {
251 route: froutes_ext::Route { destination, action, properties: _ },
252 effective_properties: froutes_ext::EffectiveRouteProperties { metric },
253 table_id,
254 } = route;
255 let (device_id, next_hop) = match action {
256 froutes_ext::RouteAction::Forward(froutes_ext::RouteTarget {
257 outbound_interface,
258 next_hop,
259 }) => (outbound_interface, next_hop),
260 froutes_ext::RouteAction::Unknown => {
261 return Err(ForwardingEntryConversionError::UnknownRouteAction);
262 }
263 };
264 let subnet = destination.into();
265 let next_hop = next_hop.map(|next_hop| next_hop.get().to_ip_addr().into());
266 Ok(Self { subnet, device_id, next_hop, metric, table_id: table_id.get() })
267 }
268}
269
270pub struct NeighborTableEntryIteratorItemVariants<T> {
271 existing: T,
272 added: T,
273 changed: T,
274 removed: T,
275 idle: T,
276}
277
278impl<T> NeighborTableEntryIteratorItemVariants<T> {
279 pub fn select(self, item: &fidl_fuchsia_net_neighbor::EntryIteratorItem) -> T {
280 use fidl_fuchsia_net_neighbor::EntryIteratorItem;
281 let Self { existing, added, changed, removed, idle } = self;
282 match item {
283 EntryIteratorItem::Existing(_) => existing,
284 EntryIteratorItem::Added(_) => added,
285 EntryIteratorItem::Changed(_) => changed,
286 EntryIteratorItem::Removed(_) => removed,
287 EntryIteratorItem::Idle(_) => idle,
288 }
289 }
290}
291
292impl<T> IntoIterator for NeighborTableEntryIteratorItemVariants<T> {
293 type Item = T;
294 type IntoIter = <[T; 5] as IntoIterator>::IntoIter;
295
296 fn into_iter(self) -> Self::IntoIter {
297 let Self { existing, added, changed, removed, idle } = self;
298 [existing, added, changed, removed, idle].into_iter()
299 }
300}
301
302pub const DISPLAYED_NEIGH_ENTRY_VARIANTS: NeighborTableEntryIteratorItemVariants<&'static str> =
303 NeighborTableEntryIteratorItemVariants {
304 existing: "EXISTING",
305 added: "ADDED",
306 changed: "CHANGED",
307 removed: "REMOVED",
308 idle: "IDLE",
309 };
310
311#[derive(serde::Serialize)]
313pub struct NeighborTableEntry {
314 interface: u64,
315 neighbor: std::net::IpAddr,
316 state: &'static str,
317 mac: Option<fidl_fuchsia_net_ext::MacAddress>,
318}
319
320impl From<fidl_fuchsia_net_neighbor_ext::Entry> for NeighborTableEntry {
321 fn from(
322 fidl_fuchsia_net_neighbor_ext::Entry {
323 interface,
324 neighbor,
325 state,
326 mac,
327 updated_at: _,
329 }: fidl_fuchsia_net_neighbor_ext::Entry,
330 ) -> NeighborTableEntry {
331 let fidl_fuchsia_net_ext::IpAddress(neighbor) = neighbor.into();
332 NeighborTableEntry {
333 interface,
334 neighbor,
335 state: fidl_fuchsia_net_neighbor_ext::display_entry_state(&state),
336 mac: mac.map(|mac| mac.into()),
337 }
338 }
339}