netstack3_base/testutil/
addr.rs

1// Copyright 2024 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//! Defines shareable address constants for use in tests.
6
7use net_declare::{net_ip_v4, net_ip_v6, net_mac, net_subnet_v4, net_subnet_v6};
8use net_types::ethernet::Mac;
9use net_types::ip::{
10    GenericOverIp, Ip, IpAddress, Ipv4, Ipv4Addr, Ipv6, Ipv6Addr, Ipv6Scope, Subnet,
11};
12use net_types::{
13    MulticastAddr, NonMappedAddr, SpecifiedAddr, UnicastAddr, UnicastAddress, Witness as _,
14};
15
16use crate::device::address::AssignedAddrIpExt;
17use crate::socket::DualStackIpExt;
18
19/// An extension trait for `Ip` providing test-related functionality.
20///
21/// This trait acts as a marker for [`TestIpExt`] for both `Self` and
22/// `Self::OtherVersion`.
23pub trait TestDualStackIpExt: TestIpExt + DualStackIpExt<OtherVersion: TestIpExt> {}
24
25impl<I> TestDualStackIpExt for I where I: TestIpExt + DualStackIpExt<OtherVersion: TestIpExt> {}
26
27/// An extension trait for `Ip` providing test-related functionality.
28pub trait TestIpExt: Ip + packet_formats::ip::IpExt + AssignedAddrIpExt {
29    /// An instance of [`TestAddrs`] providing addresses for use in tests.
30    const TEST_ADDRS: TestAddrs<Self::Addr>;
31
32    /// Get an IP address in the same subnet as `Self::TEST_ADDRS`.
33    ///
34    /// `last` is the value to be put in the last octet of the IP address.
35    fn get_other_ip_address(last: u8) -> SpecifiedAddr<Self::Addr>;
36
37    /// Get an IP address in a different subnet from `Self::TEST_ADDRS`.
38    ///
39    /// `last` is the value to be put in the last octet of the IP address.
40    fn get_other_remote_ip_address(last: u8) -> SpecifiedAddr<Self::Addr>;
41
42    /// Get a multicast IP address.
43    ///
44    /// `last` is the value to be put in the last octet of the IP address.
45    fn get_multicast_addr(last: u8) -> MulticastAddr<Self::Addr>;
46}
47
48impl TestIpExt for Ipv4 {
49    const TEST_ADDRS: TestAddrs<Ipv4Addr> = TEST_ADDRS_V4;
50
51    fn get_other_ip_address(last: u8) -> SpecifiedAddr<Ipv4Addr> {
52        let mut bytes = Self::TEST_ADDRS.local_ip.get().ipv4_bytes();
53        bytes[bytes.len() - 1] = last;
54        SpecifiedAddr::new(Ipv4Addr::new(bytes)).unwrap()
55    }
56
57    fn get_other_remote_ip_address(last: u8) -> SpecifiedAddr<Self::Addr> {
58        let mut bytes = Self::TEST_ADDRS.local_ip.get().ipv4_bytes();
59        bytes[0] += 1;
60        bytes[bytes.len() - 1] = last;
61        SpecifiedAddr::new(Ipv4Addr::new(bytes)).unwrap()
62    }
63
64    fn get_multicast_addr(last: u8) -> MulticastAddr<Self::Addr> {
65        assert!(u32::from(Self::Addr::BYTES * 8 - Self::MULTICAST_SUBNET.prefix()) > u8::BITS);
66        let mut bytes = Self::MULTICAST_SUBNET.network().ipv4_bytes();
67        bytes[bytes.len() - 1] = last;
68        MulticastAddr::new(Ipv4Addr::new(bytes)).unwrap()
69    }
70}
71
72impl TestIpExt for Ipv6 {
73    const TEST_ADDRS: TestAddrs<Ipv6Addr> = TEST_ADDRS_V6;
74
75    fn get_other_ip_address(last: u8) -> SpecifiedAddr<Ipv6Addr> {
76        let mut bytes = Self::TEST_ADDRS.local_ip.get().ipv6_bytes();
77        bytes[bytes.len() - 1] = last;
78        SpecifiedAddr::new(Ipv6Addr::from(bytes)).unwrap()
79    }
80
81    fn get_other_remote_ip_address(last: u8) -> SpecifiedAddr<Self::Addr> {
82        let mut bytes = Self::TEST_ADDRS.local_ip.get().ipv6_bytes();
83        bytes[0] += 1;
84        bytes[bytes.len() - 1] = last;
85        SpecifiedAddr::new(Ipv6Addr::from(bytes)).unwrap()
86    }
87
88    fn get_multicast_addr(last: u8) -> MulticastAddr<Self::Addr> {
89        assert!((Self::Addr::BYTES * 8 - Self::MULTICAST_SUBNET.prefix()) as u32 > u8::BITS);
90        let mut bytes = Self::MULTICAST_SUBNET.network().ipv6_bytes();
91        // Don't use the reserved (0) scope for these addresses.
92        bytes[1] = Ipv6Scope::MULTICAST_SCOPE_ID_GLOBAL;
93        bytes[bytes.len() - 1] = last;
94        MulticastAddr::new(Ipv6Addr::from_bytes(bytes)).unwrap()
95    }
96}
97
98/// A configuration for a simple network.
99///
100/// `TestAddrs` describes a simple network with two IP hosts
101/// - one remote and one local - both on the same Ethernet network.
102#[derive(Clone, GenericOverIp)]
103#[generic_over_ip(A, IpAddress)]
104pub struct TestAddrs<A: IpAddress> {
105    /// The subnet of the local Ethernet network.
106    pub subnet: Subnet<A>,
107    /// The IP address of our interface to the local network (must be in
108    /// subnet).
109    pub local_ip: SpecifiedAddr<A>,
110    /// The MAC address of our interface to the local network.
111    pub local_mac: UnicastAddr<Mac>,
112    /// The remote host's IP address (must be in subnet if provided).
113    pub remote_ip: SpecifiedAddr<A>,
114    /// The remote host's MAC address.
115    pub remote_mac: UnicastAddr<Mac>,
116}
117
118const LOCAL_MAC: UnicastAddr<Mac> =
119    unsafe { UnicastAddr::new_unchecked(net_mac!("00:01:02:03:04:05")) };
120const REMOTE_MAC: UnicastAddr<Mac> =
121    unsafe { UnicastAddr::new_unchecked(net_mac!("06:07:08:09:0A:0B")) };
122
123/// A `TestAddrs` with reasonable values for an IPv4 network.
124pub const TEST_ADDRS_V4: TestAddrs<Ipv4Addr> = TestAddrs {
125    subnet: net_subnet_v4!("192.0.2.0/24"),
126    local_ip: unsafe { SpecifiedAddr::new_unchecked(net_ip_v4!("192.0.2.1")) },
127    local_mac: LOCAL_MAC,
128    remote_ip: unsafe { SpecifiedAddr::new_unchecked(net_ip_v4!("192.0.2.2")) },
129    remote_mac: REMOTE_MAC,
130};
131
132/// A `TestAddrs` with reasonable values for an IPv6 network.
133pub const TEST_ADDRS_V6: TestAddrs<Ipv6Addr> = TestAddrs {
134    subnet: net_subnet_v6!("2001:db8::/32"),
135    local_ip: unsafe { SpecifiedAddr::new_unchecked(net_ip_v6!("2001:db8::1")) },
136    local_mac: LOCAL_MAC,
137    remote_ip: unsafe { SpecifiedAddr::new_unchecked(net_ip_v6!("2001:db8::2")) },
138    remote_mac: REMOTE_MAC,
139};
140
141impl<A: IpAddress> TestAddrs<A> {
142    /// Creates a copy of `self` with all the remote and local fields reversed.
143    pub fn swap(&self) -> Self {
144        Self {
145            subnet: self.subnet,
146            local_ip: self.remote_ip,
147            local_mac: self.remote_mac,
148            remote_ip: self.local_ip,
149            remote_mac: self.local_mac,
150        }
151    }
152
153    /// Gets the local address with the non mapped and unicast witnesses
154    /// applied.
155    pub fn local_non_mapped_unicast(&self) -> NonMappedAddr<UnicastAddr<A>>
156    where
157        A: UnicastAddress,
158    {
159        NonMappedAddr::new(UnicastAddr::try_from(self.local_ip).unwrap()).unwrap()
160    }
161
162    /// Gets the remote address with the non mapped and unicast witnesses
163    /// applied.
164    pub fn remote_non_mapped_unicast(&self) -> NonMappedAddr<UnicastAddr<A>>
165    where
166        A: UnicastAddress,
167    {
168        NonMappedAddr::new(UnicastAddr::try_from(self.remote_ip).unwrap()).unwrap()
169    }
170}