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