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