1use fidl_fuchsia_net_routes_ext as froutes_ext;
10use net_types::ip::IpAddress as _;
11use net_types::Witness 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}
183
184impl
185 From<(
186 fidl_fuchsia_net_interfaces_ext::Properties<fidl_fuchsia_net_interfaces_ext::AllInterest>,
187 Option<fidl_fuchsia_net::MacAddress>,
188 )> for InterfaceView
189{
190 fn from(
191 t: (
192 fidl_fuchsia_net_interfaces_ext::Properties<
193 fidl_fuchsia_net_interfaces_ext::AllInterest,
194 >,
195 Option<fidl_fuchsia_net::MacAddress>,
196 ),
197 ) -> InterfaceView {
198 let (
199 fidl_fuchsia_net_interfaces_ext::Properties {
200 id,
201 name,
202 port_class,
203 online,
204 addresses,
205 has_default_ipv4_route,
206 has_default_ipv6_route,
207 },
208 mac,
209 ) = t;
210 InterfaceView {
211 nicid: id.get(),
212 name,
213 device_class: port_class.into(),
214 online,
215 addresses: addresses.into_iter().into(),
216 has_default_ipv4_route,
217 has_default_ipv6_route,
218 mac: mac.map(Into::into),
219 }
220 }
221}
222
223#[derive(serde::Serialize, Ord, PartialOrd, Eq, PartialEq)]
224pub struct ForwardingEntry {
226 #[serde(rename = "destination")]
227 subnet: Subnet<std::net::IpAddr>,
228 #[serde(rename = "nicid")]
229 device_id: u64,
230 #[serde(rename = "gateway")]
231 next_hop: Option<std::net::IpAddr>,
232 metric: u32,
233}
234
235#[derive(Debug, Error)]
238pub enum ForwardingEntryConversionError {
239 #[error("the route's action was unknown")]
240 UnknownRouteAction,
241}
242
243impl<I: net_types::ip::Ip> TryFrom<froutes_ext::InstalledRoute<I>> for ForwardingEntry {
244 type Error = ForwardingEntryConversionError;
245 fn try_from(route: froutes_ext::InstalledRoute<I>) -> Result<Self, Self::Error> {
246 let froutes_ext::InstalledRoute {
247 route: froutes_ext::Route { destination, action, properties: _ },
248 effective_properties: froutes_ext::EffectiveRouteProperties { metric },
249 table_id: _,
250 } = route;
251 let (device_id, next_hop) = match action {
252 froutes_ext::RouteAction::Forward(froutes_ext::RouteTarget {
253 outbound_interface,
254 next_hop,
255 }) => (outbound_interface, next_hop),
256 froutes_ext::RouteAction::Unknown => {
257 return Err(ForwardingEntryConversionError::UnknownRouteAction)
258 }
259 };
260 let subnet = destination.into();
261 let next_hop = next_hop.map(|next_hop| next_hop.get().to_ip_addr().into());
262 Ok(Self { subnet, device_id, next_hop, metric })
263 }
264}
265
266pub struct NeighborTableEntryIteratorItemVariants<T> {
267 existing: T,
268 added: T,
269 changed: T,
270 removed: T,
271 idle: T,
272}
273
274impl<T> NeighborTableEntryIteratorItemVariants<T> {
275 pub fn select(self, item: &fidl_fuchsia_net_neighbor::EntryIteratorItem) -> T {
276 use fidl_fuchsia_net_neighbor::EntryIteratorItem;
277 let Self { existing, added, changed, removed, idle } = self;
278 match item {
279 EntryIteratorItem::Existing(_) => existing,
280 EntryIteratorItem::Added(_) => added,
281 EntryIteratorItem::Changed(_) => changed,
282 EntryIteratorItem::Removed(_) => removed,
283 EntryIteratorItem::Idle(_) => idle,
284 }
285 }
286}
287
288impl<T> IntoIterator for NeighborTableEntryIteratorItemVariants<T> {
289 type Item = T;
290 type IntoIter = <[T; 5] as IntoIterator>::IntoIter;
291
292 fn into_iter(self) -> Self::IntoIter {
293 let Self { existing, added, changed, removed, idle } = self;
294 [existing, added, changed, removed, idle].into_iter()
295 }
296}
297
298pub const DISPLAYED_NEIGH_ENTRY_VARIANTS: NeighborTableEntryIteratorItemVariants<&'static str> =
299 NeighborTableEntryIteratorItemVariants {
300 existing: "EXISTING",
301 added: "ADDED",
302 changed: "CHANGED",
303 removed: "REMOVED",
304 idle: "IDLE",
305 };
306
307#[derive(serde::Serialize)]
309pub struct NeighborTableEntry {
310 interface: u64,
311 neighbor: std::net::IpAddr,
312 state: &'static str,
313 mac: Option<fidl_fuchsia_net_ext::MacAddress>,
314}
315
316impl From<fidl_fuchsia_net_neighbor_ext::Entry> for NeighborTableEntry {
317 fn from(
318 fidl_fuchsia_net_neighbor_ext::Entry {
319 interface,
320 neighbor,
321 state,
322 mac,
323 updated_at: _,
325 }: fidl_fuchsia_net_neighbor_ext::Entry,
326 ) -> NeighborTableEntry {
327 let fidl_fuchsia_net_ext::IpAddress(neighbor) = neighbor.into();
328 NeighborTableEntry {
329 interface,
330 neighbor,
331 state: fidl_fuchsia_net_neighbor_ext::display_entry_state(&state),
332 mac: mac.map(|mac| mac.into()),
333 }
334 }
335}