propagting routes

This commit is contained in:
Maxime Van Hees
2023-05-11 16:00:01 +00:00
parent 7ca67c61f1
commit fa280aebf5
5 changed files with 153 additions and 82 deletions
-44
View File
@@ -52,50 +52,6 @@ async fn main() -> Result<(), Box<dyn Error>> {
// Creating a new PeerManager instance
let _peer_manager: peer_manager::PeerManager = peer_manager::PeerManager::new(router.clone(), static_peers);
// create routing entry for this node
// for the moment we say that each node has a /24 subnet that it can route
// only IPv4 is supported for now
// {
// // omit the last octet of the node_tun address to get the prefix
// let tun_octects = node_tun.address().unwrap().octets();
// let node_prefix = Ipv4Addr::new(tun_octects[0], tun_octects[1], tun_octects[2], 0);
// // create a source key for the node
// let source_key = SourceKey {
// prefix: IpAddr::V4(node_prefix),
// plen: 24,
// router_id: router.router_id,
// };
// // default metric value for own source is 0
// let feas_dist = FeasibilityDistance(0, 0);
// // insert source into source table of router
// router.source_table.lock().unwrap().insert(source_key, feas_dist);
// // create a routing entry for the node
// let route_key = RouteKey {
// prefix: IpAddr::V4(node_prefix),
// plen: 24,
// neighbor: IpAddr::V4(node_tun.address().unwrap()),
// };
// // bit skuft: we create a dummy peer for this node itself as this is required for the route entry
// let dummy_peer = Peer::new_dummy(node_tun.address().unwrap());
// // creates a route entry for the node and also creates an update timer for the route
// let route_entry = RouteEntry::new(
// source_key.clone(),
// dummy_peer,
// 0, // metric value for own route is 0
// router.router_seqno,
// IpAddr::V4(node_tun.address().unwrap()),
// true,
// );
// router.routing_table.lock().unwrap().insert(route_key, route_entry);
// }
// Read packets from the TUN interface (originating from the kernel) and send them to the router
// Note: we will never receive control packets from the kernel, only data packets
{
+62 -8
View File
@@ -4,8 +4,8 @@ use crate::{
DataPacket,
},
peer::Peer,
routing_table::{RouteEntry, RouteKey, RoutingTable},
source_table::{SourceKey, SourceTable, FeasibilityDistance}, timers::{Timer, self},
routing_table::{RouteEntry, RouteKey, RoutingTable, self},
source_table::{SourceKey, SourceTable, FeasibilityDistance, self}, timers::{Timer, self},
};
use std::{
collections::HashMap,
@@ -59,6 +59,10 @@ impl Router {
// loops over all peers and adds routing table entries for each peer
tokio::spawn(Router::initialize_peer_route_entries(router.clone()));
// propagate routes
tokio::spawn(Router::propagate_routes(router.clone()));
router
}
@@ -70,8 +74,12 @@ impl Router {
BabelTLVType::Ack => todo!(),
BabelTLVType::Hello => Self::handle_incoming_hello(control_struct),
BabelTLVType::IHU => Self::handle_incoming_ihu(&self, control_struct),
BabelTLVType::NextHop => todo!(),
BabelTLVType::Update => todo!(),
BabelTLVType::NextHop => todo!(),
BabelTLVType::Update => {
let mut source_table = self.source_table.lock().unwrap();
let mut routing_table = self.routing_table.lock().unwrap();
Self::handle_incoming_update(self.clone(), &mut source_table, &mut routing_table, control_struct);
},
BabelTLVType::RouteReq => todo!(),
BabelTLVType::SeqnoReq => todo!(),
}
@@ -145,6 +153,32 @@ impl Router {
println!("IHU timer for peer {:?} reset", source_peer.overlay_ip);
}
fn handle_incoming_update(router: Router, source_table: &mut SourceTable, routing_table: &mut RoutingTable, update: ControlStruct) {
if source_table.is_feasible(&update) {
source_table.update(&update);
// get routing table entry for the source of the update
match update.control_packet.body.tlv {
BabelTLV::Update { plen, interval, seqno, metric, prefix, router_id } => {
let source_ip = update.src_overlay_ip;
let source_peer = router.get_peer_by_ip(source_ip).unwrap();
// get RouteEntry for the source of the update
if let Some(route_entry) = routing_table.table.get_mut(&RouteKey { prefix, plen, neighbor: source_ip }) {
route_entry.update(update);
}
},
_ => {},
}
} else {
// received update is not feasible
// unselect to route if it was selected
}
}
pub fn add_directly_connected_peer(&self, peer: Peer) {
self.peer_interfaces.lock().unwrap().push(peer);
}
@@ -185,6 +219,8 @@ impl Router {
// this is done by looking at the currently set link cost. as the cost gets initialized to 65535, we can use this to check if
// the link cost has been set to a lower value, indicating that the peer is reachable and a routing table entry exits already
pub async fn initialize_peer_route_entries(self) {
// we wait for 10 seconds before we start initializing the routing table entries
// possible optimization: only run this when necassary (e.g. when a new peer is added)
loop {
tokio::time::sleep(tokio::time::Duration::from_secs(10)).await;
for peer in self.peer_interfaces.lock().unwrap().iter_mut() {
@@ -218,7 +254,6 @@ impl Router {
seqno: 0, // we set the seqno to 0 for now
next_hop: IpAddr::V4(peer.overlay_ip),
selected: true, // set selected always to true for now as we have manually decided the topology to only have p2p links
route_expiry_timer: Timer::new_route_expiry_timer(UPDATE_INTERVAL as u64),
};
// create the routing table entry
self.routing_table.lock().unwrap().insert(route_key, route_entry);
@@ -231,11 +266,30 @@ impl Router {
// routing table updates are send periodically to all directly connected peers
// updates are used to advertise new routes or the retract existing routes (retracting when the metric is set to 0xFFFF)
// this function is run when the route_update timer expires
pub fn propagate_update(self) {
let router_table = self.routing_table.lock().unwrap();
pub async fn propagate_routes(self) {
loop {
// routes are propagated every 10 secs
tokio::time::sleep(tokio::time::Duration::from_secs(10)).await;
// loop over all directly connected peers
let router_table = self.routing_table.lock().unwrap();
let peers = self.peer_interfaces.lock().unwrap();
for (key, entry) in router_table.table.iter() {
for peer in peers.iter() {
let update = ControlPacket::new_update (
key.plen,
UPDATE_INTERVAL as u16,
entry.seqno,
entry.metric,
key.prefix,
entry.source.router_id,
);
peer.to_peer_control.send(update).unwrap();
}
}
}
}
}
+21 -9
View File
@@ -1,6 +1,6 @@
use std::{net::IpAddr, collections::HashMap};
use crate::{source_table::SourceKey, peer::Peer, timers::Timer};
use crate::{source_table::SourceKey, peer::Peer, timers::Timer, router::Router, packet::{ControlStruct, BabelTLV}};
const HELLO_INTERVAL: u16 = 4;
const IHU_INTERVAL: u16 = HELLO_INTERVAL * 3;
@@ -21,11 +21,11 @@ pub struct RouteEntry {
pub seqno: u16,
pub next_hop: IpAddr, // This is the Peer's address
pub selected: bool,
pub route_expiry_timer: Timer,
//pub route_expiry_timer: Timer,
}
impl RouteEntry {
pub fn new(source: SourceKey, neighbor: Peer, metric: u16, seqno: u16, next_hop: IpAddr, selected: bool) -> Self {
pub fn new(source: SourceKey, neighbor: Peer, metric: u16, seqno: u16, next_hop: IpAddr, selected: bool, router: Router) -> Self {
Self {
source,
neighbor,
@@ -33,14 +33,26 @@ impl RouteEntry {
seqno,
next_hop,
selected,
route_expiry_timer: Timer::new_route_expiry_timer(UPDATE_INTERVAL as u64),
}
}
pub fn update(&mut self, metric: u16, seqno: u16, next_hop: IpAddr) {
self.metric = metric;
self.seqno = seqno;
self.next_hop = next_hop;
// pub fn update(&mut self, metric: u16, seqno: u16, next_hop: IpAddr) {
// self.metric = metric;
// self.seqno = seqno;
// self.next_hop = next_hop;
// }
pub fn update(&mut self, update: ControlStruct) {
// the update is assumed to be feasible here
match update.control_packet.body.tlv {
BabelTLV::Update { plen, interval, seqno, metric, prefix, router_id } => {
self.metric = metric;
self.seqno = seqno;
},
_ => {
println!("Received update with invalid TLV");
}
}
}
pub fn retracted(&mut self) {
@@ -67,7 +79,7 @@ impl RoutingTable {
pub fn insert(&mut self, key: RouteKey, entry: RouteEntry) {
self.table.insert(key, entry);
println!("Added route to routing table: {:?}", self.table);
//println!("Added route to routing table: {:?}", self.table);
}
pub fn remove(&mut self, key: &RouteKey) {
+70 -2
View File
@@ -1,5 +1,7 @@
use std::{net::IpAddr, collections::HashMap};
use crate::packet::{ControlStruct, BabelTLV};
#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)]
pub struct SourceKey {
pub prefix: IpAddr,
@@ -7,8 +9,7 @@ pub struct SourceKey {
pub router_id: u64, // We temporarily use 100 for all router IDs
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Copy)]
pub struct FeasibilityDistance(pub u16, pub u16); // (metric, seqno)
// Store (prefix, plen, router_id) -> feasibility distance mapping
@@ -34,4 +35,71 @@ impl SourceTable {
pub fn get(&self, key: &SourceKey) -> Option<&FeasibilityDistance> {
self.table.get(key)
}
pub fn update(&mut self, update: &ControlStruct) {
match update.control_packet.body.tlv {
BabelTLV::Update { plen, interval, seqno, metric, prefix, router_id } => {
// first check if the update is feasible
if !self.is_feasible(update) {
return;
}
let key = SourceKey {
prefix: prefix,
plen: plen,
router_id: router_id
};
let new_distance = FeasibilityDistance(metric, seqno);
let old_distance = self.table.get(&key).cloned();
match old_distance {
Some(old_distance) => {
if new_distance.0 < old_distance.0 {
self.table.insert(key, FeasibilityDistance(new_distance.0, new_distance.1));
}
}
None => {
self.table.insert(key, FeasibilityDistance(new_distance.0, new_distance.1));
}
}
}
_ => {
panic!("not an update");
}
}
}
pub fn is_feasible(&self, update: &ControlStruct) -> bool {
match update.control_packet.body.tlv {
BabelTLV::Update { plen, interval, seqno, metric, prefix, router_id } => {
let key = SourceKey {
prefix: prefix,
plen: plen,
router_id: router_id
};
match self.table.get(&key) {
Some(&source_entry) => {
let metric_2= source_entry.0;
let seqno_2 = source_entry.1;
if seqno > seqno_2 || (seqno == seqno_2 && metric < metric_2) {
return true
} else {
return false
}
}
None => return true,
}
}
_ => {
panic!("not an update");
}
}
}
}
-19
View File
@@ -67,23 +67,4 @@ impl Timer {
timer
}
// add update timer
pub fn new_route_expiry_timer(update_interval: u64) -> Timer {
let timer = Timer::new(Duration::from_secs(update_interval));
{
let timer = timer.clone();
tokio::spawn(async move {
timer.run(|| {
println!("Route timer expired! Sending routes...");
// send update packet of that route to all peers
}).await;
});
}
timer
}
// add ack timer
}