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 crate::messaging::testutil::FakeCreds;
1654    use crate::messaging::{NetlinkMessageWithCreds, Permission};
1655    use crate::multicast_groups::GroupSupport;
1656    use netlink_packet_core::NetlinkHeader;
1657
1658    pub(crate) const LEGACY_GROUP1: u32 = 0x00000001;
1659    pub(crate) const LEGACY_GROUP2: u32 = 0x00000002;
1660    pub(crate) const LEGACY_GROUP3: u32 = 0x00000004;
1661    pub(crate) const INVALID_LEGACY_GROUP: u32 = 0x00000008;
1662    pub(crate) const MODERN_GROUP1: ModernGroup = ModernGroup(1);
1663    pub(crate) const MODERN_GROUP2: ModernGroup = ModernGroup(2);
1664    pub(crate) const MODERN_GROUP3: ModernGroup = ModernGroup(3);
1665    pub(crate) const INVALID_MODERN_GROUP: ModernGroup = ModernGroup(4);
1666    pub(crate) const MODERN_GROUP_NEEDS_BLOCKING: ModernGroup = ModernGroup(5);
1667    // AF_PACKET can't be generated by bindgen for some reason.
1668    pub(crate) const AF_PACKET: u16 = 17;
1669
1670    #[derive(Debug)]
1671    pub(crate) enum FakeProtocolFamily {}
1672
1673    impl MulticastCapableNetlinkFamily for FakeProtocolFamily {
1674        fn check_support(group: &ModernGroup) -> Result<GroupSupport, InvalidModernGroupError> {
1675            match *group {
1676                MODERN_GROUP1 | MODERN_GROUP2 | MODERN_GROUP3 | MODERN_GROUP_NEEDS_BLOCKING => {
1677                    Ok(GroupSupport::Unsupported)
1678                }
1679                _ => Err(InvalidModernGroupError),
1680            }
1681        }
1682    }
1683
1684    pub(crate) fn new_fake_netlink_message() -> NetlinkMessage<FakeNetlinkInnerMessage> {
1685        NetlinkMessage::new(
1686            NetlinkHeader::default(),
1687            NetlinkPayload::InnerMessage(FakeNetlinkInnerMessage),
1688        )
1689    }
1690
1691    pub(crate) fn new_fake_netlink_message_with_creds()
1692    -> NetlinkMessageWithCreds<NetlinkMessage<FakeNetlinkInnerMessage>, FakeCreds> {
1693        NetlinkMessageWithCreds::new(new_fake_netlink_message(), FakeCreds::default())
1694    }
1695
1696    #[derive(Clone, Debug, Default, PartialEq)]
1697    pub(crate) struct FakeNetlinkInnerMessage;
1698
1699    impl MessageWithPermission for FakeNetlinkInnerMessage {
1700        fn permission(&self) -> Permission {
1701            Permission::NetlinkRouteWrite
1702        }
1703    }
1704
1705    impl NetlinkSerializable for FakeNetlinkInnerMessage {
1706        fn message_type(&self) -> u16 {
1707            u16::MAX
1708        }
1709
1710        fn buffer_len(&self) -> usize {
1711            0
1712        }
1713
1714        fn serialize(&self, _buffer: &mut [u8]) {}
1715    }
1716
1717    impl NetlinkDeserializable for FakeNetlinkInnerMessage {
1718        type DeserializeOptions = ();
1719        type Error = DecodeError;
1720
1721        fn deserialize(
1722            _header: &NetlinkHeader,
1723            _payload: &[u8],
1724            _options: (),
1725        ) -> Result<Self, Self::Error> {
1726            unimplemented!()
1727        }
1728    }
1729
1730    /// Handler of [`FakeNetlinkInnerMessage`] requests.
1731    ///
1732    /// Reflects the given request back as the response.
1733    #[derive(Clone)]
1734    pub(crate) struct FakeNetlinkRequestHandler;
1735
1736    impl<S: Sender<FakeNetlinkInnerMessage>> NetlinkFamilyRequestHandler<FakeProtocolFamily, S>
1737        for FakeNetlinkRequestHandler
1738    {
1739        async fn handle_request(
1740            &mut self,
1741            req: NetlinkMessage<FakeNetlinkInnerMessage>,
1742            client: &mut InternalClient<FakeProtocolFamily, S>,
1743        ) {
1744            client.send_unicast(req)
1745        }
1746    }
1747
1748    impl NamedNetlinkFamily for FakeProtocolFamily {
1749        const NAME: &'static str = "FAKE_PROTOCOL_FAMILY";
1750    }
1751
1752    impl ProtocolFamily for FakeProtocolFamily {
1753        type Request = FakeNetlinkInnerMessage;
1754        type Response = FakeNetlinkInnerMessage;
1755        type RequestHandler<S: Sender<Self::Response>> = FakeNetlinkRequestHandler;
1756        type NotifiedMulticastGroup = ();
1757        type AsyncWorkItem = !;
1758
1759        fn should_notify_on_group_membership_change(
1760            group: ModernGroup,
1761        ) -> Option<Self::NotifiedMulticastGroup> {
1762            (group == MODERN_GROUP_NEEDS_BLOCKING).then_some(())
1763        }
1764    }
1765}
1766
1767#[cfg(test)]
1768mod test {
1769    use super::*;
1770
1771    use fuchsia_sync::Mutex;
1772    use std::collections::VecDeque;
1773    use std::net::IpAddr;
1774    use std::num::{NonZeroU32, NonZeroU64};
1775    use std::pin::pin;
1776    use std::sync::Arc;
1777
1778    use fidl_fuchsia_net_routes_ext as fnet_routes_ext;
1779
1780    use assert_matches::assert_matches;
1781    use fidl_fuchsia_net as fnet;
1782    use fuchsia_async as fasync;
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        SubnetEither,
1798    };
1799    use net_types::{SpecifiedAddr, Witness as _};
1800    use netlink_packet_core::{NLM_F_ACK, NLM_F_CREATE, NLM_F_DUMP, NLM_F_REPLACE, NetlinkHeader};
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    fn new_del_addr_request_from_subnet(
2600        kind: AddressRequestKind,
2601        ack: bool,
2602        subnet: SubnetEither,
2603        interface_id: u64,
2604    ) -> TestAddrCase {
2605        let (net, prefix) = subnet.net_prefix();
2606        TestAddrCase {
2607            kind,
2608            flags: if ack { NLM_F_ACK } else { 0 },
2609            family: match subnet {
2610                SubnetEither::V4(_) => AF_INET as u16,
2611                SubnetEither::V6(_) => AF_INET6 as u16,
2612            },
2613            nlas: vec![AddressAttribute::Local(net.into())],
2614            prefix_len: prefix,
2615            interface_id: interface_id_as_u32(interface_id),
2616            expected_request_args: None,
2617            expected_response: ack.then_some(ExpectedResponse::Ack),
2618        }
2619    }
2620
2621    /// Test RTM_NEWADDR and RTM_DELADDR
2622    // Add address tests cases.
2623    #[test_case(
2624        new_del_addr_request_from_subnet(
2625            AddressRequestKind::New { add_subnet_route: true },
2626            true,
2627            net_subnet_v4!("0.0.0.0/0").into(),
2628            interfaces::testutil::PPP_INTERFACE_ID,
2629        ); "new_v4_unspecified_address_zero_prefix_ok_ack")]
2630    #[test_case(
2631        new_del_addr_request_from_subnet(
2632            AddressRequestKind::New { add_subnet_route: true },
2633            false,
2634            net_subnet_v4!("0.0.0.0/24").into(),
2635            interfaces::testutil::PPP_INTERFACE_ID,
2636        ); "new_v4_unspecified_address_non_zero_prefix_ok_no_ack")]
2637    #[test_case(
2638        TestAddrCase {
2639            expected_response: Some(ExpectedResponse::Error(Errno::EADDRNOTAVAIL)),
2640            ..new_del_addr_request_from_subnet(
2641                AddressRequestKind::New { add_subnet_route: true },
2642                true,
2643                net_subnet_v6!("::/0").into(),
2644                interfaces::testutil::ETH_INTERFACE_ID,
2645            )
2646        }; "new_v6_unspecified_address_zero_prefix_ack")]
2647    #[test_case(
2648        TestAddrCase {
2649            expected_response: Some(ExpectedResponse::Error(Errno::EADDRNOTAVAIL)),
2650            ..new_del_addr_request_from_subnet(
2651                AddressRequestKind::New { add_subnet_route: true },
2652                false,
2653                net_subnet_v6!("::/64").into(),
2654                interfaces::testutil::ETH_INTERFACE_ID,
2655            )
2656        }; "new_v6_unspecified_address_non_zero_prefix_no_ack")]
2657    #[test_case(
2658        valid_new_addr_request(
2659            true,
2660            interfaces::testutil::test_addr_subnet_v4(),
2661            interfaces::testutil::LO_INTERFACE_ID,
2662            Ok(())); "new_v4_ok_ack")]
2663    #[test_case(
2664        valid_new_addr_request(
2665            true,
2666            interfaces::testutil::test_addr_subnet_v6(),
2667            interfaces::testutil::LO_INTERFACE_ID,
2668            Ok(())); "new_v6_ok_ack")]
2669    #[test_case(
2670        valid_new_addr_request(
2671            false,
2672            interfaces::testutil::test_addr_subnet_v4(),
2673            interfaces::testutil::ETH_INTERFACE_ID,
2674            Ok(())); "new_v4_ok_no_ack")]
2675    #[test_case(
2676        valid_new_addr_request(
2677            false,
2678            interfaces::testutil::test_addr_subnet_v6(),
2679            interfaces::testutil::ETH_INTERFACE_ID,
2680            Ok(())); "new_v6_ok_no_ack")]
2681    #[test_case(
2682        TestAddrCase {
2683            nlas: vec![
2684                AddressAttribute::Local(ip_from_addr(interfaces::testutil::test_addr_subnet_v4())),
2685            ],
2686            ..valid_new_addr_request(
2687                false,
2688                interfaces::testutil::test_addr_subnet_v4(),
2689                interfaces::testutil::ETH_INTERFACE_ID,
2690                Ok(()),
2691            )
2692        }; "new_v4_local_nla_ok_no_ack")]
2693    #[test_case(
2694        TestAddrCase {
2695            nlas: vec![
2696                AddressAttribute::Address(ip_from_addr(interfaces::testutil::test_addr_subnet_v6())),
2697            ],
2698            ..valid_new_addr_request(
2699                true,
2700                interfaces::testutil::test_addr_subnet_v6(),
2701                interfaces::testutil::PPP_INTERFACE_ID,
2702                Ok(()),
2703            )
2704        }; "new_v6_address_nla_ok_ack")]
2705    #[test_case(
2706        TestAddrCase {
2707            nlas: vec![
2708                AddressAttribute::Address(ip_from_addr(interfaces::testutil::test_addr_subnet_v6())),
2709                AddressAttribute::Local(ip_from_addr(interfaces::testutil::test_addr_subnet_v6())),
2710            ],
2711            ..valid_new_addr_request(
2712                false,
2713                interfaces::testutil::test_addr_subnet_v6(),
2714                interfaces::testutil::PPP_INTERFACE_ID,
2715                Ok(()),
2716            )
2717        }; "new_v6_same_local_and_address_nla_ok_no_ack")]
2718    #[test_case(
2719        TestAddrCase {
2720            kind: AddressRequestKind::New { add_subnet_route: true },
2721            ..valid_new_addr_request_with_extra_nlas(
2722                false,
2723                interfaces::testutil::test_addr_subnet_v4(),
2724                [AddressAttribute::Flags(AddressFlags::empty())],
2725                interfaces::testutil::ETH_INTERFACE_ID,
2726                Ok(()),
2727            )
2728        }; "new_v4_with_route_ok_no_ack")]
2729    #[test_case(
2730        TestAddrCase {
2731            kind: AddressRequestKind::New { add_subnet_route: false },
2732            ..valid_new_addr_request_with_extra_nlas(
2733                true,
2734                interfaces::testutil::test_addr_subnet_v6(),
2735                [AddressAttribute::Flags(AddressFlags::from_bits(IFA_F_NOPREFIXROUTE).unwrap())],
2736                interfaces::testutil::LO_INTERFACE_ID,
2737                Ok(()),
2738            )
2739        }; "new_v6_without_route_ok_ack")]
2740    #[test_case(
2741        TestAddrCase {
2742            expected_response: Some(ExpectedResponse::Error(Errno::EINVAL)),
2743            ..valid_new_addr_request(
2744                true,
2745                interfaces::testutil::test_addr_subnet_v4(),
2746                interfaces::testutil::LO_INTERFACE_ID,
2747                Err(interfaces::RequestError::InvalidRequest),
2748            )
2749        }; "new_v4_invalid_response_ack")]
2750    #[test_case(
2751        TestAddrCase {
2752            expected_response: Some(ExpectedResponse::Error(Errno::EEXIST)),
2753            ..valid_new_addr_request(
2754                false,
2755                interfaces::testutil::test_addr_subnet_v6(),
2756                interfaces::testutil::LO_INTERFACE_ID,
2757                Err(interfaces::RequestError::AlreadyExists),
2758            )
2759        }; "new_v6_exist_response_no_ack")]
2760    #[test_case(
2761        TestAddrCase {
2762            expected_response: Some(ExpectedResponse::Error(Errno::ENODEV)),
2763            ..valid_new_addr_request(
2764                false,
2765                interfaces::testutil::test_addr_subnet_v6(),
2766                interfaces::testutil::WLAN_INTERFACE_ID,
2767                Err(interfaces::RequestError::UnrecognizedInterface),
2768            )
2769        }; "new_v6_unrecognized_interface_response_no_ack")]
2770    #[test_case(
2771        TestAddrCase {
2772            expected_response: Some(ExpectedResponse::Error(Errno::EADDRNOTAVAIL)),
2773            ..valid_new_addr_request(
2774                true,
2775                interfaces::testutil::test_addr_subnet_v4(),
2776                interfaces::testutil::ETH_INTERFACE_ID,
2777                Err(interfaces::RequestError::AddressNotFound),
2778            )
2779        }; "new_v4_not_found_response_ck")]
2780    #[test_case(
2781        TestAddrCase {
2782            interface_id: 0,
2783            ..invalid_new_addr_request(
2784                true,
2785                interfaces::testutil::test_addr_subnet_v6(),
2786                interfaces::testutil::LO_INTERFACE_ID,
2787                Errno::EINVAL,
2788            )
2789        }; "new_zero_interface_id_ack")]
2790    #[test_case(
2791        TestAddrCase {
2792            interface_id: 0,
2793            ..invalid_new_addr_request(
2794                false,
2795                interfaces::testutil::test_addr_subnet_v4(),
2796                interfaces::testutil::WLAN_INTERFACE_ID,
2797                Errno::EINVAL,
2798            )
2799        }; "new_zero_interface_id_no_ack")]
2800    #[test_case(
2801        TestAddrCase {
2802            nlas: Vec::new(),
2803            ..invalid_new_addr_request(
2804                true,
2805                interfaces::testutil::test_addr_subnet_v4(),
2806                interfaces::testutil::WLAN_INTERFACE_ID,
2807                Errno::EINVAL,
2808            )
2809        }; "new_no_nlas_ack")]
2810    #[test_case(
2811        TestAddrCase {
2812            nlas: Vec::new(),
2813            ..invalid_new_addr_request(
2814                false,
2815                interfaces::testutil::test_addr_subnet_v6(),
2816                interfaces::testutil::WLAN_INTERFACE_ID,
2817                Errno::EINVAL,
2818            )
2819        }; "new_no_nlas_no_ack")]
2820    #[test_case(
2821        TestAddrCase {
2822            nlas: vec![AddressAttribute::Flags(AddressFlags::empty())],
2823            ..invalid_new_addr_request(
2824                true,
2825                interfaces::testutil::test_addr_subnet_v4(),
2826                interfaces::testutil::WLAN_INTERFACE_ID,
2827                Errno::EINVAL,
2828            )
2829        }; "new_missing_address_and_local_nla_ack")]
2830    #[test_case(
2831        TestAddrCase {
2832            nlas: vec![AddressAttribute::Flags(AddressFlags::empty())],
2833            ..invalid_new_addr_request(
2834                false,
2835                interfaces::testutil::test_addr_subnet_v6(),
2836                interfaces::testutil::WLAN_INTERFACE_ID,
2837                Errno::EINVAL,
2838            )
2839        }; "new_missing_address_and_local_nla_no_ack")]
2840    #[test_case(
2841        TestAddrCase {
2842            prefix_len: 0,
2843            kind: AddressRequestKind::New { add_subnet_route: false },
2844            ..valid_new_addr_request(
2845                true,
2846                net_addr_subnet!("192.0.2.123/0"),
2847                interfaces::testutil::WLAN_INTERFACE_ID,
2848                Ok(()),
2849            )
2850        }; "new_zero_prefix_len_ack")]
2851    #[test_case(
2852        TestAddrCase {
2853            prefix_len: 0,
2854            ..valid_new_addr_request(
2855                false,
2856                net_addr_subnet!("2001:db8::1324/0"),
2857                interfaces::testutil::WLAN_INTERFACE_ID,
2858                Ok(()),
2859            )
2860        }; "new_zero_prefix_len_no_ack")]
2861    #[test_case(
2862        TestAddrCase {
2863            prefix_len: u8::MAX,
2864            ..invalid_new_addr_request(
2865                true,
2866                interfaces::testutil::test_addr_subnet_v4(),
2867                interfaces::testutil::WLAN_INTERFACE_ID,
2868                Errno::EINVAL,
2869            )
2870        }; "new_invalid_prefix_len_ack")]
2871    #[test_case(
2872        TestAddrCase {
2873            prefix_len: u8::MAX,
2874            ..invalid_new_addr_request(
2875                false,
2876                interfaces::testutil::test_addr_subnet_v6(),
2877                interfaces::testutil::WLAN_INTERFACE_ID,
2878                Errno::EINVAL,
2879            )
2880        }; "new_invalid_prefix_len_no_ack")]
2881    #[test_case(
2882        TestAddrCase {
2883            family: AF_UNSPEC as u16,
2884            ..invalid_new_addr_request(
2885                true,
2886                interfaces::testutil::test_addr_subnet_v4(),
2887                interfaces::testutil::LO_INTERFACE_ID,
2888                Errno::EINVAL,
2889            )
2890        }; "new_invalid_family_ack")]
2891    #[test_case(
2892        TestAddrCase {
2893            family: AF_UNSPEC as u16,
2894            ..invalid_new_addr_request(
2895                false,
2896                interfaces::testutil::test_addr_subnet_v6(),
2897                interfaces::testutil::PPP_INTERFACE_ID,
2898                Errno::EINVAL,
2899            )
2900        }; "new_invalid_family_no_ack")]
2901    // Delete address tests cases.
2902    #[test_case(
2903        valid_del_addr_request(
2904            true,
2905            interfaces::testutil::test_addr_subnet_v4(),
2906            interfaces::testutil::LO_INTERFACE_ID,
2907            Ok(())); "del_v4_ok_ack")]
2908    #[test_case(
2909        valid_del_addr_request(
2910            true,
2911            interfaces::testutil::test_addr_subnet_v6(),
2912            interfaces::testutil::LO_INTERFACE_ID,
2913            Ok(())); "del_v6_ok_ack")]
2914    #[test_case(
2915        valid_del_addr_request(
2916            false,
2917            interfaces::testutil::test_addr_subnet_v4(),
2918            interfaces::testutil::ETH_INTERFACE_ID,
2919            Ok(())); "del_v4_ok_no_ack")]
2920    #[test_case(
2921        valid_del_addr_request(
2922            false,
2923            interfaces::testutil::test_addr_subnet_v6(),
2924            interfaces::testutil::ETH_INTERFACE_ID,
2925            Ok(())); "del_v6_ok_no_ack")]
2926    #[test_case(
2927        TestAddrCase {
2928            expected_response: Some(ExpectedResponse::Error(Errno::EINVAL)),
2929            ..valid_del_addr_request(
2930                true,
2931                interfaces::testutil::test_addr_subnet_v4(),
2932                interfaces::testutil::LO_INTERFACE_ID,
2933                Err(interfaces::RequestError::InvalidRequest),
2934            )
2935        }; "del_v4_invalid_response_ack")]
2936    #[test_case(
2937        TestAddrCase {
2938            nlas: vec![
2939                AddressAttribute::Local(ip_from_addr(interfaces::testutil::test_addr_subnet_v4())),
2940            ],
2941            ..valid_del_addr_request(
2942                false,
2943                interfaces::testutil::test_addr_subnet_v4(),
2944                interfaces::testutil::ETH_INTERFACE_ID,
2945                Ok(()),
2946            )
2947        }; "del_v4_local_nla_ok_no_ack")]
2948    #[test_case(
2949        TestAddrCase {
2950            nlas: vec![
2951                AddressAttribute::Address(ip_from_addr(interfaces::testutil::test_addr_subnet_v6())),
2952            ],
2953            ..valid_del_addr_request(
2954                true,
2955                interfaces::testutil::test_addr_subnet_v6(),
2956                interfaces::testutil::PPP_INTERFACE_ID,
2957                Ok(()),
2958            )
2959        }; "del_v6_address_nla_ok_ack")]
2960    #[test_case(
2961        TestAddrCase {
2962            nlas: vec![
2963                AddressAttribute::Address(ip_from_addr(interfaces::testutil::test_addr_subnet_v4())),
2964                AddressAttribute::Local(ip_from_addr(interfaces::testutil::test_addr_subnet_v4())),
2965            ],
2966            ..valid_del_addr_request(
2967                true,
2968                interfaces::testutil::test_addr_subnet_v4(),
2969                interfaces::testutil::ETH_INTERFACE_ID,
2970                Ok(()),
2971            )
2972        }; "del_v4_same_local_and_address_nla_ok_ack")]
2973    #[test_case(
2974        TestAddrCase {
2975            expected_response: Some(ExpectedResponse::Error(Errno::EEXIST)),
2976            ..valid_del_addr_request(
2977                false,
2978                interfaces::testutil::test_addr_subnet_v6(),
2979                interfaces::testutil::LO_INTERFACE_ID,
2980                Err(interfaces::RequestError::AlreadyExists),
2981            )
2982        }; "del_v6_exist_response_no_ack")]
2983    #[test_case(
2984        TestAddrCase {
2985            expected_response: Some(ExpectedResponse::Error(Errno::ENODEV)),
2986            ..valid_del_addr_request(
2987                false,
2988                interfaces::testutil::test_addr_subnet_v6(),
2989                interfaces::testutil::WLAN_INTERFACE_ID,
2990                Err(interfaces::RequestError::UnrecognizedInterface),
2991            )
2992        }; "del_v6_unrecognized_interface_response_no_ack")]
2993    #[test_case(
2994        TestAddrCase {
2995            expected_response: Some(ExpectedResponse::Error(Errno::EADDRNOTAVAIL)),
2996            ..valid_del_addr_request(
2997                true,
2998                interfaces::testutil::test_addr_subnet_v4(),
2999                interfaces::testutil::ETH_INTERFACE_ID,
3000                Err(interfaces::RequestError::AddressNotFound),
3001            )
3002        }; "del_v4_not_found_response_ck")]
3003    #[test_case(
3004        TestAddrCase {
3005            interface_id: 0,
3006            ..invalid_del_addr_request(
3007                true,
3008                interfaces::testutil::test_addr_subnet_v6(),
3009                interfaces::testutil::LO_INTERFACE_ID,
3010                Errno::EINVAL,
3011            )
3012        }; "del_zero_interface_id_ack")]
3013    #[test_case(
3014        TestAddrCase {
3015            interface_id: 0,
3016            ..invalid_del_addr_request(
3017                false,
3018                interfaces::testutil::test_addr_subnet_v4(),
3019                interfaces::testutil::WLAN_INTERFACE_ID,
3020                Errno::EINVAL,
3021            )
3022        }; "del_zero_interface_id_no_ack")]
3023    #[test_case(
3024        TestAddrCase {
3025            nlas: Vec::new(),
3026            ..invalid_del_addr_request(
3027                true,
3028                interfaces::testutil::test_addr_subnet_v4(),
3029                interfaces::testutil::WLAN_INTERFACE_ID,
3030                Errno::EINVAL,
3031            )
3032        }; "del_no_nlas_ack")]
3033    #[test_case(
3034        TestAddrCase {
3035            nlas: Vec::new(),
3036            ..invalid_del_addr_request(
3037                false,
3038                interfaces::testutil::test_addr_subnet_v6(),
3039                interfaces::testutil::WLAN_INTERFACE_ID,
3040                Errno::EINVAL,
3041            )
3042        }; "del_no_nlas_no_ack")]
3043    #[test_case(
3044        TestAddrCase {
3045            nlas: vec![AddressAttribute::Flags(AddressFlags::empty())],
3046            ..invalid_del_addr_request(
3047                true,
3048                interfaces::testutil::test_addr_subnet_v4(),
3049                interfaces::testutil::WLAN_INTERFACE_ID,
3050                Errno::EINVAL,
3051            )
3052        }; "del_missing_address_and_local_nla_ack")]
3053    #[test_case(
3054        TestAddrCase {
3055            nlas: vec![AddressAttribute::Flags(AddressFlags::empty())],
3056            ..invalid_del_addr_request(
3057                false,
3058                interfaces::testutil::test_addr_subnet_v6(),
3059                interfaces::testutil::WLAN_INTERFACE_ID,
3060                Errno::EINVAL,
3061            )
3062        }; "del_missing_address_and_local_nla_no_ack")]
3063    #[test_case(
3064        TestAddrCase {
3065            prefix_len: 0,
3066            ..valid_del_addr_request(
3067                true,
3068                net_addr_subnet!("192.0.2.123/0"),
3069                interfaces::testutil::WLAN_INTERFACE_ID,
3070                Ok(()),
3071            )
3072        }; "del_zero_prefix_len_ack")]
3073    #[test_case(
3074        TestAddrCase {
3075            prefix_len: 0,
3076            ..valid_del_addr_request(
3077                false,
3078                net_addr_subnet!("2001:db8::1324/0"),
3079                interfaces::testutil::WLAN_INTERFACE_ID,
3080                Ok(()),
3081            )
3082        }; "del_zero_prefix_len_no_ack")]
3083    #[test_case(
3084        TestAddrCase {
3085            prefix_len: u8::MAX,
3086            ..invalid_del_addr_request(
3087                true,
3088                interfaces::testutil::test_addr_subnet_v4(),
3089                interfaces::testutil::WLAN_INTERFACE_ID,
3090                Errno::EINVAL,
3091            )
3092        }; "del_invalid_prefix_len_ack")]
3093    #[test_case(
3094        TestAddrCase {
3095            prefix_len: u8::MAX,
3096            ..invalid_del_addr_request(
3097                false,
3098                interfaces::testutil::test_addr_subnet_v6(),
3099                interfaces::testutil::WLAN_INTERFACE_ID,
3100                Errno::EINVAL,
3101            )
3102        }; "del_invalid_prefix_len_no_ack")]
3103    #[test_case(
3104        TestAddrCase {
3105            family: AF_UNSPEC as u16,
3106            ..invalid_del_addr_request(
3107                true,
3108                interfaces::testutil::test_addr_subnet_v4(),
3109                interfaces::testutil::LO_INTERFACE_ID,
3110                Errno::EINVAL,
3111            )
3112        }; "del_invalid_family_ack")]
3113    #[test_case(
3114        TestAddrCase {
3115            family: AF_UNSPEC as u16,
3116            ..invalid_del_addr_request(
3117                false,
3118                interfaces::testutil::test_addr_subnet_v6(),
3119                interfaces::testutil::PPP_INTERFACE_ID,
3120                Errno::EINVAL,
3121            )
3122        }; "del_invalid_family_no_ack")]
3123    #[fuchsia::test]
3124    async fn test_new_del_addr(test_case: TestAddrCase) {
3125        let TestAddrCase {
3126            kind,
3127            flags,
3128            family,
3129            nlas,
3130            prefix_len,
3131            interface_id,
3132            expected_request_args,
3133            expected_response,
3134        } = test_case;
3135
3136        let header = header_with_flags(flags);
3137        let address_message = {
3138            let mut message = AddressMessage::default();
3139            // Conversion is safe because family is guaranteed to fit into an 8-bit integer.
3140            message.header.family = AddressFamily::from(family as u8).into();
3141            message.header.index = interface_id.into();
3142            message.header.prefix_len = prefix_len;
3143            message.attributes = nlas;
3144            message
3145        };
3146
3147        let (message, request) = match kind {
3148            AddressRequestKind::New { add_subnet_route } => (
3149                RouteNetlinkMessage::NewAddress(address_message),
3150                expected_request_args.map(|RequestAndResponse { request, response }| {
3151                    RequestAndResponse {
3152                        request: interfaces::RequestArgs::Address(
3153                            interfaces::AddressRequestArgs::New(interfaces::NewAddressArgs {
3154                                address_and_interface_id: request,
3155                                add_subnet_route,
3156                            }),
3157                        ),
3158                        response,
3159                    }
3160                }),
3161            ),
3162            AddressRequestKind::Del => (
3163                RouteNetlinkMessage::DelAddress(address_message),
3164                expected_request_args.map(|RequestAndResponse { request, response }| {
3165                    RequestAndResponse {
3166                        request: interfaces::RequestArgs::Address(
3167                            interfaces::AddressRequestArgs::Del(interfaces::DelAddressArgs {
3168                                address_and_interface_id: request,
3169                            }),
3170                        ),
3171                        response,
3172                    }
3173                }),
3174            ),
3175        };
3176
3177        pretty_assertions::assert_eq!(
3178            test_request(
3179                NetlinkMessage::new(header, NetlinkPayload::InnerMessage(message),),
3180                request,
3181            )
3182            .await,
3183            expected_sent_messages(expected_response, header),
3184        )
3185    }
3186
3187    /// Given a stream of `UnifiedRequest`s and sinks for v4 and v6 routes
3188    /// requests, feeds the v4 and v6 routes requests from the stream into the
3189    /// appropriate sinks, discarding other requests.
3190    async fn split_route_requests(
3191        unified_request_stream: mpsc::Receiver<UnifiedRequest<FakeSender<RouteNetlinkMessage>>>,
3192        v4_routes_request_sink: mpsc::Sender<
3193            crate::routes::Request<FakeSender<RouteNetlinkMessage>, Ipv4>,
3194        >,
3195        v6_routes_request_sink: mpsc::Sender<
3196            crate::routes::Request<FakeSender<RouteNetlinkMessage>, Ipv6>,
3197        >,
3198    ) {
3199        unified_request_stream
3200            .fold(
3201                (v4_routes_request_sink, v6_routes_request_sink),
3202                |(mut v4_routes_request_sink, mut v6_routes_request_sink), req| async move {
3203                    match req {
3204                        UnifiedRequest::RoutesV4Request(req) => {
3205                            v4_routes_request_sink
3206                                .send(req)
3207                                .map(|res| res.expect("send should succeed"))
3208                                .await
3209                        }
3210                        UnifiedRequest::RoutesV6Request(req) => {
3211                            v6_routes_request_sink
3212                                .send(req)
3213                                .map(|res| res.expect("send should succeed"))
3214                                .await
3215                        }
3216                        _ => (),
3217                    };
3218                    (v4_routes_request_sink, v6_routes_request_sink)
3219                },
3220            )
3221            .map(|(_v4_sink, _v6_sink)| ())
3222            .await
3223    }
3224
3225    // Separate from `test_route_request`, because RTM_GETROUTE requests do not have typed
3226    // arguments and there needs to be an option to send a DUMP request to the
3227    // v4 and v6 routes worker.
3228    async fn test_get_route_request(
3229        family: u16,
3230        request: NetlinkMessage<RouteNetlinkMessage>,
3231        expected_request: Option<routes::GetRouteArgs>,
3232    ) -> Vec<SentMessage<RouteNetlinkMessage>> {
3233        let (mut client_sink, mut client, async_work_drain_task) =
3234            crate::client::testutil::new_fake_client::<NetlinkRoute>(
3235                crate::client::testutil::CLIENT_ID_1,
3236                std::iter::empty(),
3237            );
3238        let join_handle = fasync::Task::spawn(async_work_drain_task);
3239
3240        {
3241            let (unified_request_sink, unified_request_stream) = mpsc::channel(0);
3242
3243            let mut handler = NetlinkRouteRequestHandler::<FakeSender<_>> { unified_request_sink };
3244
3245            let (v4_routes_request_sink, mut v4_routes_request_stream) = mpsc::channel(0);
3246            let (v6_routes_request_sink, mut v6_routes_request_stream) = mpsc::channel(0);
3247
3248            let mut split_route_requests_background_work = pin!(
3249                split_route_requests(
3250                    unified_request_stream,
3251                    v4_routes_request_sink,
3252                    v6_routes_request_sink,
3253                )
3254                .fuse()
3255            );
3256
3257            let mut handler_fut = pin!(
3258                futures::future::join(handler.handle_request(request, &mut client), async {
3259                    // Conversions are safe as constants can fit into 16-bit integers.
3260                    if family == AF_UNSPEC as u16 || family == AF_INET as u16 {
3261                        let next = v4_routes_request_stream.next();
3262                        match expected_request.map(|a| {
3263                            routes::RequestArgs::<Ipv4>::Route(routes::RouteRequestArgs::Get(a))
3264                        }) {
3265                            Some(expected_request) => {
3266                                let routes::Request {
3267                                    args,
3268                                    sequence_number: _,
3269                                    client: _,
3270                                    completer,
3271                                } = next.await.expect("handler should send request");
3272                                assert_eq!(args, expected_request);
3273                                completer.send(Ok(())).expect("handler should be alive");
3274                            }
3275                            None => assert_matches!(next.now_or_never(), None),
3276                        };
3277                    }
3278                    if family == AF_UNSPEC as u16 || family == AF_INET6 as u16 {
3279                        let next = v6_routes_request_stream.next();
3280                        match expected_request.map(|a| {
3281                            routes::RequestArgs::<Ipv6>::Route(routes::RouteRequestArgs::Get(a))
3282                        }) {
3283                            Some(expected_request) => {
3284                                let routes::Request {
3285                                    args,
3286                                    sequence_number: _,
3287                                    client: _,
3288                                    completer,
3289                                } = next.await.expect("handler should send request");
3290                                assert_eq!(args, expected_request);
3291                                completer.send(Ok(())).expect("handler should be alive");
3292                            }
3293                            None => assert_matches!(next.now_or_never(), None),
3294                        };
3295                    }
3296                })
3297                .fuse()
3298            );
3299
3300            futures::select! {
3301                ((), ()) = handler_fut => (),
3302                () = split_route_requests_background_work => unreachable!(),
3303            };
3304        }
3305        drop(client);
3306        join_handle.await;
3307        client_sink.take_messages()
3308    }
3309
3310    /// Test RTM_GETROUTE.
3311    /// Conversions are safe as constants fit within 16-bit integers.
3312    #[test_case(
3313        0,
3314        AF_UNSPEC as u16,
3315        None,
3316        None; "af_unspec_no_flags")]
3317    #[test_case(
3318        NLM_F_ACK,
3319        AF_UNSPEC as u16,
3320        None,
3321        Some(ExpectedResponse::Ack); "af_unspec_ack_flag")]
3322    #[test_case(
3323        NLM_F_DUMP,
3324        AF_UNSPEC as u16,
3325        Some(routes::GetRouteArgs::Dump),
3326        Some(ExpectedResponse::Done); "af_unspec_dump_flag")]
3327    #[test_case(
3328        NLM_F_DUMP | NLM_F_ACK,
3329        AF_UNSPEC as u16,
3330        Some(routes::GetRouteArgs::Dump),
3331        Some(ExpectedResponse::Done); "af_unspec_dump_and_ack_flags")]
3332    #[test_case(
3333        0,
3334        AF_INET as u16,
3335        None,
3336        None; "af_inet_no_flags")]
3337    #[test_case(
3338        NLM_F_ACK,
3339        AF_INET as u16,
3340        None,
3341        Some(ExpectedResponse::Ack); "af_inet_ack_flag")]
3342    #[test_case(
3343        NLM_F_DUMP,
3344        AF_INET as u16,
3345        Some(routes::GetRouteArgs::Dump),
3346        Some(ExpectedResponse::Done); "af_inet_dump_flag")]
3347    #[test_case(
3348        NLM_F_DUMP | NLM_F_ACK,
3349        AF_INET as u16,
3350        Some(routes::GetRouteArgs::Dump),
3351        Some(ExpectedResponse::Done); "af_inet_dump_and_ack_flags")]
3352    #[test_case(
3353        0,
3354        AF_INET6 as u16,
3355        None,
3356        None; "af_inet6_no_flags")]
3357    #[test_case(
3358        NLM_F_ACK,
3359        AF_INET6 as u16,
3360        None,
3361        Some(ExpectedResponse::Ack); "af_inet6_ack_flag")]
3362    #[test_case(
3363        NLM_F_DUMP,
3364        AF_INET6 as u16,
3365        Some(routes::GetRouteArgs::Dump),
3366        Some(ExpectedResponse::Done); "af_inet6_dump_flag")]
3367    #[test_case(
3368        NLM_F_DUMP | NLM_F_ACK,
3369        AF_INET6 as u16,
3370        Some(routes::GetRouteArgs::Dump),
3371        Some(ExpectedResponse::Done); "af_inet6_dump_and_ack_flags")]
3372    #[test_case(
3373        0,
3374        AF_PACKET,
3375        None,
3376        None; "af_other_no_flags")]
3377    #[test_case(
3378        NLM_F_ACK,
3379        AF_PACKET,
3380        None,
3381        Some(ExpectedResponse::Ack); "af_other_ack_flag")]
3382    #[test_case(
3383        NLM_F_DUMP,
3384        AF_PACKET,
3385        None,
3386        Some(ExpectedResponse::Error(Errno::EINVAL)); "af_other_dump_flag")]
3387    #[test_case(
3388        NLM_F_DUMP | NLM_F_ACK,
3389        AF_PACKET,
3390        None,
3391        Some(ExpectedResponse::Error(Errno::EINVAL)); "af_other_dump_and_ack_flags")]
3392    #[fuchsia::test]
3393    async fn test_get_route(
3394        flags: u16,
3395        family: u16,
3396        expected_request_args: Option<routes::GetRouteArgs>,
3397        expected_response: Option<ExpectedResponse>,
3398    ) {
3399        let header = header_with_flags(flags);
3400        let route_message = {
3401            let mut message = RouteMessage::default();
3402            message.header.address_family = AddressFamily::from(family as u8);
3403            message
3404        };
3405
3406        pretty_assertions::assert_eq!(
3407            test_get_route_request(
3408                family,
3409                NetlinkMessage::new(
3410                    header,
3411                    NetlinkPayload::InnerMessage(RouteNetlinkMessage::GetRoute(route_message)),
3412                ),
3413                expected_request_args,
3414            )
3415            .await,
3416            expected_sent_messages(expected_response, header)
3417        )
3418    }
3419
3420    /// Represents a single expected request, and the fake response.
3421    #[derive(Debug)]
3422    pub(crate) struct FakeRuleRequestResponse {
3423        pub(crate) expected_request_args: RuleRequestArgs,
3424        pub(crate) expected_ip_version: IpVersion,
3425        pub(crate) response: Result<(), Errno>,
3426    }
3427
3428    /// A fake implementation of [`RuleRequestHandler`].
3429    ///
3430    /// Handles a sequence of rule requests by pulling the expected request
3431    /// and fake response from the front of `requests_and_responses`.
3432    #[derive(Clone, Debug)]
3433    pub(crate) struct FakeRuleRequestHandler {
3434        pub(crate) requests_and_responses: Arc<Mutex<VecDeque<FakeRuleRequestResponse>>>,
3435    }
3436
3437    impl FakeRuleRequestHandler {
3438        fn new(requests_and_responses: impl IntoIterator<Item = FakeRuleRequestResponse>) -> Self {
3439            FakeRuleRequestHandler {
3440                requests_and_responses: Arc::new(Mutex::new(VecDeque::from_iter(
3441                    requests_and_responses,
3442                ))),
3443            }
3444        }
3445
3446        fn handle_request<S: Sender<RouteNetlinkMessage>, I: Ip>(
3447            &mut self,
3448            actual_request: RuleRequest<S, I>,
3449        ) -> Result<(), Errno> {
3450            let Self { requests_and_responses } = self;
3451            let FakeRuleRequestResponse { expected_request_args, expected_ip_version, response } =
3452                requests_and_responses.lock().pop_front().expect(
3453                    "FakeRuleRequest handler should have a fake request/response pre-configured",
3454                );
3455            let RuleRequest { args, _ip_version_marker, sequence_number: _, client: _ } =
3456                actual_request;
3457            assert_eq!(args, expected_request_args);
3458            assert_eq!(I::VERSION, expected_ip_version);
3459            response
3460        }
3461    }
3462
3463    fn default_rule_for_family(family: u16) -> RuleMessage {
3464        let mut rule = RuleMessage::default();
3465        // Conversion is safe as family is guaranteed to fit into an 8-bit integer.
3466        rule.header.family = AddressFamily::from(family as u8);
3467        rule
3468    }
3469
3470    const AF_INVALID: u16 = 255;
3471    /// Conversions are safe as constants fit into a 16-bit integer.
3472    #[test_case(
3473        RouteNetlinkMessage::GetRule,
3474        0,
3475        AF_UNSPEC as u16,
3476        vec![],
3477        Some(ExpectedResponse::Error(Errno::ENOTSUP)); "get_rule_no_dump")]
3478    #[test_case(
3479        RouteNetlinkMessage::GetRule,
3480        NLM_F_DUMP,
3481        AF_INVALID,
3482        vec![],
3483        Some(ExpectedResponse::Error(Errno::EAFNOSUPPORT)); "get_rule_dump_invalid_address_family")]
3484    #[test_case(
3485        RouteNetlinkMessage::GetRule,
3486        NLM_F_DUMP,
3487        AF_INET as u16,
3488        vec![FakeRuleRequestResponse{
3489            expected_request_args: RuleRequestArgs::DumpRules,
3490            expected_ip_version: IpVersion::V4,
3491            response: Ok(()),
3492        }],
3493        Some(ExpectedResponse::Done); "get_rule_dump_v4")]
3494    #[test_case(
3495        RouteNetlinkMessage::GetRule,
3496        NLM_F_DUMP,
3497        AF_INET6 as u16,
3498        vec![FakeRuleRequestResponse{
3499            expected_request_args: RuleRequestArgs::DumpRules,
3500            expected_ip_version: IpVersion::V6,
3501            response: Ok(()),
3502        }],
3503        Some(ExpectedResponse::Done); "get_rule_dump_v6")]
3504    #[test_case(
3505        RouteNetlinkMessage::GetRule,
3506        NLM_F_DUMP,
3507        AF_UNSPEC as u16,
3508        vec![FakeRuleRequestResponse{
3509            expected_request_args: RuleRequestArgs::DumpRules,
3510            expected_ip_version: IpVersion::V4,
3511            response: Ok(()),
3512        },
3513        FakeRuleRequestResponse{
3514            expected_request_args: RuleRequestArgs::DumpRules,
3515            expected_ip_version: IpVersion::V6,
3516            response: Ok(()),
3517        }],
3518        Some(ExpectedResponse::Done); "get_rule_dump_af_unspec")]
3519    #[test_case(
3520        RouteNetlinkMessage::GetRule,
3521        NLM_F_DUMP,
3522        AF_INET as u16,
3523        vec![FakeRuleRequestResponse{
3524            expected_request_args: RuleRequestArgs::DumpRules,
3525            expected_ip_version: IpVersion::V4,
3526            response: Err(Errno::ENOTSUP),
3527        }],
3528        Some(ExpectedResponse::Error(Errno::ENOTSUP)); "get_rule_dump_v4_fails")]
3529    #[test_case(
3530        RouteNetlinkMessage::GetRule,
3531        NLM_F_DUMP,
3532        AF_INET6 as u16,
3533        vec![FakeRuleRequestResponse{
3534            expected_request_args: RuleRequestArgs::DumpRules,
3535            expected_ip_version: IpVersion::V6,
3536            response: Err(Errno::ENOTSUP),
3537        }],
3538        Some(ExpectedResponse::Error(Errno::ENOTSUP)); "get_rule_dump_v6_fails")]
3539    #[test_case(
3540        RouteNetlinkMessage::GetRule,
3541        NLM_F_DUMP,
3542        AF_UNSPEC as u16,
3543        vec![FakeRuleRequestResponse{
3544            expected_request_args: RuleRequestArgs::DumpRules,
3545            expected_ip_version: IpVersion::V4,
3546            response: Err(Errno::ENOTSUP),
3547        }],
3548        Some(ExpectedResponse::Error(Errno::ENOTSUP)); "get_rule_dump_af_unspec_v4_fails")]
3549    #[test_case(
3550        RouteNetlinkMessage::GetRule,
3551        NLM_F_DUMP,
3552        AF_UNSPEC as u16,
3553        vec![FakeRuleRequestResponse{
3554            expected_request_args: RuleRequestArgs::DumpRules,
3555            expected_ip_version: IpVersion::V4,
3556            response: Ok(()),
3557        },
3558        FakeRuleRequestResponse{
3559            expected_request_args: RuleRequestArgs::DumpRules,
3560            expected_ip_version: IpVersion::V6,
3561            response: Err(Errno::ENOTSUP),
3562        }],
3563        Some(ExpectedResponse::Error(Errno::ENOTSUP)); "get_rule_dump_af_unspec_v6_fails")]
3564    #[test_case(
3565        RouteNetlinkMessage::NewRule,
3566        0,
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        None; "new_rule_succeeds_v4")]
3574    #[test_case(
3575        RouteNetlinkMessage::NewRule,
3576        0,
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        None; "new_rule_succeeds_v6")]
3584    #[test_case(
3585        RouteNetlinkMessage::NewRule,
3586        0,
3587        AF_UNSPEC as u16,
3588        vec![],
3589        Some(ExpectedResponse::Error(Errno::EAFNOSUPPORT)); "new_rule_af_unspec_fails")]
3590    #[test_case(
3591        RouteNetlinkMessage::NewRule,
3592        NLM_F_ACK,
3593        AF_INET as u16,
3594        vec![FakeRuleRequestResponse{
3595            expected_request_args: RuleRequestArgs::New(default_rule_for_family(AF_INET as u16)),
3596            expected_ip_version: IpVersion::V4,
3597            response: Ok(()),
3598        }],
3599        Some(ExpectedResponse::Ack); "new_rule_v4_succeeds_with_ack")]
3600    #[test_case(
3601        RouteNetlinkMessage::NewRule,
3602        NLM_F_ACK,
3603        AF_INET6 as u16,
3604        vec![FakeRuleRequestResponse{
3605            expected_request_args: RuleRequestArgs::New(default_rule_for_family(AF_INET6 as u16)),
3606            expected_ip_version: IpVersion::V6,
3607            response: Ok(()),
3608        }],
3609        Some(ExpectedResponse::Ack); "new_rule_v6_succeeds_with_ack")]
3610    #[test_case(
3611        RouteNetlinkMessage::NewRule,
3612        0,
3613        AF_INET as u16,
3614        vec![FakeRuleRequestResponse{
3615            expected_request_args: RuleRequestArgs::New(default_rule_for_family(AF_INET as u16)),
3616            expected_ip_version: IpVersion::V4,
3617            response: Err(Errno::ENOTSUP),
3618        }],
3619        Some(ExpectedResponse::Error(Errno::ENOTSUP)); "new_rule_v4_fails")]
3620    #[test_case(
3621        RouteNetlinkMessage::NewRule,
3622        0,
3623        AF_INET6 as u16,
3624        vec![FakeRuleRequestResponse{
3625            expected_request_args: RuleRequestArgs::New(default_rule_for_family(AF_INET6 as u16)),
3626            expected_ip_version: IpVersion::V6,
3627            response: Err(Errno::ENOTSUP),
3628        }],
3629        Some(ExpectedResponse::Error(Errno::ENOTSUP)); "new_rule_v6_fails")]
3630    #[test_case(
3631        RouteNetlinkMessage::NewRule,
3632        NLM_F_REPLACE,
3633        AF_INET as u16,
3634        vec![],
3635        Some(ExpectedResponse::Error(Errno::ENOTSUP)); "new_rule_v4_replace_unimplemented")]
3636    #[test_case(
3637        RouteNetlinkMessage::NewRule,
3638        NLM_F_REPLACE,
3639        AF_INET6 as u16,
3640        vec![],
3641        Some(ExpectedResponse::Error(Errno::ENOTSUP)); "new_rule_v6_replace_unimplemented")]
3642    #[test_case(
3643        RouteNetlinkMessage::DelRule,
3644        0,
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        None; "del_rule_succeeds_v4")]
3652    #[test_case(
3653        RouteNetlinkMessage::DelRule,
3654        0,
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        None; "del_rule_succeeds_v6")]
3662    #[test_case(
3663        RouteNetlinkMessage::DelRule,
3664        0,
3665        AF_UNSPEC as u16,
3666        vec![],
3667        Some(ExpectedResponse::Error(Errno::EAFNOSUPPORT)); "del_rule_af_unspec_fails")]
3668    #[test_case(
3669        RouteNetlinkMessage::DelRule,
3670        NLM_F_ACK,
3671        AF_INET as u16,
3672        vec![FakeRuleRequestResponse{
3673            expected_request_args: RuleRequestArgs::Del(default_rule_for_family(AF_INET as u16)),
3674            expected_ip_version: IpVersion::V4,
3675            response: Ok(()),
3676        }],
3677        Some(ExpectedResponse::Ack); "del_rule_v4_succeeds_with_ack")]
3678    #[test_case(
3679        RouteNetlinkMessage::DelRule,
3680        NLM_F_ACK,
3681        AF_INET6 as u16,
3682        vec![FakeRuleRequestResponse{
3683            expected_request_args: RuleRequestArgs::Del(default_rule_for_family(AF_INET6 as u16)),
3684            expected_ip_version: IpVersion::V6,
3685            response: Ok(()),
3686        }],
3687        Some(ExpectedResponse::Ack); "del_rule_v6_succeeds_with_ack")]
3688    #[test_case(
3689        RouteNetlinkMessage::DelRule,
3690        0,
3691        AF_INET as u16,
3692        vec![FakeRuleRequestResponse{
3693            expected_request_args: RuleRequestArgs::Del(default_rule_for_family(AF_INET as u16)),
3694            expected_ip_version: IpVersion::V4,
3695            response: Err(Errno::ENOTSUP),
3696        }],
3697        Some(ExpectedResponse::Error(Errno::ENOTSUP)); "del_rule_v4_fails")]
3698    #[test_case(
3699        RouteNetlinkMessage::DelRule,
3700        0,
3701        AF_INET6 as u16,
3702        vec![FakeRuleRequestResponse{
3703            expected_request_args: RuleRequestArgs::Del(default_rule_for_family(AF_INET6 as u16)),
3704            expected_ip_version: IpVersion::V6,
3705            response: Err(Errno::ENOTSUP),
3706        }],
3707        Some(ExpectedResponse::Error(Errno::ENOTSUP)); "del_rule_v6_fails")]
3708    #[fuchsia::test]
3709    async fn test_rule_request(
3710        rule_fn: fn(RuleMessage) -> RouteNetlinkMessage,
3711        flags: u16,
3712        address_family: u16,
3713        requests_and_responses: Vec<FakeRuleRequestResponse>,
3714        expected_response: Option<ExpectedResponse>,
3715    ) {
3716        let rules_request_handler = FakeRuleRequestHandler::new(requests_and_responses);
3717        let (unified_request_sink, unified_request_stream) = mpsc::channel(0);
3718        let unified_request_stream = pin!(unified_request_stream);
3719        let mut handler = NetlinkRouteRequestHandler::<FakeSender<_>> { unified_request_sink };
3720
3721        let (mut client_sink, mut client, async_work_drain_task) = {
3722            crate::client::testutil::new_fake_client::<NetlinkRoute>(
3723                crate::client::testutil::CLIENT_ID_1,
3724                std::iter::empty(),
3725            )
3726        };
3727        let join_handle = fasync::Task::spawn(async_work_drain_task);
3728
3729        let header = header_with_flags(flags);
3730
3731        let handle_request_fut = handler
3732            .handle_request(
3733                NetlinkMessage::new(
3734                    header,
3735                    NetlinkPayload::InnerMessage(rule_fn(default_rule_for_family(address_family))),
3736                ),
3737                &mut client,
3738            )
3739            .fuse();
3740
3741        futures::select! {
3742            () = pin!(handle_request_fut) => {},
3743            _rules_request_handler = unified_request_stream.fold(
3744                rules_request_handler,
3745                |mut rules_request_handler, req| async move {
3746                    match req {
3747                        UnifiedRequest::RuleV4Request(request, completer) => {
3748                            completer
3749                                .send(rules_request_handler.handle_request(request))
3750                                .expect("send should succeed");
3751                            rules_request_handler
3752                        }
3753                        UnifiedRequest::RuleV6Request(request, completer) => {
3754                            completer
3755                                .send(rules_request_handler.handle_request(request))
3756                                .expect("send should succeed");
3757                            rules_request_handler
3758                        }
3759                        _ => panic!("not RuleRequest"),
3760                    }
3761                }
3762            ).fuse() => {},
3763        }
3764        assert_eq!(client_sink.take_messages(), expected_sent_messages(expected_response, header));
3765
3766        drop(client);
3767        join_handle.await;
3768    }
3769
3770    const TEST_V4_SUBNET: Subnet<Ipv4Addr> = net_subnet_v4!("192.0.2.0/24");
3771    const TEST_V4_NEXTHOP: Ipv4Addr = net_ip_v4!("192.0.2.1");
3772    const TEST_V6_SUBNET: Subnet<Ipv6Addr> = net_subnet_v6!("2001:db8::0/32");
3773    const TEST_V6_NEXTHOP: Ipv6Addr = net_ip_v6!("2001:db8::1");
3774
3775    fn test_nexthop_spec_addr<I: Ip>() -> SpecifiedAddr<I::Addr> {
3776        I::map_ip(
3777            (),
3778            |()| SpecifiedAddr::new(TEST_V4_NEXTHOP).unwrap(),
3779            |()| SpecifiedAddr::new(TEST_V6_NEXTHOP).unwrap(),
3780        )
3781    }
3782
3783    #[derive(Clone)]
3784    struct RouteRequestAndResponse<R> {
3785        request: R,
3786        response: Result<(), routes::RequestError>,
3787    }
3788
3789    #[derive(Clone, Copy)]
3790    enum RouteRequestKind {
3791        New,
3792        Del,
3793    }
3794
3795    struct TestRouteCase<I: Ip> {
3796        kind: RouteRequestKind,
3797        flags: u16,
3798        family: u16,
3799        nlas: Vec<RouteAttribute>,
3800        destination_prefix_len: u8,
3801        table: u8,
3802        rtm_type: u8,
3803        expected_request_args: Option<RouteRequestAndResponse<routes::RouteRequestArgs<I>>>,
3804        expected_response: Option<ExpectedResponse>,
3805    }
3806
3807    fn route_addr_from_spec_addr<I: Ip>(a: &SpecifiedAddr<I::Addr>) -> RouteAddress {
3808        let bytes = I::map_ip_in(a, |a| a.ipv4_bytes().to_vec(), |a| a.ipv6_bytes().to_vec());
3809        match I::VERSION {
3810            IpVersion::V4 => RouteAddress::parse(AddressFamily::Inet, &bytes).unwrap(),
3811            IpVersion::V6 => RouteAddress::parse(AddressFamily::Inet6, &bytes).unwrap(),
3812        }
3813    }
3814
3815    fn route_addr_from_subnet<I: Ip>(a: &Subnet<I::Addr>) -> RouteAddress {
3816        let bytes = I::map_ip_in(
3817            a,
3818            |a| a.network().ipv4_bytes().to_vec(),
3819            |a| a.network().ipv6_bytes().to_vec(),
3820        );
3821        match I::VERSION {
3822            IpVersion::V4 => RouteAddress::parse(AddressFamily::Inet, &bytes).unwrap(),
3823            IpVersion::V6 => RouteAddress::parse(AddressFamily::Inet6, &bytes).unwrap(),
3824        }
3825    }
3826
3827    fn build_route_test_case<I: Ip>(
3828        kind: RouteRequestKind,
3829        flags: u16,
3830        dst: Subnet<I::Addr>,
3831        next_hop: Option<SpecifiedAddr<I::Addr>>,
3832        extra_nlas: impl IntoIterator<Item = RouteAttribute>,
3833        interface_id: Option<NonZeroU64>,
3834        table: u8,
3835        rtm_type: u8,
3836        response: Result<(), routes::RequestError>,
3837    ) -> TestRouteCase<I> {
3838        let extra_nlas = extra_nlas.into_iter().collect::<Vec<_>>();
3839        let table_from_nla = extra_nlas.clone().into_iter().find_map(|nla| match nla {
3840            RouteAttribute::Table(table) => Some(NetlinkRouteTableIndex::new(table)),
3841            _ => None,
3842        });
3843        let priority_from_nla = extra_nlas.clone().into_iter().find_map(|nla| match nla {
3844            RouteAttribute::Priority(priority) => Some(priority),
3845            _ => None,
3846        });
3847
3848        TestRouteCase::<I> {
3849            kind,
3850            flags,
3851            family: {
3852                let family = match I::VERSION {
3853                    IpVersion::V4 => AF_INET,
3854                    IpVersion::V6 => AF_INET6,
3855                };
3856                // Conversion is safe as family is guaranteed to fit into an 8-bit integer.
3857                family as u16
3858            },
3859            nlas: [RouteAttribute::Destination(route_addr_from_subnet::<I>(&dst))]
3860                .into_iter()
3861                .chain(interface_id.map(|id| RouteAttribute::Oif(interface_id_as_u32(id.get()))))
3862                .chain(extra_nlas.into_iter())
3863                .collect(),
3864            destination_prefix_len: {
3865                let prefix_len = I::map_ip_in(dst, |dst| dst.prefix(), |dst| dst.prefix());
3866                prefix_len
3867            },
3868            table,
3869            rtm_type,
3870            expected_request_args: Some(RouteRequestAndResponse {
3871                request: {
3872                    match kind {
3873                        RouteRequestKind::New => {
3874                            let interface_id =
3875                                interface_id.expect("new requests must have interface id");
3876
3877                            routes::RouteRequestArgs::New::<I>(routes::NewRouteArgs::Unicast(
3878                                routes::UnicastNewRouteArgs {
3879                                    subnet: dst,
3880                                    target: fnet_routes_ext::RouteTarget {
3881                                        outbound_interface: interface_id.get(),
3882                                        next_hop,
3883                                    },
3884                                    priority: priority_from_nla.and_then(NonZeroU32::new),
3885                                    // Use the table value from the NLA if provided.
3886                                    table: table_from_nla.unwrap_or_else(|| {
3887                                        NetlinkRouteTableIndex::new(table as u32)
3888                                    }),
3889                                },
3890                            ))
3891                        }
3892                        RouteRequestKind::Del => {
3893                            routes::RouteRequestArgs::Del::<I>(routes::DelRouteArgs::Unicast(
3894                                routes::UnicastDelRouteArgs {
3895                                    subnet: dst,
3896                                    outbound_interface: interface_id,
3897                                    next_hop,
3898                                    priority: priority_from_nla
3899                                        .map(|priority| NonZeroU32::new(priority))
3900                                        .flatten(),
3901                                    // Use the table value from the NLA if provided. When the NLA
3902                                    // value is 0, use the value from the header. Default to
3903                                    // RT_TABLE_MAIN when the header value is unspecified.
3904                                    table: table_from_nla
3905                                        .map(|table_nla| {
3906                                            NonZeroNetlinkRouteTableIndex::new(table_nla)
3907                                        })
3908                                        .flatten()
3909                                        .unwrap_or_else(|| {
3910                                            NonZeroNetlinkRouteTableIndex::new_non_zero(
3911                                                NonZeroU32::new(table as u32).unwrap_or(
3912                                                    NonZeroU32::new(
3913                                                        rt_class_t_RT_TABLE_MAIN as u32,
3914                                                    )
3915                                                    .unwrap(),
3916                                                ),
3917                                            )
3918                                        }),
3919                                },
3920                            ))
3921                        }
3922                    }
3923                },
3924                response,
3925            }),
3926            expected_response: (flags & NLM_F_ACK == NLM_F_ACK).then_some(ExpectedResponse::Ack),
3927        }
3928    }
3929
3930    fn build_valid_route_test_case_with_extra_nlas<I: Ip>(
3931        kind: RouteRequestKind,
3932        flags: u16,
3933        addr: Subnet<I::Addr>,
3934        next_hop: Option<SpecifiedAddr<I::Addr>>,
3935        extra_nlas: impl IntoIterator<Item = RouteAttribute>,
3936        interface_id: Option<u64>,
3937        table: u8,
3938        rtm_type: u8,
3939        response: Result<(), routes::RequestError>,
3940    ) -> TestRouteCase<I> {
3941        build_route_test_case::<I>(
3942            kind,
3943            flags,
3944            addr,
3945            next_hop,
3946            extra_nlas,
3947            interface_id.map(|id| NonZeroU64::new(id)).flatten(),
3948            table,
3949            rtm_type,
3950            response,
3951        )
3952    }
3953
3954    fn build_valid_route_test_case<I: Ip>(
3955        kind: RouteRequestKind,
3956        flags: u16,
3957        addr: Subnet<I::Addr>,
3958        interface_id: Option<u64>,
3959        table: u8,
3960        rtm_type: u8,
3961        response: Result<(), routes::RequestError>,
3962    ) -> TestRouteCase<I> {
3963        build_valid_route_test_case_with_extra_nlas::<I>(
3964            kind,
3965            flags,
3966            addr,
3967            None,
3968            None,
3969            interface_id,
3970            table,
3971            rtm_type,
3972            response,
3973        )
3974    }
3975
3976    fn build_invalid_route_test_case<I: Ip>(
3977        kind: RouteRequestKind,
3978        flags: u16,
3979        addr: Subnet<I::Addr>,
3980        interface_id: Option<u64>,
3981        table: u8,
3982        rtm_type: u8,
3983        errno: Errno,
3984    ) -> TestRouteCase<I> {
3985        build_invalid_route_test_case_with_extra_nlas::<I>(
3986            kind,
3987            flags,
3988            addr,
3989            None,
3990            None,
3991            interface_id,
3992            table,
3993            rtm_type,
3994            errno,
3995        )
3996    }
3997
3998    fn build_invalid_route_test_case_with_extra_nlas<I: Ip>(
3999        kind: RouteRequestKind,
4000        flags: u16,
4001        addr: Subnet<I::Addr>,
4002        next_hop: Option<SpecifiedAddr<I::Addr>>,
4003        extra_nlas: impl IntoIterator<Item = RouteAttribute>,
4004        interface_id: Option<u64>,
4005        table: u8,
4006        rtm_type: u8,
4007        errno: Errno,
4008    ) -> TestRouteCase<I> {
4009        TestRouteCase {
4010            expected_request_args: None,
4011            expected_response: Some(ExpectedResponse::Error(errno)),
4012            ..build_valid_route_test_case_with_extra_nlas::<I>(
4013                kind,
4014                flags,
4015                addr,
4016                next_hop,
4017                extra_nlas,
4018                interface_id,
4019                table,
4020                rtm_type,
4021                Ok(()),
4022            )
4023        }
4024    }
4025
4026    #[derive(Clone, Debug, PartialEq)]
4027    enum RouteRequestArgsEither {
4028        V4(routes::RequestArgs<Ipv4>),
4029        V6(routes::RequestArgs<Ipv6>),
4030    }
4031
4032    async fn test_route_request<I: Ip>(
4033        request: NetlinkMessage<RouteNetlinkMessage>,
4034        req_and_resp: Option<RouteRequestAndResponse<routes::RouteRequestArgs<I>>>,
4035    ) -> Vec<SentMessage<RouteNetlinkMessage>> {
4036        let (mut client_sink, mut client, async_work_drain_task) = {
4037            crate::client::testutil::new_fake_client::<NetlinkRoute>(
4038                crate::client::testutil::CLIENT_ID_1,
4039                std::iter::empty(),
4040            )
4041        };
4042        let join_handle = fasync::Task::spawn(async_work_drain_task);
4043
4044        let (unified_request_sink, unified_request_stream) = mpsc::channel(0);
4045        let mut handler = NetlinkRouteRequestHandler::<FakeSender<_>> { unified_request_sink };
4046
4047        let mut unified_request_stream = pin!(unified_request_stream);
4048
4049        match req_and_resp {
4050            None => {
4051                handler.handle_request(request, &mut client).await;
4052                assert_matches!(unified_request_stream.next().now_or_never(), None);
4053            }
4054            Some(RouteRequestAndResponse { request: expected_request, response }) => {
4055                let ((), ()) =
4056                    futures::join!(handler.handle_request(request, &mut client), async {
4057                        let args = match I::VERSION {
4058                            IpVersion::V4 => {
4059                                let next = unified_request_stream.next();
4060                                let routes::Request {
4061                                    args,
4062                                    sequence_number: _,
4063                                    client: _,
4064                                    completer,
4065                                } = match next.await.expect("handler should send request") {
4066                                    UnifiedRequest::RoutesV4Request(request) => request,
4067                                    UnifiedRequest::InterfacesRequest(_)
4068                                    | UnifiedRequest::RoutesV6Request(_)
4069                                    | UnifiedRequest::RuleV4Request(_, _)
4070                                    | UnifiedRequest::RuleV6Request(_, _)
4071                                    | UnifiedRequest::NeighborsRequest(_) => {
4072                                        panic!("not RoutesV4Request")
4073                                    }
4074                                };
4075                                completer.send(response).expect("handler should be alive");
4076                                RouteRequestArgsEither::V4(args)
4077                            }
4078                            IpVersion::V6 => {
4079                                let next = unified_request_stream.next();
4080                                let routes::Request {
4081                                    args,
4082                                    sequence_number: _,
4083                                    client: _,
4084                                    completer,
4085                                } = match next.await.expect("handler should send request") {
4086                                    UnifiedRequest::RoutesV6Request(request) => request,
4087                                    UnifiedRequest::InterfacesRequest(_)
4088                                    | UnifiedRequest::RoutesV4Request(_)
4089                                    | UnifiedRequest::RuleV4Request(_, _)
4090                                    | UnifiedRequest::RuleV6Request(_, _)
4091                                    | UnifiedRequest::NeighborsRequest(_) => {
4092                                        panic!("not RoutesV6Request")
4093                                    }
4094                                };
4095                                completer.send(response).expect("handler should be alive");
4096                                RouteRequestArgsEither::V6(args)
4097                            }
4098                        };
4099
4100                        #[derive(GenericOverIp)]
4101                        #[generic_over_ip(I, Ip)]
4102                        struct EqualityInputs<I: Ip> {
4103                            args: RouteRequestArgsEither,
4104                            expected_request: routes::RequestArgs<I>,
4105                        }
4106
4107                        I::map_ip_in(
4108                            EqualityInputs {
4109                                args: args,
4110                                expected_request: routes::RequestArgs::Route(expected_request),
4111                            },
4112                            |EqualityInputs { args, expected_request }| {
4113                                let args = assert_matches!(
4114                                    args,
4115                                    RouteRequestArgsEither::V4(request) => request
4116                                );
4117                                assert_eq!(args, expected_request);
4118                            },
4119                            |EqualityInputs { args, expected_request }| {
4120                                let args = assert_matches!(
4121                                    args,
4122                                    RouteRequestArgsEither::V6(request) => request
4123                                );
4124                                assert_eq!(args, expected_request);
4125                            },
4126                        );
4127                    });
4128            }
4129        }
4130
4131        drop(client);
4132        join_handle.await;
4133        client_sink.take_messages()
4134    }
4135
4136    /// Test RTM_NEWROUTE and RTM_DELROUTE
4137    // Add route test cases.
4138    // Downcasts are safe as constants have values that fit within an 8-bit integer.
4139    #[test_case(
4140        TestRouteCase::<Ipv4> {
4141            family: AF_UNSPEC as u16,
4142            ..build_invalid_route_test_case(
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::EINVAL,
4150            )
4151        }; "new_v4_invalid_family_ack")]
4152    #[test_case(
4153        TestRouteCase::<Ipv6> {
4154            family: AF_UNSPEC as u16,
4155            ..build_invalid_route_test_case(
4156                RouteRequestKind::New,
4157                0,
4158                TEST_V6_SUBNET,
4159                Some(interfaces::testutil::LO_INTERFACE_ID),
4160                rt_class_t_RT_TABLE_MAIN as u8,
4161                RTN_UNICAST as u8,
4162                Errno::EINVAL,
4163            )
4164        })]
4165    #[test_case(
4166        TestRouteCase::<Ipv4> {
4167            flags: NLM_F_ACK | NLM_F_REPLACE,
4168            ..build_invalid_route_test_case::<Ipv4>(
4169                RouteRequestKind::New,
4170                NLM_F_ACK,
4171                TEST_V4_SUBNET,
4172                Some(interfaces::testutil::LO_INTERFACE_ID),
4173                rt_class_t_RT_TABLE_MAIN as u8,
4174                RTN_UNICAST as u8,
4175                Errno::ENOTSUP,
4176            )
4177        }; "new_v4_replace_flag_ack")]
4178    #[test_case(
4179        build_invalid_route_test_case::<Ipv6>(
4180            RouteRequestKind::New,
4181            NLM_F_REPLACE,
4182            TEST_V6_SUBNET,
4183            Some(interfaces::testutil::LO_INTERFACE_ID),
4184            rt_class_t_RT_TABLE_MAIN as u8,
4185            RTN_UNICAST as u8,
4186            Errno::ENOTSUP,
4187        ); "new_v6_replace_flag_no_ack")]
4188    #[test_case(
4189        build_invalid_route_test_case::<Ipv4>(
4190            RouteRequestKind::New,
4191            NLM_F_ACK,
4192            TEST_V4_SUBNET,
4193            Some(interfaces::testutil::LO_INTERFACE_ID),
4194            rt_class_t_RT_TABLE_MAIN as u8,
4195            RTN_MULTICAST as u8,
4196            Errno::ENOTSUP); "new_v4_non_unicast_type_ack")]
4197    #[test_case(
4198        build_invalid_route_test_case::<Ipv6>(
4199            RouteRequestKind::New,
4200            0,
4201            TEST_V6_SUBNET,
4202            Some(interfaces::testutil::LO_INTERFACE_ID),
4203            rt_class_t_RT_TABLE_MAIN as u8,
4204            RTN_MULTICAST as u8,
4205            Errno::ENOTSUP); "new_v6_non_unicast_type_no_ack")]
4206    #[test_case(
4207        build_valid_route_test_case::<Ipv4>(
4208            RouteRequestKind::New,
4209            NLM_F_ACK,
4210            net_subnet_v4!("0.0.0.0/0"),
4211            Some(interfaces::testutil::LO_INTERFACE_ID),
4212            rt_class_t_RT_TABLE_MAIN as u8,
4213            RTN_UNICAST as u8,
4214            Ok(())); "new_v4_default_route_ok_ack")]
4215    #[test_case(
4216        build_valid_route_test_case::<Ipv4>(
4217            RouteRequestKind::New,
4218            0,
4219            net_subnet_v4!("0.0.0.0/24"),
4220            Some(interfaces::testutil::LO_INTERFACE_ID),
4221            rt_class_t_RT_TABLE_MAIN as u8,
4222            RTN_UNICAST as u8,
4223            Ok(())); "new_v4_unspecified_route_non_zero_prefix_ok_no_ack")]
4224    #[test_case(
4225        build_valid_route_test_case::<Ipv6>(
4226            RouteRequestKind::New,
4227            NLM_F_ACK,
4228            net_subnet_v6!("::/0"),
4229            Some(interfaces::testutil::LO_INTERFACE_ID),
4230            rt_class_t_RT_TABLE_MAIN as u8,
4231            RTN_UNICAST as u8,
4232            Ok(())); "new_v6_default_route_prefix_ack")]
4233    #[test_case(
4234        build_valid_route_test_case::<Ipv6>(
4235            RouteRequestKind::New,
4236            0,
4237            net_subnet_v6!("::/64"),
4238            Some(interfaces::testutil::LO_INTERFACE_ID),
4239            rt_class_t_RT_TABLE_MAIN as u8,
4240            RTN_UNICAST as u8,
4241            Ok(())); "new_v6_unspecified_route_non_zero_prefix_no_ack")]
4242    #[test_case(
4243        build_valid_route_test_case::<Ipv4>(
4244            RouteRequestKind::New,
4245            NLM_F_ACK,
4246            TEST_V4_SUBNET,
4247            Some(interfaces::testutil::LO_INTERFACE_ID),
4248            rt_class_t_RT_TABLE_MAIN as u8,
4249            RTN_UNICAST as u8,
4250            Ok(())); "new_v4_ok_ack")]
4251    #[test_case(
4252        build_valid_route_test_case::<Ipv6>(
4253            RouteRequestKind::New,
4254            NLM_F_ACK,
4255            TEST_V6_SUBNET,
4256            Some(interfaces::testutil::LO_INTERFACE_ID),
4257            rt_class_t_RT_TABLE_MAIN as u8,
4258            RTN_UNICAST as u8,
4259            Ok(())); "new_v6_ok_ack")]
4260    #[test_case(
4261        build_valid_route_test_case::<Ipv4>(
4262            RouteRequestKind::New,
4263            0,
4264            TEST_V4_SUBNET,
4265            Some(interfaces::testutil::LO_INTERFACE_ID),
4266            rt_class_t_RT_TABLE_MAIN as u8,
4267            RTN_UNICAST as u8,
4268            Ok(())); "new_v4_ok_no_ack")]
4269    #[test_case(
4270        build_valid_route_test_case::<Ipv6>(
4271            RouteRequestKind::New,
4272            0,
4273            TEST_V6_SUBNET,
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_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            Some(test_nexthop_spec_addr::<Ipv4>()),
4284            [RouteAttribute::Gateway(route_addr_from_spec_addr::<Ipv4>(
4285                &test_nexthop_spec_addr::<Ipv4>()
4286            ))],
4287            Some(interfaces::testutil::LO_INTERFACE_ID),
4288            rt_class_t_RT_TABLE_MAIN as u8,
4289            RTN_UNICAST as u8,
4290            Ok(())); "new_v4_with_nexthop_ok_ack")]
4291    #[test_case(
4292        build_valid_route_test_case_with_extra_nlas::<Ipv6>(
4293            RouteRequestKind::New,
4294            0,
4295            TEST_V6_SUBNET,
4296            Some(test_nexthop_spec_addr::<Ipv6>()),
4297            [RouteAttribute::Gateway(route_addr_from_spec_addr::<Ipv6>(
4298                &test_nexthop_spec_addr::<Ipv6>()
4299            ))],
4300            Some(interfaces::testutil::LO_INTERFACE_ID),
4301            rt_class_t_RT_TABLE_MAIN as u8,
4302            RTN_UNICAST as u8,
4303            Ok(())); "new_v6_with_nexthop_ok_no_ack")]
4304    #[test_case(
4305        build_valid_route_test_case_with_extra_nlas::<Ipv4>(
4306            RouteRequestKind::New,
4307            NLM_F_ACK,
4308            TEST_V4_SUBNET,
4309            None,
4310            [RouteAttribute::Gateway(RouteAddress::parse(AddressFamily::Inet, &net_ip_v4!("0.0.0.0").ipv4_bytes().to_vec()).unwrap())],
4311            Some(interfaces::testutil::LO_INTERFACE_ID),
4312            rt_class_t_RT_TABLE_MAIN as u8,
4313            RTN_UNICAST as u8,
4314            Ok(())); "new_v4_unspecified_nexthop_ok_ack")]
4315    #[test_case(
4316        build_valid_route_test_case_with_extra_nlas::<Ipv6>(
4317            RouteRequestKind::New,
4318            0,
4319            TEST_V6_SUBNET,
4320            None,
4321            [RouteAttribute::Gateway(RouteAddress::parse(AddressFamily::Inet6, &net_ip_v6!("::").ipv6_bytes().to_vec()).unwrap())],
4322            Some(interfaces::testutil::LO_INTERFACE_ID),
4323            rt_class_t_RT_TABLE_MAIN as u8,
4324            RTN_UNICAST as u8,
4325            Ok(())); "new_v6_unspecified_nexthop_no_ack")]
4326    #[test_case(
4327        build_valid_route_test_case_with_extra_nlas::<Ipv4>(
4328            RouteRequestKind::New,
4329            NLM_F_ACK,
4330            TEST_V4_SUBNET,
4331            None,
4332            [RouteAttribute::Priority(100)],
4333            Some(interfaces::testutil::LO_INTERFACE_ID),
4334            rt_class_t_RT_TABLE_MAIN as u8,
4335            RTN_UNICAST as u8,
4336            Ok(())); "new_v4_priority_nla_ok_ack")]
4337    #[test_case(
4338        build_valid_route_test_case_with_extra_nlas::<Ipv6>(
4339            RouteRequestKind::New,
4340            0,
4341            TEST_V6_SUBNET,
4342            None,
4343            [RouteAttribute::Priority(100)],
4344            Some(interfaces::testutil::LO_INTERFACE_ID),
4345            rt_class_t_RT_TABLE_MAIN as u8,
4346            RTN_UNICAST as u8,
4347            Ok(())); "new_v6_priority_nla_ok_no_ack")]
4348    #[test_case(
4349        TestRouteCase::<Ipv4> {
4350            expected_response: Some(ExpectedResponse::Error(Errno::EINVAL)),
4351            ..build_valid_route_test_case(
4352                RouteRequestKind::New,
4353                NLM_F_ACK,
4354                TEST_V4_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::InvalidRequest),
4359            )
4360        }; "new_v4_invalid_request_response_ack")]
4361    #[test_case(
4362        TestRouteCase::<Ipv6> {
4363            expected_response: Some(ExpectedResponse::Error(Errno::EINVAL)),
4364            ..build_valid_route_test_case(
4365                RouteRequestKind::New,
4366                NLM_F_ACK,
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::InvalidRequest),
4372            )
4373        }; "new_v6_invalid_request_response_no_ack")]
4374    #[test_case(
4375        TestRouteCase::<Ipv6> {
4376            expected_response: Some(ExpectedResponse::Error(Errno::ENODEV)),
4377            ..build_valid_route_test_case(
4378                RouteRequestKind::New,
4379                0,
4380                TEST_V6_SUBNET,
4381                Some(interfaces::testutil::LO_INTERFACE_ID),
4382                rt_class_t_RT_TABLE_MAIN as u8,
4383                RTN_UNICAST as u8,
4384                Err(routes::RequestError::UnrecognizedInterface),
4385            )
4386        }; "new_v6_unrecognized_interface_response_no_ack")]
4387    #[test_case(
4388        TestRouteCase::<Ipv6> {
4389            expected_response: Some(ExpectedResponse::Error(Errno::ENOTSUP)),
4390            ..build_valid_route_test_case(
4391                RouteRequestKind::New,
4392                0,
4393                TEST_V6_SUBNET,
4394                Some(interfaces::testutil::LO_INTERFACE_ID),
4395                rt_class_t_RT_TABLE_MAIN as u8,
4396                RTN_UNICAST as u8,
4397                Err(routes::RequestError::Unknown),
4398            )
4399        }; "new_v6_unknown_response_no_ack")]
4400    #[test_case(
4401        TestRouteCase::<Ipv4> {
4402            nlas: vec![
4403                RouteAttribute::Destination(route_addr_from_subnet::<Ipv4>(
4404                    &TEST_V4_SUBNET
4405                )),
4406            ],
4407            ..build_invalid_route_test_case(
4408                RouteRequestKind::New,
4409                0,
4410                TEST_V4_SUBNET,
4411                Some(interfaces::testutil::LO_INTERFACE_ID),
4412                rt_class_t_RT_TABLE_MAIN as u8,
4413                RTN_UNICAST as u8,
4414                Errno::ENOTSUP,
4415            )
4416        }; "new_v4_missing_oif_nla_ack")]
4417    #[test_case(
4418        TestRouteCase::<Ipv6> {
4419            nlas: vec![
4420                RouteAttribute::Destination(route_addr_from_subnet::<Ipv6>(
4421                    &TEST_V6_SUBNET
4422                )),
4423            ],
4424            ..build_invalid_route_test_case(
4425                RouteRequestKind::New,
4426                0,
4427                TEST_V6_SUBNET,
4428                Some(interfaces::testutil::LO_INTERFACE_ID),
4429                rt_class_t_RT_TABLE_MAIN as u8,
4430                RTN_UNICAST as u8,
4431                Errno::ENOTSUP,
4432            )
4433        }; "new_v6_missing_oif_nla_ack")]
4434    #[test_case(
4435        TestRouteCase::<Ipv4> {
4436            nlas: vec![
4437                RouteAttribute::Destination(route_addr_from_subnet::<Ipv4>(
4438                    &TEST_V4_SUBNET
4439                )),
4440            ],
4441            ..build_invalid_route_test_case(
4442                RouteRequestKind::New,
4443                0,
4444                TEST_V4_SUBNET,
4445                Some(interfaces::testutil::LO_INTERFACE_ID),
4446                rt_class_t_RT_TABLE_MAIN as u8,
4447                RTN_UNICAST as u8,
4448                Errno::ENOTSUP,
4449            )
4450        }; "new_v4_missing_oif_nla_no_ack")]
4451    #[test_case(
4452        TestRouteCase::<Ipv6> {
4453            nlas: vec![
4454                RouteAttribute::Destination(route_addr_from_subnet::<Ipv6>(
4455                    &TEST_V6_SUBNET
4456                )),
4457            ],
4458            ..build_invalid_route_test_case(
4459                RouteRequestKind::New,
4460                0,
4461                TEST_V6_SUBNET,
4462                Some(interfaces::testutil::LO_INTERFACE_ID),
4463                rt_class_t_RT_TABLE_MAIN as u8,
4464                RTN_UNICAST as u8,
4465                Errno::ENOTSUP,
4466            )
4467        }; "new_v6_missing_oif_nla_no_ack")]
4468    #[test_case(
4469        TestRouteCase::<Ipv4> {
4470            nlas: vec![
4471                RouteAttribute::Oif(interfaces::testutil::ETH_INTERFACE_ID.try_into().unwrap()),
4472            ],
4473            destination_prefix_len: 1,
4474            ..build_invalid_route_test_case(
4475                RouteRequestKind::New,
4476                NLM_F_ACK,
4477                TEST_V4_SUBNET,
4478                Some(interfaces::testutil::LO_INTERFACE_ID),
4479                rt_class_t_RT_TABLE_MAIN as u8,
4480                RTN_UNICAST as u8,
4481                Errno::EINVAL,
4482            )
4483        }; "new_v4_missing_destination_nla_nonzero_prefix_ack")]
4484    #[test_case(
4485        TestRouteCase::<Ipv6> {
4486            nlas: vec![
4487                RouteAttribute::Oif(interfaces::testutil::ETH_INTERFACE_ID.try_into().unwrap()),
4488            ],
4489            destination_prefix_len: 1,
4490            ..build_invalid_route_test_case(
4491                RouteRequestKind::New,
4492                0,
4493                TEST_V6_SUBNET,
4494                Some(interfaces::testutil::LO_INTERFACE_ID),
4495                rt_class_t_RT_TABLE_MAIN as u8,
4496                RTN_UNICAST as u8,
4497                Errno::EINVAL,
4498            )
4499        }; "new_v6_missing_destination_nla_nonzero_prefix_no_ack")]
4500    #[test_case(
4501        TestRouteCase::<Ipv4> {
4502            nlas: vec![
4503                RouteAttribute::Oif(interfaces::testutil::LO_INTERFACE_ID.try_into().unwrap()),
4504            ],
4505            ..build_valid_route_test_case(
4506                RouteRequestKind::New,
4507                NLM_F_ACK,
4508                net_subnet_v4!("0.0.0.0/0"),
4509                Some(interfaces::testutil::LO_INTERFACE_ID),
4510                rt_class_t_RT_TABLE_MAIN as u8,
4511                RTN_UNICAST as u8,
4512                Ok(()))}; "new_v4_missing_destination_nla_zero_prefix_ack")]
4513    #[test_case(
4514        TestRouteCase::<Ipv6> {
4515            nlas: vec![
4516                RouteAttribute::Oif(interfaces::testutil::LO_INTERFACE_ID.try_into().unwrap()),
4517            ],
4518            ..build_valid_route_test_case(
4519                RouteRequestKind::New,
4520                0,
4521                net_subnet_v6!("::/0"),
4522                Some(interfaces::testutil::LO_INTERFACE_ID),
4523                rt_class_t_RT_TABLE_MAIN as u8,
4524                RTN_UNICAST as u8,
4525                Ok(()))}; "new_v6_missing_destination_nla_zero_prefix_no_ack")]
4526    #[test_case(
4527        TestRouteCase::<Ipv4> {
4528            nlas: Vec::new(),
4529            ..build_invalid_route_test_case(
4530                RouteRequestKind::New,
4531                NLM_F_ACK,
4532                TEST_V4_SUBNET,
4533                Some(interfaces::testutil::LO_INTERFACE_ID),
4534                rt_class_t_RT_TABLE_MAIN as u8,
4535                RTN_UNICAST as u8,
4536                Errno::EINVAL,
4537            )
4538        }; "new_v4_no_nlas_ack")]
4539    #[test_case(
4540        TestRouteCase::<Ipv6> {
4541            nlas: Vec::new(),
4542            ..build_invalid_route_test_case(
4543                RouteRequestKind::New,
4544                0,
4545                TEST_V6_SUBNET,
4546                Some(interfaces::testutil::LO_INTERFACE_ID),
4547                rt_class_t_RT_TABLE_MAIN as u8,
4548                RTN_UNICAST as u8,
4549                Errno::EINVAL,
4550            )
4551        }; "new_v6_no_nlas_no_ack")]
4552    #[test_case(
4553        build_valid_route_test_case_with_extra_nlas::<Ipv4>(
4554            RouteRequestKind::New,
4555            NLM_F_ACK,
4556            TEST_V4_SUBNET,
4557            None,
4558            // `RT_TABLE_COMPAT` is generally used when `table` is outside the bounds of u8 values.
4559            [RouteAttribute::Table(u8::MAX as u32 + 1)],
4560            Some(interfaces::testutil::LO_INTERFACE_ID),
4561            rt_class_t_RT_TABLE_COMPAT as u8,
4562            RTN_UNICAST as u8,
4563            Ok(())); "new_v4_with_table_nla_rt_table_compat_ack")]
4564    #[test_case(
4565        build_valid_route_test_case_with_extra_nlas::<Ipv6>(
4566            RouteRequestKind::New,
4567            0,
4568            TEST_V6_SUBNET,
4569            None,
4570            // `RT_TABLE_COMPAT` is generally used when `table` is outside the bounds of u8 values.
4571            [RouteAttribute::Table(u8::MAX as u32 + 1)],
4572            Some(interfaces::testutil::LO_INTERFACE_ID),
4573            rt_class_t_RT_TABLE_COMPAT as u8,
4574            RTN_UNICAST as u8,
4575            Ok(())); "new_v6_with_table_nla_rt_table_compat_no_ack")]
4576    #[test_case(
4577        build_valid_route_test_case_with_extra_nlas::<Ipv4>(
4578            RouteRequestKind::New,
4579            NLM_F_ACK,
4580            TEST_V4_SUBNET,
4581            None,
4582            [RouteAttribute::Table(u8::MAX as u32 + 1)],
4583            Some(interfaces::testutil::LO_INTERFACE_ID),
4584            rt_class_t_RT_TABLE_MAIN as u8,
4585            RTN_UNICAST as u8,
4586            Ok(())); "new_v4_with_table_nla_rt_class_t_RT_TABLE_MAIN as u8_ack")]
4587    #[test_case(
4588        build_valid_route_test_case_with_extra_nlas::<Ipv6>(
4589            RouteRequestKind::New,
4590            0,
4591            TEST_V6_SUBNET,
4592            None,
4593            [RouteAttribute::Table(u8::MAX as u32 + 1)],
4594            Some(interfaces::testutil::LO_INTERFACE_ID),
4595            rt_class_t_RT_TABLE_MAIN as u8,
4596            RTN_UNICAST as u8,
4597            Ok(())); "new_v6_with_table_nla_rt_class_t_RT_TABLE_MAIN as u8_no_ack")]
4598    #[test_case(
4599        TestRouteCase::<Ipv4> {
4600            destination_prefix_len: u8::MAX,
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_invalid_prefix_len_ack")]
4611    #[test_case(
4612        TestRouteCase::<Ipv6> {
4613            destination_prefix_len: u8::MAX,
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_invalid_prefix_len_no_ack")]
4624    #[test_case(
4625        TestRouteCase::<Ipv4> {
4626            destination_prefix_len: 0,
4627            ..build_invalid_route_test_case(
4628                RouteRequestKind::New,
4629                NLM_F_ACK,
4630                TEST_V4_SUBNET,
4631                Some(interfaces::testutil::LO_INTERFACE_ID),
4632                rt_class_t_RT_TABLE_MAIN as u8,
4633                RTN_UNICAST as u8,
4634                Errno::EINVAL,
4635            )
4636        }; "new_v4_zero_prefix_len_ack")]
4637    #[test_case(
4638        TestRouteCase::<Ipv6> {
4639            destination_prefix_len: 0,
4640            ..build_invalid_route_test_case(
4641                RouteRequestKind::New,
4642                0,
4643                TEST_V6_SUBNET,
4644                Some(interfaces::testutil::LO_INTERFACE_ID),
4645                rt_class_t_RT_TABLE_MAIN as u8,
4646                RTN_UNICAST as u8,
4647                Errno::EINVAL,
4648            )
4649        }; "new_v6_zero_prefix_len_no_ack")]
4650    // Delete route test cases.
4651    #[test_case(
4652        TestRouteCase::<Ipv4> {
4653            family: AF_UNSPEC as u16,
4654            ..build_invalid_route_test_case(
4655                RouteRequestKind::Del,
4656                NLM_F_ACK,
4657                TEST_V4_SUBNET,
4658                Some(interfaces::testutil::LO_INTERFACE_ID),
4659                rt_class_t_RT_TABLE_MAIN as u8,
4660                RTN_UNICAST as u8,
4661                Errno::EINVAL,
4662            )
4663        }; "del_v4_invalid_family_ack")]
4664    #[test_case(
4665        TestRouteCase::<Ipv6> {
4666            family: AF_UNSPEC as u16,
4667            ..build_invalid_route_test_case(
4668                RouteRequestKind::Del,
4669                0,
4670                TEST_V6_SUBNET,
4671                Some(interfaces::testutil::LO_INTERFACE_ID),
4672                rt_class_t_RT_TABLE_MAIN as u8,
4673                RTN_UNICAST as u8,
4674                Errno::EINVAL,
4675            )
4676        }; "del_v6_invalid_family_no_ack")]
4677    #[test_case(
4678        build_invalid_route_test_case::<Ipv4>(
4679            RouteRequestKind::Del,
4680            NLM_F_ACK,
4681            TEST_V4_SUBNET,
4682            Some(interfaces::testutil::LO_INTERFACE_ID),
4683            rt_class_t_RT_TABLE_MAIN as u8,
4684            RTN_MULTICAST as u8,
4685            Errno::ENOTSUP); "del_v4_non_unicast_type_ack")]
4686    #[test_case(
4687        build_invalid_route_test_case::<Ipv6>(
4688            RouteRequestKind::Del,
4689            0,
4690            TEST_V6_SUBNET,
4691            Some(interfaces::testutil::LO_INTERFACE_ID),
4692            rt_class_t_RT_TABLE_MAIN as u8,
4693            RTN_MULTICAST as u8,
4694            Errno::ENOTSUP); "del_v6_non_unicast_type_no_ack")]
4695    #[test_case(
4696        build_valid_route_test_case::<Ipv4>(
4697            RouteRequestKind::Del,
4698            NLM_F_ACK,
4699            net_subnet_v4!("0.0.0.0/0"),
4700            Some(interfaces::testutil::LO_INTERFACE_ID),
4701            rt_class_t_RT_TABLE_MAIN as u8,
4702            RTN_UNICAST as u8,
4703            Ok(())); "del_v4_default_route_ok_ack")]
4704    #[test_case(
4705        build_valid_route_test_case::<Ipv4>(
4706            RouteRequestKind::Del,
4707            0,
4708            net_subnet_v4!("0.0.0.0/24"),
4709            Some(interfaces::testutil::LO_INTERFACE_ID),
4710            rt_class_t_RT_TABLE_MAIN as u8,
4711            RTN_UNICAST as u8,
4712            Ok(())); "del_v4_unspecified_route_non_zero_prefix_ok_no_ack")]
4713    #[test_case(
4714        build_valid_route_test_case::<Ipv6>(
4715            RouteRequestKind::Del,
4716            NLM_F_ACK,
4717            net_subnet_v6!("::/0"),
4718            Some(interfaces::testutil::LO_INTERFACE_ID),
4719            rt_class_t_RT_TABLE_MAIN as u8,
4720            RTN_UNICAST as u8,
4721            Ok(())); "del_v6_default_route_prefix_ack")]
4722    #[test_case(
4723        build_valid_route_test_case::<Ipv6>(
4724            RouteRequestKind::Del,
4725            0,
4726            net_subnet_v6!("::/64"),
4727            Some(interfaces::testutil::LO_INTERFACE_ID),
4728            rt_class_t_RT_TABLE_MAIN as u8,
4729            RTN_UNICAST as u8,
4730            Ok(())); "del_v6_unspecified_route_non_zero_prefix_no_ack")]
4731    #[test_case(
4732        build_valid_route_test_case::<Ipv4>(
4733            RouteRequestKind::Del,
4734            NLM_F_ACK,
4735            TEST_V4_SUBNET,
4736            None,
4737            rt_class_t_RT_TABLE_MAIN as u8,
4738            RTN_UNICAST as u8,
4739            Ok(())); "del_v4_only_dest_nla_ack")]
4740    #[test_case(
4741        build_valid_route_test_case::<Ipv6>(
4742            RouteRequestKind::Del,
4743            NLM_F_ACK,
4744            TEST_V6_SUBNET,
4745            None,
4746            rt_class_t_RT_TABLE_MAIN as u8,
4747            RTN_UNICAST as u8,
4748            Ok(())); "del_v6_only_dest_nla_ack")]
4749    #[test_case(
4750        build_valid_route_test_case::<Ipv4>(
4751            RouteRequestKind::Del,
4752            0,
4753            TEST_V4_SUBNET,
4754            None,
4755            rt_class_t_RT_TABLE_MAIN as u8,
4756            RTN_UNICAST as u8,
4757            Ok(())); "del_v4_only_dest_nla_no_ack")]
4758    #[test_case(
4759        build_valid_route_test_case::<Ipv6>(
4760            RouteRequestKind::Del,
4761            0,
4762            TEST_V6_SUBNET,
4763            None,
4764            rt_class_t_RT_TABLE_MAIN as u8,
4765            RTN_UNICAST as u8,
4766            Ok(())); "del_v6_only_dest_nla_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            Some(test_nexthop_spec_addr::<Ipv4>()),
4773            [RouteAttribute::Gateway(route_addr_from_spec_addr::<Ipv4>(
4774                &test_nexthop_spec_addr::<Ipv4>()
4775            ))],
4776            Some(interfaces::testutil::LO_INTERFACE_ID),
4777            rt_class_t_RT_TABLE_MAIN as u8,
4778            RTN_UNICAST as u8,
4779            Ok(())); "del_v4_with_nexthop_ok_ack")]
4780    #[test_case(
4781        build_valid_route_test_case_with_extra_nlas::<Ipv6>(
4782            RouteRequestKind::Del,
4783            0,
4784            TEST_V6_SUBNET,
4785            Some(test_nexthop_spec_addr::<Ipv6>()),
4786            [RouteAttribute::Gateway(route_addr_from_spec_addr::<Ipv6>(
4787                &test_nexthop_spec_addr::<Ipv6>()
4788            ))],
4789            Some(interfaces::testutil::LO_INTERFACE_ID),
4790            rt_class_t_RT_TABLE_MAIN as u8,
4791            RTN_UNICAST as u8,
4792            Ok(())); "del_v6_with_nexthop_ok_no_ack")]
4793    #[test_case(
4794        build_valid_route_test_case_with_extra_nlas::<Ipv4>(
4795            RouteRequestKind::Del,
4796            NLM_F_ACK,
4797            TEST_V4_SUBNET,
4798            None,
4799            [RouteAttribute::Gateway(RouteAddress::parse(AddressFamily::Inet, &net_ip_v4!("0.0.0.0").ipv4_bytes().to_vec()).unwrap())],
4800            Some(interfaces::testutil::LO_INTERFACE_ID),
4801            rt_class_t_RT_TABLE_MAIN as u8,
4802            RTN_UNICAST as u8,
4803            Ok(())); "del_v4_unspecified_nexthop_ok_ack")]
4804    #[test_case(
4805        build_valid_route_test_case_with_extra_nlas::<Ipv6>(
4806            RouteRequestKind::Del,
4807            0,
4808            TEST_V6_SUBNET,
4809            None,
4810            [RouteAttribute::Gateway(RouteAddress::parse(AddressFamily::Inet6, &net_ip_v6!("::").ipv6_bytes().to_vec()).unwrap())],
4811            Some(interfaces::testutil::LO_INTERFACE_ID),
4812            rt_class_t_RT_TABLE_MAIN as u8,
4813            RTN_UNICAST as u8,
4814            Ok(())); "del_v6_unspecified_nexthop_no_ack")]
4815    #[test_case(
4816        build_valid_route_test_case_with_extra_nlas::<Ipv4>(
4817            RouteRequestKind::Del,
4818            NLM_F_ACK,
4819            TEST_V4_SUBNET,
4820            None,
4821            [RouteAttribute::Priority(100)],
4822            Some(interfaces::testutil::LO_INTERFACE_ID),
4823            rt_class_t_RT_TABLE_MAIN as u8,
4824            RTN_UNICAST as u8,
4825            Ok(())); "del_v4_priority_nla_ok_ack")]
4826    #[test_case(
4827        build_valid_route_test_case_with_extra_nlas::<Ipv6>(
4828            RouteRequestKind::Del,
4829            0,
4830            TEST_V6_SUBNET,
4831            None,
4832            [RouteAttribute::Priority(100)],
4833            Some(interfaces::testutil::LO_INTERFACE_ID),
4834            rt_class_t_RT_TABLE_MAIN as u8,
4835            RTN_UNICAST as u8,
4836            Ok(())); "del_v6_priority_nla_ok_no_ack")]
4837    #[test_case(
4838        TestRouteCase::<Ipv4> {
4839            expected_response: Some(ExpectedResponse::Error(Errno::EINVAL)),
4840            ..build_valid_route_test_case(
4841                RouteRequestKind::Del,
4842                NLM_F_ACK,
4843                TEST_V4_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::InvalidRequest),
4848            )
4849        }; "del_v4_invalid_request_response_ack")]
4850    #[test_case(
4851        TestRouteCase::<Ipv6> {
4852            expected_response: Some(ExpectedResponse::Error(Errno::EINVAL)),
4853            ..build_valid_route_test_case(
4854                RouteRequestKind::Del,
4855                NLM_F_ACK,
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::InvalidRequest),
4861            )
4862        }; "del_v6_invalid_request_response_no_ack")]
4863    #[test_case(
4864        TestRouteCase::<Ipv6> {
4865            expected_response: Some(ExpectedResponse::Error(Errno::ENODEV)),
4866            ..build_valid_route_test_case(
4867                RouteRequestKind::Del,
4868                0,
4869                TEST_V6_SUBNET,
4870                Some(interfaces::testutil::LO_INTERFACE_ID),
4871                rt_class_t_RT_TABLE_MAIN as u8,
4872                RTN_UNICAST as u8,
4873                Err(routes::RequestError::UnrecognizedInterface),
4874            )
4875        }; "del_v6_unrecognized_interface_response_no_ack")]
4876    #[test_case(
4877        TestRouteCase::<Ipv6> {
4878            expected_response: Some(ExpectedResponse::Error(Errno::ENOTSUP)),
4879            ..build_valid_route_test_case(
4880                RouteRequestKind::Del,
4881                0,
4882                TEST_V6_SUBNET,
4883                Some(interfaces::testutil::LO_INTERFACE_ID),
4884                rt_class_t_RT_TABLE_MAIN as u8,
4885                RTN_UNICAST as u8,
4886                Err(routes::RequestError::Unknown),
4887            )
4888        }; "del_v6_unknown_response_no_ack")]
4889    #[test_case(
4890        build_valid_route_test_case::<Ipv4>(
4891            RouteRequestKind::Del,
4892            NLM_F_ACK,
4893            TEST_V4_SUBNET,
4894            Some(interfaces::testutil::LO_INTERFACE_ID),
4895            rt_class_t_RT_TABLE_MAIN as u8,
4896            RTN_UNICAST as u8,
4897            Ok(()),
4898        ); "del_v4_dest_oif_nlas_ack")]
4899    #[test_case(
4900        build_valid_route_test_case::<Ipv6>(
4901            RouteRequestKind::Del,
4902            NLM_F_ACK,
4903            TEST_V6_SUBNET,
4904            Some(interfaces::testutil::LO_INTERFACE_ID),
4905            rt_class_t_RT_TABLE_MAIN as u8,
4906            RTN_UNICAST as u8,
4907            Ok(()),
4908        ); "del_v6_dest_oif_nlas_ack")]
4909    #[test_case(
4910        build_valid_route_test_case::<Ipv4>(
4911            RouteRequestKind::Del,
4912            0,
4913            TEST_V4_SUBNET,
4914            Some(interfaces::testutil::LO_INTERFACE_ID),
4915            rt_class_t_RT_TABLE_MAIN as u8,
4916            RTN_UNICAST as u8,
4917            Ok(()),
4918        ); "del_v4_dest_oif_nlas_no_ack")]
4919    #[test_case(
4920        build_valid_route_test_case::<Ipv6>(
4921            RouteRequestKind::Del,
4922            0,
4923            TEST_V6_SUBNET,
4924            Some(interfaces::testutil::LO_INTERFACE_ID),
4925            rt_class_t_RT_TABLE_MAIN as u8,
4926            RTN_UNICAST as u8,
4927            Ok(()),
4928        ); "del_v6_dest_oif_nlas_no_ack")]
4929    #[test_case(
4930        TestRouteCase::<Ipv4> {
4931            nlas: Vec::new(),
4932            destination_prefix_len: 1,
4933            ..build_invalid_route_test_case(
4934                RouteRequestKind::Del,
4935                NLM_F_ACK,
4936                TEST_V4_SUBNET,
4937                Some(interfaces::testutil::LO_INTERFACE_ID),
4938                rt_class_t_RT_TABLE_MAIN as u8,
4939                RTN_UNICAST as u8,
4940                Errno::EINVAL,
4941            )
4942        }; "del_v4_missing_destination_nla_nonzero_prefix_ack")]
4943    #[test_case(
4944        TestRouteCase::<Ipv6> {
4945            nlas: Vec::new(),
4946            destination_prefix_len: 1,
4947            ..build_invalid_route_test_case(
4948                RouteRequestKind::Del,
4949                0,
4950                TEST_V6_SUBNET,
4951                Some(interfaces::testutil::LO_INTERFACE_ID),
4952                rt_class_t_RT_TABLE_MAIN as u8,
4953                RTN_UNICAST as u8,
4954                Errno::EINVAL,
4955            )
4956        }; "del_v6_missing_destination_nla_nonzero_prefix_no_ack")]
4957    #[test_case(
4958        TestRouteCase::<Ipv4> {
4959            nlas: Vec::new(),
4960            destination_prefix_len: 0,
4961            ..build_valid_route_test_case(
4962                RouteRequestKind::Del,
4963                NLM_F_ACK,
4964                net_subnet_v4!("0.0.0.0/0"),
4965                None,
4966                rt_class_t_RT_TABLE_MAIN as u8,
4967                RTN_UNICAST as u8,
4968                Ok(()),
4969            )
4970        }; "del_v4_no_nlas_zero_prefix_len_ack")]
4971    #[test_case(
4972        TestRouteCase::<Ipv6> {
4973            nlas: Vec::new(),
4974            destination_prefix_len: 0,
4975            ..build_valid_route_test_case(
4976                RouteRequestKind::Del,
4977                0,
4978                net_subnet_v6!("::/0"),
4979                None,
4980                rt_class_t_RT_TABLE_MAIN as u8,
4981                RTN_UNICAST as u8,
4982                Ok(()),
4983            )
4984        }; "del_v6_no_nlas_zero_prefix_len_no_ack")]
4985    #[test_case(
4986        build_valid_route_test_case::<Ipv4>(
4987            RouteRequestKind::Del,
4988            NLM_F_ACK,
4989            net_subnet_v4!("0.0.0.0/0"),
4990            Some(interfaces::testutil::LO_INTERFACE_ID),
4991            rt_class_t_RT_TABLE_MAIN as u8,
4992            RTN_UNICAST as u8,
4993            Ok(()),
4994        ); "del_v4_missing_destination_nla_zero_prefix_ack")]
4995    #[test_case(
4996        build_valid_route_test_case::<Ipv6>(
4997            RouteRequestKind::Del,
4998            0,
4999            net_subnet_v6!("::/0"),
5000            Some(interfaces::testutil::LO_INTERFACE_ID),
5001            rt_class_t_RT_TABLE_MAIN as u8,
5002            RTN_UNICAST as u8,
5003            Ok(()),
5004        ); "del_v6_missing_destination_nla_zero_prefix_no_ack")]
5005    #[test_case(
5006        build_valid_route_test_case_with_extra_nlas::<Ipv4>(
5007            RouteRequestKind::Del,
5008            NLM_F_ACK,
5009            TEST_V4_SUBNET,
5010            None,
5011            // `RT_TABLE_COMPAT` is generally used when `table` is outside the bounds of u8 values.
5012            [RouteAttribute::Table(u8::MAX as u32 + 1)],
5013            Some(interfaces::testutil::LO_INTERFACE_ID),
5014            rt_class_t_RT_TABLE_COMPAT as u8,
5015            RTN_UNICAST as u8,
5016            Ok(())); "del_v4_with_table_nla_rt_table_compat_ack")]
5017    #[test_case(
5018        build_valid_route_test_case_with_extra_nlas::<Ipv6>(
5019            RouteRequestKind::Del,
5020            0,
5021            TEST_V6_SUBNET,
5022            None,
5023            // `RT_TABLE_COMPAT` is generally used when `table` is outside the bounds of u8 values.
5024            [RouteAttribute::Table(u8::MAX as u32 + 1)],
5025            Some(interfaces::testutil::LO_INTERFACE_ID),
5026            rt_class_t_RT_TABLE_COMPAT as u8,
5027            RTN_UNICAST as u8,
5028            Ok(())); "del_v6_with_table_nla_rt_table_compat_no_ack")]
5029    #[test_case(
5030        build_valid_route_test_case_with_extra_nlas::<Ipv4>(
5031            RouteRequestKind::Del,
5032            NLM_F_ACK,
5033            TEST_V4_SUBNET,
5034            None,
5035            [RouteAttribute::Table(u8::MAX as u32 + 1)],
5036            Some(interfaces::testutil::LO_INTERFACE_ID),
5037            rt_class_t_RT_TABLE_MAIN as u8,
5038            RTN_UNICAST as u8,
5039            Ok(())); "del_v4_with_table_nla_rt_class_t_RT_TABLE_MAIN as u8_ack")]
5040    #[test_case(
5041        build_valid_route_test_case_with_extra_nlas::<Ipv6>(
5042            RouteRequestKind::Del,
5043            0,
5044            TEST_V6_SUBNET,
5045            None,
5046            [RouteAttribute::Table(u8::MAX as u32 + 1)],
5047            Some(interfaces::testutil::LO_INTERFACE_ID),
5048            rt_class_t_RT_TABLE_MAIN as u8,
5049            RTN_UNICAST as u8,
5050            Ok(())); "del_v6_with_table_nla_rt_class_t_RT_TABLE_MAIN as u8_no_ack")]
5051    #[test_case(
5052        TestRouteCase::<Ipv4> {
5053            destination_prefix_len: u8::MAX,
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_invalid_prefix_len_ack")]
5064    #[test_case(
5065        TestRouteCase::<Ipv6> {
5066            destination_prefix_len: u8::MAX,
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_invalid_prefix_len_no_ack")]
5077    #[test_case(
5078        TestRouteCase::<Ipv4> {
5079            destination_prefix_len: 0,
5080            ..build_invalid_route_test_case(
5081                RouteRequestKind::Del,
5082                NLM_F_ACK,
5083                TEST_V4_SUBNET,
5084                Some(interfaces::testutil::LO_INTERFACE_ID),
5085                rt_class_t_RT_TABLE_MAIN as u8,
5086                RTN_UNICAST as u8,
5087                Errno::EINVAL,
5088            )
5089        }; "del_v4_zero_prefix_len_ack")]
5090    #[test_case(
5091        TestRouteCase::<Ipv6> {
5092            destination_prefix_len: 0,
5093            ..build_invalid_route_test_case(
5094                RouteRequestKind::Del,
5095                0,
5096                TEST_V6_SUBNET,
5097                Some(interfaces::testutil::LO_INTERFACE_ID),
5098                rt_class_t_RT_TABLE_MAIN as u8,
5099                RTN_UNICAST as u8,
5100                Errno::EINVAL,
5101            )
5102        }; "del_v6_zero_prefix_len_no_ack")]
5103    #[test_case(
5104        build_valid_route_test_case_with_extra_nlas::<Ipv4>(
5105            RouteRequestKind::Del,
5106            NLM_F_ACK,
5107            TEST_V4_SUBNET,
5108            None,
5109            [RouteAttribute::Oif(0)],
5110            None,
5111            rt_class_t_RT_TABLE_MAIN as u8,
5112            RTN_UNICAST as u8,
5113            Ok(()),
5114        ); "del_v4_zero_interface_id_ack")]
5115    #[test_case(
5116        build_valid_route_test_case_with_extra_nlas::<Ipv6>(
5117            RouteRequestKind::Del,
5118            NLM_F_ACK,
5119            TEST_V6_SUBNET,
5120            None,
5121            [RouteAttribute::Oif(0)],
5122            None,
5123            rt_class_t_RT_TABLE_MAIN as u8,
5124            RTN_UNICAST as u8,
5125            Ok(()),
5126        ); "del_v6_zero_interface_id_no_ack")]
5127    #[fuchsia::test]
5128    async fn test_new_del_route<I: Ip>(test_case: TestRouteCase<I>) {
5129        let TestRouteCase {
5130            kind,
5131            flags,
5132            family,
5133            nlas,
5134            destination_prefix_len,
5135            table,
5136            rtm_type,
5137            expected_request_args,
5138            expected_response,
5139        }: TestRouteCase<I> = test_case;
5140
5141        let header = header_with_flags(flags);
5142        let route_message = {
5143            let mut message = RouteMessage::default();
5144            message.header.address_family = AddressFamily::from(family as u8);
5145            message.header.destination_prefix_length = destination_prefix_len;
5146            message.header.table = table;
5147            message.header.kind = RouteType::from(rtm_type);
5148            message.attributes = nlas;
5149            message
5150        };
5151
5152        let (message, request) = match kind {
5153            RouteRequestKind::New => {
5154                (RouteNetlinkMessage::NewRoute(route_message), expected_request_args)
5155            }
5156            RouteRequestKind::Del => {
5157                (RouteNetlinkMessage::DelRoute(route_message), expected_request_args)
5158            }
5159        };
5160
5161        pretty_assertions::assert_eq!(
5162            test_route_request(
5163                NetlinkMessage::new(header, NetlinkPayload::InnerMessage(message)),
5164                request,
5165            )
5166            .await,
5167            expected_sent_messages(expected_response, header),
5168        )
5169    }
5170
5171    async fn test_neighbor_request(
5172        request: NetlinkMessage<RouteNetlinkMessage>,
5173        expected_request: Option<neighbors::NeighborRequestArgs>,
5174    ) -> Vec<SentMessage<RouteNetlinkMessage>> {
5175        let (mut client_sink, mut client, async_work_drain_task) =
5176            crate::client::testutil::new_fake_client::<NetlinkRoute>(
5177                crate::client::testutil::CLIENT_ID_1,
5178                std::iter::empty(),
5179            );
5180        let join_handle = fasync::Task::spawn(async_work_drain_task);
5181        {
5182            let (unified_request_sink, mut unified_request_stream) = mpsc::channel(0);
5183
5184            let mut handler = NetlinkRouteRequestHandler::<FakeSender<_>> { unified_request_sink };
5185
5186            let handle_request_fut = handler.handle_request(request, &mut client).fuse();
5187            let mut handle_request_fut = pin!(handle_request_fut);
5188            let mut request_fut = unified_request_stream.next().fuse();
5189
5190            futures::select! {
5191                _ = handle_request_fut => assert_eq!(expected_request, None),
5192                request = request_fut => match request.expect("request channel should be open") {
5193                    UnifiedRequest::NeighborsRequest(neigh_req) => {
5194                        let neighbors::Request { args, sequence_number: _, client: _, completer } =
5195                            neigh_req;
5196                        assert_eq!(expected_request, Some(args));
5197                        completer.send(Ok(())).expect("handler should be alive");
5198                        handle_request_fut.await;
5199                    },
5200                    _ => panic!("received unexpected request"),
5201                }
5202            }
5203        }
5204        drop(client);
5205        join_handle.await;
5206        client_sink.take_messages()
5207    }
5208
5209    #[test_case(
5210        NLM_F_DUMP,
5211        NeighbourHeader::default(),
5212        vec![],
5213        Some(neighbors::GetNeighborArgs::Dump { ip_version: None, interface: None }),
5214        Some(ExpectedResponse::Done); "dump all")]
5215    #[test_case(
5216        NLM_F_DUMP,
5217        NeighbourHeader { family: AddressFamily::Inet, ..Default::default() },
5218        vec![NeighbourAttribute::IfIndex(1)],
5219        Some(neighbors::GetNeighborArgs::Dump {
5220            ip_version: Some(IpVersion::V4),
5221            interface: Some(NonZeroU64::new(1).unwrap()),
5222        }),
5223        Some(ExpectedResponse::Done); "dump ipv4 on interface 1")]
5224    #[test_case(
5225        NLM_F_DUMP | NLM_F_ACK,
5226        NeighbourHeader::default(),
5227        vec![],
5228        Some(neighbors::GetNeighborArgs::Dump { ip_version: None, interface: None }),
5229        Some(ExpectedResponse::Done); "dump all with ack")]
5230    #[test_case(
5231        NLM_F_DUMP,
5232        NeighbourHeader { family: AddressFamily::Local, ..Default::default() },
5233        vec![],
5234        None,
5235        Some(ExpectedResponse::Error(Errno::EAFNOSUPPORT)); "dump invalid request")]
5236    #[test_case(
5237        0,
5238        NeighbourHeader { family: AddressFamily::Inet, ifindex: 1, ..Default::default() },
5239        vec![NeighbourAttribute::Destination(std_ip_v4!("192.168.0.1").into())],
5240        Some(neighbors::GetNeighborArgs::Get {
5241            ip: fidl_ip!("192.168.0.1"),
5242            interface: NonZeroU64::new(1).unwrap(),
5243        }),
5244        None; "get")]
5245    #[test_case(
5246        NLM_F_ACK,
5247        NeighbourHeader { family: AddressFamily::Inet, ifindex: 1, ..Default::default() },
5248        vec![NeighbourAttribute::Destination(std_ip_v4!("192.168.0.1").into())],
5249        Some(neighbors::GetNeighborArgs::Get {
5250            ip: fidl_ip!("192.168.0.1"),
5251            interface: NonZeroU64::new(1).unwrap(),
5252        }),
5253        Some(ExpectedResponse::Ack); "get with ack")]
5254    #[test_case(
5255        0,
5256        NeighbourHeader::default(),
5257        vec![],
5258        None,
5259        Some(ExpectedResponse::Error(Errno::EAFNOSUPPORT)); "get invalid request")]
5260    #[fuchsia::test]
5261    async fn get_neighbor_with_faked_response(
5262        flags: u16,
5263        header: NeighbourHeader,
5264        attrs: Vec<NeighbourAttribute>,
5265        expected_request_args: Option<neighbors::GetNeighborArgs>,
5266        expected_response: Option<ExpectedResponse>,
5267    ) {
5268        let nl_header = header_with_flags(flags);
5269        let neighbor_message = {
5270            let mut message = NeighbourMessage::default();
5271            message.header = header;
5272            message.attributes = attrs;
5273            message
5274        };
5275
5276        pretty_assertions::assert_eq!(
5277            test_neighbor_request(
5278                NetlinkMessage::new(
5279                    nl_header,
5280                    NetlinkPayload::InnerMessage(RouteNetlinkMessage::GetNeighbour(
5281                        neighbor_message
5282                    )),
5283                ),
5284                expected_request_args.map(neighbors::NeighborRequestArgs::Get),
5285            )
5286            .await,
5287            expected_sent_messages(expected_response, nl_header),
5288        )
5289    }
5290
5291    #[test_case(
5292        0,
5293        NeighbourHeader { family: AddressFamily::Inet, ifindex: 1, ..Default::default() },
5294        vec![NeighbourAttribute::Destination(std_ip_v4!("192.168.0.1").into())],
5295        Some(neighbors::DelNeighborArgs {
5296            ip: fidl_ip!("192.168.0.1"),
5297            interface: NonZeroU64::new(1).unwrap(),
5298        }),
5299        None; "del ipv4")]
5300    #[test_case(
5301        0,
5302        NeighbourHeader { family: AddressFamily::Inet6, ifindex: 1, ..Default::default() },
5303        vec![NeighbourAttribute::Destination(std_ip_v6!("fe80::1").into())],
5304        Some(neighbors::DelNeighborArgs {
5305            ip: fidl_ip!("fe80::1"),
5306            interface: NonZeroU64::new(1).unwrap(),
5307        }),
5308        None; "del ipv6")]
5309    #[test_case(
5310        NLM_F_ACK,
5311        NeighbourHeader { family: AddressFamily::Inet, ifindex: 1, ..Default::default() },
5312        vec![NeighbourAttribute::Destination(std_ip_v4!("192.168.0.1").into())],
5313        Some(neighbors::DelNeighborArgs {
5314            ip: fidl_ip!("192.168.0.1"),
5315            interface: NonZeroU64::new(1).unwrap(),
5316        }),
5317        Some(ExpectedResponse::Ack); "del with ack")]
5318    #[test_case(
5319        0,
5320        NeighbourHeader { family: AddressFamily::Local, ifindex: 1, ..Default::default() },
5321        vec![NeighbourAttribute::Destination(std_ip_v4!("192.168.0.1").into())],
5322        None,
5323        Some(ExpectedResponse::Error(Errno::EAFNOSUPPORT)); "del invalid family")]
5324    #[test_case(
5325        0,
5326        NeighbourHeader { family: AddressFamily::Inet, ifindex: 1, ..Default::default() },
5327        vec![],
5328        None,
5329        Some(ExpectedResponse::Error(Errno::EINVAL)); "del missing destination")]
5330    #[test_case(
5331        0,
5332        NeighbourHeader { family: AddressFamily::Inet, ifindex: 0, ..Default::default() },
5333        vec![NeighbourAttribute::Destination(std_ip_v4!("192.168.0.1").into())],
5334        None,
5335        Some(ExpectedResponse::Error(Errno::EINVAL)); "del missing interface")]
5336    #[fuchsia::test]
5337    async fn del_neighbor_with_faked_response(
5338        flags: u16,
5339        header: NeighbourHeader,
5340        attrs: Vec<NeighbourAttribute>,
5341        expected_request_args: Option<neighbors::DelNeighborArgs>,
5342        expected_response: Option<ExpectedResponse>,
5343    ) {
5344        let nl_header = header_with_flags(flags);
5345        let neighbor_message = {
5346            let mut message = NeighbourMessage::default();
5347            message.header = header;
5348            message.attributes = attrs;
5349            message
5350        };
5351
5352        pretty_assertions::assert_eq!(
5353            test_neighbor_request(
5354                NetlinkMessage::new(
5355                    nl_header,
5356                    NetlinkPayload::InnerMessage(RouteNetlinkMessage::DelNeighbour(
5357                        neighbor_message
5358                    )),
5359                ),
5360                expected_request_args.map(neighbors::NeighborRequestArgs::Del),
5361            )
5362            .await,
5363            expected_sent_messages(expected_response, nl_header),
5364        )
5365    }
5366
5367    #[test_case(
5368        0,
5369        NeighbourHeader { family: AddressFamily::Inet, ifindex: 1, ..Default::default() },
5370        vec![NeighbourAttribute::Destination(std_ip_v4!("192.168.0.1").into())],
5371        None,
5372        Some(ExpectedResponse::Error(Errno::ENOTSUP)); "missing flags")]
5373    #[test_case(
5374        NLM_F_CREATE | NLM_F_REPLACE,
5375        NeighbourHeader {
5376            family: AddressFamily::Inet,
5377            ifindex: 1,
5378            state: NeighbourState::Permanent,
5379            ..Default::default()
5380        },
5381        vec![
5382            NeighbourAttribute::Destination(std_ip_v4!("192.168.0.1").into()),
5383            NeighbourAttribute::LinkLocalAddress(vec![0, 1, 2, 3, 4, 5]),
5384        ],
5385        Some(neighbors::NeighborRequestArgs::New(neighbors::NewNeighborArgs::CreateStatic {
5386            ip: fidl_ip!("192.168.0.1"),
5387            interface: NonZeroU64::new(1).unwrap(),
5388            mac: fnet::MacAddress { octets: [0, 1, 2, 3, 4, 5] },
5389        })),
5390        None; "create static ipv4")]
5391    #[test_case(
5392        NLM_F_CREATE | NLM_F_REPLACE,
5393        NeighbourHeader {
5394            family: AddressFamily::Inet6,
5395            ifindex: 1,
5396            state: NeighbourState::Permanent,
5397            ..Default::default()
5398        },
5399        vec![
5400            NeighbourAttribute::Destination(std_ip_v6!("fe80::1").into()),
5401            NeighbourAttribute::LinkLocalAddress(vec![0, 1, 2, 3, 4, 5]),
5402        ],
5403        Some(neighbors::NeighborRequestArgs::New(neighbors::NewNeighborArgs::CreateStatic {
5404            ip: fidl_ip!("fe80::1"),
5405            interface: NonZeroU64::new(1).unwrap(),
5406            mac: fnet::MacAddress { octets: [0, 1, 2, 3, 4, 5] },
5407        })),
5408        None; "create static ipv6")]
5409    #[test_case(
5410        NLM_F_REPLACE,
5411        NeighbourHeader {
5412            family: AddressFamily::Inet,
5413            ifindex: 1,
5414            state: NeighbourState::Probe,
5415            ..Default::default()
5416        },
5417        vec![NeighbourAttribute::Destination(std_ip_v4!("192.168.0.1").into())],
5418        Some(neighbors::NeighborRequestArgs::New(neighbors::NewNeighborArgs::ProbeExisting {
5419            ip: fidl_ip!("192.168.0.1"),
5420            interface: NonZeroU64::new(1).unwrap(),
5421        })),
5422        None; "probe existing")]
5423    #[test_case(
5424        NLM_F_REPLACE,
5425        NeighbourHeader { family: AddressFamily::Local, ifindex: 1, ..Default::default() },
5426        vec![
5427            NeighbourAttribute::Destination(std_ip_v4!("192.168.0.1").into()),
5428        ],
5429        None,
5430        Some(ExpectedResponse::Error(Errno::EAFNOSUPPORT)); "invalid family")]
5431    #[test_case(
5432        NLM_F_CREATE | NLM_F_REPLACE,
5433        NeighbourHeader {
5434            family: AddressFamily::Inet,
5435            ifindex: 1,
5436            state: NeighbourState::Probe,
5437            ..Default::default()
5438        },
5439        vec![
5440            NeighbourAttribute::Destination(std_ip_v4!("192.168.0.1").into()),
5441            NeighbourAttribute::LinkLocalAddress(vec![0, 1, 2, 3, 4, 5]),
5442        ],
5443        None,
5444        Some(ExpectedResponse::Error(Errno::EINVAL)); "invalid state for create static")]
5445    #[test_case(
5446        NLM_F_CREATE | NLM_F_REPLACE,
5447        NeighbourHeader {
5448            family: AddressFamily::Inet,
5449            ifindex: 1,
5450            state: NeighbourState::Permanent,
5451            ..Default::default()
5452        },
5453        vec![
5454            NeighbourAttribute::Destination(std_ip_v4!("192.168.0.1").into()),
5455        ],
5456        None,
5457        Some(ExpectedResponse::Error(Errno::EINVAL)); "invalid state for probe")]
5458    #[test_case(
5459        NLM_F_CREATE | NLM_F_REPLACE,
5460        NeighbourHeader {
5461            family: AddressFamily::Inet,
5462            ifindex: 1,
5463            state: NeighbourState::Permanent,
5464            ..Default::default()
5465        },
5466        vec![NeighbourAttribute::Destination(std_ip_v4!("192.168.0.1").into())],
5467        None,
5468        Some(ExpectedResponse::Error(Errno::EINVAL)); "create static missing mac")]
5469    #[fuchsia::test]
5470    async fn new_neighbor_with_faked_response(
5471        flags: u16,
5472        header: NeighbourHeader,
5473        attrs: Vec<NeighbourAttribute>,
5474        expected_request_args: Option<neighbors::NeighborRequestArgs>,
5475        expected_response: Option<ExpectedResponse>,
5476    ) {
5477        let nl_header = header_with_flags(flags);
5478        let neighbor_message = {
5479            let mut message = NeighbourMessage::default();
5480            message.header = header;
5481            message.attributes = attrs;
5482            message
5483        };
5484
5485        pretty_assertions::assert_eq!(
5486            test_neighbor_request(
5487                NetlinkMessage::new(
5488                    nl_header,
5489                    NetlinkPayload::InnerMessage(RouteNetlinkMessage::NewNeighbour(
5490                        neighbor_message
5491                    )),
5492                ),
5493                expected_request_args,
5494            )
5495            .await,
5496            expected_sent_messages(expected_response, nl_header),
5497        )
5498    }
5499}