Skip to main content

netlink/
protocol_family.rs

1// Copyright 2023 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! A module for managing protocol-specific aspects of Netlink.
6
7pub mod sock_diag;
8
9use netlink_packet_core::{
10    NetlinkDeserializable, NetlinkMessage, NetlinkPayload, NetlinkSerializable,
11};
12use netlink_packet_utils::DecodeError;
13
14use std::fmt::Debug;
15use std::hash::Hash;
16use std::num::NonZeroU32;
17
18use crate::client::{AsyncWorkCompletionWaiter, ExternalClient, InternalClient};
19use crate::logging::{log_debug, log_warn};
20use crate::messaging::{MessageWithPermission, Sender};
21use crate::multicast_groups::{
22    InvalidLegacyGroupsError, InvalidModernGroupError, LegacyGroups, ModernGroup,
23    MulticastCapableNetlinkFamily,
24};
25use crate::route_tables::{NetlinkRouteTableIndex, NonZeroNetlinkRouteTableIndex};
26
27/// A type representing a named Netlink family.
28pub(crate) trait NamedNetlinkFamily {
29    const NAME: &'static str;
30}
31
32/// A type representing a Netlink Protocol Family.
33pub(crate) trait ProtocolFamily:
34    MulticastCapableNetlinkFamily + NamedNetlinkFamily + Send + Sized
35{
36    /// The request message type associated with the protocol family.
37    type Request: Clone
38        + Debug
39        + NetlinkDeserializable<Error: Into<DecodeError>>
40        + MessageWithPermission
41        + Send;
42
43    /// The response message type associated with the protocol family.
44    type Response: Clone + Debug + NetlinkSerializable + Send;
45
46    /// The implementation for handling requests from this protocol family.
47    type RequestHandler<S: Sender<Self::Response>>: NetlinkFamilyRequestHandler<Self, S>;
48
49    type NotifiedMulticastGroup: PartialEq + Eq + Hash + Clone + Copy + Debug + Send;
50
51    /// Family-specific async work to be passed through
52    /// [`crate::client::AsyncWorkItem`].
53    type AsyncWorkItem: Debug;
54
55    /// Returns `true` if we may need to notify the worker event loop in
56    /// response to a client joining or leaving the given `ModernGroup`.
57    fn should_notify_on_group_membership_change(
58        group: ModernGroup,
59    ) -> Option<Self::NotifiedMulticastGroup>;
60}
61
62/// A request handler implementation for a particular Netlink protocol family.
63pub(crate) trait NetlinkFamilyRequestHandler<F: ProtocolFamily, S: Sender<F::Response>>:
64    Clone + Send
65{
66    /// Handles the given request and generates the associated response(s).
67    async fn handle_request(
68        &mut self,
69        req: NetlinkMessage<F::Request>,
70        client: &mut InternalClient<F, S>,
71    );
72}
73
74/// A client of a Netlink protocol family.
75pub trait NetlinkClient: Send + Sync {
76    /// The request message type associated with this client's protocol family.
77    type Request: Clone
78        + Debug
79        + NetlinkDeserializable<Error: Into<DecodeError>>
80        + MessageWithPermission
81        + Send;
82
83    /// Sets the PID assigned to the client.
84    fn set_pid(&self, pid: NonZeroU32);
85
86    /// Adds the given multicast group membership.
87    fn add_membership(
88        &self,
89        group: ModernGroup,
90    ) -> Result<AsyncWorkCompletionWaiter, InvalidModernGroupError>;
91
92    /// Deletes the given multicast group membership.
93    fn del_membership(&self, group: ModernGroup) -> Result<(), InvalidModernGroupError>;
94
95    /// Sets the legacy multicast group memberships.
96    fn set_legacy_memberships(
97        &self,
98        legacy_memberships: LegacyGroups,
99    ) -> Result<AsyncWorkCompletionWaiter, InvalidLegacyGroupsError>;
100}
101
102pub mod route {
103    //! This module implements the Route Netlink Protocol Family.
104
105    use super::*;
106
107    use std::fmt::Display;
108    use std::num::NonZeroU64;
109
110    use fidl_fuchsia_net_routes_ext as fnet_routes_ext;
111
112    use either::Either;
113    use futures::channel::{mpsc, oneshot};
114    use futures::sink::SinkExt as _;
115    use linux_uapi::{
116        IFA_F_NOPREFIXROUTE, rt_class_t_RT_TABLE_COMPAT, rt_class_t_RT_TABLE_MAIN,
117        rtnetlink_groups_RTNLGRP_DCB, rtnetlink_groups_RTNLGRP_DECnet_IFADDR,
118        rtnetlink_groups_RTNLGRP_DECnet_ROUTE, rtnetlink_groups_RTNLGRP_DECnet_RULE,
119        rtnetlink_groups_RTNLGRP_IPV4_IFADDR, rtnetlink_groups_RTNLGRP_IPV4_MROUTE,
120        rtnetlink_groups_RTNLGRP_IPV4_MROUTE_R, rtnetlink_groups_RTNLGRP_IPV4_NETCONF,
121        rtnetlink_groups_RTNLGRP_IPV4_ROUTE, rtnetlink_groups_RTNLGRP_IPV4_RULE,
122        rtnetlink_groups_RTNLGRP_IPV6_IFADDR, rtnetlink_groups_RTNLGRP_IPV6_IFINFO,
123        rtnetlink_groups_RTNLGRP_IPV6_MROUTE, rtnetlink_groups_RTNLGRP_IPV6_MROUTE_R,
124        rtnetlink_groups_RTNLGRP_IPV6_NETCONF, rtnetlink_groups_RTNLGRP_IPV6_PREFIX,
125        rtnetlink_groups_RTNLGRP_IPV6_ROUTE, rtnetlink_groups_RTNLGRP_IPV6_RULE,
126        rtnetlink_groups_RTNLGRP_LINK, rtnetlink_groups_RTNLGRP_MDB,
127        rtnetlink_groups_RTNLGRP_MPLS_NETCONF, rtnetlink_groups_RTNLGRP_MPLS_ROUTE,
128        rtnetlink_groups_RTNLGRP_ND_USEROPT, rtnetlink_groups_RTNLGRP_NEIGH,
129        rtnetlink_groups_RTNLGRP_NONE, rtnetlink_groups_RTNLGRP_NOP2,
130        rtnetlink_groups_RTNLGRP_NOP4, rtnetlink_groups_RTNLGRP_NOTIFY,
131        rtnetlink_groups_RTNLGRP_NSID, rtnetlink_groups_RTNLGRP_PHONET_IFADDR,
132        rtnetlink_groups_RTNLGRP_PHONET_ROUTE, rtnetlink_groups_RTNLGRP_TC,
133    };
134    use net_types::SpecifiedAddr;
135    use net_types::ip::{
136        AddrSubnetEither, AddrSubnetError, Ip, IpAddr, IpInvariant, IpVersion, Ipv4, Ipv4Addr,
137        Ipv6, Ipv6Addr, Subnet,
138    };
139    use netlink_packet_route::address::{AddressAttribute, AddressMessage};
140    use netlink_packet_route::link::{InfoKind, LinkAttribute, LinkFlags, LinkInfo, LinkMessage};
141    use netlink_packet_route::route::{RouteAttribute, RouteMessage, RouteType};
142    use netlink_packet_route::{AddressFamily, RouteNetlinkMessage};
143
144    use crate::client::AsyncWorkCompletionWaiter;
145    use crate::interfaces::AcceptRaRtTable;
146    use crate::messaging::{MessageWithPermission, Permission};
147    use crate::multicast_groups::GroupSupport;
148    use crate::neighbors::{
149        DelNeighborArgs, GetNeighborArgs, NeighborRequestArgs, NewNeighborArgs,
150    };
151    use crate::netlink_packet::errno::Errno;
152    use crate::netlink_packet::{self, NetlinkRequestType};
153    use crate::route_eventloop::UnifiedRequest;
154    use crate::rules::{RuleRequest, RuleRequestArgs};
155    use crate::{SysctlError, SysctlInterfaceSelector, interfaces, neighbors, routes};
156
157    use netlink_packet_core::{NLM_F_ACK, NLM_F_DUMP, NLM_F_EXCL, NLM_F_REPLACE, NetlinkHeader};
158
159    /// An implementation of the Netlink Route protocol family.
160    pub(crate) enum NetlinkRoute {}
161
162    impl MulticastCapableNetlinkFamily for NetlinkRoute {
163        #[allow(non_upper_case_globals)]
164        fn check_support(
165            ModernGroup(group): &ModernGroup,
166        ) -> Result<GroupSupport, InvalidModernGroupError> {
167            match *group {
168                rtnetlink_groups_RTNLGRP_IPV4_IFADDR
169                | rtnetlink_groups_RTNLGRP_IPV4_ROUTE
170                | rtnetlink_groups_RTNLGRP_IPV6_IFADDR
171                | rtnetlink_groups_RTNLGRP_IPV6_ROUTE
172                | rtnetlink_groups_RTNLGRP_LINK
173                | rtnetlink_groups_RTNLGRP_ND_USEROPT
174                | rtnetlink_groups_RTNLGRP_NEIGH => Ok(GroupSupport::Supported),
175                rtnetlink_groups_RTNLGRP_DCB
176                | rtnetlink_groups_RTNLGRP_DECnet_IFADDR
177                | rtnetlink_groups_RTNLGRP_DECnet_ROUTE
178                | rtnetlink_groups_RTNLGRP_DECnet_RULE
179                | rtnetlink_groups_RTNLGRP_IPV4_MROUTE
180                | rtnetlink_groups_RTNLGRP_IPV4_MROUTE_R
181                | rtnetlink_groups_RTNLGRP_IPV4_NETCONF
182                | rtnetlink_groups_RTNLGRP_IPV4_RULE
183                | rtnetlink_groups_RTNLGRP_IPV6_IFINFO
184                | rtnetlink_groups_RTNLGRP_IPV6_MROUTE
185                | rtnetlink_groups_RTNLGRP_IPV6_MROUTE_R
186                | rtnetlink_groups_RTNLGRP_IPV6_NETCONF
187                | rtnetlink_groups_RTNLGRP_IPV6_PREFIX
188                | rtnetlink_groups_RTNLGRP_IPV6_RULE
189                | rtnetlink_groups_RTNLGRP_MDB
190                | rtnetlink_groups_RTNLGRP_MPLS_NETCONF
191                | rtnetlink_groups_RTNLGRP_MPLS_ROUTE
192                | rtnetlink_groups_RTNLGRP_NONE
193                | rtnetlink_groups_RTNLGRP_NOP2
194                | rtnetlink_groups_RTNLGRP_NOP4
195                | rtnetlink_groups_RTNLGRP_NOTIFY
196                | rtnetlink_groups_RTNLGRP_NSID
197                | rtnetlink_groups_RTNLGRP_PHONET_IFADDR
198                | rtnetlink_groups_RTNLGRP_PHONET_ROUTE
199                | rtnetlink_groups_RTNLGRP_TC => Ok(GroupSupport::Unsupported),
200                _ => Err(InvalidModernGroupError),
201            }
202        }
203    }
204
205    #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
206    pub(crate) enum NetlinkRouteNotifiedGroup {
207        Nduseropt,
208    }
209
210    impl MessageWithPermission for RouteNetlinkMessage {
211        fn permission(&self) -> Permission {
212            match self {
213                Self::GetLink(_)
214                | Self::GetAddress(_)
215                | Self::GetNeighbour(_)
216                | Self::GetNeighbourTable(_)
217                | Self::GetRoute(_)
218                | Self::GetQueueDiscipline(_)
219                | Self::GetTrafficClass(_)
220                | Self::GetTrafficFilter(_)
221                | Self::GetTrafficChain(_)
222                | Self::GetNsId(_)
223                | Self::GetRule(_) => Permission::NetlinkRouteRead,
224
225                Self::NewLink(_)
226                | Self::DelLink(_)
227                | Self::SetLink(_)
228                | Self::NewLinkProp(_)
229                | Self::DelLinkProp(_)
230                | Self::NewAddress(_)
231                | Self::DelAddress(_)
232                | Self::NewNeighbour(_)
233                | Self::DelNeighbour(_)
234                | Self::NewNeighbourTable(_)
235                | Self::SetNeighbourTable(_)
236                | Self::NewNeighbourDiscoveryUserOption(_)
237                | Self::NewRoute(_)
238                | Self::DelRoute(_)
239                | Self::NewPrefix(_)
240                | Self::NewQueueDiscipline(_)
241                | Self::DelQueueDiscipline(_)
242                | Self::NewTrafficClass(_)
243                | Self::DelTrafficClass(_)
244                | Self::NewTrafficFilter(_)
245                | Self::DelTrafficFilter(_)
246                | Self::NewTrafficChain(_)
247                | Self::DelTrafficChain(_)
248                | Self::NewNsId(_)
249                | Self::DelNsId(_)
250                | Self::NewRule(_)
251                | Self::DelRule(_) => Permission::NetlinkRouteWrite,
252            }
253        }
254    }
255
256    impl NamedNetlinkFamily for NetlinkRoute {
257        const NAME: &'static str = "NETLINK_ROUTE";
258    }
259
260    impl ProtocolFamily for NetlinkRoute {
261        type Request = RouteNetlinkMessage;
262        type Response = RouteNetlinkMessage;
263        type RequestHandler<S: Sender<Self::Response>> = NetlinkRouteRequestHandler<S>;
264        type NotifiedMulticastGroup = NetlinkRouteNotifiedGroup;
265        type AsyncWorkItem = RouteAsyncWork;
266
267        fn should_notify_on_group_membership_change(
268            group: ModernGroup,
269        ) -> Option<Self::NotifiedMulticastGroup> {
270            (group == ModernGroup(rtnetlink_groups_RTNLGRP_ND_USEROPT))
271                .then_some(NetlinkRouteNotifiedGroup::Nduseropt)
272        }
273    }
274
275    #[derive(Debug)]
276    pub(crate) enum RouteAsyncWork {
277        SetAcceptRaRtTable {
278            interface: SysctlInterfaceSelector,
279            value: AcceptRaRtTable,
280            responder: oneshot_sync::Sender<Result<(), SysctlError>>,
281        },
282        GetAcceptRaRtTable {
283            interface: SysctlInterfaceSelector,
284            responder: oneshot_sync::Sender<Result<AcceptRaRtTable, SysctlError>>,
285        },
286    }
287
288    #[derive(Clone)]
289    pub(crate) struct NetlinkRouteRequestHandler<S: Sender<RouteNetlinkMessage>> {
290        pub(crate) unified_request_sink: mpsc::Sender<UnifiedRequest<S>>,
291    }
292
293    struct ExtractedAddressRequest {
294        address_and_interface_id: interfaces::AddressAndInterfaceArgs,
295        addr_flags: u32,
296    }
297
298    fn extract_if_id_and_addr_from_addr_message(
299        message: &AddressMessage,
300        client: &impl Display,
301        req: &RouteNetlinkMessage,
302        // `true` for new address requests; `false` for delete address requests.
303        is_new: bool,
304    ) -> Result<Option<ExtractedAddressRequest>, Errno> {
305        let kind = if is_new { "new" } else { "del" };
306
307        let interface_id = match NonZeroU32::new(message.header.index.into()) {
308            Some(interface_id) => interface_id,
309            None => {
310                log_debug!(
311                    "unspecified interface ID in address {} request from {}: {:?}",
312                    kind,
313                    client,
314                    req,
315                );
316                return Err(Errno::EINVAL);
317            }
318        };
319
320        let mut address = None;
321        let mut local = None;
322        let mut addr_flags = None;
323        message.attributes.iter().for_each(|nla| match nla {
324            AddressAttribute::Address(a) => address = Some(a),
325            AddressAttribute::Local(l) => local = Some(l),
326            AddressAttribute::Flags(flags) => addr_flags = Some(*flags),
327            nla => {
328                log_warn!(
329                    "unexpected Address NLA in {} request from {}: {:?}; req = {:?}",
330                    kind,
331                    client,
332                    nla,
333                    req,
334                );
335            }
336        });
337
338        // Linux supports the notion of a "peer" address which is used for
339        // pointtopoint interfaces. Fuchsia does not support this so we do not
340        // allow different-valued `IFA_LOCAL` and `IFA_ADDRESS` values.
341        //
342        // Per https://www.man7.org/linux/man-pages/man8/ip-address.8.html,
343        //
344        //   ip address add - add new protocol address.
345        //       dev IFNAME
346        //            the name of the device to add the address to.
347        //
348        //       local ADDRESS (default)
349        //            the address of the interface. The format of the address
350        //            depends on the protocol. It is a dotted quad for IP and a
351        //            sequence of hexadecimal halfwords separated by colons for
352        //            IPv6. The ADDRESS may be followed by a slash and a decimal
353        //            number which encodes the network prefix length.
354        //
355        //       peer ADDRESS
356        //            the address of the remote endpoint for pointopoint
357        //            interfaces. Again, the ADDRESS may be followed by a slash
358        //            and a decimal number, encoding the network prefix length.
359        //            If a peer address is specified, the local address cannot
360        //            have a prefix length. The network prefix is associated
361        //            with the peer rather than with the local address.
362        //
363        //   ...
364        //
365        //   ip address delete - delete protocol address
366        //       Arguments: coincide with the arguments of ip addr add. The
367        //       device name is a required argument. The rest are optional. If
368        //       no arguments are given, the first address is deleted.
369        //
370        // Note that when only one of `IFA_LOCAL` or `IFA_ADDRESS` is included
371        // in a message, it is treated as the "local" address on the interface
372        // to be added/removed. When both are included, `IFA_LOCAL` is treated
373        // as the "local" address and `IFA_ADDRESS` is treated as the "peer".
374        // TODO(https://fxbug.dev/42079868): Support peer addresses.
375        let addr = match (local, address) {
376            (Some(local), Some(address)) => {
377                if local == address {
378                    address
379                } else {
380                    log_debug!(
381                        "got different `IFA_ADDRESS` and `IFA_LOCAL` values for {} address request from {}: {:?}",
382                        kind,
383                        client,
384                        req,
385                    );
386                    return Err(Errno::ENOTSUP);
387                }
388            }
389            (Some(addr), None) | (None, Some(addr)) => addr,
390            (None, None) => {
391                log_debug!(
392                    "missing `IFA_ADDRESS` and `IFA_LOCAL` in address {} request from {}: {:?}",
393                    kind,
394                    client,
395                    req,
396                );
397                return Err(Errno::EINVAL);
398            }
399        };
400
401        let addr = match message.header.family() {
402            AddressFamily::Inet => {
403                if addr.is_unspecified() {
404                    // Linux treats adding the unspecified IPv4 address as a
405                    // no-op.
406                    return Ok(None);
407                }
408                match addr {
409                    std::net::IpAddr::V4(v4) => IpAddr::V4(Ipv4Addr::new(v4.octets())),
410                    std::net::IpAddr::V6(_) => {
411                        log_debug!(
412                            "expected IPv4 address in new address request from {}: {:?}",
413                            client,
414                            req
415                        );
416                        return Err(Errno::EINVAL);
417                    }
418                }
419            }
420            AddressFamily::Inet6 => {
421                if addr.is_unspecified() {
422                    // Linux returns this error when adding the unspecified IPv6
423                    // address.
424                    return Err(Errno::EADDRNOTAVAIL);
425                }
426                match addr {
427                    std::net::IpAddr::V4(_) => {
428                        log_debug!(
429                            "expected IPv6 address in new address request from {}: {:?}",
430                            client,
431                            req
432                        );
433                        return Err(Errno::EINVAL);
434                    }
435                    std::net::IpAddr::V6(v6) => IpAddr::V6(Ipv6Addr::new(v6.segments())),
436                }
437            }
438            family => {
439                log_debug!(
440                    "invalid address family ({:?}) in new address \
441                    request from {}: {:?}",
442                    family,
443                    client,
444                    req
445                );
446                return Err(Errno::EINVAL);
447            }
448        };
449
450        let address = match AddrSubnetEither::new(addr, message.header.prefix_len) {
451            Ok(address) => address,
452            Err(
453                AddrSubnetError::PrefixTooLong
454                | AddrSubnetError::NotUnicastInSubnet
455                | AddrSubnetError::InvalidWitness,
456            ) => {
457                log_debug!(
458                    "invalid address in address {} request from {}: {:?}",
459                    kind,
460                    client,
461                    req
462                );
463                return Err(Errno::EINVAL);
464            }
465        };
466
467        Ok(Some(ExtractedAddressRequest {
468            address_and_interface_id: interfaces::AddressAndInterfaceArgs { address, interface_id },
469            addr_flags: addr_flags
470                .map(|value| value.bits())
471                .unwrap_or_else(|| message.header.flags.into()),
472        }))
473    }
474
475    /// Constructs the appropriate [`GetLinkArgs`] for this GetLink request.
476    fn to_get_link_args(
477        link_msg: LinkMessage,
478        is_dump: bool,
479    ) -> Result<interfaces::GetLinkArgs, Errno> {
480        // NB: In the case where the request is "malformed" and specifies
481        // multiple fields, Linux prefers the dump flag over the link index, and
482        // prefers the link index over the link_name.
483        if is_dump {
484            return Ok(interfaces::GetLinkArgs::Dump);
485        }
486        if let Ok(link_id) = <u32 as TryInto<NonZeroU32>>::try_into(link_msg.header.index) {
487            return Ok(interfaces::GetLinkArgs::Get(interfaces::LinkSpecifier::Index(link_id)));
488        }
489        if let Some(name) = link_msg.attributes.into_iter().find_map(|nla| match nla {
490            LinkAttribute::IfName(name) => Some(name),
491            nla => {
492                log_debug!("ignoring unexpected NLA in GetLink request: {:?}", nla);
493                None
494            }
495        }) {
496            return Ok(interfaces::GetLinkArgs::Get(interfaces::LinkSpecifier::Name(name)));
497        }
498        return Err(Errno::EINVAL);
499    }
500
501    /// Constructs the appropriate [`SetLinkArgs`] for this SetLink request.
502    fn to_set_link_args(link_msg: LinkMessage) -> Result<interfaces::SetLinkArgs, Errno> {
503        let link_id = NonZeroU32::new(link_msg.header.index);
504        let link_name = link_msg.attributes.into_iter().find_map(|nla| match nla {
505            LinkAttribute::IfName(name) => Some(name),
506            nla => {
507                log_debug!("ignoring unexpected NLA in SetLink request: {:?}", nla);
508                None
509            }
510        });
511        let link = match (link_id, link_name) {
512            (Some(id), None) => interfaces::LinkSpecifier::Index(id),
513            (None, Some(name)) => interfaces::LinkSpecifier::Name(name),
514            (None, None) => return Err(Errno::EINVAL),
515            // NB: If both the index and name are specified, Linux returns EBUSY
516            // rather than EINVAL. Do the same here for conformance.
517            (Some(_id), Some(_name)) => return Err(Errno::EBUSY),
518        };
519        // `change_mask` specifies which flags should be updated, while `flags`
520        // specifies whether the value should be set/unset.
521        let enable: Option<bool> = ((link_msg.header.change_mask & LinkFlags::Up) == LinkFlags::Up)
522            .then_some((link_msg.header.flags & LinkFlags::Up) != LinkFlags::empty());
523
524        let unsupported_changes = link_msg.header.change_mask & !LinkFlags::Up;
525        if unsupported_changes != LinkFlags::empty() {
526            log_warn!(
527                "ignoring unsupported changes in SetLink request: {:#X}",
528                unsupported_changes
529            );
530        }
531
532        Ok(interfaces::SetLinkArgs { link, enable })
533    }
534
535    #[derive(Debug)]
536    enum ExtractedRouteRequest<I: Ip> {
537        // A gateway or direct route.
538        Unicast(ExtractedUnicastRouteRequest<I>),
539    }
540    /// Route request information from a route of type `RTN_UNICAST`.
541    /// Fields other than subnet marked as optional to allow for translation
542    /// to [`UnicastRouteArgs`] and [`UnicastDelRouteArgs`].
543    #[derive(Debug)]
544    struct ExtractedUnicastRouteRequest<I: Ip> {
545        subnet: Subnet<I::Addr>,
546        outbound_interface: Option<NonZeroU64>,
547        next_hop: Option<SpecifiedAddr<I::Addr>>,
548        priority: Option<NonZeroU32>,
549        table: NonZeroNetlinkRouteTableIndex,
550    }
551
552    // Extracts unicast route information from a request.
553    // Returns an error if the request is malformed. This error
554    // should be returned to the client.
555    fn extract_data_from_unicast_route_message<I: Ip>(
556        message: &RouteMessage,
557        client: &impl Display,
558        req: &RouteNetlinkMessage,
559        kind: &str,
560    ) -> Result<ExtractedRouteRequest<I>, Errno> {
561        let destination_prefix_len = message.header.destination_prefix_length;
562        let mut table: NetlinkRouteTableIndex =
563            NetlinkRouteTableIndex::new(message.header.table.into());
564
565        let mut destination_addr = None;
566        let mut outbound_interface = None;
567        let mut next_hop_addr = None;
568        let mut priority = None;
569        message.attributes.iter().for_each(|nla| match nla {
570            RouteAttribute::Destination(addr) => destination_addr = Some(addr),
571            RouteAttribute::Oif(id) => outbound_interface = Some(id),
572            RouteAttribute::Gateway(addr) => next_hop_addr = Some(addr),
573            RouteAttribute::Priority(num) => priority = Some(*num),
574            RouteAttribute::Table(num) => {
575                // When the table is set to `RT_TABLE_COMPAT`, the table id is greater than
576                // `u8::MAX` and cannot be represented in the header u8. The actual table
577                // number is stored in the `RTA_TABLE` NLA.
578                // We expect to see the NLA if the value in the header is `RT_TABLE_COMPAT`,
579                // although we will use it if it is present, regardless of if `RT_TABLE_COMPAT`
580                // is specified.
581                if message.header.table != rt_class_t_RT_TABLE_COMPAT as u8 {
582                    log_debug!(
583                        "`RTA_TABLE` is expected only when table in header is `RT_TABLE_COMPAT`, \
584                        but it was {}. Using provided value of {} in the NLA",
585                        message.header.table,
586                        num
587                    );
588                }
589                table = NetlinkRouteTableIndex::new(*num)
590            }
591            nla => {
592                log_warn!(
593                    "ignoring unexpected Route NLA in {} request from {}: {:?}; req = {:?}",
594                    kind,
595                    client,
596                    nla,
597                    req,
598                );
599            }
600        });
601
602        let outbound_interface =
603            outbound_interface.map(|id| NonZeroU64::new((*id).into())).flatten();
604        let priority = priority.map(NonZeroU32::new).flatten();
605        let table = NonZeroNetlinkRouteTableIndex::new(table).unwrap_or_else(|| {
606            NonZeroNetlinkRouteTableIndex::new_non_zero(
607                NonZeroU32::new(rt_class_t_RT_TABLE_MAIN.into()).unwrap(),
608            )
609        });
610        let destination_addr = match destination_addr {
611            Some(addr) => crate::netlink_packet::ip_addr_from_route::<I>(addr)?,
612            None => {
613                // Use the unspecified address if there wasn't a destination NLA present
614                // and the prefix len is 0.
615                if destination_prefix_len != 0 {
616                    log_warn!(
617                        "rejecting route {} request with prefix length {} and missing `RTA_DST` \
618                    from {}: {:?}",
619                        kind,
620                        destination_prefix_len,
621                        client,
622                        req
623                    );
624                    return Err(Errno::EINVAL);
625                }
626                I::UNSPECIFIED_ADDRESS
627            }
628        };
629
630        let next_hop = match next_hop_addr {
631            Some(addr) => {
632                // Linux ignores the provided nexthop if it is the default route. To conform
633                // to Linux expectations, `SpecifiedAddr::new()` becomes `None` when the addr
634                // is unspecified.
635                crate::netlink_packet::ip_addr_from_route::<I>(addr).map(SpecifiedAddr::new)?
636            }
637            None => None,
638        };
639
640        let extracted_route_request = match Subnet::new(destination_addr, destination_prefix_len) {
641            Ok(subnet) => ExtractedRouteRequest::Unicast(ExtractedUnicastRouteRequest {
642                subnet,
643                outbound_interface,
644                next_hop,
645                priority,
646                table,
647            }),
648            Err(e) => {
649                log_warn!(
650                    "{:?} subnet ({}) in route {} request from {}: {:?}",
651                    e,
652                    destination_addr,
653                    kind,
654                    client,
655                    req,
656                );
657                return Err(Errno::EINVAL);
658            }
659        };
660
661        Ok(extracted_route_request)
662    }
663
664    // Translates `RouteMessage` to `RouteRequestArgs::New`.
665    //
666    // `RouteRequestArgs::New` requires all fields except for next_hop, so optional
667    // fields from `ExtractedRouteRequest` are converted to the defaults expected
668    // by Netstack.
669    fn to_new_route_args<I: Ip>(
670        message: &RouteMessage,
671        client: &impl Display,
672        req: &RouteNetlinkMessage,
673    ) -> Result<routes::RouteRequestArgs<I>, Errno> {
674        let extracted_request =
675            extract_data_from_unicast_route_message::<I>(message, client, req, "new")?;
676
677        let ExtractedRouteRequest::Unicast(ExtractedUnicastRouteRequest {
678            subnet,
679            outbound_interface,
680            next_hop,
681            priority,
682            table,
683        }) = extracted_request;
684
685        let outbound_interface = outbound_interface.map(NonZeroU64::get).ok_or_else(|| {
686            // TODO(https://issues.fuchsia.dev/292103361): Resolve destination
687            // IP to find interface index if it is not provided explicitly.
688            log_warn!(
689                "unsupported request: missing `RTA_OIF` in new route request from {}: {:?}",
690                client,
691                req
692            );
693            Errno::ENOTSUP
694        })?;
695
696        Ok(routes::RouteRequestArgs::New(routes::NewRouteArgs::Unicast(
697            routes::UnicastNewRouteArgs {
698                subnet,
699                target: fnet_routes_ext::RouteTarget { outbound_interface, next_hop },
700                priority,
701                table: table.into(),
702            },
703        )))
704    }
705
706    // Translates `RouteMessage` to `RouteRequestArgs::Del`.
707    fn to_del_route_args<I: Ip>(
708        message: &RouteMessage,
709        client: &impl Display,
710        req: &RouteNetlinkMessage,
711    ) -> Result<routes::RouteRequestArgs<I>, Errno> {
712        let extracted_request =
713            extract_data_from_unicast_route_message::<I>(message, client, req, "del")?;
714
715        let ExtractedRouteRequest::Unicast(ExtractedUnicastRouteRequest {
716            subnet,
717            outbound_interface,
718            next_hop,
719            priority,
720            table,
721        }) = extracted_request;
722
723        Ok(routes::RouteRequestArgs::Del(routes::DelRouteArgs::Unicast(
724            routes::UnicastDelRouteArgs { subnet, outbound_interface, next_hop, priority, table },
725        )))
726    }
727
728    impl From<&RouteNetlinkMessage> for NetlinkRequestType {
729        fn from(message: &RouteNetlinkMessage) -> NetlinkRequestType {
730            match message {
731                RouteNetlinkMessage::GetLink(_)
732                | RouteNetlinkMessage::GetAddress(_)
733                | RouteNetlinkMessage::GetNeighbour(_)
734                | RouteNetlinkMessage::GetNeighbourTable(_)
735                | RouteNetlinkMessage::GetRoute(_)
736                | RouteNetlinkMessage::GetQueueDiscipline(_)
737                | RouteNetlinkMessage::GetTrafficClass(_)
738                | RouteNetlinkMessage::GetTrafficFilter(_)
739                | RouteNetlinkMessage::GetTrafficChain(_)
740                | RouteNetlinkMessage::GetNsId(_)
741                | RouteNetlinkMessage::GetRule(_) => Self::Get,
742
743                RouteNetlinkMessage::NewLink(_)
744                | RouteNetlinkMessage::NewLinkProp(_)
745                | RouteNetlinkMessage::NewAddress(_)
746                | RouteNetlinkMessage::NewNeighbour(_)
747                | RouteNetlinkMessage::NewNeighbourTable(_)
748                | RouteNetlinkMessage::NewNeighbourDiscoveryUserOption(_)
749                | RouteNetlinkMessage::NewRoute(_)
750                | RouteNetlinkMessage::NewPrefix(_)
751                | RouteNetlinkMessage::NewQueueDiscipline(_)
752                | RouteNetlinkMessage::NewTrafficClass(_)
753                | RouteNetlinkMessage::NewTrafficFilter(_)
754                | RouteNetlinkMessage::NewTrafficChain(_)
755                | RouteNetlinkMessage::NewNsId(_)
756                | RouteNetlinkMessage::NewRule(_) => Self::New,
757
758                RouteNetlinkMessage::SetLink(_) | RouteNetlinkMessage::SetNeighbourTable(_) => {
759                    Self::Set
760                }
761
762                RouteNetlinkMessage::DelLink(_)
763                | RouteNetlinkMessage::DelLinkProp(_)
764                | RouteNetlinkMessage::DelAddress(_)
765                | RouteNetlinkMessage::DelNeighbour(_)
766                | RouteNetlinkMessage::DelRoute(_)
767                | RouteNetlinkMessage::DelQueueDiscipline(_)
768                | RouteNetlinkMessage::DelTrafficClass(_)
769                | RouteNetlinkMessage::DelTrafficFilter(_)
770                | RouteNetlinkMessage::DelTrafficChain(_)
771                | RouteNetlinkMessage::DelNsId(_)
772                | RouteNetlinkMessage::DelRule(_) => Self::Del,
773            }
774        }
775    }
776
777    impl<S: Sender<RouteNetlinkMessage>> NetlinkFamilyRequestHandler<NetlinkRoute, S>
778        for NetlinkRouteRequestHandler<S>
779    {
780        async fn handle_request(
781            &mut self,
782            req: NetlinkMessage<RouteNetlinkMessage>,
783            client: &mut InternalClient<NetlinkRoute, S>,
784        ) {
785            let Self { unified_request_sink } = self;
786
787            let (req_header, payload) = req.into_parts();
788            let req = match payload {
789                NetlinkPayload::InnerMessage(p) => p,
790                p => {
791                    log_warn!(
792                        "Ignoring request from client {} with unexpected payload: {:?}",
793                        client,
794                        p
795                    );
796                    return;
797                }
798            };
799
800            let is_dump = req_header.flags & NLM_F_DUMP == NLM_F_DUMP;
801            let is_replace = req_header.flags & NLM_F_REPLACE == NLM_F_REPLACE;
802            let is_excl = req_header.flags & NLM_F_EXCL == NLM_F_EXCL;
803            let expects_ack = req_header.flags & NLM_F_ACK == NLM_F_ACK;
804
805            use RouteNetlinkMessage::*;
806            match req {
807                GetLink(link_msg) => {
808                    let (completer, waiter) = oneshot::channel();
809                    let args = match to_get_link_args(link_msg, is_dump) {
810                        Ok(args) => args,
811                        Err(e) => {
812                            log_debug!("received invalid `GetLink` request from {}", client);
813                            client.send_unicast(netlink_packet::new_error(Err(e), req_header));
814                            return;
815                        }
816                    };
817                    unified_request_sink
818                        .send(UnifiedRequest::InterfacesRequest(interfaces::Request {
819                            args: interfaces::RequestArgs::Link(interfaces::LinkRequestArgs::Get(
820                                args,
821                            )),
822                            sequence_number: req_header.sequence_number,
823                            client: client.clone(),
824                            completer,
825                        }))
826                        .await
827                        .expect("interface event loop should never terminate");
828                    match waiter
829                        .await
830                        .expect("interfaces event loop should have handled the request")
831                    {
832                        Ok(()) => {
833                            if is_dump {
834                                client.send_unicast(netlink_packet::new_done(req_header))
835                            } else if expects_ack {
836                                client.send_unicast(netlink_packet::new_error(Ok(()), req_header))
837                            }
838                        }
839                        Err(e) => client.send_unicast(netlink_packet::new_error(
840                            Err(e.into_errno()),
841                            req_header,
842                        )),
843                    }
844                }
845                SetLink(link_msg) => {
846                    let args = match to_set_link_args(link_msg) {
847                        Ok(args) => args,
848                        Err(e) => {
849                            log_debug!("received invalid `SetLink` request from {}", client);
850                            client.send_unicast(netlink_packet::new_error(Err(e), req_header));
851                            return;
852                        }
853                    };
854                    let (completer, waiter) = oneshot::channel();
855                    unified_request_sink
856                        .send(UnifiedRequest::InterfacesRequest(interfaces::Request {
857                            args: interfaces::RequestArgs::Link(interfaces::LinkRequestArgs::Set(
858                                args,
859                            )),
860                            sequence_number: req_header.sequence_number,
861                            client: client.clone(),
862                            completer,
863                        }))
864                        .await
865                        .expect("interface event loop should never terminate");
866                    match waiter
867                        .await
868                        .expect("interfaces event loop should have handled the request")
869                    {
870                        Ok(()) => {
871                            if expects_ack {
872                                client.send_unicast(netlink_packet::new_error(Ok(()), req_header))
873                            }
874                        }
875                        Err(e) => client.send_unicast(netlink_packet::new_error(
876                            Err(e.into_errno()),
877                            req_header,
878                        )),
879                    }
880                }
881                NewLink(ref link_msg) => {
882                    let kind = link_msg
883                        .attributes
884                        .iter()
885                        .flat_map(|attr| match attr {
886                            LinkAttribute::LinkInfo(info) => info.iter(),
887                            _ => [].iter(),
888                        })
889                        .find_map(|info| match info {
890                            LinkInfo::Kind(kind) => Some(kind),
891                            _ => None,
892                        });
893                    match kind {
894                        Some(InfoKind::Xfrm) => {
895                            // Only log if the link type is one we haven't
896                            // already seen in the wild.
897                        }
898                        Some(_) | None => log_warn!(
899                            "Received RTM_NEWLINK request with unsupported link type {kind:?}"
900                        ),
901                    }
902                    client.send_unicast(netlink_packet::new_error(Err(Errno::ENOTSUP), req_header));
903                }
904                DelLink(_) => {
905                    client.send_unicast(netlink_packet::new_error(Err(Errno::ENOTSUP), req_header));
906                }
907                GetAddress(ref message) if is_dump => {
908                    let ip_version_filter = match message.header.family() {
909                        AddressFamily::Unspec => None,
910                        AddressFamily::Inet => Some(IpVersion::V4),
911                        AddressFamily::Inet6 => Some(IpVersion::V6),
912                        family => {
913                            log_debug!(
914                                "invalid address family ({:?}) in address dump request from {}: {:?}",
915                                family,
916                                client,
917                                req,
918                            );
919                            client.send_unicast(netlink_packet::new_error(
920                                Err(Errno::EINVAL),
921                                req_header,
922                            ));
923                            return;
924                        }
925                    };
926
927                    let (completer, waiter) = oneshot::channel();
928                    unified_request_sink
929                        .send(UnifiedRequest::InterfacesRequest(interfaces::Request {
930                            args: interfaces::RequestArgs::Address(
931                                interfaces::AddressRequestArgs::Get(
932                                    interfaces::GetAddressArgs::Dump { ip_version_filter },
933                                ),
934                            ),
935                            sequence_number: req_header.sequence_number,
936                            client: client.clone(),
937                            completer,
938                        }))
939                        .await
940                        .expect("interface event loop should never terminate");
941                    waiter
942                        .await
943                        .expect("interfaces event loop should have handled the request")
944                        .expect("addr dump requests are infallible");
945                    client.send_unicast(netlink_packet::new_done(req_header))
946                }
947                NewAddress(ref message) => {
948                    let extracted_request =
949                        match extract_if_id_and_addr_from_addr_message(message, client, &req, true)
950                        {
951                            Ok(o) => o,
952                            Err(e) => {
953                                return client
954                                    .send_unicast(netlink_packet::new_error(Err(e), req_header));
955                            }
956                        };
957                    let result = if let Some(ExtractedAddressRequest {
958                        address_and_interface_id,
959                        addr_flags,
960                    }) = extracted_request
961                    {
962                        let (completer, waiter) = oneshot::channel();
963                        let requested_subnet_route =
964                            addr_flags & IFA_F_NOPREFIXROUTE != IFA_F_NOPREFIXROUTE;
965                        // Linux doesn't add subnet routes for /0 and /32 IPv4 addresses.
966                        let can_add_subnet_route = match address_and_interface_id.address {
967                            AddrSubnetEither::V4(addr_subnet) => {
968                                let prefix = addr_subnet.subnet().prefix();
969                                prefix != 0 && prefix != 32
970                            }
971                            AddrSubnetEither::V6(_addr_subnet) => true,
972                        };
973                        let add_subnet_route = requested_subnet_route && can_add_subnet_route;
974                        unified_request_sink
975                            .send(UnifiedRequest::InterfacesRequest(interfaces::Request {
976                                args: interfaces::RequestArgs::Address(
977                                    interfaces::AddressRequestArgs::New(
978                                        interfaces::NewAddressArgs {
979                                            address_and_interface_id,
980                                            add_subnet_route,
981                                            replace: is_replace && !is_excl,
982                                        },
983                                    ),
984                                ),
985                                sequence_number: req_header.sequence_number,
986                                client: client.clone(),
987                                completer,
988                            }))
989                            .await
990                            .expect("interface event loop should never terminate");
991                        waiter.await.expect("interfaces event loop should have handled the request")
992                    } else {
993                        Ok(())
994                    };
995
996                    match result {
997                        Ok(()) => {
998                            if expects_ack {
999                                client.send_unicast(netlink_packet::new_error(Ok(()), req_header))
1000                            }
1001                        }
1002                        Err(e) => client.send_unicast(netlink_packet::new_error(
1003                            Err(e.into_errno()),
1004                            req_header,
1005                        )),
1006                    }
1007                }
1008                DelAddress(ref message) => {
1009                    let extracted_request = match extract_if_id_and_addr_from_addr_message(
1010                        message, client, &req, false,
1011                    ) {
1012                        Ok(o) => o,
1013                        Err(e) => {
1014                            return client
1015                                .send_unicast(netlink_packet::new_error(Err(e), req_header));
1016                        }
1017                    };
1018
1019                    let result = if let Some(ExtractedAddressRequest {
1020                        address_and_interface_id,
1021                        addr_flags: _,
1022                    }) = extracted_request
1023                    {
1024                        let (completer, waiter) = oneshot::channel();
1025                        unified_request_sink
1026                            .send(UnifiedRequest::InterfacesRequest(interfaces::Request {
1027                                args: interfaces::RequestArgs::Address(
1028                                    interfaces::AddressRequestArgs::Del(
1029                                        interfaces::DelAddressArgs { address_and_interface_id },
1030                                    ),
1031                                ),
1032                                sequence_number: req_header.sequence_number,
1033                                client: client.clone(),
1034                                completer,
1035                            }))
1036                            .await
1037                            .expect("interface event loop should never terminate");
1038                        waiter.await.expect("interfaces event loop should have handled the request")
1039                    } else {
1040                        Ok(())
1041                    };
1042                    match result {
1043                        Ok(()) => {
1044                            if expects_ack {
1045                                client.send_unicast(netlink_packet::new_error(Ok(()), req_header))
1046                            }
1047                        }
1048                        Err(e) => client.send_unicast(netlink_packet::new_error(
1049                            Err(e.into_errno()),
1050                            req_header,
1051                        )),
1052                    }
1053                }
1054                // Non-dump GetRoute is not currently necessary for our use.
1055                GetRoute(ref message) if is_dump => {
1056                    match message.header.address_family {
1057                        AddressFamily::Unspec => {
1058                            // V4 routes are requested prior to V6 routes to conform
1059                            // with `ip list` output.
1060                            process_routes_worker_request::<_, Ipv4>(
1061                                unified_request_sink,
1062                                client,
1063                                req_header,
1064                                routes::RouteRequestArgs::Get(routes::GetRouteArgs::Dump),
1065                            )
1066                            .await
1067                            .expect("route dump requests are infallible");
1068                            process_routes_worker_request::<_, Ipv6>(
1069                                unified_request_sink,
1070                                client,
1071                                req_header,
1072                                routes::RouteRequestArgs::Get(routes::GetRouteArgs::Dump),
1073                            )
1074                            .await
1075                            .expect("route dump requests are infallible");
1076                        }
1077                        AddressFamily::Inet => {
1078                            process_routes_worker_request::<_, Ipv4>(
1079                                unified_request_sink,
1080                                client,
1081                                req_header,
1082                                routes::RouteRequestArgs::Get(routes::GetRouteArgs::Dump),
1083                            )
1084                            .await
1085                            .expect("route dump requests are infallible");
1086                        }
1087                        AddressFamily::Inet6 => {
1088                            process_routes_worker_request::<_, Ipv6>(
1089                                unified_request_sink,
1090                                client,
1091                                req_header,
1092                                routes::RouteRequestArgs::Get(routes::GetRouteArgs::Dump),
1093                            )
1094                            .await
1095                            .expect("route dump requests are infallible");
1096                        }
1097                        family => {
1098                            log_debug!(
1099                                "invalid address family ({:?}) in route dump request from {}: {:?}",
1100                                family,
1101                                client,
1102                                req
1103                            );
1104                            client.send_unicast(netlink_packet::new_error(
1105                                Err(Errno::EINVAL),
1106                                req_header,
1107                            ));
1108                            return;
1109                        }
1110                    };
1111
1112                    client.send_unicast(netlink_packet::new_done(req_header))
1113                }
1114                GetRule(msg) => {
1115                    if !is_dump {
1116                        client.send_unicast(netlink_packet::new_error(
1117                            Err(Errno::ENOTSUP),
1118                            req_header,
1119                        ));
1120                        return;
1121                    }
1122                    let ip_versions = match msg.header.family {
1123                        AddressFamily::Inet => Either::Left(std::iter::once(IpVersion::V4)),
1124                        AddressFamily::Inet6 => Either::Left(std::iter::once(IpVersion::V6)),
1125                        AddressFamily::Unspec => {
1126                            Either::Right([IpVersion::V4, IpVersion::V6].into_iter())
1127                        }
1128                        family => {
1129                            client.send_unicast(netlink_packet::new_error(
1130                                Err(Errno::EAFNOSUPPORT),
1131                                req_header,
1132                            ));
1133                            log_debug!(
1134                                "received RTM_GETRULE req from {} with invalid address \
1135                                family ({:?}): {:?}",
1136                                client,
1137                                family,
1138                                msg
1139                            );
1140                            return;
1141                        }
1142                    };
1143                    for ip_version in ip_versions.into_iter() {
1144                        let (completer, receiver) = oneshot::channel();
1145                        net_types::for_any_ip_version!(ip_version, I, {
1146                            unified_request_sink
1147                                .send(UnifiedRequest::rule_request::<I>(
1148                                    RuleRequest {
1149                                        args: RuleRequestArgs::DumpRules,
1150                                        _ip_version_marker: <I as Ip>::VERSION_MARKER,
1151                                        sequence_number: req_header.sequence_number,
1152                                        client: client.clone(),
1153                                    },
1154                                    completer,
1155                                ))
1156                                .await
1157                                .expect("event loop should never terminate");
1158                        });
1159
1160                        match receiver.await.expect("completer should not be dropped") {
1161                            Ok(()) => {}
1162                            Err(e) => {
1163                                client.send_unicast(netlink_packet::new_error(Err(e), req_header));
1164                                return;
1165                            }
1166                        }
1167                    }
1168                    client.send_unicast(netlink_packet::new_done(req_header))
1169                }
1170                NewRule(msg) => {
1171                    if is_replace {
1172                        log_warn!("unimplemented: RTM_NEWRULE requests with NLM_F_REPLACE set.");
1173                        client.send_unicast(netlink_packet::new_error(
1174                            Err(Errno::ENOTSUP),
1175                            req_header,
1176                        ));
1177                        return;
1178                    }
1179                    let ip_version = match msg.header.family {
1180                        AddressFamily::Inet => IpVersion::V4,
1181                        AddressFamily::Inet6 => IpVersion::V6,
1182                        family => {
1183                            log_debug!(
1184                                "received RTM_NEWRULE req from {} with invalid address \
1185                                family ({:?}): {:?}",
1186                                client,
1187                                family,
1188                                msg
1189                            );
1190                            client.send_unicast(netlink_packet::new_error(
1191                                Err(Errno::EAFNOSUPPORT),
1192                                req_header,
1193                            ));
1194                            return;
1195                        }
1196                    };
1197                    let (completer, receiver) = oneshot::channel();
1198                    net_types::for_any_ip_version!(ip_version, I, {
1199                        let request = RuleRequest {
1200                            args: RuleRequestArgs::New(msg),
1201                            _ip_version_marker: <I as Ip>::VERSION_MARKER,
1202                            sequence_number: req_header.sequence_number,
1203                            client: client.clone(),
1204                        };
1205                        unified_request_sink
1206                            .send(UnifiedRequest::rule_request::<I>(request, completer))
1207                            .await
1208                            .expect("event loop should never terminate");
1209                    });
1210                    match receiver.await.expect("completer should not be dropped") {
1211                        Ok(()) => {
1212                            if expects_ack {
1213                                client.send_unicast(netlink_packet::new_error(Ok(()), req_header))
1214                            }
1215                        }
1216                        Err(e) => {
1217                            client.send_unicast(netlink_packet::new_error(Err(e), req_header));
1218                        }
1219                    }
1220                }
1221                DelRule(msg) => {
1222                    let ip_version = match msg.header.family {
1223                        AddressFamily::Inet => IpVersion::V4,
1224                        AddressFamily::Inet6 => IpVersion::V6,
1225                        family => {
1226                            log_debug!(
1227                                "received RTM_DELRULE req from {} with invalid address \
1228                                family ({:?}): {:?}",
1229                                client,
1230                                family,
1231                                msg
1232                            );
1233                            client.send_unicast(netlink_packet::new_error(
1234                                Err(Errno::EAFNOSUPPORT),
1235                                req_header,
1236                            ));
1237                            return;
1238                        }
1239                    };
1240                    let (completer, receiver) = oneshot::channel();
1241                    net_types::for_any_ip_version!(ip_version, I, {
1242                        let request = RuleRequest {
1243                            args: RuleRequestArgs::Del(msg),
1244                            _ip_version_marker: <I as Ip>::VERSION_MARKER,
1245                            sequence_number: req_header.sequence_number,
1246                            client: client.clone(),
1247                        };
1248                        unified_request_sink
1249                            .send(UnifiedRequest::rule_request::<I>(request, completer))
1250                            .await
1251                            .expect("event loop should never terminate");
1252                    });
1253                    match receiver.await.expect("completer should not be dropped") {
1254                        Ok(()) => {
1255                            if expects_ack {
1256                                client.send_unicast(netlink_packet::new_error(Ok(()), req_header))
1257                            }
1258                        }
1259                        Err(e) => {
1260                            client.send_unicast(netlink_packet::new_error(Err(e), req_header));
1261                        }
1262                    }
1263                }
1264                NewRoute(ref message) => {
1265                    // TODO(https://issues.fuchsia.dev/290803327): Emulate REPLACE by
1266                    // dispatching a delete then add request to Netstack.
1267                    let is_replace = req_header.flags & NLM_F_REPLACE == NLM_F_REPLACE;
1268                    if is_replace {
1269                        log_warn!(
1270                            "unsupported request type: NLM_F_REPLACE flag present in new \
1271                            route request from {}: {:?}",
1272                            client,
1273                            req
1274                        );
1275                        client.send_unicast(netlink_packet::new_error(
1276                            Err(Errno::ENOTSUP),
1277                            req_header,
1278                        ));
1279                        return;
1280                    }
1281
1282                    if message.header.kind != RouteType::Unicast {
1283                        log_warn!(
1284                            "unsupported request type: {:?} route present in new route \
1285                            request from {}: {:?}, only `RTN_UNICAST` is supported",
1286                            message.header.kind,
1287                            client,
1288                            req
1289                        );
1290                        client.send_unicast(netlink_packet::new_error(
1291                            Err(Errno::ENOTSUP),
1292                            req_header,
1293                        ));
1294                        return;
1295                    }
1296
1297                    let result = match message.header.address_family {
1298                        AddressFamily::Inet => {
1299                            match to_new_route_args::<Ipv4>(message, client, &req) {
1300                                Ok(req) => {
1301                                    process_routes_worker_request::<_, Ipv4>(
1302                                        unified_request_sink,
1303                                        client,
1304                                        req_header,
1305                                        req,
1306                                    )
1307                                    .await
1308                                }
1309                                Err(e) => {
1310                                    return client.send_unicast(netlink_packet::new_error(
1311                                        Err(e),
1312                                        req_header,
1313                                    ));
1314                                }
1315                            }
1316                        }
1317                        AddressFamily::Inet6 => {
1318                            match to_new_route_args::<Ipv6>(message, client, &req) {
1319                                Ok(req) => {
1320                                    process_routes_worker_request::<_, Ipv6>(
1321                                        unified_request_sink,
1322                                        client,
1323                                        req_header,
1324                                        req,
1325                                    )
1326                                    .await
1327                                }
1328                                Err(e) => {
1329                                    return client.send_unicast(netlink_packet::new_error(
1330                                        Err(e),
1331                                        req_header,
1332                                    ));
1333                                }
1334                            }
1335                        }
1336                        family => {
1337                            log_debug!(
1338                                "invalid address family ({:?}) in new route \
1339                                request from {}: {:?}",
1340                                family,
1341                                client,
1342                                req
1343                            );
1344                            return client.send_unicast(netlink_packet::new_error(
1345                                Err(Errno::EINVAL),
1346                                req_header,
1347                            ));
1348                        }
1349                    };
1350
1351                    match result {
1352                        Ok(()) => {
1353                            if expects_ack {
1354                                client.send_unicast(netlink_packet::new_error(Ok(()), req_header))
1355                            }
1356                        }
1357                        Err(e) => client.send_unicast(netlink_packet::new_error(
1358                            Err(e.into_errno()),
1359                            req_header,
1360                        )),
1361                    }
1362                }
1363                DelRoute(ref message) => {
1364                    if message.header.kind != RouteType::Unicast {
1365                        log_warn!(
1366                            "unsupported request type: {:?} route present in new route \
1367                            request from {}: {:?}, only `RTN_UNICAST` is supported",
1368                            message.header.kind,
1369                            client,
1370                            req
1371                        );
1372                        client.send_unicast(netlink_packet::new_error(
1373                            Err(Errno::ENOTSUP),
1374                            req_header,
1375                        ));
1376                        return;
1377                    }
1378
1379                    let result = match message.header.address_family {
1380                        AddressFamily::Inet => {
1381                            match to_del_route_args::<Ipv4>(message, client, &req) {
1382                                Ok(req) => {
1383                                    process_routes_worker_request::<_, Ipv4>(
1384                                        unified_request_sink,
1385                                        client,
1386                                        req_header,
1387                                        req,
1388                                    )
1389                                    .await
1390                                }
1391                                Err(e) => {
1392                                    return client.send_unicast(netlink_packet::new_error(
1393                                        Err(e),
1394                                        req_header,
1395                                    ));
1396                                }
1397                            }
1398                        }
1399                        AddressFamily::Inet6 => {
1400                            match to_del_route_args::<Ipv6>(message, client, &req) {
1401                                Ok(req) => {
1402                                    process_routes_worker_request::<_, Ipv6>(
1403                                        unified_request_sink,
1404                                        client,
1405                                        req_header,
1406                                        req,
1407                                    )
1408                                    .await
1409                                }
1410                                Err(e) => {
1411                                    return client.send_unicast(netlink_packet::new_error(
1412                                        Err(e),
1413                                        req_header,
1414                                    ));
1415                                }
1416                            }
1417                        }
1418                        family => {
1419                            log_debug!(
1420                                "invalid address family ({:?}) in new route \
1421                                request from {}: {:?}",
1422                                family,
1423                                client,
1424                                req
1425                            );
1426                            return client.send_unicast(netlink_packet::new_error(
1427                                Err(Errno::EINVAL),
1428                                req_header,
1429                            ));
1430                        }
1431                    };
1432
1433                    match result {
1434                        Ok(()) => {
1435                            if expects_ack {
1436                                client.send_unicast(netlink_packet::new_error(Ok(()), req_header))
1437                            }
1438                        }
1439                        Err(e) => client.send_unicast(netlink_packet::new_error(
1440                            Err(e.into_errno()),
1441                            req_header,
1442                        )),
1443                    }
1444                }
1445                GetNeighbour(ref message) => {
1446                    let (completer, waiter) = oneshot::channel();
1447                    let request = match GetNeighborArgs::try_from_rtnl_neighbor(message, is_dump) {
1448                        Ok(get_args) => neighbors::Request {
1449                            args: NeighborRequestArgs::Get(get_args),
1450                            sequence_number: req_header.sequence_number,
1451                            client: client.clone(),
1452                            completer,
1453                        },
1454                        Err(e) => {
1455                            return client.send_unicast(netlink_packet::new_error(
1456                                Err(e.into()),
1457                                req_header,
1458                            ));
1459                        }
1460                    };
1461                    unified_request_sink
1462                        .send(UnifiedRequest::NeighborsRequest(request))
1463                        .await
1464                        .expect("route event loop should never terminate");
1465                    let result =
1466                        waiter.await.expect("routes event loop should have handled the request");
1467
1468                    match result {
1469                        Ok(()) => {
1470                            if is_dump {
1471                                client.send_unicast(netlink_packet::new_done(req_header))
1472                            } else if expects_ack {
1473                                client.send_unicast(netlink_packet::new_error(Ok(()), req_header))
1474                            }
1475                        }
1476                        Err(e) => client
1477                            .send_unicast(netlink_packet::new_error(Err(e.into()), req_header)),
1478                    }
1479                }
1480                NewNeighbour(ref message) => {
1481                    let (completer, waiter) = oneshot::channel();
1482                    let request =
1483                        match NewNeighborArgs::try_from_rtnl_neighbor(message, req_header.flags) {
1484                            Ok(add_args) => neighbors::Request {
1485                                args: NeighborRequestArgs::New(add_args),
1486                                sequence_number: req_header.sequence_number,
1487                                client: client.clone(),
1488                                completer,
1489                            },
1490                            Err(e) => {
1491                                return client.send_unicast(netlink_packet::new_error(
1492                                    Err(e.into()),
1493                                    req_header,
1494                                ));
1495                            }
1496                        };
1497                    unified_request_sink
1498                        .send(UnifiedRequest::NeighborsRequest(request))
1499                        .await
1500                        .expect("route event loop should never terminate");
1501                    let result =
1502                        waiter.await.expect("routes event loop should have handled the request");
1503
1504                    match result {
1505                        Ok(()) => {
1506                            if expects_ack {
1507                                client.send_unicast(netlink_packet::new_error(Ok(()), req_header))
1508                            }
1509                        }
1510                        Err(e) => client
1511                            .send_unicast(netlink_packet::new_error(Err(e.into()), req_header)),
1512                    }
1513                }
1514                DelNeighbour(ref message) => {
1515                    let (completer, waiter) = oneshot::channel();
1516                    let request = match DelNeighborArgs::try_from_rtnl_neighbor(message) {
1517                        Ok(del_args) => neighbors::Request {
1518                            args: NeighborRequestArgs::Del(del_args),
1519                            sequence_number: req_header.sequence_number,
1520                            client: client.clone(),
1521                            completer,
1522                        },
1523                        Err(e) => {
1524                            return client.send_unicast(netlink_packet::new_error(
1525                                Err(e.into()),
1526                                req_header,
1527                            ));
1528                        }
1529                    };
1530                    unified_request_sink
1531                        .send(UnifiedRequest::NeighborsRequest(request))
1532                        .await
1533                        .expect("route event loop should never terminate");
1534                    let result =
1535                        waiter.await.expect("routes event loop should have handled the request");
1536
1537                    match result {
1538                        Ok(()) => {
1539                            if expects_ack {
1540                                client.send_unicast(netlink_packet::new_error(Ok(()), req_header))
1541                            }
1542                        }
1543                        Err(e) => client
1544                            .send_unicast(netlink_packet::new_error(Err(e.into()), req_header)),
1545                    }
1546                }
1547                // Style note: avoid placing comments between the match arms
1548                // below as it prevents rustfmt from formatting the entire
1549                // `match` statement.
1550                //
1551                // TODO(https://issues.fuchsia.dev/278565021): Implement
1552                // GetAddress.
1553                GetAddress(_)
1554                | NewLinkProp(_)
1555                | DelLinkProp(_)
1556                | NewNeighbourTable(_)
1557                | GetNeighbourTable(_)
1558                | SetNeighbourTable(_)
1559                | NewTrafficClass(_)
1560                | GetTrafficClass(_)
1561                | DelTrafficClass(_)
1562                | NewTrafficFilter(_)
1563                | GetTrafficFilter(_)
1564                | DelTrafficFilter(_)
1565                | NewTrafficChain(_)
1566                | GetTrafficChain(_)
1567                | DelTrafficChain(_)
1568                | NewNsId(_)
1569                | GetNsId(_)
1570                | DelNsId(_)
1571                | GetRoute(_)
1572                | NewNeighbourDiscoveryUserOption(_)
1573                | NewPrefix(_)
1574                | NewQueueDiscipline(_)
1575                | GetQueueDiscipline(_)
1576                | DelQueueDiscipline(_) => {
1577                    let req_type = (&req).into();
1578                    let nl_flags_dbg =
1579                        netlink_packet::netlink_flags_debug_string(req_header.flags, req_type);
1580                    log_warn!(
1581                        "Received unsupported NETLINK_ROUTE {req_type:?} request: \
1582                        {req:?} with flags {nl_flags_dbg}"
1583                    );
1584                    if is_dump && req_type == NetlinkRequestType::Get {
1585                        client.send_unicast(netlink_packet::new_done(req_header));
1586                    } else if expects_ack {
1587                        client.send_unicast(netlink_packet::new_error(Ok(()), req_header));
1588                    }
1589                }
1590            }
1591        }
1592    }
1593
1594    // Dispatch a route request to the given v4 or v6 Routes sink.
1595    async fn process_routes_worker_request<S: Sender<RouteNetlinkMessage>, I: Ip>(
1596        sink: &mut mpsc::Sender<UnifiedRequest<S>>,
1597        client: &mut InternalClient<NetlinkRoute, S>,
1598        req_header: NetlinkHeader,
1599        route_request: routes::RouteRequestArgs<I>,
1600    ) -> Result<(), routes::RequestError> {
1601        let (completer, waiter) = oneshot::channel();
1602        let request = routes::Request {
1603            args: routes::RequestArgs::Route(route_request),
1604            sequence_number: req_header.sequence_number,
1605            client: client.clone(),
1606            completer,
1607        };
1608        let fut = I::map_ip_in(
1609            (request, IpInvariant(sink)),
1610            |(request, IpInvariant(sink))| sink.send(UnifiedRequest::RoutesV4Request(request)),
1611            |(request, IpInvariant(sink))| sink.send(UnifiedRequest::RoutesV6Request(request)),
1612        );
1613        fut.await.expect("route event loop should never terminate");
1614        waiter.await.expect("routes event loop should have handled the request")
1615    }
1616
1617    /// A connection to the Route Netlink Protocol family.
1618    pub struct NetlinkRouteClient(pub(crate) ExternalClient<NetlinkRoute>);
1619
1620    impl NetlinkClient for NetlinkRouteClient {
1621        type Request = RouteNetlinkMessage;
1622
1623        fn set_pid(&self, pid: NonZeroU32) {
1624            let NetlinkRouteClient(client) = self;
1625            client.set_port_number(pid)
1626        }
1627
1628        fn add_membership(
1629            &self,
1630            group: ModernGroup,
1631        ) -> Result<AsyncWorkCompletionWaiter, InvalidModernGroupError> {
1632            let NetlinkRouteClient(client) = self;
1633            client.add_membership(group)
1634        }
1635
1636        fn del_membership(&self, group: ModernGroup) -> Result<(), InvalidModernGroupError> {
1637            let NetlinkRouteClient(client) = self;
1638            client.del_membership(group)
1639        }
1640
1641        fn set_legacy_memberships(
1642            &self,
1643            legacy_memberships: LegacyGroups,
1644        ) -> Result<AsyncWorkCompletionWaiter, InvalidLegacyGroupsError> {
1645            let NetlinkRouteClient(client) = self;
1646            client.set_legacy_memberships(legacy_memberships)
1647        }
1648    }
1649}
1650
1651#[cfg(test)]
1652pub(crate) mod testutil {
1653    use super::*;
1654
1655    use crate::messaging::testutil::FakeCreds;
1656    use crate::messaging::{NetlinkMessageWithCreds, Permission};
1657    use crate::multicast_groups::GroupSupport;
1658    use netlink_packet_core::NetlinkHeader;
1659
1660    pub(crate) const LEGACY_GROUP1: u32 = 0x00000001;
1661    pub(crate) const LEGACY_GROUP2: u32 = 0x00000002;
1662    pub(crate) const LEGACY_GROUP3: u32 = 0x00000004;
1663    pub(crate) const INVALID_LEGACY_GROUP: u32 = 0x00000008;
1664    pub(crate) const MODERN_GROUP1: ModernGroup = ModernGroup(1);
1665    pub(crate) const MODERN_GROUP2: ModernGroup = ModernGroup(2);
1666    pub(crate) const MODERN_GROUP3: ModernGroup = ModernGroup(3);
1667    pub(crate) const INVALID_MODERN_GROUP: ModernGroup = ModernGroup(4);
1668    pub(crate) const MODERN_GROUP_NEEDS_BLOCKING: ModernGroup = ModernGroup(5);
1669    // AF_PACKET can't be generated by bindgen for some reason.
1670    pub(crate) const AF_PACKET: u16 = 17;
1671
1672    #[derive(Debug)]
1673    pub(crate) enum FakeProtocolFamily {}
1674
1675    impl MulticastCapableNetlinkFamily for FakeProtocolFamily {
1676        fn check_support(group: &ModernGroup) -> Result<GroupSupport, InvalidModernGroupError> {
1677            match *group {
1678                MODERN_GROUP1 | MODERN_GROUP2 | MODERN_GROUP3 | MODERN_GROUP_NEEDS_BLOCKING => {
1679                    Ok(GroupSupport::Unsupported)
1680                }
1681                _ => Err(InvalidModernGroupError),
1682            }
1683        }
1684    }
1685
1686    pub(crate) fn new_fake_netlink_message() -> NetlinkMessage<FakeNetlinkInnerMessage> {
1687        NetlinkMessage::new(
1688            NetlinkHeader::default(),
1689            NetlinkPayload::InnerMessage(FakeNetlinkInnerMessage),
1690        )
1691    }
1692
1693    pub(crate) fn new_fake_netlink_message_with_creds()
1694    -> NetlinkMessageWithCreds<NetlinkMessage<FakeNetlinkInnerMessage>, FakeCreds> {
1695        NetlinkMessageWithCreds::new(new_fake_netlink_message(), FakeCreds::default())
1696    }
1697
1698    #[derive(Clone, Debug, Default, PartialEq)]
1699    pub(crate) struct FakeNetlinkInnerMessage;
1700
1701    impl MessageWithPermission for FakeNetlinkInnerMessage {
1702        fn permission(&self) -> Permission {
1703            Permission::NetlinkRouteWrite
1704        }
1705    }
1706
1707    impl NetlinkSerializable for FakeNetlinkInnerMessage {
1708        fn message_type(&self) -> u16 {
1709            u16::MAX
1710        }
1711
1712        fn buffer_len(&self) -> usize {
1713            0
1714        }
1715
1716        fn serialize(&self, _buffer: &mut [u8]) {}
1717    }
1718
1719    impl NetlinkDeserializable for FakeNetlinkInnerMessage {
1720        type DeserializeOptions = ();
1721        type Error = DecodeError;
1722
1723        fn deserialize(
1724            _header: &NetlinkHeader,
1725            _payload: &[u8],
1726            _options: (),
1727        ) -> Result<Self, Self::Error> {
1728            unimplemented!()
1729        }
1730    }
1731
1732    /// Handler of [`FakeNetlinkInnerMessage`] requests.
1733    ///
1734    /// Reflects the given request back as the response.
1735    #[derive(Clone)]
1736    pub(crate) struct FakeNetlinkRequestHandler;
1737
1738    impl<S: Sender<FakeNetlinkInnerMessage>> NetlinkFamilyRequestHandler<FakeProtocolFamily, S>
1739        for FakeNetlinkRequestHandler
1740    {
1741        async fn handle_request(
1742            &mut self,
1743            req: NetlinkMessage<FakeNetlinkInnerMessage>,
1744            client: &mut InternalClient<FakeProtocolFamily, S>,
1745        ) {
1746            client.send_unicast(req)
1747        }
1748    }
1749
1750    impl NamedNetlinkFamily for FakeProtocolFamily {
1751        const NAME: &'static str = "FAKE_PROTOCOL_FAMILY";
1752    }
1753
1754    impl ProtocolFamily for FakeProtocolFamily {
1755        type Request = FakeNetlinkInnerMessage;
1756        type Response = FakeNetlinkInnerMessage;
1757        type RequestHandler<S: Sender<Self::Response>> = FakeNetlinkRequestHandler;
1758        type NotifiedMulticastGroup = ();
1759        type AsyncWorkItem = !;
1760
1761        fn should_notify_on_group_membership_change(
1762            group: ModernGroup,
1763        ) -> Option<Self::NotifiedMulticastGroup> {
1764            (group == MODERN_GROUP_NEEDS_BLOCKING).then_some(())
1765        }
1766    }
1767}
1768
1769#[cfg(test)]
1770mod test {
1771    use super::*;
1772
1773    use fuchsia_sync::Mutex;
1774    use std::collections::VecDeque;
1775    use std::net::IpAddr;
1776    use std::num::{NonZeroU32, NonZeroU64};
1777    use std::pin::pin;
1778    use std::sync::Arc;
1779
1780    use fidl_fuchsia_net_routes_ext as fnet_routes_ext;
1781
1782    use assert_matches::assert_matches;
1783    use fidl_fuchsia_net as fnet;
1784    use fuchsia_async as fasync;
1785    use futures::SinkExt;
1786    use futures::channel::mpsc;
1787    use futures::future::FutureExt as _;
1788    use futures::stream::StreamExt as _;
1789    use linux_uapi::{
1790        AF_INET, AF_INET6, AF_UNSPEC, IFA_F_NOPREFIXROUTE, RTN_MULTICAST, RTN_UNICAST,
1791        net_device_flags_IFF_UP, rt_class_t_RT_TABLE_COMPAT, rt_class_t_RT_TABLE_MAIN,
1792    };
1793    use net_declare::{
1794        fidl_ip, net_addr_subnet, net_ip_v4, net_ip_v6, net_subnet_v4, net_subnet_v6, std_ip_v4,
1795        std_ip_v6,
1796    };
1797    use net_types::ip::{
1798        AddrSubnetEither, GenericOverIp, Ip, IpVersion, Ipv4, Ipv4Addr, Ipv6, Ipv6Addr, Subnet,
1799        SubnetEither,
1800    };
1801    use net_types::{SpecifiedAddr, Witness as _};
1802    use netlink_packet_core::{
1803        NLM_F_ACK, NLM_F_CREATE, NLM_F_DUMP, NLM_F_EXCL, NLM_F_REPLACE, NetlinkHeader,
1804    };
1805
1806    use netlink_packet_route::address::{AddressAttribute, AddressFlags, AddressMessage};
1807    use netlink_packet_route::link::{InfoKind, LinkAttribute, LinkFlags, LinkInfo, LinkMessage};
1808    use netlink_packet_route::neighbour::{
1809        NeighbourAttribute, NeighbourHeader, NeighbourMessage, NeighbourState,
1810    };
1811    use netlink_packet_route::neighbour_discovery_user_option::{
1812        NeighbourDiscoveryIcmpType, NeighbourDiscoveryIcmpV6Type,
1813        NeighbourDiscoveryUserOptionHeader, NeighbourDiscoveryUserOptionMessage,
1814    };
1815    use netlink_packet_route::route::{RouteAddress, RouteAttribute, RouteMessage, RouteType};
1816    use netlink_packet_route::rule::RuleMessage;
1817    use netlink_packet_route::{AddressFamily, RouteNetlinkMessage};
1818    use test::testutil::AF_PACKET;
1819    use test_case::test_case;
1820
1821    use crate::messaging::testutil::{FakeSender, SentMessage};
1822    use crate::netlink_packet::errno::Errno;
1823    use crate::netlink_packet::{self};
1824    use crate::protocol_family::route::{NetlinkRoute, NetlinkRouteRequestHandler};
1825    use crate::route_eventloop::UnifiedRequest;
1826    use crate::rules::{RuleRequest, RuleRequestArgs};
1827    use crate::{interfaces, neighbors, routes};
1828
1829    enum ExpectedResponse {
1830        Ack,
1831        Error(Errno),
1832        Done,
1833    }
1834
1835    fn expected_sent_messages(
1836        expected_response: Option<ExpectedResponse>,
1837        nl_header: NetlinkHeader,
1838    ) -> Vec<SentMessage<RouteNetlinkMessage>> {
1839        expected_response
1840            .into_iter()
1841            .map(|expected_response| {
1842                SentMessage::unicast(match expected_response {
1843                    ExpectedResponse::Ack => netlink_packet::new_error(Ok(()), nl_header),
1844                    ExpectedResponse::Error(e) => netlink_packet::new_error(Err(e), nl_header),
1845                    ExpectedResponse::Done => netlink_packet::new_done(nl_header),
1846                })
1847            })
1848            .collect::<Vec<_>>()
1849    }
1850
1851    fn header_with_flags(flags: u16) -> NetlinkHeader {
1852        let mut header = NetlinkHeader::default();
1853        header.flags = flags;
1854        header
1855    }
1856
1857    fn neighbour_discovery_user_option_msg() -> NeighbourDiscoveryUserOptionMessage {
1858        NeighbourDiscoveryUserOptionMessage::new(
1859            NeighbourDiscoveryUserOptionHeader::new(
1860                0,
1861                NeighbourDiscoveryIcmpType::Inet6(
1862                    NeighbourDiscoveryIcmpV6Type::NeighbourAdvertisement,
1863                ),
1864            ),
1865            Default::default(),
1866            Default::default(),
1867        )
1868    }
1869
1870    /// Tests that unhandled requests are treated as a no-op.
1871    ///
1872    /// Get requests are responded to with a Done message if the dump flag
1873    /// is set, an Ack message if the ack flag is set or nothing. New/Del
1874    /// requests are responded to with an Ack message if the ack flag is set
1875    /// or nothing.
1876    #[test_case(
1877        RouteNetlinkMessage::GetTrafficChain(Default::default()),
1878        0,
1879        None; "get_tc__with_no_flags")]
1880    #[test_case(
1881        RouteNetlinkMessage::GetTrafficChain(Default::default()),
1882        NLM_F_ACK,
1883        Some(ExpectedResponse::Ack); "get_tc_with_ack_flag")]
1884    #[test_case(
1885        RouteNetlinkMessage::GetTrafficChain(Default::default()),
1886        NLM_F_DUMP,
1887        Some(ExpectedResponse::Done); "get_tc_with_dump_flag")]
1888    #[test_case(
1889        RouteNetlinkMessage::GetTrafficChain(Default::default()),
1890        NLM_F_ACK | NLM_F_DUMP,
1891        Some(ExpectedResponse::Done); "get_tc_with_ack_and_dump_flag")]
1892    #[test_case(
1893        RouteNetlinkMessage::NewTrafficChain(Default::default()),
1894        0,
1895        None; "new_tc_with_no_flags")]
1896    #[test_case(
1897        RouteNetlinkMessage::NewTrafficChain(Default::default()),
1898        NLM_F_DUMP,
1899        None; "new_tc_with_dump_flag")]
1900    #[test_case(
1901        RouteNetlinkMessage::NewTrafficChain(Default::default()),
1902        NLM_F_ACK,
1903        Some(ExpectedResponse::Ack); "new_tc_with_ack_flag")]
1904    #[test_case(
1905        RouteNetlinkMessage::NewTrafficChain(Default::default()),
1906        NLM_F_ACK | NLM_F_DUMP,
1907        Some(ExpectedResponse::Ack); "new_tc_with_ack_and_dump_flags")]
1908    #[test_case(
1909        RouteNetlinkMessage::DelTrafficChain(Default::default()),
1910        0,
1911        None; "deltc_with_no_flags")]
1912    #[test_case(
1913        RouteNetlinkMessage::DelTrafficChain(Default::default()),
1914        NLM_F_DUMP,
1915        None; "del_tc_with_dump_flag")]
1916    #[test_case(
1917        RouteNetlinkMessage::DelTrafficChain(Default::default()),
1918        NLM_F_ACK,
1919        Some(ExpectedResponse::Ack); "del_tc_with_ack_flag")]
1920    #[test_case(
1921        RouteNetlinkMessage::DelTrafficChain(Default::default()),
1922        NLM_F_ACK | NLM_F_DUMP,
1923        Some(ExpectedResponse::Ack); "del_tc_with_ack_and_dump_flags")]
1924    #[test_case(
1925        RouteNetlinkMessage::NewNeighbourDiscoveryUserOption(neighbour_discovery_user_option_msg()),
1926        NLM_F_ACK,
1927        Some(ExpectedResponse::Ack); "new_neighbour_user_option_with_ack_flag")]
1928    #[test_case(
1929        RouteNetlinkMessage::NewNeighbourDiscoveryUserOption(neighbour_discovery_user_option_msg()),
1930        0,
1931        None; "new_neighbour_user_option_no_flags")]
1932    #[test_case(
1933        RouteNetlinkMessage::NewPrefix(Default::default()),
1934        NLM_F_ACK,
1935        Some(ExpectedResponse::Ack); "new_prefix_with_ack_flag")]
1936    #[test_case(
1937        RouteNetlinkMessage::NewPrefix(Default::default()),
1938        0,
1939        None; "new_prefix_no_flags")]
1940    #[fuchsia::test]
1941    async fn test_handle_unsupported_request_response(
1942        inner_message: RouteNetlinkMessage,
1943        flags: u16,
1944        expected_response: Option<ExpectedResponse>,
1945    ) {
1946        let (unified_request_sink, _unified_request_stream) = mpsc::channel(0);
1947
1948        let mut handler = NetlinkRouteRequestHandler::<FakeSender<_>> { unified_request_sink };
1949
1950        let (mut client_sink, mut client, async_work_drain_task) =
1951            crate::client::testutil::new_fake_client::<NetlinkRoute>(
1952                crate::client::testutil::CLIENT_ID_1,
1953                std::iter::empty(),
1954            );
1955        let join_handle = fasync::Task::spawn(async_work_drain_task);
1956
1957        let header = header_with_flags(flags);
1958
1959        handler
1960            .handle_request(
1961                NetlinkMessage::new(header, NetlinkPayload::InnerMessage(inner_message)),
1962                &mut client,
1963            )
1964            .await;
1965
1966        assert_eq!(client_sink.take_messages(), expected_sent_messages(expected_response, header));
1967
1968        drop(client);
1969        join_handle.await;
1970    }
1971
1972    struct RequestAndResponse<R> {
1973        request: R,
1974        response: Result<(), interfaces::RequestError>,
1975    }
1976
1977    async fn test_request(
1978        request: NetlinkMessage<RouteNetlinkMessage>,
1979        req_and_resp: Option<RequestAndResponse<interfaces::RequestArgs>>,
1980    ) -> Vec<SentMessage<RouteNetlinkMessage>> {
1981        let (mut client_sink, mut client, async_work_drain_task) =
1982            crate::client::testutil::new_fake_client::<NetlinkRoute>(
1983                crate::client::testutil::CLIENT_ID_1,
1984                std::iter::empty(),
1985            );
1986        let join_handle = fasync::Task::spawn(async_work_drain_task);
1987
1988        let (unified_request_sink, unified_request_stream) = mpsc::channel(0);
1989        let mut handler = NetlinkRouteRequestHandler::<FakeSender<_>> { unified_request_sink };
1990
1991        let mut interfaces_request_stream = unified_request_stream.filter_map(|req| {
1992            futures::future::ready(match req {
1993                UnifiedRequest::InterfacesRequest(req) => Some(req),
1994                _ => None,
1995            })
1996        });
1997
1998        let ((), ()) = futures::future::join(handler.handle_request(request, &mut client), async {
1999            let next = interfaces_request_stream.next();
2000            match req_and_resp {
2001                Some(RequestAndResponse { request, response }) => {
2002                    let interfaces::Request { args, sequence_number: _, client: _, completer } =
2003                        next.await.expect("handler should send request");
2004                    assert_eq!(args, request);
2005                    completer.send(response).expect("handler should be alive");
2006                }
2007                None => assert_matches!(next.now_or_never(), None),
2008            }
2009        })
2010        .await;
2011
2012        drop(client);
2013        join_handle.await;
2014        client_sink.take_messages()
2015    }
2016
2017    const FAKE_INTERFACE_ID: u32 = 1;
2018    const FAKE_INTERFACE_NAME: &str = "interface";
2019
2020    /// Test RTM_GETLINK.
2021    #[test_case(
2022        0,
2023        0,
2024        None,
2025        None,
2026        Ok(()),
2027        Some(ExpectedResponse::Error(Errno::EINVAL)); "no_specifiers")]
2028    #[test_case(
2029        NLM_F_DUMP,
2030        0,
2031        None,
2032        Some(interfaces::GetLinkArgs::Dump),
2033        Ok(()),
2034        Some(ExpectedResponse::Done); "dump")]
2035    #[test_case(
2036        NLM_F_DUMP | NLM_F_ACK,
2037        0,
2038        None,
2039        Some(interfaces::GetLinkArgs::Dump),
2040        Ok(()),
2041        Some(ExpectedResponse::Done); "dump_with_ack")]
2042    #[test_case(
2043        NLM_F_DUMP,
2044        FAKE_INTERFACE_ID,
2045        None,
2046        Some(interfaces::GetLinkArgs::Dump),
2047        Ok(()),
2048        Some(ExpectedResponse::Done); "dump_with_id")]
2049    #[test_case(
2050        NLM_F_DUMP,
2051        FAKE_INTERFACE_ID,
2052        Some(FAKE_INTERFACE_NAME),
2053        Some(interfaces::GetLinkArgs::Dump),
2054        Ok(()),
2055        Some(ExpectedResponse::Done); "dump_with_id_and_name")]
2056    #[test_case(
2057        0,
2058        FAKE_INTERFACE_ID,
2059        None,
2060        Some(interfaces::GetLinkArgs::Get(interfaces::LinkSpecifier::Index(
2061            NonZeroU32::new(FAKE_INTERFACE_ID).unwrap()))),
2062        Ok(()),
2063        None; "id")]
2064    #[test_case(
2065        NLM_F_ACK,
2066        FAKE_INTERFACE_ID,
2067        None,
2068        Some(interfaces::GetLinkArgs::Get(interfaces::LinkSpecifier::Index(
2069            NonZeroU32::new(FAKE_INTERFACE_ID).unwrap()))),
2070        Ok(()),
2071        Some(ExpectedResponse::Ack); "id_with_ack")]
2072    #[test_case(
2073        0,
2074        FAKE_INTERFACE_ID,
2075        Some(FAKE_INTERFACE_NAME),
2076        Some(interfaces::GetLinkArgs::Get(interfaces::LinkSpecifier::Index(
2077            NonZeroU32::new(FAKE_INTERFACE_ID).unwrap()))),
2078        Ok(()),
2079        None; "id_with_name")]
2080    #[test_case(
2081        0,
2082        0,
2083        Some(FAKE_INTERFACE_NAME),
2084        Some(interfaces::GetLinkArgs::Get(interfaces::LinkSpecifier::Name(
2085            FAKE_INTERFACE_NAME.to_string()))),
2086        Ok(()),
2087        None; "name")]
2088    #[test_case(
2089        NLM_F_ACK,
2090        0,
2091        Some(FAKE_INTERFACE_NAME),
2092        Some(interfaces::GetLinkArgs::Get(interfaces::LinkSpecifier::Name(
2093            FAKE_INTERFACE_NAME.to_string()))),
2094        Ok(()),
2095        Some(ExpectedResponse::Ack); "name_with_ack")]
2096    #[test_case(
2097        0,
2098        FAKE_INTERFACE_ID,
2099        None,
2100        Some(interfaces::GetLinkArgs::Get(interfaces::LinkSpecifier::Index(
2101            NonZeroU32::new(FAKE_INTERFACE_ID).unwrap()))),
2102        Err(interfaces::RequestError::UnrecognizedInterface),
2103        Some(ExpectedResponse::Error(Errno::ENODEV)); "id_not_found")]
2104    #[test_case(
2105        0,
2106        0,
2107        Some(FAKE_INTERFACE_NAME),
2108        Some(interfaces::GetLinkArgs::Get(interfaces::LinkSpecifier::Name(
2109            FAKE_INTERFACE_NAME.to_string()))),
2110        Err(interfaces::RequestError::UnrecognizedInterface),
2111        Some(ExpectedResponse::Error(Errno::ENODEV)); "name_not_found")]
2112    #[fuchsia::test]
2113    async fn test_get_link(
2114        flags: u16,
2115        link_id: u32,
2116        link_name: Option<&str>,
2117        expected_request_args: Option<interfaces::GetLinkArgs>,
2118        interfaces_worker_result: Result<(), interfaces::RequestError>,
2119        expected_response: Option<ExpectedResponse>,
2120    ) {
2121        let header = header_with_flags(flags);
2122        let mut link_message = LinkMessage::default();
2123        link_message.header.index = link_id;
2124        link_message.attributes =
2125            link_name.map(|n| LinkAttribute::IfName(n.to_string())).into_iter().collect();
2126
2127        pretty_assertions::assert_eq!(
2128            test_request(
2129                NetlinkMessage::new(
2130                    header,
2131                    NetlinkPayload::InnerMessage(RouteNetlinkMessage::GetLink(link_message)),
2132                ),
2133                expected_request_args.map(|a| RequestAndResponse {
2134                    request: interfaces::RequestArgs::Link(interfaces::LinkRequestArgs::Get(a)),
2135                    response: interfaces_worker_result,
2136                }),
2137            )
2138            .await,
2139            expected_sent_messages(expected_response, header),
2140        )
2141    }
2142
2143    #[test_case(
2144        0,
2145        0,
2146        None,
2147        0,
2148        0,
2149        None,
2150        Ok(()),
2151        Some(ExpectedResponse::Error(Errno::EINVAL)); "interface_not_specified")]
2152    #[test_case(
2153        0,
2154        FAKE_INTERFACE_ID,
2155        Some(FAKE_INTERFACE_NAME),
2156        0,
2157        0,
2158        None,
2159        Ok(()),
2160        Some(ExpectedResponse::Error(Errno::EBUSY)); "name_and_id")]
2161    #[test_case(
2162        0,
2163        FAKE_INTERFACE_ID,
2164        None,
2165        0,
2166        0,
2167        Some(interfaces::SetLinkArgs{
2168            link: interfaces::LinkSpecifier::Index(NonZeroU32::new(FAKE_INTERFACE_ID).unwrap()),
2169            enable: None,
2170        }),
2171        Ok(()),
2172        None; "no_change_by_id")]
2173    #[test_case(
2174        0,
2175        0,
2176        Some(FAKE_INTERFACE_NAME),
2177        0,
2178        0,
2179        Some(interfaces::SetLinkArgs{
2180            link: interfaces::LinkSpecifier::Name(FAKE_INTERFACE_NAME.to_string()),
2181            enable: None,
2182        }),
2183        Ok(()),
2184        None; "no_change_by_name")]
2185    #[test_case(
2186        NLM_F_ACK,
2187        0,
2188        Some(FAKE_INTERFACE_NAME),
2189        0,
2190        0,
2191        Some(interfaces::SetLinkArgs{
2192            link: interfaces::LinkSpecifier::Name(FAKE_INTERFACE_NAME.to_string()),
2193            enable: None,
2194        }),
2195        Ok(()),
2196        Some(ExpectedResponse::Ack); "no_change_ack")]
2197    #[test_case(
2198        0,
2199        0,
2200        Some(FAKE_INTERFACE_NAME),
2201        net_device_flags_IFF_UP,
2202        net_device_flags_IFF_UP,
2203        Some(interfaces::SetLinkArgs{
2204            link: interfaces::LinkSpecifier::Name(FAKE_INTERFACE_NAME.to_string()),
2205            enable: Some(true),
2206        }),
2207        Ok(()),
2208        None; "enable")]
2209    #[test_case(
2210        NLM_F_ACK,
2211        0,
2212        Some(FAKE_INTERFACE_NAME),
2213        net_device_flags_IFF_UP,
2214        net_device_flags_IFF_UP,
2215        Some(interfaces::SetLinkArgs{
2216            link: interfaces::LinkSpecifier::Name(FAKE_INTERFACE_NAME.to_string()),
2217            enable: Some(true),
2218        }),
2219        Ok(()),
2220        Some(ExpectedResponse::Ack); "enable_ack")]
2221    #[test_case(
2222        NLM_F_ACK,
2223        0,
2224        Some(FAKE_INTERFACE_NAME),
2225        net_device_flags_IFF_UP,
2226        net_device_flags_IFF_UP,
2227        Some(interfaces::SetLinkArgs{
2228            link: interfaces::LinkSpecifier::Name(FAKE_INTERFACE_NAME.to_string()),
2229            enable: Some(true),
2230        }),
2231        Err(interfaces::RequestError::UnrecognizedInterface),
2232        Some(ExpectedResponse::Error(Errno::ENODEV)); "enable_error")]
2233    #[test_case(
2234        0,
2235        0,
2236        Some(FAKE_INTERFACE_NAME),
2237        0,
2238        net_device_flags_IFF_UP,
2239        Some(interfaces::SetLinkArgs{
2240            link: interfaces::LinkSpecifier::Name(FAKE_INTERFACE_NAME.to_string()),
2241            enable: Some(false),
2242        }),
2243        Ok(()),
2244        None; "disable")]
2245    #[test_case(
2246        NLM_F_ACK,
2247        0,
2248        Some(FAKE_INTERFACE_NAME),
2249        0,
2250        net_device_flags_IFF_UP,
2251        Some(interfaces::SetLinkArgs{
2252            link: interfaces::LinkSpecifier::Name(FAKE_INTERFACE_NAME.to_string()),
2253            enable: Some(false),
2254        }),
2255        Ok(()),
2256        Some(ExpectedResponse::Ack); "disable_ack")]
2257    #[test_case(
2258        NLM_F_ACK,
2259        0,
2260        Some(FAKE_INTERFACE_NAME),
2261        0,
2262        net_device_flags_IFF_UP,
2263        Some(interfaces::SetLinkArgs{
2264            link: interfaces::LinkSpecifier::Name(FAKE_INTERFACE_NAME.to_string()),
2265            enable: Some(false),
2266        }),
2267        Err(interfaces::RequestError::UnrecognizedInterface),
2268        Some(ExpectedResponse::Error(Errno::ENODEV)); "disable_error")]
2269    #[fuchsia::test]
2270    async fn test_set_link(
2271        flags: u16,
2272        link_id: u32,
2273        link_name: Option<&str>,
2274        link_flags: u32,
2275        change_mask: u32,
2276        expected_request_args: Option<interfaces::SetLinkArgs>,
2277        interfaces_worker_result: Result<(), interfaces::RequestError>,
2278        expected_response: Option<ExpectedResponse>,
2279    ) {
2280        let header = header_with_flags(flags);
2281        let mut link_message = LinkMessage::default();
2282        link_message.header.index = link_id;
2283        link_message.header.flags = LinkFlags::from_bits(link_flags).unwrap();
2284        link_message.header.change_mask = LinkFlags::from_bits(change_mask).unwrap();
2285        link_message.attributes =
2286            link_name.map(|n| LinkAttribute::IfName(n.to_string())).into_iter().collect();
2287
2288        pretty_assertions::assert_eq!(
2289            test_request(
2290                NetlinkMessage::new(
2291                    header,
2292                    NetlinkPayload::InnerMessage(RouteNetlinkMessage::SetLink(link_message)),
2293                ),
2294                expected_request_args.map(|a| RequestAndResponse {
2295                    request: interfaces::RequestArgs::Link(interfaces::LinkRequestArgs::Set(a)),
2296                    response: interfaces_worker_result,
2297                }),
2298            )
2299            .await,
2300            expected_sent_messages(expected_response, header),
2301        )
2302    }
2303
2304    #[fuchsia::test]
2305    async fn test_new_link() {
2306        let header = header_with_flags(0);
2307        let mut link_message = LinkMessage::default();
2308        link_message.header.index = 1;
2309        link_message.attributes = vec![
2310            LinkAttribute::IfName("interface".to_string()),
2311            LinkAttribute::LinkInfo(vec![LinkInfo::Kind(InfoKind::Xfrm)]),
2312        ];
2313
2314        pretty_assertions::assert_eq!(
2315            test_request(
2316                NetlinkMessage::new(
2317                    header,
2318                    NetlinkPayload::InnerMessage(RouteNetlinkMessage::NewLink(link_message)),
2319                ),
2320                None,
2321            )
2322            .await,
2323            expected_sent_messages(Some(ExpectedResponse::Error(Errno::ENOTSUP)), header)
2324        );
2325    }
2326
2327    #[fuchsia::test]
2328    async fn test_del_link() {
2329        let header = header_with_flags(0);
2330        let mut link_message = LinkMessage::default();
2331        link_message.header.index = 1;
2332        link_message.attributes = vec![LinkAttribute::IfName("interface".to_string())];
2333
2334        pretty_assertions::assert_eq!(
2335            test_request(
2336                NetlinkMessage::new(
2337                    header,
2338                    NetlinkPayload::InnerMessage(RouteNetlinkMessage::DelLink(link_message)),
2339                ),
2340                None,
2341            )
2342            .await,
2343            expected_sent_messages(Some(ExpectedResponse::Error(Errno::ENOTSUP)), header)
2344        );
2345    }
2346
2347    /// Test RTM_GETADDR.
2348    /// Conversions to u16 are safe because the constants fit within a 16-bit integer,
2349    #[test_case(
2350        0,
2351        AF_UNSPEC,
2352        None,
2353        None; "af_unspec_no_flags")]
2354    #[test_case(
2355        NLM_F_ACK,
2356        AF_UNSPEC,
2357        None,
2358        Some(ExpectedResponse::Ack); "af_unspec_ack_flag")]
2359    #[test_case(
2360        NLM_F_DUMP,
2361        AF_UNSPEC,
2362        Some(interfaces::GetAddressArgs::Dump {
2363            ip_version_filter: None,
2364        }),
2365        Some(ExpectedResponse::Done); "af_unspec_dump_flag")]
2366    #[test_case(
2367        NLM_F_DUMP | NLM_F_ACK,
2368        AF_UNSPEC,
2369        Some(interfaces::GetAddressArgs::Dump {
2370            ip_version_filter: None,
2371        }),
2372        Some(ExpectedResponse::Done); "af_unspec_dump_and_ack_flags")]
2373    #[test_case(
2374        0,
2375        AF_INET,
2376        None,
2377        None; "af_inet_no_flags")]
2378    #[test_case(
2379        NLM_F_ACK,
2380        AF_INET,
2381        None,
2382        Some(ExpectedResponse::Ack); "af_inet_ack_flag")]
2383    #[test_case(
2384        NLM_F_DUMP,
2385        AF_INET,
2386        Some(interfaces::GetAddressArgs::Dump {
2387            ip_version_filter: Some(IpVersion::V4),
2388        }),
2389        Some(ExpectedResponse::Done); "af_inet_dump_flag")]
2390    #[test_case(
2391        NLM_F_DUMP | NLM_F_ACK,
2392        AF_INET,
2393        Some(interfaces::GetAddressArgs::Dump {
2394            ip_version_filter: Some(IpVersion::V4),
2395        }),
2396        Some(ExpectedResponse::Done); "af_inet_dump_and_ack_flags")]
2397    #[test_case(
2398        0,
2399        AF_INET6,
2400        None,
2401        None; "af_inet6_no_flags")]
2402    #[test_case(
2403        NLM_F_ACK,
2404        AF_INET6,
2405        None,
2406        Some(ExpectedResponse::Ack); "af_inet6_ack_flag")]
2407    #[test_case(
2408        NLM_F_DUMP,
2409        AF_INET6,
2410        Some(interfaces::GetAddressArgs::Dump {
2411            ip_version_filter: Some(IpVersion::V6),
2412        }),
2413        Some(ExpectedResponse::Done); "af_inet6_dump_flag")]
2414    #[test_case(
2415        NLM_F_DUMP | NLM_F_ACK,
2416        AF_INET6,
2417        Some(interfaces::GetAddressArgs::Dump {
2418            ip_version_filter: Some(IpVersion::V6),
2419        }),
2420        Some(ExpectedResponse::Done); "af_inet6_dump_and_ack_flags")]
2421    #[test_case(
2422        0,
2423        AF_PACKET.into(),
2424        None,
2425        None; "af_other_no_flags")]
2426    #[test_case(
2427        NLM_F_ACK,
2428        AF_PACKET.into(),
2429        None,
2430        Some(ExpectedResponse::Ack); "af_other_ack_flag")]
2431    #[test_case(
2432        NLM_F_DUMP,
2433        AF_PACKET.into(),
2434        None,
2435        Some(ExpectedResponse::Error(Errno::EINVAL)); "af_other_dump_flag")]
2436    #[test_case(
2437        NLM_F_DUMP | NLM_F_ACK,
2438        AF_PACKET.into(),
2439        None,
2440        Some(ExpectedResponse::Error(Errno::EINVAL)); "af_other_dump_and_ack_flags")]
2441    #[fuchsia::test]
2442    async fn test_get_addr(
2443        flags: u16,
2444        family: u32,
2445        expected_request_args: Option<interfaces::GetAddressArgs>,
2446        expected_response: Option<ExpectedResponse>,
2447    ) {
2448        // This conversion is safe because family is actually a u16.
2449        let family = family as u16;
2450        let header = header_with_flags(flags);
2451        let address_message = {
2452            let mut message = AddressMessage::default();
2453            // Conversion is safe, because family is guaranteed to fit into an 8-bit integer.
2454            message.header.family = AddressFamily::from(family as u8).into();
2455            message
2456        };
2457
2458        pretty_assertions::assert_eq!(
2459            test_request(
2460                NetlinkMessage::new(
2461                    header,
2462                    NetlinkPayload::InnerMessage(RouteNetlinkMessage::GetAddress(address_message)),
2463                ),
2464                expected_request_args.map(|a| RequestAndResponse {
2465                    request: interfaces::RequestArgs::Address(interfaces::AddressRequestArgs::Get(
2466                        a
2467                    )),
2468                    response: Ok(()),
2469                }),
2470            )
2471            .await,
2472            expected_sent_messages(expected_response, header)
2473        )
2474    }
2475
2476    enum AddressRequestKind {
2477        New { add_subnet_route: bool, replace: bool },
2478        Del,
2479    }
2480
2481    struct TestAddrCase {
2482        kind: AddressRequestKind,
2483        flags: u16,
2484        family: u16,
2485        nlas: Vec<AddressAttribute>,
2486        prefix_len: u8,
2487        interface_id: u32,
2488        expected_request_args: Option<RequestAndResponse<interfaces::AddressAndInterfaceArgs>>,
2489        expected_response: Option<ExpectedResponse>,
2490    }
2491
2492    fn ip_from_addr(a: AddrSubnetEither) -> IpAddr {
2493        match a {
2494            AddrSubnetEither::V4(a) => IpAddr::V4(a.addr().get().ipv4_bytes().into()),
2495            AddrSubnetEither::V6(a) => IpAddr::V6(a.addr().get().ipv6_bytes().into()),
2496        }
2497    }
2498
2499    fn prefix_from_addr(a: AddrSubnetEither) -> u8 {
2500        let (_addr, prefix) = a.addr_prefix();
2501        prefix
2502    }
2503
2504    fn interface_id_as_u32(id: u64) -> u32 {
2505        id.try_into().unwrap()
2506    }
2507
2508    fn valid_new_del_addr_request(
2509        kind: AddressRequestKind,
2510        ack: bool,
2511        addr: AddrSubnetEither,
2512        extra_nlas: impl IntoIterator<Item = AddressAttribute>,
2513        interface_id: u64,
2514        response: Result<(), interfaces::RequestError>,
2515    ) -> TestAddrCase {
2516        TestAddrCase {
2517            kind,
2518            flags: if ack { NLM_F_ACK } else { 0 },
2519            family: match addr {
2520                // Conversions to u16 are safe as AF_INET and AF_INET6
2521                // fit into 16-bit integers.
2522                AddrSubnetEither::V4(_) => AF_INET as u16,
2523                AddrSubnetEither::V6(_) => AF_INET6 as u16,
2524            },
2525            nlas: [AddressAttribute::Local(ip_from_addr(addr))]
2526                .into_iter()
2527                .chain(extra_nlas)
2528                .collect(),
2529            prefix_len: prefix_from_addr(addr),
2530            interface_id: interface_id_as_u32(interface_id),
2531            expected_request_args: Some(RequestAndResponse {
2532                request: interfaces::AddressAndInterfaceArgs {
2533                    address: addr,
2534                    interface_id: NonZeroU32::new(interface_id_as_u32(interface_id)).unwrap(),
2535                },
2536                response,
2537            }),
2538            expected_response: ack.then_some(ExpectedResponse::Ack),
2539        }
2540    }
2541
2542    fn valid_new_addr_request_with_extra_nlas(
2543        ack: bool,
2544        addr: AddrSubnetEither,
2545        extra_nlas: impl IntoIterator<Item = AddressAttribute>,
2546        interface_id: u64,
2547        response: Result<(), interfaces::RequestError>,
2548    ) -> TestAddrCase {
2549        valid_new_del_addr_request(
2550            AddressRequestKind::New { add_subnet_route: true, replace: false },
2551            ack,
2552            addr,
2553            extra_nlas,
2554            interface_id,
2555            response,
2556        )
2557    }
2558
2559    fn valid_new_addr_request(
2560        ack: bool,
2561        addr: AddrSubnetEither,
2562        interface_id: u64,
2563        response: Result<(), interfaces::RequestError>,
2564    ) -> TestAddrCase {
2565        valid_new_addr_request_with_extra_nlas(ack, addr, None, interface_id, response)
2566    }
2567
2568    fn invalid_new_addr_request(
2569        ack: bool,
2570        addr: AddrSubnetEither,
2571        interface_id: u64,
2572        errno: Errno,
2573    ) -> TestAddrCase {
2574        TestAddrCase {
2575            expected_request_args: None,
2576            expected_response: Some(ExpectedResponse::Error(errno)),
2577            ..valid_new_addr_request(ack, addr, interface_id, Ok(()))
2578        }
2579    }
2580
2581    fn valid_del_addr_request(
2582        ack: bool,
2583        addr: AddrSubnetEither,
2584        interface_id: u64,
2585        response: Result<(), interfaces::RequestError>,
2586    ) -> TestAddrCase {
2587        valid_new_del_addr_request(AddressRequestKind::Del, ack, addr, None, interface_id, response)
2588    }
2589
2590    fn invalid_del_addr_request(
2591        ack: bool,
2592        addr: AddrSubnetEither,
2593        interface_id: u64,
2594        errno: Errno,
2595    ) -> TestAddrCase {
2596        TestAddrCase {
2597            expected_request_args: None,
2598            expected_response: Some(ExpectedResponse::Error(errno)),
2599            ..valid_del_addr_request(ack, addr, interface_id, Ok(()))
2600        }
2601    }
2602
2603    fn new_del_addr_request_from_subnet(
2604        kind: AddressRequestKind,
2605        ack: bool,
2606        subnet: SubnetEither,
2607        interface_id: u64,
2608    ) -> TestAddrCase {
2609        let (net, prefix) = subnet.net_prefix();
2610        TestAddrCase {
2611            kind,
2612            flags: if ack { NLM_F_ACK } else { 0 },
2613            family: match subnet {
2614                SubnetEither::V4(_) => AF_INET as u16,
2615                SubnetEither::V6(_) => AF_INET6 as u16,
2616            },
2617            nlas: vec![AddressAttribute::Local(net.into())],
2618            prefix_len: prefix,
2619            interface_id: interface_id_as_u32(interface_id),
2620            expected_request_args: None,
2621            expected_response: ack.then_some(ExpectedResponse::Ack),
2622        }
2623    }
2624
2625    /// Test RTM_NEWADDR and RTM_DELADDR
2626    // Add address tests cases.
2627    #[test_case(
2628        new_del_addr_request_from_subnet(
2629            AddressRequestKind::New { add_subnet_route: true, replace: false },
2630            true,
2631            net_subnet_v4!("0.0.0.0/0").into(),
2632            interfaces::testutil::PPP_INTERFACE_ID,
2633        ); "new_v4_unspecified_address_zero_prefix_ok_ack")]
2634    #[test_case(
2635        new_del_addr_request_from_subnet(
2636            AddressRequestKind::New { add_subnet_route: true, replace: false },
2637            false,
2638            net_subnet_v4!("0.0.0.0/24").into(),
2639            interfaces::testutil::PPP_INTERFACE_ID,
2640        ); "new_v4_unspecified_address_non_zero_prefix_ok_no_ack")]
2641    #[test_case(
2642        TestAddrCase {
2643            expected_response: Some(ExpectedResponse::Error(Errno::EADDRNOTAVAIL)),
2644            ..new_del_addr_request_from_subnet(
2645                AddressRequestKind::New { add_subnet_route: true, replace: false },
2646                true,
2647                net_subnet_v6!("::/0").into(),
2648                interfaces::testutil::ETH_INTERFACE_ID,
2649            )
2650        }; "new_v6_unspecified_address_zero_prefix_ack")]
2651    #[test_case(
2652        TestAddrCase {
2653            expected_response: Some(ExpectedResponse::Error(Errno::EADDRNOTAVAIL)),
2654            ..new_del_addr_request_from_subnet(
2655                AddressRequestKind::New { add_subnet_route: true, replace: false },
2656                false,
2657                net_subnet_v6!("::/64").into(),
2658                interfaces::testutil::ETH_INTERFACE_ID,
2659            )
2660        }; "new_v6_unspecified_address_non_zero_prefix_no_ack")]
2661    #[test_case(
2662        valid_new_addr_request(
2663            true,
2664            interfaces::testutil::test_addr_subnet_v4(),
2665            interfaces::testutil::LO_INTERFACE_ID,
2666            Ok(())); "new_v4_ok_ack")]
2667    #[test_case(
2668        valid_new_addr_request(
2669            true,
2670            interfaces::testutil::test_addr_subnet_v6(),
2671            interfaces::testutil::LO_INTERFACE_ID,
2672            Ok(())); "new_v6_ok_ack")]
2673    #[test_case(
2674        valid_new_addr_request(
2675            false,
2676            interfaces::testutil::test_addr_subnet_v4(),
2677            interfaces::testutil::ETH_INTERFACE_ID,
2678            Ok(())); "new_v4_ok_no_ack")]
2679    #[test_case(
2680        valid_new_addr_request(
2681            false,
2682            interfaces::testutil::test_addr_subnet_v6(),
2683            interfaces::testutil::ETH_INTERFACE_ID,
2684            Ok(())); "new_v6_ok_no_ack")]
2685    #[test_case(
2686        TestAddrCase {
2687            nlas: vec![
2688                AddressAttribute::Local(ip_from_addr(interfaces::testutil::test_addr_subnet_v4())),
2689            ],
2690            ..valid_new_addr_request(
2691                false,
2692                interfaces::testutil::test_addr_subnet_v4(),
2693                interfaces::testutil::ETH_INTERFACE_ID,
2694                Ok(()),
2695            )
2696        }; "new_v4_local_nla_ok_no_ack")]
2697    #[test_case(
2698        TestAddrCase {
2699            nlas: vec![
2700                AddressAttribute::Address(ip_from_addr(interfaces::testutil::test_addr_subnet_v6())),
2701            ],
2702            ..valid_new_addr_request(
2703                true,
2704                interfaces::testutil::test_addr_subnet_v6(),
2705                interfaces::testutil::PPP_INTERFACE_ID,
2706                Ok(()),
2707            )
2708        }; "new_v6_address_nla_ok_ack")]
2709    #[test_case(
2710        TestAddrCase {
2711            nlas: vec![
2712                AddressAttribute::Address(ip_from_addr(interfaces::testutil::test_addr_subnet_v6())),
2713                AddressAttribute::Local(ip_from_addr(interfaces::testutil::test_addr_subnet_v6())),
2714            ],
2715            ..valid_new_addr_request(
2716                false,
2717                interfaces::testutil::test_addr_subnet_v6(),
2718                interfaces::testutil::PPP_INTERFACE_ID,
2719                Ok(()),
2720            )
2721        }; "new_v6_same_local_and_address_nla_ok_no_ack")]
2722    #[test_case(
2723        TestAddrCase {
2724            kind: AddressRequestKind::New { add_subnet_route: true, replace: false },
2725            ..valid_new_addr_request_with_extra_nlas(
2726                false,
2727                interfaces::testutil::test_addr_subnet_v4(),
2728                [AddressAttribute::Flags(AddressFlags::empty())],
2729                interfaces::testutil::ETH_INTERFACE_ID,
2730                Ok(()),
2731            )
2732        }; "new_v4_with_route_ok_no_ack")]
2733    #[test_case(
2734        TestAddrCase {
2735            kind: AddressRequestKind::New { add_subnet_route: false, replace: false },
2736            ..valid_new_addr_request_with_extra_nlas(
2737                true,
2738                interfaces::testutil::test_addr_subnet_v6(),
2739                [AddressAttribute::Flags(AddressFlags::from_bits(IFA_F_NOPREFIXROUTE).unwrap())],
2740                interfaces::testutil::LO_INTERFACE_ID,
2741                Ok(()),
2742            )
2743        }; "new_v6_without_route_ok_ack")]
2744    #[test_case(
2745        TestAddrCase {
2746            flags: NLM_F_REPLACE | NLM_F_ACK,
2747            kind: AddressRequestKind::New { add_subnet_route: true, replace: true },
2748            ..valid_new_addr_request(
2749                true,
2750                interfaces::testutil::test_addr_subnet_v4(),
2751                interfaces::testutil::ETH_INTERFACE_ID,
2752                Ok(()),
2753            )
2754        }; "new_v4_replace_ack")]
2755    #[test_case(
2756        TestAddrCase {
2757            flags: NLM_F_REPLACE,
2758            kind: AddressRequestKind::New { add_subnet_route: true, replace: true },
2759            ..valid_new_addr_request(
2760                false,
2761                interfaces::testutil::test_addr_subnet_v6(),
2762                interfaces::testutil::ETH_INTERFACE_ID,
2763                Ok(()),
2764            )
2765        }; "new_v6_replace_no_ack")]
2766    #[test_case(
2767        TestAddrCase {
2768            flags: NLM_F_REPLACE | NLM_F_EXCL | NLM_F_ACK,
2769            kind: AddressRequestKind::New { add_subnet_route: true, replace: false },
2770            ..valid_new_addr_request(
2771                true,
2772                interfaces::testutil::test_addr_subnet_v4(),
2773                interfaces::testutil::ETH_INTERFACE_ID,
2774                Ok(()),
2775            )
2776        }; "new_v4_replace_excl_ack")]
2777    #[test_case(
2778        TestAddrCase {
2779            expected_response: Some(ExpectedResponse::Error(Errno::EINVAL)),
2780            ..valid_new_addr_request(
2781                true,
2782                interfaces::testutil::test_addr_subnet_v4(),
2783                interfaces::testutil::LO_INTERFACE_ID,
2784                Err(interfaces::RequestError::InvalidRequest),
2785            )
2786        }; "new_v4_invalid_response_ack")]
2787    #[test_case(
2788        TestAddrCase {
2789            expected_response: Some(ExpectedResponse::Error(Errno::EEXIST)),
2790            ..valid_new_addr_request(
2791                false,
2792                interfaces::testutil::test_addr_subnet_v6(),
2793                interfaces::testutil::LO_INTERFACE_ID,
2794                Err(interfaces::RequestError::AlreadyExists),
2795            )
2796        }; "new_v6_exist_response_no_ack")]
2797    #[test_case(
2798        TestAddrCase {
2799            expected_response: Some(ExpectedResponse::Error(Errno::ENODEV)),
2800            ..valid_new_addr_request(
2801                false,
2802                interfaces::testutil::test_addr_subnet_v6(),
2803                interfaces::testutil::WLAN_INTERFACE_ID,
2804                Err(interfaces::RequestError::UnrecognizedInterface),
2805            )
2806        }; "new_v6_unrecognized_interface_response_no_ack")]
2807    #[test_case(
2808        TestAddrCase {
2809            expected_response: Some(ExpectedResponse::Error(Errno::EADDRNOTAVAIL)),
2810            ..valid_new_addr_request(
2811                true,
2812                interfaces::testutil::test_addr_subnet_v4(),
2813                interfaces::testutil::ETH_INTERFACE_ID,
2814                Err(interfaces::RequestError::AddressNotFound),
2815            )
2816        }; "new_v4_not_found_response_ck")]
2817    #[test_case(
2818        TestAddrCase {
2819            interface_id: 0,
2820            ..invalid_new_addr_request(
2821                true,
2822                interfaces::testutil::test_addr_subnet_v6(),
2823                interfaces::testutil::LO_INTERFACE_ID,
2824                Errno::EINVAL,
2825            )
2826        }; "new_zero_interface_id_ack")]
2827    #[test_case(
2828        TestAddrCase {
2829            interface_id: 0,
2830            ..invalid_new_addr_request(
2831                false,
2832                interfaces::testutil::test_addr_subnet_v4(),
2833                interfaces::testutil::WLAN_INTERFACE_ID,
2834                Errno::EINVAL,
2835            )
2836        }; "new_zero_interface_id_no_ack")]
2837    #[test_case(
2838        TestAddrCase {
2839            nlas: Vec::new(),
2840            ..invalid_new_addr_request(
2841                true,
2842                interfaces::testutil::test_addr_subnet_v4(),
2843                interfaces::testutil::WLAN_INTERFACE_ID,
2844                Errno::EINVAL,
2845            )
2846        }; "new_no_nlas_ack")]
2847    #[test_case(
2848        TestAddrCase {
2849            nlas: Vec::new(),
2850            ..invalid_new_addr_request(
2851                false,
2852                interfaces::testutil::test_addr_subnet_v6(),
2853                interfaces::testutil::WLAN_INTERFACE_ID,
2854                Errno::EINVAL,
2855            )
2856        }; "new_no_nlas_no_ack")]
2857    #[test_case(
2858        TestAddrCase {
2859            nlas: vec![AddressAttribute::Flags(AddressFlags::empty())],
2860            ..invalid_new_addr_request(
2861                true,
2862                interfaces::testutil::test_addr_subnet_v4(),
2863                interfaces::testutil::WLAN_INTERFACE_ID,
2864                Errno::EINVAL,
2865            )
2866        }; "new_missing_address_and_local_nla_ack")]
2867    #[test_case(
2868        TestAddrCase {
2869            nlas: vec![AddressAttribute::Flags(AddressFlags::empty())],
2870            ..invalid_new_addr_request(
2871                false,
2872                interfaces::testutil::test_addr_subnet_v6(),
2873                interfaces::testutil::WLAN_INTERFACE_ID,
2874                Errno::EINVAL,
2875            )
2876        }; "new_missing_address_and_local_nla_no_ack")]
2877    #[test_case(
2878        TestAddrCase {
2879            prefix_len: 0,
2880            kind: AddressRequestKind::New { add_subnet_route: false, replace: false },
2881            ..valid_new_addr_request(
2882                true,
2883                net_addr_subnet!("192.0.2.123/0"),
2884                interfaces::testutil::WLAN_INTERFACE_ID,
2885                Ok(()),
2886            )
2887        }; "new_zero_prefix_len_ack")]
2888    #[test_case(
2889        TestAddrCase {
2890            prefix_len: 0,
2891            ..valid_new_addr_request(
2892                false,
2893                net_addr_subnet!("2001:db8::1324/0"),
2894                interfaces::testutil::WLAN_INTERFACE_ID,
2895                Ok(()),
2896            )
2897        }; "new_zero_prefix_len_no_ack")]
2898    #[test_case(
2899        TestAddrCase {
2900            prefix_len: u8::MAX,
2901            ..invalid_new_addr_request(
2902                true,
2903                interfaces::testutil::test_addr_subnet_v4(),
2904                interfaces::testutil::WLAN_INTERFACE_ID,
2905                Errno::EINVAL,
2906            )
2907        }; "new_invalid_prefix_len_ack")]
2908    #[test_case(
2909        TestAddrCase {
2910            prefix_len: u8::MAX,
2911            ..invalid_new_addr_request(
2912                false,
2913                interfaces::testutil::test_addr_subnet_v6(),
2914                interfaces::testutil::WLAN_INTERFACE_ID,
2915                Errno::EINVAL,
2916            )
2917        }; "new_invalid_prefix_len_no_ack")]
2918    #[test_case(
2919        TestAddrCase {
2920            family: AF_UNSPEC as u16,
2921            ..invalid_new_addr_request(
2922                true,
2923                interfaces::testutil::test_addr_subnet_v4(),
2924                interfaces::testutil::LO_INTERFACE_ID,
2925                Errno::EINVAL,
2926            )
2927        }; "new_invalid_family_ack")]
2928    #[test_case(
2929        TestAddrCase {
2930            family: AF_UNSPEC as u16,
2931            ..invalid_new_addr_request(
2932                false,
2933                interfaces::testutil::test_addr_subnet_v6(),
2934                interfaces::testutil::PPP_INTERFACE_ID,
2935                Errno::EINVAL,
2936            )
2937        }; "new_invalid_family_no_ack")]
2938    // Delete address tests cases.
2939    #[test_case(
2940        valid_del_addr_request(
2941            true,
2942            interfaces::testutil::test_addr_subnet_v4(),
2943            interfaces::testutil::LO_INTERFACE_ID,
2944            Ok(())); "del_v4_ok_ack")]
2945    #[test_case(
2946        valid_del_addr_request(
2947            true,
2948            interfaces::testutil::test_addr_subnet_v6(),
2949            interfaces::testutil::LO_INTERFACE_ID,
2950            Ok(())); "del_v6_ok_ack")]
2951    #[test_case(
2952        valid_del_addr_request(
2953            false,
2954            interfaces::testutil::test_addr_subnet_v4(),
2955            interfaces::testutil::ETH_INTERFACE_ID,
2956            Ok(())); "del_v4_ok_no_ack")]
2957    #[test_case(
2958        valid_del_addr_request(
2959            false,
2960            interfaces::testutil::test_addr_subnet_v6(),
2961            interfaces::testutil::ETH_INTERFACE_ID,
2962            Ok(())); "del_v6_ok_no_ack")]
2963    #[test_case(
2964        TestAddrCase {
2965            expected_response: Some(ExpectedResponse::Error(Errno::EINVAL)),
2966            ..valid_del_addr_request(
2967                true,
2968                interfaces::testutil::test_addr_subnet_v4(),
2969                interfaces::testutil::LO_INTERFACE_ID,
2970                Err(interfaces::RequestError::InvalidRequest),
2971            )
2972        }; "del_v4_invalid_response_ack")]
2973    #[test_case(
2974        TestAddrCase {
2975            nlas: vec![
2976                AddressAttribute::Local(ip_from_addr(interfaces::testutil::test_addr_subnet_v4())),
2977            ],
2978            ..valid_del_addr_request(
2979                false,
2980                interfaces::testutil::test_addr_subnet_v4(),
2981                interfaces::testutil::ETH_INTERFACE_ID,
2982                Ok(()),
2983            )
2984        }; "del_v4_local_nla_ok_no_ack")]
2985    #[test_case(
2986        TestAddrCase {
2987            nlas: vec![
2988                AddressAttribute::Address(ip_from_addr(interfaces::testutil::test_addr_subnet_v6())),
2989            ],
2990            ..valid_del_addr_request(
2991                true,
2992                interfaces::testutil::test_addr_subnet_v6(),
2993                interfaces::testutil::PPP_INTERFACE_ID,
2994                Ok(()),
2995            )
2996        }; "del_v6_address_nla_ok_ack")]
2997    #[test_case(
2998        TestAddrCase {
2999            nlas: vec![
3000                AddressAttribute::Address(ip_from_addr(interfaces::testutil::test_addr_subnet_v4())),
3001                AddressAttribute::Local(ip_from_addr(interfaces::testutil::test_addr_subnet_v4())),
3002            ],
3003            ..valid_del_addr_request(
3004                true,
3005                interfaces::testutil::test_addr_subnet_v4(),
3006                interfaces::testutil::ETH_INTERFACE_ID,
3007                Ok(()),
3008            )
3009        }; "del_v4_same_local_and_address_nla_ok_ack")]
3010    #[test_case(
3011        TestAddrCase {
3012            expected_response: Some(ExpectedResponse::Error(Errno::EEXIST)),
3013            ..valid_del_addr_request(
3014                false,
3015                interfaces::testutil::test_addr_subnet_v6(),
3016                interfaces::testutil::LO_INTERFACE_ID,
3017                Err(interfaces::RequestError::AlreadyExists),
3018            )
3019        }; "del_v6_exist_response_no_ack")]
3020    #[test_case(
3021        TestAddrCase {
3022            expected_response: Some(ExpectedResponse::Error(Errno::ENODEV)),
3023            ..valid_del_addr_request(
3024                false,
3025                interfaces::testutil::test_addr_subnet_v6(),
3026                interfaces::testutil::WLAN_INTERFACE_ID,
3027                Err(interfaces::RequestError::UnrecognizedInterface),
3028            )
3029        }; "del_v6_unrecognized_interface_response_no_ack")]
3030    #[test_case(
3031        TestAddrCase {
3032            expected_response: Some(ExpectedResponse::Error(Errno::EADDRNOTAVAIL)),
3033            ..valid_del_addr_request(
3034                true,
3035                interfaces::testutil::test_addr_subnet_v4(),
3036                interfaces::testutil::ETH_INTERFACE_ID,
3037                Err(interfaces::RequestError::AddressNotFound),
3038            )
3039        }; "del_v4_not_found_response_ck")]
3040    #[test_case(
3041        TestAddrCase {
3042            interface_id: 0,
3043            ..invalid_del_addr_request(
3044                true,
3045                interfaces::testutil::test_addr_subnet_v6(),
3046                interfaces::testutil::LO_INTERFACE_ID,
3047                Errno::EINVAL,
3048            )
3049        }; "del_zero_interface_id_ack")]
3050    #[test_case(
3051        TestAddrCase {
3052            interface_id: 0,
3053            ..invalid_del_addr_request(
3054                false,
3055                interfaces::testutil::test_addr_subnet_v4(),
3056                interfaces::testutil::WLAN_INTERFACE_ID,
3057                Errno::EINVAL,
3058            )
3059        }; "del_zero_interface_id_no_ack")]
3060    #[test_case(
3061        TestAddrCase {
3062            nlas: Vec::new(),
3063            ..invalid_del_addr_request(
3064                true,
3065                interfaces::testutil::test_addr_subnet_v4(),
3066                interfaces::testutil::WLAN_INTERFACE_ID,
3067                Errno::EINVAL,
3068            )
3069        }; "del_no_nlas_ack")]
3070    #[test_case(
3071        TestAddrCase {
3072            nlas: Vec::new(),
3073            ..invalid_del_addr_request(
3074                false,
3075                interfaces::testutil::test_addr_subnet_v6(),
3076                interfaces::testutil::WLAN_INTERFACE_ID,
3077                Errno::EINVAL,
3078            )
3079        }; "del_no_nlas_no_ack")]
3080    #[test_case(
3081        TestAddrCase {
3082            nlas: vec![AddressAttribute::Flags(AddressFlags::empty())],
3083            ..invalid_del_addr_request(
3084                true,
3085                interfaces::testutil::test_addr_subnet_v4(),
3086                interfaces::testutil::WLAN_INTERFACE_ID,
3087                Errno::EINVAL,
3088            )
3089        }; "del_missing_address_and_local_nla_ack")]
3090    #[test_case(
3091        TestAddrCase {
3092            nlas: vec![AddressAttribute::Flags(AddressFlags::empty())],
3093            ..invalid_del_addr_request(
3094                false,
3095                interfaces::testutil::test_addr_subnet_v6(),
3096                interfaces::testutil::WLAN_INTERFACE_ID,
3097                Errno::EINVAL,
3098            )
3099        }; "del_missing_address_and_local_nla_no_ack")]
3100    #[test_case(
3101        TestAddrCase {
3102            prefix_len: 0,
3103            ..valid_del_addr_request(
3104                true,
3105                net_addr_subnet!("192.0.2.123/0"),
3106                interfaces::testutil::WLAN_INTERFACE_ID,
3107                Ok(()),
3108            )
3109        }; "del_zero_prefix_len_ack")]
3110    #[test_case(
3111        TestAddrCase {
3112            prefix_len: 0,
3113            ..valid_del_addr_request(
3114                false,
3115                net_addr_subnet!("2001:db8::1324/0"),
3116                interfaces::testutil::WLAN_INTERFACE_ID,
3117                Ok(()),
3118            )
3119        }; "del_zero_prefix_len_no_ack")]
3120    #[test_case(
3121        TestAddrCase {
3122            prefix_len: u8::MAX,
3123            ..invalid_del_addr_request(
3124                true,
3125                interfaces::testutil::test_addr_subnet_v4(),
3126                interfaces::testutil::WLAN_INTERFACE_ID,
3127                Errno::EINVAL,
3128            )
3129        }; "del_invalid_prefix_len_ack")]
3130    #[test_case(
3131        TestAddrCase {
3132            prefix_len: u8::MAX,
3133            ..invalid_del_addr_request(
3134                false,
3135                interfaces::testutil::test_addr_subnet_v6(),
3136                interfaces::testutil::WLAN_INTERFACE_ID,
3137                Errno::EINVAL,
3138            )
3139        }; "del_invalid_prefix_len_no_ack")]
3140    #[test_case(
3141        TestAddrCase {
3142            family: AF_UNSPEC as u16,
3143            ..invalid_del_addr_request(
3144                true,
3145                interfaces::testutil::test_addr_subnet_v4(),
3146                interfaces::testutil::LO_INTERFACE_ID,
3147                Errno::EINVAL,
3148            )
3149        }; "del_invalid_family_ack")]
3150    #[test_case(
3151        TestAddrCase {
3152            family: AF_UNSPEC as u16,
3153            ..invalid_del_addr_request(
3154                false,
3155                interfaces::testutil::test_addr_subnet_v6(),
3156                interfaces::testutil::PPP_INTERFACE_ID,
3157                Errno::EINVAL,
3158            )
3159        }; "del_invalid_family_no_ack")]
3160    #[fuchsia::test]
3161    async fn test_new_del_addr(test_case: TestAddrCase) {
3162        let TestAddrCase {
3163            kind,
3164            flags,
3165            family,
3166            nlas,
3167            prefix_len,
3168            interface_id,
3169            expected_request_args,
3170            expected_response,
3171        } = test_case;
3172
3173        let header = header_with_flags(flags);
3174        let address_message = {
3175            let mut message = AddressMessage::default();
3176            // Conversion is safe because family is guaranteed to fit into an 8-bit integer.
3177            message.header.family = AddressFamily::from(family as u8).into();
3178            message.header.index = interface_id.into();
3179            message.header.prefix_len = prefix_len;
3180            message.attributes = nlas;
3181            message
3182        };
3183
3184        let (message, request) = match kind {
3185            AddressRequestKind::New { add_subnet_route, replace } => (
3186                RouteNetlinkMessage::NewAddress(address_message),
3187                expected_request_args.map(|RequestAndResponse { request, response }| {
3188                    RequestAndResponse {
3189                        request: interfaces::RequestArgs::Address(
3190                            interfaces::AddressRequestArgs::New(interfaces::NewAddressArgs {
3191                                address_and_interface_id: request,
3192                                add_subnet_route,
3193                                replace,
3194                            }),
3195                        ),
3196                        response,
3197                    }
3198                }),
3199            ),
3200            AddressRequestKind::Del => (
3201                RouteNetlinkMessage::DelAddress(address_message),
3202                expected_request_args.map(|RequestAndResponse { request, response }| {
3203                    RequestAndResponse {
3204                        request: interfaces::RequestArgs::Address(
3205                            interfaces::AddressRequestArgs::Del(interfaces::DelAddressArgs {
3206                                address_and_interface_id: request,
3207                            }),
3208                        ),
3209                        response,
3210                    }
3211                }),
3212            ),
3213        };
3214
3215        pretty_assertions::assert_eq!(
3216            test_request(
3217                NetlinkMessage::new(header, NetlinkPayload::InnerMessage(message),),
3218                request,
3219            )
3220            .await,
3221            expected_sent_messages(expected_response, header),
3222        )
3223    }
3224
3225    /// Given a stream of `UnifiedRequest`s and sinks for v4 and v6 routes
3226    /// requests, feeds the v4 and v6 routes requests from the stream into the
3227    /// appropriate sinks, discarding other requests.
3228    async fn split_route_requests(
3229        unified_request_stream: mpsc::Receiver<UnifiedRequest<FakeSender<RouteNetlinkMessage>>>,
3230        v4_routes_request_sink: mpsc::Sender<
3231            crate::routes::Request<FakeSender<RouteNetlinkMessage>, Ipv4>,
3232        >,
3233        v6_routes_request_sink: mpsc::Sender<
3234            crate::routes::Request<FakeSender<RouteNetlinkMessage>, Ipv6>,
3235        >,
3236    ) {
3237        unified_request_stream
3238            .fold(
3239                (v4_routes_request_sink, v6_routes_request_sink),
3240                |(mut v4_routes_request_sink, mut v6_routes_request_sink), req| async move {
3241                    match req {
3242                        UnifiedRequest::RoutesV4Request(req) => {
3243                            v4_routes_request_sink
3244                                .send(req)
3245                                .map(|res| res.expect("send should succeed"))
3246                                .await
3247                        }
3248                        UnifiedRequest::RoutesV6Request(req) => {
3249                            v6_routes_request_sink
3250                                .send(req)
3251                                .map(|res| res.expect("send should succeed"))
3252                                .await
3253                        }
3254                        _ => (),
3255                    };
3256                    (v4_routes_request_sink, v6_routes_request_sink)
3257                },
3258            )
3259            .map(|(_v4_sink, _v6_sink)| ())
3260            .await
3261    }
3262
3263    // Separate from `test_route_request`, because RTM_GETROUTE requests do not have typed
3264    // arguments and there needs to be an option to send a DUMP request to the
3265    // v4 and v6 routes worker.
3266    async fn test_get_route_request(
3267        family: u16,
3268        request: NetlinkMessage<RouteNetlinkMessage>,
3269        expected_request: Option<routes::GetRouteArgs>,
3270    ) -> Vec<SentMessage<RouteNetlinkMessage>> {
3271        let (mut client_sink, mut client, async_work_drain_task) =
3272            crate::client::testutil::new_fake_client::<NetlinkRoute>(
3273                crate::client::testutil::CLIENT_ID_1,
3274                std::iter::empty(),
3275            );
3276        let join_handle = fasync::Task::spawn(async_work_drain_task);
3277
3278        {
3279            let (unified_request_sink, unified_request_stream) = mpsc::channel(0);
3280
3281            let mut handler = NetlinkRouteRequestHandler::<FakeSender<_>> { unified_request_sink };
3282
3283            let (v4_routes_request_sink, mut v4_routes_request_stream) = mpsc::channel(0);
3284            let (v6_routes_request_sink, mut v6_routes_request_stream) = mpsc::channel(0);
3285
3286            let mut split_route_requests_background_work = pin!(
3287                split_route_requests(
3288                    unified_request_stream,
3289                    v4_routes_request_sink,
3290                    v6_routes_request_sink,
3291                )
3292                .fuse()
3293            );
3294
3295            let mut handler_fut = pin!(
3296                futures::future::join(handler.handle_request(request, &mut client), async {
3297                    // Conversions are safe as constants can fit into 16-bit integers.
3298                    if family == AF_UNSPEC as u16 || family == AF_INET as u16 {
3299                        let next = v4_routes_request_stream.next();
3300                        match expected_request.map(|a| {
3301                            routes::RequestArgs::<Ipv4>::Route(routes::RouteRequestArgs::Get(a))
3302                        }) {
3303                            Some(expected_request) => {
3304                                let routes::Request {
3305                                    args,
3306                                    sequence_number: _,
3307                                    client: _,
3308                                    completer,
3309                                } = next.await.expect("handler should send request");
3310                                assert_eq!(args, expected_request);
3311                                completer.send(Ok(())).expect("handler should be alive");
3312                            }
3313                            None => assert_matches!(next.now_or_never(), None),
3314                        };
3315                    }
3316                    if family == AF_UNSPEC as u16 || family == AF_INET6 as u16 {
3317                        let next = v6_routes_request_stream.next();
3318                        match expected_request.map(|a| {
3319                            routes::RequestArgs::<Ipv6>::Route(routes::RouteRequestArgs::Get(a))
3320                        }) {
3321                            Some(expected_request) => {
3322                                let routes::Request {
3323                                    args,
3324                                    sequence_number: _,
3325                                    client: _,
3326                                    completer,
3327                                } = next.await.expect("handler should send request");
3328                                assert_eq!(args, expected_request);
3329                                completer.send(Ok(())).expect("handler should be alive");
3330                            }
3331                            None => assert_matches!(next.now_or_never(), None),
3332                        };
3333                    }
3334                })
3335                .fuse()
3336            );
3337
3338            futures::select! {
3339                ((), ()) = handler_fut => (),
3340                () = split_route_requests_background_work => unreachable!(),
3341            };
3342        }
3343        drop(client);
3344        join_handle.await;
3345        client_sink.take_messages()
3346    }
3347
3348    /// Test RTM_GETROUTE.
3349    /// Conversions are safe as constants fit within 16-bit integers.
3350    #[test_case(
3351        0,
3352        AF_UNSPEC as u16,
3353        None,
3354        None; "af_unspec_no_flags")]
3355    #[test_case(
3356        NLM_F_ACK,
3357        AF_UNSPEC as u16,
3358        None,
3359        Some(ExpectedResponse::Ack); "af_unspec_ack_flag")]
3360    #[test_case(
3361        NLM_F_DUMP,
3362        AF_UNSPEC as u16,
3363        Some(routes::GetRouteArgs::Dump),
3364        Some(ExpectedResponse::Done); "af_unspec_dump_flag")]
3365    #[test_case(
3366        NLM_F_DUMP | NLM_F_ACK,
3367        AF_UNSPEC as u16,
3368        Some(routes::GetRouteArgs::Dump),
3369        Some(ExpectedResponse::Done); "af_unspec_dump_and_ack_flags")]
3370    #[test_case(
3371        0,
3372        AF_INET as u16,
3373        None,
3374        None; "af_inet_no_flags")]
3375    #[test_case(
3376        NLM_F_ACK,
3377        AF_INET as u16,
3378        None,
3379        Some(ExpectedResponse::Ack); "af_inet_ack_flag")]
3380    #[test_case(
3381        NLM_F_DUMP,
3382        AF_INET as u16,
3383        Some(routes::GetRouteArgs::Dump),
3384        Some(ExpectedResponse::Done); "af_inet_dump_flag")]
3385    #[test_case(
3386        NLM_F_DUMP | NLM_F_ACK,
3387        AF_INET as u16,
3388        Some(routes::GetRouteArgs::Dump),
3389        Some(ExpectedResponse::Done); "af_inet_dump_and_ack_flags")]
3390    #[test_case(
3391        0,
3392        AF_INET6 as u16,
3393        None,
3394        None; "af_inet6_no_flags")]
3395    #[test_case(
3396        NLM_F_ACK,
3397        AF_INET6 as u16,
3398        None,
3399        Some(ExpectedResponse::Ack); "af_inet6_ack_flag")]
3400    #[test_case(
3401        NLM_F_DUMP,
3402        AF_INET6 as u16,
3403        Some(routes::GetRouteArgs::Dump),
3404        Some(ExpectedResponse::Done); "af_inet6_dump_flag")]
3405    #[test_case(
3406        NLM_F_DUMP | NLM_F_ACK,
3407        AF_INET6 as u16,
3408        Some(routes::GetRouteArgs::Dump),
3409        Some(ExpectedResponse::Done); "af_inet6_dump_and_ack_flags")]
3410    #[test_case(
3411        0,
3412        AF_PACKET,
3413        None,
3414        None; "af_other_no_flags")]
3415    #[test_case(
3416        NLM_F_ACK,
3417        AF_PACKET,
3418        None,
3419        Some(ExpectedResponse::Ack); "af_other_ack_flag")]
3420    #[test_case(
3421        NLM_F_DUMP,
3422        AF_PACKET,
3423        None,
3424        Some(ExpectedResponse::Error(Errno::EINVAL)); "af_other_dump_flag")]
3425    #[test_case(
3426        NLM_F_DUMP | NLM_F_ACK,
3427        AF_PACKET,
3428        None,
3429        Some(ExpectedResponse::Error(Errno::EINVAL)); "af_other_dump_and_ack_flags")]
3430    #[fuchsia::test]
3431    async fn test_get_route(
3432        flags: u16,
3433        family: u16,
3434        expected_request_args: Option<routes::GetRouteArgs>,
3435        expected_response: Option<ExpectedResponse>,
3436    ) {
3437        let header = header_with_flags(flags);
3438        let route_message = {
3439            let mut message = RouteMessage::default();
3440            message.header.address_family = AddressFamily::from(family as u8);
3441            message
3442        };
3443
3444        pretty_assertions::assert_eq!(
3445            test_get_route_request(
3446                family,
3447                NetlinkMessage::new(
3448                    header,
3449                    NetlinkPayload::InnerMessage(RouteNetlinkMessage::GetRoute(route_message)),
3450                ),
3451                expected_request_args,
3452            )
3453            .await,
3454            expected_sent_messages(expected_response, header)
3455        )
3456    }
3457
3458    /// Represents a single expected request, and the fake response.
3459    #[derive(Debug)]
3460    pub(crate) struct FakeRuleRequestResponse {
3461        pub(crate) expected_request_args: RuleRequestArgs,
3462        pub(crate) expected_ip_version: IpVersion,
3463        pub(crate) response: Result<(), Errno>,
3464    }
3465
3466    /// A fake implementation of [`RuleRequestHandler`].
3467    ///
3468    /// Handles a sequence of rule requests by pulling the expected request
3469    /// and fake response from the front of `requests_and_responses`.
3470    #[derive(Clone, Debug)]
3471    pub(crate) struct FakeRuleRequestHandler {
3472        pub(crate) requests_and_responses: Arc<Mutex<VecDeque<FakeRuleRequestResponse>>>,
3473    }
3474
3475    impl FakeRuleRequestHandler {
3476        fn new(requests_and_responses: impl IntoIterator<Item = FakeRuleRequestResponse>) -> Self {
3477            FakeRuleRequestHandler {
3478                requests_and_responses: Arc::new(Mutex::new(VecDeque::from_iter(
3479                    requests_and_responses,
3480                ))),
3481            }
3482        }
3483
3484        fn handle_request<S: Sender<RouteNetlinkMessage>, I: Ip>(
3485            &mut self,
3486            actual_request: RuleRequest<S, I>,
3487        ) -> Result<(), Errno> {
3488            let Self { requests_and_responses } = self;
3489            let FakeRuleRequestResponse { expected_request_args, expected_ip_version, response } =
3490                requests_and_responses.lock().pop_front().expect(
3491                    "FakeRuleRequest handler should have a fake request/response pre-configured",
3492                );
3493            let RuleRequest { args, _ip_version_marker, sequence_number: _, client: _ } =
3494                actual_request;
3495            assert_eq!(args, expected_request_args);
3496            assert_eq!(I::VERSION, expected_ip_version);
3497            response
3498        }
3499    }
3500
3501    fn default_rule_for_family(family: u16) -> RuleMessage {
3502        let mut rule = RuleMessage::default();
3503        // Conversion is safe as family is guaranteed to fit into an 8-bit integer.
3504        rule.header.family = AddressFamily::from(family as u8);
3505        rule
3506    }
3507
3508    const AF_INVALID: u16 = 255;
3509    /// Conversions are safe as constants fit into a 16-bit integer.
3510    #[test_case(
3511        RouteNetlinkMessage::GetRule,
3512        0,
3513        AF_UNSPEC as u16,
3514        vec![],
3515        Some(ExpectedResponse::Error(Errno::ENOTSUP)); "get_rule_no_dump")]
3516    #[test_case(
3517        RouteNetlinkMessage::GetRule,
3518        NLM_F_DUMP,
3519        AF_INVALID,
3520        vec![],
3521        Some(ExpectedResponse::Error(Errno::EAFNOSUPPORT)); "get_rule_dump_invalid_address_family")]
3522    #[test_case(
3523        RouteNetlinkMessage::GetRule,
3524        NLM_F_DUMP,
3525        AF_INET as u16,
3526        vec![FakeRuleRequestResponse{
3527            expected_request_args: RuleRequestArgs::DumpRules,
3528            expected_ip_version: IpVersion::V4,
3529            response: Ok(()),
3530        }],
3531        Some(ExpectedResponse::Done); "get_rule_dump_v4")]
3532    #[test_case(
3533        RouteNetlinkMessage::GetRule,
3534        NLM_F_DUMP,
3535        AF_INET6 as u16,
3536        vec![FakeRuleRequestResponse{
3537            expected_request_args: RuleRequestArgs::DumpRules,
3538            expected_ip_version: IpVersion::V6,
3539            response: Ok(()),
3540        }],
3541        Some(ExpectedResponse::Done); "get_rule_dump_v6")]
3542    #[test_case(
3543        RouteNetlinkMessage::GetRule,
3544        NLM_F_DUMP,
3545        AF_UNSPEC as u16,
3546        vec![FakeRuleRequestResponse{
3547            expected_request_args: RuleRequestArgs::DumpRules,
3548            expected_ip_version: IpVersion::V4,
3549            response: Ok(()),
3550        },
3551        FakeRuleRequestResponse{
3552            expected_request_args: RuleRequestArgs::DumpRules,
3553            expected_ip_version: IpVersion::V6,
3554            response: Ok(()),
3555        }],
3556        Some(ExpectedResponse::Done); "get_rule_dump_af_unspec")]
3557    #[test_case(
3558        RouteNetlinkMessage::GetRule,
3559        NLM_F_DUMP,
3560        AF_INET as u16,
3561        vec![FakeRuleRequestResponse{
3562            expected_request_args: RuleRequestArgs::DumpRules,
3563            expected_ip_version: IpVersion::V4,
3564            response: Err(Errno::ENOTSUP),
3565        }],
3566        Some(ExpectedResponse::Error(Errno::ENOTSUP)); "get_rule_dump_v4_fails")]
3567    #[test_case(
3568        RouteNetlinkMessage::GetRule,
3569        NLM_F_DUMP,
3570        AF_INET6 as u16,
3571        vec![FakeRuleRequestResponse{
3572            expected_request_args: RuleRequestArgs::DumpRules,
3573            expected_ip_version: IpVersion::V6,
3574            response: Err(Errno::ENOTSUP),
3575        }],
3576        Some(ExpectedResponse::Error(Errno::ENOTSUP)); "get_rule_dump_v6_fails")]
3577    #[test_case(
3578        RouteNetlinkMessage::GetRule,
3579        NLM_F_DUMP,
3580        AF_UNSPEC as u16,
3581        vec![FakeRuleRequestResponse{
3582            expected_request_args: RuleRequestArgs::DumpRules,
3583            expected_ip_version: IpVersion::V4,
3584            response: Err(Errno::ENOTSUP),
3585        }],
3586        Some(ExpectedResponse::Error(Errno::ENOTSUP)); "get_rule_dump_af_unspec_v4_fails")]
3587    #[test_case(
3588        RouteNetlinkMessage::GetRule,
3589        NLM_F_DUMP,
3590        AF_UNSPEC as u16,
3591        vec![FakeRuleRequestResponse{
3592            expected_request_args: RuleRequestArgs::DumpRules,
3593            expected_ip_version: IpVersion::V4,
3594            response: Ok(()),
3595        },
3596        FakeRuleRequestResponse{
3597            expected_request_args: RuleRequestArgs::DumpRules,
3598            expected_ip_version: IpVersion::V6,
3599            response: Err(Errno::ENOTSUP),
3600        }],
3601        Some(ExpectedResponse::Error(Errno::ENOTSUP)); "get_rule_dump_af_unspec_v6_fails")]
3602    #[test_case(
3603        RouteNetlinkMessage::NewRule,
3604        0,
3605        AF_INET as u16,
3606        vec![FakeRuleRequestResponse{
3607            expected_request_args: RuleRequestArgs::New(default_rule_for_family(AF_INET as u16)),
3608            expected_ip_version: IpVersion::V4,
3609            response: Ok(()),
3610        }],
3611        None; "new_rule_succeeds_v4")]
3612    #[test_case(
3613        RouteNetlinkMessage::NewRule,
3614        0,
3615        AF_INET6 as u16,
3616        vec![FakeRuleRequestResponse{
3617            expected_request_args: RuleRequestArgs::New(default_rule_for_family(AF_INET6 as u16)),
3618            expected_ip_version: IpVersion::V6,
3619            response: Ok(()),
3620        }],
3621        None; "new_rule_succeeds_v6")]
3622    #[test_case(
3623        RouteNetlinkMessage::NewRule,
3624        0,
3625        AF_UNSPEC as u16,
3626        vec![],
3627        Some(ExpectedResponse::Error(Errno::EAFNOSUPPORT)); "new_rule_af_unspec_fails")]
3628    #[test_case(
3629        RouteNetlinkMessage::NewRule,
3630        NLM_F_ACK,
3631        AF_INET as u16,
3632        vec![FakeRuleRequestResponse{
3633            expected_request_args: RuleRequestArgs::New(default_rule_for_family(AF_INET as u16)),
3634            expected_ip_version: IpVersion::V4,
3635            response: Ok(()),
3636        }],
3637        Some(ExpectedResponse::Ack); "new_rule_v4_succeeds_with_ack")]
3638    #[test_case(
3639        RouteNetlinkMessage::NewRule,
3640        NLM_F_ACK,
3641        AF_INET6 as u16,
3642        vec![FakeRuleRequestResponse{
3643            expected_request_args: RuleRequestArgs::New(default_rule_for_family(AF_INET6 as u16)),
3644            expected_ip_version: IpVersion::V6,
3645            response: Ok(()),
3646        }],
3647        Some(ExpectedResponse::Ack); "new_rule_v6_succeeds_with_ack")]
3648    #[test_case(
3649        RouteNetlinkMessage::NewRule,
3650        0,
3651        AF_INET as u16,
3652        vec![FakeRuleRequestResponse{
3653            expected_request_args: RuleRequestArgs::New(default_rule_for_family(AF_INET as u16)),
3654            expected_ip_version: IpVersion::V4,
3655            response: Err(Errno::ENOTSUP),
3656        }],
3657        Some(ExpectedResponse::Error(Errno::ENOTSUP)); "new_rule_v4_fails")]
3658    #[test_case(
3659        RouteNetlinkMessage::NewRule,
3660        0,
3661        AF_INET6 as u16,
3662        vec![FakeRuleRequestResponse{
3663            expected_request_args: RuleRequestArgs::New(default_rule_for_family(AF_INET6 as u16)),
3664            expected_ip_version: IpVersion::V6,
3665            response: Err(Errno::ENOTSUP),
3666        }],
3667        Some(ExpectedResponse::Error(Errno::ENOTSUP)); "new_rule_v6_fails")]
3668    #[test_case(
3669        RouteNetlinkMessage::NewRule,
3670        NLM_F_REPLACE,
3671        AF_INET as u16,
3672        vec![],
3673        Some(ExpectedResponse::Error(Errno::ENOTSUP)); "new_rule_v4_replace_unimplemented")]
3674    #[test_case(
3675        RouteNetlinkMessage::NewRule,
3676        NLM_F_REPLACE,
3677        AF_INET6 as u16,
3678        vec![],
3679        Some(ExpectedResponse::Error(Errno::ENOTSUP)); "new_rule_v6_replace_unimplemented")]
3680    #[test_case(
3681        RouteNetlinkMessage::DelRule,
3682        0,
3683        AF_INET as u16,
3684        vec![FakeRuleRequestResponse{
3685            expected_request_args: RuleRequestArgs::Del(default_rule_for_family(AF_INET as u16)),
3686            expected_ip_version: IpVersion::V4,
3687            response: Ok(()),
3688        }],
3689        None; "del_rule_succeeds_v4")]
3690    #[test_case(
3691        RouteNetlinkMessage::DelRule,
3692        0,
3693        AF_INET6 as u16,
3694        vec![FakeRuleRequestResponse{
3695            expected_request_args: RuleRequestArgs::Del(default_rule_for_family(AF_INET6 as u16)),
3696            expected_ip_version: IpVersion::V6,
3697            response: Ok(()),
3698        }],
3699        None; "del_rule_succeeds_v6")]
3700    #[test_case(
3701        RouteNetlinkMessage::DelRule,
3702        0,
3703        AF_UNSPEC as u16,
3704        vec![],
3705        Some(ExpectedResponse::Error(Errno::EAFNOSUPPORT)); "del_rule_af_unspec_fails")]
3706    #[test_case(
3707        RouteNetlinkMessage::DelRule,
3708        NLM_F_ACK,
3709        AF_INET as u16,
3710        vec![FakeRuleRequestResponse{
3711            expected_request_args: RuleRequestArgs::Del(default_rule_for_family(AF_INET as u16)),
3712            expected_ip_version: IpVersion::V4,
3713            response: Ok(()),
3714        }],
3715        Some(ExpectedResponse::Ack); "del_rule_v4_succeeds_with_ack")]
3716    #[test_case(
3717        RouteNetlinkMessage::DelRule,
3718        NLM_F_ACK,
3719        AF_INET6 as u16,
3720        vec![FakeRuleRequestResponse{
3721            expected_request_args: RuleRequestArgs::Del(default_rule_for_family(AF_INET6 as u16)),
3722            expected_ip_version: IpVersion::V6,
3723            response: Ok(()),
3724        }],
3725        Some(ExpectedResponse::Ack); "del_rule_v6_succeeds_with_ack")]
3726    #[test_case(
3727        RouteNetlinkMessage::DelRule,
3728        0,
3729        AF_INET as u16,
3730        vec![FakeRuleRequestResponse{
3731            expected_request_args: RuleRequestArgs::Del(default_rule_for_family(AF_INET as u16)),
3732            expected_ip_version: IpVersion::V4,
3733            response: Err(Errno::ENOTSUP),
3734        }],
3735        Some(ExpectedResponse::Error(Errno::ENOTSUP)); "del_rule_v4_fails")]
3736    #[test_case(
3737        RouteNetlinkMessage::DelRule,
3738        0,
3739        AF_INET6 as u16,
3740        vec![FakeRuleRequestResponse{
3741            expected_request_args: RuleRequestArgs::Del(default_rule_for_family(AF_INET6 as u16)),
3742            expected_ip_version: IpVersion::V6,
3743            response: Err(Errno::ENOTSUP),
3744        }],
3745        Some(ExpectedResponse::Error(Errno::ENOTSUP)); "del_rule_v6_fails")]
3746    #[fuchsia::test]
3747    async fn test_rule_request(
3748        rule_fn: fn(RuleMessage) -> RouteNetlinkMessage,
3749        flags: u16,
3750        address_family: u16,
3751        requests_and_responses: Vec<FakeRuleRequestResponse>,
3752        expected_response: Option<ExpectedResponse>,
3753    ) {
3754        let rules_request_handler = FakeRuleRequestHandler::new(requests_and_responses);
3755        let (unified_request_sink, unified_request_stream) = mpsc::channel(0);
3756        let unified_request_stream = pin!(unified_request_stream);
3757        let mut handler = NetlinkRouteRequestHandler::<FakeSender<_>> { unified_request_sink };
3758
3759        let (mut client_sink, mut client, async_work_drain_task) = {
3760            crate::client::testutil::new_fake_client::<NetlinkRoute>(
3761                crate::client::testutil::CLIENT_ID_1,
3762                std::iter::empty(),
3763            )
3764        };
3765        let join_handle = fasync::Task::spawn(async_work_drain_task);
3766
3767        let header = header_with_flags(flags);
3768
3769        let handle_request_fut = handler
3770            .handle_request(
3771                NetlinkMessage::new(
3772                    header,
3773                    NetlinkPayload::InnerMessage(rule_fn(default_rule_for_family(address_family))),
3774                ),
3775                &mut client,
3776            )
3777            .fuse();
3778
3779        futures::select! {
3780            () = pin!(handle_request_fut) => {},
3781            _rules_request_handler = unified_request_stream.fold(
3782                rules_request_handler,
3783                |mut rules_request_handler, req| async move {
3784                    match req {
3785                        UnifiedRequest::RuleV4Request(request, completer) => {
3786                            completer
3787                                .send(rules_request_handler.handle_request(request))
3788                                .expect("send should succeed");
3789                            rules_request_handler
3790                        }
3791                        UnifiedRequest::RuleV6Request(request, completer) => {
3792                            completer
3793                                .send(rules_request_handler.handle_request(request))
3794                                .expect("send should succeed");
3795                            rules_request_handler
3796                        }
3797                        _ => panic!("not RuleRequest"),
3798                    }
3799                }
3800            ).fuse() => {},
3801        }
3802        assert_eq!(client_sink.take_messages(), expected_sent_messages(expected_response, header));
3803
3804        drop(client);
3805        join_handle.await;
3806    }
3807
3808    const TEST_V4_SUBNET: Subnet<Ipv4Addr> = net_subnet_v4!("192.0.2.0/24");
3809    const TEST_V4_NEXTHOP: Ipv4Addr = net_ip_v4!("192.0.2.1");
3810    const TEST_V6_SUBNET: Subnet<Ipv6Addr> = net_subnet_v6!("2001:db8::0/32");
3811    const TEST_V6_NEXTHOP: Ipv6Addr = net_ip_v6!("2001:db8::1");
3812
3813    fn test_nexthop_spec_addr<I: Ip>() -> SpecifiedAddr<I::Addr> {
3814        I::map_ip(
3815            (),
3816            |()| SpecifiedAddr::new(TEST_V4_NEXTHOP).unwrap(),
3817            |()| SpecifiedAddr::new(TEST_V6_NEXTHOP).unwrap(),
3818        )
3819    }
3820
3821    #[derive(Clone)]
3822    struct RouteRequestAndResponse<R> {
3823        request: R,
3824        response: Result<(), routes::RequestError>,
3825    }
3826
3827    #[derive(Clone, Copy)]
3828    enum RouteRequestKind {
3829        New,
3830        Del,
3831    }
3832
3833    struct TestRouteCase<I: Ip> {
3834        kind: RouteRequestKind,
3835        flags: u16,
3836        family: u16,
3837        nlas: Vec<RouteAttribute>,
3838        destination_prefix_len: u8,
3839        table: u8,
3840        rtm_type: u8,
3841        expected_request_args: Option<RouteRequestAndResponse<routes::RouteRequestArgs<I>>>,
3842        expected_response: Option<ExpectedResponse>,
3843    }
3844
3845    fn route_addr_from_spec_addr<I: Ip>(a: &SpecifiedAddr<I::Addr>) -> RouteAddress {
3846        let bytes = I::map_ip_in(a, |a| a.ipv4_bytes().to_vec(), |a| a.ipv6_bytes().to_vec());
3847        match I::VERSION {
3848            IpVersion::V4 => RouteAddress::parse(AddressFamily::Inet, &bytes).unwrap(),
3849            IpVersion::V6 => RouteAddress::parse(AddressFamily::Inet6, &bytes).unwrap(),
3850        }
3851    }
3852
3853    fn route_addr_from_subnet<I: Ip>(a: &Subnet<I::Addr>) -> RouteAddress {
3854        let bytes = I::map_ip_in(
3855            a,
3856            |a| a.network().ipv4_bytes().to_vec(),
3857            |a| a.network().ipv6_bytes().to_vec(),
3858        );
3859        match I::VERSION {
3860            IpVersion::V4 => RouteAddress::parse(AddressFamily::Inet, &bytes).unwrap(),
3861            IpVersion::V6 => RouteAddress::parse(AddressFamily::Inet6, &bytes).unwrap(),
3862        }
3863    }
3864
3865    fn build_route_test_case<I: Ip>(
3866        kind: RouteRequestKind,
3867        flags: u16,
3868        dst: Subnet<I::Addr>,
3869        next_hop: Option<SpecifiedAddr<I::Addr>>,
3870        extra_nlas: impl IntoIterator<Item = RouteAttribute>,
3871        interface_id: Option<NonZeroU64>,
3872        table: u8,
3873        rtm_type: u8,
3874        response: Result<(), routes::RequestError>,
3875    ) -> TestRouteCase<I> {
3876        let extra_nlas = extra_nlas.into_iter().collect::<Vec<_>>();
3877        let table_from_nla = extra_nlas.clone().into_iter().find_map(|nla| match nla {
3878            RouteAttribute::Table(table) => Some(NetlinkRouteTableIndex::new(table)),
3879            _ => None,
3880        });
3881        let priority_from_nla = extra_nlas.clone().into_iter().find_map(|nla| match nla {
3882            RouteAttribute::Priority(priority) => Some(priority),
3883            _ => None,
3884        });
3885
3886        TestRouteCase::<I> {
3887            kind,
3888            flags,
3889            family: {
3890                let family = match I::VERSION {
3891                    IpVersion::V4 => AF_INET,
3892                    IpVersion::V6 => AF_INET6,
3893                };
3894                // Conversion is safe as family is guaranteed to fit into an 8-bit integer.
3895                family as u16
3896            },
3897            nlas: [RouteAttribute::Destination(route_addr_from_subnet::<I>(&dst))]
3898                .into_iter()
3899                .chain(interface_id.map(|id| RouteAttribute::Oif(interface_id_as_u32(id.get()))))
3900                .chain(extra_nlas.into_iter())
3901                .collect(),
3902            destination_prefix_len: {
3903                let prefix_len = I::map_ip_in(dst, |dst| dst.prefix(), |dst| dst.prefix());
3904                prefix_len
3905            },
3906            table,
3907            rtm_type,
3908            expected_request_args: Some(RouteRequestAndResponse {
3909                request: {
3910                    match kind {
3911                        RouteRequestKind::New => {
3912                            let interface_id =
3913                                interface_id.expect("new requests must have interface id");
3914
3915                            routes::RouteRequestArgs::New::<I>(routes::NewRouteArgs::Unicast(
3916                                routes::UnicastNewRouteArgs {
3917                                    subnet: dst,
3918                                    target: fnet_routes_ext::RouteTarget {
3919                                        outbound_interface: interface_id.get(),
3920                                        next_hop,
3921                                    },
3922                                    priority: priority_from_nla.and_then(NonZeroU32::new),
3923                                    // Use the table value from the NLA if provided.
3924                                    table: table_from_nla.unwrap_or_else(|| {
3925                                        NetlinkRouteTableIndex::new(table as u32)
3926                                    }),
3927                                },
3928                            ))
3929                        }
3930                        RouteRequestKind::Del => {
3931                            routes::RouteRequestArgs::Del::<I>(routes::DelRouteArgs::Unicast(
3932                                routes::UnicastDelRouteArgs {
3933                                    subnet: dst,
3934                                    outbound_interface: interface_id,
3935                                    next_hop,
3936                                    priority: priority_from_nla
3937                                        .map(|priority| NonZeroU32::new(priority))
3938                                        .flatten(),
3939                                    // Use the table value from the NLA if provided. When the NLA
3940                                    // value is 0, use the value from the header. Default to
3941                                    // RT_TABLE_MAIN when the header value is unspecified.
3942                                    table: table_from_nla
3943                                        .map(|table_nla| {
3944                                            NonZeroNetlinkRouteTableIndex::new(table_nla)
3945                                        })
3946                                        .flatten()
3947                                        .unwrap_or_else(|| {
3948                                            NonZeroNetlinkRouteTableIndex::new_non_zero(
3949                                                NonZeroU32::new(table as u32).unwrap_or(
3950                                                    NonZeroU32::new(
3951                                                        rt_class_t_RT_TABLE_MAIN as u32,
3952                                                    )
3953                                                    .unwrap(),
3954                                                ),
3955                                            )
3956                                        }),
3957                                },
3958                            ))
3959                        }
3960                    }
3961                },
3962                response,
3963            }),
3964            expected_response: (flags & NLM_F_ACK == NLM_F_ACK).then_some(ExpectedResponse::Ack),
3965        }
3966    }
3967
3968    fn build_valid_route_test_case_with_extra_nlas<I: Ip>(
3969        kind: RouteRequestKind,
3970        flags: u16,
3971        addr: Subnet<I::Addr>,
3972        next_hop: Option<SpecifiedAddr<I::Addr>>,
3973        extra_nlas: impl IntoIterator<Item = RouteAttribute>,
3974        interface_id: Option<u64>,
3975        table: u8,
3976        rtm_type: u8,
3977        response: Result<(), routes::RequestError>,
3978    ) -> TestRouteCase<I> {
3979        build_route_test_case::<I>(
3980            kind,
3981            flags,
3982            addr,
3983            next_hop,
3984            extra_nlas,
3985            interface_id.map(|id| NonZeroU64::new(id)).flatten(),
3986            table,
3987            rtm_type,
3988            response,
3989        )
3990    }
3991
3992    fn build_valid_route_test_case<I: Ip>(
3993        kind: RouteRequestKind,
3994        flags: u16,
3995        addr: Subnet<I::Addr>,
3996        interface_id: Option<u64>,
3997        table: u8,
3998        rtm_type: u8,
3999        response: Result<(), routes::RequestError>,
4000    ) -> TestRouteCase<I> {
4001        build_valid_route_test_case_with_extra_nlas::<I>(
4002            kind,
4003            flags,
4004            addr,
4005            None,
4006            None,
4007            interface_id,
4008            table,
4009            rtm_type,
4010            response,
4011        )
4012    }
4013
4014    fn build_invalid_route_test_case<I: Ip>(
4015        kind: RouteRequestKind,
4016        flags: u16,
4017        addr: Subnet<I::Addr>,
4018        interface_id: Option<u64>,
4019        table: u8,
4020        rtm_type: u8,
4021        errno: Errno,
4022    ) -> TestRouteCase<I> {
4023        build_invalid_route_test_case_with_extra_nlas::<I>(
4024            kind,
4025            flags,
4026            addr,
4027            None,
4028            None,
4029            interface_id,
4030            table,
4031            rtm_type,
4032            errno,
4033        )
4034    }
4035
4036    fn build_invalid_route_test_case_with_extra_nlas<I: Ip>(
4037        kind: RouteRequestKind,
4038        flags: u16,
4039        addr: Subnet<I::Addr>,
4040        next_hop: Option<SpecifiedAddr<I::Addr>>,
4041        extra_nlas: impl IntoIterator<Item = RouteAttribute>,
4042        interface_id: Option<u64>,
4043        table: u8,
4044        rtm_type: u8,
4045        errno: Errno,
4046    ) -> TestRouteCase<I> {
4047        TestRouteCase {
4048            expected_request_args: None,
4049            expected_response: Some(ExpectedResponse::Error(errno)),
4050            ..build_valid_route_test_case_with_extra_nlas::<I>(
4051                kind,
4052                flags,
4053                addr,
4054                next_hop,
4055                extra_nlas,
4056                interface_id,
4057                table,
4058                rtm_type,
4059                Ok(()),
4060            )
4061        }
4062    }
4063
4064    #[derive(Clone, Debug, PartialEq)]
4065    enum RouteRequestArgsEither {
4066        V4(routes::RequestArgs<Ipv4>),
4067        V6(routes::RequestArgs<Ipv6>),
4068    }
4069
4070    async fn test_route_request<I: Ip>(
4071        request: NetlinkMessage<RouteNetlinkMessage>,
4072        req_and_resp: Option<RouteRequestAndResponse<routes::RouteRequestArgs<I>>>,
4073    ) -> Vec<SentMessage<RouteNetlinkMessage>> {
4074        let (mut client_sink, mut client, async_work_drain_task) = {
4075            crate::client::testutil::new_fake_client::<NetlinkRoute>(
4076                crate::client::testutil::CLIENT_ID_1,
4077                std::iter::empty(),
4078            )
4079        };
4080        let join_handle = fasync::Task::spawn(async_work_drain_task);
4081
4082        let (unified_request_sink, unified_request_stream) = mpsc::channel(0);
4083        let mut handler = NetlinkRouteRequestHandler::<FakeSender<_>> { unified_request_sink };
4084
4085        let mut unified_request_stream = pin!(unified_request_stream);
4086
4087        match req_and_resp {
4088            None => {
4089                handler.handle_request(request, &mut client).await;
4090                assert_matches!(unified_request_stream.next().now_or_never(), None);
4091            }
4092            Some(RouteRequestAndResponse { request: expected_request, response }) => {
4093                let ((), ()) =
4094                    futures::join!(handler.handle_request(request, &mut client), async {
4095                        let args = match I::VERSION {
4096                            IpVersion::V4 => {
4097                                let next = unified_request_stream.next();
4098                                let routes::Request {
4099                                    args,
4100                                    sequence_number: _,
4101                                    client: _,
4102                                    completer,
4103                                } = match next.await.expect("handler should send request") {
4104                                    UnifiedRequest::RoutesV4Request(request) => request,
4105                                    UnifiedRequest::InterfacesRequest(_)
4106                                    | UnifiedRequest::RoutesV6Request(_)
4107                                    | UnifiedRequest::RuleV4Request(_, _)
4108                                    | UnifiedRequest::RuleV6Request(_, _)
4109                                    | UnifiedRequest::NeighborsRequest(_) => {
4110                                        panic!("not RoutesV4Request")
4111                                    }
4112                                };
4113                                completer.send(response).expect("handler should be alive");
4114                                RouteRequestArgsEither::V4(args)
4115                            }
4116                            IpVersion::V6 => {
4117                                let next = unified_request_stream.next();
4118                                let routes::Request {
4119                                    args,
4120                                    sequence_number: _,
4121                                    client: _,
4122                                    completer,
4123                                } = match next.await.expect("handler should send request") {
4124                                    UnifiedRequest::RoutesV6Request(request) => request,
4125                                    UnifiedRequest::InterfacesRequest(_)
4126                                    | UnifiedRequest::RoutesV4Request(_)
4127                                    | UnifiedRequest::RuleV4Request(_, _)
4128                                    | UnifiedRequest::RuleV6Request(_, _)
4129                                    | UnifiedRequest::NeighborsRequest(_) => {
4130                                        panic!("not RoutesV6Request")
4131                                    }
4132                                };
4133                                completer.send(response).expect("handler should be alive");
4134                                RouteRequestArgsEither::V6(args)
4135                            }
4136                        };
4137
4138                        #[derive(GenericOverIp)]
4139                        #[generic_over_ip(I, Ip)]
4140                        struct EqualityInputs<I: Ip> {
4141                            args: RouteRequestArgsEither,
4142                            expected_request: routes::RequestArgs<I>,
4143                        }
4144
4145                        I::map_ip_in(
4146                            EqualityInputs {
4147                                args: args,
4148                                expected_request: routes::RequestArgs::Route(expected_request),
4149                            },
4150                            |EqualityInputs { args, expected_request }| {
4151                                let args = assert_matches!(
4152                                    args,
4153                                    RouteRequestArgsEither::V4(request) => request
4154                                );
4155                                assert_eq!(args, expected_request);
4156                            },
4157                            |EqualityInputs { args, expected_request }| {
4158                                let args = assert_matches!(
4159                                    args,
4160                                    RouteRequestArgsEither::V6(request) => request
4161                                );
4162                                assert_eq!(args, expected_request);
4163                            },
4164                        );
4165                    });
4166            }
4167        }
4168
4169        drop(client);
4170        join_handle.await;
4171        client_sink.take_messages()
4172    }
4173
4174    /// Test RTM_NEWROUTE and RTM_DELROUTE
4175    // Add route test cases.
4176    // Downcasts are safe as constants have values that fit within an 8-bit integer.
4177    #[test_case(
4178        TestRouteCase::<Ipv4> {
4179            family: AF_UNSPEC as u16,
4180            ..build_invalid_route_test_case(
4181                RouteRequestKind::New,
4182                NLM_F_ACK,
4183                TEST_V4_SUBNET,
4184                Some(interfaces::testutil::LO_INTERFACE_ID),
4185                rt_class_t_RT_TABLE_MAIN as u8,
4186                RTN_UNICAST as u8,
4187                Errno::EINVAL,
4188            )
4189        }; "new_v4_invalid_family_ack")]
4190    #[test_case(
4191        TestRouteCase::<Ipv6> {
4192            family: AF_UNSPEC as u16,
4193            ..build_invalid_route_test_case(
4194                RouteRequestKind::New,
4195                0,
4196                TEST_V6_SUBNET,
4197                Some(interfaces::testutil::LO_INTERFACE_ID),
4198                rt_class_t_RT_TABLE_MAIN as u8,
4199                RTN_UNICAST as u8,
4200                Errno::EINVAL,
4201            )
4202        })]
4203    #[test_case(
4204        TestRouteCase::<Ipv4> {
4205            flags: NLM_F_ACK | NLM_F_REPLACE,
4206            ..build_invalid_route_test_case::<Ipv4>(
4207                RouteRequestKind::New,
4208                NLM_F_ACK,
4209                TEST_V4_SUBNET,
4210                Some(interfaces::testutil::LO_INTERFACE_ID),
4211                rt_class_t_RT_TABLE_MAIN as u8,
4212                RTN_UNICAST as u8,
4213                Errno::ENOTSUP,
4214            )
4215        }; "new_v4_replace_flag_ack")]
4216    #[test_case(
4217        build_invalid_route_test_case::<Ipv6>(
4218            RouteRequestKind::New,
4219            NLM_F_REPLACE,
4220            TEST_V6_SUBNET,
4221            Some(interfaces::testutil::LO_INTERFACE_ID),
4222            rt_class_t_RT_TABLE_MAIN as u8,
4223            RTN_UNICAST as u8,
4224            Errno::ENOTSUP,
4225        ); "new_v6_replace_flag_no_ack")]
4226    #[test_case(
4227        build_invalid_route_test_case::<Ipv4>(
4228            RouteRequestKind::New,
4229            NLM_F_ACK,
4230            TEST_V4_SUBNET,
4231            Some(interfaces::testutil::LO_INTERFACE_ID),
4232            rt_class_t_RT_TABLE_MAIN as u8,
4233            RTN_MULTICAST as u8,
4234            Errno::ENOTSUP); "new_v4_non_unicast_type_ack")]
4235    #[test_case(
4236        build_invalid_route_test_case::<Ipv6>(
4237            RouteRequestKind::New,
4238            0,
4239            TEST_V6_SUBNET,
4240            Some(interfaces::testutil::LO_INTERFACE_ID),
4241            rt_class_t_RT_TABLE_MAIN as u8,
4242            RTN_MULTICAST as u8,
4243            Errno::ENOTSUP); "new_v6_non_unicast_type_no_ack")]
4244    #[test_case(
4245        build_valid_route_test_case::<Ipv4>(
4246            RouteRequestKind::New,
4247            NLM_F_ACK,
4248            net_subnet_v4!("0.0.0.0/0"),
4249            Some(interfaces::testutil::LO_INTERFACE_ID),
4250            rt_class_t_RT_TABLE_MAIN as u8,
4251            RTN_UNICAST as u8,
4252            Ok(())); "new_v4_default_route_ok_ack")]
4253    #[test_case(
4254        build_valid_route_test_case::<Ipv4>(
4255            RouteRequestKind::New,
4256            0,
4257            net_subnet_v4!("0.0.0.0/24"),
4258            Some(interfaces::testutil::LO_INTERFACE_ID),
4259            rt_class_t_RT_TABLE_MAIN as u8,
4260            RTN_UNICAST as u8,
4261            Ok(())); "new_v4_unspecified_route_non_zero_prefix_ok_no_ack")]
4262    #[test_case(
4263        build_valid_route_test_case::<Ipv6>(
4264            RouteRequestKind::New,
4265            NLM_F_ACK,
4266            net_subnet_v6!("::/0"),
4267            Some(interfaces::testutil::LO_INTERFACE_ID),
4268            rt_class_t_RT_TABLE_MAIN as u8,
4269            RTN_UNICAST as u8,
4270            Ok(())); "new_v6_default_route_prefix_ack")]
4271    #[test_case(
4272        build_valid_route_test_case::<Ipv6>(
4273            RouteRequestKind::New,
4274            0,
4275            net_subnet_v6!("::/64"),
4276            Some(interfaces::testutil::LO_INTERFACE_ID),
4277            rt_class_t_RT_TABLE_MAIN as u8,
4278            RTN_UNICAST as u8,
4279            Ok(())); "new_v6_unspecified_route_non_zero_prefix_no_ack")]
4280    #[test_case(
4281        build_valid_route_test_case::<Ipv4>(
4282            RouteRequestKind::New,
4283            NLM_F_ACK,
4284            TEST_V4_SUBNET,
4285            Some(interfaces::testutil::LO_INTERFACE_ID),
4286            rt_class_t_RT_TABLE_MAIN as u8,
4287            RTN_UNICAST as u8,
4288            Ok(())); "new_v4_ok_ack")]
4289    #[test_case(
4290        build_valid_route_test_case::<Ipv6>(
4291            RouteRequestKind::New,
4292            NLM_F_ACK,
4293            TEST_V6_SUBNET,
4294            Some(interfaces::testutil::LO_INTERFACE_ID),
4295            rt_class_t_RT_TABLE_MAIN as u8,
4296            RTN_UNICAST as u8,
4297            Ok(())); "new_v6_ok_ack")]
4298    #[test_case(
4299        build_valid_route_test_case::<Ipv4>(
4300            RouteRequestKind::New,
4301            0,
4302            TEST_V4_SUBNET,
4303            Some(interfaces::testutil::LO_INTERFACE_ID),
4304            rt_class_t_RT_TABLE_MAIN as u8,
4305            RTN_UNICAST as u8,
4306            Ok(())); "new_v4_ok_no_ack")]
4307    #[test_case(
4308        build_valid_route_test_case::<Ipv6>(
4309            RouteRequestKind::New,
4310            0,
4311            TEST_V6_SUBNET,
4312            Some(interfaces::testutil::LO_INTERFACE_ID),
4313            rt_class_t_RT_TABLE_MAIN as u8,
4314            RTN_UNICAST as u8,
4315            Ok(())); "new_v6_ok_no_ack")]
4316    #[test_case(
4317        build_valid_route_test_case_with_extra_nlas::<Ipv4>(
4318            RouteRequestKind::New,
4319            NLM_F_ACK,
4320            TEST_V4_SUBNET,
4321            Some(test_nexthop_spec_addr::<Ipv4>()),
4322            [RouteAttribute::Gateway(route_addr_from_spec_addr::<Ipv4>(
4323                &test_nexthop_spec_addr::<Ipv4>()
4324            ))],
4325            Some(interfaces::testutil::LO_INTERFACE_ID),
4326            rt_class_t_RT_TABLE_MAIN as u8,
4327            RTN_UNICAST as u8,
4328            Ok(())); "new_v4_with_nexthop_ok_ack")]
4329    #[test_case(
4330        build_valid_route_test_case_with_extra_nlas::<Ipv6>(
4331            RouteRequestKind::New,
4332            0,
4333            TEST_V6_SUBNET,
4334            Some(test_nexthop_spec_addr::<Ipv6>()),
4335            [RouteAttribute::Gateway(route_addr_from_spec_addr::<Ipv6>(
4336                &test_nexthop_spec_addr::<Ipv6>()
4337            ))],
4338            Some(interfaces::testutil::LO_INTERFACE_ID),
4339            rt_class_t_RT_TABLE_MAIN as u8,
4340            RTN_UNICAST as u8,
4341            Ok(())); "new_v6_with_nexthop_ok_no_ack")]
4342    #[test_case(
4343        build_valid_route_test_case_with_extra_nlas::<Ipv4>(
4344            RouteRequestKind::New,
4345            NLM_F_ACK,
4346            TEST_V4_SUBNET,
4347            None,
4348            [RouteAttribute::Gateway(RouteAddress::parse(AddressFamily::Inet, &net_ip_v4!("0.0.0.0").ipv4_bytes().to_vec()).unwrap())],
4349            Some(interfaces::testutil::LO_INTERFACE_ID),
4350            rt_class_t_RT_TABLE_MAIN as u8,
4351            RTN_UNICAST as u8,
4352            Ok(())); "new_v4_unspecified_nexthop_ok_ack")]
4353    #[test_case(
4354        build_valid_route_test_case_with_extra_nlas::<Ipv6>(
4355            RouteRequestKind::New,
4356            0,
4357            TEST_V6_SUBNET,
4358            None,
4359            [RouteAttribute::Gateway(RouteAddress::parse(AddressFamily::Inet6, &net_ip_v6!("::").ipv6_bytes().to_vec()).unwrap())],
4360            Some(interfaces::testutil::LO_INTERFACE_ID),
4361            rt_class_t_RT_TABLE_MAIN as u8,
4362            RTN_UNICAST as u8,
4363            Ok(())); "new_v6_unspecified_nexthop_no_ack")]
4364    #[test_case(
4365        build_valid_route_test_case_with_extra_nlas::<Ipv4>(
4366            RouteRequestKind::New,
4367            NLM_F_ACK,
4368            TEST_V4_SUBNET,
4369            None,
4370            [RouteAttribute::Priority(100)],
4371            Some(interfaces::testutil::LO_INTERFACE_ID),
4372            rt_class_t_RT_TABLE_MAIN as u8,
4373            RTN_UNICAST as u8,
4374            Ok(())); "new_v4_priority_nla_ok_ack")]
4375    #[test_case(
4376        build_valid_route_test_case_with_extra_nlas::<Ipv6>(
4377            RouteRequestKind::New,
4378            0,
4379            TEST_V6_SUBNET,
4380            None,
4381            [RouteAttribute::Priority(100)],
4382            Some(interfaces::testutil::LO_INTERFACE_ID),
4383            rt_class_t_RT_TABLE_MAIN as u8,
4384            RTN_UNICAST as u8,
4385            Ok(())); "new_v6_priority_nla_ok_no_ack")]
4386    #[test_case(
4387        TestRouteCase::<Ipv4> {
4388            expected_response: Some(ExpectedResponse::Error(Errno::EINVAL)),
4389            ..build_valid_route_test_case(
4390                RouteRequestKind::New,
4391                NLM_F_ACK,
4392                TEST_V4_SUBNET,
4393                Some(interfaces::testutil::LO_INTERFACE_ID),
4394                rt_class_t_RT_TABLE_MAIN as u8,
4395                RTN_UNICAST as u8,
4396                Err(routes::RequestError::InvalidRequest),
4397            )
4398        }; "new_v4_invalid_request_response_ack")]
4399    #[test_case(
4400        TestRouteCase::<Ipv6> {
4401            expected_response: Some(ExpectedResponse::Error(Errno::EINVAL)),
4402            ..build_valid_route_test_case(
4403                RouteRequestKind::New,
4404                NLM_F_ACK,
4405                TEST_V6_SUBNET,
4406                Some(interfaces::testutil::LO_INTERFACE_ID),
4407                rt_class_t_RT_TABLE_MAIN as u8,
4408                RTN_UNICAST as u8,
4409                Err(routes::RequestError::InvalidRequest),
4410            )
4411        }; "new_v6_invalid_request_response_no_ack")]
4412    #[test_case(
4413        TestRouteCase::<Ipv6> {
4414            expected_response: Some(ExpectedResponse::Error(Errno::ENODEV)),
4415            ..build_valid_route_test_case(
4416                RouteRequestKind::New,
4417                0,
4418                TEST_V6_SUBNET,
4419                Some(interfaces::testutil::LO_INTERFACE_ID),
4420                rt_class_t_RT_TABLE_MAIN as u8,
4421                RTN_UNICAST as u8,
4422                Err(routes::RequestError::UnrecognizedInterface),
4423            )
4424        }; "new_v6_unrecognized_interface_response_no_ack")]
4425    #[test_case(
4426        TestRouteCase::<Ipv6> {
4427            expected_response: Some(ExpectedResponse::Error(Errno::ENOTSUP)),
4428            ..build_valid_route_test_case(
4429                RouteRequestKind::New,
4430                0,
4431                TEST_V6_SUBNET,
4432                Some(interfaces::testutil::LO_INTERFACE_ID),
4433                rt_class_t_RT_TABLE_MAIN as u8,
4434                RTN_UNICAST as u8,
4435                Err(routes::RequestError::Unknown),
4436            )
4437        }; "new_v6_unknown_response_no_ack")]
4438    #[test_case(
4439        TestRouteCase::<Ipv4> {
4440            nlas: vec![
4441                RouteAttribute::Destination(route_addr_from_subnet::<Ipv4>(
4442                    &TEST_V4_SUBNET
4443                )),
4444            ],
4445            ..build_invalid_route_test_case(
4446                RouteRequestKind::New,
4447                0,
4448                TEST_V4_SUBNET,
4449                Some(interfaces::testutil::LO_INTERFACE_ID),
4450                rt_class_t_RT_TABLE_MAIN as u8,
4451                RTN_UNICAST as u8,
4452                Errno::ENOTSUP,
4453            )
4454        }; "new_v4_missing_oif_nla_ack")]
4455    #[test_case(
4456        TestRouteCase::<Ipv6> {
4457            nlas: vec![
4458                RouteAttribute::Destination(route_addr_from_subnet::<Ipv6>(
4459                    &TEST_V6_SUBNET
4460                )),
4461            ],
4462            ..build_invalid_route_test_case(
4463                RouteRequestKind::New,
4464                0,
4465                TEST_V6_SUBNET,
4466                Some(interfaces::testutil::LO_INTERFACE_ID),
4467                rt_class_t_RT_TABLE_MAIN as u8,
4468                RTN_UNICAST as u8,
4469                Errno::ENOTSUP,
4470            )
4471        }; "new_v6_missing_oif_nla_ack")]
4472    #[test_case(
4473        TestRouteCase::<Ipv4> {
4474            nlas: vec![
4475                RouteAttribute::Destination(route_addr_from_subnet::<Ipv4>(
4476                    &TEST_V4_SUBNET
4477                )),
4478            ],
4479            ..build_invalid_route_test_case(
4480                RouteRequestKind::New,
4481                0,
4482                TEST_V4_SUBNET,
4483                Some(interfaces::testutil::LO_INTERFACE_ID),
4484                rt_class_t_RT_TABLE_MAIN as u8,
4485                RTN_UNICAST as u8,
4486                Errno::ENOTSUP,
4487            )
4488        }; "new_v4_missing_oif_nla_no_ack")]
4489    #[test_case(
4490        TestRouteCase::<Ipv6> {
4491            nlas: vec![
4492                RouteAttribute::Destination(route_addr_from_subnet::<Ipv6>(
4493                    &TEST_V6_SUBNET
4494                )),
4495            ],
4496            ..build_invalid_route_test_case(
4497                RouteRequestKind::New,
4498                0,
4499                TEST_V6_SUBNET,
4500                Some(interfaces::testutil::LO_INTERFACE_ID),
4501                rt_class_t_RT_TABLE_MAIN as u8,
4502                RTN_UNICAST as u8,
4503                Errno::ENOTSUP,
4504            )
4505        }; "new_v6_missing_oif_nla_no_ack")]
4506    #[test_case(
4507        TestRouteCase::<Ipv4> {
4508            nlas: vec![
4509                RouteAttribute::Oif(interfaces::testutil::ETH_INTERFACE_ID.try_into().unwrap()),
4510            ],
4511            destination_prefix_len: 1,
4512            ..build_invalid_route_test_case(
4513                RouteRequestKind::New,
4514                NLM_F_ACK,
4515                TEST_V4_SUBNET,
4516                Some(interfaces::testutil::LO_INTERFACE_ID),
4517                rt_class_t_RT_TABLE_MAIN as u8,
4518                RTN_UNICAST as u8,
4519                Errno::EINVAL,
4520            )
4521        }; "new_v4_missing_destination_nla_nonzero_prefix_ack")]
4522    #[test_case(
4523        TestRouteCase::<Ipv6> {
4524            nlas: vec![
4525                RouteAttribute::Oif(interfaces::testutil::ETH_INTERFACE_ID.try_into().unwrap()),
4526            ],
4527            destination_prefix_len: 1,
4528            ..build_invalid_route_test_case(
4529                RouteRequestKind::New,
4530                0,
4531                TEST_V6_SUBNET,
4532                Some(interfaces::testutil::LO_INTERFACE_ID),
4533                rt_class_t_RT_TABLE_MAIN as u8,
4534                RTN_UNICAST as u8,
4535                Errno::EINVAL,
4536            )
4537        }; "new_v6_missing_destination_nla_nonzero_prefix_no_ack")]
4538    #[test_case(
4539        TestRouteCase::<Ipv4> {
4540            nlas: vec![
4541                RouteAttribute::Oif(interfaces::testutil::LO_INTERFACE_ID.try_into().unwrap()),
4542            ],
4543            ..build_valid_route_test_case(
4544                RouteRequestKind::New,
4545                NLM_F_ACK,
4546                net_subnet_v4!("0.0.0.0/0"),
4547                Some(interfaces::testutil::LO_INTERFACE_ID),
4548                rt_class_t_RT_TABLE_MAIN as u8,
4549                RTN_UNICAST as u8,
4550                Ok(()))}; "new_v4_missing_destination_nla_zero_prefix_ack")]
4551    #[test_case(
4552        TestRouteCase::<Ipv6> {
4553            nlas: vec![
4554                RouteAttribute::Oif(interfaces::testutil::LO_INTERFACE_ID.try_into().unwrap()),
4555            ],
4556            ..build_valid_route_test_case(
4557                RouteRequestKind::New,
4558                0,
4559                net_subnet_v6!("::/0"),
4560                Some(interfaces::testutil::LO_INTERFACE_ID),
4561                rt_class_t_RT_TABLE_MAIN as u8,
4562                RTN_UNICAST as u8,
4563                Ok(()))}; "new_v6_missing_destination_nla_zero_prefix_no_ack")]
4564    #[test_case(
4565        TestRouteCase::<Ipv4> {
4566            nlas: Vec::new(),
4567            ..build_invalid_route_test_case(
4568                RouteRequestKind::New,
4569                NLM_F_ACK,
4570                TEST_V4_SUBNET,
4571                Some(interfaces::testutil::LO_INTERFACE_ID),
4572                rt_class_t_RT_TABLE_MAIN as u8,
4573                RTN_UNICAST as u8,
4574                Errno::EINVAL,
4575            )
4576        }; "new_v4_no_nlas_ack")]
4577    #[test_case(
4578        TestRouteCase::<Ipv6> {
4579            nlas: Vec::new(),
4580            ..build_invalid_route_test_case(
4581                RouteRequestKind::New,
4582                0,
4583                TEST_V6_SUBNET,
4584                Some(interfaces::testutil::LO_INTERFACE_ID),
4585                rt_class_t_RT_TABLE_MAIN as u8,
4586                RTN_UNICAST as u8,
4587                Errno::EINVAL,
4588            )
4589        }; "new_v6_no_nlas_no_ack")]
4590    #[test_case(
4591        build_valid_route_test_case_with_extra_nlas::<Ipv4>(
4592            RouteRequestKind::New,
4593            NLM_F_ACK,
4594            TEST_V4_SUBNET,
4595            None,
4596            // `RT_TABLE_COMPAT` is generally used when `table` is outside the bounds of u8 values.
4597            [RouteAttribute::Table(u8::MAX as u32 + 1)],
4598            Some(interfaces::testutil::LO_INTERFACE_ID),
4599            rt_class_t_RT_TABLE_COMPAT as u8,
4600            RTN_UNICAST as u8,
4601            Ok(())); "new_v4_with_table_nla_rt_table_compat_ack")]
4602    #[test_case(
4603        build_valid_route_test_case_with_extra_nlas::<Ipv6>(
4604            RouteRequestKind::New,
4605            0,
4606            TEST_V6_SUBNET,
4607            None,
4608            // `RT_TABLE_COMPAT` is generally used when `table` is outside the bounds of u8 values.
4609            [RouteAttribute::Table(u8::MAX as u32 + 1)],
4610            Some(interfaces::testutil::LO_INTERFACE_ID),
4611            rt_class_t_RT_TABLE_COMPAT as u8,
4612            RTN_UNICAST as u8,
4613            Ok(())); "new_v6_with_table_nla_rt_table_compat_no_ack")]
4614    #[test_case(
4615        build_valid_route_test_case_with_extra_nlas::<Ipv4>(
4616            RouteRequestKind::New,
4617            NLM_F_ACK,
4618            TEST_V4_SUBNET,
4619            None,
4620            [RouteAttribute::Table(u8::MAX as u32 + 1)],
4621            Some(interfaces::testutil::LO_INTERFACE_ID),
4622            rt_class_t_RT_TABLE_MAIN as u8,
4623            RTN_UNICAST as u8,
4624            Ok(())); "new_v4_with_table_nla_rt_class_t_RT_TABLE_MAIN as u8_ack")]
4625    #[test_case(
4626        build_valid_route_test_case_with_extra_nlas::<Ipv6>(
4627            RouteRequestKind::New,
4628            0,
4629            TEST_V6_SUBNET,
4630            None,
4631            [RouteAttribute::Table(u8::MAX as u32 + 1)],
4632            Some(interfaces::testutil::LO_INTERFACE_ID),
4633            rt_class_t_RT_TABLE_MAIN as u8,
4634            RTN_UNICAST as u8,
4635            Ok(())); "new_v6_with_table_nla_rt_class_t_RT_TABLE_MAIN as u8_no_ack")]
4636    #[test_case(
4637        TestRouteCase::<Ipv4> {
4638            destination_prefix_len: u8::MAX,
4639            ..build_invalid_route_test_case(
4640                RouteRequestKind::New,
4641                NLM_F_ACK,
4642                TEST_V4_SUBNET,
4643                Some(interfaces::testutil::LO_INTERFACE_ID),
4644                rt_class_t_RT_TABLE_MAIN as u8,
4645                RTN_UNICAST as u8,
4646                Errno::EINVAL,
4647            )
4648        }; "new_v4_invalid_prefix_len_ack")]
4649    #[test_case(
4650        TestRouteCase::<Ipv6> {
4651            destination_prefix_len: u8::MAX,
4652            ..build_invalid_route_test_case(
4653                RouteRequestKind::New,
4654                0,
4655                TEST_V6_SUBNET,
4656                Some(interfaces::testutil::LO_INTERFACE_ID),
4657                rt_class_t_RT_TABLE_MAIN as u8,
4658                RTN_UNICAST as u8,
4659                Errno::EINVAL,
4660            )
4661        }; "new_v6_invalid_prefix_len_no_ack")]
4662    #[test_case(
4663        TestRouteCase::<Ipv4> {
4664            destination_prefix_len: 0,
4665            ..build_invalid_route_test_case(
4666                RouteRequestKind::New,
4667                NLM_F_ACK,
4668                TEST_V4_SUBNET,
4669                Some(interfaces::testutil::LO_INTERFACE_ID),
4670                rt_class_t_RT_TABLE_MAIN as u8,
4671                RTN_UNICAST as u8,
4672                Errno::EINVAL,
4673            )
4674        }; "new_v4_zero_prefix_len_ack")]
4675    #[test_case(
4676        TestRouteCase::<Ipv6> {
4677            destination_prefix_len: 0,
4678            ..build_invalid_route_test_case(
4679                RouteRequestKind::New,
4680                0,
4681                TEST_V6_SUBNET,
4682                Some(interfaces::testutil::LO_INTERFACE_ID),
4683                rt_class_t_RT_TABLE_MAIN as u8,
4684                RTN_UNICAST as u8,
4685                Errno::EINVAL,
4686            )
4687        }; "new_v6_zero_prefix_len_no_ack")]
4688    // Delete route test cases.
4689    #[test_case(
4690        TestRouteCase::<Ipv4> {
4691            family: AF_UNSPEC as u16,
4692            ..build_invalid_route_test_case(
4693                RouteRequestKind::Del,
4694                NLM_F_ACK,
4695                TEST_V4_SUBNET,
4696                Some(interfaces::testutil::LO_INTERFACE_ID),
4697                rt_class_t_RT_TABLE_MAIN as u8,
4698                RTN_UNICAST as u8,
4699                Errno::EINVAL,
4700            )
4701        }; "del_v4_invalid_family_ack")]
4702    #[test_case(
4703        TestRouteCase::<Ipv6> {
4704            family: AF_UNSPEC as u16,
4705            ..build_invalid_route_test_case(
4706                RouteRequestKind::Del,
4707                0,
4708                TEST_V6_SUBNET,
4709                Some(interfaces::testutil::LO_INTERFACE_ID),
4710                rt_class_t_RT_TABLE_MAIN as u8,
4711                RTN_UNICAST as u8,
4712                Errno::EINVAL,
4713            )
4714        }; "del_v6_invalid_family_no_ack")]
4715    #[test_case(
4716        build_invalid_route_test_case::<Ipv4>(
4717            RouteRequestKind::Del,
4718            NLM_F_ACK,
4719            TEST_V4_SUBNET,
4720            Some(interfaces::testutil::LO_INTERFACE_ID),
4721            rt_class_t_RT_TABLE_MAIN as u8,
4722            RTN_MULTICAST as u8,
4723            Errno::ENOTSUP); "del_v4_non_unicast_type_ack")]
4724    #[test_case(
4725        build_invalid_route_test_case::<Ipv6>(
4726            RouteRequestKind::Del,
4727            0,
4728            TEST_V6_SUBNET,
4729            Some(interfaces::testutil::LO_INTERFACE_ID),
4730            rt_class_t_RT_TABLE_MAIN as u8,
4731            RTN_MULTICAST as u8,
4732            Errno::ENOTSUP); "del_v6_non_unicast_type_no_ack")]
4733    #[test_case(
4734        build_valid_route_test_case::<Ipv4>(
4735            RouteRequestKind::Del,
4736            NLM_F_ACK,
4737            net_subnet_v4!("0.0.0.0/0"),
4738            Some(interfaces::testutil::LO_INTERFACE_ID),
4739            rt_class_t_RT_TABLE_MAIN as u8,
4740            RTN_UNICAST as u8,
4741            Ok(())); "del_v4_default_route_ok_ack")]
4742    #[test_case(
4743        build_valid_route_test_case::<Ipv4>(
4744            RouteRequestKind::Del,
4745            0,
4746            net_subnet_v4!("0.0.0.0/24"),
4747            Some(interfaces::testutil::LO_INTERFACE_ID),
4748            rt_class_t_RT_TABLE_MAIN as u8,
4749            RTN_UNICAST as u8,
4750            Ok(())); "del_v4_unspecified_route_non_zero_prefix_ok_no_ack")]
4751    #[test_case(
4752        build_valid_route_test_case::<Ipv6>(
4753            RouteRequestKind::Del,
4754            NLM_F_ACK,
4755            net_subnet_v6!("::/0"),
4756            Some(interfaces::testutil::LO_INTERFACE_ID),
4757            rt_class_t_RT_TABLE_MAIN as u8,
4758            RTN_UNICAST as u8,
4759            Ok(())); "del_v6_default_route_prefix_ack")]
4760    #[test_case(
4761        build_valid_route_test_case::<Ipv6>(
4762            RouteRequestKind::Del,
4763            0,
4764            net_subnet_v6!("::/64"),
4765            Some(interfaces::testutil::LO_INTERFACE_ID),
4766            rt_class_t_RT_TABLE_MAIN as u8,
4767            RTN_UNICAST as u8,
4768            Ok(())); "del_v6_unspecified_route_non_zero_prefix_no_ack")]
4769    #[test_case(
4770        build_valid_route_test_case::<Ipv4>(
4771            RouteRequestKind::Del,
4772            NLM_F_ACK,
4773            TEST_V4_SUBNET,
4774            None,
4775            rt_class_t_RT_TABLE_MAIN as u8,
4776            RTN_UNICAST as u8,
4777            Ok(())); "del_v4_only_dest_nla_ack")]
4778    #[test_case(
4779        build_valid_route_test_case::<Ipv6>(
4780            RouteRequestKind::Del,
4781            NLM_F_ACK,
4782            TEST_V6_SUBNET,
4783            None,
4784            rt_class_t_RT_TABLE_MAIN as u8,
4785            RTN_UNICAST as u8,
4786            Ok(())); "del_v6_only_dest_nla_ack")]
4787    #[test_case(
4788        build_valid_route_test_case::<Ipv4>(
4789            RouteRequestKind::Del,
4790            0,
4791            TEST_V4_SUBNET,
4792            None,
4793            rt_class_t_RT_TABLE_MAIN as u8,
4794            RTN_UNICAST as u8,
4795            Ok(())); "del_v4_only_dest_nla_no_ack")]
4796    #[test_case(
4797        build_valid_route_test_case::<Ipv6>(
4798            RouteRequestKind::Del,
4799            0,
4800            TEST_V6_SUBNET,
4801            None,
4802            rt_class_t_RT_TABLE_MAIN as u8,
4803            RTN_UNICAST as u8,
4804            Ok(())); "del_v6_only_dest_nla_no_ack")]
4805    #[test_case(
4806        build_valid_route_test_case_with_extra_nlas::<Ipv4>(
4807            RouteRequestKind::Del,
4808            NLM_F_ACK,
4809            TEST_V4_SUBNET,
4810            Some(test_nexthop_spec_addr::<Ipv4>()),
4811            [RouteAttribute::Gateway(route_addr_from_spec_addr::<Ipv4>(
4812                &test_nexthop_spec_addr::<Ipv4>()
4813            ))],
4814            Some(interfaces::testutil::LO_INTERFACE_ID),
4815            rt_class_t_RT_TABLE_MAIN as u8,
4816            RTN_UNICAST as u8,
4817            Ok(())); "del_v4_with_nexthop_ok_ack")]
4818    #[test_case(
4819        build_valid_route_test_case_with_extra_nlas::<Ipv6>(
4820            RouteRequestKind::Del,
4821            0,
4822            TEST_V6_SUBNET,
4823            Some(test_nexthop_spec_addr::<Ipv6>()),
4824            [RouteAttribute::Gateway(route_addr_from_spec_addr::<Ipv6>(
4825                &test_nexthop_spec_addr::<Ipv6>()
4826            ))],
4827            Some(interfaces::testutil::LO_INTERFACE_ID),
4828            rt_class_t_RT_TABLE_MAIN as u8,
4829            RTN_UNICAST as u8,
4830            Ok(())); "del_v6_with_nexthop_ok_no_ack")]
4831    #[test_case(
4832        build_valid_route_test_case_with_extra_nlas::<Ipv4>(
4833            RouteRequestKind::Del,
4834            NLM_F_ACK,
4835            TEST_V4_SUBNET,
4836            None,
4837            [RouteAttribute::Gateway(RouteAddress::parse(AddressFamily::Inet, &net_ip_v4!("0.0.0.0").ipv4_bytes().to_vec()).unwrap())],
4838            Some(interfaces::testutil::LO_INTERFACE_ID),
4839            rt_class_t_RT_TABLE_MAIN as u8,
4840            RTN_UNICAST as u8,
4841            Ok(())); "del_v4_unspecified_nexthop_ok_ack")]
4842    #[test_case(
4843        build_valid_route_test_case_with_extra_nlas::<Ipv6>(
4844            RouteRequestKind::Del,
4845            0,
4846            TEST_V6_SUBNET,
4847            None,
4848            [RouteAttribute::Gateway(RouteAddress::parse(AddressFamily::Inet6, &net_ip_v6!("::").ipv6_bytes().to_vec()).unwrap())],
4849            Some(interfaces::testutil::LO_INTERFACE_ID),
4850            rt_class_t_RT_TABLE_MAIN as u8,
4851            RTN_UNICAST as u8,
4852            Ok(())); "del_v6_unspecified_nexthop_no_ack")]
4853    #[test_case(
4854        build_valid_route_test_case_with_extra_nlas::<Ipv4>(
4855            RouteRequestKind::Del,
4856            NLM_F_ACK,
4857            TEST_V4_SUBNET,
4858            None,
4859            [RouteAttribute::Priority(100)],
4860            Some(interfaces::testutil::LO_INTERFACE_ID),
4861            rt_class_t_RT_TABLE_MAIN as u8,
4862            RTN_UNICAST as u8,
4863            Ok(())); "del_v4_priority_nla_ok_ack")]
4864    #[test_case(
4865        build_valid_route_test_case_with_extra_nlas::<Ipv6>(
4866            RouteRequestKind::Del,
4867            0,
4868            TEST_V6_SUBNET,
4869            None,
4870            [RouteAttribute::Priority(100)],
4871            Some(interfaces::testutil::LO_INTERFACE_ID),
4872            rt_class_t_RT_TABLE_MAIN as u8,
4873            RTN_UNICAST as u8,
4874            Ok(())); "del_v6_priority_nla_ok_no_ack")]
4875    #[test_case(
4876        TestRouteCase::<Ipv4> {
4877            expected_response: Some(ExpectedResponse::Error(Errno::EINVAL)),
4878            ..build_valid_route_test_case(
4879                RouteRequestKind::Del,
4880                NLM_F_ACK,
4881                TEST_V4_SUBNET,
4882                Some(interfaces::testutil::LO_INTERFACE_ID),
4883                rt_class_t_RT_TABLE_MAIN as u8,
4884                RTN_UNICAST as u8,
4885                Err(routes::RequestError::InvalidRequest),
4886            )
4887        }; "del_v4_invalid_request_response_ack")]
4888    #[test_case(
4889        TestRouteCase::<Ipv6> {
4890            expected_response: Some(ExpectedResponse::Error(Errno::EINVAL)),
4891            ..build_valid_route_test_case(
4892                RouteRequestKind::Del,
4893                NLM_F_ACK,
4894                TEST_V6_SUBNET,
4895                Some(interfaces::testutil::LO_INTERFACE_ID),
4896                rt_class_t_RT_TABLE_MAIN as u8,
4897                RTN_UNICAST as u8,
4898                Err(routes::RequestError::InvalidRequest),
4899            )
4900        }; "del_v6_invalid_request_response_no_ack")]
4901    #[test_case(
4902        TestRouteCase::<Ipv6> {
4903            expected_response: Some(ExpectedResponse::Error(Errno::ENODEV)),
4904            ..build_valid_route_test_case(
4905                RouteRequestKind::Del,
4906                0,
4907                TEST_V6_SUBNET,
4908                Some(interfaces::testutil::LO_INTERFACE_ID),
4909                rt_class_t_RT_TABLE_MAIN as u8,
4910                RTN_UNICAST as u8,
4911                Err(routes::RequestError::UnrecognizedInterface),
4912            )
4913        }; "del_v6_unrecognized_interface_response_no_ack")]
4914    #[test_case(
4915        TestRouteCase::<Ipv6> {
4916            expected_response: Some(ExpectedResponse::Error(Errno::ENOTSUP)),
4917            ..build_valid_route_test_case(
4918                RouteRequestKind::Del,
4919                0,
4920                TEST_V6_SUBNET,
4921                Some(interfaces::testutil::LO_INTERFACE_ID),
4922                rt_class_t_RT_TABLE_MAIN as u8,
4923                RTN_UNICAST as u8,
4924                Err(routes::RequestError::Unknown),
4925            )
4926        }; "del_v6_unknown_response_no_ack")]
4927    #[test_case(
4928        build_valid_route_test_case::<Ipv4>(
4929            RouteRequestKind::Del,
4930            NLM_F_ACK,
4931            TEST_V4_SUBNET,
4932            Some(interfaces::testutil::LO_INTERFACE_ID),
4933            rt_class_t_RT_TABLE_MAIN as u8,
4934            RTN_UNICAST as u8,
4935            Ok(()),
4936        ); "del_v4_dest_oif_nlas_ack")]
4937    #[test_case(
4938        build_valid_route_test_case::<Ipv6>(
4939            RouteRequestKind::Del,
4940            NLM_F_ACK,
4941            TEST_V6_SUBNET,
4942            Some(interfaces::testutil::LO_INTERFACE_ID),
4943            rt_class_t_RT_TABLE_MAIN as u8,
4944            RTN_UNICAST as u8,
4945            Ok(()),
4946        ); "del_v6_dest_oif_nlas_ack")]
4947    #[test_case(
4948        build_valid_route_test_case::<Ipv4>(
4949            RouteRequestKind::Del,
4950            0,
4951            TEST_V4_SUBNET,
4952            Some(interfaces::testutil::LO_INTERFACE_ID),
4953            rt_class_t_RT_TABLE_MAIN as u8,
4954            RTN_UNICAST as u8,
4955            Ok(()),
4956        ); "del_v4_dest_oif_nlas_no_ack")]
4957    #[test_case(
4958        build_valid_route_test_case::<Ipv6>(
4959            RouteRequestKind::Del,
4960            0,
4961            TEST_V6_SUBNET,
4962            Some(interfaces::testutil::LO_INTERFACE_ID),
4963            rt_class_t_RT_TABLE_MAIN as u8,
4964            RTN_UNICAST as u8,
4965            Ok(()),
4966        ); "del_v6_dest_oif_nlas_no_ack")]
4967    #[test_case(
4968        TestRouteCase::<Ipv4> {
4969            nlas: Vec::new(),
4970            destination_prefix_len: 1,
4971            ..build_invalid_route_test_case(
4972                RouteRequestKind::Del,
4973                NLM_F_ACK,
4974                TEST_V4_SUBNET,
4975                Some(interfaces::testutil::LO_INTERFACE_ID),
4976                rt_class_t_RT_TABLE_MAIN as u8,
4977                RTN_UNICAST as u8,
4978                Errno::EINVAL,
4979            )
4980        }; "del_v4_missing_destination_nla_nonzero_prefix_ack")]
4981    #[test_case(
4982        TestRouteCase::<Ipv6> {
4983            nlas: Vec::new(),
4984            destination_prefix_len: 1,
4985            ..build_invalid_route_test_case(
4986                RouteRequestKind::Del,
4987                0,
4988                TEST_V6_SUBNET,
4989                Some(interfaces::testutil::LO_INTERFACE_ID),
4990                rt_class_t_RT_TABLE_MAIN as u8,
4991                RTN_UNICAST as u8,
4992                Errno::EINVAL,
4993            )
4994        }; "del_v6_missing_destination_nla_nonzero_prefix_no_ack")]
4995    #[test_case(
4996        TestRouteCase::<Ipv4> {
4997            nlas: Vec::new(),
4998            destination_prefix_len: 0,
4999            ..build_valid_route_test_case(
5000                RouteRequestKind::Del,
5001                NLM_F_ACK,
5002                net_subnet_v4!("0.0.0.0/0"),
5003                None,
5004                rt_class_t_RT_TABLE_MAIN as u8,
5005                RTN_UNICAST as u8,
5006                Ok(()),
5007            )
5008        }; "del_v4_no_nlas_zero_prefix_len_ack")]
5009    #[test_case(
5010        TestRouteCase::<Ipv6> {
5011            nlas: Vec::new(),
5012            destination_prefix_len: 0,
5013            ..build_valid_route_test_case(
5014                RouteRequestKind::Del,
5015                0,
5016                net_subnet_v6!("::/0"),
5017                None,
5018                rt_class_t_RT_TABLE_MAIN as u8,
5019                RTN_UNICAST as u8,
5020                Ok(()),
5021            )
5022        }; "del_v6_no_nlas_zero_prefix_len_no_ack")]
5023    #[test_case(
5024        build_valid_route_test_case::<Ipv4>(
5025            RouteRequestKind::Del,
5026            NLM_F_ACK,
5027            net_subnet_v4!("0.0.0.0/0"),
5028            Some(interfaces::testutil::LO_INTERFACE_ID),
5029            rt_class_t_RT_TABLE_MAIN as u8,
5030            RTN_UNICAST as u8,
5031            Ok(()),
5032        ); "del_v4_missing_destination_nla_zero_prefix_ack")]
5033    #[test_case(
5034        build_valid_route_test_case::<Ipv6>(
5035            RouteRequestKind::Del,
5036            0,
5037            net_subnet_v6!("::/0"),
5038            Some(interfaces::testutil::LO_INTERFACE_ID),
5039            rt_class_t_RT_TABLE_MAIN as u8,
5040            RTN_UNICAST as u8,
5041            Ok(()),
5042        ); "del_v6_missing_destination_nla_zero_prefix_no_ack")]
5043    #[test_case(
5044        build_valid_route_test_case_with_extra_nlas::<Ipv4>(
5045            RouteRequestKind::Del,
5046            NLM_F_ACK,
5047            TEST_V4_SUBNET,
5048            None,
5049            // `RT_TABLE_COMPAT` is generally used when `table` is outside the bounds of u8 values.
5050            [RouteAttribute::Table(u8::MAX as u32 + 1)],
5051            Some(interfaces::testutil::LO_INTERFACE_ID),
5052            rt_class_t_RT_TABLE_COMPAT as u8,
5053            RTN_UNICAST as u8,
5054            Ok(())); "del_v4_with_table_nla_rt_table_compat_ack")]
5055    #[test_case(
5056        build_valid_route_test_case_with_extra_nlas::<Ipv6>(
5057            RouteRequestKind::Del,
5058            0,
5059            TEST_V6_SUBNET,
5060            None,
5061            // `RT_TABLE_COMPAT` is generally used when `table` is outside the bounds of u8 values.
5062            [RouteAttribute::Table(u8::MAX as u32 + 1)],
5063            Some(interfaces::testutil::LO_INTERFACE_ID),
5064            rt_class_t_RT_TABLE_COMPAT as u8,
5065            RTN_UNICAST as u8,
5066            Ok(())); "del_v6_with_table_nla_rt_table_compat_no_ack")]
5067    #[test_case(
5068        build_valid_route_test_case_with_extra_nlas::<Ipv4>(
5069            RouteRequestKind::Del,
5070            NLM_F_ACK,
5071            TEST_V4_SUBNET,
5072            None,
5073            [RouteAttribute::Table(u8::MAX as u32 + 1)],
5074            Some(interfaces::testutil::LO_INTERFACE_ID),
5075            rt_class_t_RT_TABLE_MAIN as u8,
5076            RTN_UNICAST as u8,
5077            Ok(())); "del_v4_with_table_nla_rt_class_t_RT_TABLE_MAIN as u8_ack")]
5078    #[test_case(
5079        build_valid_route_test_case_with_extra_nlas::<Ipv6>(
5080            RouteRequestKind::Del,
5081            0,
5082            TEST_V6_SUBNET,
5083            None,
5084            [RouteAttribute::Table(u8::MAX as u32 + 1)],
5085            Some(interfaces::testutil::LO_INTERFACE_ID),
5086            rt_class_t_RT_TABLE_MAIN as u8,
5087            RTN_UNICAST as u8,
5088            Ok(())); "del_v6_with_table_nla_rt_class_t_RT_TABLE_MAIN as u8_no_ack")]
5089    #[test_case(
5090        TestRouteCase::<Ipv4> {
5091            destination_prefix_len: u8::MAX,
5092            ..build_invalid_route_test_case(
5093                RouteRequestKind::Del,
5094                NLM_F_ACK,
5095                TEST_V4_SUBNET,
5096                Some(interfaces::testutil::LO_INTERFACE_ID),
5097                rt_class_t_RT_TABLE_MAIN as u8,
5098                RTN_UNICAST as u8,
5099                Errno::EINVAL,
5100            )
5101        }; "del_v4_invalid_prefix_len_ack")]
5102    #[test_case(
5103        TestRouteCase::<Ipv6> {
5104            destination_prefix_len: u8::MAX,
5105            ..build_invalid_route_test_case(
5106                RouteRequestKind::Del,
5107                0,
5108                TEST_V6_SUBNET,
5109                Some(interfaces::testutil::LO_INTERFACE_ID),
5110                rt_class_t_RT_TABLE_MAIN as u8,
5111                RTN_UNICAST as u8,
5112                Errno::EINVAL,
5113            )
5114        }; "del_v6_invalid_prefix_len_no_ack")]
5115    #[test_case(
5116        TestRouteCase::<Ipv4> {
5117            destination_prefix_len: 0,
5118            ..build_invalid_route_test_case(
5119                RouteRequestKind::Del,
5120                NLM_F_ACK,
5121                TEST_V4_SUBNET,
5122                Some(interfaces::testutil::LO_INTERFACE_ID),
5123                rt_class_t_RT_TABLE_MAIN as u8,
5124                RTN_UNICAST as u8,
5125                Errno::EINVAL,
5126            )
5127        }; "del_v4_zero_prefix_len_ack")]
5128    #[test_case(
5129        TestRouteCase::<Ipv6> {
5130            destination_prefix_len: 0,
5131            ..build_invalid_route_test_case(
5132                RouteRequestKind::Del,
5133                0,
5134                TEST_V6_SUBNET,
5135                Some(interfaces::testutil::LO_INTERFACE_ID),
5136                rt_class_t_RT_TABLE_MAIN as u8,
5137                RTN_UNICAST as u8,
5138                Errno::EINVAL,
5139            )
5140        }; "del_v6_zero_prefix_len_no_ack")]
5141    #[test_case(
5142        build_valid_route_test_case_with_extra_nlas::<Ipv4>(
5143            RouteRequestKind::Del,
5144            NLM_F_ACK,
5145            TEST_V4_SUBNET,
5146            None,
5147            [RouteAttribute::Oif(0)],
5148            None,
5149            rt_class_t_RT_TABLE_MAIN as u8,
5150            RTN_UNICAST as u8,
5151            Ok(()),
5152        ); "del_v4_zero_interface_id_ack")]
5153    #[test_case(
5154        build_valid_route_test_case_with_extra_nlas::<Ipv6>(
5155            RouteRequestKind::Del,
5156            NLM_F_ACK,
5157            TEST_V6_SUBNET,
5158            None,
5159            [RouteAttribute::Oif(0)],
5160            None,
5161            rt_class_t_RT_TABLE_MAIN as u8,
5162            RTN_UNICAST as u8,
5163            Ok(()),
5164        ); "del_v6_zero_interface_id_no_ack")]
5165    #[fuchsia::test]
5166    async fn test_new_del_route<I: Ip>(test_case: TestRouteCase<I>) {
5167        let TestRouteCase {
5168            kind,
5169            flags,
5170            family,
5171            nlas,
5172            destination_prefix_len,
5173            table,
5174            rtm_type,
5175            expected_request_args,
5176            expected_response,
5177        }: TestRouteCase<I> = test_case;
5178
5179        let header = header_with_flags(flags);
5180        let route_message = {
5181            let mut message = RouteMessage::default();
5182            message.header.address_family = AddressFamily::from(family as u8);
5183            message.header.destination_prefix_length = destination_prefix_len;
5184            message.header.table = table;
5185            message.header.kind = RouteType::from(rtm_type);
5186            message.attributes = nlas;
5187            message
5188        };
5189
5190        let (message, request) = match kind {
5191            RouteRequestKind::New => {
5192                (RouteNetlinkMessage::NewRoute(route_message), expected_request_args)
5193            }
5194            RouteRequestKind::Del => {
5195                (RouteNetlinkMessage::DelRoute(route_message), expected_request_args)
5196            }
5197        };
5198
5199        pretty_assertions::assert_eq!(
5200            test_route_request(
5201                NetlinkMessage::new(header, NetlinkPayload::InnerMessage(message)),
5202                request,
5203            )
5204            .await,
5205            expected_sent_messages(expected_response, header),
5206        )
5207    }
5208
5209    async fn test_neighbor_request(
5210        request: NetlinkMessage<RouteNetlinkMessage>,
5211        expected_request: Option<neighbors::NeighborRequestArgs>,
5212    ) -> Vec<SentMessage<RouteNetlinkMessage>> {
5213        let (mut client_sink, mut client, async_work_drain_task) =
5214            crate::client::testutil::new_fake_client::<NetlinkRoute>(
5215                crate::client::testutil::CLIENT_ID_1,
5216                std::iter::empty(),
5217            );
5218        let join_handle = fasync::Task::spawn(async_work_drain_task);
5219        {
5220            let (unified_request_sink, mut unified_request_stream) = mpsc::channel(0);
5221
5222            let mut handler = NetlinkRouteRequestHandler::<FakeSender<_>> { unified_request_sink };
5223
5224            let handle_request_fut = handler.handle_request(request, &mut client).fuse();
5225            let mut handle_request_fut = pin!(handle_request_fut);
5226            let mut request_fut = unified_request_stream.next().fuse();
5227
5228            futures::select! {
5229                _ = handle_request_fut => assert_eq!(expected_request, None),
5230                request = request_fut => match request.expect("request channel should be open") {
5231                    UnifiedRequest::NeighborsRequest(neigh_req) => {
5232                        let neighbors::Request { args, sequence_number: _, client: _, completer } =
5233                            neigh_req;
5234                        assert_eq!(expected_request, Some(args));
5235                        completer.send(Ok(())).expect("handler should be alive");
5236                        handle_request_fut.await;
5237                    },
5238                    _ => panic!("received unexpected request"),
5239                }
5240            }
5241        }
5242        drop(client);
5243        join_handle.await;
5244        client_sink.take_messages()
5245    }
5246
5247    #[test_case(
5248        NLM_F_DUMP,
5249        NeighbourHeader::default(),
5250        vec![],
5251        Some(neighbors::GetNeighborArgs::Dump { ip_version: None, interface: None }),
5252        Some(ExpectedResponse::Done); "dump all")]
5253    #[test_case(
5254        NLM_F_DUMP,
5255        NeighbourHeader { family: AddressFamily::Inet, ..Default::default() },
5256        vec![NeighbourAttribute::IfIndex(1)],
5257        Some(neighbors::GetNeighborArgs::Dump {
5258            ip_version: Some(IpVersion::V4),
5259            interface: Some(NonZeroU64::new(1).unwrap()),
5260        }),
5261        Some(ExpectedResponse::Done); "dump ipv4 on interface 1")]
5262    #[test_case(
5263        NLM_F_DUMP | NLM_F_ACK,
5264        NeighbourHeader::default(),
5265        vec![],
5266        Some(neighbors::GetNeighborArgs::Dump { ip_version: None, interface: None }),
5267        Some(ExpectedResponse::Done); "dump all with ack")]
5268    #[test_case(
5269        NLM_F_DUMP,
5270        NeighbourHeader { family: AddressFamily::Local, ..Default::default() },
5271        vec![],
5272        None,
5273        Some(ExpectedResponse::Error(Errno::EAFNOSUPPORT)); "dump invalid request")]
5274    #[test_case(
5275        0,
5276        NeighbourHeader { family: AddressFamily::Inet, ifindex: 1, ..Default::default() },
5277        vec![NeighbourAttribute::Destination(std_ip_v4!("192.168.0.1").into())],
5278        Some(neighbors::GetNeighborArgs::Get {
5279            ip: fidl_ip!("192.168.0.1"),
5280            interface: NonZeroU64::new(1).unwrap(),
5281        }),
5282        None; "get")]
5283    #[test_case(
5284        NLM_F_ACK,
5285        NeighbourHeader { family: AddressFamily::Inet, ifindex: 1, ..Default::default() },
5286        vec![NeighbourAttribute::Destination(std_ip_v4!("192.168.0.1").into())],
5287        Some(neighbors::GetNeighborArgs::Get {
5288            ip: fidl_ip!("192.168.0.1"),
5289            interface: NonZeroU64::new(1).unwrap(),
5290        }),
5291        Some(ExpectedResponse::Ack); "get with ack")]
5292    #[test_case(
5293        0,
5294        NeighbourHeader::default(),
5295        vec![],
5296        None,
5297        Some(ExpectedResponse::Error(Errno::EAFNOSUPPORT)); "get invalid request")]
5298    #[fuchsia::test]
5299    async fn get_neighbor_with_faked_response(
5300        flags: u16,
5301        header: NeighbourHeader,
5302        attrs: Vec<NeighbourAttribute>,
5303        expected_request_args: Option<neighbors::GetNeighborArgs>,
5304        expected_response: Option<ExpectedResponse>,
5305    ) {
5306        let nl_header = header_with_flags(flags);
5307        let neighbor_message = {
5308            let mut message = NeighbourMessage::default();
5309            message.header = header;
5310            message.attributes = attrs;
5311            message
5312        };
5313
5314        pretty_assertions::assert_eq!(
5315            test_neighbor_request(
5316                NetlinkMessage::new(
5317                    nl_header,
5318                    NetlinkPayload::InnerMessage(RouteNetlinkMessage::GetNeighbour(
5319                        neighbor_message
5320                    )),
5321                ),
5322                expected_request_args.map(neighbors::NeighborRequestArgs::Get),
5323            )
5324            .await,
5325            expected_sent_messages(expected_response, nl_header),
5326        )
5327    }
5328
5329    #[test_case(
5330        0,
5331        NeighbourHeader { family: AddressFamily::Inet, ifindex: 1, ..Default::default() },
5332        vec![NeighbourAttribute::Destination(std_ip_v4!("192.168.0.1").into())],
5333        Some(neighbors::DelNeighborArgs {
5334            ip: fidl_ip!("192.168.0.1"),
5335            interface: NonZeroU64::new(1).unwrap(),
5336        }),
5337        None; "del ipv4")]
5338    #[test_case(
5339        0,
5340        NeighbourHeader { family: AddressFamily::Inet6, ifindex: 1, ..Default::default() },
5341        vec![NeighbourAttribute::Destination(std_ip_v6!("fe80::1").into())],
5342        Some(neighbors::DelNeighborArgs {
5343            ip: fidl_ip!("fe80::1"),
5344            interface: NonZeroU64::new(1).unwrap(),
5345        }),
5346        None; "del ipv6")]
5347    #[test_case(
5348        NLM_F_ACK,
5349        NeighbourHeader { family: AddressFamily::Inet, ifindex: 1, ..Default::default() },
5350        vec![NeighbourAttribute::Destination(std_ip_v4!("192.168.0.1").into())],
5351        Some(neighbors::DelNeighborArgs {
5352            ip: fidl_ip!("192.168.0.1"),
5353            interface: NonZeroU64::new(1).unwrap(),
5354        }),
5355        Some(ExpectedResponse::Ack); "del with ack")]
5356    #[test_case(
5357        0,
5358        NeighbourHeader { family: AddressFamily::Local, ifindex: 1, ..Default::default() },
5359        vec![NeighbourAttribute::Destination(std_ip_v4!("192.168.0.1").into())],
5360        None,
5361        Some(ExpectedResponse::Error(Errno::EAFNOSUPPORT)); "del invalid family")]
5362    #[test_case(
5363        0,
5364        NeighbourHeader { family: AddressFamily::Inet, ifindex: 1, ..Default::default() },
5365        vec![],
5366        None,
5367        Some(ExpectedResponse::Error(Errno::EINVAL)); "del missing destination")]
5368    #[test_case(
5369        0,
5370        NeighbourHeader { family: AddressFamily::Inet, ifindex: 0, ..Default::default() },
5371        vec![NeighbourAttribute::Destination(std_ip_v4!("192.168.0.1").into())],
5372        None,
5373        Some(ExpectedResponse::Error(Errno::EINVAL)); "del missing interface")]
5374    #[fuchsia::test]
5375    async fn del_neighbor_with_faked_response(
5376        flags: u16,
5377        header: NeighbourHeader,
5378        attrs: Vec<NeighbourAttribute>,
5379        expected_request_args: Option<neighbors::DelNeighborArgs>,
5380        expected_response: Option<ExpectedResponse>,
5381    ) {
5382        let nl_header = header_with_flags(flags);
5383        let neighbor_message = {
5384            let mut message = NeighbourMessage::default();
5385            message.header = header;
5386            message.attributes = attrs;
5387            message
5388        };
5389
5390        pretty_assertions::assert_eq!(
5391            test_neighbor_request(
5392                NetlinkMessage::new(
5393                    nl_header,
5394                    NetlinkPayload::InnerMessage(RouteNetlinkMessage::DelNeighbour(
5395                        neighbor_message
5396                    )),
5397                ),
5398                expected_request_args.map(neighbors::NeighborRequestArgs::Del),
5399            )
5400            .await,
5401            expected_sent_messages(expected_response, nl_header),
5402        )
5403    }
5404
5405    #[test_case(
5406        0,
5407        NeighbourHeader { family: AddressFamily::Inet, ifindex: 1, ..Default::default() },
5408        vec![NeighbourAttribute::Destination(std_ip_v4!("192.168.0.1").into())],
5409        None,
5410        Some(ExpectedResponse::Error(Errno::ENOTSUP)); "missing flags")]
5411    #[test_case(
5412        NLM_F_CREATE | NLM_F_REPLACE,
5413        NeighbourHeader {
5414            family: AddressFamily::Inet,
5415            ifindex: 1,
5416            state: NeighbourState::Permanent,
5417            ..Default::default()
5418        },
5419        vec![
5420            NeighbourAttribute::Destination(std_ip_v4!("192.168.0.1").into()),
5421            NeighbourAttribute::LinkLocalAddress(vec![0, 1, 2, 3, 4, 5]),
5422        ],
5423        Some(neighbors::NeighborRequestArgs::New(neighbors::NewNeighborArgs::CreateStatic {
5424            ip: fidl_ip!("192.168.0.1"),
5425            interface: NonZeroU64::new(1).unwrap(),
5426            mac: fnet::MacAddress { octets: [0, 1, 2, 3, 4, 5] },
5427        })),
5428        None; "create static ipv4")]
5429    #[test_case(
5430        NLM_F_CREATE | NLM_F_REPLACE,
5431        NeighbourHeader {
5432            family: AddressFamily::Inet6,
5433            ifindex: 1,
5434            state: NeighbourState::Permanent,
5435            ..Default::default()
5436        },
5437        vec![
5438            NeighbourAttribute::Destination(std_ip_v6!("fe80::1").into()),
5439            NeighbourAttribute::LinkLocalAddress(vec![0, 1, 2, 3, 4, 5]),
5440        ],
5441        Some(neighbors::NeighborRequestArgs::New(neighbors::NewNeighborArgs::CreateStatic {
5442            ip: fidl_ip!("fe80::1"),
5443            interface: NonZeroU64::new(1).unwrap(),
5444            mac: fnet::MacAddress { octets: [0, 1, 2, 3, 4, 5] },
5445        })),
5446        None; "create static ipv6")]
5447    #[test_case(
5448        NLM_F_REPLACE,
5449        NeighbourHeader {
5450            family: AddressFamily::Inet,
5451            ifindex: 1,
5452            state: NeighbourState::Probe,
5453            ..Default::default()
5454        },
5455        vec![NeighbourAttribute::Destination(std_ip_v4!("192.168.0.1").into())],
5456        Some(neighbors::NeighborRequestArgs::New(neighbors::NewNeighborArgs::ProbeExisting {
5457            ip: fidl_ip!("192.168.0.1"),
5458            interface: NonZeroU64::new(1).unwrap(),
5459        })),
5460        None; "probe existing")]
5461    #[test_case(
5462        NLM_F_REPLACE,
5463        NeighbourHeader { family: AddressFamily::Local, ifindex: 1, ..Default::default() },
5464        vec![
5465            NeighbourAttribute::Destination(std_ip_v4!("192.168.0.1").into()),
5466        ],
5467        None,
5468        Some(ExpectedResponse::Error(Errno::EAFNOSUPPORT)); "invalid family")]
5469    #[test_case(
5470        NLM_F_CREATE | NLM_F_REPLACE,
5471        NeighbourHeader {
5472            family: AddressFamily::Inet,
5473            ifindex: 1,
5474            state: NeighbourState::Probe,
5475            ..Default::default()
5476        },
5477        vec![
5478            NeighbourAttribute::Destination(std_ip_v4!("192.168.0.1").into()),
5479            NeighbourAttribute::LinkLocalAddress(vec![0, 1, 2, 3, 4, 5]),
5480        ],
5481        None,
5482        Some(ExpectedResponse::Error(Errno::EINVAL)); "invalid state for create static")]
5483    #[test_case(
5484        NLM_F_CREATE | NLM_F_REPLACE,
5485        NeighbourHeader {
5486            family: AddressFamily::Inet,
5487            ifindex: 1,
5488            state: NeighbourState::Permanent,
5489            ..Default::default()
5490        },
5491        vec![
5492            NeighbourAttribute::Destination(std_ip_v4!("192.168.0.1").into()),
5493        ],
5494        None,
5495        Some(ExpectedResponse::Error(Errno::EINVAL)); "invalid state for probe")]
5496    #[test_case(
5497        NLM_F_CREATE | NLM_F_REPLACE,
5498        NeighbourHeader {
5499            family: AddressFamily::Inet,
5500            ifindex: 1,
5501            state: NeighbourState::Permanent,
5502            ..Default::default()
5503        },
5504        vec![NeighbourAttribute::Destination(std_ip_v4!("192.168.0.1").into())],
5505        None,
5506        Some(ExpectedResponse::Error(Errno::EINVAL)); "create static missing mac")]
5507    #[fuchsia::test]
5508    async fn new_neighbor_with_faked_response(
5509        flags: u16,
5510        header: NeighbourHeader,
5511        attrs: Vec<NeighbourAttribute>,
5512        expected_request_args: Option<neighbors::NeighborRequestArgs>,
5513        expected_response: Option<ExpectedResponse>,
5514    ) {
5515        let nl_header = header_with_flags(flags);
5516        let neighbor_message = {
5517            let mut message = NeighbourMessage::default();
5518            message.header = header;
5519            message.attributes = attrs;
5520            message
5521        };
5522
5523        pretty_assertions::assert_eq!(
5524            test_neighbor_request(
5525                NetlinkMessage::new(
5526                    nl_header,
5527                    NetlinkPayload::InnerMessage(RouteNetlinkMessage::NewNeighbour(
5528                        neighbor_message
5529                    )),
5530                ),
5531                expected_request_args,
5532            )
5533            .await,
5534            expected_sent_messages(expected_response, nl_header),
5535        )
5536    }
5537}