From fa280aebf5eceaf814c263e4dd9f64be20af7a96 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Thu, 11 May 2023 16:00:01 +0000 Subject: [PATCH] propagting routes --- src/main.rs | 44 --------------------------- src/router.rs | 70 +++++++++++++++++++++++++++++++++++++----- src/routing_table.rs | 30 ++++++++++++------ src/source_table.rs | 72 ++++++++++++++++++++++++++++++++++++++++++-- src/timers.rs | 19 ------------ 5 files changed, 153 insertions(+), 82 deletions(-) diff --git a/src/main.rs b/src/main.rs index 0d2612e..fde6161 100644 --- a/src/main.rs +++ b/src/main.rs @@ -52,50 +52,6 @@ async fn main() -> Result<(), Box> { // 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 { diff --git a/src/router.rs b/src/router.rs index c7a4d87..5e53839 100644 --- a/src/router.rs +++ b/src/router.rs @@ -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(); + } + } + } } } diff --git a/src/routing_table.rs b/src/routing_table.rs index ed465cc..c5bd96a 100644 --- a/src/routing_table.rs +++ b/src/routing_table.rs @@ -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) { diff --git a/src/source_table.rs b/src/source_table.rs index 9232eaf..79180f9 100644 --- a/src/source_table.rs +++ b/src/source_table.rs @@ -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"); + } + } + } } \ No newline at end of file diff --git a/src/timers.rs b/src/timers.rs index 8e9ce40..a499387 100644 --- a/src/timers.rs +++ b/src/timers.rs @@ -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 }