ip_network_table_deps_treebitmap/lib.rs
1// Copyright 2016 Hroi Sigurdsson
2//
3// Licensed under the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>.
4// This file may not be copied, modified, or distributed except according to those terms.
5
6//! # Fast IP lookup table for IPv4/IPv6 prefixes
7//!
8//! This crate provides a datastructure for fast IP address lookups.
9//! It aims at fast lookup times, and a small memory footprint.
10//! A full IPv4 BGP table of more than 600k entries fits in less than 5 MB. A
11//! full IPv6 BGP table of more than 25k entries fits in less than 1 MB.
12//!
13//! Longest match lookups on full BGP IP tables take on the order of 100ns.
14//!
15//! The internal datastructure is based on the Tree-bitmap algorithm described
16//! by W. Eatherton, Z. Dittia, G. Varghes.
17//!
18#![cfg_attr(feature = "alloc", no_std)]
19#![cfg_attr(feature = "alloc", feature(alloc))]
20
21#[cfg(feature = "alloc")]
22extern crate alloc;
23#[cfg(feature = "alloc")]
24use core as std;
25
26use std::marker::PhantomData;
27
28mod tree_bitmap;
29use tree_bitmap::TreeBitmap;
30
31pub mod address;
32use address::Address;
33
34#[cfg(feature = "alloc")]
35pub use address::addr::*;
36
37/// A fast, compressed IP lookup table.
38pub struct IpLookupTable<A, T> {
39 inner: TreeBitmap<T>,
40 _addrtype: PhantomData<A>,
41}
42
43impl<A, T> IpLookupTable<A, T>
44where
45 A: Address,
46{
47 /// Initialize an empty lookup table with no preallocation.
48 pub fn new() -> Self {
49 IpLookupTable {
50 inner: TreeBitmap::new(),
51 _addrtype: PhantomData,
52 }
53 }
54
55 /// Initialize an empty lookup table with pre-allocated buffers.
56 pub fn with_capacity(n: usize) -> Self {
57 IpLookupTable {
58 inner: TreeBitmap::with_capacity(n),
59 _addrtype: PhantomData,
60 }
61 }
62
63 /// Return the bytes used by nodes and results.
64 pub fn mem_usage(&self) -> (usize, usize) {
65 self.inner.mem_usage()
66 }
67
68 /// Return number of items inside table.
69 pub fn len(&self) -> usize {
70 self.inner.len()
71 }
72
73 /// Return `true` if no item is inside table.
74 pub fn is_empty(&self) -> bool {
75 self.len() == 0
76 }
77
78 /// Insert a value for the prefix designated by ip and masklen. If prefix
79 /// existed previously, the old value is returned.
80 ///
81 /// # Panics
82 ///
83 /// Panics if prefix has bits set to the right of mask.
84 ///
85 /// # Examples
86 ///
87 /// ```
88 /// use treebitmap::IpLookupTable;
89 /// use std::net::Ipv6Addr;
90 ///
91 /// let mut table = IpLookupTable::new();
92 /// let prefix = Ipv6Addr::new(0x2001, 0xdb8, 0xdead, 0xbeef, 0, 0, 0, 0);
93 /// let masklen = 32;
94 ///
95 /// assert_eq!(table.insert(prefix, masklen, "foo"), None);
96 /// // Insert duplicate
97 /// assert_eq!(table.insert(prefix, masklen, "bar"), Some("foo"));
98 /// ```
99 pub fn insert(&mut self, ip: A, masklen: u32, value: T) -> Option<T> {
100 self.inner.insert(&ip.nibbles().as_ref(), masklen, value)
101 }
102
103 /// Remove an entry from the lookup table. If the prefix existed previously,
104 /// the value is returned.
105 ///
106 /// # Examples
107 ///
108 /// ```
109 /// use treebitmap::IpLookupTable;
110 /// use std::net::Ipv6Addr;
111 ///
112 /// let mut table = IpLookupTable::new();
113 /// let prefix = Ipv6Addr::new(0x2001, 0xdb8, 0xdead, 0xbeef, 0, 0, 0, 0);
114 /// let masklen = 32;
115 /// table.insert(prefix, masklen, "foo");
116 ///
117 /// assert_eq!(table.remove(prefix, masklen), Some("foo"));
118 /// // Remove non-existant
119 /// assert_eq!(table.remove(prefix, masklen), None);
120 /// ```
121 pub fn remove(&mut self, ip: A, masklen: u32) -> Option<T> {
122 self.inner.remove(&ip.nibbles().as_ref(), masklen)
123 }
124
125 /// Perform exact match lookup of `ip`/`masklen` and return the
126 /// value.
127 ///
128 /// # Panics
129 ///
130 /// Panics if prefix has bits set to the right of mask.
131 ///
132 /// # Examples
133 ///
134 /// ```
135 /// use treebitmap::IpLookupTable;
136 /// use std::net::Ipv6Addr;
137 ///
138 /// let mut table = IpLookupTable::new();
139 /// let prefix = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0);
140 /// let masklen = 32;
141 /// table.insert(prefix, masklen, "foo");
142 ///
143 /// assert_eq!(table.exact_match(prefix, masklen), Some(&"foo"));
144 /// // differing mask
145 /// assert_eq!(table.exact_match(prefix, 48), None);
146 /// ```
147 pub fn exact_match(&self, ip: A, masklen: u32) -> Option<&T> {
148 self.inner.exact_match(&ip.nibbles().as_ref(), masklen)
149 }
150
151 /// Perform exact match lookup of `ip`/`masklen` and return the
152 /// value as mutable.
153 ///
154 /// # Examples
155 ///
156 /// ```
157 /// use treebitmap::IpLookupTable;
158 /// use std::net::Ipv6Addr;
159 ///
160 /// let mut table = IpLookupTable::new();
161 /// let prefix = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0);
162 /// let masklen = 32;
163 /// table.insert(prefix, masklen, "foo");
164 ///
165 /// assert_eq!(table.exact_match(prefix, masklen), Some(&"foo"));
166 /// // Mutate value
167 /// if let Some(value) = table.exact_match_mut(prefix, masklen) {
168 /// *value = &"bar";
169 /// }
170 /// // Get new value
171 /// assert_eq!(table.exact_match(prefix, masklen), Some(&"bar"));
172 /// ```
173 pub fn exact_match_mut(&mut self, ip: A, masklen: u32) -> Option<&mut T> {
174 self.inner.exact_match_mut(&ip.nibbles().as_ref(), masklen)
175 }
176
177 /// Perform longest match lookup of `ip` and return the best matching
178 /// prefix, designated by ip, masklen, along with its value.
179 ///
180 /// # Example
181 ///
182 /// ```
183 /// use treebitmap::IpLookupTable;
184 /// use std::net::Ipv6Addr;
185 ///
186 /// let mut table = IpLookupTable::new();
187 /// let less_specific = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0);
188 /// let more_specific = Ipv6Addr::new(0x2001, 0xdb8, 0xdead, 0, 0, 0, 0, 0);
189 /// table.insert(less_specific, 32, "foo");
190 /// table.insert(more_specific, 48, "bar");
191 ///
192 /// let lookupip = Ipv6Addr::new(0x2001, 0xdb8, 0xdead, 0xbeef,
193 /// 0xcafe, 0xbabe, 0, 1);
194 /// let result = table.longest_match(lookupip);
195 /// assert_eq!(result, Some((more_specific, 48, &"bar")));
196 ///
197 /// let lookupip = Ipv6Addr::new(0x2001, 0xdb8, 0xcafe, 0xf00,
198 /// 0xf00, 0xf00, 0, 1);
199 /// let result = table.longest_match(lookupip);
200 /// assert_eq!(result, Some((less_specific, 32, &"foo")));
201 /// ```
202 pub fn longest_match(&self, ip: A) -> Option<(A, u32, &T)> {
203 match self.inner.longest_match(&ip.nibbles().as_ref()) {
204 Some((bits_matched, value)) => Some((ip.mask(bits_matched), bits_matched, value)),
205 None => None,
206 }
207 }
208
209 /// Perform longest match lookup of `ip` and return the best matching
210 /// prefix, designated by ip, masklen, along with its value as mutable.
211 ///
212 /// # Example
213 ///
214 /// ```
215 /// use treebitmap::IpLookupTable;
216 /// use std::net::Ipv6Addr;
217 ///
218 /// let mut table = IpLookupTable::new();
219 /// let less_specific = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0);
220 /// let more_specific = Ipv6Addr::new(0x2001, 0xdb8, 0xdead, 0, 0, 0, 0, 0);
221 /// table.insert(less_specific, 32, "foo");
222 /// table.insert(more_specific, 48, "bar");
223 ///
224 /// let lookupip = Ipv6Addr::new(0x2001, 0xdb8, 0xdead, 0xbeef,
225 /// 0xcafe, 0xbabe, 0, 1);
226 /// if let Some((_, _, value)) = table.longest_match_mut(lookupip) {
227 /// assert_eq!(value, &"bar");
228 /// *value = &"foo";
229 /// }
230 ///
231 /// let result = table.longest_match(lookupip);
232 /// assert_eq!(result, Some((more_specific, 48, &"foo")));
233 /// ```
234 pub fn longest_match_mut(&mut self, ip: A) -> Option<(A, u32, &mut T)> {
235 match self.inner.longest_match_mut(&ip.nibbles().as_ref()) {
236 Some((bits_matched, value)) => Some((ip.mask(bits_matched), bits_matched, value)),
237 None => None,
238 }
239 }
240
241 /// Perform match lookup of `ip` and return the all matching
242 /// prefixes, designated by ip, masklen, along with its value.
243 ///
244 /// # Example
245 ///
246 /// ```
247 /// use treebitmap::IpLookupTable;
248 /// use std::net::Ipv6Addr;
249 ///
250 /// let mut table = IpLookupTable::new();
251 /// let less_specific = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0);
252 /// let more_specific = Ipv6Addr::new(0x2001, 0xdb8, 0xdead, 0, 0, 0, 0, 0);
253 /// table.insert(less_specific, 32, "foo");
254 /// table.insert(more_specific, 48, "bar");
255 ///
256 /// let lookupip = Ipv6Addr::new(0x2001, 0xdb8, 0xdead, 0xbeef,
257 /// 0xcafe, 0xbabe, 0, 1);
258 /// let matches = table.matches(lookupip);
259 /// assert_eq!(matches.count(), 2);
260 ///
261 /// let lookupip = Ipv6Addr::new(0x2001, 0xdb8, 0xcafe, 0xf00,
262 /// 0xf00, 0xf00, 0, 1);
263 /// let matches = table.matches(lookupip);
264 /// assert_eq!(matches.count(), 1);
265 /// ```
266 pub fn matches(&self, ip: A) -> impl Iterator<Item = (A, u32, &T)> {
267 self.inner
268 .matches(ip.nibbles().as_ref())
269 .map(move |(bits_matched, value)| (ip.mask(bits_matched), bits_matched, value))
270 }
271
272 /// Perform match lookup of `ip` and return the all matching
273 /// prefixes, designated by ip, masklen, along with its mutable value.
274 pub fn matches_mut(&mut self, ip: A) -> impl Iterator<Item = (A, u32, &mut T)> {
275 self.inner
276 .matches_mut(ip.nibbles().as_ref())
277 .map(move |(bits_matched, value)| (ip.mask(bits_matched), bits_matched, value))
278 }
279
280 /// Returns iterator over prefixes and values.
281 ///
282 /// # Examples
283 ///
284 /// ```
285 /// use treebitmap::IpLookupTable;
286 /// use std::net::Ipv6Addr;
287 ///
288 /// let mut table = IpLookupTable::new();
289 /// let less_specific = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0);
290 /// let more_specific = Ipv6Addr::new(0x2001, 0xdb8, 0xdead, 0, 0, 0, 0, 0);
291 /// table.insert(less_specific, 32, "foo");
292 /// table.insert(more_specific, 48, "bar");
293 ///
294 /// let mut iter = table.iter();
295 /// assert_eq!(iter.next(), Some((less_specific, 32, &"foo")));
296 /// assert_eq!(iter.next(), Some((more_specific, 48, &"bar")));
297 /// assert_eq!(iter.next(), None);
298 /// ```
299 pub fn iter(&self) -> Iter<A, T> {
300 Iter {
301 inner: self.inner.iter(),
302 _addrtype: PhantomData,
303 }
304 }
305
306 /// Mutable version of iter().
307 ///
308 /// # Examples
309 ///
310 /// ```
311 /// use treebitmap::IpLookupTable;
312 /// use std::net::Ipv6Addr;
313 ///
314 /// let x: Ipv6Addr = "2001:db8:100::".parse().unwrap();
315 /// let y: Ipv6Addr = "2001:db8:100::".parse().unwrap();
316 /// let z: Ipv6Addr = "2001:db8:102::".parse().unwrap();
317 /// let mut table = IpLookupTable::new();
318 ///
319 /// table.insert(x, 48, 1);
320 /// table.insert(y, 56, 2);
321 /// table.insert(z, 56, 3);
322 ///
323 /// for (_ip, _mask, val) in table.iter_mut() {
324 /// *val += 10;
325 /// }
326 ///
327 /// assert_eq!(table.exact_match(x, 48), Some(&11));
328 /// assert_eq!(table.exact_match(y, 56), Some(&12));
329 /// assert_eq!(table.exact_match(z, 56), Some(&13));
330 /// ```
331 pub fn iter_mut(&mut self) -> IterMut<A, T> {
332 IterMut {
333 inner: self.inner.iter_mut(),
334 _addrtype: PhantomData,
335 }
336 }
337}
338
339impl<A, T> Default for IpLookupTable<A, T>
340where
341 A: Address,
342{
343 fn default() -> Self {
344 Self::new()
345 }
346}
347
348impl<'a, A, T: 'a> Iterator for Iter<'a, A, T>
349where
350 A: Address,
351{
352 type Item = (A, u32, &'a T);
353
354 fn next(&mut self) -> Option<Self::Item> {
355 match self.inner.next() {
356 Some((nibbles, masklen, value)) => {
357 Some((Address::from_nibbles(&nibbles[..]), masklen, value))
358 }
359 None => None,
360 }
361 }
362}
363
364impl<'a, A, T: 'a> Iterator for IterMut<'a, A, T>
365where
366 A: Address,
367{
368 type Item = (A, u32, &'a mut T);
369
370 fn next(&mut self) -> Option<Self::Item> {
371 match self.inner.next() {
372 Some((nibbles, masklen, value)) => {
373 Some((Address::from_nibbles(&nibbles[..]), masklen, value))
374 }
375 None => None,
376 }
377 }
378}
379
380impl<'a, A, T: 'a> Iterator for IntoIter<A, T>
381where
382 A: Address,
383{
384 type Item = (A, u32, T);
385
386 fn next(&mut self) -> Option<Self::Item> {
387 match self.inner.next() {
388 Some((nibbles, masklen, value)) => {
389 Some((Address::from_nibbles(&nibbles[..]), masklen, value))
390 }
391 None => None,
392 }
393 }
394}
395
396impl<A, T> IntoIterator for IpLookupTable<A, T>
397where
398 A: Address,
399{
400 type Item = (A, u32, T);
401 type IntoIter = IntoIter<A, T>;
402
403 fn into_iter(self) -> IntoIter<A, T> {
404 IntoIter {
405 inner: self.inner.into_iter(),
406 _addrtype: PhantomData,
407 }
408 }
409}
410
411/// Iterator over prefixes and associated values. The prefixes are returned in
412/// "tree"-order.
413#[doc(hidden)]
414pub struct Iter<'a, A, T: 'a> {
415 inner: tree_bitmap::Iter<'a, T>,
416 _addrtype: PhantomData<A>,
417}
418
419/// Mutable iterator over prefixes and associated values. The prefixes are
420/// returned in "tree"-order.
421#[doc(hidden)]
422pub struct IterMut<'a, A, T: 'a> {
423 inner: tree_bitmap::IterMut<'a, T>,
424 _addrtype: PhantomData<A>,
425}
426
427/// Converts ```IpLookupTable``` into an iterator. The prefixes are returned in
428/// "tree"-order.
429#[doc(hidden)]
430pub struct IntoIter<A, T> {
431 inner: tree_bitmap::IntoIter<T>,
432 _addrtype: PhantomData<A>,
433}