Skip to main content

ts_bart/table/
split_stack.rs

1use core::net::IpAddr;
2
3use crate::{RouteModification, RoutingTable, iptrie, node, table};
4
5/// Routing table that segregates routes into independent IPv4 and IPv6 tables.
6///
7/// This is likely the kind of table you want unless you know you'll be
8/// operating in an exclusively-single-stack environment and want to save the
9/// slight runtime overhead of discriminating on address type.
10#[derive(Debug, Copy, Clone, Default, PartialEq, Eq, Hash)]
11pub struct SplitStackTable<Node> {
12    table4: table::SimpleTable<Node>,
13    table6: table::SimpleTable<Node>,
14}
15
16impl<T, C> SplitStackTable<crate::Node<T, C>>
17where
18    C: ?Sized + crate::Storage,
19{
20    /// The empty table.
21    pub const EMPTY: Self = Self {
22        table4: table::SimpleTable::EMPTY,
23        table6: table::SimpleTable::EMPTY,
24    };
25}
26
27impl<Node> SplitStackTable<Node>
28where
29    Node: node::StrideOps,
30{
31    /// Report the total number of IPv4 routes stored in the table.
32    #[inline]
33    pub fn size4(&self) -> usize {
34        self.table4.size()
35    }
36
37    /// Report the total number of IPv6 routes stored in the table.
38    #[inline]
39    pub fn size6(&self) -> usize {
40        self.table6.size()
41    }
42
43    /// Get a reference to the root node for the given ip stack.
44    #[inline]
45    pub const fn root(&self, ipv4: bool) -> &Node {
46        if ipv4 {
47            self.table4.root()
48        } else {
49            self.table6.root()
50        }
51    }
52
53    #[inline]
54    const fn stack_table(&self, ipv4: bool) -> &table::SimpleTable<Node> {
55        if ipv4 { &self.table4 } else { &self.table6 }
56    }
57
58    #[inline]
59    const fn stack_table_mut(&mut self, ipv4: bool) -> &mut table::SimpleTable<Node> {
60        if ipv4 {
61            &mut self.table4
62        } else {
63            &mut self.table6
64        }
65    }
66}
67
68impl<Node> RoutingTable for SplitStackTable<Node>
69where
70    Node: node::StrideOps,
71{
72    type Value = Node::T;
73
74    #[inline]
75    fn contains(&self, ip: IpAddr) -> bool {
76        self.stack_table(ip.is_ipv4()).contains(ip)
77    }
78
79    #[inline]
80    fn insert(&mut self, prefix: ipnet::IpNet, val: Node::T) -> Option<Node::T> {
81        self.stack_table_mut(prefix.addr().is_ipv4())
82            .insert(prefix, val)
83    }
84
85    #[inline]
86    fn remove(&mut self, prefix: ipnet::IpNet) -> Option<Node::T> {
87        self.stack_table_mut(prefix.addr().is_ipv4()).remove(prefix)
88    }
89
90    #[inline]
91    fn modify_impl(
92        &mut self,
93        prefix: ipnet::IpNet,
94        modify: &mut dyn FnMut(Option<&mut Node::T>) -> RouteModification<Node::T>,
95    ) -> Option<Node::T> {
96        self.stack_table_mut(prefix.addr().is_ipv4())
97            .modify_impl(prefix, modify)
98    }
99
100    #[inline]
101    fn clear(&mut self) {
102        self.table4.clear();
103        self.table6.clear();
104    }
105
106    #[inline]
107    fn lookup(&self, ip: IpAddr) -> Option<&Node::T> {
108        self.stack_table(ip.is_ipv4()).lookup(ip)
109    }
110
111    fn lookup_all(&self, ip: IpAddr) -> iptrie::LookupIter<'_, Self::Value> {
112        self.stack_table(ip.is_ipv4()).lookup_all(ip)
113    }
114
115    #[inline]
116    fn lookup_prefix_exact(&self, prefix: ipnet::IpNet) -> Option<&Node::T> {
117        self.stack_table(prefix.addr().is_ipv4())
118            .lookup_prefix_exact(prefix)
119    }
120
121    #[inline]
122    fn lookup_prefix(&self, prefix: ipnet::IpNet) -> Option<&Node::T> {
123        self.stack_table(prefix.addr().is_ipv4())
124            .lookup_prefix(prefix)
125    }
126
127    #[inline]
128    fn lookup_prefix_lpm(&self, prefix: ipnet::IpNet) -> Option<(ipnet::IpNet, &Node::T)> {
129        self.stack_table(prefix.addr().is_ipv4())
130            .lookup_prefix_lpm(prefix)
131    }
132
133    #[inline]
134    fn size(&self) -> usize {
135        self.table4.size() + self.table6.size()
136    }
137}