Crates.io | root |
lib.rs | root |
version | 0.1.1 |
source | src |
created_at | 2024-06-08 21:24:22.354835 |
updated_at | 2024-08-30 01:25:44.815879 |
description | root is an abstract I/O free routing protocol |
homepage | |
repository | https://github.com/encodeous/root |
max_upload_size | |
id | 1265966 |
size | 43,962 |
root is an abstract I/O-free routing framework inspired by the Babel Routing Protocol. It provides a high-level framework to design dynamic, fault-tolerant networks.
The application is solely responsible for providing I/O and scheduling events, meaning that users of root are free to use any platform, framework, or architecture they desire.
For a complete example routing application that uses TCP as transport, see /examples/simple-mesh
.
To get started with root, run:
cargo add root
, use the serde
feature for serialization.
root is designed from the ground up to offer a platform, network, and protocol agnostic way to do routing.
For more motivations, you can read this set of articles.
root tries its best to abstract the complexity of networking, while maintaining compatibility with low level concepts.
When building a routing network using the root framework, the architect can specify a set of pre-defined parameters that defines it.
NodeAddress
typeThe NodeAddress is a globally (on each network) unique identifier that is attached to each node.
Link
typeThe link type represents a physical bidirectional connection between two nodes. This is not sent to other nodes, and should be unique on each node.
[!CAUTION] These examples do not implement MAC, meaning that routes/packets can be forged. The root crate implicitly trusts the authenticity of such packets.
To demonstrate the use of the root crate, here is a super simple example where we have 3 nodes, bob
, eve
, and alice
.
We have: bob <-> eve <-> alice
, but not bob <-> alice
.
We want the routing system to figure out how to reach alice
from bob
We can start off by defining the routing parameters. This is a compile-time constant shared across all nodes.
use root::framework::RoutingSystem;
use root::router::NoMACSystem;
struct SimpleExample {} // just a type to inform root of your network parameters
impl RoutingSystem for SimpleExample{
type NodeAddress = String; // our nodes have string names
type Link = i32;
type MACSystem = NoMACSystem; // we won't use MAC for this example
}
Now, for each node, we can create a router:
// we have the following connection: bob <-> eve <-> alice
let mut nodes = HashMap::new();
let mut bob = Router::<SimpleExample>::new("bob".to_string());
bob.links.insert(1, Neighbour::new("eve".to_string()));
nodes.insert("bob", bob);
let mut eve = Router::<SimpleExample>::new("eve".to_string());
eve.links.insert(1, Neighbour::new("bob".to_string()));
eve.links.insert(2, Neighbour::new("alice".to_string()));
nodes.insert("eve", eve);
let mut alice = Router::<SimpleExample>::new("alice".to_string());
alice.links.insert(2, Neighbour::new("eve".to_string()));
nodes.insert("alice", alice);
Now we can let root take over, and have it automatically discover the route.
We simply let root generate routing packets, and simulate sending them to the other nodes. In a real network, these packets need to be serialized and sent over the network.
// lets simulate routing!
for step in 0..3 {
// collect all of our packets, if any
let packets: Vec<OutboundPacket<SimpleExample>> = nodes.iter_mut().flat_map(|(_id, node)| node.outbound_packets.drain(..)).collect();
for OutboundPacket{link, dest, packet} in packets{
// deliver the routing packet. in this simple example, the link isn't really used. in a real network, this link will give us information on how to send the packet
if let Some(node) = nodes.get_mut(dest.as_str()){
node.handle_packet(&packet, &link, &dest).expect("Failed to handle packet");
}
}
for node in nodes.values_mut(){
node.full_update(); // performs route table calculations, and writes routing updates into outbound_packets
}
// lets observe bob's route table:
println!("Bob's routes in step {step}:");
for (neigh, Route::<SimpleExample>{ metric, next_hop, .. }) in &nodes["bob"].routes{
println!(" - {neigh}: metric: {metric}, next_hop: {next_hop}")
}
}
Here is the output for this example:
Bob's routes in step 0:
Bob's routes in step 1:
- eve: metric: 1, next_hop: eve
Bob's routes in step 2:
- eve: metric: 1, next_hop: eve
- alice: metric: 2, next_hop: eve
[!NOTE]
You can try running this example yourself, its files are located in./examples/super-simple
[!NOTE]
To demonstrate the root crate working over real network connections, a complete example is provided in./examples/simple-mesh
.
This example uses TCP streams as the transport, and is based on a event/channel pattern.