rotonda_macros/lib.rs
1extern crate proc_macro;
2
3mod maps;
4
5use proc_macro::TokenStream;
6use quote::{format_ident, quote};
7use std::iter::Iterator;
8use syn::parse_macro_input;
9
10#[proc_macro_attribute]
11pub fn stride_sizes(attr: TokenStream, input: TokenStream) -> TokenStream {
12 // The arguments for the macro invocation
13 let attrs = parse_macro_input!(attr as syn::ExprTuple);
14
15 let attrs = attrs.elems.iter().collect::<Vec<_>>();
16
17 let input = parse_macro_input!(input as syn::ItemStruct);
18 let type_name = &input.ident;
19 let ip_af = match attrs[0] {
20 syn::Expr::Path(t) => t,
21 _ => panic!("Expected Family Type"),
22 };
23 let prefixes_all_len;
24 let all_len;
25 let prefixes_buckets_name: syn::Ident;
26 // let prefix_store_bits;
27 let get_root_prefix_set;
28
29 // The name of the Struct that we're going to generate
30 // We'll prepend it with the name of the TreeBitMap struct
31 // that the user wants, so that our macro is a little bit
32 // more hygienic, and the user can create multiple types
33 // of TreeBitMap structs with different stride sizes.
34 let buckets_name = if ip_af.path.is_ident("IPv4") {
35 format_ident!("{}NodeBuckets4", type_name)
36 } else {
37 format_ident!("{}NodeBuckets6", type_name)
38 };
39 let store_bits = if ip_af.path.is_ident("IPv4") {
40 all_len = (0..=32_u8).collect::<Vec<_>>();
41 prefixes_all_len = (0..=32_u8)
42 .map(|l| format_ident!("p{}", l))
43 .collect::<Vec<_>>();
44 prefixes_buckets_name = format_ident!("PrefixBuckets4");
45 // prefix_store_bits = format_ident!("prefix_store_bits_4");
46 get_root_prefix_set = quote! {
47 fn get_root_prefix_set(&self, len: u8) -> &'_ PrefixSet<IPv4, M> {
48 [
49 &self.p0, &self.p1, &self.p2, &self.p3, &self.p4, &self.p5, &self.p6, &self.p7, &self.p8,
50 &self.p9, &self.p10, &self.p11, &self.p12, &self.p13, &self.p14, &self.p15, &self.p16,
51 &self.p17, &self.p18, &self.p19, &self.p20, &self.p21, &self.p22, &self.p23, &self.p24,
52 &self.p25, &self.p26, &self.p27, &self.p28, &self.p29, &self.p30, &self.p31, &self.p32
53 ][len as usize]
54 }
55 };
56 crate::maps::node_buckets_map_v4()
57 } else {
58 all_len = (0..=128_u8).collect::<Vec<_>>();
59 prefixes_all_len = (0..=128_u8)
60 .map(|l| format_ident!("p{}", l))
61 .collect::<Vec<_>>();
62
63 prefixes_buckets_name = format_ident!("PrefixBuckets6");
64 // prefix_store_bits = format_ident!("prefix_store_bits_6");
65 get_root_prefix_set = quote! {
66 fn get_root_prefix_set(&self, len: u8) -> &'_ PrefixSet<IPv6, M> {
67 [
68 &self.p0, &self.p1, &self.p2, &self.p3, &self.p4, &self.p5, &self.p6, &self.p7, &self.p8,
69 &self.p9, &self.p10, &self.p11, &self.p12, &self.p13, &self.p14, &self.p15, &self.p16,
70 &self.p17, &self.p18, &self.p19, &self.p20, &self.p21, &self.p22, &self.p23, &self.p24,
71 &self.p25, &self.p26, &self.p27, &self.p28, &self.p29, &self.p30, &self.p31, &self.p32,
72 &self.p33, &self.p34, &self.p35, &self.p36, &self.p37, &self.p38, &self.p39, &self.p40,
73 &self.p41, &self.p42, &self.p43, &self.p44, &self.p45, &self.p46, &self.p47, &self.p48,
74 &self.p49, &self.p50, &self.p51, &self.p52, &self.p53, &self.p54, &self.p55, &self.p56,
75 &self.p57, &self.p58, &self.p59, &self.p60, &self.p61, &self.p62, &self.p63, &self.p64,
76 &self.p65, &self.p66, &self.p67, &self.p68, &self.p69, &self.p70, &self.p71, &self.p72,
77 &self.p73, &self.p74, &self.p75, &self.p76, &self.p77, &self.p78, &self.p79, &self.p80,
78 &self.p81, &self.p82, &self.p83, &self.p84, &self.p85, &self.p86, &self.p87, &self.p88,
79 &self.p89, &self.p90, &self.p91, &self.p92, &self.p93, &self.p94, &self.p95, &self.p96,
80 &self.p97, &self.p98, &self.p99, &self.p100, &self.p101, &self.p102, &self.p103, &self.p104,
81 &self.p105, &self.p106, &self.p107, &self.p108, &self.p109, &self.p110, &self.p111, &self.p112,
82 &self.p113, &self.p114, &self.p115, &self.p116, &self.p117, &self.p118, &self.p119, &self.p120,
83 &self.p121, &self.p122, &self.p123, &self.p124, &self.p125, &self.p126, &self.p127, &self.p128
84 ][len as usize]
85 }
86 };
87 crate::maps::node_buckets_map_v6()
88 };
89
90 let mut strides_num: Vec<u8> = vec![];
91 let mut strides = vec![];
92 let mut strides_all_len = vec![];
93 let mut strides_all_len_accu: Vec<u8> = vec![];
94 let mut strides_all_len_level = vec![];
95 let mut strides_len3 = vec![];
96 let mut strides_len3_l = vec![];
97 let mut strides_len4 = vec![];
98 let mut strides_len4_l = vec![];
99 let mut strides_len5 = vec![];
100 let mut strides_len5_l = vec![];
101
102 let mut s_accu = 0_u8;
103
104 let attrs_s = match attrs[1] {
105 syn::Expr::Array(arr) => arr,
106 _ => panic!("Expected an array"),
107 };
108 let strides_len = attrs_s.elems.len() as u8;
109 let first_stride_size = &attrs_s.elems[0];
110
111 for (len, stride) in attrs_s.elems.iter().enumerate() {
112 strides_all_len.push(format_ident!("l{}", len));
113
114 match stride {
115 syn::Expr::Lit(s) => {
116 if let syn::Lit::Int(i) = &s.lit {
117 let stride_len = i.base10_digits().parse::<u8>().unwrap();
118 strides_num.push(stride_len);
119 strides_all_len_level.push(format_ident!("l{}", s_accu));
120
121 match stride_len {
122 3 => {
123 strides_len3.push(s_accu as usize);
124 strides_len3_l.push(format_ident!("l{}", s_accu));
125 }
126 4 => {
127 strides_len4.push(s_accu as usize);
128 strides_len4_l.push(format_ident!("l{}", s_accu));
129 }
130 5 => {
131 strides_len5.push(s_accu as usize);
132 strides_len5_l.push(format_ident!("l{}", s_accu));
133 }
134 _ => panic!("Expected a stride of 3, 4 or 5"),
135 };
136 strides_all_len_accu.push(s_accu);
137
138 s_accu += stride_len;
139 strides.push(format_ident!("Stride{}", stride_len))
140 } else {
141 panic!("Expected an integer")
142 }
143 }
144 _ => {
145 panic!("Expected a literal")
146 }
147 }
148 }
149
150 // Check if the strides division makes sense
151 let mut len_to_stride_arr = [0_u8; 128];
152 strides_all_len_accu
153 .iter()
154 .zip(strides_num.iter())
155 .for_each(|(acc, s)| {
156 len_to_stride_arr[*acc as usize] = *s;
157 });
158
159 // These are the stride sizes as an array of u8s, padded with 0s to the
160 // right. It's bounded to 42 u8s to avoid having to set a const generic
161 // on the type (which would have to be carried over to its parent). So
162 // if a 0 is encountered, it's the end of the strides.
163 let mut stride_sizes = [0; 42];
164 let (left, _right) = stride_sizes.split_at_mut(strides_len as usize);
165 left.swap_with_slice(&mut strides_num);
166
167 let struct_creation = quote! {
168
169 #[derive(Debug)]
170 pub(crate) struct #buckets_name<AF: AddressFamily> {
171 // created fields for each sub-prefix (StrideNodeId) length,
172 // with hard-coded field-names, like this:
173 // l0: NodeSet<AF, Stride5>,
174 // l5: NodeSet<AF, Stride5>,
175 // l10: NodeSet<AF, Stride4>,
176 // ...
177 // l29: NodeSet<AF, Stride3>
178 # ( #strides_all_len_level: NodeSet<#ip_af, #strides>, )*
179 _af: PhantomData<AF>,
180 stride_sizes: [u8; 42],
181 strides_len: u8
182 }
183
184 #[derive(Debug)]
185 pub(crate) struct #prefixes_buckets_name<AF: AddressFamily, M: Meta> {
186 // creates a bucket for each prefix (PrefixId) length, with
187 // hard-coded field-names, like this:
188 // p0: PrefixSet<AF, M>,
189 // p1: PrefixSet<AF, M>,
190 // ...
191 // p32: PrefixSet<AF, M>,
192 #( #prefixes_all_len: PrefixSet<#ip_af, M>, )*
193 _af: PhantomData<AF>,
194 _m: PhantomData<M>,
195 }
196
197 };
198
199 let prefix_buckets_map = if ip_af.path.is_ident("IPv4") {
200 crate::maps::prefix_buckets_map_v4()
201 } else {
202 crate::maps::prefix_buckets_map_v6()
203 };
204
205 let prefix_buckets_impl = quote! {
206
207 impl<AF: AddressFamily, M: Meta> PrefixBuckets<#ip_af, M> for #prefixes_buckets_name<AF, M> {
208 fn init() -> #prefixes_buckets_name<AF, M> {
209 #prefixes_buckets_name {
210 #( #prefixes_all_len: PrefixSet::init(1 << #prefixes_buckets_name::<AF, M>::get_bits_for_len(#all_len, 0)), )*
211 _af: PhantomData,
212 _m: PhantomData,
213 }
214 }
215
216 fn remove(&mut self, id: PrefixId<#ip_af>) -> Option<M> { unimplemented!() }
217
218 #get_root_prefix_set
219
220 #prefix_buckets_map
221
222 }
223
224 };
225
226 let struct_impl = quote! {
227
228 impl<AF: AddressFamily> NodeBuckets<#ip_af> for #buckets_name<AF> {
229 fn init() -> Self {
230 #buckets_name {
231 // creates l0, l1, ... l<AF::BITS>, but only for the
232 // levels at the end of each stride, so for strides
233 // [5,5,4,3,3,3,3,3,3] is will create l0, l5, l10, l14,
234 // l17, l20, l23, l26, l29 last level will be omitted,
235 // because that will never be used (l29 has children
236 // with prefixes up to prefix-length 32 in this example).
237 #( #strides_all_len_level: NodeSet::init(#buckets_name::<AF>::len_to_store_bits(#strides_all_len_accu, 0) ), )*
238 _af: PhantomData,
239 stride_sizes: [ #( #stride_sizes, )*],
240 strides_len: #strides_len
241 }
242 }
243
244 fn get_store3(&self, id: StrideNodeId<#ip_af>) -> &NodeSet<#ip_af, Stride3> {
245 match id.get_id().1 as usize {
246 #( #strides_len3 => &self.#strides_len3_l, )*
247 _ => panic!(
248 "unexpected sub prefix length {} in stride size 3 ({})",
249 id.get_id().1,
250 id
251 ),
252 }
253 }
254
255 fn get_store4(&self, id: StrideNodeId<#ip_af>) -> &NodeSet<#ip_af, Stride4> {
256 match id.get_id().1 as usize {
257 #( #strides_len4 => &self.#strides_len4_l, )*
258 // ex.:
259 // 10 => &self.l10,
260 _ => panic!(
261 "unexpected sub prefix length {} in stride size 4 ({})",
262 id.get_id().1,
263 id
264 ),
265 }
266 }
267
268 fn get_store5(&self, id: StrideNodeId<#ip_af>) -> &NodeSet<#ip_af, Stride5> {
269 match id.get_id().1 as usize {
270 #( #strides_len5 => &self.#strides_len5_l, )*
271 // ex.:
272 // 0 => &self.l0,
273 // 5 => &self.l5,
274 _ => panic!(
275 "unexpected sub prefix length {} in stride size 5 ({})",
276 id.get_id().1,
277 id
278 ),
279 }
280 }
281
282 #[inline]
283 fn get_stride_sizes(&self) -> &[u8] {
284 &self.stride_sizes[0..self.strides_len as usize]
285 }
286
287 #[inline]
288 fn get_stride_for_id(&self, id: StrideNodeId<#ip_af>) -> u8 {
289 [ #(#len_to_stride_arr, )* ][id.get_id().1 as usize]
290 }
291
292 #[inline]
293 #store_bits
294
295 fn get_strides_len() -> u8 {
296 #strides_len
297 }
298
299 fn get_first_stride_size() -> u8 {
300 #first_stride_size
301 }
302 }
303
304 };
305
306 let type_alias = quote! {
307 type #type_name<M> = TreeBitMap<#ip_af, M, #buckets_name<#ip_af>, #prefixes_buckets_name<#ip_af, M>>;
308 };
309
310 let result = quote! {
311 #struct_creation
312 #struct_impl
313 #prefix_buckets_impl
314 #type_alias
315 };
316
317 TokenStream::from(result)
318}
319
320// ---------- Create Store struct -------------------------------------------
321
322// This macro creates the struct that will be the public API for the
323// PrefixStore. Therefore all methods defined in here should be public.
324
325/// Creates a new, user-named struct with user-defined specified stride sizes
326/// that can used as a store type.
327///
328/// # Usage
329/// ```ignore
330/// use rotonda_store::prelude::*;
331/// use rotonda_store::prelude::multi::*;
332/// use rotonda_store::meta_examples::PrefixAs;
333///
334/// const IP4_STRIDE_ARRAY = [4; 8];
335/// const IP6_STRIDE_ARRAY = [4; 32];
336///
337/// #[create_store((IPV4_STRIDE_ARRAY, IPV6_STRIDE_ARRAY))]
338/// struct NuStorage;
339/// ```
340///
341/// This will create a `NuStorage` struct, that can be used as a regular
342/// store.
343///
344/// The stride-sizes can be any of \[3,4,5\], and they should add up
345/// to the total number of bits in the address family (32 for IPv4 and
346/// 128 for IPv6). Stride sizes in the array will be repeated if the sum
347/// of them falls short of the total number of bits for the address
348/// family.
349///
350/// # Example
351/// ```ignore
352/// use rotonda_store::prelude::*;
353/// use rotonda_store::prelude::multi::*;
354/// use rotonda_store::meta_examples::PrefixAs;
355///
356/// // The default stride sizes for IPv4, IPv6, resp.
357/// #[create_store((
358/// [5, 5, 4, 3, 3, 3, 3, 3, 3, 3],
359/// [4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
360/// 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4]
361/// ))]
362/// struct NuStore;
363///
364/// let store = Arc::new(NuStore::<PrefixAs>::new().unwrap());
365/// ```
366#[proc_macro_attribute]
367pub fn create_store(attr: TokenStream, item: TokenStream) -> TokenStream {
368 let input = parse_macro_input!(item as syn::ItemStruct);
369 let store_name = &input.ident;
370
371 let attr = parse_macro_input!(attr as syn::ExprTuple);
372 let attrs = attr.elems.iter().collect::<Vec<_>>();
373 let strides4 = attrs[0].clone();
374 let strides6 = attrs[1].clone();
375 let strides4_name = format_ident!("{}IPv4", store_name);
376 let strides6_name = format_ident!("{}IPv6", store_name);
377
378 let create_strides = quote! {
379 use ::std::marker::PhantomData;
380 use ::inetnum::addr::Prefix;
381
382 #[stride_sizes((IPv4, #strides4))]
383 struct #strides4_name;
384
385 #[stride_sizes((IPv6, #strides6))]
386 struct #strides6_name;
387 };
388
389 let store = quote! {
390 /// A concurrently read/writable, lock-free Prefix Store, for use in a
391 /// multi-threaded context.
392 ///
393 /// This store will hold records keyed on Prefix, and with values
394 /// consisting of a multi-map (a map that can hold multiple values per
395 /// key), filled with Records.
396 ///
397 /// Records in the store contain the metadata, a `multi_uniq_id`,
398 /// logical time (to disambiguate the order of inserts into the store)
399 /// and the status of the Record.
400 ///
401 /// Effectively this means that the store holds values for the set of
402 /// `(prefix, multi_uniq_id)` pairs, where the primary key is the
403 /// prefix, and the secondary key is the `multi_uniq_id`. These
404 /// `multi_uniq_id`s are unique across all of the store. The store
405 /// facilitates iterating over and changing the status for all
406 /// prefixes per `multi_uniq_id`.
407 ///
408 /// The store has the concept of a global status for a
409 /// `multi_uniq_id`, e.g. to set all prefixes for a `multi_uniq_id` in
410 /// one atomic transaction to withdrawn. It also has local statuses
411 /// per `(prefix, multi_uniq_id)` pairs, e.g. to withdraw one value
412 /// for a `multi_uniq_id`.
413 ///
414 /// This way the store can hold RIBs for multiple peers in one
415 /// data-structure.
416 pub struct #store_name<
417 M: Meta
418 > {
419 v4: #strides4_name<M>,
420 v6: #strides6_name<M>,
421 }
422
423 impl<
424 M: Meta
425 > Default for #store_name<M>
426 {
427 fn default() -> Self {
428 Self::new().expect("failed to create store")
429 }
430 }
431
432 impl<
433 M: Meta
434 > #store_name<M>
435 {
436 /// Creates a new empty store with a tree for IPv4 and on for IPv6.
437 ///
438 /// The store will be created with the default stride sizes. After
439 /// creation you can wrap the store in an Arc<_> and `clone()` that
440 /// for every thread that needs read access and/or write acces to
441 /// it. As a convenience both read and write methods take a `&self`
442 /// instead of `&mut self`.
443 ///
444 /// If you need custom stride sizes you can use the
445 /// [`#[create_store]`](rotonda_macros::create_store) macro to
446 /// create a struct with custom stride sizes.
447 ///
448 /// # Example
449 /// ```
450 /// use std::{sync::Arc, thread};
451 /// use std::net::Ipv4Addr;
452 ///
453 /// use rotonda_store::prelude::*;
454 /// use rotonda_store::prelude::multi::*;
455 /// use rotonda_store::meta_examples::{NoMeta, PrefixAs};
456 ///
457 /// let tree_bitmap = Arc::new(MultiThreadedStore::<NoMeta>::new().unwrap());
458 ///
459 /// let _: Vec<_> = (0..16)
460 /// .map(|_| {
461 /// let tree_bitmap = tree_bitmap.clone();
462 ///
463 /// thread::spawn(move || {
464 /// let pfxs = [
465 /// Prefix::new_relaxed(
466 /// Ipv4Addr::new(130, 55, 241, 0).into(),
467 /// 24,
468 /// ),
469 /// Prefix::new_relaxed(
470 /// Ipv4Addr::new(130, 55, 240, 0).into(),
471 /// 24,
472 /// )
473 /// ];
474 ///
475 /// for pfx in pfxs.into_iter() {
476 /// println!("insert {}", pfx.unwrap());
477 /// tree_bitmap.insert(
478 /// &pfx.unwrap(),
479 /// Record::new(0, 0, RouteStatus::Active, NoMeta::Empty),
480 /// None
481 /// ).unwrap();
482 /// }
483 /// })
484 /// }).map(|t| t.join()).collect();
485 /// ```
486 pub fn new() -> Result<Self, Box<dyn std::error::Error>> {
487 Ok(Self {
488 v4: #strides4_name::new()?,
489 v6: #strides6_name::new()?,
490 })
491 }
492 }
493
494 impl<'a, M: Meta,
495 > #store_name<M>
496 {
497 /// Search for and return one or more prefixes that match the given
498 /// `search_pfx` argument.
499 ///
500 /// The search will return a [QueryResult] with the matching prefix,
501 /// if any, the type of match for the found prefix and the more and
502 /// less specifics for the requested prefix. The inclusion of more-
503 /// or less-specifics and the requested `match_type` is configurable
504 /// through the [MatchOptions] argument.
505 ///
506 /// The `match_type` in the `MatchOptions` indicates what match
507 /// types can appear in the [QueryResult] result.
508 ///
509 /// `ExactMatch` is the most strict, and will only allow exactly
510 /// matching prefixes in the result. Failing an exacly matching
511 /// prefix, it will return an `EmptyMatch`.
512 ///
513 /// `LongestMatch` is less strict, and either an exactly matching
514 /// prefix or - in case there is no exact match - a longest matching
515 /// prefix will be allowed in the result. Failing both an EmptyMatch
516 /// will be returned.
517 ///
518 /// For both `ExactMatch` and `LongestMatch` the
519 /// `include_less_specifics` and `include_more_specifics` options
520 /// will be respected and the result will contain the more and less
521 /// specifics according to the options for the requested prefix,
522 /// even if the result returns a `match_type` of `EmptyMatch`.
523 ///
524 /// `EmptyMatch` is the least strict, and will *always* return the
525 /// requested prefix, be it exactly matching, longest matching or not
526 /// matching at all (empty match), again, together with its less|more
527 /// specifics (if requested). Note that the last option, the empty
528 /// match in the result will never return less-specifics, but can
529 /// return more-specifics for a prefix that itself is not present
530 /// in the store.
531 ///
532 ///
533 /// This table sums it up:
534 ///
535 /// | query match_type | possible result types | less-specifics? | more-specifics? |
536 /// | ---------------- | ------------------------------------------ | --------------- | --------------- |
537 /// | `ExactMatch` | `ExactMatch`, `EmptyMatch` | maybe | maybe |
538 /// | `LongestMatch` | `ExactMatch`, `LongestMatch`, `EmptyMatch` | maybe | maybe |
539 /// | `EmptyMatch` | `ExactMatch`, `LongestMatch`, `EmptyMatch` | no for EmptyM res, maybe for others | yes for EmptyM for res, maybe for others |
540 ///
541 ///
542 /// Note that the behavior of the CLI command `show route exact` on
543 /// most router platforms can be modeled by setting the `match_type`
544 /// to `ExactMatch` and `include_less_specifics` to `true`.
545 ///
546 /// # Example
547 /// ```
548 /// use std::net::Ipv4Addr;
549 ///
550 /// use rotonda_store::prelude::*;
551 /// use rotonda_store::meta_examples::PrefixAs;
552 /// use rotonda_store::prelude::multi::*;
553 ///
554 /// let store = MultiThreadedStore::<PrefixAs>::new().unwrap();
555 /// let guard = &epoch::pin();
556 ///
557 /// let pfx_addr = "185.49.140.0".parse::<Ipv4Addr>()
558 /// .unwrap()
559 /// .into();
560 ///
561 /// store.insert(
562 /// &Prefix::new(pfx_addr, 22).unwrap(),
563 /// Record::new(0, 0, RouteStatus::Active, PrefixAs(211321)),
564 /// None
565 /// );
566 ///
567 /// let res = store.match_prefix(
568 /// &Prefix::new(pfx_addr, 24).unwrap(),
569 /// &MatchOptions {
570 /// match_type: MatchType::LongestMatch,
571 /// include_withdrawn: false,
572 /// include_less_specifics: false,
573 /// include_more_specifics: false,
574 /// mui: None
575 /// },
576 /// guard
577 /// );
578 ///
579 /// assert_eq!(res.prefix_meta[0].meta.0, 211321);
580 ///
581 /// let res = store.match_prefix(
582 /// &Prefix::new(pfx_addr, 24).unwrap(),
583 /// &MatchOptions {
584 /// match_type: MatchType::ExactMatch,
585 /// include_withdrawn: false,
586 /// include_less_specifics: false,
587 /// include_more_specifics: false,
588 /// mui: None
589 /// },
590 /// guard
591 /// );
592 ///
593 /// assert!(res.match_type.is_empty());
594 ///
595 /// ```
596 pub fn match_prefix(
597 &'a self,
598 search_pfx: &Prefix,
599 options: &MatchOptions,
600 guard: &'a Guard,
601 ) -> QueryResult<M> {
602
603 match search_pfx.addr() {
604 std::net::IpAddr::V4(addr) => {
605 self.v4.match_prefix_by_store_direct(
606 PrefixId::<IPv4>::new(
607 addr.into(),
608 search_pfx.len(),
609 ),
610 options,
611 options.mui,
612 guard
613 )
614 },
615 std::net::IpAddr::V6(addr) => self.v6.match_prefix_by_store_direct(
616 PrefixId::<IPv6>::new(
617 addr.into(),
618 search_pfx.len(),
619 ),
620 options,
621 options.mui,
622 guard
623 ),
624 }
625 }
626
627 /// Return the record that belongs to the pre-calculated and
628 /// stored best path for a given prefix.
629 ///
630 /// If the Prefix does not exist in the store `None` is returned.
631 /// If the prefix does exist, but no best path was calculated
632 /// (yet), a `PrefixStoreError::BestPathNotFound` error will be
633 /// returned. A returned result of
634 /// `PrefixError::StoreNotReadyError` should never happen: it
635 /// would indicate an internal inconsistency in the store.
636 pub fn best_path(&'a self,
637 search_pfx: &Prefix,
638 guard: &Guard
639 ) -> Option<Result<Record<M>, PrefixStoreError>> {
640
641 match search_pfx.addr() {
642 std::net::IpAddr::V4(addr) => self.v4.store
643 .non_recursive_retrieve_prefix(
644 PrefixId::<IPv4>::new(
645 addr.into(),
646 search_pfx.len(),
647 ),
648 )
649 .0
650 .map(|p_rec| unsafe { p_rec
651 .get_path_selections(guard).best()
652 .map_or_else(
653 || Err(PrefixStoreError::BestPathNotFound),
654 |mui| p_rec.record_map
655 .get_record_for_active_mui(mui)
656 .ok_or(PrefixStoreError::StoreNotReadyError)
657 )
658 }),
659 std::net::IpAddr::V6(addr) => self.v6.store
660 .non_recursive_retrieve_prefix(
661 PrefixId::<IPv6>::new(
662 addr.into(),
663 search_pfx.len(),
664 ),
665 )
666 .0
667 .map(|p_rec| unsafe { p_rec
668 .get_path_selections(guard).best()
669 .map_or_else(
670 || Err(PrefixStoreError::BestPathNotFound),
671 |mui| p_rec.record_map
672 .get_record_for_active_mui(mui)
673 .ok_or(PrefixStoreError::StoreNotReadyError)
674 )
675 })
676 }
677 }
678
679 /// Calculate and store the best path for the specified Prefix.
680 ///
681 /// If the result of the calculation is successful it will be
682 /// stored for the prefix. If they were set, it will return the
683 /// multi_uniq_id of the best path and the one for the backup
684 /// path, respectively. If the prefix does not exist in the store,
685 /// `None` will be returned. If the best path cannot be
686 /// calculated, a `Ok(None, None)` will be returned.
687 ///
688 /// Failing to calculate a best path, may be caused by
689 /// unavailability of any active paths, or by a lack of data (in
690 /// either the paths, or the supplied `TiebreakerInfo`).
691 ///
692 /// An Error result indicates an inconsistency in the store.
693 pub fn calculate_and_store_best_and_backup_path(
694 &self,
695 search_pfx: &Prefix,
696 tbi: &<M as Meta>::TBI,
697 guard: &Guard
698 ) -> Result<(Option<u32>, Option<u32>), PrefixStoreError> {
699 match search_pfx.addr() {
700 std::net::IpAddr::V4(addr) => self.v4.store
701 .non_recursive_retrieve_prefix(
702 PrefixId::<IPv4>::new(
703 addr.into(),
704 search_pfx.len(),
705 ),
706 // guard
707 ).0.map_or(
708 Err(PrefixStoreError::StoreNotReadyError),
709 |p_rec| p_rec.calculate_and_store_best_backup(
710 tbi, guard),
711 ),
712 std::net::IpAddr::V6(addr) => self.v6.store
713 .non_recursive_retrieve_prefix(
714 PrefixId::<IPv6>::new(
715 addr.into(),
716 search_pfx.len(),
717 ),
718 // guard
719 ).0.map_or(
720 Err(PrefixStoreError::StoreNotReadyError),
721 |p_rec| p_rec.calculate_and_store_best_backup(
722 tbi, guard),
723 ),
724 }
725 }
726
727 pub fn is_ps_outdated(
728 &self,
729 search_pfx: &Prefix,
730 guard: &Guard
731 ) -> Result<bool, PrefixStoreError> {
732 match search_pfx.addr() {
733 std::net::IpAddr::V4(addr) => self.v4.store
734 .non_recursive_retrieve_prefix(
735 PrefixId::<IPv4>::new(
736 addr.into(),
737 search_pfx.len(),
738 ),
739 // guard
740 ).0.map_or(
741 Err(PrefixStoreError::StoreNotReadyError),
742 |p| Ok(p.is_ps_outdated(guard))
743 ),
744 std::net::IpAddr::V6(addr) => self.v6.store
745 .non_recursive_retrieve_prefix(
746 PrefixId::<IPv6>::new(
747 addr.into(),
748 search_pfx.len(),
749 ),
750 // guard
751 ).0.map_or(
752 Err(PrefixStoreError::StoreNotReadyError),
753 |p| Ok(p.is_ps_outdated(guard))
754 )
755 }
756 }
757
758 /// Return a [QueryResult] that contains all the more-specific
759 /// prefixes of the `search_pfx` in the store, including the
760 /// meta-data of these prefixes.
761 ///
762 /// The `search_pfx` argument can be either a IPv4 or an IPv6
763 /// prefix. The `search_pfx` itself doesn't have to be present
764 /// in the store for an iterator to be non-empty, i.e. if
765 /// more-specific prefixes exist for a non-existent
766 /// `search_pfx` the iterator will yield these more-specific
767 /// prefixes.
768 ///
769 /// The `guard` should be a `&epoch::pin()`. It allows the
770 /// QuerySet to contain references to the meta-data objects,
771 /// instead of cloning them into it.
772 pub fn more_specifics_from(&'a self,
773 search_pfx: &Prefix,
774 mui: Option<u32>,
775 include_withdrawn: bool,
776 guard: &'a Guard,
777 ) -> QueryResult<M> {
778
779 match search_pfx.addr() {
780 std::net::IpAddr::V4(addr) => self.v4.more_specifics_from(
781 PrefixId::<IPv4>::new(
782 addr.into(),
783 search_pfx.len(),
784 ),
785 mui,
786 include_withdrawn,
787 guard
788 ),
789 std::net::IpAddr::V6(addr) => self.v6.more_specifics_from(
790 PrefixId::<IPv6>::new(
791 addr.into(),
792 search_pfx.len(),
793 ),
794 mui,
795 include_withdrawn,
796 guard
797 ),
798 }
799 }
800
801 /// Return a `QuerySet` that contains all the less-specific
802 /// prefixes of the `search_pfx` in the store, including the
803 /// meta-data of these prefixes.
804 ///
805 /// The `search_pfx` argument can be either a IPv4 or an IPv6
806 /// prefix. The `search_pfx` itself doesn't have to be present
807 /// in the store for an iterator to be non-empty, i.e. if
808 /// less-specific prefixes exist for a non-existent
809 /// `search_pfx` the iterator will yield these less-specific
810 /// prefixes.
811 ///
812 /// The `guard` should be a `&epoch::pin()`. It allows the
813 /// QuerySet to contain references to the meta-data objects,
814 /// instead of cloning them into it.
815 pub fn less_specifics_from(&'a self,
816 search_pfx: &Prefix,
817 mui: Option<u32>,
818 include_withdrawn: bool,
819 guard: &'a Guard,
820 ) -> QueryResult<M> {
821
822 match search_pfx.addr() {
823 std::net::IpAddr::V4(addr) => self.v4.less_specifics_from(
824 PrefixId::<IPv4>::new(
825 addr.into(),
826 search_pfx.len(),
827 ),
828 mui,
829 include_withdrawn,
830 guard
831 ),
832 std::net::IpAddr::V6(addr) => self.v6.less_specifics_from(
833 PrefixId::<IPv6>::new(
834 addr.into(),
835 search_pfx.len(),
836 ),
837 mui,
838 include_withdrawn,
839 guard
840 ),
841 }
842 }
843
844 /// Returns an iterator over all the less-specific prefixes
845 /// of the `search_prefix`, if present in the store, including
846 /// the meta-data of these prefixes.
847 ///
848 /// The `search_pfx` argument can be either a IPv4 or an IPv6
849 /// prefix. The `search_pfx` itself doesn't have to be present
850 /// in the store for an iterator to be non-empty, i.e. if
851 /// less-specific prefixes exist for a non-existent
852 /// `search_pfx` the iterator will yield these less-specific
853 /// prefixes.
854 ///
855 /// The `guard` should be a `&epoch::pin()`. It allows the
856 /// iterator to create and return references to the meta-data
857 /// objects to the caller (instead of cloning them).
858 ///
859 /// # Example
860 /// ```
861 /// use std::net::Ipv4Addr;
862 ///
863 /// use rotonda_store::prelude::*;
864 /// use rotonda_store::meta_examples::PrefixAs;
865 /// use rotonda_store::prelude::multi::*;
866 ///
867 ///
868 /// let store = MultiThreadedStore::<PrefixAs>::new().unwrap();
869 /// let guard = epoch::pin();
870 ///
871 /// let pfx_addr = "185.49.140.0".parse::<Ipv4Addr>()
872 /// .unwrap()
873 /// .into();
874 ///
875 /// store.insert(
876 /// &Prefix::new(pfx_addr, 22).unwrap(),
877 /// Record::new(0, 0, RouteStatus::Active, PrefixAs(211321)),
878 /// None
879 /// );
880 ///
881 /// for prefix_record in store.less_specifics_iter_from(
882 /// &Prefix::new(pfx_addr, 24).unwrap(),
883 /// None,
884 /// false,
885 /// &guard
886 /// ) {
887 /// assert_eq!(prefix_record.meta[0].meta.0, 211321);
888 /// }
889 /// ```
890 pub fn less_specifics_iter_from(&'a self,
891 search_pfx: &Prefix,
892 mui: Option<u32>,
893 include_withdrawn: bool,
894 guard: &'a Guard,
895 ) -> impl Iterator<Item=PrefixRecord<M>> + 'a {
896 let (left, right) = match search_pfx.addr() {
897 std::net::IpAddr::V4(addr) => {
898 (
899 Some(self.v4.store.less_specific_prefix_iter(
900 PrefixId::<IPv4>::new(
901 addr.into(),
902 search_pfx.len(),
903 ),
904 mui,
905 include_withdrawn,
906 guard
907 )
908 .map(|p| PrefixRecord::from(p))
909 ),
910 None
911 )
912 }
913 std::net::IpAddr::V6(addr) => {
914 (
915 None,
916 Some(self.v6.store.less_specific_prefix_iter(
917 PrefixId::<IPv6>::new(
918 addr.into(),
919 search_pfx.len(),
920 ),
921 mui,
922 include_withdrawn,
923 guard
924 )
925 .map(|p| PrefixRecord::from(p))
926 )
927 )
928 }
929 };
930 left.into_iter().flatten().chain(right.into_iter().flatten())
931 }
932
933 /// Returns an iterator over all the more-specifics prefixes
934 /// of the `search_prefix`, if present in the store, including
935 /// the meta-data of these prefixes.
936 ///
937 /// The `search_pfx` argument can be either a IPv4 or an IPv6
938 /// prefix. The `search_pfx` itself doesn't have to be present
939 /// in the store for an iterator to be non-empty, i.e. if
940 /// more-specific prefixes exist for a non-existent
941 /// `search_pfx` the iterator will yield these more-specific
942 /// prefixes.
943 ///
944 /// The `guard` should be a `&epoch::pin()`. It allows the
945 /// iterator to create and return references to the meta-data
946 /// objects to the caller (instead of cloning them).
947 ///
948 /// # Example
949 /// ```
950 /// use std::net::Ipv4Addr;
951 ///
952 /// use rotonda_store::prelude::*;
953 /// use rotonda_store::prelude::multi::*;
954 /// use rotonda_store::meta_examples::PrefixAs;
955 ///
956 /// let store = MultiThreadedStore::<PrefixAs>::new().unwrap();
957 /// let guard = epoch::pin();
958 ///
959 /// let pfx_addr = "185.49.140.0".parse::<Ipv4Addr>()
960 /// .unwrap()
961 /// .into();
962 ///
963 /// store.insert(
964 /// &Prefix::new(pfx_addr, 24).unwrap(),
965 /// Record::new(0, 0, RouteStatus::Active, PrefixAs(211321)),
966 /// None
967 /// );
968 ///
969 /// for prefix_record in store.more_specifics_iter_from(
970 /// &Prefix::new(pfx_addr, 22).unwrap(),
971 /// None,
972 /// false,
973 /// &guard
974 /// ) {
975 /// assert_eq!(prefix_record.meta[0].meta.0, 211321);
976 /// }
977 /// ```
978 pub fn more_specifics_iter_from(&'a self,
979 search_pfx: &Prefix,
980 mui: Option<u32>,
981 include_withdrawn: bool,
982 guard: &'a Guard,
983 ) -> impl Iterator<Item=PrefixRecord<M>> + 'a {
984
985 let (left, right) = match search_pfx.addr() {
986 std::net::IpAddr::V4(addr) => {
987 let bmin = unsafe {
988 self.v4.store.withdrawn_muis_bmin.load(
989 Ordering::Acquire, guard
990 ).deref()
991 };
992 if mui.is_some() && bmin.contains(mui.unwrap()) {
993 (None, None)
994 } else {
995 (
996 Some(self.v4.store.more_specific_prefix_iter_from(
997 PrefixId::<IPv4>::new(
998 addr.into(),
999 search_pfx.len(),
1000 ),
1001 mui,
1002 include_withdrawn,
1003 guard
1004 ).map(|p| PrefixRecord::from(p))
1005 ),
1006 None
1007 )
1008 }
1009 }
1010 std::net::IpAddr::V6(addr) => {
1011 let bmin = unsafe {
1012 self.v6.store.withdrawn_muis_bmin.load(
1013 Ordering::Acquire, guard
1014 ).deref()
1015 };
1016 if mui.is_some() && bmin.contains(mui.unwrap()) {
1017 (None, None)
1018 } else {
1019 (
1020 None,
1021 Some(self.v6.store.more_specific_prefix_iter_from(
1022 PrefixId::<IPv6>::new(
1023 addr.into(),
1024 search_pfx.len(),
1025 ),
1026 mui,
1027 include_withdrawn,
1028 guard
1029 ).map(|p| PrefixRecord::from(p))
1030 )
1031 )
1032 }
1033 }
1034 };
1035 left.into_iter().flatten().chain(right.into_iter().flatten())
1036 }
1037
1038 pub fn iter_records_for_mui_v4(
1039 &'a self,
1040 mui: u32,
1041 include_withdrawn: bool,
1042 guard: &'a Guard
1043 ) -> impl Iterator<Item=PrefixRecord<M>> +'a {
1044
1045 let bmin = unsafe {
1046 self.v4.store.withdrawn_muis_bmin.load(
1047 Ordering::Acquire, guard
1048 ).deref()
1049 };
1050
1051 if bmin.contains(mui) && !include_withdrawn {
1052 None
1053 } else {
1054 Some(
1055 self.v4.store.more_specific_prefix_iter_from(
1056 PrefixId::<IPv4>::new(
1057 0,
1058 0,
1059 ),
1060 Some(mui),
1061 include_withdrawn,
1062 guard
1063 ).map(|p| PrefixRecord::from(p))
1064 )
1065 }.into_iter().flatten()
1066 }
1067
1068 pub fn iter_records_for_mui_v6(
1069 &'a self,
1070 mui: u32,
1071 include_withdrawn: bool,
1072 guard: &'a Guard
1073 ) -> impl Iterator<Item=PrefixRecord<M>> +'a {
1074
1075 let bmin = unsafe {
1076 self.v4.store.withdrawn_muis_bmin.load(
1077 Ordering::Acquire, guard
1078 ).deref()
1079 };
1080
1081 if bmin.contains(mui) && !include_withdrawn {
1082 None
1083 } else {
1084 Some(
1085 self.v6.store.more_specific_prefix_iter_from(
1086 PrefixId::<IPv6>::new(
1087 0,
1088 0,
1089 ),
1090 Some(mui),
1091 include_withdrawn,
1092 guard
1093 ).map(|p| PrefixRecord::from(p))
1094 )
1095 }.into_iter().flatten()
1096 }
1097
1098 /// Insert or replace a Record into the Store
1099 ///
1100 /// The specified Record will replace an existing record in the
1101 /// store if the multi-map for the specified prefix already has an
1102 /// entry for the `multi_uniq_id`, otherwise it will be added to
1103 /// the multi-map.
1104 ///
1105 /// If the `update_path_sections` argument is used the best path
1106 /// selection will be run on the resulting multi-map after insert
1107 /// and stored for the specified prefix.
1108 ///
1109 /// Returns some metrics about the resulting insert.
1110 pub fn insert(
1111 &self,
1112 prefix: &Prefix,
1113 record: Record<M>,
1114 update_path_selections: Option<M::TBI>
1115 ) -> Result<UpsertReport, PrefixStoreError> {
1116 match prefix.addr() {
1117 std::net::IpAddr::V4(addr) => {
1118 self.v4.insert(
1119 PrefixId::<IPv4>::from(*prefix),
1120 record,
1121 update_path_selections,
1122 )
1123 }
1124 std::net::IpAddr::V6(addr) => {
1125 self.v6.insert(
1126 PrefixId::<IPv6>::from(*prefix),
1127 record,
1128 update_path_selections,
1129 )
1130 }
1131 }
1132 }
1133
1134 /// Returns an unordered iterator over all prefixes, with any
1135 /// status (including Withdrawn), for both IPv4 and IPv6,
1136 /// currently in the store, including meta-data.
1137 ///
1138 /// Although the iterator is unordered within an address-family,
1139 /// it first iterates over all IPv4 addresses and then over all
1140 /// IPv6 addresses.
1141 ///
1142 /// The `guard` should be a `&epoch::pin()`. It allows the
1143 /// iterator to create and return references to the meta-data
1144 /// objects to the caller (instead of cloning them).
1145 ///
1146 /// # Example
1147 /// ```
1148 /// use std::net::Ipv4Addr;
1149 ///
1150 /// use rotonda_store::prelude::*;
1151 /// use rotonda_store::prelude::multi::*;
1152 /// use rotonda_store::meta_examples::PrefixAs;
1153 ///
1154 /// let store = MultiThreadedStore::<PrefixAs>::new().unwrap();
1155 /// let guard = epoch::pin();
1156 ///
1157 /// let pfx_addr = "185.49.140.0".parse::<Ipv4Addr>()
1158 /// .unwrap()
1159 /// .into();
1160 /// let our_asn = Record::new(0, 0, RouteStatus::Active, PrefixAs(211321));
1161 ///
1162 /// store.insert(&Prefix::new(pfx_addr, 22).unwrap(), our_asn.clone(), None);
1163 /// store.insert(&Prefix::new(pfx_addr, 23).unwrap(), our_asn.clone(), None);
1164 /// store.insert(&Prefix::new(pfx_addr, 24).unwrap(), our_asn.clone(), None);
1165 /// store.insert(&Prefix::new(pfx_addr, 25).unwrap(), our_asn, None);
1166 ///
1167 /// let mut iter = store.prefixes_iter();
1168 ///
1169 /// assert_eq!(iter.next().unwrap().prefix,
1170 /// Prefix::new(pfx_addr, 22).unwrap());
1171 /// assert_eq!(iter.next().unwrap().prefix,
1172 /// Prefix::new(pfx_addr, 23).unwrap());
1173 /// assert_eq!(iter.next().unwrap().prefix,
1174 /// Prefix::new(pfx_addr, 24).unwrap());
1175 /// assert_eq!(iter.next().unwrap().prefix,
1176 /// Prefix::new(pfx_addr, 25).unwrap());
1177 /// ```
1178 pub fn prefixes_iter(
1179 &'a self,
1180 ) -> impl Iterator<Item=PrefixRecord<M>> + 'a {
1181 self.v4.store.prefixes_iter()
1182 .map(|p| PrefixRecord::from(p))
1183 .chain(
1184 self.v6.store.prefixes_iter()
1185 .map(|p| PrefixRecord::from(p))
1186 )
1187 }
1188
1189 /// Returns an unordered iterator over all IPv4 prefixes in the
1190 /// currently in the store, with any status (including Withdrawn),
1191 /// including meta-data.
1192 ///
1193 /// The `guard` should be a `&epoch::pin()`. It allows the
1194 /// iterator to create and return references to the meta-data
1195 /// objects to the caller (instead of cloning them).
1196 ///
1197 /// # Example
1198 /// ```
1199 /// use std::net::Ipv4Addr;
1200 ///
1201 /// use rotonda_store::prelude::*;
1202 /// use rotonda_store::prelude::multi::*;
1203 /// use rotonda_store::meta_examples::PrefixAs;
1204 ///
1205 /// let store = MultiThreadedStore::<PrefixAs>::new().unwrap();
1206 /// let guard = epoch::pin();
1207 ///
1208 /// let pfx_addr = "185.49.140.0".parse::<Ipv4Addr>()
1209 /// .unwrap()
1210 /// .into();
1211 /// let our_asn = Record::new(0, 0, RouteStatus::Active, PrefixAs(211321));
1212 ///
1213 /// store.insert(&Prefix::new(pfx_addr, 22).unwrap(), our_asn.clone(), None);
1214 /// store.insert(&Prefix::new(pfx_addr, 23).unwrap(), our_asn.clone(), None);
1215 /// store.insert(&Prefix::new(pfx_addr, 24).unwrap(), our_asn.clone(), None);
1216 /// store.insert(&Prefix::new(pfx_addr, 25).unwrap(), our_asn, None);
1217 ///
1218 /// let mut iter = store.prefixes_iter();
1219 ///
1220 /// assert_eq!(iter.next().unwrap().prefix,
1221 /// Prefix::new(pfx_addr, 22).unwrap());
1222 /// assert_eq!(iter.next().unwrap().prefix,
1223 /// Prefix::new(pfx_addr, 23).unwrap());
1224 /// assert_eq!(iter.next().unwrap().prefix,
1225 /// Prefix::new(pfx_addr, 24).unwrap());
1226 /// assert_eq!(iter.next().unwrap().prefix,
1227 /// Prefix::new(pfx_addr, 25).unwrap());
1228 /// ```
1229 pub fn prefixes_iter_v4(
1230 &'a self,
1231 ) -> impl Iterator<Item=PrefixRecord<M>> + 'a {
1232 self.v4.store.prefixes_iter()
1233 .map(|p| PrefixRecord::from(p))
1234 }
1235
1236 /// Returns an unordered iterator over all IPv6 prefixes in the
1237 /// currently in the store, with any status (including Withdrawn),
1238 /// including meta-data.
1239 ///
1240 /// The `guard` should be a `&epoch::pin()`. It allows the
1241 /// iterator to create and return references to the meta-data
1242 /// objects to the caller (instead of cloning them).
1243 ///
1244 /// # Example
1245 /// ```
1246 /// use std::net::Ipv6Addr;
1247 ///
1248 /// use rotonda_store::prelude::*;
1249 /// use rotonda_store::prelude::multi::*;
1250 /// use rotonda_store::meta_examples::PrefixAs;
1251 ///
1252 /// let store = MultiThreadedStore::<PrefixAs>::new().unwrap();
1253 /// let guard = epoch::pin();
1254 ///
1255 /// let pfx_addr = "2a04:b900::".parse::<Ipv6Addr>()
1256 /// .unwrap()
1257 /// .into();
1258 /// let our_asn = Record::new(0, 0, RouteStatus::Active, PrefixAs(211321));
1259 ///
1260 /// store.insert(&Prefix::new(pfx_addr, 29).unwrap(), our_asn.clone(), None);
1261 /// store.insert(&Prefix::new(pfx_addr, 48).unwrap(), our_asn.clone(), None);
1262 /// store.insert(&Prefix::new(pfx_addr, 56).unwrap(), our_asn.clone(), None);
1263 /// store.insert(&Prefix::new(pfx_addr, 64).unwrap(), our_asn, None);
1264 ///
1265 /// let mut iter = store.prefixes_iter();
1266 ///
1267 /// assert_eq!(iter.next().unwrap().prefix,
1268 /// Prefix::new(pfx_addr, 29).unwrap());
1269 /// assert_eq!(iter.next().unwrap().prefix,
1270 /// Prefix::new(pfx_addr, 48).unwrap());
1271 /// assert_eq!(iter.next().unwrap().prefix,
1272 /// Prefix::new(pfx_addr, 56).unwrap());
1273 /// assert_eq!(iter.next().unwrap().prefix,
1274 /// Prefix::new(pfx_addr, 64).unwrap());
1275 /// ```
1276 pub fn prefixes_iter_v6(
1277 &'a self,
1278 ) -> impl Iterator<Item=PrefixRecord<M>> + 'a {
1279 self.v6.store.prefixes_iter()
1280 .map(|p| PrefixRecord::from(p))
1281 }
1282
1283 /// Change the local status of the record for the combination of
1284 /// (prefix, multi_uniq_id) to Withdrawn. Note that by default the
1285 /// global `Withdrawn` status for a mui overrides the local status
1286 /// of a record.
1287 pub fn mark_mui_as_withdrawn_for_prefix(
1288 &self,
1289 prefix: &Prefix,
1290 mui: u32
1291 ) -> Result<(), PrefixStoreError> {
1292 let guard = &epoch::pin();
1293 match prefix.addr() {
1294 std::net::IpAddr::V4(addr) => {
1295 self.v4.store.mark_mui_as_withdrawn_for_prefix(
1296 PrefixId::<IPv4>::from(*prefix),
1297 mui,
1298 // &guard
1299 )
1300 }
1301 std::net::IpAddr::V6(addr) => {
1302 self.v6.store.mark_mui_as_withdrawn_for_prefix(
1303 PrefixId::<IPv6>::from(*prefix),
1304 mui,
1305 // &guard
1306 )
1307 }
1308 }
1309 }
1310
1311 /// Change the local status of the record for the combination of
1312 /// (prefix, multi_uniq_id) to Active. Note that by default the
1313 /// global `Withdrawn` status for a mui overrides the local status
1314 /// of a record.
1315 pub fn mark_mui_as_active_for_prefix(
1316 &self,
1317 prefix: &Prefix,
1318 mui: u32
1319 ) -> Result<(), PrefixStoreError> {
1320 let guard = &epoch::pin();
1321 match prefix.addr() {
1322 std::net::IpAddr::V4(addr) => {
1323 self.v4.store.mark_mui_as_active_for_prefix(
1324 PrefixId::<IPv4>::from(*prefix),
1325 mui,
1326 // &guard
1327 )
1328 }
1329 std::net::IpAddr::V6(addr) => {
1330 self.v6.store.mark_mui_as_active_for_prefix(
1331 PrefixId::<IPv6>::from(*prefix),
1332 mui,
1333 // &guard
1334 )
1335 }
1336 }
1337 }
1338
1339 /// Change the status of all records for IPv4 prefixes for this
1340 /// `multi_uniq_id` globally to Active. Note that the global
1341 /// `Active` status will be overridden by the local status of the
1342 /// record.
1343 pub fn mark_mui_as_active_v4(
1344 &self,
1345 mui: u32
1346 ) -> Result<(), PrefixStoreError> {
1347 let guard = &epoch::pin();
1348
1349 self.v4.store.mark_mui_as_active(
1350 mui,
1351 &guard
1352 )
1353 }
1354
1355 /// Change the status of all records for IPv4 prefixes for this
1356 /// `multi_uniq_id` globally to Withdrawn. A global `Withdrawn`
1357 /// status for a `multi_uniq_id` overrides the local status of
1358 /// prefixes for this mui. However the local status can still be
1359 /// modified. This modification will take effect if the global
1360 /// status is changed to `Active`.
1361 pub fn mark_mui_as_withdrawn_v4(
1362 &self,
1363 mui: u32
1364 ) -> Result<(), PrefixStoreError> {
1365 let guard = &epoch::pin();
1366
1367 self.v4.store.mark_mui_as_withdrawn(
1368 mui,
1369 &guard
1370 )
1371 }
1372
1373 /// Change the status of all records for IPv6 prefixes for this
1374 /// `multi_uniq_id` globally to Active. Note that the global
1375 /// `Active` status will be overridden by the local status of the
1376 /// record.
1377 pub fn mark_mui_as_active_v6(
1378 &self,
1379 mui: u32
1380 ) -> Result<(), PrefixStoreError> {
1381 let guard = &epoch::pin();
1382
1383 self.v6.store.mark_mui_as_active(
1384 mui,
1385 &guard
1386 )
1387 }
1388
1389 /// Change the status of all records for IPv6 prefixes for this
1390 /// `multi_uniq_id` globally to Withdrawn. A global `Withdrawn`
1391 /// status for a `multi_uniq_id` overrides the local status of
1392 /// prefixes for this mui. However the local status can still be
1393 /// modified. This modification will take effect if the global
1394 /// status is changed to `Active`.
1395 pub fn mark_mui_as_withdrawn_v6(
1396 &self,
1397 mui: u32
1398 ) -> Result<(), PrefixStoreError> {
1399 let guard = &epoch::pin();
1400
1401 self.v6.store.mark_mui_as_withdrawn(
1402 mui,
1403 &guard
1404 )
1405 }
1406
1407
1408 /// Change the status of all records for this `multi_uniq_id` to
1409 /// Withdrawn.
1410 ///
1411 /// This method tries to mark all records: first the IPv4 records,
1412 /// then the IPv6 records. If marking of the IPv4 records fails,
1413 /// the method continues and tries to mark the IPv6 records. If
1414 /// either or both fail, an error is returned.
1415 pub fn mark_mui_as_withdrawn(
1416 &self,
1417 mui: u32
1418 ) -> Result<(), PrefixStoreError> {
1419 let guard = &epoch::pin();
1420
1421 let res_v4 = self.v4.store.mark_mui_as_withdrawn(
1422 mui,
1423 &guard
1424 );
1425 let res_v6 = self.v6.store.mark_mui_as_withdrawn(
1426 mui,
1427 &guard
1428 );
1429
1430 res_v4.and(res_v6)
1431 }
1432
1433
1434
1435 // Whether the global status for IPv4 prefixes and the specified
1436 // `multi_uniq_id` is set to `Withdrawn`.
1437 pub fn mui_is_withdrawn_v4(
1438 &self,
1439 mui: u32
1440 ) -> bool {
1441 let guard = &epoch::pin();
1442
1443 self.v4.store.mui_is_withdrawn(mui, guard)
1444 }
1445
1446 // Whether the global status for IPv6 prefixes and the specified
1447 // `multi_uniq_id` is set to `Active`.
1448 pub fn mui_is_withdrawn_v6(
1449 &self,
1450 mui: u32
1451 ) -> bool {
1452 let guard = &epoch::pin();
1453
1454 self.v6.store.mui_is_withdrawn(mui, guard)
1455 }
1456
1457 /// Returns the number of all prefixes in the store.
1458 ///
1459 /// Note that this method will actually traverse the complete
1460 /// tree.
1461 pub fn prefixes_count(&self) -> usize {
1462 self.v4.store.get_prefixes_count()
1463 + self.v6.store.get_prefixes_count()
1464 }
1465
1466 /// Returns the number of all IPv4 prefixes in the store.
1467 ///
1468 /// Note that this counter may be lower than the actual
1469 /// number in the store, due to contention at the time of
1470 /// reading the value.
1471 pub fn prefixes_v4_count(&self) -> usize {
1472 self.v4.store.get_prefixes_count()
1473 }
1474
1475 /// Returns the number of all IPv4 prefixes with the
1476 /// supplied prefix length in the store.
1477 ///
1478 /// Note that this counter may be lower than the actual
1479 /// number in the store, due to contention at the time of
1480 /// reading the value.
1481 pub fn prefixes_v4_count_for_len(&self, len: u8) -> usize {
1482 self.v4.store.get_prefixes_count_for_len(len)
1483 }
1484
1485 /// Returns the number of all IPv6 prefixes in the store.
1486 ///
1487 /// Note that this counter may be lower than the actual
1488 /// number in the store, due to contention at the time of
1489 /// reading the value.
1490 pub fn prefixes_v6_count(&self) -> usize {
1491 self.v6.store.get_prefixes_count()
1492 }
1493
1494 /// Returns the number of all IPv6 prefixes with the
1495 /// supplied prefix length in the store.
1496 ///
1497 /// Note that this counter may be lower than the actual
1498 /// number in the store, due to contention at the time of
1499 /// reading the value.
1500 pub fn prefixes_v6_count_for_len(&self, len: u8) -> usize {
1501 self.v6.store.get_prefixes_count_for_len(len)
1502 }
1503
1504 /// Returns the number of nodes in the store.
1505 ///
1506 /// Note that this counter may be lower than the actual
1507 /// number in the store, due to contention at the time of
1508 /// reading the value.
1509 pub fn nodes_count(&self) -> usize {
1510 self.v4.store.get_nodes_count()
1511 + self.v6.store.get_nodes_count()
1512 }
1513
1514 /// Returns the number of IPv4 nodes in the store.
1515 ///
1516 /// Note that this counter may be lower than the actual
1517 /// number in the store, due to contention at the time of
1518 /// reading the value.
1519 pub fn nodes_v4_count(&self) -> usize {
1520 self.v4.store.get_nodes_count()
1521 }
1522
1523 /// Returns the number of IPv6 nodes in the store.
1524 ///
1525 /// Note that this counter may be lower than the actual
1526 /// number in the store, due to contention at the time of
1527 /// reading the value.
1528 pub fn nodes_v6_count(&self) -> usize {
1529 self.v6.store.get_nodes_count()
1530 }
1531
1532 /// Print the store statistics to the standard output.
1533 #[cfg(feature = "cli")]
1534 pub fn print_funky_stats(&self) {
1535 println!("");
1536 println!("Stats for IPv4 multi-threaded store\n");
1537 println!("{}", self.v4);
1538 println!("Stats for IPv6 multi-threaded store\n");
1539 println!("{}", self.v6);
1540 }
1541
1542 // The Store statistics.
1543 pub fn stats(&self) -> StoreStats {
1544 StoreStats {
1545 v4: self.v4.store.counters.get_prefix_stats(),
1546 v6: self.v6.store.counters.get_prefix_stats(),
1547 }
1548 }
1549 }
1550 };
1551
1552 let result = quote! {
1553 #create_strides
1554 #store
1555 };
1556
1557 TokenStream::from(result)
1558}