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