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