1use std::collections::{BTreeMap, HashMap, HashSet};
9use std::net::IpAddr;
10use std::num::NonZeroU64;
11
12use crate::Errno;
13use crate::client::{ClientTable, InternalClient};
14use crate::logging::{log_debug, log_warn};
15use crate::messaging::Sender;
16use crate::multicast_groups::ModernGroup;
17use crate::netlink_packet::UNSPECIFIED_SEQUENCE_NUMBER;
18use crate::protocol_family::ProtocolFamily;
19use crate::protocol_family::route::NetlinkRoute;
20use crate::util::respond_to_completer;
21use derivative::Derivative;
22use futures::StreamExt as _;
23use futures::channel::oneshot;
24use linux_uapi::rtnetlink_groups_RTNLGRP_NEIGH;
25use net_types::ip::IpVersion;
26use netlink_packet_core::{
27 NLM_F_APPEND, NLM_F_CREATE, NLM_F_EXCL, NLM_F_MULTIPART, NLM_F_REPLACE, NetlinkMessage,
28};
29use netlink_packet_route::neighbour::{
30 NeighbourAddress, NeighbourAttribute, NeighbourFlags, NeighbourHeader, NeighbourMessage,
31 NeighbourState,
32};
33use netlink_packet_route::route::RouteType;
34use netlink_packet_route::{AddressFamily, RouteNetlinkMessage};
35use thiserror::Error;
36
37use fidl_fuchsia_net as fnet;
38use fidl_fuchsia_net_ext as fnet_ext;
39use fidl_fuchsia_net_interfaces_ext as fnet_interfaces_ext;
40use fidl_fuchsia_net_neighbor as fnet_neighbor;
41use fidl_fuchsia_net_neighbor_ext as fnet_neighbor_ext;
42
43#[derive(Debug, PartialEq)]
45pub(crate) enum NetlinkNeighborMessageConversionError {
46 InvalidInterfaceId(u64),
48}
49
50#[derive(Clone, Debug, Eq, PartialEq)]
53pub(crate) struct NetlinkNeighborMessage(pub(crate) NeighbourMessage);
54
55impl NetlinkNeighborMessage {
56 pub(crate) fn optionally_from(
57 neighbor: fnet_neighbor_ext::Entry,
58 ) -> Option<NetlinkNeighborMessage> {
59 match neighbor.try_into() {
60 Ok(message) => Some(message),
61 Err(NetlinkNeighborMessageConversionError::InvalidInterfaceId(id)) => {
62 log_warn!("Invalid interface id found in neighbor table entry: {}", id);
63 None
64 }
65 }
66 }
67
68 pub(crate) fn into_rtnl_new_neighbor(
70 self,
71 sequence_number: u32,
72 is_dump: bool,
73 ) -> NetlinkMessage<RouteNetlinkMessage> {
74 let NetlinkNeighborMessage(message) = self;
75 let mut msg: NetlinkMessage<RouteNetlinkMessage> =
76 RouteNetlinkMessage::NewNeighbour(message).into();
77 msg.header.sequence_number = sequence_number;
78 if is_dump {
79 msg.header.flags |= NLM_F_MULTIPART;
80 }
81 msg.finalize();
82 msg
83 }
84
85 pub(crate) fn into_rtnl_del_neighbor(self) -> NetlinkMessage<RouteNetlinkMessage> {
87 let NetlinkNeighborMessage(message) = self;
88 let mut msg: NetlinkMessage<RouteNetlinkMessage> =
89 RouteNetlinkMessage::DelNeighbour(message).into();
90 msg.finalize();
91 msg
92 }
93}
94
95impl TryFrom<fnet_neighbor_ext::Entry> for NetlinkNeighborMessage {
96 type Error = NetlinkNeighborMessageConversionError;
97
98 fn try_from(
99 neighbor: fnet_neighbor_ext::Entry,
100 ) -> Result<NetlinkNeighborMessage, NetlinkNeighborMessageConversionError> {
101 let mut header = NeighbourHeader::default();
102 let fnet_ext::IpAddress(addr) = neighbor.neighbor.into();
103 header.family = match addr {
104 IpAddr::V4(_) => AddressFamily::Inet,
105 IpAddr::V6(_) => AddressFamily::Inet6,
106 };
107 header.ifindex = neighbor.interface.get().try_into().map_err(|_| {
108 NetlinkNeighborMessageConversionError::InvalidInterfaceId(neighbor.interface.get())
109 })?;
110 header.state = match neighbor.state {
111 fnet_neighbor::EntryState::Delay => NeighbourState::Delay,
112 fnet_neighbor::EntryState::Incomplete => NeighbourState::Incomplete,
113 fnet_neighbor::EntryState::Probe => NeighbourState::Probe,
114 fnet_neighbor::EntryState::Reachable => NeighbourState::Reachable,
115 fnet_neighbor::EntryState::Stale => NeighbourState::Stale,
116 fnet_neighbor::EntryState::Static => NeighbourState::Permanent,
117 fnet_neighbor::EntryState::Unreachable => NeighbourState::Failed,
118 };
119 header.kind = RouteType::Unicast;
123
124 let mut attributes = vec![];
125 attributes.push(NeighbourAttribute::Destination(match addr {
126 IpAddr::V4(addr) => addr.into(),
127 IpAddr::V6(addr) => addr.into(),
128 }));
129 if let Some(mac) = neighbor.mac {
130 attributes.push(NeighbourAttribute::LinkLocalAddress(mac.octets.into()));
131 }
132 let mut msg = NeighbourMessage::default();
136 msg.header = header;
137 msg.attributes = attributes;
138 Ok(NetlinkNeighborMessage(msg))
139 }
140}
141
142fn neighbor_fidl_ip(
143 family: AddressFamily,
144 address: Option<&NeighbourAddress>,
145) -> Result<fnet::IpAddress, RequestError> {
146 match family {
147 AddressFamily::Inet => match address {
148 Some(NeighbourAddress::Inet(addr)) => Ok(fnet_ext::IpAddress(IpAddr::V4(*addr)).into()),
149 Some(_) => Err(RequestError::AddressFamilyMismatch(family)),
150 None => Err(RequestError::MissingIpAddress),
151 },
152 AddressFamily::Inet6 => match address {
153 Some(NeighbourAddress::Inet6(addr)) => {
154 Ok(fnet_ext::IpAddress(IpAddr::V6(*addr)).into())
155 }
156 Some(_) => Err(RequestError::AddressFamilyMismatch(family)),
157 None => Err(RequestError::MissingIpAddress),
158 },
159 _ => Err(RequestError::InvalidAddressFamily(family)),
160 }
161}
162
163#[derive(Copy, Clone, Debug, PartialEq, Eq)]
165pub(crate) enum GetNeighborArgs {
166 Dump { ip_version: Option<IpVersion>, interface: Option<NonZeroU64> },
167 Get { ip: fnet::IpAddress, interface: NonZeroU64 },
168}
169
170impl GetNeighborArgs {
171 pub(crate) fn try_from_rtnl_neighbor(
174 message: &NeighbourMessage,
175 is_dump: bool,
176 ) -> Result<Self, RequestError> {
177 if is_dump {
178 Self::dump_request_from_rtnl_neighbor(message)
179 .inspect_err(|e| log_debug!("{e} in dump neighbors request"))
180 } else {
181 Self::get_request_from_rtnl_neighbor(message)
182 .inspect_err(|e| log_debug!("{e} in get neighbors request"))
183 }
184 }
185
186 fn dump_request_from_rtnl_neighbor(message: &NeighbourMessage) -> Result<Self, RequestError> {
187 let NeighbourHeader { family, flags, .. } = &message.header;
188 if flags.contains(NeighbourFlags::Proxy) {
189 log_warn!("unsupported Proxy flag in dump neighbors request");
192 return Err(RequestError::UnsupportedFlags(*flags));
193 }
194 let ip_version = match family {
197 AddressFamily::Unspec => None,
198 AddressFamily::Inet => Some(IpVersion::V4),
199 AddressFamily::Inet6 => Some(IpVersion::V6),
200 family => {
201 return Err(RequestError::InvalidAddressFamily(*family));
202 }
203 };
204 let interface = message
208 .attributes
209 .iter()
210 .find_map(|attr| match attr {
211 NeighbourAttribute::IfIndex(ifindex) => Some(u64::from(*ifindex).try_into()),
212 _ => None,
213 })
214 .transpose()
215 .unwrap_or(None);
217 Ok(GetNeighborArgs::Dump { ip_version, interface })
218 }
219
220 fn get_request_from_rtnl_neighbor(message: &NeighbourMessage) -> Result<Self, RequestError> {
221 let NeighbourHeader { ifindex, family, state, flags, kind } = &message.header;
222 if *state != NeighbourState::None {
223 return Err(RequestError::InvalidState {
224 actual: *state,
225 expected: NeighbourState::None,
226 });
227 }
228 if *kind != RouteType::Unspec {
229 return Err(RequestError::InvalidKind(*kind));
230 }
231 if flags.intersects(!NeighbourFlags::Proxy) {
232 return Err(RequestError::InvalidFlags(*flags));
233 }
234 if flags.contains(NeighbourFlags::Proxy) {
235 log_warn!("unsupported Proxy flag in get neighbor request");
238 return Err(RequestError::UnsupportedFlags(*flags));
239 }
240
241 let (address, unsupported) = message.attributes.iter().fold(
242 (None, false),
243 |(address_acc, unsupported_acc), attr| {
244 match attr {
245 NeighbourAttribute::Destination(addr) => {
246 (address_acc.or(Some(addr)), unsupported_acc)
249 }
250 _ => {
251 if !unsupported_acc {
252 log_warn!(
254 "unsupported request attribute: {attr:?} in get neighbor\
255 request; only `DST` is supported"
256 );
257 }
258 (address_acc, true)
259 }
260 }
261 },
262 );
263 if unsupported {
264 return Err(RequestError::InvalidAttribute);
265 }
266 let ip = neighbor_fidl_ip(*family, address)?;
267 let interface =
271 u64::from(*ifindex).try_into().map_err(|_| RequestError::MissingInterface)?;
272 Ok(GetNeighborArgs::Get { ip, interface })
273 }
274}
275
276#[derive(Copy, Clone, Debug, PartialEq, Eq)]
278pub(crate) enum NewNeighborArgs {
279 CreateStatic { ip: fnet::IpAddress, interface: NonZeroU64, mac: fnet::MacAddress },
280 ProbeExisting { ip: fnet::IpAddress, interface: NonZeroU64 },
281}
282
283impl NewNeighborArgs {
284 pub(crate) fn try_from_rtnl_neighbor(
287 message: &NeighbourMessage,
288 netlink_flags: u16,
289 ) -> Result<Self, RequestError> {
290 Self::try_from_rtnl_neighbor_internal(message, netlink_flags)
291 .inspect_err(|e| log_debug!("{e} in new neighbor request"))
292 }
293
294 fn try_from_rtnl_neighbor_internal(
295 message: &NeighbourMessage,
296 netlink_flags: u16,
297 ) -> Result<Self, RequestError> {
298 let NeighbourHeader { ifindex, family, flags, state, .. } = &message.header;
299 if flags.contains(NeighbourFlags::Proxy) {
300 log_warn!("unsupported Proxy flag in new neighbor request");
303 return Err(RequestError::UnsupportedFlags(*flags));
304 }
305
306 let (ip_addr, ll_addr) =
309 message.attributes.iter().fold((None, None), |acc @ (ip, ll), attr| match attr {
310 NeighbourAttribute::Destination(addr) => (ip.or(Some(addr)), ll),
313 NeighbourAttribute::LinkLocalAddress(addr) => (ip, ll.or(Some(addr))),
314 _ => acc,
315 });
316 let ip = neighbor_fidl_ip(*family, ip_addr)?;
317 let interface =
318 u64::from(*ifindex).try_into().map_err(|_| RequestError::MissingInterface)?;
319
320 let new_neighbor_flags = NLM_F_CREATE | NLM_F_REPLACE | NLM_F_EXCL | NLM_F_APPEND;
324 let set_flags = netlink_flags & new_neighbor_flags;
325 if set_flags == NLM_F_REPLACE {
326 if *state != NeighbourState::Probe {
329 return Err(RequestError::InvalidState {
330 actual: *state,
331 expected: NeighbourState::Probe,
332 });
333 }
334 if ll_addr.is_some() {
337 return Err(RequestError::InvalidAttribute);
338 }
339 Ok(NewNeighborArgs::ProbeExisting { interface, ip })
340 } else if set_flags == (NLM_F_CREATE | NLM_F_REPLACE) {
341 if *state != NeighbourState::Permanent {
344 return Err(RequestError::InvalidState {
345 actual: *state,
346 expected: NeighbourState::Permanent,
347 });
348 }
349 let mac = ll_addr.ok_or(RequestError::MissingMacAddress).and_then(|mac| {
350 mac.clone()
351 .try_into()
352 .map_err(|_| RequestError::InvalidMacAddress)
353 .map(|octets| fnet::MacAddress { octets })
354 })?;
355 Ok(NewNeighborArgs::CreateStatic { interface, ip, mac })
356 } else {
357 Err(RequestError::UnsupportedOperation)
358 }
359 }
360}
361
362#[derive(Copy, Clone, Debug, PartialEq, Eq)]
364pub(crate) struct DelNeighborArgs {
365 pub(crate) ip: fnet::IpAddress,
366 pub(crate) interface: NonZeroU64,
367}
368
369impl DelNeighborArgs {
370 pub(crate) fn try_from_rtnl_neighbor(message: &NeighbourMessage) -> Result<Self, RequestError> {
373 Self::try_from_rtnl_neighbor_internal(message)
374 .inspect_err(|e| log_debug!("{e} in del neighbor request"))
375 }
376
377 fn try_from_rtnl_neighbor_internal(message: &NeighbourMessage) -> Result<Self, RequestError> {
378 let NeighbourHeader { ifindex, family, flags, .. } = &message.header;
379 if flags.contains(NeighbourFlags::Proxy) {
380 log_warn!("unsupported Proxy flag in del neighbor request");
383 return Err(RequestError::UnsupportedFlags(*flags));
384 }
385
386 let address = message.attributes.iter().find_map(|attr| match attr {
387 NeighbourAttribute::Destination(addr) => Some(addr),
388 _ => None,
389 });
390 let ip = neighbor_fidl_ip(*family, address)?;
391 let interface =
392 u64::from(*ifindex).try_into().map_err(|_| RequestError::MissingInterface)?;
393 Ok(Self { interface, ip })
394 }
395}
396
397#[derive(Copy, Clone, Debug, PartialEq, Eq)]
399pub(crate) enum NeighborRequestArgs {
400 Get(GetNeighborArgs),
402 New(NewNeighborArgs),
404 Del(DelNeighborArgs),
406}
407
408#[derive(Copy, Clone, Debug, PartialEq, Eq, Error)]
410pub(crate) enum RequestError {
411 #[error("invalid state; expected={expected:?}, actual={actual:?}")]
413 InvalidState { actual: NeighbourState, expected: NeighbourState },
414 #[error("invalid kind: {0:?}")]
416 InvalidKind(RouteType),
417 #[error("invalid flags: {0:?}")]
419 InvalidFlags(NeighbourFlags),
420 #[error("unsupported flags: {0:?}")]
422 UnsupportedFlags(NeighbourFlags),
423 #[error("invalid address family: {0:?}")]
425 InvalidAddressFamily(AddressFamily),
426 #[error("address family mismatch; expected={0:?}")]
432 AddressFamilyMismatch(AddressFamily),
433 #[error("missing required `DST` attribute")]
435 MissingIpAddress,
436 #[error("missing required `LLADDR` attribute")]
438 MissingMacAddress,
439 #[error("missing required interface")]
441 MissingInterface,
442 #[error("invalid request attribute")]
444 InvalidAttribute,
445 #[error("no such neighbor")]
447 NeighborNotFound,
448 #[error("no such interface")]
450 InterfaceNotFound,
451 #[error("invalid neighbor IP address")]
453 InvalidIpAddress,
454 #[error("invalid neighbor MAC address")]
456 InvalidMacAddress,
457 #[error("interface not supported")]
459 InterfaceUnsupported,
460 #[error("link address unknown")]
462 LinkAddressUnknown,
463 #[error("unsupported operation")]
465 UnsupportedOperation,
466 #[error("table full")]
468 TableFull,
469}
470
471impl From<RequestError> for Errno {
472 fn from(value: RequestError) -> Self {
473 match value {
474 RequestError::InvalidState { .. } => Errno::EINVAL,
475 RequestError::InvalidKind(_) => Errno::EINVAL,
476 RequestError::InvalidFlags(_) => Errno::EINVAL,
477 RequestError::UnsupportedFlags(_) => Errno::ENOTSUP,
478 RequestError::InvalidAddressFamily(_) => Errno::EAFNOSUPPORT,
479 RequestError::AddressFamilyMismatch(_) => Errno::EINVAL,
480 RequestError::MissingIpAddress => Errno::EINVAL,
481 RequestError::MissingMacAddress => Errno::EINVAL,
482 RequestError::MissingInterface => Errno::EINVAL,
483 RequestError::InvalidAttribute => Errno::EINVAL,
484 RequestError::NeighborNotFound => Errno::ENOENT,
485 RequestError::InterfaceNotFound => Errno::ENODEV,
486 RequestError::InvalidIpAddress => Errno::EINVAL,
487 RequestError::InvalidMacAddress => Errno::EINVAL,
488 RequestError::InterfaceUnsupported => Errno::ENOTSUP,
489 RequestError::LinkAddressUnknown => Errno::EINVAL,
490 RequestError::UnsupportedOperation => Errno::ENOTSUP,
491 RequestError::TableFull => Errno::ENOBUFS,
492 }
493 }
494}
495
496impl From<fnet_neighbor::ControllerError> for RequestError {
497 fn from(value: fnet_neighbor::ControllerError) -> Self {
498 use fnet_neighbor::ControllerError;
499 match value {
500 ControllerError::InterfaceNotFound => RequestError::InterfaceNotFound,
501 ControllerError::InterfaceNotSupported => RequestError::InterfaceUnsupported,
502 ControllerError::InvalidIpAddress => RequestError::InvalidIpAddress,
503 ControllerError::MacAddressNotUnicast => RequestError::InvalidMacAddress,
504 ControllerError::NeighborNotFound => RequestError::NeighborNotFound,
505 ControllerError::LinkAddressUnknown => RequestError::LinkAddressUnknown,
506 ControllerError::TooManyEntries => RequestError::TableFull,
507 ControllerError::__SourceBreaking { unknown_ordinal: e } => {
508 panic!("encountered unknown controller error: {e:?}")
509 }
510 }
511 }
512}
513
514pub(crate) trait LookupIfInterfaceExists {
516 fn exists(&self, interface: NonZeroU64) -> bool;
518}
519
520type InterfaceMap = BTreeMap<
521 u64,
522 fnet_interfaces_ext::PropertiesAndState<
523 crate::interfaces::InterfaceState,
524 fnet_interfaces_ext::AllInterest,
525 >,
526>;
527
528impl LookupIfInterfaceExists for InterfaceMap {
529 fn exists(&self, interface: NonZeroU64) -> bool {
530 self.contains_key(&interface.get())
531 }
532}
533
534#[derive(Derivative)]
536#[derivative(Debug(bound = ""))]
537pub(crate) struct Request<S: Sender<<NetlinkRoute as ProtocolFamily>::Response>> {
538 pub args: NeighborRequestArgs,
540 pub sequence_number: u32,
545 pub client: InternalClient<NetlinkRoute, S>,
547 pub completer: oneshot::Sender<Result<(), RequestError>>,
549}
550
551#[derive(Clone, Debug, PartialEq, Eq)]
553pub(crate) enum PendingNeighborRequestArgs {
554 New(NewNeighborArgs),
556 Del(DelNeighborArgs),
558}
559
560#[derive(Derivative)]
561#[derivative(Debug(bound = ""))]
562pub(crate) struct PendingNeighborRequest<S: Sender<<NetlinkRoute as ProtocolFamily>::Response>> {
563 request_args: PendingNeighborRequestArgs,
564 client: InternalClient<NetlinkRoute, S>,
565 completer: oneshot::Sender<Result<(), RequestError>>,
566}
567
568#[derive(Debug, Error, PartialEq)]
570pub(crate) enum HandleWatchEventError {
571 #[error("Netstack reported removal of an unknown neighbor: {0:?}")]
573 UnknownNeighborRemoved(fnet_neighbor_ext::Entry),
574 #[error("Netstack reported change of an unknown neighbor: {0:?}")]
576 UnknownNeighborChanged(fnet_neighbor_ext::Entry),
577 #[error(
580 "Netstack reported addition of a neighbor that already exists: \
581 existing={existing:?}, new={new:?}"
582 )]
583 ConflictingNeighborAdded { existing: fnet_neighbor_ext::Entry, new: fnet_neighbor_ext::Entry },
584 #[error("Netstack reported unexpected event: {0:?}")]
587 UnexpectedEventReceived(fnet_neighbor_ext::Event),
588}
589
590#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
591struct NeighborKey {
592 interface: NonZeroU64,
593 neighbor: fnet::IpAddress,
594}
595
596impl From<&fnet_neighbor_ext::Entry> for NeighborKey {
597 fn from(
598 fnet_neighbor_ext::Entry { interface, neighbor, .. }: &fnet_neighbor_ext::Entry,
599 ) -> NeighborKey {
600 NeighborKey { interface: *interface, neighbor: *neighbor }
601 }
602}
603
604pub(crate) struct NeighborsWorker {
608 neighbor_table: HashMap<NeighborKey, fnet_neighbor_ext::Entry>,
609 neighbors_controller: fnet_neighbor::ControllerProxy,
610}
611
612impl NeighborsWorker {
613 pub(crate) async fn create(
618 neighbors_view: &fnet_neighbor::ViewProxy,
619 neighbors_controller: fnet_neighbor::ControllerProxy,
620 ) -> (
621 Self,
622 impl futures::Stream<
623 Item = Result<fnet_neighbor_ext::Event, fnet_neighbor_ext::EntryIteratorError>,
624 > + Unpin
625 + 'static,
626 ) {
627 let mut neighbor_event_stream = Box::pin(
628 fnet_neighbor_ext::event_stream_from_view(neighbors_view)
629 .expect("connecting to fuchsia.net.neighbors.View FIDL should succeed"),
630 );
631 let existing_neighbors: HashSet<fnet_neighbor_ext::Entry> =
632 fnet_neighbor_ext::collect_neighbors_until_idle(neighbor_event_stream.by_ref())
633 .await
634 .expect("determining existing neighbors should succeed");
635 let existing_count = existing_neighbors.len();
636 let neighbor_table = existing_neighbors
637 .into_iter()
638 .map(|e| (NeighborKey::from(&e), e))
639 .collect::<HashMap<_, _>>();
640 assert_eq!(
641 neighbor_table.len(),
642 existing_count,
643 "conflicting existing entry in neighbor table"
644 );
645 (Self { neighbor_table, neighbors_controller }, neighbor_event_stream)
646 }
647
648 pub(crate) fn handle_neighbor_watcher_event<
649 S: Sender<<NetlinkRoute as ProtocolFamily>::Response>,
650 >(
651 &mut self,
652 event: fnet_neighbor_ext::Event,
653 clients: &ClientTable<NetlinkRoute, S>,
654 ) -> Result<(), HandleWatchEventError> {
655 let message_for_group = match event {
656 fnet_neighbor_ext::Event::Removed(entry) => {
657 match self.neighbor_table.remove(&(&entry).into()) {
658 Some(_) => Ok(NetlinkNeighborMessage::optionally_from(entry)
659 .map(NetlinkNeighborMessage::into_rtnl_del_neighbor)),
660 None => Err(HandleWatchEventError::UnknownNeighborRemoved(entry)),
661 }
662 }
663 fnet_neighbor_ext::Event::Added(entry) => {
664 match self.neighbor_table.insert((&entry).into(), entry.clone()) {
665 Some(existing) => Err(HandleWatchEventError::ConflictingNeighborAdded {
666 existing,
667 new: entry,
668 }),
669 None => Ok(NetlinkNeighborMessage::optionally_from(entry)
670 .map(|n| n.into_rtnl_new_neighbor(UNSPECIFIED_SEQUENCE_NUMBER, false))),
671 }
672 }
673 fnet_neighbor_ext::Event::Changed(entry) => {
674 match self.neighbor_table.insert((&entry).into(), entry.clone()) {
675 Some(_) => Ok(NetlinkNeighborMessage::optionally_from(entry)
676 .map(|n| n.into_rtnl_new_neighbor(UNSPECIFIED_SEQUENCE_NUMBER, false))),
677 None => Err(HandleWatchEventError::UnknownNeighborChanged(entry)),
678 }
679 }
680 e @ fnet_neighbor_ext::Event::Existing(_) | e @ fnet_neighbor_ext::Event::Idle => {
681 Err(HandleWatchEventError::UnexpectedEventReceived(e))
682 }
683 }?;
684 if let Some(message) = message_for_group {
685 clients.send_message_to_group(message, ModernGroup(rtnetlink_groups_RTNLGRP_NEIGH));
686 }
687 Ok(())
688 }
689
690 pub(crate) async fn handle_request<S: Sender<<NetlinkRoute as ProtocolFamily>::Response>>(
691 &mut self,
692 Request { args, mut client, sequence_number, completer }: Request<S>,
693 interface_lookup: &impl LookupIfInterfaceExists,
694 ) -> Option<PendingNeighborRequest<S>> {
695 enum HandleResult {
696 Done(Result<(), RequestError>),
697 Pending(PendingNeighborRequestArgs),
698 }
699 let result = match args {
700 NeighborRequestArgs::Get(args) => match args {
701 GetNeighborArgs::Dump { ip_version, interface } => {
702 self.neighbor_table
703 .values()
704 .filter(|n| {
705 ip_version.map_or(true, |ip_version| match n.neighbor {
706 fnet::IpAddress::Ipv4(_) => ip_version == IpVersion::V4,
707 fnet::IpAddress::Ipv6(_) => ip_version == IpVersion::V6,
708 })
709 })
710 .filter(|n| interface.map_or(true, |i| n.interface == i))
711 .filter_map(|e| NetlinkNeighborMessage::optionally_from(e.clone()))
712 .for_each(|m| {
713 client.send_unicast(m.into_rtnl_new_neighbor(sequence_number, true));
714 });
715 HandleResult::Done(Ok(()))
716 }
717 GetNeighborArgs::Get { ip, interface } => {
718 let neighbor = self
719 .neighbor_table
720 .get(&NeighborKey { interface, neighbor: ip })
721 .map(|e| NetlinkNeighborMessage::optionally_from(e.clone()))
722 .flatten();
723 match neighbor {
724 Some(msg) => {
725 client.send_unicast(msg.into_rtnl_new_neighbor(sequence_number, false));
726 HandleResult::Done(Ok(()))
727 }
728 None => {
729 let err = if interface_lookup.exists(interface) {
730 RequestError::NeighborNotFound
731 } else {
732 RequestError::InterfaceNotFound
733 };
734 HandleResult::Done(Err(err))
735 }
736 }
737 }
738 },
739 NeighborRequestArgs::New(args) => match args {
740 args @ NewNeighborArgs::CreateStatic { ip, interface, mac } => {
741 let response = self
742 .neighbors_controller
743 .add_entry(interface.get(), &ip, &mac)
744 .await
745 .expect("sent neighbor controller request");
746 match response {
747 Ok(_) => HandleResult::Pending(PendingNeighborRequestArgs::New(args)),
748 Err(e) => HandleResult::Done(Err(e.into())),
749 }
750 }
751 args @ NewNeighborArgs::ProbeExisting { ip, interface } => {
752 let response = self
753 .neighbors_controller
754 .probe_entry(interface.get(), &ip)
755 .await
756 .expect("sent neighbor controller request");
757 match response {
758 Ok(_) => HandleResult::Pending(PendingNeighborRequestArgs::New(args)),
759 Err(e) => HandleResult::Done(Err(e.into())),
760 }
761 }
762 },
763 NeighborRequestArgs::Del(args @ DelNeighborArgs { interface, ip }) => {
764 let response = self
765 .neighbors_controller
766 .remove_entry(interface.get(), &ip)
767 .await
768 .expect("sent neighbor controller request");
769 match response {
770 Ok(_) => HandleResult::Pending(PendingNeighborRequestArgs::Del(args)),
771 Err(e) => HandleResult::Done(Err(e.into())),
772 }
773 }
774 };
775
776 match result {
777 HandleResult::Done(result) => {
778 log_debug!("handled request {args:?} from {client} with result = {result:?}");
779 respond_to_completer(client, completer, result, args);
780 None
781 }
782 HandleResult::Pending(request_args) => {
783 log_debug!("pending request {args:?} from {client}");
784 Some(PendingNeighborRequest { request_args, client, completer })
785 }
786 }
787 }
788
789 pub(crate) fn handle_pending_request<S: Sender<<NetlinkRoute as ProtocolFamily>::Response>>(
796 &self,
797 pending_neighbor_request: PendingNeighborRequest<S>,
798 ) -> Option<PendingNeighborRequest<S>> {
799 let PendingNeighborRequest { request_args, client: _, completer: _ } =
800 &pending_neighbor_request;
801
802 let done = match request_args {
803 PendingNeighborRequestArgs::New(NewNeighborArgs::ProbeExisting { ip, interface }) => {
804 self.neighbor_table
832 .get(&NeighborKey { interface: *interface, neighbor: *ip })
833 .map_or(false, |entry| entry.state == fnet_neighbor::EntryState::Probe)
834 }
835 PendingNeighborRequestArgs::New(NewNeighborArgs::CreateStatic {
836 ip,
837 interface,
838 mac,
839 }) => {
840 self.neighbor_table
845 .get(&NeighborKey { interface: *interface, neighbor: *ip })
846 .map_or(false, |entry| {
847 entry.mac.is_some_and(|m| m == *mac)
848 && entry.state == fnet_neighbor::EntryState::Static
849 })
850 }
851 PendingNeighborRequestArgs::Del(DelNeighborArgs { ip, interface }) => !self
852 .neighbor_table
853 .contains_key(&NeighborKey { interface: *interface, neighbor: *ip }),
854 };
855
856 if done {
857 log_debug!("completed pending request; req = {pending_neighbor_request:?}");
858 let PendingNeighborRequest { request_args, client, completer } =
859 pending_neighbor_request;
860
861 respond_to_completer(client, completer, Ok(()), request_args);
862 None
863 } else {
864 log_debug!("pending request not done yet; req = {pending_neighbor_request:?}");
866 Some(pending_neighbor_request)
867 }
868 }
869}
870
871#[cfg(test)]
872mod tests {
873 use crate::client::ClientTable;
874 use crate::client::testutil::{CLIENT_ID_1, CLIENT_ID_2, new_fake_client};
875 use crate::interfaces::testutil::FakeInterfacesHandler;
876 use crate::messaging::testutil::{FakeSender, SentMessage};
877 use crate::route_eventloop::{
878 EventLoopComponent, EventLoopInputs, EventLoopSpec, EventLoopState, IncludedWorkers,
879 Optional, Required, UnifiedRequest,
880 };
881
882 use super::*;
883
884 use assert_matches::assert_matches;
885 use fidl_fuchsia_net as fnet;
886 use fidl_fuchsia_net_interfaces as fnet_interfaces;
887 use fidl_fuchsia_net_neighbor::ViewRequest;
888 use fidl_fuchsia_net_neighbor_ext::testutil::EventSpec;
889 use fidl_fuchsia_net_root as fnet_root;
890 use futures::channel::mpsc;
891 use futures::{FutureExt as _, SinkExt as _, TryStreamExt as _, pin_mut};
892 use maplit::hashset;
893 use net_declare::{fidl_ip, std_ip_v4, std_ip_v6};
894 use netlink_packet_core::NetlinkPayload;
895 use netlink_packet_route::neighbour::{NeighbourAddress, NeighbourFlags};
896 use std::collections::HashSet;
897 use test_case::test_case;
898
899 fn valid_neighbor_entry() -> fnet_neighbor_ext::Entry {
900 fnet_neighbor_ext::Entry {
901 interface: NonZeroU64::new(1).unwrap(),
902 neighbor: fidl_ip!("192.168.0.1"),
903 state: fnet_neighbor::EntryState::Reachable,
904 mac: Some(fnet::MacAddress { octets: [0, 1, 2, 3, 4, 5] }),
905 updated_at: 123456,
906 }
907 }
908
909 #[test]
910 fn netlink_neighbor_message_from_entry_invalid_iface_id() {
911 let entry = fnet_neighbor_ext::Entry {
912 interface: NonZeroU64::new(u64::MAX).unwrap(),
913 ..valid_neighbor_entry()
914 };
915
916 assert_eq!(
917 NetlinkNeighborMessage::try_from(entry),
918 Err(NetlinkNeighborMessageConversionError::InvalidInterfaceId(u64::MAX))
919 );
920 }
921
922 #[test]
923 fn netlink_neighbor_message_from_entry_valid_iface_id() {
924 assert_matches!(
925 NetlinkNeighborMessage::try_from(fnet_neighbor_ext::Entry {
926 interface: NonZeroU64::new(1).unwrap(),
927 ..valid_neighbor_entry()
928 }),
929 Ok(NetlinkNeighborMessage(NeighbourMessage {
930 header: NeighbourHeader { ifindex: 1, .. },
931 ..
932 }))
933 );
934 }
935
936 #[test_case(fnet_neighbor::EntryState::Delay, NeighbourState::Delay; "delay")]
937 #[test_case(fnet_neighbor::EntryState::Incomplete, NeighbourState::Incomplete; "incomplete")]
938 #[test_case(fnet_neighbor::EntryState::Probe, NeighbourState::Probe; "probe")]
939 #[test_case(fnet_neighbor::EntryState::Reachable, NeighbourState::Reachable; "reachable")]
940 #[test_case(fnet_neighbor::EntryState::Stale, NeighbourState::Stale; "stale")]
941 #[test_case(fnet_neighbor::EntryState::Static, NeighbourState::Permanent; "permanent")]
942 #[test_case(fnet_neighbor::EntryState::Unreachable, NeighbourState::Failed; "failed")]
943 fn netlink_neighbor_message_from_entry_state_converted(
944 fidl_state: fnet_neighbor::EntryState,
945 expected: NeighbourState,
946 ) {
947 assert_matches!(
948 NetlinkNeighborMessage::try_from(fnet_neighbor_ext::Entry {
949 state: fidl_state,
950 ..valid_neighbor_entry()
951 }),
952 Ok(NetlinkNeighborMessage(NeighbourMessage {
953 header: NeighbourHeader { state, .. },
954 ..
955 })) if state == expected
956 );
957 }
958
959 #[test]
960 fn netlink_neighbor_message_from_entry_ipv4() {
961 let fidl_entry = fnet_neighbor_ext::Entry {
962 neighbor: fidl_ip!("192.168.0.1"),
963 ..valid_neighbor_entry()
964 };
965 let NetlinkNeighborMessage(message) =
966 fidl_entry.try_into().expect("should be able to convert valid neighbor entry");
967
968 assert_eq!(message.header.family, AddressFamily::Inet);
969 let expected_address: NeighbourAddress = std_ip_v4!("192.168.0.1").into();
970 assert_matches!(
971 &message.attributes[..],
972 [
973 NeighbourAttribute::Destination(address),
974 NeighbourAttribute::LinkLocalAddress(_)
975 ] if *address == expected_address
976 );
977 }
978
979 #[test]
980 fn netlink_neighbor_message_from_entry_ipv6() {
981 let fidl_entry =
982 fnet_neighbor_ext::Entry { neighbor: fidl_ip!("fe80::1"), ..valid_neighbor_entry() };
983 let NetlinkNeighborMessage(message) =
984 fidl_entry.try_into().expect("should be able to convert valid neighbor entry");
985
986 assert_eq!(message.header.family, AddressFamily::Inet6);
987 let expected_address: NeighbourAddress = std_ip_v6!("fe80::1").into();
988 assert_matches!(
989 &message.attributes[..],
990 [
991 NeighbourAttribute::Destination(address),
992 NeighbourAttribute::LinkLocalAddress(_)
993 ] if *address == expected_address
994 );
995 }
996
997 #[test]
998 fn netlink_neighbor_message_from_entry_address_link_local_present() {
999 let fidl_entry = fnet_neighbor_ext::Entry {
1000 mac: Some(fnet::MacAddress { octets: [0, 1, 2, 3, 4, 5] }),
1001 ..valid_neighbor_entry()
1002 };
1003 let NetlinkNeighborMessage(message) =
1004 fidl_entry.try_into().expect("should be able to convert valid neighbor entry");
1005
1006 assert_matches!(
1007 &message.attributes[..],
1008 [
1009 NeighbourAttribute::Destination(_),
1010 NeighbourAttribute::LinkLocalAddress(addr)
1011 ] if addr == &[0, 1, 2, 3, 4, 5]
1012 );
1013 }
1014
1015 #[test]
1016 fn netlink_neighbor_message_from_entry_address_link_local_absent() {
1017 let fidl_entry = fnet_neighbor_ext::Entry { mac: None, ..valid_neighbor_entry() };
1018 let NetlinkNeighborMessage(message) =
1019 fidl_entry.try_into().expect("should be able to convert valid neighbor entry");
1020
1021 assert_matches!(&message.attributes[..], [NeighbourAttribute::Destination(_)]);
1022 }
1023
1024 #[test]
1025 fn netlink_neighbor_message_optionally_from_failure() {
1026 assert_eq!(
1027 NetlinkNeighborMessage::optionally_from(fnet_neighbor_ext::Entry {
1028 interface: NonZeroU64::new(u64::MAX).unwrap(),
1029 ..valid_neighbor_entry()
1030 }),
1031 None
1032 );
1033 }
1034
1035 #[test]
1036 fn netlink_neighbor_message_optionally_from_success() {
1037 let fidl_entry = fnet_neighbor_ext::Entry {
1038 interface: NonZeroU64::new(1).unwrap(),
1039 neighbor: fidl_ip!("192.168.0.1"),
1040 state: fnet_neighbor::EntryState::Reachable,
1041 mac: None,
1042 updated_at: 123456,
1043 };
1044
1045 let mut expected_message = NeighbourMessage::default();
1046 expected_message.header = NeighbourHeader {
1047 ifindex: 1,
1048 family: AddressFamily::Inet,
1049 state: NeighbourState::Reachable,
1050 flags: NeighbourFlags::empty(),
1051 kind: RouteType::Unicast,
1052 };
1053 expected_message.attributes =
1054 vec![NeighbourAttribute::Destination(std_ip_v4!("192.168.0.1").into())];
1055
1056 assert_eq!(
1057 NetlinkNeighborMessage::optionally_from(fidl_entry),
1058 Some(NetlinkNeighborMessage(expected_message))
1059 );
1060 }
1061
1062 #[test]
1063 fn netlink_neighbor_message_into_rtnl_new_neighbor() {
1064 let message: NetlinkNeighborMessage = valid_neighbor_entry()
1065 .try_into()
1066 .expect("should be able to convert valid neighbor entry");
1067 let NetlinkNeighborMessage(payload) = &message;
1068
1069 let expected_payload =
1070 NetlinkPayload::InnerMessage(RouteNetlinkMessage::NewNeighbour(payload.clone()));
1071
1072 let result = message.clone().into_rtnl_new_neighbor(1, true);
1073 assert_eq!(result.payload, expected_payload);
1074 assert_eq!(result.header.sequence_number, 1);
1075 assert_eq!(result.header.flags & NLM_F_MULTIPART, NLM_F_MULTIPART);
1076
1077 let result = message.into_rtnl_new_neighbor(1, false);
1078 assert_eq!(result.payload, expected_payload);
1079 assert_ne!(result.header.flags & NLM_F_MULTIPART, NLM_F_MULTIPART);
1080 }
1081
1082 #[test]
1083 fn neighbor_keyed_by_interface_and_ip() {
1084 let entry = fnet_neighbor_ext::Entry {
1085 interface: NonZeroU64::new(1).unwrap(),
1086 neighbor: fidl_ip!("192.168.0.1"),
1087 mac: None,
1088 state: fnet_neighbor::EntryState::Reachable,
1089 updated_at: 123456,
1090 };
1091
1092 let same_iface_and_ip = fnet_neighbor_ext::Entry {
1093 mac: Some(fnet::MacAddress { octets: [0, 1, 2, 3, 4, 5] }),
1094 state: fnet_neighbor::EntryState::Stale,
1095 updated_at: 654321,
1096 ..entry
1097 };
1098 assert_eq!(NeighborKey::from(&entry), NeighborKey::from(&same_iface_and_ip));
1099
1100 let different_iface =
1101 fnet_neighbor_ext::Entry { interface: NonZeroU64::new(2).unwrap(), ..entry };
1102 assert_ne!(NeighborKey::from(&entry), NeighborKey::from(&different_iface));
1103
1104 let different_ip = fnet_neighbor_ext::Entry { neighbor: fidl_ip!("192.168.0.2"), ..entry };
1105 assert_ne!(NeighborKey::from(&entry), NeighborKey::from(&different_ip));
1106
1107 let different_iface_and_ip = fnet_neighbor_ext::Entry {
1108 interface: NonZeroU64::new(2).unwrap(),
1109 neighbor: fidl_ip!("192.168.0.2"),
1110 ..entry
1111 };
1112 assert_ne!(NeighborKey::from(&entry), NeighborKey::from(&different_iface_and_ip));
1113 }
1114
1115 #[fuchsia::test]
1116 #[should_panic(expected = "determining existing neighbors should succeed")]
1117 async fn neighbors_worker_create_panics_on_view_protocol_error() {
1118 let (controller, _controller_server_end) =
1119 fidl::endpoints::create_proxy::<fnet_neighbor::ControllerMarker>();
1120 let (view, view_server_end) = fidl::endpoints::create_proxy::<fnet_neighbor::ViewMarker>();
1121 drop(view_server_end);
1123
1124 let (_worker, _remaining) = NeighborsWorker::create(&view, controller).await;
1125 }
1126
1127 #[fuchsia::test]
1128 #[should_panic(expected = "determining existing neighbors should succeed")]
1129 async fn neighbors_worker_create_panics_on_event_stream_error() {
1130 let (controller, _controller_server_end) =
1131 fidl::endpoints::create_proxy::<fnet_neighbor::ControllerMarker>();
1132 let (view, view_server_end) = fidl::endpoints::create_proxy::<fnet_neighbor::ViewMarker>();
1133 let mut view_request_stream = view_server_end.into_stream();
1134
1135 let entry_iter_fut = view_request_stream
1136 .next()
1137 .then(|req| {
1138 match req
1139 .expect("View request_stream unexpectedly ended")
1140 .expect("failed to receive `OpenEntryIterator` request")
1141 {
1142 ViewRequest::OpenEntryIterator { it, .. } => {
1143 drop(it);
1145 futures::future::ready(())
1146 }
1147 }
1148 })
1149 .fuse();
1150
1151 let worker_fut = NeighborsWorker::create(&view, controller);
1152
1153 let ((), (_worker, _remaining)) = futures::join!(entry_iter_fut, worker_fut);
1154 }
1155
1156 #[fuchsia::test]
1157 #[should_panic(expected = "conflicting existing entry")]
1158 async fn neighbors_worker_create_panics_on_conflicting_entry() {
1159 let events: Vec<_> = [
1160 fnet_neighbor_ext::Entry {
1163 state: fnet_neighbor::EntryState::Reachable,
1164 ..valid_neighbor_entry()
1165 },
1166 fnet_neighbor_ext::Entry {
1167 state: fnet_neighbor::EntryState::Stale,
1168 ..valid_neighbor_entry()
1169 },
1170 ]
1171 .into_iter()
1172 .map(Into::into)
1173 .map(fnet_neighbor::EntryIteratorItem::Existing)
1174 .chain(std::iter::once(fnet_neighbor::EntryIteratorItem::Idle(fnet_neighbor::IdleEvent)))
1175 .collect();
1176 let batches = vec![events];
1177 let (view, server_fut) =
1178 fnet_neighbor_ext::testutil::create_fake_view(futures::stream::iter(batches));
1179
1180 let (controller, _controller_server_end) =
1181 fidl::endpoints::create_proxy::<fnet_neighbor::ControllerMarker>();
1182 let worker_fut = NeighborsWorker::create(&view, controller);
1183
1184 let ((), (_worker, _remaining)) = futures::join!(server_fut, worker_fut);
1185 }
1186
1187 #[fuchsia::test]
1188 async fn neighbors_worker_create_success() {
1189 use fnet_neighbor_ext::testutil::EventSpec::*;
1190 let events = fnet_neighbor_ext::testutil::generate_events_from_spec(&[
1191 Existing(1),
1192 Existing(2),
1193 Existing(3),
1194 Idle,
1195 Added(4),
1196 ]);
1197 let (view, server_fut) =
1198 fnet_neighbor_ext::testutil::create_fake_view(futures::stream::iter(vec![
1199 events.clone(),
1200 ]));
1201
1202 let (controller, _controller_server_end) =
1203 fidl::endpoints::create_proxy::<fnet_neighbor::ControllerMarker>();
1204 let worker_fut = NeighborsWorker::create(&view, controller);
1205
1206 let ((), (worker, event_stream)) = futures::join!(server_fut, worker_fut);
1207
1208 let remaining_events: Vec<_> = event_stream.collect().await;
1209 assert_matches!(
1210 &remaining_events[..],
1211 [
1212 Ok(fnet_neighbor_ext::Event::Added(_)),
1213 Err(fnet_neighbor_ext::EntryIteratorError::Fidl(
1214 fidl::Error::ClientChannelClosed { .. }
1215 ))
1216 ]
1217 );
1218
1219 for event in events {
1220 match event {
1221 fnet_neighbor::EntryIteratorItem::Existing(fidl_entry) => {
1222 let entry: fnet_neighbor_ext::Entry = fidl_entry.try_into().unwrap();
1223 assert_eq!(worker.neighbor_table.get(&(&entry).into()), Some(&entry));
1224 }
1225 _ => {}
1226 }
1227 }
1228 }
1229
1230 #[test_case(
1231 EventSpec::Added(2),
1232 |e| matches!(e, HandleWatchEventError::ConflictingNeighborAdded { .. });
1233 "conflicting added"
1234 )]
1235 #[test_case(
1236 EventSpec::Removed(4),
1237 |e| matches!(e, HandleWatchEventError::UnknownNeighborRemoved(_));
1238 "unknown removed"
1239 )]
1240 #[test_case(
1241 EventSpec::Changed(4),
1242 |e| matches!(e, HandleWatchEventError::UnknownNeighborChanged(_));
1243 "unknown changed"
1244 )]
1245 #[test_case(
1246 EventSpec::Existing(4),
1247 |e| matches!(e, HandleWatchEventError::UnexpectedEventReceived(_));
1248 "existing after initial collection"
1249 )]
1250 #[test_case(
1251 EventSpec::Idle,
1252 |e| matches!(e, HandleWatchEventError::UnexpectedEventReceived(_));
1253 "idle after initial collection"
1254 )]
1255 #[fuchsia::test]
1256 async fn neighbors_worker_handle_watch_event_failure(
1257 spec: EventSpec,
1258 error_matcher: fn(&HandleWatchEventError) -> bool,
1259 ) {
1260 use fnet_neighbor_ext::testutil::EventSpec::*;
1261 let events = fnet_neighbor_ext::testutil::generate_events_from_spec(&[
1262 Existing(1),
1263 Existing(2),
1264 Existing(3),
1265 Idle,
1266 spec,
1267 ]);
1268 let (view, server_fut) =
1269 fnet_neighbor_ext::testutil::create_fake_view(futures::stream::iter(vec![
1270 events.clone(),
1271 ]));
1272
1273 let (controller, _controller_server_end) =
1274 fidl::endpoints::create_proxy::<fnet_neighbor::ControllerMarker>();
1275 let worker_fut = NeighborsWorker::create(&view, controller);
1276
1277 let ((), (mut worker, event_stream)) = futures::join!(server_fut, worker_fut);
1278
1279 let client_table = ClientTable::<NetlinkRoute, FakeSender<_>>::default();
1280
1281 let remaining_events: Vec<_> = event_stream.collect().await;
1282 assert_eq!(remaining_events.len(), 2);
1283 match &remaining_events[0] {
1284 Ok(event) => {
1285 assert_matches!(
1286 worker.handle_neighbor_watcher_event(event.clone(), &client_table),
1287 Err(error) if error_matcher(&error)
1288 );
1289 }
1290 _ => panic!("expected bad event in stream"),
1291 }
1292 match &remaining_events[1] {
1293 Err(fnet_neighbor_ext::EntryIteratorError::Fidl(
1294 fidl::Error::ClientChannelClosed { .. },
1295 )) => {}
1296 _ => panic!("expected PEER_CLOSED error at end of stream"),
1297 }
1298 }
1299
1300 #[fuchsia::test]
1301 async fn neighbors_worker_handle_added_event() {
1302 use fnet_neighbor_ext::testutil::EventSpec::*;
1303 let events = fnet_neighbor_ext::testutil::generate_events_from_spec(&[
1304 Existing(1),
1305 Existing(2),
1306 Existing(3),
1307 Idle,
1308 Added(4),
1309 ]);
1310 let (view, server_fut) =
1311 fnet_neighbor_ext::testutil::create_fake_view(futures::stream::iter(vec![
1312 events.clone(),
1313 ]));
1314
1315 let (controller, _controller_server_end) =
1316 fidl::endpoints::create_proxy::<fnet_neighbor::ControllerMarker>();
1317 let worker_fut = NeighborsWorker::create(&view, controller);
1318
1319 let ((), (mut worker, event_stream)) = futures::join!(server_fut, worker_fut);
1320
1321 let client_table = ClientTable::<NetlinkRoute, FakeSender<_>>::default();
1322
1323 let remaining_events: Vec<_> = event_stream.collect().await;
1324 assert_eq!(remaining_events.len(), 2);
1325 match &remaining_events[0] {
1326 Ok(e @ fnet_neighbor_ext::Event::Added(entry)) => {
1327 let key = NeighborKey::from(entry);
1328 assert_eq!(worker.neighbor_table.get(&key), None);
1329 assert_matches!(
1330 worker.handle_neighbor_watcher_event(e.clone(), &client_table),
1331 Ok(_)
1332 );
1333 assert_eq!(worker.neighbor_table.get(&key), Some(entry));
1334 }
1335 _ => panic!("expected Added event in stream"),
1336 }
1337 match &remaining_events[1] {
1338 Err(fnet_neighbor_ext::EntryIteratorError::Fidl(
1339 fidl::Error::ClientChannelClosed { .. },
1340 )) => {}
1341 _ => panic!("expected PEER_CLOSED error at end of stream"),
1342 }
1343 }
1344
1345 #[fuchsia::test]
1346 async fn neighbors_worker_handle_removed_event() {
1347 use fnet_neighbor_ext::testutil::EventSpec::*;
1348 let events = fnet_neighbor_ext::testutil::generate_events_from_spec(&[
1349 Existing(1),
1350 Existing(2),
1351 Existing(3),
1352 Idle,
1353 Removed(2),
1354 ]);
1355 let (view, server_fut) =
1356 fnet_neighbor_ext::testutil::create_fake_view(futures::stream::iter(vec![
1357 events.clone(),
1358 ]));
1359
1360 let (controller, _controller_server_end) =
1361 fidl::endpoints::create_proxy::<fnet_neighbor::ControllerMarker>();
1362 let worker_fut = NeighborsWorker::create(&view, controller);
1363
1364 let ((), (mut worker, event_stream)) = futures::join!(server_fut, worker_fut);
1365
1366 let client_table = ClientTable::<NetlinkRoute, FakeSender<_>>::default();
1367
1368 let remaining_events: Vec<_> = event_stream.collect().await;
1369 assert_eq!(remaining_events.len(), 2);
1370 match &remaining_events[0] {
1371 Ok(e @ fnet_neighbor_ext::Event::Removed(entry)) => {
1372 let key = NeighborKey::from(entry);
1373 assert_eq!(worker.neighbor_table.get(&key), Some(entry));
1374 assert_matches!(
1375 worker.handle_neighbor_watcher_event(e.clone(), &client_table),
1376 Ok(_)
1377 );
1378 assert_eq!(worker.neighbor_table.get(&key), None);
1379 }
1380 _ => panic!("expected Removed event in stream"),
1381 }
1382 match &remaining_events[1] {
1383 Err(fnet_neighbor_ext::EntryIteratorError::Fidl(
1384 fidl::Error::ClientChannelClosed { .. },
1385 )) => {}
1386 _ => panic!("expected PEER_CLOSED error at end of stream"),
1387 }
1388 }
1389
1390 #[fuchsia::test]
1391 async fn neighbors_worker_handle_changed_event() {
1392 use fnet_neighbor_ext::testutil::EventSpec::*;
1393 let mut events = fnet_neighbor_ext::testutil::generate_events_from_spec(&[
1394 Existing(1),
1395 Existing(2),
1396 Existing(3),
1397 Idle,
1398 Changed(2),
1399 ]);
1400 match &mut events[1] {
1401 fnet_neighbor::EntryIteratorItem::Existing(entry) => {
1402 entry.updated_at = Some(1234);
1403 }
1404 _ => panic!("expected Existing event in stream"),
1405 }
1406 match &mut events[4] {
1407 fnet_neighbor::EntryIteratorItem::Changed(entry) => {
1408 entry.updated_at = Some(5678);
1409 }
1410 _ => panic!("expected Changed event in stream"),
1411 }
1412
1413 let (view, server_fut) =
1414 fnet_neighbor_ext::testutil::create_fake_view(futures::stream::iter(vec![
1415 events.clone(),
1416 ]));
1417
1418 let (controller, _controller_server_end) =
1419 fidl::endpoints::create_proxy::<fnet_neighbor::ControllerMarker>();
1420 let worker_fut = NeighborsWorker::create(&view, controller);
1421
1422 let ((), (mut worker, event_stream)) = futures::join!(server_fut, worker_fut);
1423
1424 let client_table = ClientTable::<NetlinkRoute, FakeSender<_>>::default();
1425
1426 let remaining_events: Vec<_> = event_stream.collect().await;
1427 assert_eq!(remaining_events.len(), 2);
1428 match &remaining_events[0] {
1429 Ok(e @ fnet_neighbor_ext::Event::Changed(entry)) => {
1430 let key = NeighborKey::from(entry);
1431 assert_matches!(
1432 worker.neighbor_table.get(&key),
1433 Some(fnet_neighbor_ext::Entry { updated_at: 1234, .. })
1434 );
1435 assert_matches!(
1436 worker.handle_neighbor_watcher_event(e.clone(), &client_table),
1437 Ok(_)
1438 );
1439 assert_matches!(
1440 worker.neighbor_table.get(&key),
1441 Some(fnet_neighbor_ext::Entry { updated_at: 5678, .. })
1442 );
1443 }
1444 _ => panic!("expected Changed event in stream"),
1445 }
1446 match &remaining_events[1] {
1447 Err(fnet_neighbor_ext::EntryIteratorError::Fidl(
1448 fidl::Error::ClientChannelClosed { .. },
1449 )) => {}
1450 _ => panic!("expected PEER_CLOSED error at end of stream"),
1451 }
1452 }
1453
1454 impl LookupIfInterfaceExists for HashSet<u64> {
1455 fn exists(&self, idx: NonZeroU64) -> bool {
1456 self.contains(&idx.get())
1457 }
1458 }
1459
1460 #[test_case(HashSet::new(), RequestError::InterfaceNotFound; "interface does not exist")]
1461 #[test_case(
1462 hashset!{1}, RequestError::NeighborNotFound;
1463 "interface exists"
1464 )]
1465 #[fuchsia::test]
1466 async fn neighbors_worker_handle_get_neighbor_not_found(
1467 interface_lookup: HashSet<u64>,
1468 expected_error: RequestError,
1469 ) {
1470 let (mut sender_sink, client, _async_work_drain_task) =
1471 new_fake_client(CLIENT_ID_1, vec![]);
1472 let (completer, completer_rcv) = oneshot::channel();
1473 let request = Request {
1474 args: NeighborRequestArgs::Get(GetNeighborArgs::Get {
1475 ip: fidl_ip!("192.168.0.1"),
1476 interface: NonZeroU64::new(1).unwrap(),
1477 }),
1478 sequence_number: 1,
1479 client,
1480 completer,
1481 };
1482
1483 let events: Vec<_> = [
1484 fnet_neighbor_ext::Entry {
1485 interface: NonZeroU64::new(2).unwrap(),
1486 neighbor: fidl_ip!("192.168.0.1"),
1487 ..valid_neighbor_entry()
1488 },
1489 fnet_neighbor_ext::Entry {
1490 interface: NonZeroU64::new(1).unwrap(),
1491 neighbor: fidl_ip!("fe80::2"),
1492 ..valid_neighbor_entry()
1493 },
1494 ]
1495 .into_iter()
1496 .map(Into::into)
1497 .map(fnet_neighbor::EntryIteratorItem::Existing)
1498 .chain(std::iter::once(fnet_neighbor::EntryIteratorItem::Idle(fnet_neighbor::IdleEvent)))
1499 .collect();
1500
1501 let batches = vec![events];
1502 let (view, server_fut) =
1503 fnet_neighbor_ext::testutil::create_fake_view(futures::stream::iter(batches));
1504
1505 let (controller, _controller_server_end) =
1506 fidl::endpoints::create_proxy::<fnet_neighbor::ControllerMarker>();
1507 let worker_fut = NeighborsWorker::create(&view, controller);
1508 let ((), (mut worker, _event_stream)) = futures::join!(server_fut, worker_fut);
1509
1510 assert_matches!(
1511 worker.handle_request(request, &interface_lookup).await,
1512 None );
1514
1515 let result = completer_rcv.await.expect("completer channel should not be closed");
1516 assert_matches!(result, Err(e) if e == expected_error);
1517 assert_eq!(&sender_sink.take_messages()[..], &[]);
1518 }
1519
1520 #[test_case(
1521 GetNeighborArgs::Dump{ ip_version: None, interface: None },
1522 &[1, 2, 3, 4];
1523 "dump all"
1524 )]
1525 #[test_case(
1526 GetNeighborArgs::Dump{ ip_version: Some(IpVersion::V4), interface: None },
1527 &[1, 3];
1528 "dump ipv4 only"
1529 )]
1530 #[test_case(
1531 GetNeighborArgs::Dump{ ip_version: Some(IpVersion::V6), interface: None },
1532 &[2, 4];
1533 "dump ipv6 only"
1534 )]
1535 #[test_case(
1536 GetNeighborArgs::Dump{
1537 ip_version: Some(IpVersion::V6),
1538 interface: Some(NonZeroU64::new(4).unwrap())
1539 },
1540 &[4];
1541 "dump interface 4 ipv6"
1542 )]
1543 #[test_case(
1544 GetNeighborArgs::Dump{
1545 ip_version: Some(IpVersion::V4),
1546 interface: Some(NonZeroU64::new(4).unwrap())
1547 },
1548 &[];
1549 "dump interface 4 ipv4"
1550 )]
1551 #[test_case(
1552 GetNeighborArgs::Get{ ip: fidl_ip!("192.168.0.1"), interface: NonZeroU64::new(1).unwrap() },
1553 &[1];
1554 "get ipv4"
1555 )]
1556 #[test_case(
1557 GetNeighborArgs::Get{ ip: fidl_ip!("fe80::2"), interface: NonZeroU64::new(2).unwrap() },
1558 &[2];
1559 "get ipv6"
1560 )]
1561 #[fuchsia::test]
1562 async fn neighbors_worker_handle_get_request(
1563 get_args: GetNeighborArgs,
1564 expected_ifindexes: &[u32],
1565 ) {
1566 let (mut sender_sink, client, _async_work_drain_task) =
1567 new_fake_client(CLIENT_ID_1, vec![]);
1568 let (completer, completer_rcv) = oneshot::channel();
1569 let request = Request {
1570 args: NeighborRequestArgs::Get(get_args),
1571 sequence_number: 1,
1572 client,
1573 completer,
1574 };
1575
1576 let events: Vec<_> = [
1577 fnet_neighbor_ext::Entry {
1578 interface: NonZeroU64::new(1).unwrap(),
1579 neighbor: fidl_ip!("192.168.0.1"),
1580 ..valid_neighbor_entry()
1581 },
1582 fnet_neighbor_ext::Entry {
1583 interface: NonZeroU64::new(2).unwrap(),
1584 neighbor: fidl_ip!("fe80::2"),
1585 ..valid_neighbor_entry()
1586 },
1587 fnet_neighbor_ext::Entry {
1588 interface: NonZeroU64::new(3).unwrap(),
1589 neighbor: fidl_ip!("192.168.0.3"),
1590 ..valid_neighbor_entry()
1591 },
1592 fnet_neighbor_ext::Entry {
1593 interface: NonZeroU64::new(4).unwrap(),
1594 neighbor: fidl_ip!("fe80::4"),
1595 ..valid_neighbor_entry()
1596 },
1597 ]
1598 .into_iter()
1599 .map(Into::into)
1600 .map(fnet_neighbor::EntryIteratorItem::Existing)
1601 .chain(std::iter::once(fnet_neighbor::EntryIteratorItem::Idle(fnet_neighbor::IdleEvent)))
1602 .collect();
1603
1604 let batches = vec![events];
1605 let (view, server_fut) =
1606 fnet_neighbor_ext::testutil::create_fake_view(futures::stream::iter(batches));
1607
1608 let (controller, _controller_server_end) =
1609 fidl::endpoints::create_proxy::<fnet_neighbor::ControllerMarker>();
1610 let worker_fut = NeighborsWorker::create(&view, controller);
1611 let ((), (mut worker, _event_stream)) = futures::join!(server_fut, worker_fut);
1612
1613 assert_matches!(
1614 worker.handle_request(request, &BTreeMap::new()).await,
1615 None );
1617
1618 completer_rcv
1619 .await
1620 .expect("completer channel should not be closed")
1621 .expect("request handling result should be OK");
1622
1623 let mut ifindexes_seen = Vec::new();
1624 for sent_message in sender_sink.take_messages() {
1625 match sent_message.message.payload {
1626 NetlinkPayload::InnerMessage(RouteNetlinkMessage::NewNeighbour(
1627 NeighbourMessage { header: NeighbourHeader { ifindex, .. }, .. },
1628 )) => {
1629 ifindexes_seen.push(ifindex);
1630 }
1631 _ => panic!("unexpected message sent"),
1632 }
1633 }
1634 ifindexes_seen.sort();
1635 assert_eq!(&ifindexes_seen[..], expected_ifindexes);
1636 }
1637
1638 #[fuchsia::test]
1639 async fn neighbors_worker_handle_del_request_controller_error() {
1640 let (_sender_sink, client, _async_work_drain_task) = new_fake_client(CLIENT_ID_1, vec![]);
1641 let (completer, completer_rcv) = oneshot::channel();
1642 let request = Request {
1643 args: NeighborRequestArgs::Del(DelNeighborArgs {
1644 ip: fidl_ip!("192.168.0.1"),
1645 interface: NonZeroU64::new(1).unwrap(),
1646 }),
1647 sequence_number: 1,
1648 client,
1649 completer,
1650 };
1651
1652 let events = {
1653 use fnet_neighbor_ext::testutil::EventSpec::*;
1654 fnet_neighbor_ext::testutil::generate_events_from_spec(&[Idle])
1655 };
1656 let (view, server_fut) =
1657 fnet_neighbor_ext::testutil::create_fake_view(futures::stream::iter(vec![events]));
1658 let (controller, mut controller_request_stream) =
1659 fidl::endpoints::create_proxy_and_stream::<fnet_neighbor::ControllerMarker>();
1660 let worker_fut = NeighborsWorker::create(&view, controller);
1661 let ((), (mut worker, _event_stream)) = futures::join!(server_fut, worker_fut);
1662
1663 let interfaces = BTreeMap::new();
1664 let handle_request_fut = worker.handle_request(request, &interfaces);
1665 let controller_fut = async {
1666 match controller_request_stream
1667 .next()
1668 .await
1669 .expect("controller stream should not be closed")
1670 .expect("failed to receive controller request")
1671 {
1672 fnet_neighbor::ControllerRequest::RemoveEntry {
1673 interface: _,
1674 neighbor: _,
1675 responder,
1676 } => {
1677 responder
1678 .send(Err(fnet_neighbor::ControllerError::InterfaceNotFound))
1679 .expect("failed to send error response");
1680 }
1681 _ => panic!("unexpected controller request"),
1682 }
1683 };
1684
1685 let (handle_result, ()) = futures::join!(handle_request_fut, controller_fut);
1686 assert_matches!(handle_result, None);
1687
1688 let result = completer_rcv.await.expect("completer channel should not be closed");
1689 assert_matches!(result, Err(RequestError::InterfaceNotFound));
1690 }
1691
1692 #[fuchsia::test]
1693 async fn neighbors_worker_handle_del_request_success() {
1694 let (_sender_sink, client, _async_work_drain_task) = new_fake_client(CLIENT_ID_1, vec![]);
1695 let (completer, _completer_rcv) = oneshot::channel();
1696 let args =
1697 DelNeighborArgs { ip: fidl_ip!("192.168.0.1"), interface: NonZeroU64::new(1).unwrap() };
1698 let request =
1699 Request { args: NeighborRequestArgs::Del(args), sequence_number: 1, client, completer };
1700
1701 let events = fnet_neighbor_ext::testutil::generate_events_from_spec(&[
1702 fnet_neighbor_ext::testutil::EventSpec::Idle,
1703 ]);
1704 let batches = vec![events];
1705 let (view, server_fut) =
1706 fnet_neighbor_ext::testutil::create_fake_view(futures::stream::iter(batches));
1707 let (controller, mut controller_request_stream) =
1708 fidl::endpoints::create_proxy_and_stream::<fnet_neighbor::ControllerMarker>();
1709 let worker_fut = NeighborsWorker::create(&view, controller);
1710 let ((), (mut worker, _event_stream)) = futures::join!(server_fut, worker_fut);
1711
1712 let interfaces = BTreeMap::new();
1713 let handle_request_fut = worker.handle_request(request, &interfaces);
1714 let controller_fut = async {
1715 match controller_request_stream
1716 .next()
1717 .await
1718 .expect("controller stream should not be closed")
1719 .expect("failed to receive controller request")
1720 {
1721 fnet_neighbor::ControllerRequest::RemoveEntry {
1722 interface: _,
1723 neighbor: _,
1724 responder,
1725 } => {
1726 responder.send(Ok(())).expect("failed to send success response");
1727 }
1728 _ => panic!("unexpected controller request"),
1729 }
1730 };
1731
1732 let (handle_result, ()) = futures::join!(handle_request_fut, controller_fut);
1733 let pending = handle_result.expect("expected pending request");
1734 assert_eq!(pending.request_args, PendingNeighborRequestArgs::Del(args));
1735 }
1736
1737 #[fuchsia::test]
1738 async fn neighbors_worker_handle_pending_del_request() {
1739 let (_sender_sink, client, _async_work_drain_task) = new_fake_client(CLIENT_ID_1, vec![]);
1740 let (completer, mut completer_rcv) = oneshot::channel();
1741 let args =
1742 DelNeighborArgs { ip: fidl_ip!("192.168.0.1"), interface: NonZeroU64::new(1).unwrap() };
1743 let pending = PendingNeighborRequest {
1744 request_args: PendingNeighborRequestArgs::Del(args),
1745 client,
1746 completer,
1747 };
1748
1749 let events = fnet_neighbor_ext::testutil::generate_events_from_spec(&[
1750 fnet_neighbor_ext::testutil::EventSpec::Idle,
1751 ]);
1752 let batches = vec![events];
1753 let (view, server_fut) =
1754 fnet_neighbor_ext::testutil::create_fake_view(futures::stream::iter(batches));
1755 let (controller, _controller_server_end) =
1756 fidl::endpoints::create_proxy::<fnet_neighbor::ControllerMarker>();
1757 let worker_fut = NeighborsWorker::create(&view, controller);
1758 let ((), (mut worker, _event_stream)) = futures::join!(server_fut, worker_fut);
1759
1760 let key = NeighborKey { interface: args.interface, neighbor: args.ip };
1761 let _ = worker.neighbor_table.insert(
1762 key,
1763 fnet_neighbor_ext::Entry {
1764 interface: args.interface,
1765 neighbor: args.ip,
1766 ..valid_neighbor_entry()
1767 },
1768 );
1769
1770 let pending = worker.handle_pending_request(pending).expect("expected pending");
1772 assert_matches!(completer_rcv.try_recv(), Ok(None)); let _ = worker.neighbor_table.remove(&key);
1776 assert_matches!(worker.handle_pending_request(pending), None);
1777
1778 let result = completer_rcv.try_recv().expect("completer channel should not be closed");
1779 assert_matches!(result, Some(Ok(())));
1780 }
1781
1782 #[fuchsia::test]
1783 async fn neighbors_worker_handle_create_static_request_controller_error() {
1784 let (_sender_sink, client, _async_work_drain_task) = new_fake_client(CLIENT_ID_1, vec![]);
1785 let (completer, completer_rcv) = oneshot::channel();
1786 let args = NewNeighborArgs::CreateStatic {
1787 ip: fidl_ip!("192.168.0.1"),
1788 interface: NonZeroU64::new(1).unwrap(),
1789 mac: fnet::MacAddress { octets: [0, 1, 2, 3, 4, 5] },
1790 };
1791 let request =
1792 Request { args: NeighborRequestArgs::New(args), sequence_number: 1, client, completer };
1793
1794 let events = fnet_neighbor_ext::testutil::generate_events_from_spec(&[
1795 fnet_neighbor_ext::testutil::EventSpec::Idle,
1796 ]);
1797 let batches = vec![events];
1798 let (view, server_fut) =
1799 fnet_neighbor_ext::testutil::create_fake_view(futures::stream::iter(batches));
1800 let (controller, mut controller_request_stream) =
1801 fidl::endpoints::create_proxy_and_stream::<fnet_neighbor::ControllerMarker>();
1802 let worker_fut = NeighborsWorker::create(&view, controller);
1803 let ((), (mut worker, _event_stream)) = futures::join!(server_fut, worker_fut);
1804
1805 let interfaces = BTreeMap::new();
1806 let handle_request_fut = worker.handle_request(request, &interfaces);
1807 let controller_fut = async {
1808 match controller_request_stream
1809 .next()
1810 .await
1811 .expect("controller stream should not be closed")
1812 .expect("failed to receive controller request")
1813 {
1814 fnet_neighbor::ControllerRequest::AddEntry {
1815 interface: _,
1816 neighbor: _,
1817 mac: _,
1818 responder,
1819 } => {
1820 responder
1821 .send(Err(fnet_neighbor::ControllerError::InterfaceNotFound))
1822 .expect("failed to send error response");
1823 }
1824 _ => panic!("unexpected controller request"),
1825 }
1826 };
1827
1828 let (handle_result, ()) = futures::join!(handle_request_fut, controller_fut);
1829 assert_matches!(handle_result, None);
1830
1831 let result = completer_rcv.await.expect("completer channel should not be closed");
1832 assert_matches!(result, Err(RequestError::InterfaceNotFound));
1833 }
1834
1835 #[fuchsia::test]
1836 async fn neighbors_worker_handle_create_static_request_success() {
1837 let (_sender_sink, client, _async_work_drain_task) = new_fake_client(CLIENT_ID_1, vec![]);
1838 let (completer, _completer_rcv) = oneshot::channel();
1839 let args = NewNeighborArgs::CreateStatic {
1840 ip: fidl_ip!("192.168.0.1"),
1841 interface: NonZeroU64::new(1).unwrap(),
1842 mac: fnet::MacAddress { octets: [0, 1, 2, 3, 4, 5] },
1843 };
1844 let request =
1845 Request { args: NeighborRequestArgs::New(args), sequence_number: 1, client, completer };
1846
1847 let events = fnet_neighbor_ext::testutil::generate_events_from_spec(&[
1848 fnet_neighbor_ext::testutil::EventSpec::Idle,
1849 ]);
1850 let (view, server_fut) =
1851 fnet_neighbor_ext::testutil::create_fake_view(futures::stream::iter(vec![events]));
1852 let (controller, mut controller_request_stream) =
1853 fidl::endpoints::create_proxy_and_stream::<fnet_neighbor::ControllerMarker>();
1854 let worker_fut = NeighborsWorker::create(&view, controller);
1855 let ((), (mut worker, _event_stream)) = futures::join!(server_fut, worker_fut);
1856
1857 let interfaces = BTreeMap::new();
1858 let handle_request_fut = worker.handle_request(request, &interfaces);
1859 let controller_fut = async {
1860 match controller_request_stream
1861 .next()
1862 .await
1863 .expect("controller stream should not be closed")
1864 .expect("failed to receive controller request")
1865 {
1866 fnet_neighbor::ControllerRequest::AddEntry {
1867 interface: _,
1868 neighbor: _,
1869 mac: _,
1870 responder,
1871 } => {
1872 responder.send(Ok(())).expect("failed to send success response");
1873 }
1874 _ => panic!("unexpected controller request"),
1875 }
1876 };
1877
1878 let (handle_result, ()) = futures::join!(handle_request_fut, controller_fut);
1879 let pending = handle_result.expect("expected pending request");
1880 assert_eq!(pending.request_args, PendingNeighborRequestArgs::New(args));
1881 }
1882
1883 #[fuchsia::test]
1884 async fn neighbors_worker_handle_probe_request_controller_error() {
1885 let (_sender_sink, client, _async_work_drain_task) = new_fake_client(CLIENT_ID_1, vec![]);
1886 let (completer, completer_rcv) = oneshot::channel();
1887 let args = NewNeighborArgs::ProbeExisting {
1888 ip: fidl_ip!("192.168.0.1"),
1889 interface: NonZeroU64::new(1).unwrap(),
1890 };
1891 let request =
1892 Request { args: NeighborRequestArgs::New(args), sequence_number: 1, client, completer };
1893
1894 let events = fnet_neighbor_ext::testutil::generate_events_from_spec(&[
1895 fnet_neighbor_ext::testutil::EventSpec::Idle,
1896 ]);
1897 let (view, server_fut) =
1898 fnet_neighbor_ext::testutil::create_fake_view(futures::stream::iter(vec![events]));
1899 let (controller, mut controller_request_stream) =
1900 fidl::endpoints::create_proxy_and_stream::<fnet_neighbor::ControllerMarker>();
1901 let worker_fut = NeighborsWorker::create(&view, controller);
1902 let ((), (mut worker, _event_stream)) = futures::join!(server_fut, worker_fut);
1903
1904 let interfaces = BTreeMap::new();
1905 let handle_request_fut = worker.handle_request(request, &interfaces);
1906 let controller_fut = async {
1907 match controller_request_stream
1908 .next()
1909 .await
1910 .expect("controller stream should not be closed")
1911 .expect("failed to receive controller request")
1912 {
1913 fnet_neighbor::ControllerRequest::ProbeEntry {
1914 interface: _,
1915 neighbor: _,
1916 responder,
1917 } => {
1918 responder
1919 .send(Err(fnet_neighbor::ControllerError::InterfaceNotFound))
1920 .expect("failed to send error response");
1921 }
1922 _ => panic!("unexpected controller request"),
1923 }
1924 };
1925
1926 let (handle_result, ()) = futures::join!(handle_request_fut, controller_fut);
1927 assert_matches!(handle_result, None);
1928
1929 let result = completer_rcv.await.expect("completer channel should not be closed");
1930 assert_matches!(result, Err(RequestError::InterfaceNotFound));
1931 }
1932
1933 #[fuchsia::test]
1934 async fn neighbors_worker_handle_probe_request_success() {
1935 let (_sender_sink, client, _async_work_drain_task) = new_fake_client(CLIENT_ID_1, vec![]);
1936 let (completer, _completer_rcv) = oneshot::channel();
1937 let args = NewNeighborArgs::ProbeExisting {
1938 ip: fidl_ip!("192.168.0.1"),
1939 interface: NonZeroU64::new(1).unwrap(),
1940 };
1941 let request =
1942 Request { args: NeighborRequestArgs::New(args), sequence_number: 1, client, completer };
1943
1944 let events = fnet_neighbor_ext::testutil::generate_events_from_spec(&[
1945 fnet_neighbor_ext::testutil::EventSpec::Idle,
1946 ]);
1947 let (view, server_fut) =
1948 fnet_neighbor_ext::testutil::create_fake_view(futures::stream::iter(vec![events]));
1949 let (controller, mut controller_request_stream) =
1950 fidl::endpoints::create_proxy_and_stream::<fnet_neighbor::ControllerMarker>();
1951 let worker_fut = NeighborsWorker::create(&view, controller);
1952 let ((), (mut worker, _event_stream)) = futures::join!(server_fut, worker_fut);
1953
1954 let interfaces = BTreeMap::new();
1955 let handle_request_fut = worker.handle_request(request, &interfaces);
1956 let controller_fut = async {
1957 match controller_request_stream
1958 .next()
1959 .await
1960 .expect("controller stream should not be closed")
1961 .expect("failed to receive controller request")
1962 {
1963 fnet_neighbor::ControllerRequest::ProbeEntry {
1964 interface: _,
1965 neighbor: _,
1966 responder,
1967 } => {
1968 responder.send(Ok(())).expect("failed to send success response");
1969 }
1970 _ => panic!("unexpected controller request"),
1971 }
1972 };
1973
1974 let (handle_result, ()) = futures::join!(handle_request_fut, controller_fut);
1975 let pending = handle_result.expect("expected pending request");
1976 assert_eq!(pending.request_args, PendingNeighborRequestArgs::New(args));
1977 }
1978
1979 #[fuchsia::test]
1980 async fn neighbors_worker_handle_pending_create_static_request() {
1981 let (_sender_sink, client, _async_work_drain_task) = new_fake_client(CLIENT_ID_1, vec![]);
1982 let (completer, mut completer_rcv) = oneshot::channel();
1983 let neighbor = valid_neighbor_entry();
1984 let args = NewNeighborArgs::CreateStatic {
1985 ip: neighbor.neighbor,
1986 interface: neighbor.interface,
1987 mac: neighbor.mac.unwrap(),
1988 };
1989 let pending = PendingNeighborRequest {
1990 request_args: PendingNeighborRequestArgs::New(args),
1991 client,
1992 completer,
1993 };
1994
1995 let events = fnet_neighbor_ext::testutil::generate_events_from_spec(&[
1996 fnet_neighbor_ext::testutil::EventSpec::Idle,
1997 ]);
1998 let (view, server_fut) =
1999 fnet_neighbor_ext::testutil::create_fake_view(futures::stream::iter(vec![events]));
2000 let (controller, _controller_server_end) =
2001 fidl::endpoints::create_proxy::<fnet_neighbor::ControllerMarker>();
2002 let worker_fut = NeighborsWorker::create(&view, controller);
2003 let ((), (mut worker, _event_stream)) = futures::join!(server_fut, worker_fut);
2004
2005 let key = NeighborKey { interface: neighbor.interface, neighbor: neighbor.neighbor };
2006
2007 let pending = worker.handle_pending_request(pending).expect("expected pending");
2009 assert_matches!(completer_rcv.try_recv(), Ok(None));
2010
2011 let _ = worker.neighbor_table.insert(
2013 key,
2014 fnet_neighbor_ext::Entry {
2015 mac: Some(fnet::MacAddress { octets: [0, 0, 0, 0, 0, 0] }),
2016 state: fnet_neighbor::EntryState::Static,
2017 ..neighbor
2018 },
2019 );
2020 let pending = worker.handle_pending_request(pending).expect("expected pending");
2021 assert_matches!(completer_rcv.try_recv(), Ok(None));
2022
2023 let _ = worker.neighbor_table.insert(
2025 key,
2026 fnet_neighbor_ext::Entry {
2027 mac: Some(fnet::MacAddress { octets: [0, 1, 2, 3, 4, 5] }),
2028 state: fnet_neighbor::EntryState::Reachable,
2029 ..neighbor
2030 },
2031 );
2032 let pending = worker.handle_pending_request(pending).expect("expected pending");
2033 assert_matches!(completer_rcv.try_recv(), Ok(None));
2034
2035 let _ = worker.neighbor_table.insert(
2037 key,
2038 fnet_neighbor_ext::Entry {
2039 mac: Some(fnet::MacAddress { octets: [0, 1, 2, 3, 4, 5] }),
2040 state: fnet_neighbor::EntryState::Static,
2041 ..neighbor
2042 },
2043 );
2044 assert_matches!(worker.handle_pending_request(pending), None);
2045
2046 let result = completer_rcv.try_recv().expect("completer channel should not be closed");
2047 assert_matches!(result, Some(Ok(())));
2048 }
2049
2050 #[fuchsia::test]
2051 async fn neighbors_worker_handle_pending_probe_request() {
2052 let (_sender_sink, client, _async_work_drain_task) = new_fake_client(CLIENT_ID_1, vec![]);
2053 let (completer, mut completer_rcv) = oneshot::channel();
2054 let neighbor = valid_neighbor_entry();
2055 let args =
2056 NewNeighborArgs::ProbeExisting { ip: neighbor.neighbor, interface: neighbor.interface };
2057 let pending = PendingNeighborRequest {
2058 request_args: PendingNeighborRequestArgs::New(args),
2059 client,
2060 completer,
2061 };
2062
2063 let events = fnet_neighbor_ext::testutil::generate_events_from_spec(&[
2064 fnet_neighbor_ext::testutil::EventSpec::Idle,
2065 ]);
2066 let (view, server_fut) =
2067 fnet_neighbor_ext::testutil::create_fake_view(futures::stream::iter(vec![events]));
2068 let (controller, _controller_server_end) =
2069 fidl::endpoints::create_proxy::<fnet_neighbor::ControllerMarker>();
2070 let worker_fut = NeighborsWorker::create(&view, controller);
2071 let ((), (mut worker, _event_stream)) = futures::join!(server_fut, worker_fut);
2072
2073 let key = NeighborKey { interface: neighbor.interface, neighbor: neighbor.neighbor };
2074
2075 let pending = worker.handle_pending_request(pending).expect("expected pending");
2077 assert_matches!(completer_rcv.try_recv(), Ok(None));
2078
2079 let _ = worker.neighbor_table.insert(
2081 key,
2082 fnet_neighbor_ext::Entry { state: fnet_neighbor::EntryState::Reachable, ..neighbor },
2083 );
2084 let pending = worker.handle_pending_request(pending).expect("expected pending");
2085 assert_matches!(completer_rcv.try_recv(), Ok(None));
2086
2087 let _ = worker.neighbor_table.insert(
2089 key,
2090 fnet_neighbor_ext::Entry { state: fnet_neighbor::EntryState::Probe, ..neighbor },
2091 );
2092 assert_matches!(worker.handle_pending_request(pending), None);
2093
2094 let result = completer_rcv.try_recv().expect("completer channel should not be closed");
2095 assert_matches!(result, Some(Ok(())));
2096 }
2097
2098 #[test_case(
2099 false,
2100 NeighbourHeader {
2101 ifindex: 1,
2102 family: AddressFamily::Inet,
2103 ..Default::default()
2104 },
2105 &[
2106 NeighbourAttribute::Destination(std_ip_v4!("192.168.0.1").into()),
2107 ] => Ok(GetNeighborArgs::Get {
2108 ip: fidl_ip!("192.168.0.1"),
2109 interface: NonZeroU64::new(1).unwrap(),
2110 });
2111 "get ipv4 success"
2112 )]
2113 #[test_case(
2114 false,
2115 NeighbourHeader {
2116 ifindex: 1,
2117 family: AddressFamily::Inet6,
2118 ..Default::default()
2119 },
2120 &[
2121 NeighbourAttribute::Destination(std_ip_v6!("fe80::1").into()),
2122 ] => Ok(GetNeighborArgs::Get {
2123 ip: fidl_ip!("fe80::1"),
2124 interface: NonZeroU64::new(1).unwrap(),
2125 });
2126 "get ipv6 success"
2127 )]
2128 #[test_case(
2129 false,
2130 NeighbourHeader {
2131 ifindex: 1,
2132 family: AddressFamily::Inet,
2133 state: NeighbourState::Reachable,
2134 ..Default::default()
2135 },
2136 &[
2137 NeighbourAttribute::Destination(std_ip_v4!("192.168.0.1").into()),
2138 ] => Err(RequestError::InvalidState {
2139 actual: NeighbourState::Reachable, expected: NeighbourState::None
2140 });
2141 "get invalid request state"
2142 )]
2143 #[test_case(
2144 false,
2145 NeighbourHeader {
2146 ifindex: 1,
2147 family: AddressFamily::Inet,
2148 kind: RouteType::Broadcast,
2149 ..Default::default()
2150 },
2151 &[
2152 NeighbourAttribute::Destination(std_ip_v4!("192.168.0.1").into()),
2153 ] => Err(RequestError::InvalidKind(RouteType::Broadcast));
2154 "get invalid request kind"
2155 )]
2156 #[test_case(
2157 false,
2158 NeighbourHeader {
2159 ifindex: 1,
2160 family: AddressFamily::Inet,
2161 flags: NeighbourFlags::Router,
2162 ..Default::default()
2163 },
2164 &[
2165 NeighbourAttribute::Destination(std_ip_v4!("192.168.0.1").into()),
2166 ] => Err(RequestError::InvalidFlags(NeighbourFlags::Router));
2167 "get invalid request flag"
2168 )]
2169 #[test_case(
2170 false,
2171 NeighbourHeader {
2172 ifindex: 1,
2173 family: AddressFamily::Inet,
2174 flags: NeighbourFlags::Proxy,
2175 ..Default::default()
2176 },
2177 &[
2178 NeighbourAttribute::Destination(std_ip_v4!("192.168.0.1").into()),
2179 ] => Err(RequestError::UnsupportedFlags(NeighbourFlags::Proxy));
2180 "get unsupported request flag"
2181 )]
2182 #[test_case(
2183 false,
2184 NeighbourHeader {
2185 ifindex: 1,
2186 family: AddressFamily::Inet6,
2187 ..Default::default()
2188 },
2189 &[
2190 NeighbourAttribute::Destination(std_ip_v4!("192.168.0.1").into()),
2191 ] => Err(RequestError::AddressFamilyMismatch(AddressFamily::Inet6));
2192 "get address family mismatch"
2193 )]
2194 #[test_case(
2195 false,
2196 NeighbourHeader {
2197 family: AddressFamily::Inet,
2198 ..Default::default()
2199 },
2200 &[
2201 NeighbourAttribute::Destination(std_ip_v4!("192.168.0.1").into()),
2202 ] => Err(RequestError::MissingInterface);
2203 "get interface unspecified"
2204 )]
2205 #[test_case(
2206 false,
2207 NeighbourHeader {
2208 ifindex: 1,
2209 family: AddressFamily::Inet,
2210 ..Default::default()
2211 },
2212 &[] => Err(RequestError::MissingIpAddress);
2213 "get destination unspecified"
2214 )]
2215 #[test_case(
2216 false,
2217 NeighbourHeader {
2218 ifindex: 1,
2219 family: AddressFamily::Inet,
2220 ..Default::default()
2221 },
2222 &[
2223 NeighbourAttribute::Destination(std_ip_v4!("192.168.0.1").into()),
2224 NeighbourAttribute::LinkLocalAddress(vec![0, 1, 2, 3, 4, 5]),
2225 ] => Err(RequestError::InvalidAttribute);
2226 "get invalid attribute"
2227 )]
2228 #[test_case(
2229 true,
2230 NeighbourHeader::default(),
2231 &[] => Ok(GetNeighborArgs::Dump {
2232 ip_version: None,
2233 interface: None,
2234 });
2235 "dump all"
2236 )]
2237 #[test_case(
2238 true,
2239 NeighbourHeader {
2240 family: AddressFamily::Inet,
2241 ..Default::default()
2242 },
2243 &[] => Ok(GetNeighborArgs::Dump {
2244 ip_version: Some(IpVersion::V4),
2245 interface: None,
2246 });
2247 "dump ipv4 only"
2248 )]
2249 #[test_case(
2250 true,
2251 NeighbourHeader {
2252 family: AddressFamily::Inet6,
2253 ..Default::default()
2254 },
2255 &[] => Ok(GetNeighborArgs::Dump {
2256 ip_version: Some(IpVersion::V6),
2257 interface: None,
2258 });
2259 "dump ipv6 only"
2260 )]
2261 #[test_case(
2262 true,
2263 NeighbourHeader::default(),
2264 &[
2265 NeighbourAttribute::IfIndex(1),
2266 ] => Ok(GetNeighborArgs::Dump {
2267 ip_version: None,
2268 interface: Some(NonZeroU64::new(1).unwrap()),
2269 });
2270 "dump interface 1"
2271 )]
2272 #[test_case(
2273 true,
2274 NeighbourHeader::default(),
2275 &[
2276 NeighbourAttribute::IfIndex(0),
2277 ] => Ok(GetNeighborArgs::Dump {
2278 ip_version: None,
2279 interface: None,
2280 });
2281 "dump interface 0 treated as all interfaces"
2282 )]
2283 #[test_case(
2284 true,
2285 NeighbourHeader {
2286 family: AddressFamily::Local,
2287 ..Default::default()
2288 },
2289 &[] => Err(RequestError::InvalidAddressFamily(AddressFamily::Local));
2290 "dump invalid address family"
2291 )]
2292 #[test_case(
2293 true,
2294 NeighbourHeader::default(),
2295 &[
2296 NeighbourAttribute::LinkLocalAddress(vec![0, 1, 2, 3, 4, 5]),
2297 ] => Ok(GetNeighborArgs::Dump {
2298 ip_version: None,
2299 interface: None,
2300 });
2301 "dump unsupported attribute ignored (non-strict)"
2302 )]
2303 #[test_case(
2304 true,
2305 NeighbourHeader {
2306 flags: NeighbourFlags::Proxy,
2307 ..Default::default()
2308 },
2309 &[] => Err(RequestError::UnsupportedFlags(NeighbourFlags::Proxy));
2310 "dump unsupported request flag"
2311 )]
2312 #[fuchsia::test]
2313 fn get_neighbor_args_try_from_rtnl_neighbor(
2314 is_dump: bool,
2315 header: NeighbourHeader,
2316 attrs: &[NeighbourAttribute],
2317 ) -> Result<GetNeighborArgs, RequestError> {
2318 let mut message = NeighbourMessage::default();
2319 message.header = header;
2320 message.attributes = attrs.to_vec();
2321 GetNeighborArgs::try_from_rtnl_neighbor(&message, is_dump)
2322 }
2323
2324 #[test_case(
2325 NeighbourHeader {
2326 ifindex: 1,
2327 family: AddressFamily::Inet,
2328 ..Default::default()
2329 },
2330 &[
2331 NeighbourAttribute::Destination(std_ip_v4!("192.168.0.1").into()),
2332 ] => Ok(DelNeighborArgs {
2333 ip: fidl_ip!("192.168.0.1"),
2334 interface: NonZeroU64::new(1).unwrap(),
2335 });
2336 "del ipv4 success"
2337 )]
2338 #[test_case(
2339 NeighbourHeader {
2340 ifindex: 1,
2341 family: AddressFamily::Inet6,
2342 ..Default::default()
2343 },
2344 &[
2345 NeighbourAttribute::Destination(std_ip_v6!("fe80::1").into()),
2346 ] => Ok(DelNeighborArgs {
2347 ip: fidl_ip!("fe80::1"),
2348 interface: NonZeroU64::new(1).unwrap(),
2349 });
2350 "del ipv6 success"
2351 )]
2352 #[test_case(
2353 NeighbourHeader {
2354 ifindex: 1,
2355 family: AddressFamily::Inet,
2356 flags: NeighbourFlags::Proxy,
2357 ..Default::default()
2358 },
2359 &[
2360 NeighbourAttribute::Destination(std_ip_v4!("192.168.0.1").into()),
2361 ] => Err(RequestError::UnsupportedFlags(NeighbourFlags::Proxy));
2362 "del unsupported request flag"
2363 )]
2364 #[test_case(
2365 NeighbourHeader {
2366 family: AddressFamily::Inet,
2367 ..Default::default()
2368 },
2369 &[
2370 NeighbourAttribute::Destination(std_ip_v4!("192.168.0.1").into()),
2371 ] => Err(RequestError::MissingInterface);
2372 "del interface unspecified"
2373 )]
2374 #[test_case(
2375 NeighbourHeader {
2376 ifindex: 1,
2377 family: AddressFamily::Inet,
2378 ..Default::default()
2379 },
2380 &[] => Err(RequestError::MissingIpAddress);
2381 "del destination unspecified"
2382 )]
2383 #[fuchsia::test]
2384 fn del_neighbor_args_try_from_rtnl_neighbor(
2385 header: NeighbourHeader,
2386 attrs: &[NeighbourAttribute],
2387 ) -> Result<DelNeighborArgs, RequestError> {
2388 let mut message = NeighbourMessage::default();
2389 message.header = header;
2390 message.attributes = attrs.to_vec();
2391 DelNeighborArgs::try_from_rtnl_neighbor(&message)
2392 }
2393
2394 #[test_case(
2395 NLM_F_CREATE | NLM_F_REPLACE,
2396 NeighbourHeader {
2397 ifindex: 1,
2398 family: AddressFamily::Inet,
2399 state: NeighbourState::Permanent,
2400 ..Default::default()
2401 },
2402 &[
2403 NeighbourAttribute::Destination(std_ip_v4!("192.168.0.1").into()),
2404 NeighbourAttribute::LinkLocalAddress(vec![0, 1, 2, 3, 4, 5]),
2405 ] => Ok(NewNeighborArgs::CreateStatic {
2406 ip: fidl_ip!("192.168.0.1"),
2407 interface: NonZeroU64::new(1).unwrap(),
2408 mac: fnet::MacAddress { octets: [0, 1, 2, 3, 4, 5] },
2409 });
2410 "create static ipv4 success"
2411 )]
2412 #[test_case(
2413 NLM_F_CREATE | NLM_F_REPLACE,
2414 NeighbourHeader {
2415 ifindex: 1,
2416 family: AddressFamily::Inet6,
2417 state: NeighbourState::Permanent,
2418 ..Default::default()
2419 },
2420 &[
2421 NeighbourAttribute::Destination(std_ip_v6!("fe80::1").into()),
2422 NeighbourAttribute::LinkLocalAddress(vec![0, 1, 2, 3, 4, 5]),
2423 ] => Ok(NewNeighborArgs::CreateStatic {
2424 ip: fidl_ip!("fe80::1"),
2425 interface: NonZeroU64::new(1).unwrap(),
2426 mac: fnet::MacAddress { octets: [0, 1, 2, 3, 4, 5] },
2427 });
2428 "create static ipv6 success"
2429 )]
2430 #[test_case(
2431 NLM_F_REPLACE,
2432 NeighbourHeader {
2433 ifindex: 1,
2434 family: AddressFamily::Inet,
2435 state: NeighbourState::Probe,
2436 ..Default::default()
2437 },
2438 &[
2439 NeighbourAttribute::Destination(std_ip_v4!("192.168.0.1").into()),
2440 ] => Ok(NewNeighborArgs::ProbeExisting {
2441 ip: fidl_ip!("192.168.0.1"),
2442 interface: NonZeroU64::new(1).unwrap(),
2443 });
2444 "probe existing ipv4 success"
2445 )]
2446 #[test_case(
2447 NLM_F_REPLACE,
2448 NeighbourHeader {
2449 ifindex: 1,
2450 family: AddressFamily::Inet6,
2451 state: NeighbourState::Probe,
2452 ..Default::default()
2453 },
2454 &[
2455 NeighbourAttribute::Destination(std_ip_v6!("fe80::1").into()),
2456 ] => Ok(NewNeighborArgs::ProbeExisting {
2457 ip: fidl_ip!("fe80::1"),
2458 interface: NonZeroU64::new(1).unwrap(),
2459 });
2460 "probe existing ipv6 success"
2461 )]
2462 #[test_case(
2463 NLM_F_REPLACE,
2464 NeighbourHeader {
2465 ifindex: 1,
2466 family: AddressFamily::Inet,
2467 flags: NeighbourFlags::Proxy,
2468 ..Default::default()
2469 },
2470 &[
2471 NeighbourAttribute::Destination(std_ip_v4!("192.168.0.1").into()),
2472 ] => Err(RequestError::UnsupportedFlags(NeighbourFlags::Proxy));
2473 "unsupported proxy flag"
2474 )]
2475 #[test_case(
2476 NLM_F_CREATE | NLM_F_REPLACE,
2477 NeighbourHeader {
2478 ifindex: 1,
2479 family: AddressFamily::Inet,
2480 state: NeighbourState::Reachable,
2481 ..Default::default()
2482 },
2483 &[
2484 NeighbourAttribute::Destination(std_ip_v4!("192.168.0.1").into()),
2485 NeighbourAttribute::LinkLocalAddress(vec![0, 1, 2, 3, 4, 5]),
2486 ] => Err(RequestError::InvalidState {
2487 actual: NeighbourState::Reachable,
2488 expected: NeighbourState::Permanent,
2489 });
2490 "create invalid state"
2491 )]
2492 #[test_case(
2493 NLM_F_REPLACE,
2494 NeighbourHeader {
2495 ifindex: 1,
2496 family: AddressFamily::Inet,
2497 state: NeighbourState::Permanent,
2498 ..Default::default()
2499 },
2500 &[
2501 NeighbourAttribute::Destination(std_ip_v4!("192.168.0.1").into()),
2502 ] => Err(RequestError::InvalidState {
2503 actual: NeighbourState::Permanent,
2504 expected: NeighbourState::Probe,
2505 });
2506 "probe invalid state"
2507 )]
2508 #[test_case(
2509 NLM_F_CREATE | NLM_F_REPLACE,
2510 NeighbourHeader {
2511 ifindex: 1,
2512 family: AddressFamily::Inet,
2513 state: NeighbourState::Permanent,
2514 ..Default::default()
2515 },
2516 &[
2517 NeighbourAttribute::Destination(std_ip_v4!("192.168.0.1").into()),
2518 ] => Err(RequestError::MissingMacAddress);
2519 "create missing mac address"
2520 )]
2521 #[test_case(
2522 NLM_F_EXCL,
2523 NeighbourHeader {
2524 ifindex: 1,
2525 family: AddressFamily::Inet,
2526 ..Default::default()
2527 },
2528 &[
2529 NeighbourAttribute::Destination(std_ip_v4!("192.168.0.1").into()),
2530 ] => Err(RequestError::UnsupportedOperation);
2531 "unsupported operation flags"
2532 )]
2533 #[fuchsia::test]
2534 fn new_neighbor_args_try_from_rtnl_neighbor(
2535 netlink_flags: u16,
2536 header: NeighbourHeader,
2537 attrs: &[NeighbourAttribute],
2538 ) -> Result<NewNeighborArgs, RequestError> {
2539 let mut message = NeighbourMessage::default();
2540 message.header = header;
2541 message.attributes = attrs.to_vec();
2542 NewNeighborArgs::try_from_rtnl_neighbor(&message, netlink_flags)
2543 }
2544
2545 #[test_case(
2546 RequestError::InvalidState {
2547 actual: NeighbourState::Reachable, expected:NeighbourState::None
2548 } => Errno::EINVAL;
2549 "invalid state"
2550 )]
2551 #[test_case(RequestError::InvalidKind(RouteType::Broadcast) => Errno::EINVAL; "invalid kind")]
2552 #[test_case(
2553 RequestError::InvalidFlags(NeighbourFlags::Router) => Errno::EINVAL;
2554 "invalid flags"
2555 )]
2556 #[test_case(
2557 RequestError::UnsupportedFlags(NeighbourFlags::Proxy) => Errno::ENOTSUP;
2558 "unsupported flags"
2559 )]
2560 #[test_case(
2561 RequestError::InvalidAddressFamily(AddressFamily::Local) => Errno::EAFNOSUPPORT;
2562 "invalid address family"
2563 )]
2564 #[test_case(
2565 RequestError::AddressFamilyMismatch(AddressFamily::Inet6) => Errno::EINVAL;
2566 "address family mismatch"
2567 )]
2568 #[test_case(RequestError::MissingInterface => Errno::EINVAL; "interface unspecified")]
2569 #[test_case(RequestError::MissingIpAddress => Errno::EINVAL; "destination unspecified")]
2570 #[test_case(RequestError::InvalidAttribute => Errno::EINVAL; "invalid attribute")]
2571 #[test_case(RequestError::NeighborNotFound => Errno::ENOENT; "neighbor not found")]
2572 #[test_case(RequestError::InterfaceNotFound => Errno::ENODEV; "interface not found")]
2573 #[test_case(RequestError::InvalidIpAddress => Errno::EINVAL; "invalid IP address")]
2574 #[test_case(RequestError::InvalidMacAddress => Errno::EINVAL; "invalid MAC address")]
2575 #[test_case(RequestError::InterfaceUnsupported => Errno::ENOTSUP; "unsupported interface")]
2576 #[fuchsia::test]
2577 fn request_error_into_errno(error: RequestError) -> Errno {
2578 error.into()
2579 }
2580
2581 enum NeighborsAndInterfaces {}
2582 impl EventLoopSpec for NeighborsAndInterfaces {
2583 type NeighborWorker = Required;
2584
2585 type InterfacesProxy = Required;
2586 type InterfacesStateProxy = Required;
2587 type InterfacesHandler = Required;
2588 type RouteClients = Required;
2589 type InterfacesWorker = Required;
2590
2591 type V4RoutesState = Optional;
2592 type V6RoutesState = Optional;
2593 type V4RoutesSetProvider = Optional;
2594 type V6RoutesSetProvider = Optional;
2595 type V4RouteTableProvider = Optional;
2596 type V6RouteTableProvider = Optional;
2597
2598 type RoutesV4Worker = Optional;
2599 type RoutesV6Worker = Optional;
2600 type RuleV4Worker = Optional;
2601 type RuleV6Worker = Optional;
2602 type NduseroptWorker = Optional;
2603 }
2604
2605 const TEST_SEQUENCE_NUMBER: u32 = 1234;
2606
2607 struct EventLoopSetup {
2608 event_loop: EventLoopState<
2609 FakeInterfacesHandler,
2610 FakeSender<RouteNetlinkMessage>,
2611 NeighborsAndInterfaces,
2612 >,
2613 request_sink: mpsc::Sender<UnifiedRequest<FakeSender<RouteNetlinkMessage>>>,
2614 neighbors_controller_request_stream: fnet_neighbor::ControllerRequestStream,
2615 neighbor_event_sink: mpsc::UnboundedSender<Vec<fnet_neighbor::EntryIteratorItem>>,
2616 interface_event_sink: mpsc::UnboundedSender<fnet_interfaces::Event>,
2617 }
2618
2619 async fn build_event_loop(
2620 scope: &fuchsia_async::Scope,
2621 neighbor_events: &[EventSpec],
2622 ) -> EventLoopSetup {
2623 let included_workers = IncludedWorkers {
2624 routes_v4: EventLoopComponent::Absent(Optional),
2625 routes_v6: EventLoopComponent::Absent(Optional),
2626 interfaces: EventLoopComponent::Present(()),
2627 rules_v4: EventLoopComponent::Absent(Optional),
2628 rules_v6: EventLoopComponent::Absent(Optional),
2629 neighbors: EventLoopComponent::Present(()),
2630 nduseropt: EventLoopComponent::Absent(Optional),
2631 };
2632 let (request_sink, request_stream) = mpsc::channel(1);
2633
2634 let (neighbors_controller, neighbors_controller_request_stream) =
2637 fidl::endpoints::create_proxy_and_stream::<fnet_neighbor::ControllerMarker>();
2638
2639 let (neighbors_view, neighbor_event_sink) = {
2640 let events = fnet_neighbor_ext::testutil::generate_events_from_spec(neighbor_events);
2641 let (event_sender, event_receiver) = mpsc::unbounded();
2642 event_sender.unbounded_send(events).expect("failed to send events");
2643 let (neighbors_view, neighbors_fut) =
2644 fnet_neighbor_ext::testutil::create_fake_view(event_receiver);
2645 let _join_handle = scope.spawn(neighbors_fut);
2646 (neighbors_view, event_sender)
2647 };
2648
2649 let (interfaces_handler, _interfaces_handler_sink) =
2652 crate::interfaces::testutil::FakeInterfacesHandler::new();
2653 let (interfaces_proxy, _interfaces) =
2654 fidl::endpoints::create_proxy::<fnet_root::InterfacesMarker>();
2655 let (interfaces_state_proxy, interfaces_state) =
2656 fidl::endpoints::create_proxy::<fnet_interfaces::StateMarker>();
2657 let route_clients = ClientTable::default();
2658
2659 let interface_event_sink = {
2660 let if_stream = interfaces_state.into_stream();
2661 let if_watcher_stream = if_stream
2662 .and_then(|req| match req {
2663 fnet_interfaces::StateRequest::GetWatcher {
2664 options: _,
2665 watcher,
2666 control_handle: _,
2667 } => futures::future::ready(Ok(watcher.into_stream())),
2668 })
2669 .try_flatten()
2670 .map(|res| res.expect("watcher stream error"));
2671 let (event_sender, event_receiver) = mpsc::unbounded();
2672 event_sender
2673 .unbounded_send(fnet_interfaces::Event::Idle(fnet_interfaces::Empty))
2674 .expect("failed to send event");
2675 let interfaces_fut =
2676 if_watcher_stream.zip(event_receiver).for_each(|(req, update)| async move {
2677 match req {
2678 fnet_interfaces::WatcherRequest::Watch { responder } => {
2679 responder.send(&update).expect("send watch response")
2680 }
2681 }
2682 });
2683 let _join_handle = scope.spawn(interfaces_fut);
2684 event_sender
2685 };
2686
2687 let (_async_work_sink, async_work_receiver) = mpsc::unbounded();
2690 let base_inputs: EventLoopInputs<
2691 FakeInterfacesHandler,
2692 FakeSender<RouteNetlinkMessage>,
2693 NeighborsAndInterfaces,
2694 > = EventLoopInputs {
2695 neighbors_view: EventLoopComponent::Present(neighbors_view),
2696 neighbors_controller: EventLoopComponent::Present(neighbors_controller),
2697
2698 route_clients: EventLoopComponent::Present(route_clients),
2699 interfaces_handler: EventLoopComponent::Present(interfaces_handler),
2700 interfaces_proxy: EventLoopComponent::Present(interfaces_proxy),
2701 interfaces_state_proxy: EventLoopComponent::Present(interfaces_state_proxy),
2702
2703 async_work_receiver,
2704
2705 v4_routes_state: EventLoopComponent::Absent(Optional),
2706 v6_routes_state: EventLoopComponent::Absent(Optional),
2707 v4_main_route_table: EventLoopComponent::Absent(Optional),
2708 v6_main_route_table: EventLoopComponent::Absent(Optional),
2709 v4_route_table_provider: EventLoopComponent::Absent(Optional),
2710 v6_route_table_provider: EventLoopComponent::Absent(Optional),
2711 v4_rule_table: EventLoopComponent::Absent(Optional),
2712 v6_rule_table: EventLoopComponent::Absent(Optional),
2713 ndp_option_watcher_provider: EventLoopComponent::Absent(Optional),
2714
2715 unified_request_stream: request_stream,
2716 };
2717
2718 let event_loop = base_inputs.initialize(included_workers).await;
2719 EventLoopSetup {
2720 event_loop,
2721 request_sink,
2722 neighbors_controller_request_stream,
2723 neighbor_event_sink,
2724 interface_event_sink,
2725 }
2726 }
2727
2728 #[fuchsia::test]
2729 async fn event_loop_with_watch_events_and_get_request() {
2730 let scope = fuchsia_async::Scope::new();
2731 use fnet_neighbor_ext::testutil::EventSpec::*;
2732 let EventLoopSetup {
2733 mut event_loop,
2734 mut request_sink,
2735 neighbors_controller_request_stream: _,
2736 neighbor_event_sink,
2737 interface_event_sink,
2738 } = build_event_loop(&scope, &[Existing(1), Existing(2), Existing(3), Idle, Added(4)])
2739 .await;
2740
2741 event_loop.run_one_step_in_tests().await;
2743
2744 let (mut response_sink, neighbor_client, async_work_drain_task) =
2747 crate::client::testutil::new_fake_client::<NetlinkRoute>(
2748 crate::client::testutil::CLIENT_ID_1,
2749 [],
2750 );
2751 let _join_handle = scope.spawn(async_work_drain_task);
2752
2753 let (completer, waiter) = oneshot::channel();
2754 let get_request: UnifiedRequest<FakeSender<RouteNetlinkMessage>> =
2755 UnifiedRequest::NeighborsRequest(Request {
2756 args: NeighborRequestArgs::Get(GetNeighborArgs::Dump {
2757 ip_version: None,
2758 interface: None,
2759 }),
2760 sequence_number: TEST_SEQUENCE_NUMBER,
2761 client: neighbor_client.clone(),
2762 completer,
2763 });
2764 request_sink.send(get_request).await.unwrap();
2765
2766 event_loop.run_one_step_in_tests().await;
2768 assert_matches!(waiter.await.unwrap(), Ok(()));
2769
2770 let responses = response_sink.take_messages();
2771 assert_eq!(responses.len(), 4); for response in responses {
2773 assert_matches!(
2774 response.message.payload,
2775 NetlinkPayload::InnerMessage(RouteNetlinkMessage::NewNeighbour(_))
2776 );
2777 }
2778
2779 neighbor_event_sink.close_channel();
2780 interface_event_sink.close_channel();
2781 drop(neighbor_client);
2782 scope.join().await;
2783 }
2784
2785 #[fuchsia::test]
2786 async fn event_loop_with_watch_events_and_delete_request() {
2787 let scope = fuchsia_async::Scope::new();
2788 let neighbor_events = {
2789 use fnet_neighbor_ext::testutil::EventSpec::*;
2790 vec![Existing(1), Existing(2), Idle]
2791 };
2792 let EventLoopSetup {
2793 mut event_loop,
2794 mut request_sink,
2795 neighbors_controller_request_stream,
2796 neighbor_event_sink,
2797 interface_event_sink,
2798 } = build_event_loop(&scope, &neighbor_events).await;
2799
2800 let fnet_neighbor::EntryIteratorItem::Existing(to_delete) =
2801 fnet_neighbor_ext::testutil::generate_event_from_spec(&neighbor_events[0])
2802 else {
2803 panic!("unexpected event")
2804 };
2805 let to_delete: fnet_neighbor_ext::Entry =
2806 to_delete.try_into().expect("extension conversion failed");
2807
2808 let (mut response_sink, neighbor_client, async_work_drain_task) =
2809 crate::client::testutil::new_fake_client::<NetlinkRoute>(
2810 crate::client::testutil::CLIENT_ID_1,
2811 [],
2812 );
2813 let _join_handle = scope.spawn(async_work_drain_task);
2814
2815 let (completer, waiter) = oneshot::channel();
2818 let waiter = waiter.fuse();
2819 pin_mut!(waiter);
2820
2821 let del_request: UnifiedRequest<FakeSender<RouteNetlinkMessage>> =
2822 UnifiedRequest::NeighborsRequest(Request {
2823 args: NeighborRequestArgs::Del(DelNeighborArgs {
2824 ip: to_delete.neighbor,
2825 interface: to_delete.interface,
2826 }),
2827 sequence_number: TEST_SEQUENCE_NUMBER,
2828 client: neighbor_client.clone(),
2829 completer,
2830 });
2831 request_sink.send(del_request).await.expect("failed to send delete request");
2832
2833 let controller_req_fut = neighbors_controller_request_stream
2837 .into_future()
2838 .then(async move |(req, _rest)| {
2839 match req
2840 .expect("Controller request stream unexpectedly ended")
2841 .expect("failed to receive `Controller` request")
2842 {
2843 fnet_neighbor::ControllerRequest::RemoveEntry {
2844 interface,
2845 neighbor,
2846 responder,
2847 ..
2848 } => {
2849 assert_eq!(interface, to_delete.interface.get());
2850 assert_eq!(neighbor, to_delete.neighbor);
2851 responder.send(Ok(())).expect("failed to respond to RemoveEntry");
2852 }
2853 _ => panic!("unexpected controller request"),
2854 }
2855 })
2856 .fuse();
2857 let _join_handle = scope.spawn(controller_req_fut);
2858 event_loop.run_one_step_in_tests().await;
2859
2860 assert_matches!(waiter.as_mut().now_or_never(), None);
2861 assert_eq!(response_sink.take_messages().len(), 0);
2862
2863 {
2867 use fnet_neighbor_ext::testutil::EventSpec::*;
2868 neighbor_event_sink
2869 .unbounded_send(fnet_neighbor_ext::testutil::generate_events_from_spec(&[Added(3)]))
2870 .expect("failed to send event");
2871 }
2872
2873 event_loop.run_one_step_in_tests().await;
2874 assert_matches!(waiter.as_mut().now_or_never(), None);
2875 assert_eq!(response_sink.take_messages().len(), 0);
2876
2877 {
2881 use fnet_neighbor_ext::testutil::EventSpec::*;
2882 neighbor_event_sink
2883 .unbounded_send(fnet_neighbor_ext::testutil::generate_events_from_spec(&[Removed(
2884 1,
2885 )]))
2886 .expect("failed to send event");
2887 }
2888
2889 event_loop.run_one_step_in_tests().await;
2890 assert_matches!(waiter.await.expect("waiter channel should not be closed"), Ok(()));
2891 neighbor_event_sink.close_channel();
2896 interface_event_sink.close_channel();
2897 drop(neighbor_client);
2898 scope.join().await;
2899 }
2900
2901 #[fuchsia::test]
2902 async fn event_loop_with_watch_events_create_static_neighbor() {
2903 let scope = fuchsia_async::Scope::new();
2904 let neighbor_events = vec![fnet_neighbor_ext::testutil::EventSpec::Idle];
2905 let EventLoopSetup {
2906 mut event_loop,
2907 mut request_sink,
2908 neighbors_controller_request_stream,
2909 neighbor_event_sink,
2910 interface_event_sink,
2911 } = build_event_loop(&scope, &neighbor_events).await;
2912
2913 let (mut response_sink, neighbor_client, async_work_drain_task) =
2914 crate::client::testutil::new_fake_client::<NetlinkRoute>(
2915 crate::client::testutil::CLIENT_ID_1,
2916 [],
2917 );
2918 let _join_handle = scope.spawn(async_work_drain_task);
2919
2920 let (event, entry) = {
2923 use fnet_neighbor_ext::testutil::EventSpec::*;
2924 let mut added = fnet_neighbor_ext::testutil::generate_event_from_spec(&Added(1));
2925 let fnet_neighbor::EntryIteratorItem::Added(to_add) = &mut added else {
2926 panic!("unexpected event")
2927 };
2928 to_add.state = Some(fnet_neighbor::EntryState::Static);
2929 let entry: fnet_neighbor_ext::Entry =
2930 to_add.clone().try_into().expect("extension conversion failed");
2931 (added, entry)
2932 };
2933
2934 let (completer, waiter) = oneshot::channel();
2937 let waiter = waiter.fuse();
2938 pin_mut!(waiter);
2939
2940 let create_request: UnifiedRequest<FakeSender<RouteNetlinkMessage>> =
2941 UnifiedRequest::NeighborsRequest(Request {
2942 args: NeighborRequestArgs::New(NewNeighborArgs::CreateStatic {
2943 ip: entry.neighbor,
2944 interface: entry.interface,
2945 mac: entry.mac.unwrap(),
2946 }),
2947 sequence_number: TEST_SEQUENCE_NUMBER,
2948 client: neighbor_client.clone(),
2949 completer,
2950 });
2951 request_sink.send(create_request).await.expect("failed to send create request");
2952
2953 let controller_req_fut = neighbors_controller_request_stream
2957 .into_future()
2958 .then(async move |(req, _rest)| {
2959 match req
2960 .expect("Controller request stream unexpectedly ended")
2961 .expect("failed to receive `Controller` request")
2962 {
2963 fnet_neighbor::ControllerRequest::AddEntry {
2964 interface,
2965 neighbor,
2966 mac,
2967 responder,
2968 } => {
2969 assert_eq!(interface, entry.interface.get());
2970 assert_eq!(neighbor, entry.neighbor);
2971 assert_eq!(mac, entry.mac.unwrap());
2972 responder.send(Ok(())).expect("failed to respond to AddEntry");
2973 }
2974 _ => panic!("unexpected controller request"),
2975 }
2976 })
2977 .fuse();
2978 let _join_handle = scope.spawn(controller_req_fut);
2979
2980 event_loop.run_one_step_in_tests().await;
2981 assert_matches!(waiter.as_mut().now_or_never(), None);
2982 assert_eq!(response_sink.take_messages().len(), 0);
2983
2984 {
2988 use fnet_neighbor_ext::testutil::EventSpec::*;
2989 neighbor_event_sink
2990 .unbounded_send(fnet_neighbor_ext::testutil::generate_events_from_spec(&[Added(3)]))
2991 .expect("failed to send event");
2992 }
2993
2994 event_loop.run_one_step_in_tests().await;
2995 assert_matches!(waiter.as_mut().now_or_never(), None);
2996 assert_eq!(response_sink.take_messages().len(), 0);
2997
2998 neighbor_event_sink.unbounded_send(vec![event]).expect("failed to send event");
3002
3003 event_loop.run_one_step_in_tests().await;
3004 assert_matches!(waiter.await.expect("waiter channel should not be closed"), Ok(()));
3005 neighbor_event_sink.close_channel();
3010 interface_event_sink.close_channel();
3011 drop(neighbor_client);
3012 scope.join().await;
3013 }
3014
3015 #[fuchsia::test]
3016 async fn event_loop_with_watch_events_create_already_existing_succeeds_without_event() {
3017 let scope = fuchsia_async::Scope::new();
3018 let neighbor_events = vec![fnet_neighbor_ext::testutil::EventSpec::Idle];
3019 let EventLoopSetup {
3020 mut event_loop,
3021 mut request_sink,
3022 neighbors_controller_request_stream,
3023 neighbor_event_sink,
3024 interface_event_sink,
3025 } = build_event_loop(&scope, &neighbor_events).await;
3026
3027 let (mut response_sink, neighbor_client, async_work_drain_task) =
3028 crate::client::testutil::new_fake_client::<NetlinkRoute>(
3029 crate::client::testutil::CLIENT_ID_1,
3030 [],
3031 );
3032 let _join_handle = scope.spawn(async_work_drain_task);
3033
3034 let (event, entry) = {
3037 use fnet_neighbor_ext::testutil::EventSpec::*;
3038 let mut added = fnet_neighbor_ext::testutil::generate_event_from_spec(&Added(1));
3039 let fnet_neighbor::EntryIteratorItem::Added(to_add) = &mut added else {
3040 panic!("unexpected event")
3041 };
3042 to_add.state = Some(fnet_neighbor::EntryState::Static);
3043 let entry: fnet_neighbor_ext::Entry =
3044 to_add.clone().try_into().expect("extension conversion failed");
3045 (added, entry)
3046 };
3047 neighbor_event_sink.unbounded_send(vec![event]).expect("failed to send event");
3048 event_loop.run_one_step_in_tests().await;
3049
3050 let (completer, waiter) = oneshot::channel();
3053 let waiter = waiter.fuse();
3054 pin_mut!(waiter);
3055
3056 let create_request: UnifiedRequest<FakeSender<RouteNetlinkMessage>> =
3057 UnifiedRequest::NeighborsRequest(Request {
3058 args: NeighborRequestArgs::New(NewNeighborArgs::CreateStatic {
3059 ip: entry.neighbor,
3060 interface: entry.interface,
3061 mac: entry.mac.unwrap(),
3062 }),
3063 sequence_number: TEST_SEQUENCE_NUMBER,
3064 client: neighbor_client.clone(),
3065 completer,
3066 });
3067 request_sink.send(create_request).await.expect("failed to send create request");
3068
3069 let controller_req_fut = neighbors_controller_request_stream
3073 .into_future()
3074 .then(async move |(req, _rest)| {
3075 match req
3076 .expect("Controller request stream unexpectedly ended")
3077 .expect("failed to receive `Controller` request")
3078 {
3079 fnet_neighbor::ControllerRequest::AddEntry {
3080 interface,
3081 neighbor,
3082 mac,
3083 responder,
3084 } => {
3085 assert_eq!(interface, entry.interface.get());
3086 assert_eq!(neighbor, entry.neighbor);
3087 assert_eq!(mac, entry.mac.unwrap());
3088 responder.send(Ok(())).expect("failed to respond to AddEntry");
3089 }
3090 _ => panic!("unexpected controller request"),
3091 }
3092 })
3093 .fuse();
3094 let _join_handle = scope.spawn(controller_req_fut);
3095
3096 event_loop.run_one_step_in_tests().await;
3097 assert_matches!(waiter.await.expect("waiter channel should not be closed"), Ok(()));
3098 assert_eq!(response_sink.take_messages().len(), 0);
3099 neighbor_event_sink.close_channel();
3104 interface_event_sink.close_channel();
3105 drop(neighbor_client);
3106 scope.join().await;
3107 }
3108
3109 #[fuchsia::test]
3110 async fn event_loop_with_watch_events_probe_neighbor() {
3111 let scope = fuchsia_async::Scope::new();
3112 let neighbor_events = vec![fnet_neighbor_ext::testutil::EventSpec::Idle];
3113 let EventLoopSetup {
3114 mut event_loop,
3115 mut request_sink,
3116 neighbors_controller_request_stream,
3117 neighbor_event_sink,
3118 interface_event_sink,
3119 } = build_event_loop(&scope, &neighbor_events).await;
3120
3121 let (mut response_sink, neighbor_client, async_work_drain_task) =
3122 crate::client::testutil::new_fake_client::<NetlinkRoute>(
3123 crate::client::testutil::CLIENT_ID_1,
3124 [],
3125 );
3126 let _join_handle = scope.spawn(async_work_drain_task);
3127
3128 let (event, entry) = {
3131 use fnet_neighbor_ext::testutil::EventSpec::*;
3132 let mut added = fnet_neighbor_ext::testutil::generate_event_from_spec(&Added(1));
3133 let fnet_neighbor::EntryIteratorItem::Added(to_add) = &mut added else {
3134 panic!("unexpected event")
3135 };
3136 to_add.state = Some(fnet_neighbor::EntryState::Reachable);
3137 let entry: fnet_neighbor_ext::Entry =
3138 to_add.clone().try_into().expect("extension conversion failed");
3139 (added, entry)
3140 };
3141 neighbor_event_sink.unbounded_send(vec![event]).expect("failed to send event");
3142 event_loop.run_one_step_in_tests().await;
3143
3144 let (completer, waiter) = oneshot::channel();
3147 let waiter = waiter.fuse();
3148 pin_mut!(waiter);
3149
3150 let probe_request: UnifiedRequest<FakeSender<RouteNetlinkMessage>> =
3151 UnifiedRequest::NeighborsRequest(Request {
3152 args: NeighborRequestArgs::New(NewNeighborArgs::ProbeExisting {
3153 ip: entry.neighbor,
3154 interface: entry.interface,
3155 }),
3156 sequence_number: TEST_SEQUENCE_NUMBER,
3157 client: neighbor_client.clone(),
3158 completer,
3159 });
3160 request_sink.send(probe_request).await.expect("failed to send create request");
3161
3162 let controller_req_fut = neighbors_controller_request_stream
3166 .into_future()
3167 .then(async move |(req, _rest)| {
3168 match req
3169 .expect("Controller request stream unexpectedly ended")
3170 .expect("failed to receive `Controller` request")
3171 {
3172 fnet_neighbor::ControllerRequest::ProbeEntry {
3173 interface,
3174 neighbor,
3175 responder,
3176 } => {
3177 assert_eq!(interface, entry.interface.get());
3178 assert_eq!(neighbor, entry.neighbor);
3179 responder.send(Ok(())).expect("failed to respond to ProbeEntry");
3180 }
3181 _ => panic!("unexpected controller request"),
3182 }
3183 })
3184 .fuse();
3185 let _join_handle = scope.spawn(controller_req_fut);
3186
3187 event_loop.run_one_step_in_tests().await;
3188 assert_matches!(waiter.as_mut().now_or_never(), None);
3189 assert_eq!(response_sink.take_messages().len(), 0);
3190
3191 {
3195 use fnet_neighbor_ext::testutil::EventSpec::*;
3196 neighbor_event_sink
3197 .unbounded_send(fnet_neighbor_ext::testutil::generate_events_from_spec(&[Added(3)]))
3198 .expect("failed to send event");
3199 }
3200
3201 event_loop.run_one_step_in_tests().await;
3202 assert_matches!(waiter.as_mut().now_or_never(), None);
3203 assert_eq!(response_sink.take_messages().len(), 0);
3204
3205 {
3209 let mut changed = entry.clone();
3210 changed.state = fnet_neighbor::EntryState::Probe;
3211 let changed_event = fnet_neighbor::EntryIteratorItem::Changed(changed.into());
3212 neighbor_event_sink.unbounded_send(vec![changed_event]).expect("failed to send event");
3213 }
3214
3215 event_loop.run_one_step_in_tests().await;
3216 assert_matches!(waiter.await.expect("waiter channel should not be closed"), Ok(()));
3217 neighbor_event_sink.close_channel();
3222 interface_event_sink.close_channel();
3223 drop(neighbor_client);
3224 scope.join().await;
3225 }
3226
3227 #[fuchsia::test]
3228 async fn event_loop_with_watch_events_probe_already_probing_succeeds_without_event() {
3229 let scope = fuchsia_async::Scope::new();
3230 let neighbor_events = vec![fnet_neighbor_ext::testutil::EventSpec::Idle];
3231 let EventLoopSetup {
3232 mut event_loop,
3233 mut request_sink,
3234 neighbors_controller_request_stream,
3235 neighbor_event_sink,
3236 interface_event_sink,
3237 } = build_event_loop(&scope, &neighbor_events).await;
3238
3239 let (mut response_sink, neighbor_client, async_work_drain_task) =
3240 crate::client::testutil::new_fake_client::<NetlinkRoute>(
3241 crate::client::testutil::CLIENT_ID_1,
3242 [],
3243 );
3244 let _join_handle = scope.spawn(async_work_drain_task);
3245
3246 let (event, entry) = {
3249 use fnet_neighbor_ext::testutil::EventSpec::*;
3250 let mut added = fnet_neighbor_ext::testutil::generate_event_from_spec(&Added(1));
3251 let fnet_neighbor::EntryIteratorItem::Added(to_add) = &mut added else {
3252 panic!("unexpected event")
3253 };
3254 to_add.state = Some(fnet_neighbor::EntryState::Probe);
3255 let entry: fnet_neighbor_ext::Entry =
3256 to_add.clone().try_into().expect("extension conversion failed");
3257 (added, entry)
3258 };
3259 neighbor_event_sink.unbounded_send(vec![event]).expect("failed to send event");
3260 event_loop.run_one_step_in_tests().await;
3261
3262 let (completer, waiter) = oneshot::channel();
3265 let waiter = waiter.fuse();
3266 pin_mut!(waiter);
3267
3268 let probe_request: UnifiedRequest<FakeSender<RouteNetlinkMessage>> =
3269 UnifiedRequest::NeighborsRequest(Request {
3270 args: NeighborRequestArgs::New(NewNeighborArgs::ProbeExisting {
3271 ip: entry.neighbor,
3272 interface: entry.interface,
3273 }),
3274 sequence_number: TEST_SEQUENCE_NUMBER,
3275 client: neighbor_client.clone(),
3276 completer,
3277 });
3278 request_sink.send(probe_request).await.expect("failed to send create request");
3279
3280 let controller_req_fut = neighbors_controller_request_stream
3284 .into_future()
3285 .then(async move |(req, _rest)| {
3286 match req
3287 .expect("Controller request stream unexpectedly ended")
3288 .expect("failed to receive `Controller` request")
3289 {
3290 fnet_neighbor::ControllerRequest::ProbeEntry {
3291 interface,
3292 neighbor,
3293 responder,
3294 } => {
3295 assert_eq!(interface, entry.interface.get());
3296 assert_eq!(neighbor, entry.neighbor);
3297 responder.send(Ok(())).expect("failed to respond to ProbeEntry");
3298 }
3299 _ => panic!("unexpected controller request"),
3300 }
3301 })
3302 .fuse();
3303 let _join_handle = scope.spawn(controller_req_fut);
3304
3305 event_loop.run_one_step_in_tests().await;
3306 assert_matches!(waiter.await.expect("waiter channel should not be closed"), Ok(()));
3307 assert_eq!(response_sink.take_messages().len(), 0);
3308 neighbor_event_sink.close_channel();
3313 interface_event_sink.close_channel();
3314 drop(neighbor_client);
3315 scope.join().await;
3316 }
3317
3318 #[fuchsia::test]
3319 async fn neighbors_worker_sends_multicast_updates() {
3320 let (mut sender_sink_member, client_member, _async_work_drain_task_1) =
3321 new_fake_client::<NetlinkRoute>(
3322 CLIENT_ID_1,
3323 [ModernGroup(rtnetlink_groups_RTNLGRP_NEIGH)],
3324 );
3325 let (mut sender_sink_non_member, client_non_member, _async_work_drain_task_2) =
3326 new_fake_client::<NetlinkRoute>(CLIENT_ID_2, []);
3327
3328 let client_table = ClientTable::default();
3329 client_table.add_client(client_member);
3330 client_table.add_client(client_non_member);
3331
3332 let (neighbors_controller, _server_end) =
3333 fidl::endpoints::create_proxy::<fnet_neighbor::ControllerMarker>();
3334 let mut worker = NeighborsWorker { neighbor_table: HashMap::new(), neighbors_controller };
3335
3336 let entry = valid_neighbor_entry();
3337
3338 worker
3342 .handle_neighbor_watcher_event(
3343 fnet_neighbor_ext::Event::Added(entry.clone()),
3344 &client_table,
3345 )
3346 .expect("handle added");
3347
3348 let messages = sender_sink_member.take_messages();
3349 assert_eq!(messages.len(), 1);
3350 let SentMessage { message, group } = &messages[0];
3351 assert_eq!(group, &Some(ModernGroup(rtnetlink_groups_RTNLGRP_NEIGH)));
3352 assert_matches!(
3353 &message.payload,
3354 NetlinkPayload::InnerMessage(RouteNetlinkMessage::NewNeighbour(msg)) => {
3355 assert_eq!(msg.header.ifindex as u64, entry.interface.get());
3356 }
3357 );
3358 assert_eq!(message.header.sequence_number, UNSPECIFIED_SEQUENCE_NUMBER);
3359 assert_eq!(sender_sink_non_member.take_messages().len(), 0);
3360
3361 let mut new_entry = entry.clone();
3365 new_entry.state = fnet_neighbor::EntryState::Stale;
3366 worker
3367 .handle_neighbor_watcher_event(
3368 fnet_neighbor_ext::Event::Changed(new_entry.clone()),
3369 &client_table,
3370 )
3371 .expect("handle changed");
3372
3373 let messages = sender_sink_member.take_messages();
3374 assert_eq!(messages.len(), 1);
3375 let SentMessage { message, group } = &messages[0];
3376 assert_eq!(group, &Some(ModernGroup(rtnetlink_groups_RTNLGRP_NEIGH)));
3377 assert_matches!(
3378 &message.payload,
3379 NetlinkPayload::InnerMessage(RouteNetlinkMessage::NewNeighbour(msg)) => {
3380 assert_eq!(msg.header.state, NeighbourState::Stale);
3381 }
3382 );
3383 assert_eq!(sender_sink_non_member.take_messages().len(), 0);
3384
3385 worker
3389 .handle_neighbor_watcher_event(
3390 fnet_neighbor_ext::Event::Removed(new_entry.clone()),
3391 &client_table,
3392 )
3393 .expect("handle removed");
3394
3395 let messages = sender_sink_member.take_messages();
3396 assert_eq!(messages.len(), 1);
3397 let SentMessage { message, group } = &messages[0];
3398 assert_eq!(group, &Some(ModernGroup(rtnetlink_groups_RTNLGRP_NEIGH)));
3399 assert_matches!(
3400 &message.payload,
3401 NetlinkPayload::InnerMessage(RouteNetlinkMessage::DelNeighbour(msg)) => {
3402 assert_eq!(msg.header.ifindex as u64, entry.interface.get());
3403 }
3404 );
3405 assert_eq!(sender_sink_non_member.take_messages().len(), 0);
3406 }
3407}