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