Skip to content

Commit dabd564

Browse files
committed
Merge remote-tracking branch 'origin/main'
2 parents bc84348 + 91350f4 commit dabd564

39 files changed

+724
-295
lines changed

.github/workflows/rust.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
name: Rust
2+
3+
on:
4+
push:
5+
branches: [ "main" ]
6+
pull_request:
7+
branches: [ "main" ]
8+
9+
env:
10+
CARGO_TERM_COLOR: always
11+
12+
jobs:
13+
build:
14+
15+
runs-on: ubuntu-latest
16+
17+
steps:
18+
- uses: actions/checkout@v4
19+
- name: Build
20+
run: cargo build --verbose
21+
- name: Run tests
22+
run: cargo test --verbose

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,6 @@ Cargo.lock
2424

2525
/examples/graph-mesh/graph-mesh
2626

27-
.idea
27+
.idea
28+
29+
/examples/simple-mesh/config.json

Cargo.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
[workspace]
2+
resolver = "2"
23

34
members = [
45
"root",
56
"examples/mesh-vis",
67
"examples/simple-mesh",
7-
"examples/graph-gen"
8-
]
8+
"examples/graph-gen",
9+
"examples/super-simple"]

README.md

Lines changed: 131 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,132 @@
11
# root
2-
An I/O Free High-Level Routing Protocol inspired by Babel
2+
3+
[root](https://github.com/encodeous/root) is an abstract I/O-free routing framework inspired by the [Babel Routing Protocol](https://datatracker.ietf.org/doc/html/rfc8966). It provides a high-level framework to design dynamic, fault-tolerant networks.
4+
5+
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.
6+
7+
For a complete example routing application that uses TCP as transport, see `/examples/simple-mesh`.
8+
9+
To get started with root, run:
10+
`cargo add root`, use the `serde` feature for serialization.
11+
12+
# Why I/O-free?
13+
14+
root is designed from the ground up to offer a platform, network, and protocol agnostic way to do routing.
15+
- Compared to traditional implementations that rely on a **specific network stack**, root is able to work for **any situation** where a graph of nodes are joined together with bidirectional links.
16+
- Decisions about how to physically forward packets are left to the **application**, allowing hybrid routing over **multiple protocols** (i.e routing over IPv4, IPv6, Serial & Bluetooth all at once)
17+
- An I/O-free implementation allows root to be thoroughly tested, and operate with deterministic state at all times.
18+
19+
For more motivations, you can read [this set of articles](https://sans-io.readthedocs.io/index.html#).
20+
21+
22+
# Concepts
23+
24+
root tries its best to abstract the complexity of networking, while maintaining compatibility with low level concepts.
25+
26+
## Templating
27+
28+
When building a routing network using the root framework, the architect can specify a set of pre-defined parameters that defines it.
29+
30+
## The `NodeAddress` type
31+
32+
The NodeAddress is a globally (on each network) unique identifier that is attached to each node.
33+
34+
## The `Link` type
35+
36+
The link type represents a physical bidirectional connection between two nodes. This is not sent to other nodes, and should be unique on each node.
37+
38+
# Example Usage
39+
40+
> [!CAUTION]
41+
> These examples do not implement MAC, meaning that routes/packets can be forged. The root crate implicitly trusts the authenticity of such packets.
42+
43+
## Basic Example
44+
45+
To demonstrate the use of the root crate, here is a super simple example where we have 3 nodes, `bob`, `eve`, and `alice`.
46+
47+
We have: `bob <-> eve <-> alice`, but not `bob <-> alice`.
48+
49+
We want the routing system to figure out how to reach `alice` from `bob`
50+
51+
We can start off by defining the routing parameters. This is a compile-time constant shared across all nodes.
52+
53+
```rust
54+
use root::framework::RoutingSystem;
55+
use root::router::NoMACSystem;
56+
57+
struct SimpleExample {} // just a type to inform root of your network parameters
58+
impl RoutingSystem for SimpleExample{
59+
type NodeAddress = String; // our nodes have string names
60+
type Link = i32;
61+
type MACSystem = NoMACSystem; // we won't use MAC for this example
62+
}
63+
```
64+
65+
Now, for each node, we can create a router:
66+
```rust
67+
// we have the following connection: bob <-> eve <-> alice
68+
69+
let mut nodes = HashMap::new();
70+
71+
let mut bob = Router::<SimpleExample>::new("bob".to_string());
72+
bob.links.insert(1, Neighbour::new("eve".to_string()));
73+
nodes.insert("bob", bob);
74+
75+
let mut eve = Router::<SimpleExample>::new("eve".to_string());
76+
eve.links.insert(1, Neighbour::new("bob".to_string()));
77+
eve.links.insert(2, Neighbour::new("alice".to_string()));
78+
nodes.insert("eve", eve);
79+
80+
let mut alice = Router::<SimpleExample>::new("alice".to_string());
81+
alice.links.insert(2, Neighbour::new("eve".to_string()));
82+
nodes.insert("alice", alice);
83+
```
84+
85+
Now we can let root take over, and have it automatically discover the route.
86+
87+
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.
88+
89+
```rust
90+
// lets simulate routing!
91+
92+
for step in 0..3 {
93+
// collect all of our packets, if any
94+
let packets: Vec<OutboundPacket<SimpleExample>> = nodes.iter_mut().flat_map(|(_id, node)| node.outbound_packets.drain(..)).collect();
95+
96+
for OutboundPacket{link, dest, packet} in packets{
97+
// 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
98+
if let Some(node) = nodes.get_mut(dest.as_str()){
99+
node.handle_packet(&packet, &link, &dest).expect("Failed to handle packet");
100+
}
101+
}
102+
103+
for node in nodes.values_mut(){
104+
node.full_update(); // performs route table calculations, and writes routing updates into outbound_packets
105+
}
106+
107+
// lets observe bob's route table:
108+
println!("Bob's routes in step {step}:");
109+
for (neigh, Route::<SimpleExample>{ metric, next_hop, .. }) in &nodes["bob"].routes{
110+
println!(" - {neigh}: metric: {metric}, next_hop: {next_hop}")
111+
}
112+
}
113+
```
114+
115+
Here is the output for this example:
116+
```
117+
Bob's routes in step 0:
118+
Bob's routes in step 1:
119+
- eve: metric: 1, next_hop: eve
120+
Bob's routes in step 2:
121+
- eve: metric: 1, next_hop: eve
122+
- alice: metric: 2, next_hop: eve
123+
```
124+
> [!NOTE]
125+
> You can try running this example yourself, its files are located in `./examples/super-simple`
126+
127+
## Network Example
128+
129+
> [!NOTE]
130+
> To demonstrate the root crate working over real network connections, a complete example is provided in `./examples/simple-mesh`.
131+
132+
This example uses TCP streams as the transport, and is based on a event/channel pattern.

examples/graph-gen/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@ version = "0.1.0"
44
edition = "2021"
55

66
[dependencies]
7-
rand = "0.9.0-alpha.1"
7+
rand = "0.9.0-alpha.1"

examples/graph-gen/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use std::cmp::{max, min};
2-
use std::collections::HashSet;
2+
use std::collections::{HashMap, HashSet};
33
use rand::{Rng};
44

55
fn main() {

examples/mesh-vis/public/networks/default.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ config:
22
broadcast_routes: true # should nodes send updates to each other, since this version of the visualiser does not store routes for each node, this should be true
33
broadcast_seqno: true # should nodes broadcast their saved seqno when another node requests for it?
44
update_routes: true # should node calculate routes based on what their neighbour has sent them
5-
refresh_interfaces: true # should we scan our interfaces for changes, i.e disconnect & metric change?
65
neighbours:
76
- 1 2 2
87
- 1 3 1

examples/mesh-vis/public/networks/fragile.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ config:
22
broadcast_routes: true # should nodes send updates to each other, since this version of the visualiser does not store routes for each node, this should be true
33
broadcast_seqno: true # should nodes broadcast their saved seqno when another node requests for it?
44
update_routes: true # should node calculate routes based on what their neighbour has sent them
5-
refresh_interfaces: true # should we scan our interfaces for changes, i.e disconnect & metric change?
65
neighbours:
76
- 1 2 1
87
- 1 3 1
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
config:
2+
broadcast_routes: true # should nodes send updates to each other, since this version of the visualiser does not store routes for each node, this should be true
3+
broadcast_seqno: true # should nodes broadcast their saved seqno when another node requests for it?
4+
update_routes: true # should node calculate routes based on what their neighbour has sent them
5+
neighbours:
6+
- 1 2 1
7+
- 2 3 1
8+
- 3 4 1
9+
- 4 5 1
10+
- 5 6 1
11+
- 6 7 1
12+
- 7 8 1
13+
- 8 9 1
14+
- 1 9 1
15+
- 9 10 1 # cut this off, and you can see that there is no cycle formed

examples/mesh-vis/public/networks/options.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
{
22
"graphs": {
33
"default.yaml": "Simple Weighted Graph",
4-
"starvation.yaml": "Graph in Starvation",
5-
"unweighted.yaml": "Simple Unweghted Graph",
4+
"unweighted.yaml": "Simple Unweighted Graph",
65
"loop.yaml": "Loop Avoidance",
76
"fragile.yaml": "Fragile Network"
87
}

0 commit comments

Comments
 (0)