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}