routedb/types/
af.rs

1use log::trace;
2use zerocopy::{NetworkEndian, U128, U32};
3
4use crate::types::BitSpan;
5
6//------------ AddressFamily (trait) ----------------------------------------
7//
8/// The address family of an IP address as a Trait.
9///
10/// The idea of this trait is that each family will have a separate type to be
11/// able to only take the exact amount of memory needed. Useful when building
12/// trees with large amounts of addresses/prefixes. Used by rotonda-store for
13/// this purpose.
14pub trait AddressFamily:
15    std::fmt::Binary
16    + std::fmt::Debug
17    + std::hash::Hash
18    + std::fmt::Display
19    + Eq
20    + std::ops::BitAnd<Output = Self>
21    + std::ops::BitOr<Output = Self>
22    + std::ops::Shr<Self, Output = Self>
23    + std::ops::Shl<Output = Self>
24    + std::ops::Shl<Self, Output = Self>
25    + std::ops::Sub<Output = Self>
26    + Copy
27    + Ord
28    + zerocopy::FromBytes
29    + zerocopy::IntoBytes
30    + zerocopy::KnownLayout
31    + zerocopy::Immutable
32    + zerocopy::Unaligned
33{
34    /// The number of bits in the byte representation of the family.
35    const BITS: u8;
36
37    /// The type actually holding the value, u32 for IPv4, and u128 for IPv6.
38    type Inner: Into<Self> + From<u32> + From<u8>;
39
40    /// The std::net that the value of self belongs to. So,
41    /// [std::net::Ipv4Addr], and [std::net::Ipv6Addr] for IPv4, and IPv6
42    /// respectively.
43    type InnerIpAddr;
44
45    fn new(value: Self::Inner) -> Self {
46        value.into()
47    }
48
49    fn from_ipaddr(ip_addr: Self::InnerIpAddr) -> Self;
50
51    fn from_u32(value: u32) -> Self;
52    fn from_u8(value: u8) -> Self;
53
54    fn zero() -> Self;
55
56    // returns the specified nibble from `start_bit` to (and including)
57    // `start_bit + len` and shifted to the right.
58    fn into_bit_span(net: Self, start_bit: u8, len: u8) -> BitSpan;
59
60    /// Treat self as a prefix and append the given bitspan to it.
61    fn add_bit_span(self, len: u8, bs: BitSpan) -> (Self, u8);
62
63    /// fill the bits after the specified len with zeros. Interpreted as an IP
64    /// Prefix, this means that self will be truncated to the specified len.
65    fn truncate_to_len(self, len: u8) -> Self;
66
67    /// Turn self in to a [std::net::IpAddr].
68    fn into_ipaddr(self) -> std::net::IpAddr;
69
70    /// Truncate self to a u32. For IPv4 this is a NOP. For IPv6 this
71    /// truncates to 32 bits.
72    fn dangerously_truncate_to_u32(self) -> u32;
73
74    // For the sake of searching for 0/0, check the the right shift, since
75    // since shifting with MAXLEN (32 in Ipv4, or 128 in IPv6) will panic
76    // in debug mode. A failed check will simply retutrn zero. Used in
77    // finding node_ids (always zero for 0/0).
78    fn checked_shr_or_zero(self, rhs: u32) -> Self;
79    fn checked_shl_or_zero(self, rhs: u32) -> Self;
80
81    // These checked shifts are for use in debug asserts only.
82    fn checked_shr(self, rhs: u32) -> Option<Self::Inner>;
83    fn checked_shl(self, rhs: u32) -> Option<Self::Inner>;
84}
85
86//-------------- Ipv4 Type --------------------------------------------------
87
88/// Exactly fitting IPv4 bytes (4 octets).
89pub type IPv4 = zerocopy::U32<NetworkEndian>;
90
91impl AddressFamily for IPv4 {
92    const BITS: u8 = 32;
93    type Inner = u32;
94    type InnerIpAddr = std::net::Ipv4Addr;
95
96    fn zero() -> Self {
97        0.into()
98    }
99
100    fn from_u8(value: u8) -> Self {
101        IPv4::from([0, 0, 0, value])
102    }
103
104    fn from_u32(value: u32) -> Self {
105        IPv4::from(value)
106    }
107
108    fn from_ipaddr(ip_addr: Self::InnerIpAddr) -> Self {
109        IPv4::from(ip_addr.octets())
110    }
111
112    fn into_bit_span(net: Self, start_bit: u8, len: u8) -> BitSpan {
113        BitSpan {
114            bits: ((net << <U32<NetworkEndian>>::from(start_bit as u32))
115                >> <U32<NetworkEndian>>::from(((32 - len) % 32) as u32))
116            .into(),
117            len,
118        }
119    }
120
121    fn add_bit_span(self, len: u8, bs: BitSpan) -> (U32<NetworkEndian>, u8) {
122        let res = self | (bs.bits << (32 - len - bs.len) as usize);
123        (res, len + bs.len)
124    }
125
126    fn into_ipaddr(self) -> std::net::IpAddr {
127        std::net::IpAddr::V4(std::net::Ipv4Addr::from(u32::from(self)))
128    }
129
130    fn dangerously_truncate_to_u32(self) -> u32 {
131        // not dangerous at all.
132        self.into()
133    }
134
135    fn truncate_to_len(self, len: u8) -> Self {
136        self & ((1_u32.rotate_right(len as u32)
137            ^ 1_u32.saturating_sub(len as u32))
138        .wrapping_sub(1)
139            ^ u32::MAX)
140    }
141
142    fn checked_shr_or_zero(self, rhs: u32) -> Self {
143        trace!("CHECKED_SHR_OR_ZERO {} >> {}", u32::from(self), rhs);
144        if rhs == 0 || rhs == 32 {
145            return 0.into();
146        }
147        self >> U32::<NetworkEndian>::from(rhs)
148    }
149
150    fn checked_shl_or_zero(self, rhs: u32) -> Self {
151        trace!("CHECKED_SHL_OR_ZERO {} >> {}", u32::from(self), rhs);
152        if rhs == 0 || rhs >= 32 {
153            return 0.into();
154        }
155        self << U32::<NetworkEndian>::from(rhs)
156    }
157
158    fn checked_shr(self, rhs: u32) -> Option<u32> {
159        u32::from(self).checked_shr(rhs)
160    }
161
162    fn checked_shl(self, rhs: u32) -> Option<u32> {
163        u32::from(self).checked_shl(rhs)
164    }
165}
166
167//-------------- Ipv6 Type --------------------------------------------------
168
169/// Exactly fitting IPv6 bytes (16 octets).
170pub type IPv6 = U128<NetworkEndian>;
171
172impl AddressFamily for IPv6 {
173    // const BITMASK: u128 = 0x1u128.rotate_right(1);
174    const BITS: u8 = 128;
175    type Inner = u128;
176    type InnerIpAddr = std::net::Ipv6Addr;
177
178    fn zero() -> Self {
179        0.into()
180    }
181
182    fn from_ipaddr(ip_addr: Self::InnerIpAddr) -> Self {
183        IPv6::from(ip_addr.octets())
184    }
185
186    fn into_bit_span(net: Self, start_bit: u8, len: u8) -> BitSpan {
187        BitSpan {
188            bits: u128::from(
189                (net << <U128<NetworkEndian>>::from(start_bit as u128))
190                    >> (<U128<NetworkEndian>>::from(128 - len as u128) % 128),
191            ) as u32,
192            len,
193        }
194    }
195
196    fn add_bit_span(self, len: u8, bs: BitSpan) -> (Self, u8) {
197        let res = self | ((bs.bits as u128) << (128 - len - bs.len) as usize);
198        (res, len + bs.len)
199    }
200
201    fn truncate_to_len(self, len: u8) -> Self {
202        self & ((1_u128.rotate_right(len as u32)
203            ^ 1_u128.saturating_sub(len as u128))
204        .wrapping_sub(1)
205            ^ u128::MAX)
206    }
207
208    fn into_ipaddr(self) -> std::net::IpAddr {
209        std::net::IpAddr::V6(std::net::Ipv6Addr::from(u128::from(self)))
210    }
211
212    fn dangerously_truncate_to_u32(self) -> u32 {
213        // this will chop off the high bits.
214        u128::from(self) as u32
215    }
216
217    fn checked_shr_or_zero(self, rhs: u32) -> Self {
218        if rhs == 0 || rhs == 128 {
219            return U128::from(0);
220        };
221
222        self >> U128::from(rhs as u128)
223    }
224
225    fn checked_shl_or_zero(self, rhs: u32) -> Self {
226        if rhs >= 128 {
227            return U128::from(0);
228        };
229
230        self << U128::from(rhs as u128)
231    }
232
233    fn checked_shr(self, rhs: u32) -> Option<u128> {
234        u128::from(self).checked_shr(rhs)
235    }
236
237    fn checked_shl(self, rhs: u32) -> Option<u128> {
238        u128::from(self).checked_shl(rhs)
239    }
240
241    fn from_u8(value: u8) -> Self {
242        IPv6::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, value])
243    }
244
245    fn from_u32(value: u32) -> Self {
246        (value as u128).into()
247    }
248}
249
250pub trait IntoIpAddr {
251    fn into_ipaddr(self) -> std::net::IpAddr;
252}
253
254impl IntoIpAddr for u32 {
255    fn into_ipaddr(self) -> std::net::IpAddr {
256        std::net::IpAddr::V4(std::net::Ipv4Addr::from(self))
257    }
258}
259
260impl IntoIpAddr for u128 {
261    fn into_ipaddr(self) -> std::net::IpAddr {
262        std::net::IpAddr::V6(std::net::Ipv6Addr::from(self))
263    }
264}