Skip to main content

netlink/
protocol_family.rs

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