netlink/
protocol_family.rs

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