Skip to main content

netlink/
protocol_family.rs

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