1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
//! Generic record types
//!
//! Records hold snippets of information that are contained in a
//! BGP packet. The type of the key is variable: it can be an NLRI, or the
//! NLRI can be disassembled into several records with the prefixes contained
//! in the NLRI as key.
//!
//! A record can be turned into a message (MessageRecord trait) to be ready
//! to be send to other units, or external systems. A message has no
//! references (anymore).
//!
//! example:
//! BGP packet → disassemble into records → turn into message → send to other
//! units
//!
//! See ```bgp``` module for records specific to BGP.
use std::borrow::Cow;
use std::fmt;
//------------ Traits for Record --------------------------------------------
/// Trait for types that act as keys for records.
///
/// These traits must be implemented by all record types.
/// Trait that describes the record key, a key can be a NLRI (or a part of
/// that), but it can also be other TLVs originating from a BGP packet.
/// Key of a record
pub trait Key {}
impl Key for (u64, u32) where Self: Copy + Sized {}
/// Trait for a type to act as the identity of the message sender
pub trait SenderId
where
Self: Copy + Sized,
{
}
impl SenderId for u32 {}
/// Sender ID type
pub type SenderIdInt = u32;
/// Lamport Timestamp. Used to order messages between units/systems.
pub type LogicalTime = u64;
/// Generic Record trait
///
/// The Record trait describes any type that has a key and metadata, and that
/// it is not a message (yet). The type should accomodate both holding
/// metadata as a reference, as well as storing the metadata inside itself.
///
/// Types implementing this trait should be used to disassemble BGP packets
/// into storable data points.
pub trait Record<'a>
where
Self: Clone,
{
type Key: crate::record::Key;
type Meta: crate::record::Meta;
fn new(key: Self::Key, meta: &'a Self::Meta) -> Self;
fn new_with_local_meta(key: Self::Key, local_meta: Self::Meta) -> Self;
fn key(&'a self) -> Self::Key;
fn meta(&'a self) -> Cow<'a, Self::Meta>;
}
/// Record as a stand-alone message
///
/// The MessageRecord trait describes a record turned message. It should have
/// at least two fields, `sender_id` and `ltime` (or be able to synthesize
/// those).
///
/// A generic record type (that implements the Record trait) should be able
/// to be turned into a message record. The message should own all the data
/// it holds so it can be cut loose and send off to other systems through
/// cloning and/or serialization.
///
/// The MessageRecord type should be used to send messages to other units or
/// external systems.
pub trait MessageRecord<'a>
where
Self: Clone + Record<'a>,
{
type SenderId: crate::record::SenderId;
fn new(
key: <Self as Record<'a>>::Key,
meta: <Self as Record<'a>>::Meta,
sender_id: Self::SenderId,
// Logical Time of this message (Lamport timestamp)
ltime: u64,
) -> Self;
fn new_from_record(
record: Self,
sender_id: Self::SenderId,
ltime: u64,
) -> Self;
#[must_use]
fn into_message(self, sender_id: Self::SenderId, ltime: u64) -> Self;
fn sender_id(&self) -> Self::SenderId;
fn key(&'a self) -> <Self as Record<'a>>::Key {
<Self as Record>::key(self)
}
fn meta(&'a self) -> Cow<<Self as Record<'a>>::Meta> {
Cow::Owned(<Self as Record>::meta(self).into_owned())
}
fn ltime(&self) -> u64;
fn set_ltime(&mut self, ltime: u64) -> u64;
fn inc_ltime(&mut self) -> u64 {
let ltime = self.ltime();
self.set_ltime(ltime + 1)
}
fn timestamp(&self) -> u64;
}
//----------------------- meta-data traits/types-----------------------------
/// Trait that describes how an existing record gets merged
///
/// MergeUpdate must be implemented by a type that implements Meta if it
/// wants to be able to be stored. It should describe how the metadata for an
/// existing record should be merged with newly arriving records for the same
/// key.
pub trait MergeUpdate {
fn merge_update(
&mut self,
update_meta: Self,
) -> Result<(), Box<dyn std::error::Error>>;
// This is part of the Read-Copy-Update pattern for updating a record
// concurrently. The Read part should be done by the caller and then
// the result should be passed in into this function together with
// the new meta-data that updates it. This function will then create
// a copy (in the pattern lingo, but in Rust that would be a Clone,
// since we're not requiring Copy for Meta) and update that with a
// copy of the new meta-data. It then returns the result of that merge.
// The caller should then proceed to insert that as a new entry
// in the global store.
fn clone_merge_update(
&self,
update_meta: &Self,
) -> Result<Self, Box<dyn std::error::Error>>
where
Self: std::marker::Sized;
}
/// Trait for types that can be used as metadata of a record
pub trait Meta
where
Self: fmt::Debug + Sized + fmt::Display + Clone,
{
fn summary(&self) -> String;
}
impl<T> Meta for T
where
T: fmt::Debug + fmt::Display + Clone,
{
fn summary(&self) -> String {
format!("{}", self)
}
}
/// Tree-wide empty meta-data type
///
/// A special type that indicates that there's no metadata in the tree
/// storing the prefixes. Note that this is different from a tree with
/// optional meta-data.
#[derive(Clone, Copy)]
pub enum NoMeta {
Empty,
}
impl fmt::Debug for NoMeta {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("")
}
}
impl fmt::Display for NoMeta {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("")
}
}
impl MergeUpdate for NoMeta {
fn merge_update(
&mut self,
_: NoMeta,
) -> Result<(), Box<dyn std::error::Error>> {
Ok(())
}
fn clone_merge_update(
&self,
_: &NoMeta,
) -> Result<Self, Box<dyn std::error::Error>> {
Ok(NoMeta::Empty)
}
}