From 2f0879ae1cab457d6ce06ca3ec32a4ca80c7a690 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Thu, 20 Apr 2023 06:46:48 +0000 Subject: [PATCH 01/89] first commit babel --- src/babel/packet.rs | 0 src/babel/router.rs | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/babel/packet.rs create mode 100644 src/babel/router.rs diff --git a/src/babel/packet.rs b/src/babel/packet.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/babel/router.rs b/src/babel/router.rs new file mode 100644 index 0000000..e69de29 From eb7e151d109679f8e26d75a7a2646b4c69e6f214 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Mon, 24 Apr 2023 09:41:55 +0000 Subject: [PATCH 02/89] 2 channels (control, data) v1 --- src/babel/packet.rs | 0 src/babel/router.rs | 0 src/codec.rs | 297 ++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 73 +++++++---- src/packet.rs | 106 +++++++++++++++ src/packet_control.rs | 197 ---------------------------- src/peer.rs | 118 ++++++++++------- src/peer_manager.rs | 41 ++++-- src/router.rs | 52 ++++++++ src/routing.rs | 0 10 files changed, 609 insertions(+), 275 deletions(-) delete mode 100644 src/babel/packet.rs delete mode 100644 src/babel/router.rs create mode 100644 src/codec.rs create mode 100644 src/packet.rs delete mode 100644 src/packet_control.rs create mode 100644 src/router.rs delete mode 100644 src/routing.rs diff --git a/src/babel/packet.rs b/src/babel/packet.rs deleted file mode 100644 index e69de29..0000000 diff --git a/src/babel/router.rs b/src/babel/router.rs deleted file mode 100644 index e69de29..0000000 diff --git a/src/codec.rs b/src/codec.rs new file mode 100644 index 0000000..ea4d942 --- /dev/null +++ b/src/codec.rs @@ -0,0 +1,297 @@ +use std::{io, net::{IpAddr, Ipv4Addr}}; +use bytes::{BufMut, BytesMut, Buf}; +use tokio_util::codec::{Encoder, Decoder}; +use crate::packet::{Packet, ControlPacket, DataPacket, PacketType, ControlPacketBody, ControlPacketType}; + +/* ********************************PAKCET*********************************** */ +pub struct PacketCodec { + packet_type: Option, + data_packet_codec: DataPacketCodec, + control_packet_codec: ControlPacketCodec, +} + +impl PacketCodec { + pub fn new() -> Self { + PacketCodec { + packet_type: None, + data_packet_codec: DataPacketCodec::new(), + control_packet_codec: ControlPacketCodec::new(), + } + } +} + +impl Decoder for PacketCodec { + type Item = Packet; + type Error = std::io::Error; + + fn decode(&mut self, src: &mut BytesMut) -> Result, Self::Error> { + + // Determine the packet_type + let packet_type = if let Some(packet_type) = self.packet_type { + packet_type + } else { + // Check we can read the packet type (1 byte) + if src.len() < 1 { + return Ok(None); + } + + let packet_type_byte = src.get_u8(); // ! This will advance the buffer 1 byte ! + let packet_type = match packet_type_byte { + 0 => PacketType::DataPacket, + 1 => PacketType::ControlPacket, + _ => return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "Invalid packet type")), + }; + + packet_type + }; + + // Decode packet based on determined packet_type + match packet_type { + PacketType::DataPacket => { + match self.data_packet_codec.decode(src) { + Ok(Some(p)) => { + self.packet_type = None; // Reset state + Ok(Some(Packet::DataPacket(p))) + }, + Ok(None) => Ok(None), + Err(e) => Err(e), + } + } + PacketType::ControlPacket => { + match self.control_packet_codec.decode(src) { + Ok(Some(p)) => { + self.packet_type = None; // Reset state + Ok(Some(Packet::ControlPacket(p))) + }, + Ok(None) => Ok(None), + Err(e) => Err(e), + } + } + } + } +} + +impl Encoder for PacketCodec { + type Error = std::io::Error; + + fn encode(&mut self, item: Packet, dst: &mut BytesMut) -> Result<(), Self::Error> { + match item { + Packet::DataPacket(datapacket) => { + dst.put_u8(0); + self.data_packet_codec.encode(datapacket, dst) + } + Packet::ControlPacket(controlpacket) => { + dst.put_u8(1); + self.control_packet_codec.encode(controlpacket, dst) + } + } + } +} + +/* ******************************DATA PACKET********************************* */ +pub struct DataPacketCodec { + len: Option, + dest_ip: Option, +} + +impl DataPacketCodec { + pub fn new() -> Self { + DataPacketCodec { + len: None, + dest_ip: None, + } + } +} + +impl Decoder for DataPacketCodec { + type Item = DataPacket; + type Error = std::io::Error; + + fn decode(&mut self, src: &mut BytesMut) -> Result, Self::Error> { + + // Determine the length of the data + let data_len = if let Some(data_len) = self.len { + data_len + } else { + // Check we have enough data to decode + if src.len() < 2 { + return Ok(None); + } + + let data_len = src.get_u16(); + self.len = Some(data_len); + + data_len + } as usize; + + // Determine the destination IP + let dest_ip = if let Some(dest_ip) = self.dest_ip { + dest_ip + } else { + if src.len() < 4 { + return Ok(None); + } + + // Decode octets + let mut ip_bytes = [0u8; 4]; + ip_bytes.copy_from_slice(&src[..4]); + let dest_ip = Ipv4Addr::from(ip_bytes); + src.advance(4); + + self.dest_ip = Some(dest_ip); + dest_ip + }; + + // Check we have enough data to decode + if src.len() < data_len { + return Ok(None); + } + + // Decode octets + let mut data = vec![0u8; data_len]; + data.copy_from_slice(&src[..data_len]); + src.advance(data_len); + + // Reset state + self.len = None; + self.dest_ip = None; + + Ok(Some(DataPacket { + raw_data: data, + dest_ip, + })) + } +} + +impl Encoder for DataPacketCodec { + type Error = std::io::Error; + + fn encode(&mut self, item: DataPacket, dst: &mut BytesMut) -> Result<(), Self::Error> { + dst.reserve(item.raw_data.len() + 6); + // Write the length of the data + dst.put_u16(item.raw_data.len() as u16); + // Write the destination IP + dst.put_slice(&item.dest_ip.octets()); + // Write the data + dst.extend_from_slice(&item.raw_data); + + Ok(()) + } +} + +/* ****************************CONTROL PACKET******************************** */ +pub struct ControlPacketCodec {} + +impl ControlPacketCodec { + pub fn new() -> Self { + ControlPacketCodec {} + } +} + +// TODO FUTURE-WISE --> HANDLE BUFFER READS THAT MIGHT NOT HAVE ARRIVED YET +impl Decoder for ControlPacketCodec { + type Item = ControlPacket; + type Error = std::io::Error; + + fn decode(&mut self, buf: &mut BytesMut) -> Result, Self::Error> { + if buf.is_empty() { + return Ok(None); + } + + let message_type = match ControlPacketType::from_u8(buf.get_u8()) { + Some(t) => t, + None => return Err(io::Error::new(io::ErrorKind::InvalidData, "Invalid message type")), + }; + + if message_type == ControlPacketType::Pad1 { + return Ok(Some(ControlPacket { + message_type, + body_length: 0, + body: Some(ControlPacketBody::Pad1), + })); + } + + let body_length = buf.get_u8(); + let body = match message_type { + ControlPacketType::PadN => { + if buf.remaining() < usize::from(body_length) { + return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "Incomplete message")); + } + buf.advance(usize::from(body_length)); + Some(ControlPacketBody::PadN(body_length)) + } + ControlPacketType::Hello => { + if buf.remaining() < 6 { + return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "Incomplete message")); + } + let flags = buf.get_u16(); + let seqno = buf.get_u16(); + let interval = buf.get_u16(); + Some(ControlPacketBody::Hello { flags, seqno, interval }) + } + ControlPacketType::IHU => { + if buf.remaining() < 8 { + return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "Incomplete message")); + } + let address_encoding = buf.get_u8(); + let reserved = buf.get_u8(); + let rxcost = buf.get_u16(); + let interval = buf.get_u16(); + let address = IpAddr::V4(Ipv4Addr::new(buf.get_u8(), buf.get_u8(), buf.get_u8(), buf.get_u8())); + Some(ControlPacketBody::IHU { address_encoding, reserved, rxcost, interval, address }) + } + // Add decoding logic for other message types. + _ => None, + }; + + Ok(Some(ControlPacket { + message_type, + body_length, + body, + })) + } +} + +impl Encoder for ControlPacketCodec { + type Error = io::Error; + + fn encode(&mut self, message: ControlPacket, buf: &mut BytesMut) -> Result<(), Self::Error> { + buf.put_u8(message.message_type as u8); + buf.put_u8(message.body_length); + + if let Some(body) = message.body { + match body { + ControlPacketBody::Pad1 => {} + ControlPacketBody::PadN(padding_length) => { + buf.put_slice(&vec![0; usize::from(padding_length)]); + } + ControlPacketBody::Hello { flags, seqno, interval } => { + buf.put_u16(flags); + buf.put_u16(seqno); + buf.put_u16(interval); + } + ControlPacketBody::IHU { address_encoding, reserved, rxcost, interval, address } => { + buf.put_u8(address_encoding); + buf.put_u8(reserved); + buf.put_u16(rxcost); + buf.put_u16(interval); + match address { + IpAddr::V4(ipv4) => { + buf.put_u8(ipv4.octets()[0]); + buf.put_u8(ipv4.octets()[1]); + buf.put_u8(ipv4.octets()[2]); + buf.put_u8(ipv4.octets()[3]); + } + IpAddr::V6(_ipv6) => { + println!("IPv6 not supported yet"); + } + } + } + // Add encoding logic for other message types. + _ => {} + } + } + + Ok(()) + } +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 70dfc3e..21a0ada 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,21 +1,19 @@ -use std::{error::Error, net::Ipv4Addr}; - +use std::{error::Error, net::Ipv4Addr, sync::Arc}; use bytes::BytesMut; use clap::Parser; -use etherparse::{InternetSlice, IpHeader, PacketHeaders, SlicedPacket}; -use packet_control::{DataPacket, Packet, PacketCodec}; -use tokio::{io::AsyncReadExt, net::TcpListener, sync::mpsc}; +use etherparse::{IpHeader, PacketHeaders}; +use packet::{DataPacket, ControlPacket}; +use tokio::{io::AsyncReadExt, io::AsyncWriteExt, net::TcpListener, sync::mpsc}; mod node_setup; -mod packet_control; +mod packet; +mod codec; mod peer; mod peer_manager; -mod routing; +mod router; use peer::Peer; use peer_manager::PeerManager; -use tokio::io::AsyncWriteExt; -use tokio_util::codec::Encoder; const LINK_MTU: usize = 1500; @@ -39,10 +37,33 @@ async fn main() -> Result<(), Box> { panic!("Error setting up node: {}", e); } }; + + // We will split the communication of DataPackets and ControlPacket into two different channels + // --> this is because we will handle them differently + + // CHANNEL FOR CONTROL PACKETS + let (to_routing_control, mut from_node_control) = mpsc::unbounded_channel::(); + + /* BABEL ADDITIONS */ + let router = Arc::new(router::Router::new()); + + { + let router_c = router.clone(); + tokio::spawn(async move { + loop { + tokio::time::sleep(std::time::Duration::from_secs(4)).await; // beter use Timer + router_c.send_hello(); + } + }); + } + + + + // CHANNELS USED FOR COMMUNICATION OF DATAPACKETS // Create an unbounded channel for this node - let (to_tun, mut from_routing) = mpsc::unbounded_channel::(); - let (to_routing, mut from_node) = mpsc::unbounded_channel::(); + let (to_tun, mut from_routing_data) = mpsc::unbounded_channel::(); + let (to_routing_data, mut from_node_data) = mpsc::unbounded_channel::(); // Create the PeerManager: an interface to all peers this node is connected to // Additional static peers are obtained through the nodeconfig.toml file @@ -50,22 +71,27 @@ async fn main() -> Result<(), Box> { // Create static peers from the nodeconfig.toml file let peer_man_clone = peer_manager.clone(); - let to_routing_clone = to_routing.clone(); + let to_routing_data_clone = to_routing_data.clone(); + let to_routing_control_clone= to_routing_control.clone(); + let router_clone = router.clone(); tokio::spawn(async move { peer_man_clone - .get_peers_from_config(to_routing_clone, cli.tun_addr) + .get_peers_from_config(to_routing_data_clone, to_routing_control_clone, cli.tun_addr, router_clone) .await; // --> here we create peer by TcpStream connect }); let peer_man_clone = peer_manager.clone(); - let to_routing_clone = to_routing.clone(); + let to_routing_data_clone = to_routing_data.clone(); + let to_routing_control_clone = to_routing_control.clone(); + let router_clone = router.clone(); // listen for inbound request --> "to created the reverse peer object" --> here we reverse create peer be listener.accept'ing tokio::spawn(async move { match TcpListener::bind("[::]:9651").await { Ok(listener) => { // loop to accept the inbound requests loop { - let to_routing_clone_clone = to_routing_clone.clone(); + let to_routing_data_clone_clone = to_routing_data_clone.clone(); + let to_routing_control_clone_clone = to_routing_control_clone.clone(); match listener.accept().await { Ok((mut stream, _)) => { // TEMPORARY: as we do not work with Babel yet, we will send to overlay ip (= addr of TUN) manually @@ -90,13 +116,16 @@ async fn main() -> Result<(), Box> { let peer_stream_ip = stream.peer_addr().unwrap().ip(); match Peer::new( peer_stream_ip, - to_routing_clone_clone, + to_routing_data_clone_clone, + to_routing_control_clone_clone, stream, received_overlay_ip, ) { Ok(new_peer) => { //println!("adding new peer to known_peers: {:?}", new_peer); - peer_man_clone.known_peers.lock().unwrap().push(new_peer); + //peer_man_clone.known_peers.lock().unwrap().push(new_peer); + // add to router directly_connected_peers + router_clone.directly_connected_peers.lock().unwrap().push(new_peer); } Err(e) => { eprintln!("Error creating 'reverse' peer: {}", e); @@ -120,8 +149,8 @@ async fn main() -> Result<(), Box> { let node_tun_clone = node_tun.clone(); tokio::spawn(async move { loop { - while let Some(packet) = from_routing.recv().await { - let data_packet = if let Packet::DataPacket(p) = packet { + while let Some(packet) = from_routing_data.recv().await { + let data_packet = if let p = packet { println!("LENTHEEE: {}", p.raw_data.len()); p } else { @@ -141,7 +170,7 @@ async fn main() -> Result<(), Box> { // Loop to read from node's TUN interface and send it to to_routing sender halve let node_tun_clone = node_tun.clone(); - let to_routing_clone = to_routing.clone(); + let to_routing_clone = to_routing_data.clone(); tokio::spawn(async move { loop { let mut buf = BytesMut::zeroed(LINK_MTU); @@ -166,7 +195,7 @@ async fn main() -> Result<(), Box> { println!("LEN: {}", data_packet.raw_data.len()); - match to_routing_clone.send(Packet::DataPacket(data_packet)) { + match to_routing_clone.send(data_packet) { Ok(_) => { println!("packet sent to to_routing"); } @@ -201,7 +230,7 @@ async fn main() -> Result<(), Box> { loop { let node_tun_inner_clone = node_tun_clone.clone(); let to_tun_sender_inner_clone = to_tun_sender_clone.clone(); - while let Some(packet) = from_node.recv().await { + while let Some(packet) = from_node_data.recv().await { //println!("Read message from from_node, sending it to route_packet function"); peer_man_clone.route_packet( packet, diff --git a/src/packet.rs b/src/packet.rs new file mode 100644 index 0000000..bf1bb92 --- /dev/null +++ b/src/packet.rs @@ -0,0 +1,106 @@ +use std::net::{IpAddr, Ipv4Addr}; + +/* ********************************PAKCET*********************************** */ +#[derive(Debug, Clone)] +pub enum Packet { + DataPacket(DataPacket), + ControlPacket(ControlPacket), +} + +#[derive(Debug, Clone, Copy)] +#[repr(u8)] +pub enum PacketType { + DataPacket = 0, + ControlPacket = 1, +} + +/* ******************************DATA PACKET********************************* */ +#[derive(Debug, Clone)] +pub struct DataPacket { + pub raw_data: Vec, + pub dest_ip: Ipv4Addr, +} + +impl DataPacket { + pub fn get_dest_ip(&self) -> Ipv4Addr { + self.dest_ip + } +} + +/* ****************************CONTROL PACKET******************************** */ +#[derive(Debug, PartialEq, Clone)] +pub struct ControlPacket { + pub message_type: ControlPacketType, + pub body_length: u8, + pub body: Option, +} + +#[derive(Debug, PartialEq, Clone)] +pub enum ControlPacketType { + Pad1 = 0, + PadN = 1, + AckReq = 2, + Ack = 3, + Hello = 4, + IHU = 5, + RouterID = 6, + NextHop = 7, + Update = 8, + RouteReq = 9, + SeqnoReq = 10, +} + +impl ControlPacketType { + pub fn from_u8(value: u8) -> Option { + match value { + 0 => Some(Self::Pad1), + 1 => Some(Self::PadN), + 2 => Some(Self::AckReq), + 3 => Some(Self::Ack), + 4 => Some(Self::Hello), + 5 => Some(Self::IHU), + 6 => Some(Self::RouterID), + 7 => Some(Self::NextHop), + 8 => Some(Self::Update), + 9 => Some(Self::RouteReq), + 10 => Some(Self::SeqnoReq), + _ => None, + } + } +} + +#[derive(Debug, Clone, PartialEq)] +pub enum ControlPacketBody { + Pad1, + PadN(u8), + AckReq { nonce: u16, interval: u16 }, + Ack { nonce: u16 }, + Hello { + flags: u16, + seqno: u16, + interval: u16, + }, + IHU { + address_encoding: u8, + reserved: u8, + rxcost: u16, + interval: u16, + address: IpAddr, + }, + RouterID { router_id: u16 }, + NextHop { address: IpAddr }, + Update { + address: IpAddr, + prefix: u8, + seqno: u16, + metric: u16, + interval: u16, + }, + RouteReq { prefix: IpAddr, plen: u8 }, + SeqnoReq { + prefix: IpAddr, + plen: u8, + seqno: u16, + router_id: u16, + }, +} \ No newline at end of file diff --git a/src/packet_control.rs b/src/packet_control.rs deleted file mode 100644 index e308b72..0000000 --- a/src/packet_control.rs +++ /dev/null @@ -1,197 +0,0 @@ -use std::net::Ipv4Addr; - -use etherparse::{PacketHeaders, IpHeader}; -use tokio_util::codec::{Decoder, Encoder}; -use bytes::{BytesMut, Buf, BufMut}; - -#[derive(Clone)] -pub enum Packet { - DataPacket(DataPacket), // packet coming from kernel - //ControlPacket(ControlPacket), // babel related packets -} - -// create function to extract destip from Packet type -impl Packet { - pub fn get_dest_ip(&self) -> std::net::Ipv4Addr { - match self { - Packet::DataPacket(packet) => packet.dest_ip, - //Packet::ControlPacket(packet) => packet.dest_ip, - } - } -} - -#[derive(Clone)] -pub struct DataPacket { - pub raw_data: Vec, - pub dest_ip: std::net::Ipv4Addr, -} - -#[derive(Debug, Clone, Copy)] -#[repr(u8)] -pub enum PacketType { - DataPacket = 0, - _ControlPacket = 1, -} - -pub struct PacketCodec { - packet_type: Option, - data_packet_codec: DataPacketCodec, - //control_packet_codec: ControlPacketCodec, -} - -impl PacketCodec { - pub fn new() -> Self { - PacketCodec {packet_type: None, data_packet_codec: DataPacketCodec::new()} - } -} - -pub struct DataPacketCodec { - len: Option, - dest_ip: Option, -} - -impl DataPacketCodec{ - pub fn new() -> Self { - DataPacketCodec { len: None , dest_ip: None } - } -} - - -impl Decoder for DataPacketCodec { - type Item = DataPacket; - type Error = std::io::Error; - - fn decode(&mut self, src: &mut BytesMut) -> Result, Self::Error> { - let data_len = if let Some(data_len) = self.len { - data_len - } else { - - // check we have enough data to decode - if src.len() < 2 { - return Ok(None); - } - - let data_len = src.get_u16(); - self.len = Some(data_len); - - data_len - } as usize; - - let dest_ip = if let Some(dest_ip) = self.dest_ip { - dest_ip - } else { - if src.len() < 4 { - return Ok(None); - } - - // decode octets - let mut ip_bytes = [0u8; 4]; - ip_bytes.copy_from_slice(&src[..4]); - let dest_ip = Ipv4Addr::from(ip_bytes); - src.advance(4); - - self.dest_ip = Some(dest_ip); - dest_ip - }; - - if src.len() < data_len { - - src.reserve(data_len - src.len()); - - return Ok(None); - } - - // we have enough data - let data = src[..data_len].to_vec(); - src.advance(data_len); - - // Reset state - self.len = None; - self.dest_ip = None; - - Ok(Some(DataPacket { raw_data: data, dest_ip })) - } -} - -impl Encoder for DataPacketCodec { - type Error = std::io::Error; - - fn encode(&mut self, item: DataPacket, dst: &mut BytesMut) -> Result<(), Self::Error> { - // implies that length is never more than u16 - - dst.reserve(item.raw_data.len() + 6); - dst.put_u16(item.raw_data.len() as u16); - // dest ip wegschrijven - dst.put_slice(&item.dest_ip.octets()); - - dst.extend_from_slice(&item.raw_data); - - - Ok(()) - } -} - -impl Decoder for PacketCodec { - type Item = Packet; - type Error = std::io::Error; - - fn decode(&mut self, src: &mut BytesMut) -> Result, Self::Error> { - let packet_type = if let Some(packet_type) = self.packet_type { - packet_type - } else { - - // Check if we have enough bytes to read one byte (which shows to packet type) - if src.len() < 1 { - return Ok(None); - } - - let raw_packet_type = src.get_u8(); // Beware: this advances src by 1 u8 - let packet_type = match raw_packet_type { - 0 => { PacketType::DataPacket } - // 1 => { PacketType::ControlPacket } - _ => return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "Unrecognized packet type")) - }; - - packet_type - }; - - match packet_type { - PacketType::DataPacket => { - match self.data_packet_codec.decode(src) { - Ok(Some(p)) => { - self.packet_type = None; // necessary otherwise we would have the situation where assume the packet_type already exists and just read further - Ok(Some(Packet::DataPacket(p))) - }, - Ok(None) => { - Ok(None) - }, - Err(e) => { - Err(e) - } - } - } - PacketType::_ControlPacket => { - unimplemented!() - } - } - } -} - -impl Encoder for PacketCodec { - type Error = std::io::Error; - - fn encode(&mut self, item: Packet, dst: &mut BytesMut) -> Result<(), Self::Error> { - match item { - Packet::DataPacket(datapacket) => { - dst.put_u8(0); - self.data_packet_codec.encode(datapacket, dst) - } - // PacketType::ControlPacket(controlpacket) => { - // dst.put_u8(1); - // self.control_packet.codec.encode(controlpacket); - // } - } - } -} - - diff --git a/src/peer.rs b/src/peer.rs index 87d9c36..6d83f26 100644 --- a/src/peer.rs +++ b/src/peer.rs @@ -1,73 +1,101 @@ use futures::{SinkExt, StreamExt}; -use std::{error::Error, net::{IpAddr, Ipv4Addr}}; -use tokio::{ - net::TcpStream, - select, - sync::{mpsc}, +use std::{ + error::Error, + net::{IpAddr, Ipv4Addr}, }; -use tokio_util::codec::{Framed, Decoder}; +use tokio::{net::TcpStream, select, sync::mpsc}; +use tokio_util::codec::Framed; -use crate::packet_control::{DataPacket, Packet, PacketCodec}; +use crate::packet::{ControlPacket, DataPacket}; +use crate::{codec::PacketCodec, packet::Packet}; + +// IS A NEIGHBOR IN THE IDEA OF BABEL #[derive(Debug)] pub struct Peer { - pub stream_ip: IpAddr, - pub to_peer: mpsc::UnboundedSender, - pub overlay_ip: Ipv4Addr, + pub stream_ip: IpAddr, + pub to_peer_data: mpsc::UnboundedSender, + pub to_peer_control: mpsc::UnboundedSender, // RFC: the local node's interface over which this neighbour is reachable + pub overlay_ip: Ipv4Addr, // RFC: address of the neigbouring interface + + // additional fields according to babel RFC + // pub txcost: u16, } impl Peer { - pub fn new(stream_ip: IpAddr, to_routing: mpsc::UnboundedSender, stream: TcpStream, overlay_ip: Ipv4Addr) -> Result> { - + pub fn new( + stream_ip: IpAddr, + to_routing_data: mpsc::UnboundedSender, + to_routing_control: mpsc::UnboundedSender, + stream: TcpStream, + overlay_ip: Ipv4Addr, + ) -> Result> { // Create a Framed for each peer let mut framed = Framed::new(stream, PacketCodec::new()); // Create an unbounded channel for each peer - let (to_peer, mut from_routing) = mpsc::unbounded_channel::(); + let (to_peer_data, mut from_routing_data) = mpsc::unbounded_channel::(); + // Create control channel + let (to_peer_control, mut from_routing_control) = + mpsc::unbounded_channel::(); tokio::spawn(async move { loop { select! { - // received from peer - frame = framed.next() => { - match frame { - Some(Ok(packet)) => { - // Send to TUN interface - // toekomst: nog een een tussenstap - println!("3: I'm the peer instance that got the message from the TCP stream"); - match packet { - Packet::DataPacket(packet) => { - if let Err(error) = to_routing.send(Packet::DataPacket(packet)){ - eprintln!("Error sending to TUN: {}", error); - } + // received from peer + frame = framed.next() => { + match frame { + Some(Ok(packet)) => { + match packet { + Packet::DataPacket(packet) => { + if let Err(error) = to_routing_data.send(packet){ + eprintln!("Error sending to TUN: {}", error); } - // Packet::ControlPacket(packet) => { - // TODO: control packet - // } - } - }, - Some(Err(e)) => { - eprintln!("Error from framed: {}", e); - }, - None => { - println!("Stream is closed."); - return + } + Packet::ControlPacket(packet) => { + if let Err(error) = to_routing_control.send(packet){ + eprintln!("Error sending to TUN: {}", error); + } + + } } } - } - // receive from from_routing - Some(packet) = from_routing.recv() => { - println!("Receiver from from_routing, sending it over the TCP stream"); - // Send it over the TCP stream - if let Err(e) = framed.send(packet).await { - eprintln!("Error writing to stream: {}", e); + Some(Err(e)) => { + eprintln!("Error from framed: {}", e); + }, + None => { + println!("Stream is closed."); + return + } } } + + // received from routing (both data and control channels) + + Some(packet) = from_routing_data.recv() => { + println!("Received DATA from routing, sending it over the TCP stream"); + // Send it over the TCP stream + if let Err(e) = framed.send(Packet::DataPacket(packet)).await { + eprintln!("Error writing to stream: {}", e); + } + } + + Some(packet) = from_routing_control.recv() => { + println!("Received CONTROL from routing, sending it over the TCP stream"); + // Send it over the TCP stream + if let Err(e) = framed.send(Packet::ControlPacket(packet)).await { + eprintln!("Error writing to stream: {}", e); + } + } } } }); - - Ok(Self { stream_ip, to_peer, overlay_ip }) + Ok(Self { + stream_ip, + to_peer_data, + to_peer_control, + overlay_ip, + }) } } diff --git a/src/peer_manager.rs b/src/peer_manager.rs index ac8e2db..1f1eea9 100644 --- a/src/peer_manager.rs +++ b/src/peer_manager.rs @@ -1,10 +1,12 @@ -use crate::{packet_control::Packet, peer::Peer}; +use crate::packet::{DataPacket, ControlPacket}; +use crate::{packet::Packet, peer::Peer}; use serde::Deserialize; use std::net::{Ipv4Addr, SocketAddr}; use std::sync::{Arc, Mutex}; use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tokio::{net::TcpStream, sync::mpsc::UnboundedSender}; use tokio_tun::Tun; +use crate::router::Router; pub const NODE_CONFIG_FILE_PATH: &str = "nodeconfig.toml"; @@ -15,22 +17,31 @@ struct PeersConfig { #[derive(Debug, Clone)] pub struct PeerManager { - pub known_peers: Arc>>, + pub known_peers: Arc>>, // --> moet eigenlijk in router + pub router: Arc, } +// PEERMANAGER HEEFT EGIENLIJK ENKEL DE TAAK OM TE CONNECTEN MET PEERS EN ZE VOLLEDIG AAN TE MAKEN +// --> ALS EEN PEER VOLLEDIG IS AANGEMAAKT MOET HIJ NAAR DE ROUTER WORDEN GESTUURD +// --> WANT DE ROUTER MOET UITEINDELIJK EEEN LIJST VAN CONNECTED_PEERS BIJHOUDEN +// --> PEERMANAGER WEL OM DE ZOVEEL TIJD EEN CHECK DOEN ALS DE PEERS NOG LEVEN (MAAR: GEBEURT MSS MET DE HELLO-IHU?) + impl PeerManager { pub fn new() -> Self { let mut known_peers: Vec = Vec::new(); Self { known_peers: Arc::new(Mutex::new(known_peers)), + router: Arc::new(Router::new()), } } pub async fn get_peers_from_config( &self, - to_routing: UnboundedSender, + to_routing_data: UnboundedSender, + to_routing_control: UnboundedSender, tun_addr_own_node: Ipv4Addr, + router: Arc, ) { // Read from the nodeconfig.toml file match std::fs::read_to_string(NODE_CONFIG_FILE_PATH) { @@ -59,14 +70,18 @@ impl PeerManager { let peer_stream_ip = peer_addr.ip(); match Peer::new( peer_stream_ip, - to_routing.clone(), + to_routing_data.clone(), + to_routing_control.clone(), peer_stream, received_overlay_ip, ) { Ok(new_peer) => { // Add peer to known_peers - let mut known_peers = self.known_peers.lock().unwrap(); - known_peers.push(new_peer); + //let mut known_peers = self.known_peers.lock().unwrap(); + //known_peers.push(new_peer); + // new + // add new_peer to router directly_connected_peers + router.directly_connected_peers.lock().unwrap().push(new_peer); } Err(e) => { eprintln!("Error creating peer: {}", e); @@ -89,29 +104,33 @@ impl PeerManager { } } + // should eventually be moved to router.rs + // SHOULD ONLY BE CALLED ON DATAPACKETS!! + // --> because control packets are only sent between directly connected nodes + // --> so they are not routed. If you receive a control packet, you know it's for you pub fn route_packet( &self, - packet: Packet, + data_packet: DataPacket, own_node_tun: Arc, - to_tun_sender: UnboundedSender, + to_tun_sender: UnboundedSender, ) { // We first extract the IP from the Packet and look if the destination IP is our own overlay IP // So if --> forward packet to our own TUN interface // If not --> look in known_peers which peer's overlay_ip matches with destination IP - let packet_dest_ip = packet.get_dest_ip(); + let packet_dest_ip = data_packet.get_dest_ip(); // Packet towards own node's TUN interface if packet_dest_ip == own_node_tun.address().unwrap() { println!("Packet got address of our own TUN --> so sending it to my own TUN"); - to_tun_sender.send(packet); + to_tun_sender.send(data_packet); // Packet towards other peer } else { let mut known_peers = self.known_peers.lock().unwrap(); for peer in known_peers.iter_mut() { if peer.overlay_ip == packet_dest_ip { println!("Routing packet towards: {}", peer.overlay_ip.to_string()); - peer.to_peer.send(packet); + peer.to_peer_data.send(data_packet); break; } else { println!("No peer match found"); diff --git a/src/router.rs b/src/router.rs new file mode 100644 index 0000000..303f41a --- /dev/null +++ b/src/router.rs @@ -0,0 +1,52 @@ +use std::{net::IpAddr, sync::{Mutex, Arc}}; + +use crate::{peer::Peer, packet::{ControlPacket, ControlPacketType}}; + +#[derive(Debug)] +pub struct Router { + pub directly_connected_peers: Arc>>, +} + +impl Router { + pub fn new() -> Self { + Router { + directly_connected_peers: Arc::new(Mutex::new(Vec::new())), + } + } + + pub fn add_directly_connected_peer(&mut self, peer: Peer) { + self.directly_connected_peers.lock().unwrap().push(peer); + } + + pub fn send_hello(&self) { + let hello_message = ControlPacket { + message_type: ControlPacketType::Hello, + body_length: 0, + body: None, + }; + // send the hello_message to all the directly connected peers + for peer in self.directly_connected_peers.lock().unwrap().iter() { + peer.to_peer_control.send(hello_message.clone()); + } + } +} + +struct Route { + prefix: u8, + plen: u8, + neighbour: Peer, +} + +struct RouteEntry { + source: (u8, u8, u16), // source (prefix, plen, router-id) for which this route is advertised + neighbour: Peer, // neighbour that advertised this route + metric: u16, // metric of this route as advertised by the neighbour + seqno: u16, // sequence number of this route as advertised by the neighbour + next_hop: IpAddr, // next-hop for this route + selected: bool, // whether this route is selected + + // each route table entry needs a route expiry timer + // each route has two distinct (seqno, metric) pairs associated with it: + // 1. (seqno, metric): describes the route's distance + // 2. (seqno, metric): describes the feasibility distance (should be stored in source table and shared between all routes with the same source) +} \ No newline at end of file diff --git a/src/routing.rs b/src/routing.rs deleted file mode 100644 index e69de29..0000000 From fda016c78d9c980f8d0c97225185fbe5f5eb2f26 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Mon, 24 Apr 2023 11:31:23 +0000 Subject: [PATCH 03/89] 2 channels (control, data) v2 --- src/main.rs | 28 +++++++++++++++++++++++++--- src/peer_manager.rs | 3 ++- src/router.rs | 13 ++++++++++--- 3 files changed, 37 insertions(+), 7 deletions(-) diff --git a/src/main.rs b/src/main.rs index 21a0ada..52a0dd4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,7 +2,7 @@ use std::{error::Error, net::Ipv4Addr, sync::Arc}; use bytes::BytesMut; use clap::Parser; use etherparse::{IpHeader, PacketHeaders}; -use packet::{DataPacket, ControlPacket}; +use packet::{DataPacket, ControlPacket, ControlPacketType}; use tokio::{io::AsyncReadExt, io::AsyncWriteExt, net::TcpListener, sync::mpsc}; mod node_setup; @@ -53,9 +53,28 @@ async fn main() -> Result<(), Box> { tokio::spawn(async move { loop { tokio::time::sleep(std::time::Duration::from_secs(4)).await; // beter use Timer + println!("sending hello"); router_c.send_hello(); } }); + + // loop to read from_node_control + tokio::spawn(async move { + loop { + while let Some(packet) = from_node_control.recv().await { + match packet.message_type { + // different type of control packets + ControlPacketType::Hello => { + println!("Received Hello"); + println!("Should send IHU back"); + } + _ => { + println!("Received unknown control packet"); + } + } + } + } + }); } @@ -124,8 +143,8 @@ async fn main() -> Result<(), Box> { Ok(new_peer) => { //println!("adding new peer to known_peers: {:?}", new_peer); //peer_man_clone.known_peers.lock().unwrap().push(new_peer); - // add to router directly_connected_peers - router_clone.directly_connected_peers.lock().unwrap().push(new_peer); + + router_clone.add_directly_connected_peer(new_peer); } Err(e) => { eprintln!("Error creating 'reverse' peer: {}", e); @@ -226,8 +245,10 @@ async fn main() -> Result<(), Box> { let peer_man_clone = peer_manager.clone(); let node_tun_clone = node_tun.clone(); let to_tun_sender_clone = to_tun.clone(); + let router_clone = router.clone(); tokio::spawn(async move { loop { + let router_inner_clone = router_clone.clone(); let node_tun_inner_clone = node_tun_clone.clone(); let to_tun_sender_inner_clone = to_tun_sender_clone.clone(); while let Some(packet) = from_node_data.recv().await { @@ -236,6 +257,7 @@ async fn main() -> Result<(), Box> { packet, node_tun_inner_clone.clone(), to_tun_sender_inner_clone.clone(), + router_inner_clone.clone(), ); } } diff --git a/src/peer_manager.rs b/src/peer_manager.rs index 1f1eea9..f1070af 100644 --- a/src/peer_manager.rs +++ b/src/peer_manager.rs @@ -81,7 +81,7 @@ impl PeerManager { //known_peers.push(new_peer); // new // add new_peer to router directly_connected_peers - router.directly_connected_peers.lock().unwrap().push(new_peer); + router.add_directly_connected_peer(new_peer); } Err(e) => { eprintln!("Error creating peer: {}", e); @@ -113,6 +113,7 @@ impl PeerManager { data_packet: DataPacket, own_node_tun: Arc, to_tun_sender: UnboundedSender, + router: Arc, ) { // We first extract the IP from the Packet and look if the destination IP is our own overlay IP // So if --> forward packet to our own TUN interface diff --git a/src/router.rs b/src/router.rs index 303f41a..d2c0d35 100644 --- a/src/router.rs +++ b/src/router.rs @@ -2,9 +2,9 @@ use std::{net::IpAddr, sync::{Mutex, Arc}}; use crate::{peer::Peer, packet::{ControlPacket, ControlPacketType}}; -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Router { - pub directly_connected_peers: Arc>>, + directly_connected_peers: Arc>>, } impl Router { @@ -14,8 +14,14 @@ impl Router { } } - pub fn add_directly_connected_peer(&mut self, peer: Peer) { + // NOTE: we gebruiken gewoon &self en niet &mut self want de mutex van directly_connected_peers fixt het feit dat er sws maar 1 iemand aankan + pub fn add_directly_connected_peer(&self, peer: Peer) { self.directly_connected_peers.lock().unwrap().push(peer); + // for debug: print connected peers once one get added + println!("CURRENT DIRECTLY CONNECTED PEERS:"); + for peer in self.directly_connected_peers.lock().unwrap().iter() { + println!("Peer: {:?}", peer); + } } pub fn send_hello(&self) { @@ -26,6 +32,7 @@ impl Router { }; // send the hello_message to all the directly connected peers for peer in self.directly_connected_peers.lock().unwrap().iter() { + println!("CONTROL: Sending hello message to peer: {:?}", peer); peer.to_peer_control.send(hello_message.clone()); } } From cd5c93d77d2fbf735a3d0cd7b5589319a03cddf0 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Mon, 24 Apr 2023 11:58:40 +0000 Subject: [PATCH 04/89] 2 channels (control, data) v4 --- src/main.rs | 6 +++--- src/peer.rs | 4 ++-- src/router.rs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main.rs b/src/main.rs index 52a0dd4..9897850 100644 --- a/src/main.rs +++ b/src/main.rs @@ -49,12 +49,12 @@ async fn main() -> Result<(), Box> { let router = Arc::new(router::Router::new()); { - let router_c = router.clone(); + let router = router.clone(); tokio::spawn(async move { loop { - tokio::time::sleep(std::time::Duration::from_secs(4)).await; // beter use Timer + tokio::time::sleep(std::time::Duration::from_secs(10)).await; // beter use Timer println!("sending hello"); - router_c.send_hello(); + router.send_hello(); } }); diff --git a/src/peer.rs b/src/peer.rs index 6d83f26..14bd5dd 100644 --- a/src/peer.rs +++ b/src/peer.rs @@ -49,13 +49,13 @@ impl Peer { match packet { Packet::DataPacket(packet) => { if let Err(error) = to_routing_data.send(packet){ - eprintln!("Error sending to TUN: {}", error); + eprintln!("Error sending to to_routing_data: {}", error); } } Packet::ControlPacket(packet) => { if let Err(error) = to_routing_control.send(packet){ - eprintln!("Error sending to TUN: {}", error); + eprintln!("Error sending to to_routing_control: {}", error); } } diff --git a/src/router.rs b/src/router.rs index d2c0d35..3533dfa 100644 --- a/src/router.rs +++ b/src/router.rs @@ -32,7 +32,7 @@ impl Router { }; // send the hello_message to all the directly connected peers for peer in self.directly_connected_peers.lock().unwrap().iter() { - println!("CONTROL: Sending hello message to peer: {:?}", peer); + println!("CONTROL: Sending hello message to peer: {}", peer.overlay_ip.to_string()); peer.to_peer_control.send(hello_message.clone()); } } From 7b18a145ed355c205c9902c41da67dd16c004cbc Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Mon, 24 Apr 2023 12:03:42 +0000 Subject: [PATCH 05/89] 2 channels (control, data) v5 --- src/router.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/router.rs b/src/router.rs index 3533dfa..e34696a 100644 --- a/src/router.rs +++ b/src/router.rs @@ -28,7 +28,7 @@ impl Router { let hello_message = ControlPacket { message_type: ControlPacketType::Hello, body_length: 0, - body: None, + body: Some(crate::packet::ControlPacketBody::Hello { flags: 100u16, seqno: 200u16, interval: 300u16 }), }; // send the hello_message to all the directly connected peers for peer in self.directly_connected_peers.lock().unwrap().iter() { From 5234db4009cba53f6650b380a15c4b17b228ecad Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Mon, 24 Apr 2023 13:18:44 +0000 Subject: [PATCH 06/89] 2 channels (control, data) v6 --- src/codec.rs | 25 +++++++++++-------------- src/main.rs | 12 ++++++++---- src/packet.rs | 34 ++++++++++++++++++++++++++++++++-- src/peer.rs | 23 ++++++++++++++++++----- src/peer_manager.rs | 4 ++-- src/router.rs | 2 ++ 6 files changed, 73 insertions(+), 27 deletions(-) diff --git a/src/codec.rs b/src/codec.rs index ea4d942..2dde7ed 100644 --- a/src/codec.rs +++ b/src/codec.rs @@ -212,33 +212,30 @@ impl Decoder for ControlPacketCodec { } let body_length = buf.get_u8(); + + if buf.remaining() < body_length as usize { + return Ok(None); + } + let body = match message_type { ControlPacketType::PadN => { - if buf.remaining() < usize::from(body_length) { - return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "Incomplete message")); - } buf.advance(usize::from(body_length)); Some(ControlPacketBody::PadN(body_length)) } ControlPacketType::Hello => { - if buf.remaining() < 6 { - return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "Incomplete message")); - } let flags = buf.get_u16(); let seqno = buf.get_u16(); let interval = buf.get_u16(); Some(ControlPacketBody::Hello { flags, seqno, interval }) } ControlPacketType::IHU => { - if buf.remaining() < 8 { - return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "Incomplete message")); - } let address_encoding = buf.get_u8(); - let reserved = buf.get_u8(); + // todo: based on address_encoding, we should decode the address on a different way + let _reserved = buf.get_u8(); let rxcost = buf.get_u16(); let interval = buf.get_u16(); let address = IpAddr::V4(Ipv4Addr::new(buf.get_u8(), buf.get_u8(), buf.get_u8(), buf.get_u8())); - Some(ControlPacketBody::IHU { address_encoding, reserved, rxcost, interval, address }) + Some(ControlPacketBody::IHU { rxcost, interval, address }) } // Add decoding logic for other message types. _ => None, @@ -270,9 +267,9 @@ impl Encoder for ControlPacketCodec { buf.put_u16(seqno); buf.put_u16(interval); } - ControlPacketBody::IHU { address_encoding, reserved, rxcost, interval, address } => { - buf.put_u8(address_encoding); - buf.put_u8(reserved); + ControlPacketBody::IHU { rxcost, interval, address } => { + buf.put_u8(0); // temp static address encoding + buf.put_u8(0); // reserved field should be set to 0 and MUST be ignored on recpetion buf.put_u16(rxcost); buf.put_u16(interval); match address { diff --git a/src/main.rs b/src/main.rs index 9897850..0b19208 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,7 +2,7 @@ use std::{error::Error, net::Ipv4Addr, sync::Arc}; use bytes::BytesMut; use clap::Parser; use etherparse::{IpHeader, PacketHeaders}; -use packet::{DataPacket, ControlPacket, ControlPacketType}; +use packet::{DataPacket, ControlPacket, ControlPacketType, ControlStruct}; use tokio::{io::AsyncReadExt, io::AsyncWriteExt, net::TcpListener, sync::mpsc}; mod node_setup; @@ -43,7 +43,7 @@ async fn main() -> Result<(), Box> { // --> this is because we will handle them differently // CHANNEL FOR CONTROL PACKETS - let (to_routing_control, mut from_node_control) = mpsc::unbounded_channel::(); + let (to_routing_control, mut from_node_control) = mpsc::unbounded_channel::(); /* BABEL ADDITIONS */ let router = Arc::new(router::Router::new()); @@ -62,11 +62,15 @@ async fn main() -> Result<(), Box> { tokio::spawn(async move { loop { while let Some(packet) = from_node_control.recv().await { - match packet.message_type { + match packet.control_packet.message_type { // different type of control packets ControlPacketType::Hello => { println!("Received Hello"); - println!("Should send IHU back"); + let dst_ip = packet.src_overlay_ip; + packet.reply(ControlPacket::new_IHU(10, 1000, dst_ip)); + } + ControlPacketType::IHU => { + println!("Received IHU"); } _ => { println!("Received unknown control packet"); diff --git a/src/packet.rs b/src/packet.rs index bf1bb92..563b7bb 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -1,5 +1,7 @@ use std::net::{IpAddr, Ipv4Addr}; +use tokio::sync::mpsc; + /* ********************************PAKCET*********************************** */ #[derive(Debug, Clone)] pub enum Packet { @@ -28,6 +30,22 @@ impl DataPacket { } /* ****************************CONTROL PACKET******************************** */ + +#[derive(Debug, Clone)] +pub struct ControlStruct { + pub control_packet: ControlPacket, + pub response_tx: mpsc::UnboundedSender, + pub src_overlay_ip: IpAddr, +} + +impl ControlStruct { + pub fn reply(self, control_packet: ControlPacket) { + if let Err(e) = self.response_tx.send(control_packet) { + eprintln!("Error reply: {:?}", e); + } + } +} + #[derive(Debug, PartialEq, Clone)] pub struct ControlPacket { pub message_type: ControlPacketType, @@ -35,6 +53,20 @@ pub struct ControlPacket { pub body: Option, } +impl ControlPacket { + pub fn new_IHU(rxcost: u16, interval: u16, address: IpAddr) -> Self { + Self { + message_type: ControlPacketType::IHU, + body_length: 10, + body: Some(ControlPacketBody::IHU { + rxcost, + interval, + address, + }), + } + } +} + #[derive(Debug, PartialEq, Clone)] pub enum ControlPacketType { Pad1 = 0, @@ -81,8 +113,6 @@ pub enum ControlPacketBody { interval: u16, }, IHU { - address_encoding: u8, - reserved: u8, rxcost: u16, interval: u16, address: IpAddr, diff --git a/src/peer.rs b/src/peer.rs index 14bd5dd..44f28d2 100644 --- a/src/peer.rs +++ b/src/peer.rs @@ -6,7 +6,7 @@ use std::{ use tokio::{net::TcpStream, select, sync::mpsc}; use tokio_util::codec::Framed; -use crate::packet::{ControlPacket, DataPacket}; +use crate::packet::{ControlPacket, DataPacket, ControlStruct}; use crate::{codec::PacketCodec, packet::Packet}; // IS A NEIGHBOR IN THE IDEA OF BABEL @@ -26,7 +26,7 @@ impl Peer { pub fn new( stream_ip: IpAddr, to_routing_data: mpsc::UnboundedSender, - to_routing_control: mpsc::UnboundedSender, + to_routing_control: mpsc::UnboundedSender, stream: TcpStream, overlay_ip: Ipv4Addr, ) -> Result> { @@ -35,8 +35,8 @@ impl Peer { // Create an unbounded channel for each peer let (to_peer_data, mut from_routing_data) = mpsc::unbounded_channel::(); // Create control channel - let (to_peer_control, mut from_routing_control) = - mpsc::unbounded_channel::(); + let (to_peer_control, mut from_routing_control) = mpsc::unbounded_channel::(); + let (control_reply_tx, mut control_reply_rx) = mpsc::unbounded_channel::(); tokio::spawn(async move { loop { @@ -54,7 +54,13 @@ impl Peer { } Packet::ControlPacket(packet) => { - if let Err(error) = to_routing_control.send(packet){ + // create control struct + let control_struct = ControlStruct { + control_packet: packet, + response_tx: control_reply_tx.clone(), + src_overlay_ip: IpAddr::V4(overlay_ip), + }; + if let Err(error) = to_routing_control.send(control_struct){ eprintln!("Error sending to to_routing_control: {}", error); } @@ -88,6 +94,13 @@ impl Peer { eprintln!("Error writing to stream: {}", e); } } + Some(packet) = control_reply_rx.recv() => { + println!("Received CONTROL REPLY from routing, sending it over the TCP stream"); + // Send it over the TCP stream + if let Err(e) = framed.send(Packet::ControlPacket(packet)).await { + eprintln!("Error writing to stream: {}", e); + } + } } } }); diff --git a/src/peer_manager.rs b/src/peer_manager.rs index f1070af..eff0c00 100644 --- a/src/peer_manager.rs +++ b/src/peer_manager.rs @@ -1,4 +1,4 @@ -use crate::packet::{DataPacket, ControlPacket}; +use crate::packet::{DataPacket, ControlPacket, ControlStruct}; use crate::{packet::Packet, peer::Peer}; use serde::Deserialize; use std::net::{Ipv4Addr, SocketAddr}; @@ -39,7 +39,7 @@ impl PeerManager { pub async fn get_peers_from_config( &self, to_routing_data: UnboundedSender, - to_routing_control: UnboundedSender, + to_routing_control: UnboundedSender, tun_addr_own_node: Ipv4Addr, router: Arc, ) { diff --git a/src/router.rs b/src/router.rs index e34696a..97c5dfa 100644 --- a/src/router.rs +++ b/src/router.rs @@ -30,6 +30,8 @@ impl Router { body_length: 0, body: Some(crate::packet::ControlPacketBody::Hello { flags: 100u16, seqno: 200u16, interval: 300u16 }), }; + + // send the hello_message to all the directly connected peers for peer in self.directly_connected_peers.lock().unwrap().iter() { println!("CONTROL: Sending hello message to peer: {}", peer.overlay_ip.to_string()); From b76177bc4bf956f6b5ad7c7feaa6ec43514a02a1 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Mon, 24 Apr 2023 17:06:43 +0000 Subject: [PATCH 07/89] 2 channels (control, data) v7 --- src/main.rs | 362 ++++++++++++++++++++++++++------------------------ src/peer.rs | 28 ++-- src/router.rs | 9 +- 3 files changed, 203 insertions(+), 196 deletions(-) diff --git a/src/main.rs b/src/main.rs index 0b19208..5e90b40 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,13 +1,13 @@ -use std::{error::Error, net::Ipv4Addr, sync::Arc}; use bytes::BytesMut; use clap::Parser; use etherparse::{IpHeader, PacketHeaders}; -use packet::{DataPacket, ControlPacket, ControlPacketType, ControlStruct}; +use packet::{ControlPacket, ControlPacketType, ControlStruct, DataPacket}; +use std::{error::Error, net::Ipv4Addr, sync::Arc}; use tokio::{io::AsyncReadExt, io::AsyncWriteExt, net::TcpListener, sync::mpsc}; +mod codec; mod node_setup; mod packet; -mod codec; mod peer; mod peer_manager; mod router; @@ -37,25 +37,33 @@ async fn main() -> Result<(), Box> { panic!("Error setting up node: {}", e); } }; - - // We will split the communication of DataPackets and ControlPacket into two different channels - // --> this is because we will handle them differently - - // CHANNEL FOR CONTROL PACKETS + // The sender halve (to_routing_control) is passed to each Peer instance. + // When a Peer instance receives a ControlPacket from another remote Peer instance (over TCP stream) it will create a ControlStruct and send it over this channel (see peer.rs). + // The receiver halve (from_node_control) is read (in a loop) in the main thread. let (to_routing_control, mut from_node_control) = mpsc::unbounded_channel::(); + + // The sender halve (to_routing_data) is passed to each Peer instance. + // When a Peer instance receives a DataPacket from another remote Peer instance (over TCP stream) it will send it over this channel (see peer.rs). + // The receiver halve (from_node_data) is read (in a loop) in the main thread. + // 2 things might happen when a DataPacket is received (see route_packet function): + // 1. The DataPacket is a packet for the local node (e.g. a ping request) --> send it to the TUN interface (through the to_tun channel) + // 2. The DataPacket is a packet for a remote node --> send it to the corresponding Peer instance (through the to_peer_data channel) + let (to_routing_data, mut from_node_data) = mpsc::unbounded_channel::(); + + // The sender (to_tun) is passed to the route_packet function. + // When a DataPacket is received and it is a packet for the local node it will be sent over this channel. + // The receiver (from_routing_data) is read (in a loop) in the main thread. + let (to_tun, mut from_routing_data) = mpsc::unbounded_channel::(); - /* BABEL ADDITIONS */ let router = Arc::new(router::Router::new()); - { let router = router.clone(); tokio::spawn(async move { - loop { - tokio::time::sleep(std::time::Duration::from_secs(10)).await; // beter use Timer - println!("sending hello"); - router.send_hello(); - } + loop { + tokio::time::sleep(std::time::Duration::from_secs(10)).await; // beter use Timer + router.send_hello(); + } }); // loop to read from_node_control @@ -63,14 +71,12 @@ async fn main() -> Result<(), Box> { loop { while let Some(packet) = from_node_control.recv().await { match packet.control_packet.message_type { - // different type of control packets ControlPacketType::Hello => { - println!("Received Hello"); let dst_ip = packet.src_overlay_ip; - packet.reply(ControlPacket::new_IHU(10, 1000, dst_ip)); + packet.reply(ControlPacket::new_IHU(10, 1000, dst_ip)); } ControlPacketType::IHU => { - println!("Received IHU"); + println!("IHU {}", packet.src_overlay_ip); } _ => { println!("Received unknown control packet"); @@ -81,191 +87,195 @@ async fn main() -> Result<(), Box> { }); } - - // CHANNELS USED FOR COMMUNICATION OF DATAPACKETS - // Create an unbounded channel for this node - let (to_tun, mut from_routing_data) = mpsc::unbounded_channel::(); - let (to_routing_data, mut from_node_data) = mpsc::unbounded_channel::(); - + + // Create the PeerManager: an interface to all peers this node is connected to // Additional static peers are obtained through the nodeconfig.toml file let peer_manager = PeerManager::new(); // Create static peers from the nodeconfig.toml file - let peer_man_clone = peer_manager.clone(); - let to_routing_data_clone = to_routing_data.clone(); - let to_routing_control_clone= to_routing_control.clone(); - let router_clone = router.clone(); - tokio::spawn(async move { - peer_man_clone - .get_peers_from_config(to_routing_data_clone, to_routing_control_clone, cli.tun_addr, router_clone) - .await; // --> here we create peer by TcpStream connect - }); + { + let peer_manager = peer_manager.clone(); + let to_routing_data = to_routing_data.clone(); + let to_routing_control = to_routing_control.clone(); + let router = router.clone(); + tokio::spawn(async move { + peer_manager + .get_peers_from_config(to_routing_data, to_routing_control, cli.tun_addr, router) + .await; // --> here we create peer by TcpStream connect + }); + } - let peer_man_clone = peer_manager.clone(); - let to_routing_data_clone = to_routing_data.clone(); - let to_routing_control_clone = to_routing_control.clone(); - let router_clone = router.clone(); - // listen for inbound request --> "to created the reverse peer object" --> here we reverse create peer be listener.accept'ing - tokio::spawn(async move { - match TcpListener::bind("[::]:9651").await { - Ok(listener) => { - // loop to accept the inbound requests - loop { - let to_routing_data_clone_clone = to_routing_data_clone.clone(); - let to_routing_control_clone_clone = to_routing_control_clone.clone(); - match listener.accept().await { - Ok((mut stream, _)) => { - // TEMPORARY: as we do not work with Babel yet, we will send to overlay ip (= addr of TUN) manually - // The packet flow looks like this: - // Listener accepts a TCP connect call here and send it's overlay IP over the stream - // In the peer_manager.rs at the place where we are connected we should manually add the overlay IP to the peer instance + { + let to_routing_data = to_routing_data.clone(); + let to_routing_control = to_routing_control.clone(); + let router = router.clone(); - // 1. Send own TUN address over the stream - let ip_bytes = cli.tun_addr.octets(); - stream.write_all(&ip_bytes).await.unwrap(); + // listen for inbound request --> "to created the reverse peer object" --> here we reverse create peer be listener.accept'ing + tokio::spawn(async move { + match TcpListener::bind("[::]:9651").await { + Ok(listener) => { + // loop to accept the inbound requests + loop { + let to_routing_data = to_routing_data.clone(); + let to_routing_control = to_routing_control.clone(); + match listener.accept().await { + Ok((mut stream, _)) => { + // TEMPORARY: as we do not work with Babel yet, we will send to overlay ip (= addr of TUN) manually + // The packet flow looks like this: + // Listener accepts a TCP connect call here and send it's overlay IP over the stream + // In the peer_manager.rs at the place where we are connected we should manually add the overlay IP to the peer instance - // 4. Read other node's TUN address from the stream - let mut buffer = [0u8; 4]; - stream.read_exact(&mut buffer).await.unwrap(); - let received_overlay_ip = Ipv4Addr::from(buffer); - println!( - "Received overlay IP from other node: {:?}", - received_overlay_ip - ); + // 1. Send own TUN address over the stream + let ip_bytes = cli.tun_addr.octets(); + stream.write_all(&ip_bytes).await.unwrap(); - // "reverse peer add" - let peer_stream_ip = stream.peer_addr().unwrap().ip(); - match Peer::new( - peer_stream_ip, - to_routing_data_clone_clone, - to_routing_control_clone_clone, - stream, - received_overlay_ip, - ) { - Ok(new_peer) => { - //println!("adding new peer to known_peers: {:?}", new_peer); - //peer_man_clone.known_peers.lock().unwrap().push(new_peer); + // 4. Read other node's TUN address from the stream + let mut buffer = [0u8; 4]; + stream.read_exact(&mut buffer).await.unwrap(); + let received_overlay_ip = Ipv4Addr::from(buffer); + println!( + "Received overlay IP from other node: {:?}", + received_overlay_ip + ); - router_clone.add_directly_connected_peer(new_peer); - } - Err(e) => { - eprintln!("Error creating 'reverse' peer: {}", e); - } - } - } - Err(e) => { - eprintln!("Error accepting TCP listener: {}", e); - } - } - } - } - Err(e) => { - eprintln!("Error binding TCP listener: {}", e); - } - } - }); + // "reverse peer add" + let peer_stream_ip = stream.peer_addr().unwrap().ip(); + match Peer::new( + peer_stream_ip, + to_routing_data, + to_routing_control, + stream, + received_overlay_ip, + ) { + Ok(new_peer) => { + //println!("adding new peer to known_peers: {:?}", new_peer); + //peer_man_clone.known_peers.lock().unwrap().push(new_peer); - // Loop to read the 'from_routing' receiver and foward it toward the TUN interface - // TODO: you will only get DataPackets on TUN so the channel should only accept DataPackets (and not just Packet) - let node_tun_clone = node_tun.clone(); - tokio::spawn(async move { - loop { - while let Some(packet) = from_routing_data.recv().await { - let data_packet = if let p = packet { - println!("LENTHEEE: {}", p.raw_data.len()); - p - } else { - continue; - }; - match node_tun_clone.send(&data_packet.raw_data).await { - Ok(_) => { - println!("Sending it towards this node's TUN"); - } - Err(e) => { - eprintln!("Error sending to TUN interface: {}", e); - } - } - } - } - }); - - // Loop to read from node's TUN interface and send it to to_routing sender halve - let node_tun_clone = node_tun.clone(); - let to_routing_clone = to_routing_data.clone(); - tokio::spawn(async move { - loop { - let mut buf = BytesMut::zeroed(LINK_MTU); - match node_tun_clone.recv(&mut buf).await { - Ok(n) => { - buf.truncate(n); - - println!("Got packet on my TUN, byyes: {}", n); - - // Remainder: if we read from TUN we will only need to parse them into DataPackets - // Extract the destination IP address using Etherparse - match PacketHeaders::from_ip_slice(&buf) { - Ok(packet) => { - if let Some(IpHeader::Version4(header, _)) = packet.ip { - let dest_addr = Ipv4Addr::from(header.destination); - println!("Destination IPv4 address: {}", dest_addr); - - let data_packet = DataPacket { - dest_ip: dest_addr, - raw_data: buf.to_vec(), - }; - - println!("LEN: {}", data_packet.raw_data.len()); - - match to_routing_clone.send(data_packet) { - Ok(_) => { - println!("packet sent to to_routing"); + router.add_directly_connected_peer(new_peer); } Err(e) => { - eprintln!("Error sending packet to to_routing: {}", e); + eprintln!("Error creating 'reverse' peer: {}", e); } } - } else { - println!("Non-IPv4 packet received, ignoring..."); } - } - Err(e) => { - println!("buffer: {:?}", buf); - eprintln!("Error from_ip_slice: {e}"); + Err(e) => { + eprintln!("Error accepting TCP listener: {}", e); + } } } } Err(e) => { - eprintln!("Error reading from TUN: {}", e); + eprintln!("Error binding TCP listener: {}", e); } } - } - }); + }); + } + + // Loop to read the 'from_routing' receiver and foward it toward the TUN interface + // TODO: you will only get DataPackets on TUN so the channel should only accept DataPackets (and not just Packet) + + { + let node_tun = node_tun.clone(); + tokio::spawn(async move { + loop { + while let Some(packet) = from_routing_data.recv().await { + let data_packet = if let p = packet { + println!("LENTHEEE: {}", p.raw_data.len()); + p + } else { + continue; + }; + match node_tun.send(&data_packet.raw_data).await { + Ok(_) => { + println!("Sending it towards this node's TUN"); + } + Err(e) => { + eprintln!("Error sending to TUN interface: {}", e); + } + } + } + } + }); + } + + // Loop to read from node's TUN interface and send it to to_routing sender halve + { + let node_tun = node_tun.clone(); + let to_routing_data = to_routing_data.clone(); + + tokio::spawn(async move { + loop { + let mut buf = BytesMut::zeroed(LINK_MTU); + match node_tun.recv(&mut buf).await { + Ok(n) => { + buf.truncate(n); + + println!("Got packet on my TUN, byyes: {}", n); + + // Remainder: if we read from TUN we will only need to parse them into DataPackets + // Extract the destination IP address using Etherparse + match PacketHeaders::from_ip_slice(&buf) { + Ok(packet) => { + if let Some(IpHeader::Version4(header, _)) = packet.ip { + let dest_addr = Ipv4Addr::from(header.destination); + println!("Destination IPv4 address: {}", dest_addr); + + let data_packet = DataPacket { + dest_ip: dest_addr, + raw_data: buf.to_vec(), + }; + + println!("LEN: {}", data_packet.raw_data.len()); + + match to_routing_data.send(data_packet) { + Ok(_) => { + println!("packet sent to to_routing"); + } + Err(e) => { + eprintln!("Error sending packet to to_routing: {}", e); + } + } + } else { + println!("Non-IPv4 packet received, ignoring..."); + } + } + Err(e) => { + println!("buffer: {:?}", buf); + eprintln!("Error from_ip_slice: {e}"); + } + } + } + Err(e) => { + eprintln!("Error reading from TUN: {}", e); + } + } + } + }); + } // Loop to read from from_node reeiver and route the packet further // the route_packet function will send the packet towards the correct to_peer (based on dest ip of packet) // or towards this own node's TUN interface (if dest ip of packet is this node's TUN addr) - let peer_man_clone = peer_manager.clone(); - let node_tun_clone = node_tun.clone(); - let to_tun_sender_clone = to_tun.clone(); - let router_clone = router.clone(); - tokio::spawn(async move { - loop { - let router_inner_clone = router_clone.clone(); - let node_tun_inner_clone = node_tun_clone.clone(); - let to_tun_sender_inner_clone = to_tun_sender_clone.clone(); - while let Some(packet) = from_node_data.recv().await { - //println!("Read message from from_node, sending it to route_packet function"); - peer_man_clone.route_packet( - packet, - node_tun_inner_clone.clone(), - to_tun_sender_inner_clone.clone(), - router_inner_clone.clone(), - ); + { + let peer_manager = peer_manager.clone(); + let node_tun = node_tun.clone(); + let to_tun = to_tun.clone(); + let router = router.clone(); + tokio::spawn(async move { + loop { + while let Some(packet) = from_node_data.recv().await { + peer_manager.route_packet( + packet, + node_tun.clone(), + to_tun.clone(), + router.clone(), + ); + } } - } - }); + }); + } tokio::time::sleep(std::time::Duration::from_secs(60 * 60 * 24)).await; Ok(()) diff --git a/src/peer.rs b/src/peer.rs index 44f28d2..88f662a 100644 --- a/src/peer.rs +++ b/src/peer.rs @@ -15,11 +15,8 @@ use crate::{codec::PacketCodec, packet::Packet}; pub struct Peer { pub stream_ip: IpAddr, pub to_peer_data: mpsc::UnboundedSender, - pub to_peer_control: mpsc::UnboundedSender, // RFC: the local node's interface over which this neighbour is reachable - pub overlay_ip: Ipv4Addr, // RFC: address of the neigbouring interface - - // additional fields according to babel RFC - // pub txcost: u16, + pub to_peer_control: mpsc::UnboundedSender, + pub overlay_ip: Ipv4Addr, } impl Peer { @@ -30,19 +27,21 @@ impl Peer { stream: TcpStream, overlay_ip: Ipv4Addr, ) -> Result> { - // Create a Framed for each peer + + // Framed for peer let mut framed = Framed::new(stream, PacketCodec::new()); - // Create an unbounded channel for each peer + // Data channel for peer let (to_peer_data, mut from_routing_data) = mpsc::unbounded_channel::(); - // Create control channel + // Control channel for peer let (to_peer_control, mut from_routing_control) = mpsc::unbounded_channel::(); + // Control reply channel for peer let (control_reply_tx, mut control_reply_rx) = mpsc::unbounded_channel::(); tokio::spawn(async move { loop { select! { - // received from peer - + + // Received over the TCP stream frame = framed.next() => { match frame { Some(Ok(packet)) => { @@ -54,7 +53,8 @@ impl Peer { } Packet::ControlPacket(packet) => { - // create control struct + // Parse the DataPacket into a ControlStruct + // as the to_routing_control channel expects let control_struct = ControlStruct { control_packet: packet, response_tx: control_reply_tx.clone(), @@ -77,10 +77,8 @@ impl Peer { } } - // received from routing (both data and control channels) - + // To send over the TCP stream Some(packet) = from_routing_data.recv() => { - println!("Received DATA from routing, sending it over the TCP stream"); // Send it over the TCP stream if let Err(e) = framed.send(Packet::DataPacket(packet)).await { eprintln!("Error writing to stream: {}", e); @@ -88,14 +86,12 @@ impl Peer { } Some(packet) = from_routing_control.recv() => { - println!("Received CONTROL from routing, sending it over the TCP stream"); // Send it over the TCP stream if let Err(e) = framed.send(Packet::ControlPacket(packet)).await { eprintln!("Error writing to stream: {}", e); } } Some(packet) = control_reply_rx.recv() => { - println!("Received CONTROL REPLY from routing, sending it over the TCP stream"); // Send it over the TCP stream if let Err(e) = framed.send(Packet::ControlPacket(packet)).await { eprintln!("Error writing to stream: {}", e); diff --git a/src/router.rs b/src/router.rs index 97c5dfa..f719285 100644 --- a/src/router.rs +++ b/src/router.rs @@ -31,11 +31,12 @@ impl Router { body: Some(crate::packet::ControlPacketBody::Hello { flags: 100u16, seqno: 200u16, interval: 300u16 }), }; - - // send the hello_message to all the directly connected peers + // Hello is sent to all directly connected peers for peer in self.directly_connected_peers.lock().unwrap().iter() { - println!("CONTROL: Sending hello message to peer: {}", peer.overlay_ip.to_string()); - peer.to_peer_control.send(hello_message.clone()); + println!("Hello {}", peer.overlay_ip); + if let Err(e) = peer.to_peer_control.send(hello_message.clone()) { + eprintln!("Error sending hello message to peer: {:?}", e); + } } } } From 3ebfb08f16fcf956c3309b56bf86845f93376861 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Mon, 24 Apr 2023 18:14:38 +0000 Subject: [PATCH 08/89] 2 channels (control, data) v8 --- src/main.rs | 3 ++- src/packet.rs | 4 ++-- src/peer.rs | 4 ++++ src/router.rs | 5 ----- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main.rs b/src/main.rs index 5e90b40..d088ed5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -74,9 +74,10 @@ async fn main() -> Result<(), Box> { ControlPacketType::Hello => { let dst_ip = packet.src_overlay_ip; packet.reply(ControlPacket::new_IHU(10, 1000, dst_ip)); + println!("IHU {}", dst_ip); } ControlPacketType::IHU => { - println!("IHU {}", packet.src_overlay_ip); + // Upon receiving an IHU message, nothing particular should happen } _ => { println!("Received unknown control packet"); diff --git a/src/packet.rs b/src/packet.rs index 563b7bb..ac6ccd8 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -54,14 +54,14 @@ pub struct ControlPacket { } impl ControlPacket { - pub fn new_IHU(rxcost: u16, interval: u16, address: IpAddr) -> Self { + pub fn new_IHU(rxcost: u16, interval: u16, dest_address: IpAddr) -> Self { Self { message_type: ControlPacketType::IHU, body_length: 10, body: Some(ControlPacketBody::IHU { rxcost, interval, - address, + address: dest_address, }), } } diff --git a/src/peer.rs b/src/peer.rs index 88f662a..65f2626 100644 --- a/src/peer.rs +++ b/src/peer.rs @@ -59,7 +59,11 @@ impl Peer { control_packet: packet, response_tx: control_reply_tx.clone(), src_overlay_ip: IpAddr::V4(overlay_ip), + // note: although this control packet is received from the TCP stream + // we set the src_overlay_op to the overlay_ip of the peer + // as we 'arrived' in the peer instance of representing the sending node on this current node }; + println!("src_overlay_ip: {}", overlay_ip.to_string()); if let Err(error) = to_routing_control.send(control_struct){ eprintln!("Error sending to to_routing_control: {}", error); } diff --git a/src/router.rs b/src/router.rs index f719285..6a726df 100644 --- a/src/router.rs +++ b/src/router.rs @@ -17,11 +17,6 @@ impl Router { // NOTE: we gebruiken gewoon &self en niet &mut self want de mutex van directly_connected_peers fixt het feit dat er sws maar 1 iemand aankan pub fn add_directly_connected_peer(&self, peer: Peer) { self.directly_connected_peers.lock().unwrap().push(peer); - // for debug: print connected peers once one get added - println!("CURRENT DIRECTLY CONNECTED PEERS:"); - for peer in self.directly_connected_peers.lock().unwrap().iter() { - println!("Peer: {:?}", peer); - } } pub fn send_hello(&self) { From 22c0d45e43f2e5077761924ca4b6ef062e9122fc Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Mon, 24 Apr 2023 21:07:24 +0000 Subject: [PATCH 09/89] refactoring v1 --- src/codec.rs | 2 +- src/main.rs | 71 +++++++++++++++------------------------------ src/packet.rs | 9 ++---- src/peer.rs | 2 +- src/peer_manager.rs | 48 ++---------------------------- src/router.rs | 41 ++++++++++++++++++++++---- 6 files changed, 66 insertions(+), 107 deletions(-) diff --git a/src/codec.rs b/src/codec.rs index 2dde7ed..34ddccf 100644 --- a/src/codec.rs +++ b/src/codec.rs @@ -229,7 +229,7 @@ impl Decoder for ControlPacketCodec { Some(ControlPacketBody::Hello { flags, seqno, interval }) } ControlPacketType::IHU => { - let address_encoding = buf.get_u8(); + let _address_encoding = buf.get_u8(); // todo: based on address_encoding, we should decode the address on a different way let _reserved = buf.get_u8(); let rxcost = buf.get_u16(); diff --git a/src/main.rs b/src/main.rs index d088ed5..af6da8e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -56,7 +56,11 @@ async fn main() -> Result<(), Box> { // The receiver (from_routing_data) is read (in a loop) in the main thread. let (to_tun, mut from_routing_data) = mpsc::unbounded_channel::(); + let router = Arc::new(router::Router::new()); + let peer_manager = PeerManager::new(); + + { let router = router.clone(); tokio::spawn(async move { @@ -66,14 +70,16 @@ async fn main() -> Result<(), Box> { } }); - // loop to read from_node_control + // This loop reads control messages from the from_node_control channel receiver Halve. + // This means that this loop will be executed whenever a ControlPacket is received from a remote Peer instance (aka another Node). + // HANDLING THE DIFFERENT CONTROL MESSAGES --> MOET ERGENS ANDERS GEBEUREN! tokio::spawn(async move { loop { while let Some(packet) = from_node_control.recv().await { match packet.control_packet.message_type { ControlPacketType::Hello => { let dst_ip = packet.src_overlay_ip; - packet.reply(ControlPacket::new_IHU(10, 1000, dst_ip)); + packet.reply(ControlPacket::new_ihu(10, 1000, dst_ip)); println!("IHU {}", dst_ip); } ControlPacketType::IHU => { @@ -88,13 +94,6 @@ async fn main() -> Result<(), Box> { }); } - - - - // Create the PeerManager: an interface to all peers this node is connected to - // Additional static peers are obtained through the nodeconfig.toml file - let peer_manager = PeerManager::new(); - // Create static peers from the nodeconfig.toml file { let peer_manager = peer_manager.clone(); @@ -151,9 +150,6 @@ async fn main() -> Result<(), Box> { received_overlay_ip, ) { Ok(new_peer) => { - //println!("adding new peer to known_peers: {:?}", new_peer); - //peer_man_clone.known_peers.lock().unwrap().push(new_peer); - router.add_directly_connected_peer(new_peer); } Err(e) => { @@ -174,34 +170,24 @@ async fn main() -> Result<(), Box> { }); } - // Loop to read the 'from_routing' receiver and foward it toward the TUN interface - // TODO: you will only get DataPackets on TUN so the channel should only accept DataPackets (and not just Packet) - + // Loop to read the from_routing_data receiver which contains data packets with a destination IP of this node. + // These packets are forwarded to the actual TUN interface. { let node_tun = node_tun.clone(); tokio::spawn(async move { loop { - while let Some(packet) = from_routing_data.recv().await { - let data_packet = if let p = packet { - println!("LENTHEEE: {}", p.raw_data.len()); - p - } else { - continue; - }; - match node_tun.send(&data_packet.raw_data).await { - Ok(_) => { - println!("Sending it towards this node's TUN"); - } - Err(e) => { - eprintln!("Error sending to TUN interface: {}", e); - } + while let Some(data_packet) = from_routing_data.recv().await { + if let Err(e) = node_tun.send(&data_packet.raw_data).await { + eprintln!("Error sending to TUN interface: {}", e); } } } }); } - // Loop to read from node's TUN interface and send it to to_routing sender halve + // Loop to read from node's TUN interface and send it to to_routing_data sender halve. + // Note: a packet will only arrive on the TUN interface if it has been put there by the kernel. + // This means that the application will never read packets from the TUN interface that it has sent itself. { let node_tun = node_tun.clone(); let to_routing_data = to_routing_data.clone(); @@ -213,10 +199,6 @@ async fn main() -> Result<(), Box> { Ok(n) => { buf.truncate(n); - println!("Got packet on my TUN, byyes: {}", n); - - // Remainder: if we read from TUN we will only need to parse them into DataPackets - // Extract the destination IP address using Etherparse match PacketHeaders::from_ip_slice(&buf) { Ok(packet) => { if let Some(IpHeader::Version4(header, _)) = packet.ip { @@ -228,8 +210,6 @@ async fn main() -> Result<(), Box> { raw_data: buf.to_vec(), }; - println!("LEN: {}", data_packet.raw_data.len()); - match to_routing_data.send(data_packet) { Ok(_) => { println!("packet sent to to_routing"); @@ -256,24 +236,19 @@ async fn main() -> Result<(), Box> { }); } - // Loop to read from from_node reeiver and route the packet further - // the route_packet function will send the packet towards the correct to_peer (based on dest ip of packet) - // or towards this own node's TUN interface (if dest ip of packet is this node's TUN addr) + // Loop to read from from_node_data receiver and to pass the packet further towards + // the route_packet function which will send the packet towards the correct to_peer + // or towards this node's TUN interface (if destination IP of packet match this node's TUN address). { - let peer_manager = peer_manager.clone(); + // let peer_manager = peer_manager.clone(); let node_tun = node_tun.clone(); let to_tun = to_tun.clone(); let router = router.clone(); tokio::spawn(async move { loop { - while let Some(packet) = from_node_data.recv().await { - peer_manager.route_packet( - packet, - node_tun.clone(), - to_tun.clone(), - router.clone(), - ); - } + while let Some(data_packet) = from_node_data.recv().await { + router.route_data_packet(data_packet, node_tun.clone(), to_tun.clone()); + } } }); } diff --git a/src/packet.rs b/src/packet.rs index ac6ccd8..cf3cd72 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -1,5 +1,4 @@ use std::net::{IpAddr, Ipv4Addr}; - use tokio::sync::mpsc; /* ********************************PAKCET*********************************** */ @@ -23,11 +22,7 @@ pub struct DataPacket { pub dest_ip: Ipv4Addr, } -impl DataPacket { - pub fn get_dest_ip(&self) -> Ipv4Addr { - self.dest_ip - } -} +impl DataPacket {} /* ****************************CONTROL PACKET******************************** */ @@ -54,7 +49,7 @@ pub struct ControlPacket { } impl ControlPacket { - pub fn new_IHU(rxcost: u16, interval: u16, dest_address: IpAddr) -> Self { + pub fn new_ihu(rxcost: u16, interval: u16, dest_address: IpAddr) -> Self { Self { message_type: ControlPacketType::IHU, body_length: 10, diff --git a/src/peer.rs b/src/peer.rs index 65f2626..bc38bd5 100644 --- a/src/peer.rs +++ b/src/peer.rs @@ -11,7 +11,7 @@ use crate::{codec::PacketCodec, packet::Packet}; // IS A NEIGHBOR IN THE IDEA OF BABEL -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Peer { pub stream_ip: IpAddr, pub to_peer_data: mpsc::UnboundedSender, diff --git a/src/peer_manager.rs b/src/peer_manager.rs index eff0c00..8fcc8e9 100644 --- a/src/peer_manager.rs +++ b/src/peer_manager.rs @@ -1,11 +1,10 @@ -use crate::packet::{DataPacket, ControlPacket, ControlStruct}; -use crate::{packet::Packet, peer::Peer}; +use crate::packet::{DataPacket, ControlStruct}; +use crate::{peer::Peer}; use serde::Deserialize; use std::net::{Ipv4Addr, SocketAddr}; use std::sync::{Arc, Mutex}; use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tokio::{net::TcpStream, sync::mpsc::UnboundedSender}; -use tokio_tun::Tun; use crate::router::Router; pub const NODE_CONFIG_FILE_PATH: &str = "nodeconfig.toml"; @@ -28,7 +27,7 @@ pub struct PeerManager { impl PeerManager { pub fn new() -> Self { - let mut known_peers: Vec = Vec::new(); + let known_peers: Vec = Vec::new(); Self { known_peers: Arc::new(Mutex::new(known_peers)), @@ -76,11 +75,6 @@ impl PeerManager { received_overlay_ip, ) { Ok(new_peer) => { - // Add peer to known_peers - //let mut known_peers = self.known_peers.lock().unwrap(); - //known_peers.push(new_peer); - // new - // add new_peer to router directly_connected_peers router.add_directly_connected_peer(new_peer); } Err(e) => { @@ -103,40 +97,4 @@ impl PeerManager { } } } - - // should eventually be moved to router.rs - // SHOULD ONLY BE CALLED ON DATAPACKETS!! - // --> because control packets are only sent between directly connected nodes - // --> so they are not routed. If you receive a control packet, you know it's for you - pub fn route_packet( - &self, - data_packet: DataPacket, - own_node_tun: Arc, - to_tun_sender: UnboundedSender, - router: Arc, - ) { - // We first extract the IP from the Packet and look if the destination IP is our own overlay IP - // So if --> forward packet to our own TUN interface - // If not --> look in known_peers which peer's overlay_ip matches with destination IP - - let packet_dest_ip = data_packet.get_dest_ip(); - - // Packet towards own node's TUN interface - if packet_dest_ip == own_node_tun.address().unwrap() { - println!("Packet got address of our own TUN --> so sending it to my own TUN"); - to_tun_sender.send(data_packet); - // Packet towards other peer - } else { - let mut known_peers = self.known_peers.lock().unwrap(); - for peer in known_peers.iter_mut() { - if peer.overlay_ip == packet_dest_ip { - println!("Routing packet towards: {}", peer.overlay_ip.to_string()); - peer.to_peer_data.send(data_packet); - break; - } else { - println!("No peer match found"); - } - } - } - } } diff --git a/src/router.rs b/src/router.rs index 6a726df..bc2024b 100644 --- a/src/router.rs +++ b/src/router.rs @@ -1,6 +1,7 @@ -use std::{net::IpAddr, sync::{Mutex, Arc}}; - -use crate::{peer::Peer, packet::{ControlPacket, ControlPacketType}}; +use std::{net::{IpAddr, Ipv4Addr}, sync::{Mutex, Arc}}; +use tokio::sync::mpsc::UnboundedSender; +use tokio_tun::Tun; +use crate::{peer::Peer, packet::{ControlPacket, ControlPacketType, DataPacket}}; #[derive(Debug, Clone)] pub struct Router { @@ -14,7 +15,6 @@ impl Router { } } - // NOTE: we gebruiken gewoon &self en niet &mut self want de mutex van directly_connected_peers fixt het feit dat er sws maar 1 iemand aankan pub fn add_directly_connected_peer(&self, peer: Peer) { self.directly_connected_peers.lock().unwrap().push(peer); } @@ -26,7 +26,7 @@ impl Router { body: Some(crate::packet::ControlPacketBody::Hello { flags: 100u16, seqno: 200u16, interval: 300u16 }), }; - // Hello is sent to all directly connected peers + // Send Hello to all directly connected peers for peer in self.directly_connected_peers.lock().unwrap().iter() { println!("Hello {}", peer.overlay_ip); if let Err(e) = peer.to_peer_control.send(hello_message.clone()) { @@ -34,6 +34,37 @@ impl Router { } } } + + pub fn route_data_packet(&self, data_packet: DataPacket, node_tun: Arc, to_tun: UnboundedSender) { + let dest_ip = data_packet.dest_ip; + // If the destination IP of the packets matches this node's overlay IP, we should forward it to the TUN interface. + // This is done by sending it to the to_tun sender halve of the channel. The receiver halve is read in the main loop + // and further forwards the packet towards the actual TUN interface. + if dest_ip == node_tun.address().unwrap() { + if let Err(e) = to_tun.send(data_packet) { + eprintln!("Error sendign packet to to_tun: {}", e); + } + } else { + // If the destination IP of the packet does not match this node's overlay IP, we should forward it to the + // correct peer. This is done by sending the packet to the to_peer_data sender halve of the channel. The receiver + // halve is read in the peer select statement and further forwards the packet towards packet over the TCP stream. + let peer = self.get_peer_from_ip(dest_ip); + if let Some(peer) = peer { + if let Err(e) = peer.to_peer_data.send(data_packet) { + eprintln!("Error sending packet to peer: {}", e); + } + } + } + } + + fn get_peer_from_ip (&self, peer_ip: Ipv4Addr) -> Option { + for peer in self.directly_connected_peers.lock().unwrap().iter() { + if peer.overlay_ip == peer_ip { + Some(peer.clone()); + } + } + None + } } struct Route { From 9436d5db191c244df39f11d01142a3b03d44b5dd Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Tue, 25 Apr 2023 06:59:05 +0000 Subject: [PATCH 10/89] refactoring + fixing little bug in get_peer_from_ip --- src/main.rs | 4 ++-- src/peer.rs | 2 -- src/router.rs | 10 +++++----- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/main.rs b/src/main.rs index af6da8e..8b7c567 100644 --- a/src/main.rs +++ b/src/main.rs @@ -212,10 +212,10 @@ async fn main() -> Result<(), Box> { match to_routing_data.send(data_packet) { Ok(_) => { - println!("packet sent to to_routing"); + println!("packet sent to to_routing_data"); } Err(e) => { - eprintln!("Error sending packet to to_routing: {}", e); + eprintln!("Error sending packet to to_routing_data: {}", e); } } } else { diff --git a/src/peer.rs b/src/peer.rs index bc38bd5..8ec958a 100644 --- a/src/peer.rs +++ b/src/peer.rs @@ -63,7 +63,6 @@ impl Peer { // we set the src_overlay_op to the overlay_ip of the peer // as we 'arrived' in the peer instance of representing the sending node on this current node }; - println!("src_overlay_ip: {}", overlay_ip.to_string()); if let Err(error) = to_routing_control.send(control_struct){ eprintln!("Error sending to to_routing_control: {}", error); } @@ -81,7 +80,6 @@ impl Peer { } } - // To send over the TCP stream Some(packet) = from_routing_data.recv() => { // Send it over the TCP stream if let Err(e) = framed.send(Packet::DataPacket(packet)).await { diff --git a/src/router.rs b/src/router.rs index bc2024b..f8a61a0 100644 --- a/src/router.rs +++ b/src/router.rs @@ -42,15 +42,15 @@ impl Router { // and further forwards the packet towards the actual TUN interface. if dest_ip == node_tun.address().unwrap() { if let Err(e) = to_tun.send(data_packet) { - eprintln!("Error sendign packet to to_tun: {}", e); + eprintln!("Error sending packet to to_tun: {}", e); } } else { // If the destination IP of the packet does not match this node's overlay IP, we should forward it to the // correct peer. This is done by sending the packet to the to_peer_data sender halve of the channel. The receiver // halve is read in the peer select statement and further forwards the packet towards packet over the TCP stream. let peer = self.get_peer_from_ip(dest_ip); - if let Some(peer) = peer { - if let Err(e) = peer.to_peer_data.send(data_packet) { + if let Some(dest_peer) = peer { + if let Err(e) = dest_peer.to_peer_data.send(data_packet) { eprintln!("Error sending packet to peer: {}", e); } } @@ -60,10 +60,10 @@ impl Router { fn get_peer_from_ip (&self, peer_ip: Ipv4Addr) -> Option { for peer in self.directly_connected_peers.lock().unwrap().iter() { if peer.overlay_ip == peer_ip { - Some(peer.clone()); + return Some(peer.clone()) } } - None + return None } } From 1e9d39c8c3968e55a92bbd8ed0b9c386a3c74815 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Tue, 25 Apr 2023 13:34:51 +0000 Subject: [PATCH 11/89] refactoring done --- src/main.rs | 189 ++------------------------------------------ src/packet.rs | 4 +- src/peer.rs | 18 ++--- src/peer_manager.rs | 107 +++++++++++++++++-------- src/router.rs | 182 +++++++++++++++++++++++++++--------------- 5 files changed, 213 insertions(+), 287 deletions(-) diff --git a/src/main.rs b/src/main.rs index 8b7c567..970f61a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,8 @@ use bytes::BytesMut; use clap::Parser; use etherparse::{IpHeader, PacketHeaders}; -use packet::{ControlPacket, ControlPacketType, ControlStruct, DataPacket}; +use packet::DataPacket; use std::{error::Error, net::Ipv4Addr, sync::Arc}; -use tokio::{io::AsyncReadExt, io::AsyncWriteExt, net::TcpListener, sync::mpsc}; mod codec; mod node_setup; @@ -12,9 +11,6 @@ mod peer; mod peer_manager; mod router; -use peer::Peer; -use peer_manager::PeerManager; - const LINK_MTU: usize = 1500; #[derive(Parser)] @@ -37,160 +33,17 @@ async fn main() -> Result<(), Box> { panic!("Error setting up node: {}", e); } }; - - // The sender halve (to_routing_control) is passed to each Peer instance. - // When a Peer instance receives a ControlPacket from another remote Peer instance (over TCP stream) it will create a ControlStruct and send it over this channel (see peer.rs). - // The receiver halve (from_node_control) is read (in a loop) in the main thread. - let (to_routing_control, mut from_node_control) = mpsc::unbounded_channel::(); - // The sender halve (to_routing_data) is passed to each Peer instance. - // When a Peer instance receives a DataPacket from another remote Peer instance (over TCP stream) it will send it over this channel (see peer.rs). - // The receiver halve (from_node_data) is read (in a loop) in the main thread. - // 2 things might happen when a DataPacket is received (see route_packet function): - // 1. The DataPacket is a packet for the local node (e.g. a ping request) --> send it to the TUN interface (through the to_tun channel) - // 2. The DataPacket is a packet for a remote node --> send it to the corresponding Peer instance (through the to_peer_data channel) - let (to_routing_data, mut from_node_data) = mpsc::unbounded_channel::(); - - // The sender (to_tun) is passed to the route_packet function. - // When a DataPacket is received and it is a packet for the local node it will be sent over this channel. - // The receiver (from_routing_data) is read (in a loop) in the main thread. - let (to_tun, mut from_routing_data) = mpsc::unbounded_channel::(); - - - let router = Arc::new(router::Router::new()); - let peer_manager = PeerManager::new(); + // Creating a new Router instance + let router = Arc::new(router::Router::new(node_tun.clone())); + // Creating a new PeerManager instance + let _peer_manager = peer_manager::PeerManager::new(router.clone()); - { - let router = router.clone(); - tokio::spawn(async move { - loop { - tokio::time::sleep(std::time::Duration::from_secs(10)).await; // beter use Timer - router.send_hello(); - } - }); - - // This loop reads control messages from the from_node_control channel receiver Halve. - // This means that this loop will be executed whenever a ControlPacket is received from a remote Peer instance (aka another Node). - // HANDLING THE DIFFERENT CONTROL MESSAGES --> MOET ERGENS ANDERS GEBEUREN! - tokio::spawn(async move { - loop { - while let Some(packet) = from_node_control.recv().await { - match packet.control_packet.message_type { - ControlPacketType::Hello => { - let dst_ip = packet.src_overlay_ip; - packet.reply(ControlPacket::new_ihu(10, 1000, dst_ip)); - println!("IHU {}", dst_ip); - } - ControlPacketType::IHU => { - // Upon receiving an IHU message, nothing particular should happen - } - _ => { - println!("Received unknown control packet"); - } - } - } - } - }); - } - - // Create static peers from the nodeconfig.toml file - { - let peer_manager = peer_manager.clone(); - let to_routing_data = to_routing_data.clone(); - let to_routing_control = to_routing_control.clone(); - let router = router.clone(); - tokio::spawn(async move { - peer_manager - .get_peers_from_config(to_routing_data, to_routing_control, cli.tun_addr, router) - .await; // --> here we create peer by TcpStream connect - }); - } - - { - let to_routing_data = to_routing_data.clone(); - let to_routing_control = to_routing_control.clone(); - let router = router.clone(); - - // listen for inbound request --> "to created the reverse peer object" --> here we reverse create peer be listener.accept'ing - tokio::spawn(async move { - match TcpListener::bind("[::]:9651").await { - Ok(listener) => { - // loop to accept the inbound requests - loop { - let to_routing_data = to_routing_data.clone(); - let to_routing_control = to_routing_control.clone(); - match listener.accept().await { - Ok((mut stream, _)) => { - // TEMPORARY: as we do not work with Babel yet, we will send to overlay ip (= addr of TUN) manually - // The packet flow looks like this: - // Listener accepts a TCP connect call here and send it's overlay IP over the stream - // In the peer_manager.rs at the place where we are connected we should manually add the overlay IP to the peer instance - - // 1. Send own TUN address over the stream - let ip_bytes = cli.tun_addr.octets(); - stream.write_all(&ip_bytes).await.unwrap(); - - // 4. Read other node's TUN address from the stream - let mut buffer = [0u8; 4]; - stream.read_exact(&mut buffer).await.unwrap(); - let received_overlay_ip = Ipv4Addr::from(buffer); - println!( - "Received overlay IP from other node: {:?}", - received_overlay_ip - ); - - // "reverse peer add" - let peer_stream_ip = stream.peer_addr().unwrap().ip(); - match Peer::new( - peer_stream_ip, - to_routing_data, - to_routing_control, - stream, - received_overlay_ip, - ) { - Ok(new_peer) => { - router.add_directly_connected_peer(new_peer); - } - Err(e) => { - eprintln!("Error creating 'reverse' peer: {}", e); - } - } - } - Err(e) => { - eprintln!("Error accepting TCP listener: {}", e); - } - } - } - } - Err(e) => { - eprintln!("Error binding TCP listener: {}", e); - } - } - }); - } - - // Loop to read the from_routing_data receiver which contains data packets with a destination IP of this node. - // These packets are forwarded to the actual TUN interface. + // The TUN interface will only receive data packets. This loops reads data packets from the TUN interface and forwards them to the router. + // NOTE: only the kernel can put data packets on the TUN interface. This application never puts data packets on the TUN interface for itself. { let node_tun = node_tun.clone(); - tokio::spawn(async move { - loop { - while let Some(data_packet) = from_routing_data.recv().await { - if let Err(e) = node_tun.send(&data_packet.raw_data).await { - eprintln!("Error sending to TUN interface: {}", e); - } - } - } - }); - } - - // Loop to read from node's TUN interface and send it to to_routing_data sender halve. - // Note: a packet will only arrive on the TUN interface if it has been put there by the kernel. - // This means that the application will never read packets from the TUN interface that it has sent itself. - { - let node_tun = node_tun.clone(); - let to_routing_data = to_routing_data.clone(); tokio::spawn(async move { loop { @@ -198,7 +51,6 @@ async fn main() -> Result<(), Box> { match node_tun.recv(&mut buf).await { Ok(n) => { buf.truncate(n); - match PacketHeaders::from_ip_slice(&buf) { Ok(packet) => { if let Some(IpHeader::Version4(header, _)) = packet.ip { @@ -209,15 +61,7 @@ async fn main() -> Result<(), Box> { dest_ip: dest_addr, raw_data: buf.to_vec(), }; - - match to_routing_data.send(data_packet) { - Ok(_) => { - println!("packet sent to to_routing_data"); - } - Err(e) => { - eprintln!("Error sending packet to to_routing_data: {}", e); - } - } + router.router_data_tx.send(data_packet).unwrap(); } else { println!("Non-IPv4 packet received, ignoring..."); } @@ -236,23 +80,6 @@ async fn main() -> Result<(), Box> { }); } - // Loop to read from from_node_data receiver and to pass the packet further towards - // the route_packet function which will send the packet towards the correct to_peer - // or towards this node's TUN interface (if destination IP of packet match this node's TUN address). - { - // let peer_manager = peer_manager.clone(); - let node_tun = node_tun.clone(); - let to_tun = to_tun.clone(); - let router = router.clone(); - tokio::spawn(async move { - loop { - while let Some(data_packet) = from_node_data.recv().await { - router.route_data_packet(data_packet, node_tun.clone(), to_tun.clone()); - } - } - }); - } - tokio::time::sleep(std::time::Duration::from_secs(60 * 60 * 24)).await; Ok(()) } diff --git a/src/packet.rs b/src/packet.rs index cf3cd72..88bcffc 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -29,13 +29,13 @@ impl DataPacket {} #[derive(Debug, Clone)] pub struct ControlStruct { pub control_packet: ControlPacket, - pub response_tx: mpsc::UnboundedSender, + pub control_reply_tx: mpsc::UnboundedSender, pub src_overlay_ip: IpAddr, } impl ControlStruct { pub fn reply(self, control_packet: ControlPacket) { - if let Err(e) = self.response_tx.send(control_packet) { + if let Err(e) = self.control_reply_tx.send(control_packet) { eprintln!("Error reply: {:?}", e); } } diff --git a/src/peer.rs b/src/peer.rs index 8ec958a..16f4c5d 100644 --- a/src/peer.rs +++ b/src/peer.rs @@ -22,13 +22,14 @@ pub struct Peer { impl Peer { pub fn new( stream_ip: IpAddr, - to_routing_data: mpsc::UnboundedSender, - to_routing_control: mpsc::UnboundedSender, + router_data_tx: mpsc::UnboundedSender, + router_control_tx: mpsc::UnboundedSender, stream: TcpStream, overlay_ip: Ipv4Addr, ) -> Result> { // Framed for peer + // Used to send and receive packets from a TCP stream let mut framed = Framed::new(stream, PacketCodec::new()); // Data channel for peer let (to_peer_data, mut from_routing_data) = mpsc::unbounded_channel::(); @@ -47,23 +48,22 @@ impl Peer { Some(Ok(packet)) => { match packet { Packet::DataPacket(packet) => { - if let Err(error) = to_routing_data.send(packet){ + if let Err(error) = router_data_tx.send(packet){ eprintln!("Error sending to to_routing_data: {}", error); } } Packet::ControlPacket(packet) => { - // Parse the DataPacket into a ControlStruct - // as the to_routing_control channel expects + // Parse the DataPacket into a ControlStruct as the to_routing_control channel expects let control_struct = ControlStruct { control_packet: packet, - response_tx: control_reply_tx.clone(), + control_reply_tx: control_reply_tx.clone(), src_overlay_ip: IpAddr::V4(overlay_ip), - // note: although this control packet is received from the TCP stream - // we set the src_overlay_op to the overlay_ip of the peer + // Note: although this control packet is received from the TCP stream + // we set the src_overlay_ip to the overlay_ip of the peer // as we 'arrived' in the peer instance of representing the sending node on this current node }; - if let Err(error) = to_routing_control.send(control_struct){ + if let Err(error) = router_control_tx.send(control_struct){ eprintln!("Error sending to to_routing_control: {}", error); } diff --git a/src/peer_manager.rs b/src/peer_manager.rs index 8fcc8e9..f0fd26b 100644 --- a/src/peer_manager.rs +++ b/src/peer_manager.rs @@ -1,11 +1,11 @@ -use crate::packet::{DataPacket, ControlStruct}; -use crate::{peer::Peer}; +use crate::peer::Peer; +use crate::router::Router; use serde::Deserialize; +use tokio::net::TcpListener; use std::net::{Ipv4Addr, SocketAddr}; use std::sync::{Arc, Mutex}; use tokio::io::{AsyncReadExt, AsyncWriteExt}; -use tokio::{net::TcpStream, sync::mpsc::UnboundedSender}; -use crate::router::Router; +use tokio::{net::TcpStream}; pub const NODE_CONFIG_FILE_PATH: &str = "nodeconfig.toml"; @@ -14,34 +14,33 @@ struct PeersConfig { peers: Vec, } -#[derive(Debug, Clone)] +#[derive(Clone)] pub struct PeerManager { pub known_peers: Arc>>, // --> moet eigenlijk in router pub router: Arc, } -// PEERMANAGER HEEFT EGIENLIJK ENKEL DE TAAK OM TE CONNECTEN MET PEERS EN ZE VOLLEDIG AAN TE MAKEN -// --> ALS EEN PEER VOLLEDIG IS AANGEMAAKT MOET HIJ NAAR DE ROUTER WORDEN GESTUURD -// --> WANT DE ROUTER MOET UITEINDELIJK EEEN LIJST VAN CONNECTED_PEERS BIJHOUDEN -// --> PEERMANAGER WEL OM DE ZOVEEL TIJD EEN CHECK DOEN ALS DE PEERS NOG LEVEN (MAAR: GEBEURT MSS MET DE HELLO-IHU?) - impl PeerManager { - pub fn new() -> Self { + + pub fn new(router: Arc) -> Self { let known_peers: Vec = Vec::new(); - Self { + let peer_manager = PeerManager { known_peers: Arc::new(Mutex::new(known_peers)), - router: Arc::new(Router::new()), - } + router, + }; + + // Start a TCP listener. When a new connection is accepted, the reverse peer exchange is performed. + tokio::spawn(PeerManager::start_listener(peer_manager.clone())); + // Reads the nodeconfig.toml file and connects to the peers in the file. + tokio::spawn(PeerManager::get_peers_from_config(peer_manager.clone())); + + peer_manager } - pub async fn get_peers_from_config( - &self, - to_routing_data: UnboundedSender, - to_routing_control: UnboundedSender, - tun_addr_own_node: Ipv4Addr, - router: Arc, - ) { + // Each node has a nodeconfig.toml file which contains the underlay socket addresses of other nodes. + async fn get_peers_from_config(self) { + // Read from the nodeconfig.toml file match std::fs::read_to_string(NODE_CONFIG_FILE_PATH) { Ok(file_content) => { @@ -50,7 +49,6 @@ impl PeerManager { for peer_addr in config.peers { match TcpStream::connect(peer_addr).await { Ok(mut peer_stream) => { - //println!("TCP stream connected: {}", peer_addr); // 2. Read other node's TUN address from the stream let mut buffer = [0u8; 4]; @@ -62,20 +60,20 @@ impl PeerManager { ); // 3. Send own TUN address over the stream - let ip_bytes = tun_addr_own_node.octets(); + let ip_bytes = self.router.get_node_tun_address().octets(); peer_stream.write_all(&ip_bytes).await.unwrap(); // Create peer instance let peer_stream_ip = peer_addr.ip(); match Peer::new( peer_stream_ip, - to_routing_data.clone(), - to_routing_control.clone(), + self.router.router_data_tx.clone(), + self.router.router_control_tx.clone(), peer_stream, received_overlay_ip, ) { Ok(new_peer) => { - router.add_directly_connected_peer(new_peer); + self.router.add_directly_connected_peer(new_peer); } Err(e) => { eprintln!("Error creating peer: {}", e); @@ -83,11 +81,7 @@ impl PeerManager { } } Err(e) => { - eprintln!( - "Error connecting to TCP stream for {}: {}", - peer_addr.to_string(), - e - ); + eprintln!("Error connecting to TCP stream for {}: {}", peer_addr.to_string(), e); } } } @@ -97,4 +91,55 @@ impl PeerManager { } } } + + async fn start_listener(self) { + match TcpListener::bind("[::]:9651").await { + Ok(listener) => { + loop { + match listener.accept().await { + Ok((stream, _)) => { + PeerManager::start_reverse_peer_exchange(stream, self.router.clone()).await; + } + Err(e) => { + eprintln!("Error accepting connection: {}", e); + } + } + } + } + Err(e) => { + eprintln!("Error starting listener: {}", e); + } + } + } + + async fn start_reverse_peer_exchange(mut stream: TcpStream, router: Arc) { + + // 1. Send own TUN address over the stream + let ip_bytes = router.get_node_tun_address().octets(); + stream.write_all(&ip_bytes).await.unwrap(); + + // 2. Read other node's TUN address from the stream + let mut buffer = [0u8; 4]; + stream.read_exact(&mut buffer).await.unwrap(); + let received_overlay_ip = Ipv4Addr::from(buffer); + println!("Received overlay IP from other node: {:?}", received_overlay_ip); + + // Create new Peer instance + let peer_stream_ip = stream.peer_addr().unwrap().ip(); + let new_peer = Peer::new( + peer_stream_ip, + router.router_data_tx.clone(), + router.router_control_tx.clone(), + stream, + received_overlay_ip, + ); + match new_peer { + Ok(new_peer) => { + router.add_directly_connected_peer(new_peer); + } + Err(e) => { + eprintln!("Error creating peer: {}", e); + } + } + } } diff --git a/src/router.rs b/src/router.rs index f8a61a0..97fac94 100644 --- a/src/router.rs +++ b/src/router.rs @@ -1,88 +1,142 @@ use std::{net::{IpAddr, Ipv4Addr}, sync::{Mutex, Arc}}; -use tokio::sync::mpsc::UnboundedSender; +use tokio::sync::mpsc::{UnboundedSender, UnboundedReceiver, self}; use tokio_tun::Tun; -use crate::{peer::Peer, packet::{ControlPacket, ControlPacketType, DataPacket}}; +use crate::{peer::Peer, packet::{ControlPacket, ControlPacketType, DataPacket, ControlStruct}}; -#[derive(Debug, Clone)] +#[derive(Clone)] pub struct Router { directly_connected_peers: Arc>>, + pub router_control_tx: UnboundedSender, + pub router_data_tx: UnboundedSender, + pub node_tun: Arc, } impl Router { - pub fn new() -> Self { - Router { + pub fn new(node_tun: Arc) -> Self { + + // Tx is passed onto each new peer instance. This enables peers to send control packets to the router. + let (router_control_tx, router_control_rx) = mpsc::unbounded_channel::(); + // Tx is passed onto each new peer instance. This enables peers to send data packets to the router. + let (router_data_tx, router_data_rx) = mpsc::unbounded_channel::(); + + let router = Router { directly_connected_peers: Arc::new(Mutex::new(Vec::new())), + router_control_tx, + router_data_tx, + node_tun, + }; + + tokio::spawn(Router::start_hello_sender(router.clone())); + tokio::spawn(Router::handle_incoming_control_packets(router_control_rx)); + tokio::spawn(Router::handle_incoming_data_packets(router.clone(), router_data_rx)); + + router + } + + async fn handle_incoming_control_packets(mut router_control_rx: UnboundedReceiver) { + loop { + while let Some(control_struct) = router_control_rx.recv().await { + match control_struct.control_packet.message_type { + ControlPacketType::Hello => { + let dest_ip = control_struct.src_overlay_ip; + control_struct.reply(ControlPacket::new_ihu(10, 1000, dest_ip)); + println!("IHU {}", dest_ip); + }, + ControlPacketType::IHU => { + // Upon receiving an IHU, nothing parrticular needs to be done. + }, + _ => { + eprintln!("Unknown control packet type"); + } + } + } } } + async fn handle_incoming_data_packets(self, mut router_data_rx: UnboundedReceiver) { + // If the destination IP of the data packet matches with the IP address of this node's TUN interface + // we should forward the data packet towards the TUN interface. + // If the destination IP doesn't match, we need to lookup if we have a matching peer instance + // where the destination IP matches with the peer's overlay IP. If we do, we should forward the + // data packet to the peer's to_peer_data channel. + loop { + while let Some(data_packet) = router_data_rx.recv().await { + let dest_ip = data_packet.dest_ip; + if dest_ip == self.node_tun.address().unwrap() { + if let Err(e) = self.node_tun.send(&data_packet.raw_data).await { + eprintln!("Error sending data packet to TUN interface: {:?}", e); + } + } + else { + let matching_peer = self.get_peer_by_ip(dest_ip); + if let Some(peer) = matching_peer { + if let Err(e) = peer.to_peer_data.send(data_packet) { + eprintln!("Error sending data packet to peer: {:?}", e); + } + } else { + eprintln!("No matching peer found for data packet"); + } + } + } + } + } + + async fn start_hello_sender(self) { + loop { + tokio::time::sleep(tokio::time::Duration::from_secs(5)).await; + let hello_message = ControlPacket { + message_type: ControlPacketType::Hello, + body_length: 0, + body: Some(crate::packet::ControlPacketBody::Hello { flags: 100u16, seqno: 200u16, interval: 300u16 }), + }; + for peer in self.get_directly_connected_peers() { + println!("Hello {}", peer.overlay_ip); + if let Err(e) = peer.to_peer_control.send(hello_message.clone()) { + eprintln!("Error sending hello message to peer: {:?}", e); + } + } + } + } + + pub fn get_directly_connected_peers(&self) -> Vec { + self.directly_connected_peers.lock().unwrap().clone() + } + pub fn add_directly_connected_peer(&self, peer: Peer) { self.directly_connected_peers.lock().unwrap().push(peer); } - pub fn send_hello(&self) { - let hello_message = ControlPacket { - message_type: ControlPacketType::Hello, - body_length: 0, - body: Some(crate::packet::ControlPacketBody::Hello { flags: 100u16, seqno: 200u16, interval: 300u16 }), - }; - - // Send Hello to all directly connected peers - for peer in self.directly_connected_peers.lock().unwrap().iter() { - println!("Hello {}", peer.overlay_ip); - if let Err(e) = peer.to_peer_control.send(hello_message.clone()) { - eprintln!("Error sending hello message to peer: {:?}", e); - } + fn get_peer_by_ip (&self, peer_ip: Ipv4Addr) -> Option { + let peers = self.get_directly_connected_peers(); + let matching_peer = peers.iter().find(|peer| peer.overlay_ip == peer_ip); + + match matching_peer { + Some(peer) => Some(peer.clone()), + None => None, } } - pub fn route_data_packet(&self, data_packet: DataPacket, node_tun: Arc, to_tun: UnboundedSender) { - let dest_ip = data_packet.dest_ip; - // If the destination IP of the packets matches this node's overlay IP, we should forward it to the TUN interface. - // This is done by sending it to the to_tun sender halve of the channel. The receiver halve is read in the main loop - // and further forwards the packet towards the actual TUN interface. - if dest_ip == node_tun.address().unwrap() { - if let Err(e) = to_tun.send(data_packet) { - eprintln!("Error sending packet to to_tun: {}", e); - } - } else { - // If the destination IP of the packet does not match this node's overlay IP, we should forward it to the - // correct peer. This is done by sending the packet to the to_peer_data sender halve of the channel. The receiver - // halve is read in the peer select statement and further forwards the packet towards packet over the TCP stream. - let peer = self.get_peer_from_ip(dest_ip); - if let Some(dest_peer) = peer { - if let Err(e) = dest_peer.to_peer_data.send(data_packet) { - eprintln!("Error sending packet to peer: {}", e); - } - } - } - } - - fn get_peer_from_ip (&self, peer_ip: Ipv4Addr) -> Option { - for peer in self.directly_connected_peers.lock().unwrap().iter() { - if peer.overlay_ip == peer_ip { - return Some(peer.clone()) - } - } - return None + pub fn get_node_tun_address(&self) -> Ipv4Addr { + self.node_tun.address().unwrap() } } -struct Route { - prefix: u8, - plen: u8, - neighbour: Peer, -} +// struct Route { +// prefix: u8, +// plen: u8, +// neighbour: Peer, +// } -struct RouteEntry { - source: (u8, u8, u16), // source (prefix, plen, router-id) for which this route is advertised - neighbour: Peer, // neighbour that advertised this route - metric: u16, // metric of this route as advertised by the neighbour - seqno: u16, // sequence number of this route as advertised by the neighbour - next_hop: IpAddr, // next-hop for this route - selected: bool, // whether this route is selected +// struct RouteEntry { +// source: (u8, u8, u16), // source (prefix, plen, router-id) for which this route is advertised +// neighbour: Peer, // neighbour that advertised this route +// metric: u16, // metric of this route as advertised by the neighbour +// seqno: u16, // sequence number of this route as advertised by the neighbour +// next_hop: IpAddr, // next-hop for this route +// selected: bool, // whether this route is selected - // each route table entry needs a route expiry timer - // each route has two distinct (seqno, metric) pairs associated with it: - // 1. (seqno, metric): describes the route's distance - // 2. (seqno, metric): describes the feasibility distance (should be stored in source table and shared between all routes with the same source) -} \ No newline at end of file +// // each route table entry needs a route expiry timer +// // each route has two distinct (seqno, metric) pairs associated with it: +// // 1. (seqno, metric): describes the route's distance +// // 2. (seqno, metric): describes the feasibility distance (should be stored in source table and shared between all routes with the same source) +// } \ No newline at end of file From f3dd56af226fd152bc2abd685a87efbf69986c23 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Thu, 27 Apr 2023 11:31:38 +0000 Subject: [PATCH 12/89] update packet structure and codec to be more in line with Babel protocol --- src/codec.rs | 112 +++++++++++++++++++++++++++++++------------------- src/packet.rs | 61 ++++++++++++++++++++------- 2 files changed, 116 insertions(+), 57 deletions(-) diff --git a/src/codec.rs b/src/codec.rs index 34ddccf..e0a9473 100644 --- a/src/codec.rs +++ b/src/codec.rs @@ -1,7 +1,7 @@ use std::{io, net::{IpAddr, Ipv4Addr}}; use bytes::{BufMut, BytesMut, Buf}; use tokio_util::codec::{Encoder, Decoder}; -use crate::packet::{Packet, ControlPacket, DataPacket, PacketType, ControlPacketBody, ControlPacketType}; +use crate::packet::{Packet, ControlPacket, DataPacket, PacketType, ControlPacketBody, ControlPacketType, BabelTLVType, BabelPacketBody, BabelTLV, BabelPacketHeader}; /* ********************************PAKCET*********************************** */ pub struct PacketCodec { @@ -194,58 +194,78 @@ impl Decoder for ControlPacketCodec { type Error = std::io::Error; fn decode(&mut self, buf: &mut BytesMut) -> Result, Self::Error> { - if buf.is_empty() { + if buf.remaining() < 4 { return Ok(None); } - let message_type = match ControlPacketType::from_u8(buf.get_u8()) { - Some(t) => t, - None => return Err(io::Error::new(io::ErrorKind::InvalidData, "Invalid message type")), - }; - - if message_type == ControlPacketType::Pad1 { - return Ok(Some(ControlPacket { - message_type, - body_length: 0, - body: Some(ControlPacketBody::Pad1), - })); - } - - let body_length = buf.get_u8(); + let magic = buf.get_u8(); + let version = buf.get_u8(); + let body_length = buf.get_u16(); if buf.remaining() < body_length as usize { return Ok(None); } - let body = match message_type { - ControlPacketType::PadN => { - buf.advance(usize::from(body_length)); - Some(ControlPacketBody::PadN(body_length)) + let header = BabelPacketHeader { + magic, + version, + body_length, + }; + + let tlv_type = match BabelTLVType::from_u8(buf.get_u8()) { + Some(t) => t, + None => return Err(io::Error::new(io::ErrorKind::InvalidData, "Invalid TLV type")), + }; + + if tlv_type == BabelTLVType::Pad1 { + return Ok(Some(ControlPacket { + header, + body: Some(BabelPacketBody { + tlv_type, + length: 0, + body: BabelTLV::Pad1, + }), + })); + } + + let length = buf.get_u8(); + + let body = match tlv_type { + BabelTLVType::PadN => { + buf.advance(usize::from(length)); + Some(BabelPacketBody { + tlv_type, + length, + body: BabelTLV::PadN(length), + }) } - ControlPacketType::Hello => { + BabelTLVType::Hello => { let flags = buf.get_u16(); let seqno = buf.get_u16(); let interval = buf.get_u16(); - Some(ControlPacketBody::Hello { flags, seqno, interval }) + Some(BabelPacketBody { + tlv_type, + length, + body: BabelTLV::Hello { flags, seqno, interval }, + }) } - ControlPacketType::IHU => { + BabelTLVType::IHU => { let _address_encoding = buf.get_u8(); - // todo: based on address_encoding, we should decode the address on a different way let _reserved = buf.get_u8(); let rxcost = buf.get_u16(); let interval = buf.get_u16(); let address = IpAddr::V4(Ipv4Addr::new(buf.get_u8(), buf.get_u8(), buf.get_u8(), buf.get_u8())); - Some(ControlPacketBody::IHU { rxcost, interval, address }) + Some(BabelPacketBody { + tlv_type, + length, + body: BabelTLV::IHU { rxcost, interval, address }, + }) } - // Add decoding logic for other message types. + // Add decoding logic for other TLV types. _ => None, }; - Ok(Some(ControlPacket { - message_type, - body_length, - body, - })) + Ok(Some(ControlPacket { header, body })) } } @@ -253,23 +273,29 @@ impl Encoder for ControlPacketCodec { type Error = io::Error; fn encode(&mut self, message: ControlPacket, buf: &mut BytesMut) -> Result<(), Self::Error> { - buf.put_u8(message.message_type as u8); - buf.put_u8(message.body_length); + // Write BabelPacketHeader + buf.put_u8(message.header.magic); + buf.put_u8(message.header.version); + buf.put_u16(message.header.body_length); if let Some(body) = message.body { - match body { - ControlPacketBody::Pad1 => {} - ControlPacketBody::PadN(padding_length) => { + // Write BabelPacketBody + buf.put_u8(body.tlv_type as u8); + buf.put_u8(body.length); + + match body.body { + BabelTLV::Pad1 => {} + BabelTLV::PadN(padding_length) => { buf.put_slice(&vec![0; usize::from(padding_length)]); } - ControlPacketBody::Hello { flags, seqno, interval } => { + BabelTLV::Hello { flags, seqno, interval } => { buf.put_u16(flags); buf.put_u16(seqno); buf.put_u16(interval); } - ControlPacketBody::IHU { rxcost, interval, address } => { - buf.put_u8(0); // temp static address encoding - buf.put_u8(0); // reserved field should be set to 0 and MUST be ignored on recpetion + BabelTLV::IHU { rxcost, interval, address } => { + buf.put_u8(0); // Temporary static address encoding + buf.put_u8(0); // Reserved field should be set to 0 and MUST be ignored on reception buf.put_u16(rxcost); buf.put_u16(interval); match address { @@ -280,15 +306,15 @@ impl Encoder for ControlPacketCodec { buf.put_u8(ipv4.octets()[3]); } IpAddr::V6(_ipv6) => { - println!("IPv6 not supported yet"); + println!("IPv6 not supported yet"); } } } - // Add encoding logic for other message types. + // Add encoding logic for other TLV types. _ => {} } } Ok(()) } -} \ No newline at end of file +} diff --git a/src/packet.rs b/src/packet.rs index 88bcffc..94e8300 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -1,6 +1,9 @@ use std::net::{IpAddr, Ipv4Addr}; use tokio::sync::mpsc; +pub const BABEL_MAGIC: u8 = 42; +pub const BABEL_VERSION: u8 = 2; + /* ********************************PAKCET*********************************** */ #[derive(Debug, Clone)] pub enum Packet { @@ -33,6 +36,29 @@ pub struct ControlStruct { pub src_overlay_ip: IpAddr, } +#[derive(Debug, PartialEq, Clone)] +pub struct ControlPacket { + pub header: BabelPacketHeader, + pub body: Option, + // pub trailer: Option, +} + +#[derive(Debug, PartialEq, Clone)] +pub struct BabelPacketHeader { + pub magic: u8, + pub version: u8, + pub body_length: u16, +} + +// A BabelPacketBody describes exactly one TLV +// According to the protocol the body of a Babel packet can contain multiple subsequent TLV's --> TODO +#[derive(Debug, PartialEq, Clone)] +pub struct BabelPacketBody { + pub tlv_type: BabelTLVType, + pub length: u8, + pub body: BabelTLV, +} + impl ControlStruct { pub fn reply(self, control_packet: ControlPacket) { if let Err(e) = self.control_reply_tx.send(control_packet) { @@ -41,29 +67,36 @@ impl ControlStruct { } } -#[derive(Debug, PartialEq, Clone)] -pub struct ControlPacket { - pub message_type: ControlPacketType, - pub body_length: u8, - pub body: Option, +impl BabelPacketHeader { + pub fn new(body_length: u16) -> Self { + Self { + magic: BABEL_MAGIC, + version: BABEL_VERSION, + body_length, + } + } } + impl ControlPacket { pub fn new_ihu(rxcost: u16, interval: u16, dest_address: IpAddr) -> Self { Self { - message_type: ControlPacketType::IHU, - body_length: 10, - body: Some(ControlPacketBody::IHU { - rxcost, - interval, - address: dest_address, + header: BabelPacketHeader::new(10), + body: Some(BabelPacketBody { + tlv_type: BabelTLVType::IHU, + length: 8, + body: BabelTLV::IHU { + rxcost, + interval, + address: dest_address, + } }), } } } #[derive(Debug, PartialEq, Clone)] -pub enum ControlPacketType { +pub enum BabelTLVType { Pad1 = 0, PadN = 1, AckReq = 2, @@ -77,7 +110,7 @@ pub enum ControlPacketType { SeqnoReq = 10, } -impl ControlPacketType { +impl BabelTLVType { pub fn from_u8(value: u8) -> Option { match value { 0 => Some(Self::Pad1), @@ -97,7 +130,7 @@ impl ControlPacketType { } #[derive(Debug, Clone, PartialEq)] -pub enum ControlPacketBody { +pub enum BabelTLV { Pad1, PadN(u8), AckReq { nonce: u16, interval: u16 }, From 408819844e306e474ce8c1ad90942abe1f04cd58 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Thu, 27 Apr 2023 11:54:26 +0000 Subject: [PATCH 13/89] fixed imports, changed router function according to new packet structure --- src/codec.rs | 2 +- src/router.rs | 33 ++++++++++++++++++++++----------- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/src/codec.rs b/src/codec.rs index e0a9473..3acf52e 100644 --- a/src/codec.rs +++ b/src/codec.rs @@ -1,7 +1,7 @@ use std::{io, net::{IpAddr, Ipv4Addr}}; use bytes::{BufMut, BytesMut, Buf}; use tokio_util::codec::{Encoder, Decoder}; -use crate::packet::{Packet, ControlPacket, DataPacket, PacketType, ControlPacketBody, ControlPacketType, BabelTLVType, BabelPacketBody, BabelTLV, BabelPacketHeader}; +use crate::packet::{Packet, ControlPacket, DataPacket, PacketType, BabelTLVType, BabelPacketBody, BabelTLV, BabelPacketHeader}; /* ********************************PAKCET*********************************** */ pub struct PacketCodec { diff --git a/src/router.rs b/src/router.rs index 97fac94..55f57d9 100644 --- a/src/router.rs +++ b/src/router.rs @@ -1,7 +1,7 @@ -use std::{net::{IpAddr, Ipv4Addr}, sync::{Mutex, Arc}}; +use std::{net::{Ipv4Addr}, sync::{Mutex, Arc}}; use tokio::sync::mpsc::{UnboundedSender, UnboundedReceiver, self}; use tokio_tun::Tun; -use crate::{peer::Peer, packet::{ControlPacket, ControlPacketType, DataPacket, ControlStruct}}; +use crate::{peer::Peer, packet::{ControlPacket, DataPacket, ControlStruct, BabelTLVType, BabelPacketHeader, BabelPacketBody, BabelTLV}}; #[derive(Clone)] pub struct Router { @@ -34,16 +34,17 @@ impl Router { } async fn handle_incoming_control_packets(mut router_control_rx: UnboundedReceiver) { - loop { - while let Some(control_struct) = router_control_rx.recv().await { - match control_struct.control_packet.message_type { - ControlPacketType::Hello => { + loop { + while let Some(control_struct) = router_control_rx.recv().await { + if let Some(body) = &control_struct.control_packet.body { + match body.tlv_type { + BabelTLVType::Hello => { let dest_ip = control_struct.src_overlay_ip; control_struct.reply(ControlPacket::new_ihu(10, 1000, dest_ip)); println!("IHU {}", dest_ip); }, - ControlPacketType::IHU => { - // Upon receiving an IHU, nothing parrticular needs to be done. + BabelTLVType::IHU => { + // Upon receiving an IHU, nothing particular needs to be done. }, _ => { eprintln!("Unknown control packet type"); @@ -51,6 +52,7 @@ impl Router { } } } + } } async fn handle_incoming_data_packets(self, mut router_data_rx: UnboundedReceiver) { @@ -84,11 +86,20 @@ impl Router { async fn start_hello_sender(self) { loop { tokio::time::sleep(tokio::time::Duration::from_secs(5)).await; + let hello_message = ControlPacket { - message_type: ControlPacketType::Hello, - body_length: 0, - body: Some(crate::packet::ControlPacketBody::Hello { flags: 100u16, seqno: 200u16, interval: 300u16 }), + header: BabelPacketHeader::new(8), + body: Some(BabelPacketBody { + tlv_type: BabelTLVType::Hello, + length: 8, + body: BabelTLV::Hello { + flags: 100u16, + seqno: 200u16, + interval: 300u16, + }, + }), }; + for peer in self.get_directly_connected_peers() { println!("Hello {}", peer.overlay_ip); if let Err(e) = peer.to_peer_control.send(hello_message.clone()) { From bbb96fc5e61b623e36af4242fb46bdb1e73b1b1b Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Thu, 27 Apr 2023 15:22:53 +0000 Subject: [PATCH 14/89] measure time between Hello and IHU v1 --- src/packet.rs | 15 ++++-- src/peer.rs | 7 +++ src/router.rs | 126 +++++++++++++++++++++++++++++++------------------- 3 files changed, 96 insertions(+), 52 deletions(-) diff --git a/src/packet.rs b/src/packet.rs index 94e8300..d3b69ac 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -51,7 +51,7 @@ pub struct BabelPacketHeader { } // A BabelPacketBody describes exactly one TLV -// According to the protocol the body of a Babel packet can contain multiple subsequent TLV's --> TODO +// TODO: According to the protocol the body of a Babel packet can contain multiple subsequent TLV's #[derive(Debug, PartialEq, Clone)] pub struct BabelPacketBody { pub tlv_type: BabelTLVType, @@ -133,7 +133,10 @@ impl BabelTLVType { pub enum BabelTLV { Pad1, PadN(u8), - AckReq { nonce: u16, interval: u16 }, + AckReq { + nonce: u16, + interval: u16 + }, Ack { nonce: u16 }, Hello { flags: u16, @@ -148,11 +151,13 @@ pub enum BabelTLV { RouterID { router_id: u16 }, NextHop { address: IpAddr }, Update { - address: IpAddr, - prefix: u8, + address_encoding: u8, + prefix_length: u8, + ommited: u8, + interval: u16, seqno: u16, metric: u16, - interval: u16, + prefix: Vec, }, RouteReq { prefix: IpAddr, plen: u8 }, SeqnoReq { diff --git a/src/peer.rs b/src/peer.rs index 16f4c5d..40a1548 100644 --- a/src/peer.rs +++ b/src/peer.rs @@ -17,6 +17,8 @@ pub struct Peer { pub to_peer_data: mpsc::UnboundedSender, pub to_peer_control: mpsc::UnboundedSender, pub overlay_ip: Ipv4Addr, + + pub last_sent_hello_seqno: u16, } impl Peer { @@ -26,6 +28,7 @@ impl Peer { router_control_tx: mpsc::UnboundedSender, stream: TcpStream, overlay_ip: Ipv4Addr, + ) -> Result> { // Framed for peer @@ -38,6 +41,9 @@ impl Peer { // Control reply channel for peer let (control_reply_tx, mut control_reply_rx) = mpsc::unbounded_channel::(); + // Initialize last_sent_hello_seqno to 0 + let last_sent_hello_seqno = 0; + tokio::spawn(async move { loop { select! { @@ -107,6 +113,7 @@ impl Peer { to_peer_data, to_peer_control, overlay_ip, + last_sent_hello_seqno, }) } } diff --git a/src/router.rs b/src/router.rs index 55f57d9..4a05755 100644 --- a/src/router.rs +++ b/src/router.rs @@ -1,7 +1,16 @@ -use std::{net::{Ipv4Addr}, sync::{Mutex, Arc}}; -use tokio::sync::mpsc::{UnboundedSender, UnboundedReceiver, self}; +use crate::{ + packet::{ + BabelPacketBody, BabelPacketHeader, BabelTLV, BabelTLVType, ControlPacket, ControlStruct, + DataPacket, + }, + peer::Peer, +}; +use std::{ + net::{Ipv4Addr, IpAddr}, + sync::{Arc, Mutex}, collections::HashMap, +}; +use tokio::sync::mpsc::{self, UnboundedReceiver, UnboundedSender}; use tokio_tun::Tun; -use crate::{peer::Peer, packet::{ControlPacket, DataPacket, ControlStruct, BabelTLVType, BabelPacketHeader, BabelPacketBody, BabelTLV}}; #[derive(Clone)] pub struct Router { @@ -9,11 +18,12 @@ pub struct Router { pub router_control_tx: UnboundedSender, pub router_data_tx: UnboundedSender, pub node_tun: Arc, + + pub sent_hello_timestamps: Arc>> } impl Router { pub fn new(node_tun: Arc) -> Self { - // Tx is passed onto each new peer instance. This enables peers to send control packets to the router. let (router_control_tx, router_control_rx) = mpsc::unbounded_channel::(); // Tx is passed onto each new peer instance. This enables peers to send data packets to the router. @@ -22,37 +32,53 @@ impl Router { let router = Router { directly_connected_peers: Arc::new(Mutex::new(Vec::new())), router_control_tx, - router_data_tx, + router_data_tx, node_tun, + sent_hello_timestamps: Arc::new(Mutex::new(HashMap::new())), }; - tokio::spawn(Router::start_hello_sender(router.clone())); - tokio::spawn(Router::handle_incoming_control_packets(router_control_rx)); - tokio::spawn(Router::handle_incoming_data_packets(router.clone(), router_data_rx)); + tokio::spawn(Router::start_hello_sender(router.clone(), router.sent_hello_timestamps.clone())); + tokio::spawn(Router::handle_incoming_control_packets(router_control_rx, router.sent_hello_timestamps.clone())); + tokio::spawn(Router::handle_incoming_data_packets( + router.clone(), + router_data_rx, + )); router } - async fn handle_incoming_control_packets(mut router_control_rx: UnboundedReceiver) { - loop { - while let Some(control_struct) = router_control_rx.recv().await { - if let Some(body) = &control_struct.control_packet.body { - match body.tlv_type { - BabelTLVType::Hello => { - let dest_ip = control_struct.src_overlay_ip; - control_struct.reply(ControlPacket::new_ihu(10, 1000, dest_ip)); - println!("IHU {}", dest_ip); - }, - BabelTLVType::IHU => { - // Upon receiving an IHU, nothing particular needs to be done. - }, - _ => { - eprintln!("Unknown control packet type"); + async fn handle_incoming_control_packets( + mut router_control_rx: UnboundedReceiver, + sent_hello_timestamps: Arc>>, + ) { + loop { + while let Some(control_struct) = router_control_rx.recv().await { + if let Some(body) = &control_struct.control_packet.body { + match body.tlv_type { + BabelTLVType::Hello => { + let dest_ip = control_struct.src_overlay_ip; + control_struct.reply(ControlPacket::new_ihu(10, 1000, dest_ip)); + println!("IHU {}", dest_ip); + } + BabelTLVType::IHU => { + // Upon receiving an IHU message, we should read the time difference between the + // time the Hello message (with the same seqno) was sent and the time the IHU message + // was received. This time difference is the link cost between this node and the peer that + // sent the IHU message. + if let Some(timestamp) = sent_hello_timestamps.lock().unwrap().get(&control_struct.src_overlay_ip) { + let time_diff = tokio::time::Instant::now().duration_since(*timestamp); + println!("Time difference (ms): {}", time_diff.as_millis()); + } else { + eprintln!("No matching Hello message found for received IHU"); + } + } + _ => { + eprintln!("Unknown control packet type"); + } } } } } - } } async fn handle_incoming_data_packets(self, mut router_data_rx: UnboundedReceiver) { @@ -68,9 +94,8 @@ impl Router { if let Err(e) = self.node_tun.send(&data_packet.raw_data).await { eprintln!("Error sending data packet to TUN interface: {:?}", e); } - } - else { - let matching_peer = self.get_peer_by_ip(dest_ip); + } else { + let matching_peer = self.get_peer_by_ip(dest_ip); if let Some(peer) = matching_peer { if let Err(e) = peer.to_peer_data.send(data_packet) { eprintln!("Error sending data packet to peer: {:?}", e); @@ -83,26 +108,33 @@ impl Router { } } - async fn start_hello_sender(self) { + async fn start_hello_sender(self, sent_hello_timestamps: Arc>>) { loop { tokio::time::sleep(tokio::time::Duration::from_secs(5)).await; - let hello_message = ControlPacket { - header: BabelPacketHeader::new(8), - body: Some(BabelPacketBody { - tlv_type: BabelTLVType::Hello, - length: 8, - body: BabelTLV::Hello { - flags: 100u16, - seqno: 200u16, - interval: 300u16, - }, - }), - }; + for mut peer in self.get_directly_connected_peers() { - for peer in self.get_directly_connected_peers() { - println!("Hello {}", peer.overlay_ip); - if let Err(e) = peer.to_peer_control.send(hello_message.clone()) { + let hello_message = ControlPacket { + header: BabelPacketHeader::new(7), + body: Some(BabelPacketBody { + tlv_type: BabelTLVType::Hello, + length: 7, + body: BabelTLV::Hello { + flags: 99u16, + seqno: peer.last_sent_hello_seqno + 1, + interval: 299u16, + }, + }), + }; + // Update the last sent hello seqno for this peer. + peer.last_sent_hello_seqno += 1; + + // Store the current timestamp for this Hello message. + let current_timestamp = tokio::time::Instant::now(); + sent_hello_timestamps.lock().unwrap().insert(IpAddr::V4(peer.overlay_ip), current_timestamp); + + println!("Hello({}) {}", peer.last_sent_hello_seqno, peer.overlay_ip); + if let Err(e) = peer.to_peer_control.send(hello_message.clone()) { eprintln!("Error sending hello message to peer: {:?}", e); } } @@ -117,10 +149,10 @@ impl Router { self.directly_connected_peers.lock().unwrap().push(peer); } - fn get_peer_by_ip (&self, peer_ip: Ipv4Addr) -> Option { + fn get_peer_by_ip(&self, peer_ip: Ipv4Addr) -> Option { let peers = self.get_directly_connected_peers(); let matching_peer = peers.iter().find(|peer| peer.overlay_ip == peer_ip); - + match matching_peer { Some(peer) => Some(peer.clone()), None => None, @@ -141,7 +173,7 @@ impl Router { // struct RouteEntry { // source: (u8, u8, u16), // source (prefix, plen, router-id) for which this route is advertised // neighbour: Peer, // neighbour that advertised this route -// metric: u16, // metric of this route as advertised by the neighbour +// metric: u16, // metric of this route as advertised by the neighbour // seqno: u16, // sequence number of this route as advertised by the neighbour // next_hop: IpAddr, // next-hop for this route // selected: bool, // whether this route is selected @@ -150,4 +182,4 @@ impl Router { // // each route has two distinct (seqno, metric) pairs associated with it: // // 1. (seqno, metric): describes the route's distance // // 2. (seqno, metric): describes the feasibility distance (should be stored in source table and shared between all routes with the same source) -// } \ No newline at end of file +// } From a9fd3a55cb0b0fcd2b9190741b85062c6a9dace9 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Thu, 27 Apr 2023 15:29:18 +0000 Subject: [PATCH 15/89] measure time between Hello and IHU v2 --- src/peer.rs | 5 +++++ src/router.rs | 7 +++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/peer.rs b/src/peer.rs index 40a1548..9df3f58 100644 --- a/src/peer.rs +++ b/src/peer.rs @@ -116,4 +116,9 @@ impl Peer { last_sent_hello_seqno, }) } + + pub fn increase_hello_seqno(&mut self) { + self.last_sent_hello_seqno += 1; + println!("last hello seqno increasted to {}", self.last_sent_hello_seqno); + } } diff --git a/src/router.rs b/src/router.rs index 4a05755..cb1a967 100644 --- a/src/router.rs +++ b/src/router.rs @@ -121,14 +121,11 @@ impl Router { length: 7, body: BabelTLV::Hello { flags: 99u16, - seqno: peer.last_sent_hello_seqno + 1, + seqno: peer.last_sent_hello_seqno, interval: 299u16, }, }), }; - // Update the last sent hello seqno for this peer. - peer.last_sent_hello_seqno += 1; - // Store the current timestamp for this Hello message. let current_timestamp = tokio::time::Instant::now(); sent_hello_timestamps.lock().unwrap().insert(IpAddr::V4(peer.overlay_ip), current_timestamp); @@ -137,6 +134,8 @@ impl Router { if let Err(e) = peer.to_peer_control.send(hello_message.clone()) { eprintln!("Error sending hello message to peer: {:?}", e); } + + peer.increase_hello_seqno(); } } } From f08dcdb9c683fecc38fa871ffb00b849b52ed662 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Thu, 27 Apr 2023 15:33:47 +0000 Subject: [PATCH 16/89] measure time between Hello and IHU v3 --- src/peer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/peer.rs b/src/peer.rs index 9df3f58..c5bdf98 100644 --- a/src/peer.rs +++ b/src/peer.rs @@ -118,7 +118,7 @@ impl Peer { } pub fn increase_hello_seqno(&mut self) { - self.last_sent_hello_seqno += 1; + self.last_sent_hello_seqno = self.last_sent_hello_seqno + 1; println!("last hello seqno increasted to {}", self.last_sent_hello_seqno); } } From f1e219f6ceb62720cb20a7a49a66905f4ddc51bb Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Thu, 27 Apr 2023 15:50:30 +0000 Subject: [PATCH 17/89] measure time between Hello and IHU v4 --- src/router.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/router.rs b/src/router.rs index cb1a967..af138cc 100644 --- a/src/router.rs +++ b/src/router.rs @@ -112,7 +112,7 @@ impl Router { loop { tokio::time::sleep(tokio::time::Duration::from_secs(5)).await; - for mut peer in self.get_directly_connected_peers() { + for peer in self.directly_connected_peers.lock().unwrap().iter_mut() { let hello_message = ControlPacket { header: BabelPacketHeader::new(7), From 4d4cc855a8cba896f2e7a0cddf2b3040a17a527b Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Wed, 3 May 2023 17:05:07 +0000 Subject: [PATCH 18/89] added routing table and source table v1 --- src/main.rs | 4 +- src/packet.rs | 2 +- src/peer.rs | 4 + src/peer_manager.rs | 3 - src/router.rs | 173 +++++++++++++++++++++++++++++++++++-------- src/routing_table.rs | 59 +++++++++++++++ src/source_table.rs | 40 ++++++++++ 7 files changed, 249 insertions(+), 36 deletions(-) create mode 100644 src/routing_table.rs create mode 100644 src/source_table.rs diff --git a/src/main.rs b/src/main.rs index 970f61a..ab02174 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,6 +10,8 @@ mod packet; mod peer; mod peer_manager; mod router; +mod routing_table; +mod source_table; const LINK_MTU: usize = 1500; @@ -37,7 +39,7 @@ async fn main() -> Result<(), Box> { // Creating a new Router instance let router = Arc::new(router::Router::new(node_tun.clone())); // Creating a new PeerManager instance - let _peer_manager = peer_manager::PeerManager::new(router.clone()); + let _peer_manager: peer_manager::PeerManager = peer_manager::PeerManager::new(router.clone()); // The TUN interface will only receive data packets. This loops reads data packets from the TUN interface and forwards them to the router. diff --git a/src/packet.rs b/src/packet.rs index d3b69ac..e093c2a 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -157,7 +157,7 @@ pub enum BabelTLV { interval: u16, seqno: u16, metric: u16, - prefix: Vec, + prefix: IpAddr, }, RouteReq { prefix: IpAddr, plen: u8 }, SeqnoReq { diff --git a/src/peer.rs b/src/peer.rs index c5bdf98..2137e53 100644 --- a/src/peer.rs +++ b/src/peer.rs @@ -19,6 +19,7 @@ pub struct Peer { pub overlay_ip: Ipv4Addr, pub last_sent_hello_seqno: u16, + pub link_cost: u16, } impl Peer { @@ -43,6 +44,8 @@ impl Peer { // Initialize last_sent_hello_seqno to 0 let last_sent_hello_seqno = 0; + // Initialize last_path_cost to infinity + let link_cost = 65535; tokio::spawn(async move { loop { @@ -114,6 +117,7 @@ impl Peer { to_peer_control, overlay_ip, last_sent_hello_seqno, + link_cost, }) } diff --git a/src/peer_manager.rs b/src/peer_manager.rs index f0fd26b..30b10ba 100644 --- a/src/peer_manager.rs +++ b/src/peer_manager.rs @@ -16,17 +16,14 @@ struct PeersConfig { #[derive(Clone)] pub struct PeerManager { - pub known_peers: Arc>>, // --> moet eigenlijk in router pub router: Arc, } impl PeerManager { pub fn new(router: Arc) -> Self { - let known_peers: Vec = Vec::new(); let peer_manager = PeerManager { - known_peers: Arc::new(Mutex::new(known_peers)), router, }; diff --git a/src/router.rs b/src/router.rs index af138cc..ec17cd7 100644 --- a/src/router.rs +++ b/src/router.rs @@ -4,10 +4,13 @@ use crate::{ DataPacket, }, peer::Peer, + routing_table::{RoutingTable, RouteKey, RouteEntry}, + source_table::{SourceTable, SourceKey, SourceEntry}, }; use std::{ - net::{Ipv4Addr, IpAddr}, - sync::{Arc, Mutex}, collections::HashMap, + collections::HashMap, + net::{IpAddr, Ipv4Addr}, + sync::{Arc, Mutex}, }; use tokio::sync::mpsc::{self, UnboundedReceiver, UnboundedSender}; use tokio_tun::Tun; @@ -19,7 +22,9 @@ pub struct Router { pub router_data_tx: UnboundedSender, pub node_tun: Arc, - pub sent_hello_timestamps: Arc>> + pub sent_hello_timestamps: Arc>>, + pub routing_table: Arc>, + pub source_table: Arc>, } impl Router { @@ -35,19 +40,30 @@ impl Router { router_data_tx, node_tun, sent_hello_timestamps: Arc::new(Mutex::new(HashMap::new())), + routing_table: Arc::new(Mutex::new(RoutingTable::new())), + source_table: Arc::new(Mutex::new(SourceTable::new())), }; - tokio::spawn(Router::start_hello_sender(router.clone(), router.sent_hello_timestamps.clone())); - tokio::spawn(Router::handle_incoming_control_packets(router_control_rx, router.sent_hello_timestamps.clone())); + tokio::spawn(Router::start_hello_sender( + router.clone(), + router.sent_hello_timestamps.clone(), + )); + tokio::spawn(Router::handle_incoming_control_packets( + router.clone(), + router_control_rx, + router.sent_hello_timestamps.clone(), + )); tokio::spawn(Router::handle_incoming_data_packets( router.clone(), router_data_rx, )); + tokio::spawn(Router::start_routing_table_updater(router.clone())); router } async fn handle_incoming_control_packets( + self, mut router_control_rx: UnboundedReceiver, sent_hello_timestamps: Arc>>, ) { @@ -65,9 +81,22 @@ impl Router { // time the Hello message (with the same seqno) was sent and the time the IHU message // was received. This time difference is the link cost between this node and the peer that // sent the IHU message. - if let Some(timestamp) = sent_hello_timestamps.lock().unwrap().get(&control_struct.src_overlay_ip) { - let time_diff = tokio::time::Instant::now().duration_since(*timestamp); - println!("Time difference (ms): {}", time_diff.as_millis()); + if let Some(timestamp) = sent_hello_timestamps + .lock() + .unwrap() + .get(&control_struct.src_overlay_ip) + { + let time_diff = + tokio::time::Instant::now().duration_since(*timestamp); + let sender_peer_ip = control_struct + .src_overlay_ip + .to_string() + .parse::() + .unwrap(); + self.update_peer_link_cost( + sender_peer_ip, + time_diff.as_millis() as u16, + ); } else { eprintln!("No matching Hello message found for received IHU"); } @@ -108,12 +137,14 @@ impl Router { } } - async fn start_hello_sender(self, sent_hello_timestamps: Arc>>) { + async fn start_hello_sender( + self, + sent_hello_timestamps: Arc>>, + ) { loop { tokio::time::sleep(tokio::time::Duration::from_secs(5)).await; for peer in self.directly_connected_peers.lock().unwrap().iter_mut() { - let hello_message = ControlPacket { header: BabelPacketHeader::new(7), body: Some(BabelPacketBody { @@ -128,7 +159,10 @@ impl Router { }; // Store the current timestamp for this Hello message. let current_timestamp = tokio::time::Instant::now(); - sent_hello_timestamps.lock().unwrap().insert(IpAddr::V4(peer.overlay_ip), current_timestamp); + sent_hello_timestamps + .lock() + .unwrap() + .insert(IpAddr::V4(peer.overlay_ip), current_timestamp); println!("Hello({}) {}", peer.last_sent_hello_seqno, peer.overlay_ip); if let Err(e) = peer.to_peer_control.send(hello_message.clone()) { @@ -140,6 +174,51 @@ impl Router { } } + // create the function for a task that will loop over the directly connected peers and create routing table entries for them + // 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 we can create a routing table entry + async fn start_routing_table_updater(self) { + loop { + tokio::time::sleep(tokio::time::Duration::from_secs(5)).await; + + for peer in self.directly_connected_peers.lock().unwrap().iter_mut() { + if peer.link_cost < 65535 { + // before we can create a routing table entry, we need to create a source table entry + let source_key = SourceKey { + prefix: IpAddr::V4(peer.overlay_ip), + plen: 32, // we set the prefix length to 32 for now, this means that each peer is a /32 network (so only route to the peer itself) + router_id: 0 // we set all router ids to 0 temporarily + }; + let source_entry = SourceEntry { + metric: peer.link_cost, + seqno: 0, // we set the seqno to 0 for now + }; + // create the source table entry + let source_key_clone = source_key.clone(); + self.source_table.lock().unwrap().insert(source_key, source_entry); + + // now we can create the routing table entry + let route_key = RouteKey { + prefix: IpAddr::V4(peer.overlay_ip), + plen: 32, // we set the prefix length to 32 for now, this means that each peer is a /32 network (so only route to the peer itself) + neighbor: IpAddr::V4(peer.overlay_ip), + }; + let route_entry = RouteEntry { + source: source_key_clone, + neighbor: peer.clone(), + metric: peer.link_cost, + 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 + }; + // create the routing table entry + self.routing_table.lock().unwrap().insert(route_key, route_entry); + } + } + } + } + + pub fn get_directly_connected_peers(&self) -> Vec { self.directly_connected_peers.lock().unwrap().clone() } @@ -161,24 +240,56 @@ impl Router { pub fn get_node_tun_address(&self) -> Ipv4Addr { self.node_tun.address().unwrap() } + + pub fn update_peer_link_cost(&self, peer_ip: Ipv4Addr, link_cost: u16) { + let mut peers = self.directly_connected_peers.lock().unwrap(); + let matching_peer = peers.iter_mut().find(|peer| peer.overlay_ip == peer_ip); + + match matching_peer { + Some(peer) => { + // Only update the link cost if the new link cost is lower than the current link cost + if link_cost < peer.link_cost { + peer.link_cost = link_cost; + println!("Link cost to {} updated to {}", peer_ip, link_cost); + } + } + None => { + eprintln!("No matching peer found for link cost update"); + } + } + } + + pub fn is_update_feasible( + // update is tuple of (prefix, prefix_length, router_id, seqno, metric) + received_update: &(IpAddr, u8, u64, u16, u16), + source_table: &SourceTable, + ) -> bool { + let (prefix, plen, router_id, seqno, metric) = received_update; + let source_key = SourceKey { + prefix: *prefix, + plen: *plen, + router_id: *router_id, + }; + + // If the received metric is infinite, it's always feasible + // An update with an infinite metric is considered a retraction + // Retractions are used to notify neighbors that a previously advertised route is no longer available + if *metric == u16::MAX { + return true; + } + + match source_table.get(&source_key) { + None => { + // If there's no entry in the source table, the update is feasible + true + } + Some(source_entry) => { + // If an entry exists in the source table, compare seqno and metric + let (seqno_2, metric_2) = (&source_entry.seqno, &source_entry.metric); + + // Check feasibility conditions + seqno > seqno_2 || (seqno == seqno_2 && metric < metric_2) + } + } + } } - -// struct Route { -// prefix: u8, -// plen: u8, -// neighbour: Peer, -// } - -// struct RouteEntry { -// source: (u8, u8, u16), // source (prefix, plen, router-id) for which this route is advertised -// neighbour: Peer, // neighbour that advertised this route -// metric: u16, // metric of this route as advertised by the neighbour -// seqno: u16, // sequence number of this route as advertised by the neighbour -// next_hop: IpAddr, // next-hop for this route -// selected: bool, // whether this route is selected - -// // each route table entry needs a route expiry timer -// // each route has two distinct (seqno, metric) pairs associated with it: -// // 1. (seqno, metric): describes the route's distance -// // 2. (seqno, metric): describes the feasibility distance (should be stored in source table and shared between all routes with the same source) -// } diff --git a/src/routing_table.rs b/src/routing_table.rs new file mode 100644 index 0000000..51af664 --- /dev/null +++ b/src/routing_table.rs @@ -0,0 +1,59 @@ +use std::{net::IpAddr, collections::HashMap}; + +use crate::{source_table::SourceKey, peer::Peer}; + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct RouteKey { + pub prefix: IpAddr, + pub plen: u8, + pub neighbor: IpAddr, +} + +#[derive(Debug, Clone)] +pub struct RouteEntry { + pub source: SourceKey, + pub neighbor: Peer, + pub metric: u16, // If metric is 0xFFFF, the route has recently been retracted + pub seqno: u16, + pub next_hop: IpAddr, // This is the Peer's address + pub selected: bool, + // route_timer +} + +#[derive(Debug, Clone)] +pub struct RoutingTable { + pub table: HashMap, +} + +impl RoutingTable { + pub fn new() -> Self { + Self { + table: HashMap::new(), + } + } + + pub fn insert(&mut self, key: RouteKey, entry: RouteEntry) { + self.table.insert(key, entry); + println!("Added route to routing table: {:?}", self.table); + } + + pub fn remove(&mut self, key: &RouteKey) { + self.table.remove(key); + } + + pub fn get(&self, key: &RouteKey) -> Option<&RouteEntry> { + self.table.get(key) + } +} + +// TODO: add support of suprious starvation detection +pub fn select_best_route(routes: &[RouteEntry]) -> Option<&RouteEntry> { + //routes.iter().min_by_key(|route| (route.metric, route.router_id)) + todo!("select_best_route") +} + + + + + + diff --git a/src/source_table.rs b/src/source_table.rs new file mode 100644 index 0000000..8f17331 --- /dev/null +++ b/src/source_table.rs @@ -0,0 +1,40 @@ +use std::{net::IpAddr, collections::HashMap}; + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct SourceKey { + pub prefix: IpAddr, + pub plen: u8, + pub router_id: u64, // We temporarily use 100 for all router IDs +} + +#[derive(Debug, Clone)] +pub struct SourceEntry { + pub metric: u16, + pub seqno: u16, + // source_timer +} + +// Used to store the feasibility distances +pub struct SourceTable { + pub table: HashMap, +} + +impl SourceTable { + pub fn new() -> Self { + Self { + table: HashMap::new(), + } + } + + pub fn insert(&mut self, key: SourceKey, entry: SourceEntry) { + self.table.insert(key, entry); + } + + pub fn remove(&mut self, key: &SourceKey) { + self.table.remove(key); + } + + pub fn get(&self, key: &SourceKey) -> Option<&SourceEntry> { + self.table.get(key) + } +} \ No newline at end of file From 95158c3a04f994f3bda63efd85606bb39ab0e850 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Wed, 3 May 2023 17:11:27 +0000 Subject: [PATCH 19/89] added routing table and source table v2 --- src/router.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/router.rs b/src/router.rs index ec17cd7..b246484 100644 --- a/src/router.rs +++ b/src/router.rs @@ -182,7 +182,7 @@ impl Router { tokio::time::sleep(tokio::time::Duration::from_secs(5)).await; for peer in self.directly_connected_peers.lock().unwrap().iter_mut() { - if peer.link_cost < 65535 { + if peer.link_cost != 65535 { // before we can create a routing table entry, we need to create a source table entry let source_key = SourceKey { prefix: IpAddr::V4(peer.overlay_ip), From f5795d16b23b5e62a71acf846878adfe712c517b Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Wed, 3 May 2023 17:14:04 +0000 Subject: [PATCH 20/89] added routing table and source table v3 --- src/router.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/router.rs b/src/router.rs index b246484..54d144f 100644 --- a/src/router.rs +++ b/src/router.rs @@ -176,13 +176,13 @@ impl Router { // create the function for a task that will loop over the directly connected peers and create routing table entries for them // 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 we can create a routing table entry + // the link cost has been set to a lower value, indicating that the peer is reachable and a routing table entry exits already async fn start_routing_table_updater(self) { loop { tokio::time::sleep(tokio::time::Duration::from_secs(5)).await; for peer in self.directly_connected_peers.lock().unwrap().iter_mut() { - if peer.link_cost != 65535 { + if peer.link_cost == 65535 { // before we can create a routing table entry, we need to create a source table entry let source_key = SourceKey { prefix: IpAddr::V4(peer.overlay_ip), From 054b05540b97fc2a44273f5bd7c78ce55257b6a6 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Fri, 5 May 2023 14:40:59 +0000 Subject: [PATCH 21/89] adding updates messages v1 --- src/codec.rs | 1 + src/packet.rs | 1 - src/router.rs | 42 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/codec.rs b/src/codec.rs index 3acf52e..153b72a 100644 --- a/src/codec.rs +++ b/src/codec.rs @@ -36,6 +36,7 @@ impl Decoder for PacketCodec { } let packet_type_byte = src.get_u8(); // ! This will advance the buffer 1 byte ! + println!("received packet with packet_type_byte: {}", packet_type_byte); let packet_type = match packet_type_byte { 0 => PacketType::DataPacket, 1 => PacketType::ControlPacket, diff --git a/src/packet.rs b/src/packet.rs index e093c2a..eea4b33 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -153,7 +153,6 @@ pub enum BabelTLV { Update { address_encoding: u8, prefix_length: u8, - ommited: u8, interval: u16, seqno: u16, metric: u16, diff --git a/src/router.rs b/src/router.rs index 54d144f..9e16697 100644 --- a/src/router.rs +++ b/src/router.rs @@ -59,6 +59,8 @@ impl Router { )); tokio::spawn(Router::start_routing_table_updater(router.clone())); + tokio::spawn(Router::propagate_updates(router.clone())); + router } @@ -217,6 +219,46 @@ impl Router { } } } + + // routing table updates are send periodically to all directly connected peers + // they can also be send when a change in the network topology occurs + // updates are used to advertise new routes or the retract existing routes (retracting when the metric is set to 0xFFFF) + async fn propagate_updates(self) { + loop { + tokio::time::sleep(tokio::time::Duration::from_secs(10)).await; + + let connected_peers = self.directly_connected_peers.lock().unwrap(); + let connected_peers_cloned: Vec<&Peer> = connected_peers.iter().collect(); + + let routing_table = self.routing_table.lock().unwrap(); + for (key, value) in routing_table.table.iter() { + // create update message and send to all peers + let update = BabelTLV::Update { + address_encoding: 1, // AE of 1 indicated IPv4 + prefix_length: 32, // temp value - working with full IPv4 for now, not prefix-based + interval: 999, // temp value + seqno: 0, // temp value + metric: value.metric, + prefix: key.prefix, + }; + + for peer in &connected_peers_cloned { + let control_packet = ControlPacket{ + header: BabelPacketHeader::new(14), + body: Some(BabelPacketBody { + tlv_type: BabelTLVType::Update, + length: 14, + body: update.clone(), + }), + }; + println!("Sending route as control packet to {}: {:?}", peer.overlay_ip, control_packet); + peer.to_peer_control.send(control_packet).unwrap(); + } + + + } + } + } pub fn get_directly_connected_peers(&self) -> Vec { From 7cdf8fe4b218495d07a3c31714d38088ee8793d9 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Fri, 5 May 2023 18:39:16 +0000 Subject: [PATCH 22/89] adding updates messages v2 --- src/codec.rs | 48 ++++++++++++++++++++++++++++++++++++++-- src/main.rs | 8 +++++-- src/peer_manager.rs | 54 ++++++++++++++++++++++++++++++++++++++++++++- src/router.rs | 52 ++++++++++++++++++++++--------------------- 4 files changed, 132 insertions(+), 30 deletions(-) diff --git a/src/codec.rs b/src/codec.rs index 153b72a..fdd5611 100644 --- a/src/codec.rs +++ b/src/codec.rs @@ -1,4 +1,4 @@ -use std::{io, net::{IpAddr, Ipv4Addr}}; +use std::{io, net::{IpAddr, Ipv4Addr, Ipv6Addr}}; use bytes::{BufMut, BytesMut, Buf}; use tokio_util::codec::{Encoder, Decoder}; use crate::packet::{Packet, ControlPacket, DataPacket, PacketType, BabelTLVType, BabelPacketBody, BabelTLV, BabelPacketHeader}; @@ -36,7 +36,6 @@ impl Decoder for PacketCodec { } let packet_type_byte = src.get_u8(); // ! This will advance the buffer 1 byte ! - println!("received packet with packet_type_byte: {}", packet_type_byte); let packet_type = match packet_type_byte { 0 => PacketType::DataPacket, 1 => PacketType::ControlPacket, @@ -262,6 +261,33 @@ impl Decoder for ControlPacketCodec { body: BabelTLV::IHU { rxcost, interval, address }, }) } + BabelTLVType::Update => { + println!("UPDATE received, trying to decode now..."); + let address_encoding = buf.get_u8(); + let prefix_length = buf.get_u8(); + let interval = buf.get_u16(); + let seqno = buf.get_u16(); + let metric = buf.get_u16(); + let prefix = match address_encoding { + 0 => IpAddr::V4(Ipv4Addr::new(buf.get_u8(), buf.get_u8(), buf.get_u8(), buf.get_u8())), + 1 => IpAddr::V6(Ipv6Addr::new( + buf.get_u16(), + buf.get_u16(), + buf.get_u16(), + buf.get_u16(), + buf.get_u16(), + buf.get_u16(), + buf.get_u16(), + buf.get_u16(), + )), + _ => return Err(io::Error::new(io::ErrorKind::InvalidData, "Invalid address encoding")), + }; + Some(BabelPacketBody { + tlv_type, + length, + body: BabelTLV::Update { address_encoding, prefix_length, interval, seqno, metric, prefix } + }) + } // Add decoding logic for other TLV types. _ => None, }; @@ -311,6 +337,24 @@ impl Encoder for ControlPacketCodec { } } } + BabelTLV::Update { address_encoding, prefix_length, interval, seqno, metric, prefix } => { + buf.put_u8(address_encoding); + buf.put_u8(prefix_length); + buf.put_u16(interval); + buf.put_u16(seqno); + buf.put_u16(metric); + match prefix { + IpAddr::V4(ipv4) => { + buf.put_u8(ipv4.octets()[0]); + buf.put_u8(ipv4.octets()[1]); + buf.put_u8(ipv4.octets()[2]); + buf.put_u8(ipv4.octets()[3]); + } + IpAddr::V6(_ipv6) => { + println!("IPv6 not supported yet"); + } + } + } // Add encoding logic for other TLV types. _ => {} } diff --git a/src/main.rs b/src/main.rs index ab02174..26f6a93 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,7 +2,7 @@ use bytes::BytesMut; use clap::Parser; use etherparse::{IpHeader, PacketHeaders}; use packet::DataPacket; -use std::{error::Error, net::Ipv4Addr, sync::Arc}; +use std::{error::Error, net::{Ipv4Addr, SocketAddr}, sync::Arc}; mod codec; mod node_setup; @@ -19,6 +19,8 @@ const LINK_MTU: usize = 1500; struct Cli { #[arg(short = 'a', long = "tun-addr")] tun_addr: Ipv4Addr, + #[arg(short = 'p', long = "peers", num_args = 1..)] + static_peers: Vec, } #[tokio::main] @@ -36,10 +38,12 @@ async fn main() -> Result<(), Box> { } }; + let static_peers = cli.static_peers; + // Creating a new Router instance let router = Arc::new(router::Router::new(node_tun.clone())); // Creating a new PeerManager instance - let _peer_manager: peer_manager::PeerManager = peer_manager::PeerManager::new(router.clone()); + let _peer_manager: peer_manager::PeerManager = peer_manager::PeerManager::new(router.clone(), static_peers); // The TUN interface will only receive data packets. This loops reads data packets from the TUN interface and forwards them to the router. diff --git a/src/peer_manager.rs b/src/peer_manager.rs index 30b10ba..cab7d4d 100644 --- a/src/peer_manager.rs +++ b/src/peer_manager.rs @@ -21,7 +21,7 @@ pub struct PeerManager { impl PeerManager { - pub fn new(router: Arc) -> Self { + pub fn new(router: Arc, static_peers_sockets: Vec) -> Self { let peer_manager = PeerManager { router, @@ -31,6 +31,9 @@ impl PeerManager { tokio::spawn(PeerManager::start_listener(peer_manager.clone())); // Reads the nodeconfig.toml file and connects to the peers in the file. tokio::spawn(PeerManager::get_peers_from_config(peer_manager.clone())); + // Remote nodes can also be read from CLI arg + tokio::spawn(PeerManager::get_peers_from_cli(peer_manager.clone(), static_peers_sockets)); + peer_manager } @@ -89,6 +92,55 @@ impl PeerManager { } } + // Each node has a nodeconfig.toml file which contains the underlay socket addresses of other nodes. + async fn get_peers_from_cli(self, socket_addresses: Vec) { + for peer_addr in socket_addresses { + println!("connecting to: {}", peer_addr); + match TcpStream::connect(peer_addr).await { + Ok(mut peer_stream) => { + println!("stream established"); + // 2. Read other node's TUN address from the stream + let mut buffer = [0u8; 4]; + peer_stream.read_exact(&mut buffer).await.unwrap(); + let received_overlay_ip = Ipv4Addr::from(buffer); + println!( + "Received overlay IP from other node: {:?}", + received_overlay_ip + ); + + // 3. Send own TUN address over the stream + let ip_bytes = self.router.get_node_tun_address().octets(); + peer_stream.write_all(&ip_bytes).await.unwrap(); + + // Create peer instance + let peer_stream_ip = peer_addr.ip(); + match Peer::new( + peer_stream_ip, + self.router.router_data_tx.clone(), + self.router.router_control_tx.clone(), + peer_stream, + received_overlay_ip, + ) { + Ok(new_peer) => { + self.router.add_directly_connected_peer(new_peer); + } + Err(e) => { + eprintln!("Error creating peer: {}", e); + } + } + } + Err(e) => { + eprintln!( + "Error connecting to TCP stream for {}: {}", + peer_addr.to_string(), + e + ); + } + } + } + } + + async fn start_listener(self) { match TcpListener::bind("[::]:9651").await { Ok(listener) => { diff --git a/src/router.rs b/src/router.rs index 9e16697..9eb3ab3 100644 --- a/src/router.rs +++ b/src/router.rs @@ -4,8 +4,8 @@ use crate::{ DataPacket, }, peer::Peer, - routing_table::{RoutingTable, RouteKey, RouteEntry}, - source_table::{SourceTable, SourceKey, SourceEntry}, + routing_table::{RouteEntry, RouteKey, RoutingTable}, + source_table::{SourceEntry, SourceKey, SourceTable}, }; use std::{ collections::HashMap, @@ -189,7 +189,7 @@ impl Router { let source_key = SourceKey { prefix: IpAddr::V4(peer.overlay_ip), plen: 32, // we set the prefix length to 32 for now, this means that each peer is a /32 network (so only route to the peer itself) - router_id: 0 // we set all router ids to 0 temporarily + router_id: 0, // we set all router ids to 0 temporarily }; let source_entry = SourceEntry { metric: peer.link_cost, @@ -197,7 +197,10 @@ impl Router { }; // create the source table entry let source_key_clone = source_key.clone(); - self.source_table.lock().unwrap().insert(source_key, source_entry); + self.source_table + .lock() + .unwrap() + .insert(source_key, source_entry); // now we can create the routing table entry let route_key = RouteKey { @@ -214,7 +217,10 @@ impl Router { selected: true, // set selected always to true for now as we have manually decided the topology to only have p2p links }; // create the routing table entry - self.routing_table.lock().unwrap().insert(route_key, route_entry); + self.routing_table + .lock() + .unwrap() + .insert(route_key, route_entry); } } } @@ -233,33 +239,29 @@ impl Router { let routing_table = self.routing_table.lock().unwrap(); for (key, value) in routing_table.table.iter() { // create update message and send to all peers - let update = BabelTLV::Update { - address_encoding: 1, // AE of 1 indicated IPv4 - prefix_length: 32, // temp value - working with full IPv4 for now, not prefix-based - interval: 999, // temp value - seqno: 0, // temp value - metric: value.metric, - prefix: key.prefix, - }; for peer in &connected_peers_cloned { - let control_packet = ControlPacket{ + let update_message = ControlPacket { header: BabelPacketHeader::new(14), - body: Some(BabelPacketBody { - tlv_type: BabelTLVType::Update, - length: 14, - body: update.clone(), - }), + body: Some(BabelPacketBody { + tlv_type: BabelTLVType::Update, + length: 14, + body: BabelTLV::Update { + address_encoding: 1, // AE of 1 indicated IPv4 + prefix_length: 32, // temp value - working with full IPv4 for now, not prefix-based + interval: 999, // temp value + seqno: 0, // temp value + metric: value.metric, + prefix: key.prefix, + }, + }), }; - println!("Sending route as control packet to {}: {:?}", peer.overlay_ip, control_packet); - peer.to_peer_control.send(control_packet).unwrap(); - } - - + println!("Sending route as control packet to {}", peer.overlay_ip); + peer.to_peer_control.send(update_message).unwrap(); + } } } } - pub fn get_directly_connected_peers(&self) -> Vec { self.directly_connected_peers.lock().unwrap().clone() From b95c3e9ebf41a657fe2cf4bb0eef034411b1f7cd Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Fri, 5 May 2023 18:53:35 +0000 Subject: [PATCH 23/89] fixed address encoding bug --- src/codec.rs | 2 ++ src/router.rs | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/codec.rs b/src/codec.rs index fdd5611..9e276bc 100644 --- a/src/codec.rs +++ b/src/codec.rs @@ -282,11 +282,13 @@ impl Decoder for ControlPacketCodec { )), _ => return Err(io::Error::new(io::ErrorKind::InvalidData, "Invalid address encoding")), }; + println!("UPDATE decoded successfully!"); Some(BabelPacketBody { tlv_type, length, body: BabelTLV::Update { address_encoding, prefix_length, interval, seqno, metric, prefix } }) + } // Add decoding logic for other TLV types. _ => None, diff --git a/src/router.rs b/src/router.rs index 9eb3ab3..1f7ce2a 100644 --- a/src/router.rs +++ b/src/router.rs @@ -247,7 +247,7 @@ impl Router { tlv_type: BabelTLVType::Update, length: 14, body: BabelTLV::Update { - address_encoding: 1, // AE of 1 indicated IPv4 + address_encoding: 0, // AE of 1 indicated IPv4 prefix_length: 32, // temp value - working with full IPv4 for now, not prefix-based interval: 999, // temp value seqno: 0, // temp value From da83e360ffd0b83c0fe51a3703532d78059b2a56 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Tue, 9 May 2023 09:58:15 +0000 Subject: [PATCH 24/89] updates --- src/codec.rs | 2 -- src/router.rs | 65 +++++++++++++++++++++++++++++---------------------- 2 files changed, 37 insertions(+), 30 deletions(-) diff --git a/src/codec.rs b/src/codec.rs index 9e276bc..18edfd5 100644 --- a/src/codec.rs +++ b/src/codec.rs @@ -262,7 +262,6 @@ impl Decoder for ControlPacketCodec { }) } BabelTLVType::Update => { - println!("UPDATE received, trying to decode now..."); let address_encoding = buf.get_u8(); let prefix_length = buf.get_u8(); let interval = buf.get_u16(); @@ -282,7 +281,6 @@ impl Decoder for ControlPacketCodec { )), _ => return Err(io::Error::new(io::ErrorKind::InvalidData, "Invalid address encoding")), }; - println!("UPDATE decoded successfully!"); Some(BabelPacketBody { tlv_type, length, diff --git a/src/router.rs b/src/router.rs index 1f7ce2a..80f1dd5 100644 --- a/src/router.rs +++ b/src/router.rs @@ -103,6 +103,14 @@ impl Router { eprintln!("No matching Hello message found for received IHU"); } } + BabelTLVType::Update => { + // get the metric from the update message + + + // upon receiving an update message, we should check if the update is feasible + // check if there is already a route (based on the index) in the routing table + println!("Received update from by boy {}! with metric ", control_struct.src_overlay_ip); + } _ => { eprintln!("Unknown control packet type"); } @@ -230,37 +238,38 @@ impl Router { // they can also be send when a change in the network topology occurs // updates are used to advertise new routes or the retract existing routes (retracting when the metric is set to 0xFFFF) async fn propagate_updates(self) { - loop { - tokio::time::sleep(tokio::time::Duration::from_secs(10)).await; + // loop { + // tokio::time::sleep(tokio::time::Duration::from_secs(10)).await; - let connected_peers = self.directly_connected_peers.lock().unwrap(); - let connected_peers_cloned: Vec<&Peer> = connected_peers.iter().collect(); + // let connected_peers = self.directly_connected_peers.lock().unwrap(); + // let connected_peers_cloned: Vec<&Peer> = connected_peers.iter().collect(); - let routing_table = self.routing_table.lock().unwrap(); - for (key, value) in routing_table.table.iter() { - // create update message and send to all peers + // let routing_table = self.routing_table.lock().unwrap(); + // for (key, value) in routing_table.table.iter() { + // // create update message and send to all peers - for peer in &connected_peers_cloned { - let update_message = ControlPacket { - header: BabelPacketHeader::new(14), - body: Some(BabelPacketBody { - tlv_type: BabelTLVType::Update, - length: 14, - body: BabelTLV::Update { - address_encoding: 0, // AE of 1 indicated IPv4 - prefix_length: 32, // temp value - working with full IPv4 for now, not prefix-based - interval: 999, // temp value - seqno: 0, // temp value - metric: value.metric, - prefix: key.prefix, - }, - }), - }; - println!("Sending route as control packet to {}", peer.overlay_ip); - peer.to_peer_control.send(update_message).unwrap(); - } - } - } + // for peer in &connected_peers_cloned { + // let update_message = ControlPacket { + // header: BabelPacketHeader::new(14), + // body: Some(BabelPacketBody { + // tlv_type: BabelTLVType::Update, + // length: 14, + // body: BabelTLV::Update { + // address_encoding: 0, // AE of 1 indicated IPv4 + // prefix_length: 32, // temp value - working with full IPv4 for now, not prefix-based + // interval: 999, // temp value + // seqno: 0, // temp value + // //metric: value.metric, // this is wrong i think? + // metric: peer.link_cost, + // prefix: key.prefix, + // }, + // }), + // }; + // println!("Sending route as control packet to {}", peer.overlay_ip); + // peer.to_peer_control.send(update_message).unwrap(); + // } + // } + // } } pub fn get_directly_connected_peers(&self) -> Vec { From 09bc9b5eca2e7a05c89c207389e3f71885c0afcd Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Tue, 9 May 2023 12:42:24 +0000 Subject: [PATCH 25/89] small refactor: replace SourceKey by FeasibilityDistance --- src/codec.rs | 29 +++------------------ src/main.rs | 63 ++++++++++++++++++++++++--------------------- src/node_setup.rs | 39 +++++++++------------------- src/packet.rs | 17 +++++++----- src/peer.rs | 6 ++--- src/peer_manager.rs | 2 +- src/router.rs | 18 ++++++------- src/source_table.rs | 17 +++++------- 8 files changed, 80 insertions(+), 111 deletions(-) diff --git a/src/codec.rs b/src/codec.rs index 18edfd5..e1202aa 100644 --- a/src/codec.rs +++ b/src/codec.rs @@ -217,28 +217,9 @@ impl Decoder for ControlPacketCodec { None => return Err(io::Error::new(io::ErrorKind::InvalidData, "Invalid TLV type")), }; - if tlv_type == BabelTLVType::Pad1 { - return Ok(Some(ControlPacket { - header, - body: Some(BabelPacketBody { - tlv_type, - length: 0, - body: BabelTLV::Pad1, - }), - })); - } - let length = buf.get_u8(); let body = match tlv_type { - BabelTLVType::PadN => { - buf.advance(usize::from(length)); - Some(BabelPacketBody { - tlv_type, - length, - body: BabelTLV::PadN(length), - }) - } BabelTLVType::Hello => { let flags = buf.get_u16(); let seqno = buf.get_u16(); @@ -281,10 +262,11 @@ impl Decoder for ControlPacketCodec { )), _ => return Err(io::Error::new(io::ErrorKind::InvalidData, "Invalid address encoding")), }; + let router_id = buf.get_u64(); Some(BabelPacketBody { tlv_type, length, - body: BabelTLV::Update { address_encoding, prefix_length, interval, seqno, metric, prefix } + body: BabelTLV::Update { address_encoding, prefix_length, interval, seqno, metric, prefix, router_id } }) } @@ -311,10 +293,6 @@ impl Encoder for ControlPacketCodec { buf.put_u8(body.length); match body.body { - BabelTLV::Pad1 => {} - BabelTLV::PadN(padding_length) => { - buf.put_slice(&vec![0; usize::from(padding_length)]); - } BabelTLV::Hello { flags, seqno, interval } => { buf.put_u16(flags); buf.put_u16(seqno); @@ -337,7 +315,7 @@ impl Encoder for ControlPacketCodec { } } } - BabelTLV::Update { address_encoding, prefix_length, interval, seqno, metric, prefix } => { + BabelTLV::Update { address_encoding, prefix_length, interval, seqno, metric, prefix , router_id} => { buf.put_u8(address_encoding); buf.put_u8(prefix_length); buf.put_u16(interval); @@ -354,6 +332,7 @@ impl Encoder for ControlPacketCodec { println!("IPv6 not supported yet"); } } + buf.put_u64(router_id); } // Add encoding logic for other TLV types. _ => {} diff --git a/src/main.rs b/src/main.rs index 26f6a93..8a2b0c2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -46,46 +46,51 @@ async fn main() -> Result<(), Box> { let _peer_manager: peer_manager::PeerManager = peer_manager::PeerManager::new(router.clone(), static_peers); - // The TUN interface will only receive data packets. This loops reads data packets from the TUN interface and forwards them to the router. - // NOTE: only the kernel can put data packets on the TUN interface. This application never puts data packets on the TUN interface for itself. + // 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 { let node_tun = node_tun.clone(); - + tokio::spawn(async move { loop { let mut buf = BytesMut::zeroed(LINK_MTU); - match node_tun.recv(&mut buf).await { - Ok(n) => { - buf.truncate(n); - match PacketHeaders::from_ip_slice(&buf) { - Ok(packet) => { - if let Some(IpHeader::Version4(header, _)) = packet.ip { - let dest_addr = Ipv4Addr::from(header.destination); - println!("Destination IPv4 address: {}", dest_addr); - - let data_packet = DataPacket { - dest_ip: dest_addr, - raw_data: buf.to_vec(), - }; - router.router_data_tx.send(data_packet).unwrap(); - } else { - println!("Non-IPv4 packet received, ignoring..."); - } - } - Err(e) => { - println!("buffer: {:?}", buf); - eprintln!("Error from_ip_slice: {e}"); - } - } - } + if let Err(e) = node_tun.recv(&mut buf).await { + eprintln!("Error reading from TUN: {}", e); + continue; + } + + let n = buf.len(); + buf.truncate(n); + + let packet = match PacketHeaders::from_ip_slice(&buf) { + Ok(packet) => packet, Err(e) => { - eprintln!("Error reading from TUN: {}", e); + println!("buffer: {:?}", buf); + eprintln!("Error from_ip_slice: {}", e); + continue; } + }; + + if let Some(IpHeader::Version4(header, _)) = packet.ip { + let dest_addr = Ipv4Addr::from(header.destination); + println!("Destination IPv4 address: {}", dest_addr); + + let data_packet = DataPacket { + dest_ip: dest_addr, + raw_data: buf.to_vec(), + }; + if router.router_data_tx.send(data_packet).is_err() { + eprintln!("Failed to send data_packet"); + } + } else { + println!("Non-IPv4 packet received, ignoring..."); } } }); } - + + // Just die after 1 day, you've probably leaked memory by then anyway tokio::time::sleep(std::time::Duration::from_secs(60 * 60 * 24)).await; + Ok(()) } diff --git a/src/node_setup.rs b/src/node_setup.rs index 8cb70a9..4ae2ef1 100644 --- a/src/node_setup.rs +++ b/src/node_setup.rs @@ -54,31 +54,16 @@ pub async fn add_route(handle: Handle) -> Result<(), Box> { } pub async fn setup_node(tun_addr: Ipv4Addr) -> Result, Box> { - match create_tun_interface(tun_addr) { - Ok(tun) => { - println!("Interface '{}' ({}) created", TUN_NAME, tun_addr); - match rtnetlink::new_connection() { - Ok((conn, handle, _)) => { - tokio::spawn(conn); - match add_route(handle.clone()).await { - Ok(_) => { - println!("Static route created"); - }, - Err(e) => { - panic!("Error adding route: {}", e); - } - } - }, - Err(e) => { - panic!("Error creating new handle: {}", e); - } - } + let tun = create_tun_interface(tun_addr)?; + println!("Interface '{}' ({}) created", TUN_NAME, tun_addr); + + let (conn, handle, _) = rtnetlink::new_connection()?; + tokio::spawn(conn); + + add_route(handle.clone()).await?; + + println!("Static route created"); + + Ok(tun) +} - - Ok(tun) - }, - Err(e) => { - panic!("Error creating TUN: {}", e); - } - } -} \ No newline at end of file diff --git a/src/packet.rs b/src/packet.rs index eea4b33..e109020 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -113,13 +113,13 @@ pub enum BabelTLVType { impl BabelTLVType { pub fn from_u8(value: u8) -> Option { match value { - 0 => Some(Self::Pad1), - 1 => Some(Self::PadN), + // 0 => Some(Self::Pad1), + // 1 => Some(Self::PadN), 2 => Some(Self::AckReq), 3 => Some(Self::Ack), 4 => Some(Self::Hello), 5 => Some(Self::IHU), - 6 => Some(Self::RouterID), + // 6 => Some(Self::RouterID), 7 => Some(Self::NextHop), 8 => Some(Self::Update), 9 => Some(Self::RouteReq), @@ -131,8 +131,9 @@ impl BabelTLVType { #[derive(Debug, Clone, PartialEq)] pub enum BabelTLV { - Pad1, - PadN(u8), + // These TLVs are not implemented as they are used for padding when sending multiple TLVs in one packet. + // Pad1, + // PadN(u8), AckReq { nonce: u16, interval: u16 @@ -148,7 +149,10 @@ pub enum BabelTLV { interval: u16, address: IpAddr, }, - RouterID { router_id: u16 }, + // RouterID TLVs are sent just before Update TLVs and server the purpose of identifying the router that sent the Update TLV. + // This is used when multiple Update TLVs are sent where a prefix is included in the first Update TLV and omitted in the subsequent Update TLVs. + // As we do not support ommitted prefixes, we do not need to implement this TLV. We pass the router_id as a parameter to the Update TLV instead. + // RouterID { router_id: u16 }, NextHop { address: IpAddr }, Update { address_encoding: u8, @@ -157,6 +161,7 @@ pub enum BabelTLV { seqno: u16, metric: u16, prefix: IpAddr, + router_id: u64, }, RouteReq { prefix: IpAddr, plen: u8 }, SeqnoReq { diff --git a/src/peer.rs b/src/peer.rs index 2137e53..cae364e 100644 --- a/src/peer.rs +++ b/src/peer.rs @@ -9,8 +9,6 @@ use tokio_util::codec::Framed; use crate::packet::{ControlPacket, DataPacket, ControlStruct}; use crate::{codec::PacketCodec, packet::Packet}; -// IS A NEIGHBOR IN THE IDEA OF BABEL - #[derive(Debug, Clone)] pub struct Peer { pub stream_ip: IpAddr, @@ -50,7 +48,7 @@ impl Peer { tokio::spawn(async move { loop { select! { - + // Received over the TCP stream frame = framed.next() => { match frame { @@ -125,4 +123,4 @@ impl Peer { self.last_sent_hello_seqno = self.last_sent_hello_seqno + 1; println!("last hello seqno increasted to {}", self.last_sent_hello_seqno); } -} +} \ No newline at end of file diff --git a/src/peer_manager.rs b/src/peer_manager.rs index cab7d4d..a54ff50 100644 --- a/src/peer_manager.rs +++ b/src/peer_manager.rs @@ -3,7 +3,7 @@ use crate::router::Router; use serde::Deserialize; use tokio::net::TcpListener; use std::net::{Ipv4Addr, SocketAddr}; -use std::sync::{Arc, Mutex}; +use std::sync::{Arc}; use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tokio::{net::TcpStream}; diff --git a/src/router.rs b/src/router.rs index 80f1dd5..8929014 100644 --- a/src/router.rs +++ b/src/router.rs @@ -5,7 +5,7 @@ use crate::{ }, peer::Peer, routing_table::{RouteEntry, RouteKey, RoutingTable}, - source_table::{SourceEntry, SourceKey, SourceTable}, + source_table::{SourceKey, SourceTable, FeasibilityDistance}, }; use std::{ collections::HashMap, @@ -25,6 +25,8 @@ pub struct Router { pub sent_hello_timestamps: Arc>>, pub routing_table: Arc>, pub source_table: Arc>, + + pub router_seqno: u16, } impl Router { @@ -42,6 +44,7 @@ impl Router { sent_hello_timestamps: Arc::new(Mutex::new(HashMap::new())), routing_table: Arc::new(Mutex::new(RoutingTable::new())), source_table: Arc::new(Mutex::new(SourceTable::new())), + router_seqno: 0, }; tokio::spawn(Router::start_hello_sender( @@ -199,16 +202,13 @@ impl Router { plen: 32, // we set the prefix length to 32 for now, this means that each peer is a /32 network (so only route to the peer itself) router_id: 0, // we set all router ids to 0 temporarily }; - let source_entry = SourceEntry { - metric: peer.link_cost, - seqno: 0, // we set the seqno to 0 for now - }; + let feas_dist = FeasibilityDistance(0, peer.link_cost); // create the source table entry let source_key_clone = source_key.clone(); self.source_table .lock() .unwrap() - .insert(source_key, source_entry); + .insert(source_key, feas_dist); // now we can create the routing table entry let route_key = RouteKey { @@ -336,12 +336,12 @@ impl Router { // If there's no entry in the source table, the update is feasible true } - Some(source_entry) => { + Some(feas_dist) => { // If an entry exists in the source table, compare seqno and metric - let (seqno_2, metric_2) = (&source_entry.seqno, &source_entry.metric); + let (metric_2, seqno_2) = (feas_dist.0, feas_dist.1); // Check feasibility conditions - seqno > seqno_2 || (seqno == seqno_2 && metric < metric_2) + seqno > &seqno_2 || (seqno == &seqno_2 && metric < &metric_2) } } } diff --git a/src/source_table.rs b/src/source_table.rs index 8f17331..a891fd8 100644 --- a/src/source_table.rs +++ b/src/source_table.rs @@ -8,15 +8,12 @@ pub struct SourceKey { } #[derive(Debug, Clone)] -pub struct SourceEntry { - pub metric: u16, - pub seqno: u16, - // source_timer -} -// Used to store the feasibility distances +pub struct FeasibilityDistance(pub u16, pub u16); // (metric, seqno) + +// Store (prefix, plen, router_id) -> feasibility distance mapping pub struct SourceTable { - pub table: HashMap, + pub table: HashMap, } impl SourceTable { @@ -26,15 +23,15 @@ impl SourceTable { } } - pub fn insert(&mut self, key: SourceKey, entry: SourceEntry) { - self.table.insert(key, entry); + pub fn insert(&mut self, key: SourceKey, feas_dist: FeasibilityDistance) { + self.table.insert(key, feas_dist); } pub fn remove(&mut self, key: &SourceKey) { self.table.remove(key); } - pub fn get(&self, key: &SourceKey) -> Option<&SourceEntry> { + pub fn get(&self, key: &SourceKey) -> Option<&FeasibilityDistance> { self.table.get(key) } } \ No newline at end of file From 9fe9b204d10fbd0cf35f0240fbcb22be498d99a8 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Tue, 9 May 2023 17:33:21 +0000 Subject: [PATCH 26/89] another refactoring --- src/codec.rs | 58 +++++---- src/packet.rs | 91 ++++++++++--- src/peer.rs | 1 - src/peer_manager.rs | 121 ++++++------------ src/router.rs | 305 +++----------------------------------------- 5 files changed, 167 insertions(+), 409 deletions(-) diff --git a/src/codec.rs b/src/codec.rs index e1202aa..ed47b49 100644 --- a/src/codec.rs +++ b/src/codec.rs @@ -221,14 +221,14 @@ impl Decoder for ControlPacketCodec { let body = match tlv_type { BabelTLVType::Hello => { - let flags = buf.get_u16(); let seqno = buf.get_u16(); let interval = buf.get_u16(); - Some(BabelPacketBody { + let body = BabelPacketBody { tlv_type, length, - body: BabelTLV::Hello { flags, seqno, interval }, - }) + tlv: BabelTLV::Hello { seqno, interval }, + }; + body } BabelTLVType::IHU => { let _address_encoding = buf.get_u8(); @@ -236,15 +236,16 @@ impl Decoder for ControlPacketCodec { let rxcost = buf.get_u16(); let interval = buf.get_u16(); let address = IpAddr::V4(Ipv4Addr::new(buf.get_u8(), buf.get_u8(), buf.get_u8(), buf.get_u8())); - Some(BabelPacketBody { + let body = BabelPacketBody { tlv_type, length, - body: BabelTLV::IHU { rxcost, interval, address }, - }) + tlv: BabelTLV::IHU { rxcost, interval, address }, + }; + body } BabelTLVType::Update => { let address_encoding = buf.get_u8(); - let prefix_length = buf.get_u8(); + let plen = buf.get_u8(); let interval = buf.get_u16(); let seqno = buf.get_u16(); let metric = buf.get_u16(); @@ -263,15 +264,18 @@ impl Decoder for ControlPacketCodec { _ => return Err(io::Error::new(io::ErrorKind::InvalidData, "Invalid address encoding")), }; let router_id = buf.get_u64(); - Some(BabelPacketBody { + let body = BabelPacketBody { tlv_type, length, - body: BabelTLV::Update { address_encoding, prefix_length, interval, seqno, metric, prefix, router_id } - }) - + tlv: BabelTLV::Update { plen, interval, seqno, metric, prefix, router_id } + }; + body } - // Add decoding logic for other TLV types. - _ => None, + BabelTLVType::AckReq => todo!(), + BabelTLVType::Ack => todo!(), + BabelTLVType::NextHop => todo!(), + BabelTLVType::RouteReq => todo!(), + BabelTLVType::SeqnoReq => todo!(), }; Ok(Some(ControlPacket { header, body })) @@ -287,14 +291,12 @@ impl Encoder for ControlPacketCodec { buf.put_u8(message.header.version); buf.put_u16(message.header.body_length); - if let Some(body) = message.body { // Write BabelPacketBody - buf.put_u8(body.tlv_type as u8); - buf.put_u8(body.length); + buf.put_u8(message.body.tlv_type as u8); + buf.put_u8(message.body.length); - match body.body { - BabelTLV::Hello { flags, seqno, interval } => { - buf.put_u16(flags); + match message.body.tlv{ + BabelTLV::Hello { seqno, interval } => { buf.put_u16(seqno); buf.put_u16(interval); } @@ -315,9 +317,8 @@ impl Encoder for ControlPacketCodec { } } } - BabelTLV::Update { address_encoding, prefix_length, interval, seqno, metric, prefix , router_id} => { - buf.put_u8(address_encoding); - buf.put_u8(prefix_length); + BabelTLV::Update { plen , interval, seqno, metric, prefix , router_id} => { + buf.put_u8(plen); buf.put_u16(interval); buf.put_u16(seqno); buf.put_u16(metric); @@ -329,14 +330,21 @@ impl Encoder for ControlPacketCodec { buf.put_u8(ipv4.octets()[3]); } IpAddr::V6(_ipv6) => { - println!("IPv6 not supported yet"); + buf.put_u16(_ipv6.segments()[0]); + buf.put_u16(_ipv6.segments()[1]); + buf.put_u16(_ipv6.segments()[2]); + buf.put_u16(_ipv6.segments()[3]); + buf.put_u16(_ipv6.segments()[4]); + buf.put_u16(_ipv6.segments()[5]); + buf.put_u16(_ipv6.segments()[6]); + buf.put_u16(_ipv6.segments()[7]); } } buf.put_u64(router_id); } // Add encoding logic for other TLV types. _ => {} - } + } Ok(()) diff --git a/src/packet.rs b/src/packet.rs index e109020..a1bde69 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -39,24 +39,22 @@ pub struct ControlStruct { #[derive(Debug, PartialEq, Clone)] pub struct ControlPacket { pub header: BabelPacketHeader, - pub body: Option, - // pub trailer: Option, + pub body: BabelPacketBody, } #[derive(Debug, PartialEq, Clone)] pub struct BabelPacketHeader { pub magic: u8, pub version: u8, - pub body_length: u16, + pub body_length: u16, // length of the whole BabelPacketBody (tlv_type, length and body) } // A BabelPacketBody describes exactly one TLV -// TODO: According to the protocol the body of a Babel packet can contain multiple subsequent TLV's #[derive(Debug, PartialEq, Clone)] pub struct BabelPacketBody { pub tlv_type: BabelTLVType, - pub length: u8, - pub body: BabelTLV, + pub length: u8, // length of the tlv (only the tlv, not tlv_type and length itself) + pub tlv: BabelTLV, } impl ControlStruct { @@ -79,31 +77,75 @@ impl BabelPacketHeader { impl ControlPacket { - pub fn new_ihu(rxcost: u16, interval: u16, dest_address: IpAddr) -> Self { + + pub fn new_hello(seqno: u16, interval: u16) -> Self { + let header_length = (BabelTLVType::Hello.get_tlv_length(false) + 2) as u16; Self { - header: BabelPacketHeader::new(10), - body: Some(BabelPacketBody { + header: BabelPacketHeader::new(header_length), + body: BabelPacketBody { + tlv_type: BabelTLVType::Hello, + length: BabelTLVType::Hello.get_tlv_length(false), + tlv: BabelTLV::Hello { + seqno, + interval, + } + }, + } + } + + pub fn new_ihu(rxcost: u16, interval: u16, dest_address: IpAddr) -> Self { + let uses_ipv6 = match dest_address { + IpAddr::V4(_) => false, + IpAddr::V6(_) => true, + }; + let header_length = (BabelTLVType::IHU.get_tlv_length(uses_ipv6) + 2) as u16; + Self { + header: BabelPacketHeader::new(header_length), + body: BabelPacketBody { tlv_type: BabelTLVType::IHU, - length: 8, - body: BabelTLV::IHU { + length: BabelTLVType::IHU.get_tlv_length(uses_ipv6), + tlv: BabelTLV::IHU { rxcost, interval, address: dest_address, } - }), + }, + } + } + + pub fn new_update(plen: u8, interval: u16, seqno: u16, metric: u16, prefix: IpAddr, router_id: u64) -> Self { + let uses_ipv6 = match prefix { + IpAddr::V4(_) => false, + IpAddr::V6(_) => true, + }; + let header_length = (BabelTLVType::Update.get_tlv_length(uses_ipv6) + 2) as u16; + Self { + header: BabelPacketHeader::new(header_length), + body: BabelPacketBody { + tlv_type: BabelTLVType::Update, + length: BabelTLVType::Update.get_tlv_length(uses_ipv6), + tlv: BabelTLV::Update { + plen, + interval, + seqno, + metric, + prefix, + router_id, + } + }, } } } #[derive(Debug, PartialEq, Clone)] pub enum BabelTLVType { - Pad1 = 0, - PadN = 1, + // Pad1 = 0, + // PadN = 1, AckReq = 2, Ack = 3, Hello = 4, IHU = 5, - RouterID = 6, + // RouterID = 6, NextHop = 7, Update = 8, RouteReq = 9, @@ -127,8 +169,23 @@ impl BabelTLVType { _ => None, } } + + pub fn get_tlv_length(self, uses_ipv6: bool) -> u8 { + let (ipv6, ipv4) = match self { + Self::AckReq => (4, 4), + Self::Ack => (2, 2), + Self::Hello => (4, 4), + Self::IHU => (20, 8), + Self::NextHop => (16, 4), + Self::Update => (28, 16), + Self::RouteReq => (17, 5), + Self::SeqnoReq => (21, 9), + }; + if uses_ipv6 { ipv6 } else { ipv4 } + } } + #[derive(Debug, Clone, PartialEq)] pub enum BabelTLV { // These TLVs are not implemented as they are used for padding when sending multiple TLVs in one packet. @@ -140,7 +197,6 @@ pub enum BabelTLV { }, Ack { nonce: u16 }, Hello { - flags: u16, seqno: u16, interval: u16, }, @@ -155,8 +211,7 @@ pub enum BabelTLV { // RouterID { router_id: u16 }, NextHop { address: IpAddr }, Update { - address_encoding: u8, - prefix_length: u8, + plen: u8, interval: u16, seqno: u16, metric: u16, diff --git a/src/peer.rs b/src/peer.rs index cae364e..2e5d1c4 100644 --- a/src/peer.rs +++ b/src/peer.rs @@ -15,7 +15,6 @@ pub struct Peer { pub to_peer_data: mpsc::UnboundedSender, pub to_peer_control: mpsc::UnboundedSender, pub overlay_ip: Ipv4Addr, - pub last_sent_hello_seqno: u16, pub link_cost: u16, } diff --git a/src/peer_manager.rs b/src/peer_manager.rs index a54ff50..b07a78d 100644 --- a/src/peer_manager.rs +++ b/src/peer_manager.rs @@ -23,9 +23,7 @@ impl PeerManager { pub fn new(router: Arc, static_peers_sockets: Vec) -> Self { - let peer_manager = PeerManager { - router, - }; + let peer_manager = PeerManager { router }; // Start a TCP listener. When a new connection is accepted, the reverse peer exchange is performed. tokio::spawn(PeerManager::start_listener(peer_manager.clone())); @@ -33,108 +31,73 @@ impl PeerManager { tokio::spawn(PeerManager::get_peers_from_config(peer_manager.clone())); // Remote nodes can also be read from CLI arg tokio::spawn(PeerManager::get_peers_from_cli(peer_manager.clone(), static_peers_sockets)); - peer_manager } - // Each node has a nodeconfig.toml file which contains the underlay socket addresses of other nodes. async fn get_peers_from_config(self) { + if let Ok(file_content) = std::fs::read_to_string(NODE_CONFIG_FILE_PATH) { + let config: PeersConfig = toml::from_str(&file_content).unwrap(); - // Read from the nodeconfig.toml file - match std::fs::read_to_string(NODE_CONFIG_FILE_PATH) { - Ok(file_content) => { - // Create a PeersConfig based on the file content - let config: PeersConfig = toml::from_str(&file_content).unwrap(); - for peer_addr in config.peers { - match TcpStream::connect(peer_addr).await { - Ok(mut peer_stream) => { - - // 2. Read other node's TUN address from the stream - let mut buffer = [0u8; 4]; - peer_stream.read_exact(&mut buffer).await.unwrap(); - let received_overlay_ip = Ipv4Addr::from(buffer); - println!( - "Received overlay IP from other node: {:?}", - received_overlay_ip - ); - - // 3. Send own TUN address over the stream - let ip_bytes = self.router.get_node_tun_address().octets(); - peer_stream.write_all(&ip_bytes).await.unwrap(); - - // Create peer instance - let peer_stream_ip = peer_addr.ip(); - match Peer::new( - peer_stream_ip, - self.router.router_data_tx.clone(), - self.router.router_control_tx.clone(), - peer_stream, - received_overlay_ip, - ) { - Ok(new_peer) => { - self.router.add_directly_connected_peer(new_peer); - } - Err(e) => { - eprintln!("Error creating peer: {}", e); - } - } - } - Err(e) => { - eprintln!("Error connecting to TCP stream for {}: {}", peer_addr.to_string(), e); - } - } - } - } - Err(e) => { - eprintln!("Error reading nodeconfig.toml file: {}", e); - } - } - } - - // Each node has a nodeconfig.toml file which contains the underlay socket addresses of other nodes. - async fn get_peers_from_cli(self, socket_addresses: Vec) { - for peer_addr in socket_addresses { - println!("connecting to: {}", peer_addr); - match TcpStream::connect(peer_addr).await { - Ok(mut peer_stream) => { - println!("stream established"); - // 2. Read other node's TUN address from the stream + for peer_addr in config.peers { + if let Ok(mut peer_stream) = TcpStream::connect(peer_addr).await { let mut buffer = [0u8; 4]; peer_stream.read_exact(&mut buffer).await.unwrap(); let received_overlay_ip = Ipv4Addr::from(buffer); + println!( "Received overlay IP from other node: {:?}", received_overlay_ip ); - // 3. Send own TUN address over the stream let ip_bytes = self.router.get_node_tun_address().octets(); peer_stream.write_all(&ip_bytes).await.unwrap(); - // Create peer instance let peer_stream_ip = peer_addr.ip(); - match Peer::new( + if let Ok(new_peer) = Peer::new( peer_stream_ip, self.router.router_data_tx.clone(), self.router.router_control_tx.clone(), peer_stream, received_overlay_ip, ) { - Ok(new_peer) => { - self.router.add_directly_connected_peer(new_peer); - } - Err(e) => { - eprintln!("Error creating peer: {}", e); - } + self.router.add_directly_connected_peer(new_peer); } } - Err(e) => { - eprintln!( - "Error connecting to TCP stream for {}: {}", - peer_addr.to_string(), - e - ); + } + } else { + eprintln!("Error reading nodeconfig.toml file"); + } + } + + async fn get_peers_from_cli(self, socket_addresses: Vec) { + for peer_addr in socket_addresses { + println!("connecting to: {}", peer_addr); + + if let Ok(mut peer_stream) = TcpStream::connect(peer_addr).await { + println!("stream established"); + + let mut buffer = [0u8; 4]; + peer_stream.read_exact(&mut buffer).await.unwrap(); + let received_overlay_ip = Ipv4Addr::from(buffer); + + println!( + "Received overlay IP from other node: {:?}", + received_overlay_ip + ); + + let ip_bytes = self.router.get_node_tun_address().octets(); + peer_stream.write_all(&ip_bytes).await.unwrap(); + + let peer_stream_ip = peer_addr.ip(); + if let Ok(new_peer) = Peer::new( + peer_stream_ip, + self.router.router_data_tx.clone(), + self.router.router_control_tx.clone(), + peer_stream, + received_overlay_ip, + ) { + self.router.add_directly_connected_peer(new_peer); } } } diff --git a/src/router.rs b/src/router.rs index 8929014..cdb46bf 100644 --- a/src/router.rs +++ b/src/router.rs @@ -15,29 +15,31 @@ use std::{ use tokio::sync::mpsc::{self, UnboundedReceiver, UnboundedSender}; use tokio_tun::Tun; +const HELLO_INTERVAL: u16 = 4; + #[derive(Clone)] pub struct Router { - directly_connected_peers: Arc>>, + // The peer interfaces are the known neighbors of this node + peer_interfaces: Arc>>, pub router_control_tx: UnboundedSender, pub router_data_tx: UnboundedSender, pub node_tun: Arc, - pub sent_hello_timestamps: Arc>>, pub routing_table: Arc>, pub source_table: Arc>, - pub router_seqno: u16, } impl Router { pub fn new(node_tun: Arc) -> Self { + // Tx is passed onto each new peer instance. This enables peers to send control packets to the router. let (router_control_tx, router_control_rx) = mpsc::unbounded_channel::(); // Tx is passed onto each new peer instance. This enables peers to send data packets to the router. let (router_data_tx, router_data_rx) = mpsc::unbounded_channel::(); let router = Router { - directly_connected_peers: Arc::new(Mutex::new(Vec::new())), + peer_interfaces: Arc::new(Mutex::new(Vec::new())), router_control_tx, router_data_tx, node_tun, @@ -47,302 +49,33 @@ impl Router { router_seqno: 0, }; - tokio::spawn(Router::start_hello_sender( - router.clone(), - router.sent_hello_timestamps.clone(), - )); - tokio::spawn(Router::handle_incoming_control_packets( - router.clone(), - router_control_rx, - router.sent_hello_timestamps.clone(), - )); - tokio::spawn(Router::handle_incoming_data_packets( - router.clone(), - router_data_rx, - )); - tokio::spawn(Router::start_routing_table_updater(router.clone())); - - tokio::spawn(Router::propagate_updates(router.clone())); + tokio::spawn(Router::periodic_hello_sender(router.clone())); router } - async fn handle_incoming_control_packets( - self, - mut router_control_rx: UnboundedReceiver, - sent_hello_timestamps: Arc>>, - ) { - loop { - while let Some(control_struct) = router_control_rx.recv().await { - if let Some(body) = &control_struct.control_packet.body { - match body.tlv_type { - BabelTLVType::Hello => { - let dest_ip = control_struct.src_overlay_ip; - control_struct.reply(ControlPacket::new_ihu(10, 1000, dest_ip)); - println!("IHU {}", dest_ip); - } - BabelTLVType::IHU => { - // Upon receiving an IHU message, we should read the time difference between the - // time the Hello message (with the same seqno) was sent and the time the IHU message - // was received. This time difference is the link cost between this node and the peer that - // sent the IHU message. - if let Some(timestamp) = sent_hello_timestamps - .lock() - .unwrap() - .get(&control_struct.src_overlay_ip) - { - let time_diff = - tokio::time::Instant::now().duration_since(*timestamp); - let sender_peer_ip = control_struct - .src_overlay_ip - .to_string() - .parse::() - .unwrap(); - self.update_peer_link_cost( - sender_peer_ip, - time_diff.as_millis() as u16, - ); - } else { - eprintln!("No matching Hello message found for received IHU"); - } - } - BabelTLVType::Update => { - // get the metric from the update message - - // upon receiving an update message, we should check if the update is feasible - // check if there is already a route (based on the index) in the routing table - println!("Received update from by boy {}! with metric ", control_struct.src_overlay_ip); - } - _ => { - eprintln!("Unknown control packet type"); - } - } - } + async fn periodic_hello_sender(self) { + for peer in self.peer_interfaces.lock().unwrap().iter_mut() { + let hello = ControlPacket::new_hello(peer.last_sent_hello_seqno, HELLO_INTERVAL); + println!("Sending hello to peer: {:?}", peer.stream_ip); + if let Err(error) = peer.to_peer_control.send(hello) { + eprintln!("Error sending hello to peer: {}", error); } - } - } - - async fn handle_incoming_data_packets(self, mut router_data_rx: UnboundedReceiver) { - // If the destination IP of the data packet matches with the IP address of this node's TUN interface - // we should forward the data packet towards the TUN interface. - // If the destination IP doesn't match, we need to lookup if we have a matching peer instance - // where the destination IP matches with the peer's overlay IP. If we do, we should forward the - // data packet to the peer's to_peer_data channel. - loop { - while let Some(data_packet) = router_data_rx.recv().await { - let dest_ip = data_packet.dest_ip; - if dest_ip == self.node_tun.address().unwrap() { - if let Err(e) = self.node_tun.send(&data_packet.raw_data).await { - eprintln!("Error sending data packet to TUN interface: {:?}", e); - } - } else { - let matching_peer = self.get_peer_by_ip(dest_ip); - if let Some(peer) = matching_peer { - if let Err(e) = peer.to_peer_data.send(data_packet) { - eprintln!("Error sending data packet to peer: {:?}", e); - } - } else { - eprintln!("No matching peer found for data packet"); - } - } - } - } - } - - async fn start_hello_sender( - self, - sent_hello_timestamps: Arc>>, - ) { - loop { - tokio::time::sleep(tokio::time::Duration::from_secs(5)).await; - - for peer in self.directly_connected_peers.lock().unwrap().iter_mut() { - let hello_message = ControlPacket { - header: BabelPacketHeader::new(7), - body: Some(BabelPacketBody { - tlv_type: BabelTLVType::Hello, - length: 7, - body: BabelTLV::Hello { - flags: 99u16, - seqno: peer.last_sent_hello_seqno, - interval: 299u16, - }, - }), - }; - // Store the current timestamp for this Hello message. - let current_timestamp = tokio::time::Instant::now(); - sent_hello_timestamps - .lock() - .unwrap() - .insert(IpAddr::V4(peer.overlay_ip), current_timestamp); - - println!("Hello({}) {}", peer.last_sent_hello_seqno, peer.overlay_ip); - if let Err(e) = peer.to_peer_control.send(hello_message.clone()) { - eprintln!("Error sending hello message to peer: {:?}", e); - } - - peer.increase_hello_seqno(); - } - } - } - - // create the function for a task that will loop over the directly connected peers and create routing table entries for them - // 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 - async fn start_routing_table_updater(self) { - loop { - tokio::time::sleep(tokio::time::Duration::from_secs(5)).await; - - for peer in self.directly_connected_peers.lock().unwrap().iter_mut() { - if peer.link_cost == 65535 { - // before we can create a routing table entry, we need to create a source table entry - let source_key = SourceKey { - prefix: IpAddr::V4(peer.overlay_ip), - plen: 32, // we set the prefix length to 32 for now, this means that each peer is a /32 network (so only route to the peer itself) - router_id: 0, // we set all router ids to 0 temporarily - }; - let feas_dist = FeasibilityDistance(0, peer.link_cost); - // create the source table entry - let source_key_clone = source_key.clone(); - self.source_table - .lock() - .unwrap() - .insert(source_key, feas_dist); - - // now we can create the routing table entry - let route_key = RouteKey { - prefix: IpAddr::V4(peer.overlay_ip), - plen: 32, // we set the prefix length to 32 for now, this means that each peer is a /32 network (so only route to the peer itself) - neighbor: IpAddr::V4(peer.overlay_ip), - }; - let route_entry = RouteEntry { - source: source_key_clone, - neighbor: peer.clone(), - metric: peer.link_cost, - 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 - }; - // create the routing table entry - self.routing_table - .lock() - .unwrap() - .insert(route_key, route_entry); - } - } - } - } - - // routing table updates are send periodically to all directly connected peers - // they can also be send when a change in the network topology occurs - // updates are used to advertise new routes or the retract existing routes (retracting when the metric is set to 0xFFFF) - async fn propagate_updates(self) { - // loop { - // tokio::time::sleep(tokio::time::Duration::from_secs(10)).await; - - // let connected_peers = self.directly_connected_peers.lock().unwrap(); - // let connected_peers_cloned: Vec<&Peer> = connected_peers.iter().collect(); - - // let routing_table = self.routing_table.lock().unwrap(); - // for (key, value) in routing_table.table.iter() { - // // create update message and send to all peers - - // for peer in &connected_peers_cloned { - // let update_message = ControlPacket { - // header: BabelPacketHeader::new(14), - // body: Some(BabelPacketBody { - // tlv_type: BabelTLVType::Update, - // length: 14, - // body: BabelTLV::Update { - // address_encoding: 0, // AE of 1 indicated IPv4 - // prefix_length: 32, // temp value - working with full IPv4 for now, not prefix-based - // interval: 999, // temp value - // seqno: 0, // temp value - // //metric: value.metric, // this is wrong i think? - // metric: peer.link_cost, - // prefix: key.prefix, - // }, - // }), - // }; - // println!("Sending route as control packet to {}", peer.overlay_ip); - // peer.to_peer_control.send(update_message).unwrap(); - // } - // } - // } - } - - pub fn get_directly_connected_peers(&self) -> Vec { - self.directly_connected_peers.lock().unwrap().clone() + } } pub fn add_directly_connected_peer(&self, peer: Peer) { - self.directly_connected_peers.lock().unwrap().push(peer); - } - - fn get_peer_by_ip(&self, peer_ip: Ipv4Addr) -> Option { - let peers = self.get_directly_connected_peers(); - let matching_peer = peers.iter().find(|peer| peer.overlay_ip == peer_ip); - - match matching_peer { - Some(peer) => Some(peer.clone()), - None => None, - } + self.peer_interfaces.lock().unwrap().push(peer); } pub fn get_node_tun_address(&self) -> Ipv4Addr { self.node_tun.address().unwrap() } - pub fn update_peer_link_cost(&self, peer_ip: Ipv4Addr, link_cost: u16) { - let mut peers = self.directly_connected_peers.lock().unwrap(); - let matching_peer = peers.iter_mut().find(|peer| peer.overlay_ip == peer_ip); - - match matching_peer { - Some(peer) => { - // Only update the link cost if the new link cost is lower than the current link cost - if link_cost < peer.link_cost { - peer.link_cost = link_cost; - println!("Link cost to {} updated to {}", peer_ip, link_cost); - } - } - None => { - eprintln!("No matching peer found for link cost update"); - } - } - } - - pub fn is_update_feasible( - // update is tuple of (prefix, prefix_length, router_id, seqno, metric) - received_update: &(IpAddr, u8, u64, u16, u16), - source_table: &SourceTable, - ) -> bool { - let (prefix, plen, router_id, seqno, metric) = received_update; - let source_key = SourceKey { - prefix: *prefix, - plen: *plen, - router_id: *router_id, - }; - - // If the received metric is infinite, it's always feasible - // An update with an infinite metric is considered a retraction - // Retractions are used to notify neighbors that a previously advertised route is no longer available - if *metric == u16::MAX { - return true; - } - - match source_table.get(&source_key) { - None => { - // If there's no entry in the source table, the update is feasible - true - } - Some(feas_dist) => { - // If an entry exists in the source table, compare seqno and metric - let (metric_2, seqno_2) = (feas_dist.0, feas_dist.1); - - // Check feasibility conditions - seqno > &seqno_2 || (seqno == &seqno_2 && metric < &metric_2) - } - } + pub fn get_peer_interfaces(&self) -> Arc>> { + self.peer_interfaces.clone() } } + + From 53addf9f798cc29318b5ad30bf2426b998d90581 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Tue, 9 May 2023 18:03:40 +0000 Subject: [PATCH 27/89] another refactoring v2 --- src/codec.rs | 7 ++----- src/packet.rs | 6 ++---- src/router.rs | 23 +++++++++++++++++++++++ 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/src/codec.rs b/src/codec.rs index ed47b49..f01642e 100644 --- a/src/codec.rs +++ b/src/codec.rs @@ -239,7 +239,7 @@ impl Decoder for ControlPacketCodec { let body = BabelPacketBody { tlv_type, length, - tlv: BabelTLV::IHU { rxcost, interval, address }, + tlv: BabelTLV::IHU { interval, address }, }; body } @@ -300,10 +300,7 @@ impl Encoder for ControlPacketCodec { buf.put_u16(seqno); buf.put_u16(interval); } - BabelTLV::IHU { rxcost, interval, address } => { - buf.put_u8(0); // Temporary static address encoding - buf.put_u8(0); // Reserved field should be set to 0 and MUST be ignored on reception - buf.put_u16(rxcost); + BabelTLV::IHU { interval, address } => { buf.put_u16(interval); match address { IpAddr::V4(ipv4) => { diff --git a/src/packet.rs b/src/packet.rs index a1bde69..2731b12 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -93,7 +93,7 @@ impl ControlPacket { } } - pub fn new_ihu(rxcost: u16, interval: u16, dest_address: IpAddr) -> Self { + pub fn new_ihu(interval: u16, dest_address: IpAddr) -> Self { let uses_ipv6 = match dest_address { IpAddr::V4(_) => false, IpAddr::V6(_) => true, @@ -105,7 +105,6 @@ impl ControlPacket { tlv_type: BabelTLVType::IHU, length: BabelTLVType::IHU.get_tlv_length(uses_ipv6), tlv: BabelTLV::IHU { - rxcost, interval, address: dest_address, } @@ -175,7 +174,7 @@ impl BabelTLVType { Self::AckReq => (4, 4), Self::Ack => (2, 2), Self::Hello => (4, 4), - Self::IHU => (20, 8), + Self::IHU => (18, 6), Self::NextHop => (16, 4), Self::Update => (28, 16), Self::RouteReq => (17, 5), @@ -201,7 +200,6 @@ pub enum BabelTLV { interval: u16, }, IHU { - rxcost: u16, interval: u16, address: IpAddr, }, diff --git a/src/router.rs b/src/router.rs index cdb46bf..90450f8 100644 --- a/src/router.rs +++ b/src/router.rs @@ -16,6 +16,7 @@ use tokio::sync::mpsc::{self, UnboundedReceiver, UnboundedSender}; use tokio_tun::Tun; const HELLO_INTERVAL: u16 = 4; +const IHU_INTERVAL: u16 = HELLO_INTERVAL * 3; #[derive(Clone)] pub struct Router { @@ -50,10 +51,32 @@ impl Router { }; tokio::spawn(Router::periodic_hello_sender(router.clone())); + tokio::spawn(Router::handle_incoming_control_packet(router.clone(), router_control_rx)); router } + async fn handle_incoming_control_packet(self, mut router_control_rx: UnboundedReceiver) { + loop { + while let Some(control_struct) = router_control_rx.recv().await { + match control_struct.control_packet.body.tlv_type { + BabelTLVType::AckReq => todo!(), + BabelTLVType::Ack => todo!(), + BabelTLVType::Hello => Self::handle_incoming_hello(control_struct), + BabelTLVType::IHU => todo!(), + BabelTLVType::NextHop => todo!(), + BabelTLVType::Update => todo!(), + BabelTLVType::RouteReq => todo!(), + BabelTLVType::SeqnoReq => todo!(), + } + } + } + } + + fn handle_incoming_hello(control_struct: ControlStruct) { + let destination_ip = control_struct.src_overlay_ip; + control_struct.reply(ControlPacket::new_ihu(IHU_INTERVAL, destination_ip)); + } async fn periodic_hello_sender(self) { for peer in self.peer_interfaces.lock().unwrap().iter_mut() { From f52289d5552404349845b675b54c82b6ae0b5a04 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Tue, 9 May 2023 18:27:27 +0000 Subject: [PATCH 28/89] another refactoring v2 --- src/peer_manager.rs | 2 +- src/router.rs | 57 ++++++++++++++++++++++++++++++++++++++------- 2 files changed, 49 insertions(+), 10 deletions(-) diff --git a/src/peer_manager.rs b/src/peer_manager.rs index b07a78d..847ca7c 100644 --- a/src/peer_manager.rs +++ b/src/peer_manager.rs @@ -82,7 +82,7 @@ impl PeerManager { let received_overlay_ip = Ipv4Addr::from(buffer); println!( - "Received overlay IP from other node: {:?}", + "3: Received overlay IP from other node: {:?}", received_overlay_ip ); diff --git a/src/router.rs b/src/router.rs index 90450f8..d10fc17 100644 --- a/src/router.rs +++ b/src/router.rs @@ -50,13 +50,14 @@ impl Router { router_seqno: 0, }; - tokio::spawn(Router::periodic_hello_sender(router.clone())); - tokio::spawn(Router::handle_incoming_control_packet(router.clone(), router_control_rx)); + tokio::spawn(Router::start_periodic_hello_sender(router.clone())); + tokio::spawn(Router::handle_incoming_control_packet(router_control_rx)); + tokio::spawn(Router::handle_incoming_data_packets(router.clone(), router_data_rx)); router } - async fn handle_incoming_control_packet(self, mut router_control_rx: UnboundedReceiver) { + async fn handle_incoming_control_packet(mut router_control_rx: UnboundedReceiver) { loop { while let Some(control_struct) = router_control_rx.recv().await { match control_struct.control_packet.body.tlv_type { @@ -73,12 +74,34 @@ impl Router { } } - fn handle_incoming_hello(control_struct: ControlStruct) { - let destination_ip = control_struct.src_overlay_ip; - control_struct.reply(ControlPacket::new_ihu(IHU_INTERVAL, destination_ip)); + async fn handle_incoming_data_packets(self, mut router_data_rx: UnboundedReceiver) { + // If the destination IP of the data packet matches with the IP address of this node's TUN interface + // we should forward the data packet towards the TUN interface. + // If the destination IP doesn't match, we need to lookup if we have a matching peer instance + // where the destination IP matches with the peer's overlay IP. If we do, we should forward the + // data packet to the peer's to_peer_data channel. + loop { + while let Some(data_packet) = router_data_rx.recv().await { + let dest_ip = data_packet.dest_ip; + if dest_ip == self.node_tun.address().unwrap() { + if let Err(e) = self.node_tun.send(&data_packet.raw_data).await { + eprintln!("Error sending data packet to TUN interface: {:?}", e); + } + } else { + let matching_peer = self.get_peer_by_ip(dest_ip); + if let Some(peer) = matching_peer { + if let Err(e) = peer.to_peer_data.send(data_packet) { + eprintln!("Error sending data packet to peer: {:?}", e); + } + } else { + eprintln!("No matching peer found for data packet"); + } + } + } + } } - async fn periodic_hello_sender(self) { + async fn start_periodic_hello_sender(self) { for peer in self.peer_interfaces.lock().unwrap().iter_mut() { let hello = ControlPacket::new_hello(peer.last_sent_hello_seqno, HELLO_INTERVAL); println!("Sending hello to peer: {:?}", peer.stream_ip); @@ -88,6 +111,12 @@ impl Router { } } + fn handle_incoming_hello(control_struct: ControlStruct) { + let destination_ip = control_struct.src_overlay_ip; + control_struct.reply(ControlPacket::new_ihu(IHU_INTERVAL, destination_ip)); + } + + pub fn add_directly_connected_peer(&self, peer: Peer) { self.peer_interfaces.lock().unwrap().push(peer); } @@ -96,8 +125,18 @@ impl Router { self.node_tun.address().unwrap() } - pub fn get_peer_interfaces(&self) -> Arc>> { - self.peer_interfaces.clone() + pub fn get_peer_interfaces(&self) -> Vec { + self.peer_interfaces.lock().unwrap().clone() + } + + fn get_peer_by_ip(&self, peer_ip: Ipv4Addr) -> Option { + let peers = self.get_peer_interfaces(); + let matching_peer = peers.iter().find(|peer| peer.overlay_ip == peer_ip); + + match matching_peer { + Some(peer) => Some(peer.clone()), + None => None, + } } } From 09d88656ed6f9d2f10a420380385116a0765c889 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Wed, 10 May 2023 09:50:11 +0000 Subject: [PATCH 29/89] added timers and IHU timer --- src/codec.rs | 40 +++++++++++++++++------------- src/main.rs | 1 + src/peer.rs | 10 +++++++- src/router.rs | 67 +++++++++++++++++++++++++++++++++++---------------- src/timer.rs | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 145 insertions(+), 39 deletions(-) create mode 100644 src/timer.rs diff --git a/src/codec.rs b/src/codec.rs index f01642e..bf81cce 100644 --- a/src/codec.rs +++ b/src/codec.rs @@ -231,9 +231,6 @@ impl Decoder for ControlPacketCodec { body } BabelTLVType::IHU => { - let _address_encoding = buf.get_u8(); - let _reserved = buf.get_u8(); - let rxcost = buf.get_u16(); let interval = buf.get_u16(); let address = IpAddr::V4(Ipv4Addr::new(buf.get_u8(), buf.get_u8(), buf.get_u8(), buf.get_u8())); let body = BabelPacketBody { @@ -244,24 +241,33 @@ impl Decoder for ControlPacketCodec { body } BabelTLVType::Update => { - let address_encoding = buf.get_u8(); let plen = buf.get_u8(); let interval = buf.get_u16(); let seqno = buf.get_u16(); let metric = buf.get_u16(); - let prefix = match address_encoding { - 0 => IpAddr::V4(Ipv4Addr::new(buf.get_u8(), buf.get_u8(), buf.get_u8(), buf.get_u8())), - 1 => IpAddr::V6(Ipv6Addr::new( - buf.get_u16(), - buf.get_u16(), - buf.get_u16(), - buf.get_u16(), - buf.get_u16(), - buf.get_u16(), - buf.get_u16(), - buf.get_u16(), - )), - _ => return Err(io::Error::new(io::ErrorKind::InvalidData, "Invalid address encoding")), + // based on the remaining bytes (ip + router_id) we can check if it's IPv4 or v6 + let prefix = match buf.remaining() { + 12 => { // 4 bytes IP + 8 bytes router_id + IpAddr::V4(Ipv4Addr::new( + buf.get_u8(), + buf.get_u8(), + buf.get_u8(), + buf.get_u8(), + )) + }, + 24 => { // 16 bytes IP + 8 bytes router_id + IpAddr::V6(Ipv6Addr::new( + buf.get_u16(), + buf.get_u16(), + buf.get_u16(), + buf.get_u16(), + buf.get_u16(), + buf.get_u16(), + buf.get_u16(), + buf.get_u16(), + )) + }, + _ => return Err(io::Error::new(io::ErrorKind::InvalidData, "Invalid address length")), }; let router_id = buf.get_u64(); let body = BabelPacketBody { diff --git a/src/main.rs b/src/main.rs index 8a2b0c2..65c1645 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,6 +12,7 @@ mod peer_manager; mod router; mod routing_table; mod source_table; +mod timer; const LINK_MTU: usize = 1500; diff --git a/src/peer.rs b/src/peer.rs index 2e5d1c4..af5d402 100644 --- a/src/peer.rs +++ b/src/peer.rs @@ -6,9 +6,11 @@ use std::{ use tokio::{net::TcpStream, select, sync::mpsc}; use tokio_util::codec::Framed; -use crate::packet::{ControlPacket, DataPacket, ControlStruct}; +use crate::{packet::{ControlPacket, DataPacket, ControlStruct}, timer::Timer}; use crate::{codec::PacketCodec, packet::Packet}; +const IHU_INTERVAL: u64 = 10; + #[derive(Debug, Clone)] pub struct Peer { pub stream_ip: IpAddr, @@ -17,6 +19,8 @@ pub struct Peer { pub overlay_ip: Ipv4Addr, pub last_sent_hello_seqno: u16, pub link_cost: u16, + + pub IHU_timer: Timer, } impl Peer { @@ -44,6 +48,9 @@ impl Peer { // Initialize last_path_cost to infinity let link_cost = 65535; + // Intialize the timers + let IHU_timer = Timer::new_IHU_timer(IHU_INTERVAL); + tokio::spawn(async move { loop { select! { @@ -115,6 +122,7 @@ impl Peer { overlay_ip, last_sent_hello_seqno, link_cost, + IHU_timer, }) } diff --git a/src/router.rs b/src/router.rs index d10fc17..b7cdabf 100644 --- a/src/router.rs +++ b/src/router.rs @@ -12,6 +12,7 @@ use std::{ net::{IpAddr, Ipv4Addr}, sync::{Arc, Mutex}, }; +use rand::Rng; use tokio::sync::mpsc::{self, UnboundedReceiver, UnboundedSender}; use tokio_tun::Tun; @@ -20,6 +21,7 @@ const IHU_INTERVAL: u16 = HELLO_INTERVAL * 3; #[derive(Clone)] pub struct Router { + pub router_id: u64, // The peer interfaces are the known neighbors of this node peer_interfaces: Arc>>, pub router_control_tx: UnboundedSender, @@ -40,6 +42,7 @@ impl Router { let (router_data_tx, router_data_rx) = mpsc::unbounded_channel::(); let router = Router { + router_id: rand::thread_rng().gen(), peer_interfaces: Arc::new(Mutex::new(Vec::new())), router_control_tx, router_data_tx, @@ -51,20 +54,20 @@ impl Router { }; tokio::spawn(Router::start_periodic_hello_sender(router.clone())); - tokio::spawn(Router::handle_incoming_control_packet(router_control_rx)); + tokio::spawn(Router::handle_incoming_control_packet(router.clone(), router_control_rx)); tokio::spawn(Router::handle_incoming_data_packets(router.clone(), router_data_rx)); router } - async fn handle_incoming_control_packet(mut router_control_rx: UnboundedReceiver) { + async fn handle_incoming_control_packet(self, mut router_control_rx: UnboundedReceiver) { loop { while let Some(control_struct) = router_control_rx.recv().await { match control_struct.control_packet.body.tlv_type { BabelTLVType::AckReq => todo!(), BabelTLVType::Ack => todo!(), BabelTLVType::Hello => Self::handle_incoming_hello(control_struct), - BabelTLVType::IHU => todo!(), + BabelTLVType::IHU => Self::handle_incoming_ihu(&self, control_struct), BabelTLVType::NextHop => todo!(), BabelTLVType::Update => todo!(), BabelTLVType::RouteReq => todo!(), @@ -80,35 +83,44 @@ impl Router { // If the destination IP doesn't match, we need to lookup if we have a matching peer instance // where the destination IP matches with the peer's overlay IP. If we do, we should forward the // data packet to the peer's to_peer_data channel. + + let tun_addr = self.node_tun.address().unwrap(); loop { while let Some(data_packet) = router_data_rx.recv().await { let dest_ip = data_packet.dest_ip; - if dest_ip == self.node_tun.address().unwrap() { - if let Err(e) = self.node_tun.send(&data_packet.raw_data).await { - eprintln!("Error sending data packet to TUN interface: {:?}", e); + + if dest_ip == tun_addr { + match self.node_tun.send(&data_packet.raw_data).await { + Ok(_) => {}, + Err(e) => eprintln!("Error sending data packet to TUN interface: {:?}", e), } } else { - let matching_peer = self.get_peer_by_ip(dest_ip); - if let Some(peer) = matching_peer { - if let Err(e) = peer.to_peer_data.send(data_packet) { - eprintln!("Error sending data packet to peer: {:?}", e); - } - } else { - eprintln!("No matching peer found for data packet"); + match self.get_peer_by_ip(IpAddr::V4(dest_ip)) { + Some(peer) => { + match peer.to_peer_data.send(data_packet) { + Ok(_) => {}, + Err(e) => eprintln!("Error sending data packet to peer: {:?}", e), + } + }, + None => eprintln!("No matching peer found for data packet"), } } } } } + async fn start_periodic_hello_sender(self) { - for peer in self.peer_interfaces.lock().unwrap().iter_mut() { - let hello = ControlPacket::new_hello(peer.last_sent_hello_seqno, HELLO_INTERVAL); - println!("Sending hello to peer: {:?}", peer.stream_ip); - if let Err(error) = peer.to_peer_control.send(hello) { - eprintln!("Error sending hello to peer: {}", error); - } - } + loop { + tokio::time::sleep(tokio::time::Duration::from_secs(HELLO_INTERVAL as u64)).await; + for peer in self.peer_interfaces.lock().unwrap().iter_mut() { + let hello = ControlPacket::new_hello(peer.last_sent_hello_seqno, HELLO_INTERVAL); + println!("Sending hello to peer: {:?}", peer.overlay_ip); + if let Err(error) = peer.to_peer_control.send(hello) { + eprintln!("Error sending hello to peer: {}", error); + } + } + } } fn handle_incoming_hello(control_struct: ControlStruct) { @@ -116,6 +128,13 @@ impl Router { control_struct.reply(ControlPacket::new_ihu(IHU_INTERVAL, destination_ip)); } + fn handle_incoming_ihu(&self, control_struct: ControlStruct) { + // reset the IHU timer associated with the peer + let source_peer = self.get_source_peer_from_control_struct(control_struct); + source_peer.IHU_timer.reset(tokio::time::Duration::from_secs(IHU_INTERVAL as u64)); + println!("IHU timer for peer {:?} reset", source_peer.overlay_ip); + } + pub fn add_directly_connected_peer(&self, peer: Peer) { self.peer_interfaces.lock().unwrap().push(peer); @@ -129,7 +148,7 @@ impl Router { self.peer_interfaces.lock().unwrap().clone() } - fn get_peer_by_ip(&self, peer_ip: Ipv4Addr) -> Option { + fn get_peer_by_ip(&self, peer_ip: IpAddr) -> Option { let peers = self.get_peer_interfaces(); let matching_peer = peers.iter().find(|peer| peer.overlay_ip == peer_ip); @@ -138,6 +157,12 @@ impl Router { None => None, } } + + fn get_source_peer_from_control_struct(&self, control_struct: ControlStruct) -> Peer { + let source = control_struct.src_overlay_ip; + + self.get_peer_by_ip(source).unwrap() + } } diff --git a/src/timer.rs b/src/timer.rs new file mode 100644 index 0000000..6221b12 --- /dev/null +++ b/src/timer.rs @@ -0,0 +1,66 @@ +use std::sync::{Arc, Mutex}; +use std::time::Duration; +use tokio::time::sleep; +use tokio::sync::oneshot; + +#[derive(Clone, Debug)] +pub struct Timer { + duration: Arc>, + cancel_tx: Arc>>>, +} + +impl Timer { + pub fn new(duration: Duration) -> Self { + Self { + duration: Arc::new(Mutex::new(duration)), + cancel_tx: Arc::new(Mutex::new(None)), + } + } + + pub fn reset(&self, duration: Duration) { + let mut cancel_tx = self.cancel_tx.lock().unwrap(); + if let Some(tx) = cancel_tx.take() { + let _ = tx.send(()); + } + *self.duration.lock().unwrap() = duration; + } + + // on_expire is of a type that implements the Fn trait, which means it's a function or a closure. + // The + Send + 'static part means this function must also satisfy the Send trait (meaning it can be sent between threads safely) + // and have a 'static lifetime (meaning it doesn't capture any non-'static (i.e., temporary) values from its environment). + // This is necessary because the function could be called at any point in the future, + // potentially long after the context it was created in has gone away. + + async fn run(&self, on_expire: impl Fn() + Send + 'static) { + loop { + let (tx, rx) = oneshot::channel(); + *self.cancel_tx.lock().unwrap() = Some(tx); + let duration = *self.duration.lock().unwrap(); + tokio::select! { + _ = sleep(duration) => { + on_expire(); + } + _ = rx => {} + } + } + } + + pub fn new_IHU_timer(ihu_interval: u64) -> Timer{ + + let timer = Timer::new(Duration::from_secs(ihu_interval)); + + { + let timer = timer.clone(); + + tokio::spawn(async move { + timer.run(|| { + println!("IHU Timer expired!"); + // on expiry the neighbour link should be set to 0xFFFF + // and the route selection process should be run + }).await; + }); + } + + timer + } +} From 4c1d1f3cd30876862f3d7281769eee4a720ef273 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Wed, 10 May 2023 11:50:16 +0000 Subject: [PATCH 30/89] added link cost --- src/packet.rs | 7 +++++-- src/peer.rs | 20 ++++++++++++-------- src/router.rs | 14 +++++++++++--- src/timer.rs | 5 ++++- 4 files changed, 32 insertions(+), 14 deletions(-) diff --git a/src/packet.rs b/src/packet.rs index 2731b12..82af95c 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -1,6 +1,8 @@ use std::net::{IpAddr, Ipv4Addr}; use tokio::sync::mpsc; +use crate::peer::Peer; + pub const BABEL_MAGIC: u8 = 42; pub const BABEL_VERSION: u8 = 2; @@ -78,15 +80,16 @@ impl BabelPacketHeader { impl ControlPacket { - pub fn new_hello(seqno: u16, interval: u16) -> Self { + pub fn new_hello(dest_peer: &mut Peer, interval: u16) -> Self { let header_length = (BabelTLVType::Hello.get_tlv_length(false) + 2) as u16; + dest_peer.increase_hello_seqno(); Self { header: BabelPacketHeader::new(header_length), body: BabelPacketBody { tlv_type: BabelTLVType::Hello, length: BabelTLVType::Hello.get_tlv_length(false), tlv: BabelTLV::Hello { - seqno, + seqno: dest_peer.hello_seqno, interval, } }, diff --git a/src/peer.rs b/src/peer.rs index af5d402..723ec07 100644 --- a/src/peer.rs +++ b/src/peer.rs @@ -17,10 +17,11 @@ pub struct Peer { pub to_peer_data: mpsc::UnboundedSender, pub to_peer_control: mpsc::UnboundedSender, pub overlay_ip: Ipv4Addr, - pub last_sent_hello_seqno: u16, + pub hello_seqno: u16, + pub time_last_received_hello: tokio::time::Instant, pub link_cost: u16, - pub IHU_timer: Timer, + pub ihu_timer: Timer, } impl Peer { @@ -44,12 +45,14 @@ impl Peer { let (control_reply_tx, mut control_reply_rx) = mpsc::unbounded_channel::(); // Initialize last_sent_hello_seqno to 0 - let last_sent_hello_seqno = 0; + let hello_seqno = 0; // Initialize last_path_cost to infinity let link_cost = 65535; + // Initialize time_last_received_hello to now + let time_last_received_hello = tokio::time::Instant::now(); // Intialize the timers - let IHU_timer = Timer::new_IHU_timer(IHU_INTERVAL); + let ihu_timer = Timer::new_ihu_timer(IHU_INTERVAL); tokio::spawn(async move { loop { @@ -120,14 +123,15 @@ impl Peer { to_peer_data, to_peer_control, overlay_ip, - last_sent_hello_seqno, + hello_seqno, link_cost, - IHU_timer, + ihu_timer, + time_last_received_hello, }) } pub fn increase_hello_seqno(&mut self) { - self.last_sent_hello_seqno = self.last_sent_hello_seqno + 1; - println!("last hello seqno increasted to {}", self.last_sent_hello_seqno); + self.hello_seqno = self.hello_seqno + 1; + println!("last hello seqno increasted to {}", self.hello_seqno); } } \ No newline at end of file diff --git a/src/router.rs b/src/router.rs index b7cdabf..1858151 100644 --- a/src/router.rs +++ b/src/router.rs @@ -114,7 +114,11 @@ impl Router { loop { tokio::time::sleep(tokio::time::Duration::from_secs(HELLO_INTERVAL as u64)).await; for peer in self.peer_interfaces.lock().unwrap().iter_mut() { - let hello = ControlPacket::new_hello(peer.last_sent_hello_seqno, HELLO_INTERVAL); + // create a new hello packet for this peer + let hello = ControlPacket::new_hello(peer, HELLO_INTERVAL); + // set the last hello timestamp for this peer + peer.time_last_received_hello = tokio::time::Instant::now(); + // send the hello packet to the peer println!("Sending hello to peer: {:?}", peer.overlay_ip); if let Err(error) = peer.to_peer_control.send(hello) { eprintln!("Error sending hello to peer: {}", error); @@ -129,9 +133,13 @@ impl Router { } fn handle_incoming_ihu(&self, control_struct: ControlStruct) { + let mut source_peer = self.get_source_peer_from_control_struct(control_struct); // reset the IHU timer associated with the peer - let source_peer = self.get_source_peer_from_control_struct(control_struct); - source_peer.IHU_timer.reset(tokio::time::Duration::from_secs(IHU_INTERVAL as u64)); + source_peer.ihu_timer.reset(tokio::time::Duration::from_secs(IHU_INTERVAL as u64)); + // measure time between Hello and and IHU and set the link cost + source_peer.link_cost = tokio::time::Instant::now().duration_since(source_peer.time_last_received_hello).as_millis() as u16; + println!("Link cost for peer {:?} set to {}", source_peer.overlay_ip, source_peer.link_cost); + println!("IHU timer for peer {:?} reset", source_peer.overlay_ip); } diff --git a/src/timer.rs b/src/timer.rs index 6221b12..0418f37 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -45,7 +45,7 @@ impl Timer { } } - pub fn new_IHU_timer(ihu_interval: u64) -> Timer{ + pub fn new_ihu_timer(ihu_interval: u64) -> Timer{ let timer = Timer::new(Duration::from_secs(ihu_interval)); @@ -63,4 +63,7 @@ impl Timer { timer } + + // add update timer + // add ack timer } From 6f9a69c5fd10179482e166e9073cc80b4963092d Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Wed, 10 May 2023 15:10:13 +0000 Subject: [PATCH 31/89] added route expiry timer --- src/main.rs | 47 +++++++++++++++++++++++++++++++++++-- src/peer.rs | 13 +++++----- src/router.rs | 10 ++++---- src/routing_table.rs | 37 +++++++++++++++++++++++++++-- src/source_table.rs | 2 +- src/{timer.rs => timers.rs} | 19 +++++++++++++++ 6 files changed, 110 insertions(+), 18 deletions(-) rename src/{timer.rs => timers.rs} (79%) diff --git a/src/main.rs b/src/main.rs index 65c1645..e3bf001 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,7 +2,10 @@ use bytes::BytesMut; use clap::Parser; use etherparse::{IpHeader, PacketHeaders}; use packet::DataPacket; -use std::{error::Error, net::{Ipv4Addr, SocketAddr}, sync::Arc}; +use router::Router; +use routing_table::{RouteEntry, RouteKey}; +use source_table::{SourceKey, FeasibilityDistance}; +use std::{error::Error, net::{Ipv4Addr, SocketAddr, IpAddr}, sync::Arc}; mod codec; mod node_setup; @@ -12,7 +15,7 @@ mod peer_manager; mod router; mod routing_table; mod source_table; -mod timer; +mod timers; const LINK_MTU: usize = 1500; @@ -47,6 +50,45 @@ async fn main() -> Result<(), Box> { 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()), + }; + // creates a route entry for the node and also creates an update timer for the route + let route_entry = RouteEntry::new( + source_key.clone(), + router.get_peer_by_ip(IpAddr::V4(node_tun.address().unwrap())).unwrap(), + router.get_peer_by_ip(IpAddr::V4(node_tun.address().unwrap())).unwrap().link_cost, + 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 { @@ -95,3 +137,4 @@ async fn main() -> Result<(), Box> { Ok(()) } + diff --git a/src/peer.rs b/src/peer.rs index 723ec07..1f34499 100644 --- a/src/peer.rs +++ b/src/peer.rs @@ -6,7 +6,7 @@ use std::{ use tokio::{net::TcpStream, select, sync::mpsc}; use tokio_util::codec::Framed; -use crate::{packet::{ControlPacket, DataPacket, ControlStruct}, timer::Timer}; +use crate::{packet::{ControlPacket, DataPacket, ControlStruct}, timers::Timer}; use crate::{codec::PacketCodec, packet::Packet}; const IHU_INTERVAL: u64 = 10; @@ -47,7 +47,7 @@ impl Peer { // Initialize last_sent_hello_seqno to 0 let hello_seqno = 0; // Initialize last_path_cost to infinity - let link_cost = 65535; + let link_cost = 100; // Initialize time_last_received_hello to now let time_last_received_hello = tokio::time::Instant::now(); @@ -65,9 +65,8 @@ impl Peer { match packet { Packet::DataPacket(packet) => { if let Err(error) = router_data_tx.send(packet){ - eprintln!("Error sending to to_routing_data: {}", error); + eprintln!("Error sending to to_routing_data: {}", error); } - } Packet::ControlPacket(packet) => { // Parse the DataPacket into a ControlStruct as the to_routing_control channel expects @@ -79,8 +78,8 @@ impl Peer { // we set the src_overlay_ip to the overlay_ip of the peer // as we 'arrived' in the peer instance of representing the sending node on this current node }; - if let Err(error) = router_control_tx.send(control_struct){ - eprintln!("Error sending to to_routing_control: {}", error); + if let Err(error) = router_control_tx.send(control_struct) { + eprintln!("Error sending to to_routing_control: {}", error); } } @@ -93,8 +92,8 @@ impl Peer { println!("Stream is closed."); return } - } } + } Some(packet) = from_routing_data.recv() => { // Send it over the TCP stream diff --git a/src/router.rs b/src/router.rs index 1858151..cbf2126 100644 --- a/src/router.rs +++ b/src/router.rs @@ -5,7 +5,7 @@ use crate::{ }, peer::Peer, routing_table::{RouteEntry, RouteKey, RoutingTable}, - source_table::{SourceKey, SourceTable, FeasibilityDistance}, + source_table::{SourceKey, SourceTable, FeasibilityDistance}, timers::Timer, }; use std::{ collections::HashMap, @@ -18,6 +18,7 @@ use tokio_tun::Tun; const HELLO_INTERVAL: u16 = 4; const IHU_INTERVAL: u16 = HELLO_INTERVAL * 3; +const UPDATE_INTERVAL: u16 = HELLO_INTERVAL * 4; #[derive(Clone)] pub struct Router { @@ -27,7 +28,6 @@ pub struct Router { pub router_control_tx: UnboundedSender, pub router_data_tx: UnboundedSender, pub node_tun: Arc, - pub sent_hello_timestamps: Arc>>, pub routing_table: Arc>, pub source_table: Arc>, pub router_seqno: u16, @@ -47,15 +47,14 @@ impl Router { router_control_tx, router_data_tx, node_tun, - sent_hello_timestamps: Arc::new(Mutex::new(HashMap::new())), routing_table: Arc::new(Mutex::new(RoutingTable::new())), source_table: Arc::new(Mutex::new(SourceTable::new())), router_seqno: 0, }; - tokio::spawn(Router::start_periodic_hello_sender(router.clone())); tokio::spawn(Router::handle_incoming_control_packet(router.clone(), router_control_rx)); tokio::spawn(Router::handle_incoming_data_packets(router.clone(), router_data_rx)); + tokio::spawn(Router::start_periodic_hello_sender(router.clone())); router } @@ -143,7 +142,6 @@ impl Router { println!("IHU timer for peer {:?} reset", source_peer.overlay_ip); } - pub fn add_directly_connected_peer(&self, peer: Peer) { self.peer_interfaces.lock().unwrap().push(peer); } @@ -156,7 +154,7 @@ impl Router { self.peer_interfaces.lock().unwrap().clone() } - fn get_peer_by_ip(&self, peer_ip: IpAddr) -> Option { + pub fn get_peer_by_ip(&self, peer_ip: IpAddr) -> Option { let peers = self.get_peer_interfaces(); let matching_peer = peers.iter().find(|peer| peer.overlay_ip == peer_ip); diff --git a/src/routing_table.rs b/src/routing_table.rs index 51af664..ed465cc 100644 --- a/src/routing_table.rs +++ b/src/routing_table.rs @@ -1,6 +1,10 @@ use std::{net::IpAddr, collections::HashMap}; -use crate::{source_table::SourceKey, peer::Peer}; +use crate::{source_table::SourceKey, peer::Peer, timers::Timer}; + +const HELLO_INTERVAL: u16 = 4; +const IHU_INTERVAL: u16 = HELLO_INTERVAL * 3; +const UPDATE_INTERVAL: u16 = HELLO_INTERVAL * 4; #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct RouteKey { @@ -17,9 +21,38 @@ pub struct RouteEntry { pub seqno: u16, pub next_hop: IpAddr, // This is the Peer's address pub selected: bool, - // route_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 { + Self { + source, + neighbor, + metric, + 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 retracted(&mut self) { + self.metric = 0xFFFF; + } + + pub fn is_retracted(&self) -> bool { + self.metric == 0xFFFF + } +} + + #[derive(Debug, Clone)] pub struct RoutingTable { pub table: HashMap, diff --git a/src/source_table.rs b/src/source_table.rs index a891fd8..9232eaf 100644 --- a/src/source_table.rs +++ b/src/source_table.rs @@ -1,6 +1,6 @@ use std::{net::IpAddr, collections::HashMap}; -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)] pub struct SourceKey { pub prefix: IpAddr, pub plen: u8, diff --git a/src/timer.rs b/src/timers.rs similarity index 79% rename from src/timer.rs rename to src/timers.rs index 0418f37..9dd8b61 100644 --- a/src/timer.rs +++ b/src/timers.rs @@ -3,6 +3,8 @@ use std::time::Duration; use tokio::time::sleep; use tokio::sync::oneshot; +use crate::router::Router; + #[derive(Clone, Debug)] pub struct Timer { duration: Arc>, @@ -55,6 +57,7 @@ impl Timer { tokio::spawn(async move { timer.run(|| { println!("IHU Timer expired!"); + // node should be assumed as dead // on expiry the neighbour link should be set to 0xFFFF // and the route selection process should be run }).await; @@ -65,5 +68,21 @@ impl 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 } From c202ecd690c4913323c80808d335d6d302795ebe Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Thu, 11 May 2023 09:30:55 +0000 Subject: [PATCH 32/89] update --- src/main.rs | 106 ++++++++++++++++++++++++++++++++++---------------- src/peer.rs | 13 +++++++ src/router.rs | 8 ++++ 3 files changed, 94 insertions(+), 33 deletions(-) diff --git a/src/main.rs b/src/main.rs index e3bf001..0d2612e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,8 +5,11 @@ use packet::DataPacket; use router::Router; use routing_table::{RouteEntry, RouteKey}; use source_table::{SourceKey, FeasibilityDistance}; +use tokio::io::AsyncBufReadExt; use std::{error::Error, net::{Ipv4Addr, SocketAddr, IpAddr}, sync::Arc}; +use crate::peer::Peer; + mod codec; mod node_setup; mod packet; @@ -53,46 +56,51 @@ async fn main() -> Result<(), Box> { // 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); + // { + // // 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 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()), - }; - // creates a route entry for the node and also creates an update timer for the route - let route_entry = RouteEntry::new( - source_key.clone(), - router.get_peer_by_ip(IpAddr::V4(node_tun.address().unwrap())).unwrap(), - router.get_peer_by_ip(IpAddr::V4(node_tun.address().unwrap())).unwrap().link_cost, - router.router_seqno, - IpAddr::V4(node_tun.address().unwrap()), - true, - ); + // // 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()), + // }; - router.routing_table.lock().unwrap().insert(route_key, route_entry); + // // 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 { let node_tun = node_tun.clone(); + let router = router.clone(); tokio::spawn(async move { loop { @@ -132,8 +140,40 @@ async fn main() -> Result<(), Box> { }); } - // Just die after 1 day, you've probably leaked memory by then anyway - tokio::time::sleep(std::time::Duration::from_secs(60 * 60 * 24)).await; + let mut reader = tokio::io::BufReader::new(tokio::io::stdin()); + let mut line = String::new(); + let router = router.clone(); + + let read_handle = tokio::spawn(async move { + loop { + line.clear(); + match reader.read_line(&mut line).await { + Ok(0) => return, // EOF, quit + Ok(_) => { + // Remove trailing newline + line.pop(); + println!("Current routes \n: {}", line); + router.print_routes(); + + println!("Current peers: \n: {:?}", router.get_peer_interfaces()); + } + Err(e) => { + eprintln!("Error reading line: {}", e); + return; + } + } + } + }); + + let sleep_handle = tokio::spawn(async move { + // Just die after 1 day, you've probably leaked memory by then anyway + tokio::time::sleep(tokio::time::Duration::from_secs(60 * 60 * 24)).await; + }); + + tokio::select! { + _ = read_handle => { /* The read task completed (this should never happen) */ } + _ = sleep_handle => { /* The sleep task completed (the program should exit here) */ } + } Ok(()) } diff --git a/src/peer.rs b/src/peer.rs index 1f34499..8bcdb07 100644 --- a/src/peer.rs +++ b/src/peer.rs @@ -129,6 +129,19 @@ impl Peer { }) } + pub fn new_dummy(overlay_ip: Ipv4Addr) -> Peer { + Peer { + stream_ip: IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), + to_peer_data: mpsc::unbounded_channel::().0, + to_peer_control: mpsc::unbounded_channel::().0, + overlay_ip, + hello_seqno: 0, + link_cost: 100, + ihu_timer: Timer::new_ihu_timer(u64::MAX), + time_last_received_hello: tokio::time::Instant::now(), + } + } + pub fn increase_hello_seqno(&mut self) { self.hello_seqno = self.hello_seqno + 1; println!("last hello seqno increasted to {}", self.hello_seqno); diff --git a/src/router.rs b/src/router.rs index cbf2126..5248e58 100644 --- a/src/router.rs +++ b/src/router.rs @@ -169,6 +169,14 @@ impl Router { self.get_peer_by_ip(source).unwrap() } + + pub fn print_routes(&self) { + let routing_table = self.routing_table.lock().unwrap(); + for route in routing_table.table.iter() { + println!("Route: {:?}/{:?} (with next-hop: {:?})", route.0.prefix, route.0.plen, route.1.next_hop); + println!("As advertised by: {:?}", route.1.source.router_id); + } + } } From 92bca4152bf51f1d504a7e66783863deaec4e909 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Thu, 11 May 2023 12:09:26 +0000 Subject: [PATCH 33/89] test route propagation --- src/peer.rs | 4 ++-- src/router.rs | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++- src/timers.rs | 1 + 3 files changed, 56 insertions(+), 3 deletions(-) diff --git a/src/peer.rs b/src/peer.rs index 8bcdb07..132beae 100644 --- a/src/peer.rs +++ b/src/peer.rs @@ -46,8 +46,8 @@ impl Peer { // Initialize last_sent_hello_seqno to 0 let hello_seqno = 0; - // Initialize last_path_cost to infinity - let link_cost = 100; + // Initialize last_path_cost to infinity - 1 + let link_cost = u16::MAX -1; // Initialize time_last_received_hello to now let time_last_received_hello = tokio::time::Instant::now(); diff --git a/src/router.rs b/src/router.rs index 5248e58..d7897ac 100644 --- a/src/router.rs +++ b/src/router.rs @@ -5,7 +5,7 @@ use crate::{ }, peer::Peer, routing_table::{RouteEntry, RouteKey, RoutingTable}, - source_table::{SourceKey, SourceTable, FeasibilityDistance}, timers::Timer, + source_table::{SourceKey, SourceTable, FeasibilityDistance}, timers::{Timer, self}, }; use std::{ collections::HashMap, @@ -55,6 +55,7 @@ impl Router { tokio::spawn(Router::handle_incoming_control_packet(router.clone(), router_control_rx)); tokio::spawn(Router::handle_incoming_data_packets(router.clone(), router_data_rx)); tokio::spawn(Router::start_periodic_hello_sender(router.clone())); + tokio::spawn(Router::initialize_peer_route_entries(router.clone())); router } @@ -177,6 +178,57 @@ impl Router { println!("As advertised by: {:?}", route.1.source.router_id); } } + + // loop over the directly connected peers and create routing table entries for them + // 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 + async fn initialize_peer_route_entries(self) { + loop { + for peer in self.peer_interfaces.lock().unwrap().iter_mut() { + // we check for the u16::MAX - 1 value, as this is the value that the link cost is initialized to + if peer.link_cost == (u16::MAX - 1) { + // before we can create a routing table entry, we need to create a source table entry + let source_key = SourceKey { + prefix: IpAddr::V4(peer.overlay_ip), + plen: 32, // we set the prefix length to 32 for now, this means that each peer is a /32 network (so only route to the peer itself) + router_id: 0, // we set all router ids to 0 temporarily + }; + let feas_dist = FeasibilityDistance(peer.link_cost, 0); + + // create the source table entry + let source_key_clone = source_key.clone(); + self.source_table + .lock() + .unwrap() + .insert(source_key, feas_dist); + + // now we can create the routing table entry + let route_key = RouteKey { + prefix: IpAddr::V4(peer.overlay_ip), + plen: 32, // we set the prefix length to 32 for now, this means that each peer is a /32 network (so only route to the peer itself) + neighbor: IpAddr::V4(peer.overlay_ip), + }; + let route_entry = RouteEntry { + source: source_key_clone, + neighbor: peer.clone(), + metric: peer.link_cost, + 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); + } + } + } + } + + // 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) { + } } diff --git a/src/timers.rs b/src/timers.rs index 9dd8b61..8e9ce40 100644 --- a/src/timers.rs +++ b/src/timers.rs @@ -78,6 +78,7 @@ impl Timer { timer.run(|| { println!("Route timer expired! Sending routes..."); // send update packet of that route to all peers + }).await; }); } From eeb21c5a9c9f094764130dcd223b8f936a44d089 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Thu, 11 May 2023 12:40:55 +0000 Subject: [PATCH 34/89] test route propagation v2 --- src/peer_manager.rs | 2 ++ src/router.rs | 71 ++++++++++++++++++++++----------------------- 2 files changed, 37 insertions(+), 36 deletions(-) diff --git a/src/peer_manager.rs b/src/peer_manager.rs index 847ca7c..05332ed 100644 --- a/src/peer_manager.rs +++ b/src/peer_manager.rs @@ -62,6 +62,7 @@ impl PeerManager { received_overlay_ip, ) { self.router.add_directly_connected_peer(new_peer); + self.router.initialize_peer_route_entries(); } } } @@ -98,6 +99,7 @@ impl PeerManager { received_overlay_ip, ) { self.router.add_directly_connected_peer(new_peer); + self.router.initialize_peer_route_entries(); } } } diff --git a/src/router.rs b/src/router.rs index d7897ac..7feeb73 100644 --- a/src/router.rs +++ b/src/router.rs @@ -182,44 +182,42 @@ impl Router { // loop over the directly connected peers and create routing table entries for them // 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 - async fn initialize_peer_route_entries(self) { - loop { - for peer in self.peer_interfaces.lock().unwrap().iter_mut() { - // we check for the u16::MAX - 1 value, as this is the value that the link cost is initialized to - if peer.link_cost == (u16::MAX - 1) { - // before we can create a routing table entry, we need to create a source table entry - let source_key = SourceKey { - prefix: IpAddr::V4(peer.overlay_ip), - plen: 32, // we set the prefix length to 32 for now, this means that each peer is a /32 network (so only route to the peer itself) - router_id: 0, // we set all router ids to 0 temporarily - }; - let feas_dist = FeasibilityDistance(peer.link_cost, 0); + pub fn initialize_peer_route_entries(&self) { + for peer in self.peer_interfaces.lock().unwrap().iter_mut() { + // we check for the u16::MAX - 1 value, as this is the value that the link cost is initialized to + if peer.link_cost == (u16::MAX - 1) { + // before we can create a routing table entry, we need to create a source table entry + let source_key = SourceKey { + prefix: IpAddr::V4(peer.overlay_ip), + plen: 32, // we set the prefix length to 32 for now, this means that each peer is a /32 network (so only route to the peer itself) + router_id: 0, // we set all router ids to 0 temporarily + }; + let feas_dist = FeasibilityDistance(peer.link_cost, 0); - // create the source table entry - let source_key_clone = source_key.clone(); - self.source_table - .lock() - .unwrap() - .insert(source_key, feas_dist); + // create the source table entry + let source_key_clone = source_key.clone(); + self.source_table + .lock() + .unwrap() + .insert(source_key, feas_dist); - // now we can create the routing table entry - let route_key = RouteKey { - prefix: IpAddr::V4(peer.overlay_ip), - plen: 32, // we set the prefix length to 32 for now, this means that each peer is a /32 network (so only route to the peer itself) - neighbor: IpAddr::V4(peer.overlay_ip), - }; - let route_entry = RouteEntry { - source: source_key_clone, - neighbor: peer.clone(), - metric: peer.link_cost, - 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); - } + // now we can create the routing table entry + let route_key = RouteKey { + prefix: IpAddr::V4(peer.overlay_ip), + plen: 32, // we set the prefix length to 32 for now, this means that each peer is a /32 network (so only route to the peer itself) + neighbor: IpAddr::V4(peer.overlay_ip), + }; + let route_entry = RouteEntry { + source: source_key_clone, + neighbor: peer.clone(), + metric: peer.link_cost, + 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); } } } @@ -228,6 +226,7 @@ impl Router { // 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(); } } From cc7c0831e2c9bd045c27aeb201cff573d2db1793 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Thu, 11 May 2023 12:42:25 +0000 Subject: [PATCH 35/89] test route propagation v3 --- src/router.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/router.rs b/src/router.rs index 7feeb73..d00781b 100644 --- a/src/router.rs +++ b/src/router.rs @@ -55,7 +55,6 @@ impl Router { tokio::spawn(Router::handle_incoming_control_packet(router.clone(), router_control_rx)); tokio::spawn(Router::handle_incoming_data_packets(router.clone(), router_data_rx)); tokio::spawn(Router::start_periodic_hello_sender(router.clone())); - tokio::spawn(Router::initialize_peer_route_entries(router.clone())); router } @@ -227,6 +226,9 @@ impl Router { // this function is run when the route_update timer expires pub fn propagate_update(self) { let router_table = self.routing_table.lock().unwrap(); + + // loop over all directly connected peers + } } From 7ca67c61f1ea1576e253f87f3a0e7be9fac4f01f Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Thu, 11 May 2023 13:01:05 +0000 Subject: [PATCH 36/89] test route propagation v4 --- src/peer_manager.rs | 2 -- src/router.rs | 75 +++++++++++++++++++++++++-------------------- 2 files changed, 41 insertions(+), 36 deletions(-) diff --git a/src/peer_manager.rs b/src/peer_manager.rs index 05332ed..847ca7c 100644 --- a/src/peer_manager.rs +++ b/src/peer_manager.rs @@ -62,7 +62,6 @@ impl PeerManager { received_overlay_ip, ) { self.router.add_directly_connected_peer(new_peer); - self.router.initialize_peer_route_entries(); } } } @@ -99,7 +98,6 @@ impl PeerManager { received_overlay_ip, ) { self.router.add_directly_connected_peer(new_peer); - self.router.initialize_peer_route_entries(); } } } diff --git a/src/router.rs b/src/router.rs index d00781b..c7a4d87 100644 --- a/src/router.rs +++ b/src/router.rs @@ -56,6 +56,9 @@ impl Router { tokio::spawn(Router::handle_incoming_data_packets(router.clone(), router_data_rx)); tokio::spawn(Router::start_periodic_hello_sender(router.clone())); + // loops over all peers and adds routing table entries for each peer + tokio::spawn(Router::initialize_peer_route_entries(router.clone())); + router } @@ -181,44 +184,48 @@ impl Router { // loop over the directly connected peers and create routing table entries for them // 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 fn initialize_peer_route_entries(&self) { - for peer in self.peer_interfaces.lock().unwrap().iter_mut() { - // we check for the u16::MAX - 1 value, as this is the value that the link cost is initialized to - if peer.link_cost == (u16::MAX - 1) { - // before we can create a routing table entry, we need to create a source table entry - let source_key = SourceKey { - prefix: IpAddr::V4(peer.overlay_ip), - plen: 32, // we set the prefix length to 32 for now, this means that each peer is a /32 network (so only route to the peer itself) - router_id: 0, // we set all router ids to 0 temporarily - }; - let feas_dist = FeasibilityDistance(peer.link_cost, 0); + pub async fn initialize_peer_route_entries(self) { + loop { + tokio::time::sleep(tokio::time::Duration::from_secs(10)).await; + for peer in self.peer_interfaces.lock().unwrap().iter_mut() { + // we check for the u16::MAX - 1 value, as this is the value that the link cost is initialized to + if peer.link_cost == (u16::MAX - 1) { + // before we can create a routing table entry, we need to create a source table entry + let source_key = SourceKey { + prefix: IpAddr::V4(peer.overlay_ip), + plen: 32, // we set the prefix length to 32 for now, this means that each peer is a /32 network (so only route to the peer itself) + router_id: 0, // we set all router ids to 0 temporarily + }; + let feas_dist = FeasibilityDistance(peer.link_cost, 0); - // create the source table entry - let source_key_clone = source_key.clone(); - self.source_table - .lock() - .unwrap() - .insert(source_key, feas_dist); + // create the source table entry + let source_key_clone = source_key.clone(); + self.source_table + .lock() + .unwrap() + .insert(source_key, feas_dist); - // now we can create the routing table entry - let route_key = RouteKey { - prefix: IpAddr::V4(peer.overlay_ip), - plen: 32, // we set the prefix length to 32 for now, this means that each peer is a /32 network (so only route to the peer itself) - neighbor: IpAddr::V4(peer.overlay_ip), - }; - let route_entry = RouteEntry { - source: source_key_clone, - neighbor: peer.clone(), - metric: peer.link_cost, - 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); + // now we can create the routing table entry + let route_key = RouteKey { + prefix: IpAddr::V4(peer.overlay_ip), + plen: 32, // we set the prefix length to 32 for now, this means that each peer is a /32 network (so only route to the peer itself) + neighbor: IpAddr::V4(peer.overlay_ip), + }; + let route_entry = RouteEntry { + source: source_key_clone, + neighbor: peer.clone(), + metric: peer.link_cost, + 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); + } } } + } // routing table updates are send periodically to all directly connected peers From fa280aebf5eceaf814c263e4dd9f64be20af7a96 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Thu, 11 May 2023 16:00:01 +0000 Subject: [PATCH 37/89] 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 } From 50ad0760208b301f8869211ebf4c5685973bc5d2 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Thu, 11 May 2023 16:14:15 +0000 Subject: [PATCH 38/89] ae encoding --- src/codec.rs | 8 +++++--- src/router.rs | 1 - 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/codec.rs b/src/codec.rs index bf81cce..7059e81 100644 --- a/src/codec.rs +++ b/src/codec.rs @@ -241,13 +241,14 @@ impl Decoder for ControlPacketCodec { body } BabelTLVType::Update => { + let ae = buf.get_u8(); let plen = buf.get_u8(); let interval = buf.get_u16(); let seqno = buf.get_u16(); let metric = buf.get_u16(); // based on the remaining bytes (ip + router_id) we can check if it's IPv4 or v6 - let prefix = match buf.remaining() { - 12 => { // 4 bytes IP + 8 bytes router_id + let prefix = match ae { + 0 => { // 4 bytes IP + 8 bytes router_id IpAddr::V4(Ipv4Addr::new( buf.get_u8(), buf.get_u8(), @@ -255,7 +256,7 @@ impl Decoder for ControlPacketCodec { buf.get_u8(), )) }, - 24 => { // 16 bytes IP + 8 bytes router_id + 1 => { // 16 bytes IP + 8 bytes router_id IpAddr::V6(Ipv6Addr::new( buf.get_u16(), buf.get_u16(), @@ -321,6 +322,7 @@ impl Encoder for ControlPacketCodec { } } BabelTLV::Update { plen , interval, seqno, metric, prefix , router_id} => { + buf.put_u8(if prefix.is_ipv4(){0} else {1}); buf.put_u8(plen); buf.put_u16(interval); buf.put_u16(seqno); diff --git a/src/router.rs b/src/router.rs index 5e53839..4b110f0 100644 --- a/src/router.rs +++ b/src/router.rs @@ -163,7 +163,6 @@ impl Router { 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 }) { From 64b3b804a712a439ba29472e6d565999cc72c257 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Thu, 11 May 2023 16:42:44 +0000 Subject: [PATCH 39/89] fixed routing propagation --- src/router.rs | 38 +++++++++++++++++++++++++++++++++++--- src/routing_table.rs | 2 +- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/src/router.rs b/src/router.rs index 4b110f0..6ddbd0e 100644 --- a/src/router.rs +++ b/src/router.rs @@ -155,8 +155,10 @@ impl Router { fn handle_incoming_update(router: Router, source_table: &mut SourceTable, routing_table: &mut RoutingTable, update: ControlStruct) { if source_table.is_feasible(&update) { + println!("incoming update is feasible"); 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 } => { @@ -167,12 +169,43 @@ impl Router { // 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 { + let source_key = SourceKey { + prefix, + plen, + router_id, + }; + let feas_dist = FeasibilityDistance(metric, seqno); + + // create the source table entry + source_table.insert(source_key.clone(), feas_dist); + + // now we can create the routing table entry + let route_key = RouteKey { + prefix, // prefix is peer that ANNOUNCED the route + plen, + neighbor: update.src_overlay_ip, + }; + + let peer = router.get_peer_by_ip(update.src_overlay_ip).unwrap(); + + let route_entry = RouteEntry { + source: source_key, + metric: metric + peer.link_cost, + seqno: seqno, + neighbor: peer, + next_hop: update.src_overlay_ip, + selected: true, // set selected always to true for now as we have manually decided the topology to only have p2p links + }; + // create the routing table entry + routing_table.insert(route_key, route_entry); } }, _ => {}, } } else { + println!("incoming update is NOT feasible"); // received update is not feasible // unselect to route if it was selected } @@ -234,11 +267,10 @@ impl Router { let feas_dist = FeasibilityDistance(peer.link_cost, 0); // create the source table entry - let source_key_clone = source_key.clone(); self.source_table .lock() .unwrap() - .insert(source_key, feas_dist); + .insert(source_key.clone(), feas_dist); // now we can create the routing table entry let route_key = RouteKey { @@ -247,7 +279,7 @@ impl Router { neighbor: IpAddr::V4(peer.overlay_ip), }; let route_entry = RouteEntry { - source: source_key_clone, + source: source_key, neighbor: peer.clone(), metric: peer.link_cost, seqno: 0, // we set the seqno to 0 for now diff --git a/src/routing_table.rs b/src/routing_table.rs index c5bd96a..07ebca9 100644 --- a/src/routing_table.rs +++ b/src/routing_table.rs @@ -50,7 +50,7 @@ impl RouteEntry { self.seqno = seqno; }, _ => { - println!("Received update with invalid TLV"); + panic!("Received update with invalid TLV"); } } } From 1fa98deedcfcb3d2bb707ca1777c3059e72d7ab6 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Thu, 11 May 2023 16:45:32 +0000 Subject: [PATCH 40/89] fixed routing propagation v2 --- src/router.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/router.rs b/src/router.rs index 6ddbd0e..97632a7 100644 --- a/src/router.rs +++ b/src/router.rs @@ -191,7 +191,7 @@ impl Router { let route_entry = RouteEntry { source: source_key, - metric: metric + peer.link_cost, + metric: metric, // + peer.link_cost, --> TODO!!! seqno: seqno, neighbor: peer, next_hop: update.src_overlay_ip, From 37744e4803c469d8fdb209c4230a60690c32c632 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Thu, 11 May 2023 17:11:10 +0000 Subject: [PATCH 41/89] fixed packet hopping --- src/router.rs | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/router.rs b/src/router.rs index 97632a7..13cada3 100644 --- a/src/router.rs +++ b/src/router.rs @@ -45,7 +45,7 @@ impl Router { router_id: rand::thread_rng().gen(), peer_interfaces: Arc::new(Mutex::new(Vec::new())), router_control_tx, - router_data_tx, + router_data_tx: router_data_tx.clone(), node_tun, routing_table: Arc::new(Mutex::new(RoutingTable::new())), source_table: Arc::new(Mutex::new(SourceTable::new())), @@ -53,7 +53,7 @@ impl Router { }; tokio::spawn(Router::handle_incoming_control_packet(router.clone(), router_control_rx)); - tokio::spawn(Router::handle_incoming_data_packets(router.clone(), router_data_rx)); + tokio::spawn(Router::handle_incoming_data_packets(router.clone(), router_data_rx, router_data_tx.clone())); tokio::spawn(Router::start_periodic_hello_sender(router.clone())); // loops over all peers and adds routing table entries for each peer @@ -87,7 +87,7 @@ impl Router { } } - async fn handle_incoming_data_packets(self, mut router_data_rx: UnboundedReceiver) { + async fn handle_incoming_data_packets(self, mut router_data_rx: UnboundedReceiver, router_data_tx: UnboundedSender) { // If the destination IP of the data packet matches with the IP address of this node's TUN interface // we should forward the data packet towards the TUN interface. // If the destination IP doesn't match, we need to lookup if we have a matching peer instance @@ -105,15 +105,7 @@ impl Router { Err(e) => eprintln!("Error sending data packet to TUN interface: {:?}", e), } } else { - match self.get_peer_by_ip(IpAddr::V4(dest_ip)) { - Some(peer) => { - match peer.to_peer_data.send(data_packet) { - Ok(_) => {}, - Err(e) => eprintln!("Error sending data packet to peer: {:?}", e), - } - }, - None => eprintln!("No matching peer found for data packet"), - } + router_data_tx.send(data_packet).unwrap(); } } } From 598ec0134b1c74bf999878dd18300657c02fca2d Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Fri, 12 May 2023 07:35:02 +0000 Subject: [PATCH 42/89] best route selection through next-hop --- src/router.rs | 39 ++++++++++++++++++++++++++++++++++++++- src/routing_table.rs | 9 --------- 2 files changed, 38 insertions(+), 10 deletions(-) diff --git a/src/router.rs b/src/router.rs index 13cada3..840ccb5 100644 --- a/src/router.rs +++ b/src/router.rs @@ -98,6 +98,7 @@ impl Router { loop { while let Some(data_packet) = router_data_rx.recv().await { let dest_ip = data_packet.dest_ip; + println!("Received data packet: {:?}", data_packet); if dest_ip == tun_addr { match self.node_tun.send(&data_packet.raw_data).await { @@ -105,7 +106,13 @@ impl Router { Err(e) => eprintln!("Error sending data packet to TUN interface: {:?}", e), } } else { - router_data_tx.send(data_packet).unwrap(); + // router_data_tx.send(data_packet).unwrap(); + // DO BABEL route selection + // kijke nr next-hop en gwn sturenn naar de peer die daarmee overeenkomt + + // select the best route towards the destination + let best_route = self.select_best_route(IpAddr::V4(dest_ip)); + println!("Best route: {:?}", best_route); } } } @@ -314,6 +321,36 @@ impl Router { } } } + + pub fn select_best_route(&self, dest_ip: IpAddr) -> Option{ + // first look in the routing table for all routekeys where prefix == dest_ip + let routing_table = self.routing_table.lock().unwrap(); + let mut matching_routes: Vec<&RouteEntry> = Vec::new(); + + for route in routing_table.table.iter() { + if route.0.prefix == dest_ip { // NOTE -- this is not correct, we need to check if the dest_ip is in the prefix range + matching_routes.push(route.1); + println!("Found matching route: {:?}", route.1); + } + } + + // now we have all routes that match the destination ip + // we need to select the route with the lowest metric + let mut best_route: Option<&RouteEntry> = None; + let mut best_metric: u16 = u16::MAX; + + for route in matching_routes.iter() { + if route.metric < best_metric { + best_route = Some(route); + best_metric = route.metric; + } + } + + match best_route { + Some(route) => Some(route.clone()), + None => None, + } + } } diff --git a/src/routing_table.rs b/src/routing_table.rs index 07ebca9..5a01efa 100644 --- a/src/routing_table.rs +++ b/src/routing_table.rs @@ -91,14 +91,5 @@ impl RoutingTable { } } -// TODO: add support of suprious starvation detection -pub fn select_best_route(routes: &[RouteEntry]) -> Option<&RouteEntry> { - //routes.iter().min_by_key(|route| (route.metric, route.router_id)) - todo!("select_best_route") -} - - - - From fb9c29d8815e07c1e736cc39b7ec244aff4f14d3 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Fri, 12 May 2023 08:27:39 +0000 Subject: [PATCH 43/89] best route selection through next-hop v2 --- src/main.rs | 9 +++++++-- src/router.rs | 11 ++++++++--- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/main.rs b/src/main.rs index fde6161..a8e65e7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -108,10 +108,15 @@ async fn main() -> Result<(), Box> { Ok(_) => { // Remove trailing newline line.pop(); - println!("Current routes \n: {}", line); + println!("----------- Current routes -----------{}\n", line); router.print_routes(); - println!("Current peers: \n: {:?}", router.get_peer_interfaces()); + println!("\n----------- Current peers: -----------"); + for p in router.get_peer_interfaces() { + println!("Peer: {:?}", p.overlay_ip); + } + + println!("\n\n"); } Err(e) => { eprintln!("Error reading line: {}", e); diff --git a/src/router.rs b/src/router.rs index 840ccb5..878916b 100644 --- a/src/router.rs +++ b/src/router.rs @@ -98,7 +98,7 @@ impl Router { loop { while let Some(data_packet) = router_data_rx.recv().await { let dest_ip = data_packet.dest_ip; - println!("Received data packet: {:?}", data_packet); + println!("Received data packet with destination: {}", data_packet.dest_ip); if dest_ip == tun_addr { match self.node_tun.send(&data_packet.raw_data).await { @@ -112,7 +112,12 @@ impl Router { // select the best route towards the destination let best_route = self.select_best_route(IpAddr::V4(dest_ip)); - println!("Best route: {:?}", best_route); + + // get the peer corresponding to the best the best route + let peer = self.get_peer_by_ip(best_route.unwrap().next_hop).unwrap(); + if let Err(e) = peer.to_peer_data.send(data_packet) { + eprintln!("Error sending data packet to peer: {:?}", e); + } } } } @@ -330,7 +335,7 @@ impl Router { for route in routing_table.table.iter() { if route.0.prefix == dest_ip { // NOTE -- this is not correct, we need to check if the dest_ip is in the prefix range matching_routes.push(route.1); - println!("Found matching route: {:?}", route.1); + println!("Found matching route with next-hop: {:?}", route.1.next_hop); } } From 637415f82852dc18a468aaec9387ad250a36eaf8 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Fri, 12 May 2023 08:33:11 +0000 Subject: [PATCH 44/89] changed route to 10.0.0.0/16 --- src/node_setup.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/node_setup.rs b/src/node_setup.rs index 4ae2ef1..18aa73f 100644 --- a/src/node_setup.rs +++ b/src/node_setup.rs @@ -9,7 +9,7 @@ use futures::stream::TryStreamExt; pub const TUN_NAME: &str = "tun0"; pub const TUN_ROUTE_DEST: Ipv4Addr = Ipv4Addr::new(10, 0, 0, 0); -pub const TUN_ROUTE_PREFIX: u8 = 24; +pub const TUN_ROUTE_PREFIX: u8 = 16; // Create a TUN interface pub fn create_tun_interface(int_addr: Ipv4Addr) -> Result, Box> { From 9b8c92bef10047a5d7e57b8e716ab50259616b47 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Fri, 12 May 2023 09:00:22 +0000 Subject: [PATCH 45/89] fixed packet decoding --- src/codec.rs | 48 +++++++++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/src/codec.rs b/src/codec.rs index 7059e81..3294c22 100644 --- a/src/codec.rs +++ b/src/codec.rs @@ -180,11 +180,15 @@ impl Encoder for DataPacketCodec { } /* ****************************CONTROL PACKET******************************** */ -pub struct ControlPacketCodec {} +pub struct ControlPacketCodec { + header: Option, +} impl ControlPacketCodec { pub fn new() -> Self { - ControlPacketCodec {} + ControlPacketCodec { + header: None, + } } } @@ -194,27 +198,37 @@ impl Decoder for ControlPacketCodec { type Error = std::io::Error; fn decode(&mut self, buf: &mut BytesMut) -> Result, Self::Error> { - if buf.remaining() < 4 { - return Ok(None); - } - let magic = buf.get_u8(); - let version = buf.get_u8(); - let body_length = buf.get_u16(); + let header = if let Some(header) = self.header.take() { + header + } else { + if buf.remaining() < 4 { + return Ok(None); + } - if buf.remaining() < body_length as usize { - return Ok(None); - } + let magic = buf.get_u8(); + let version = buf.get_u8(); + let body_length = buf.get_u16(); - let header = BabelPacketHeader { - magic, - version, - body_length, + BabelPacketHeader { + magic, + version, + body_length, + } }; + + + + if buf.remaining() < header.body_length as usize { + // here the self.header is actually always None (due to take function) + // so assign it again to Some(header) + self.header = Some(header); + return Ok(None); + } let tlv_type = match BabelTLVType::from_u8(buf.get_u8()) { - Some(t) => t, - None => return Err(io::Error::new(io::ErrorKind::InvalidData, "Invalid TLV type")), + Some(t) => t, + None => return Err(io::Error::new(io::ErrorKind::InvalidData, "Invalid TLV type")), }; let length = buf.get_u8(); From 3c1a4f3b169d954db41b8ae6641611ac76005f01 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Fri, 12 May 2023 09:15:08 +0000 Subject: [PATCH 46/89] fixed packet decoding v2 --- src/codec.rs | 5 ++++- src/router.rs | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/codec.rs b/src/codec.rs index 3294c22..076cbe4 100644 --- a/src/codec.rs +++ b/src/codec.rs @@ -39,7 +39,10 @@ impl Decoder for PacketCodec { let packet_type = match packet_type_byte { 0 => PacketType::DataPacket, 1 => PacketType::ControlPacket, - _ => return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "Invalid packet type")), + _ => { + println!("buffer: {:?}", &src[..src.remaining()]); + return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "Invalid packet type")), + } }; packet_type diff --git a/src/router.rs b/src/router.rs index 878916b..62c6e92 100644 --- a/src/router.rs +++ b/src/router.rs @@ -321,7 +321,9 @@ impl Router { entry.source.router_id, ); - peer.to_peer_control.send(update).unwrap(); + if peer.to_peer_control.send(update).is_err() { + println!("route update packet dropped"); + } } } } From 76bea11497cb3b2c4230e445f705f11547b16837 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Fri, 12 May 2023 09:16:16 +0000 Subject: [PATCH 47/89] fixed packet decoding v3 --- src/codec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/codec.rs b/src/codec.rs index 076cbe4..c158baf 100644 --- a/src/codec.rs +++ b/src/codec.rs @@ -41,7 +41,7 @@ impl Decoder for PacketCodec { 1 => PacketType::ControlPacket, _ => { println!("buffer: {:?}", &src[..src.remaining()]); - return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "Invalid packet type")), + return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "Invalid packet type")); } }; From e083202ee8f19931824252c5138274bcf932f042 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Fri, 12 May 2023 09:30:28 +0000 Subject: [PATCH 48/89] ae encoding fixed --- src/packet.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/packet.rs b/src/packet.rs index 82af95c..212d9d8 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -179,7 +179,7 @@ impl BabelTLVType { Self::Hello => (4, 4), Self::IHU => (18, 6), Self::NextHop => (16, 4), - Self::Update => (28, 16), + Self::Update => (28+1, 16+1), // +1 for ae Self::RouteReq => (17, 5), Self::SeqnoReq => (21, 9), }; From 318fd1a9fe52de72681e2565091f4fa6917002b2 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Fri, 12 May 2023 09:37:33 +0000 Subject: [PATCH 49/89] ae encoding fixed v2 --- src/packet.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/packet.rs b/src/packet.rs index 212d9d8..3139256 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -179,7 +179,7 @@ impl BabelTLVType { Self::Hello => (4, 4), Self::IHU => (18, 6), Self::NextHop => (16, 4), - Self::Update => (28+1, 16+1), // +1 for ae + Self::Update => (31+1, 19+1), // +1 for ae Self::RouteReq => (17, 5), Self::SeqnoReq => (21, 9), }; From 2334415c5f436a0a383094f799f29cb9272a8f18 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Fri, 12 May 2023 09:45:15 +0000 Subject: [PATCH 50/89] ae encoding fixed v3 --- src/codec.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/codec.rs b/src/codec.rs index c158baf..5951dc4 100644 --- a/src/codec.rs +++ b/src/codec.rs @@ -48,6 +48,8 @@ impl Decoder for PacketCodec { packet_type }; + self.packet_type = Some(packet_type); + // Decode packet based on determined packet_type match packet_type { PacketType::DataPacket => { From 077d2152670796005b6c2cb2e0cf02b8eb661b1f Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Fri, 12 May 2023 11:41:22 +0000 Subject: [PATCH 51/89] metric analysis --- src/codec.rs | 3 ++- src/main.rs | 2 +- src/router.rs | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/codec.rs b/src/codec.rs index 5951dc4..e59d687 100644 --- a/src/codec.rs +++ b/src/codec.rs @@ -44,11 +44,12 @@ impl Decoder for PacketCodec { return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "Invalid packet type")); } }; + + self.packet_type = Some(packet_type); packet_type }; - self.packet_type = Some(packet_type); // Decode packet based on determined packet_type match packet_type { diff --git a/src/main.rs b/src/main.rs index a8e65e7..3d16115 100644 --- a/src/main.rs +++ b/src/main.rs @@ -113,7 +113,7 @@ async fn main() -> Result<(), Box> { println!("\n----------- Current peers: -----------"); for p in router.get_peer_interfaces() { - println!("Peer: {:?}", p.overlay_ip); + println!("Peer: {:?}, with link cost: {}", p.overlay_ip, p.link_cost); } println!("\n\n"); diff --git a/src/router.rs b/src/router.rs index 62c6e92..ab8b85e 100644 --- a/src/router.rs +++ b/src/router.rs @@ -246,7 +246,7 @@ impl Router { pub fn print_routes(&self) { let routing_table = self.routing_table.lock().unwrap(); for route in routing_table.table.iter() { - println!("Route: {:?}/{:?} (with next-hop: {:?})", route.0.prefix, route.0.plen, route.1.next_hop); + println!("Route: {:?}/{:?} (with next-hop: {:?}, metric: {})", route.0.prefix, route.0.plen, route.1.next_hop, route.1.metric); println!("As advertised by: {:?}", route.1.source.router_id); } } From fc9a1647b121855a73e10ced46d8ecabec574ca9 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Fri, 12 May 2023 14:55:00 +0000 Subject: [PATCH 52/89] leefactor --- src/codec.rs | 177 ++++++++++++++++++++++----------------- src/main.rs | 47 ++++++----- src/node_setup.rs | 13 +-- src/packet.rs | 115 +++++++++++++++----------- src/peer.rs | 148 ++++++++++++++++++++++++++------- src/peer_manager.rs | 102 +++++++++++++++++++---- src/router.rs | 191 ++++++++++++++++++++++++++----------------- src/routing_table.rs | 39 ++++++--- src/source_table.rs | 47 +++++++---- src/timers.rs | 30 +++---- 10 files changed, 593 insertions(+), 316 deletions(-) diff --git a/src/codec.rs b/src/codec.rs index e59d687..5f8e68f 100644 --- a/src/codec.rs +++ b/src/codec.rs @@ -1,7 +1,13 @@ -use std::{io, net::{IpAddr, Ipv4Addr, Ipv6Addr}}; -use bytes::{BufMut, BytesMut, Buf}; -use tokio_util::codec::{Encoder, Decoder}; -use crate::packet::{Packet, ControlPacket, DataPacket, PacketType, BabelTLVType, BabelPacketBody, BabelTLV, BabelPacketHeader}; +use crate::packet::{ + BabelPacketBody, BabelPacketHeader, BabelTLV, BabelTLVType, ControlPacket, DataPacket, Packet, + PacketType, +}; +use bytes::{Buf, BufMut, BytesMut}; +use std::{ + io, + net::{IpAddr, Ipv4Addr, Ipv6Addr}, +}; +use tokio_util::codec::{Decoder, Encoder}; /* ********************************PAKCET*********************************** */ pub struct PacketCodec { @@ -25,7 +31,6 @@ impl Decoder for PacketCodec { type Error = std::io::Error; fn decode(&mut self, src: &mut BytesMut) -> Result, Self::Error> { - // Determine the packet_type let packet_type = if let Some(packet_type) = self.packet_type { packet_type @@ -41,16 +46,18 @@ impl Decoder for PacketCodec { 1 => PacketType::ControlPacket, _ => { println!("buffer: {:?}", &src[..src.remaining()]); - return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "Invalid packet type")); + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "Invalid packet type", + )); } }; - + self.packet_type = Some(packet_type); packet_type }; - // Decode packet based on determined packet_type match packet_type { PacketType::DataPacket => { @@ -58,7 +65,7 @@ impl Decoder for PacketCodec { Ok(Some(p)) => { self.packet_type = None; // Reset state Ok(Some(Packet::DataPacket(p))) - }, + } Ok(None) => Ok(None), Err(e) => Err(e), } @@ -68,7 +75,7 @@ impl Decoder for PacketCodec { Ok(Some(p)) => { self.packet_type = None; // Reset state Ok(Some(Packet::ControlPacket(p))) - }, + } Ok(None) => Ok(None), Err(e) => Err(e), } @@ -114,7 +121,6 @@ impl Decoder for DataPacketCodec { type Error = std::io::Error; fn decode(&mut self, src: &mut BytesMut) -> Result, Self::Error> { - // Determine the length of the data let data_len = if let Some(data_len) = self.len { data_len @@ -192,9 +198,7 @@ pub struct ControlPacketCodec { impl ControlPacketCodec { pub fn new() -> Self { - ControlPacketCodec { - header: None, - } + ControlPacketCodec { header: None } } } @@ -204,7 +208,6 @@ impl Decoder for ControlPacketCodec { type Error = std::io::Error; fn decode(&mut self, buf: &mut BytesMut) -> Result, Self::Error> { - let header = if let Some(header) = self.header.take() { header } else { @@ -222,8 +225,6 @@ impl Decoder for ControlPacketCodec { body_length, } }; - - if buf.remaining() < header.body_length as usize { // here the self.header is actually always None (due to take function) @@ -233,8 +234,13 @@ impl Decoder for ControlPacketCodec { } let tlv_type = match BabelTLVType::from_u8(buf.get_u8()) { - Some(t) => t, - None => return Err(io::Error::new(io::ErrorKind::InvalidData, "Invalid TLV type")), + Some(t) => t, + None => { + return Err(io::Error::new( + io::ErrorKind::InvalidData, + "Invalid TLV type", + )) + } }; let length = buf.get_u8(); @@ -252,7 +258,12 @@ impl Decoder for ControlPacketCodec { } BabelTLVType::IHU => { let interval = buf.get_u16(); - let address = IpAddr::V4(Ipv4Addr::new(buf.get_u8(), buf.get_u8(), buf.get_u8(), buf.get_u8())); + let address = IpAddr::V4(Ipv4Addr::new( + buf.get_u8(), + buf.get_u8(), + buf.get_u8(), + buf.get_u8(), + )); let body = BabelPacketBody { tlv_type, length, @@ -268,15 +279,17 @@ impl Decoder for ControlPacketCodec { let metric = buf.get_u16(); // based on the remaining bytes (ip + router_id) we can check if it's IPv4 or v6 let prefix = match ae { - 0 => { // 4 bytes IP + 8 bytes router_id + 0 => { + // 4 bytes IP + 8 bytes router_id IpAddr::V4(Ipv4Addr::new( buf.get_u8(), buf.get_u8(), buf.get_u8(), buf.get_u8(), )) - }, - 1 => { // 16 bytes IP + 8 bytes router_id + } + 1 => { + // 16 bytes IP + 8 bytes router_id IpAddr::V6(Ipv6Addr::new( buf.get_u16(), buf.get_u16(), @@ -287,14 +300,26 @@ impl Decoder for ControlPacketCodec { buf.get_u16(), buf.get_u16(), )) - }, - _ => return Err(io::Error::new(io::ErrorKind::InvalidData, "Invalid address length")), + } + _ => { + return Err(io::Error::new( + io::ErrorKind::InvalidData, + "Invalid address length", + )) + } }; let router_id = buf.get_u64(); let body = BabelPacketBody { tlv_type, length, - tlv: BabelTLV::Update { plen, interval, seqno, metric, prefix, router_id } + tlv: BabelTLV::Update { + plen, + interval, + seqno, + metric, + prefix, + router_id, + }, }; body } @@ -318,58 +343,64 @@ impl Encoder for ControlPacketCodec { buf.put_u8(message.header.version); buf.put_u16(message.header.body_length); - // Write BabelPacketBody - buf.put_u8(message.body.tlv_type as u8); - buf.put_u8(message.body.length); + // Write BabelPacketBody + buf.put_u8(message.body.tlv_type as u8); + buf.put_u8(message.body.length); - match message.body.tlv{ - BabelTLV::Hello { seqno, interval } => { - buf.put_u16(seqno); - buf.put_u16(interval); - } - BabelTLV::IHU { interval, address } => { - buf.put_u16(interval); - match address { - IpAddr::V4(ipv4) => { - buf.put_u8(ipv4.octets()[0]); - buf.put_u8(ipv4.octets()[1]); - buf.put_u8(ipv4.octets()[2]); - buf.put_u8(ipv4.octets()[3]); - } - IpAddr::V6(_ipv6) => { - println!("IPv6 not supported yet"); - } + match message.body.tlv { + BabelTLV::Hello { seqno, interval } => { + buf.put_u16(seqno); + buf.put_u16(interval); + } + BabelTLV::IHU { interval, address } => { + buf.put_u16(interval); + match address { + IpAddr::V4(ipv4) => { + buf.put_u8(ipv4.octets()[0]); + buf.put_u8(ipv4.octets()[1]); + buf.put_u8(ipv4.octets()[2]); + buf.put_u8(ipv4.octets()[3]); + } + IpAddr::V6(_ipv6) => { + println!("IPv6 not supported yet"); } } - BabelTLV::Update { plen , interval, seqno, metric, prefix , router_id} => { - buf.put_u8(if prefix.is_ipv4(){0} else {1}); - buf.put_u8(plen); - buf.put_u16(interval); - buf.put_u16(seqno); - buf.put_u16(metric); - match prefix { - IpAddr::V4(ipv4) => { - buf.put_u8(ipv4.octets()[0]); - buf.put_u8(ipv4.octets()[1]); - buf.put_u8(ipv4.octets()[2]); - buf.put_u8(ipv4.octets()[3]); - } - IpAddr::V6(_ipv6) => { - buf.put_u16(_ipv6.segments()[0]); - buf.put_u16(_ipv6.segments()[1]); - buf.put_u16(_ipv6.segments()[2]); - buf.put_u16(_ipv6.segments()[3]); - buf.put_u16(_ipv6.segments()[4]); - buf.put_u16(_ipv6.segments()[5]); - buf.put_u16(_ipv6.segments()[6]); - buf.put_u16(_ipv6.segments()[7]); - } + } + BabelTLV::Update { + plen, + interval, + seqno, + metric, + prefix, + router_id, + } => { + buf.put_u8(if prefix.is_ipv4() { 0 } else { 1 }); + buf.put_u8(plen); + buf.put_u16(interval); + buf.put_u16(seqno); + buf.put_u16(metric); + match prefix { + IpAddr::V4(ipv4) => { + buf.put_u8(ipv4.octets()[0]); + buf.put_u8(ipv4.octets()[1]); + buf.put_u8(ipv4.octets()[2]); + buf.put_u8(ipv4.octets()[3]); + } + IpAddr::V6(_ipv6) => { + buf.put_u16(_ipv6.segments()[0]); + buf.put_u16(_ipv6.segments()[1]); + buf.put_u16(_ipv6.segments()[2]); + buf.put_u16(_ipv6.segments()[3]); + buf.put_u16(_ipv6.segments()[4]); + buf.put_u16(_ipv6.segments()[5]); + buf.put_u16(_ipv6.segments()[6]); + buf.put_u16(_ipv6.segments()[7]); } - buf.put_u64(router_id); } - // Add encoding logic for other TLV types. - _ => {} - + buf.put_u64(router_id); + } + // Add encoding logic for other TLV types. + _ => {} } Ok(()) diff --git a/src/main.rs b/src/main.rs index 3d16115..69c4d43 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,9 +4,13 @@ use etherparse::{IpHeader, PacketHeaders}; use packet::DataPacket; use router::Router; use routing_table::{RouteEntry, RouteKey}; -use source_table::{SourceKey, FeasibilityDistance}; +use source_table::{FeasibilityDistance, SourceKey}; +use std::{ + error::Error, + net::{IpAddr, Ipv4Addr, SocketAddr}, + sync::Arc, +}; use tokio::io::AsyncBufReadExt; -use std::{error::Error, net::{Ipv4Addr, SocketAddr, IpAddr}, sync::Arc}; use crate::peer::Peer; @@ -20,7 +24,7 @@ mod routing_table; mod source_table; mod timers; -const LINK_MTU: usize = 1500; +const LINK_MTU: usize = 1420; #[derive(Parser)] struct Cli { @@ -44,31 +48,35 @@ async fn main() -> Result<(), Box> { panic!("Error setting up node: {}", e); } }; - + let static_peers = cli.static_peers; - - // Creating a new Router instance + + // Creating a new Router instance let router = Arc::new(router::Router::new(node_tun.clone())); // Creating a new PeerManager instance - let _peer_manager: peer_manager::PeerManager = peer_manager::PeerManager::new(router.clone(), static_peers); + let _peer_manager: peer_manager::PeerManager = + peer_manager::PeerManager::new(router.clone(), static_peers); // 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 { let node_tun = node_tun.clone(); let router = router.clone(); - + tokio::spawn(async move { loop { let mut buf = BytesMut::zeroed(LINK_MTU); - if let Err(e) = node_tun.recv(&mut buf).await { - eprintln!("Error reading from TUN: {}", e); - continue; + + match node_tun.recv(&mut buf).await { + Ok(n) => { + buf.truncate(n); + } + Err(e) => { + eprintln!("Error reading from TUN: {}", e); + continue; + } } - - let n = buf.len(); - buf.truncate(n); - + let packet = match PacketHeaders::from_ip_slice(&buf) { Ok(packet) => packet, Err(e) => { @@ -77,11 +85,11 @@ async fn main() -> Result<(), Box> { continue; } }; - + if let Some(IpHeader::Version4(header, _)) = packet.ip { let dest_addr = Ipv4Addr::from(header.destination); println!("Destination IPv4 address: {}", dest_addr); - + let data_packet = DataPacket { dest_ip: dest_addr, raw_data: buf.to_vec(), @@ -95,7 +103,7 @@ async fn main() -> Result<(), Box> { } }); } - + let mut reader = tokio::io::BufReader::new(tokio::io::stdin()); let mut line = String::new(); let router = router.clone(); @@ -113,7 +121,7 @@ async fn main() -> Result<(), Box> { println!("\n----------- Current peers: -----------"); for p in router.get_peer_interfaces() { - println!("Peer: {:?}, with link cost: {}", p.overlay_ip, p.link_cost); + println!("Peer: {:?}, with link cost: {}", p.overlay_ip(), p.link_cost()); } println!("\n\n"); @@ -138,4 +146,3 @@ async fn main() -> Result<(), Box> { Ok(()) } - diff --git a/src/node_setup.rs b/src/node_setup.rs index 18aa73f..f308b86 100644 --- a/src/node_setup.rs +++ b/src/node_setup.rs @@ -1,11 +1,7 @@ -use tokio_tun::{Tun, TunBuilder}; -use std::{ - sync::Arc, - net::Ipv4Addr, - error::Error, -}; -use rtnetlink::Handle; use futures::stream::TryStreamExt; +use rtnetlink::Handle; +use std::{error::Error, net::Ipv4Addr, sync::Arc}; +use tokio_tun::{Tun, TunBuilder}; pub const TUN_NAME: &str = "tun0"; pub const TUN_ROUTE_DEST: Ipv4Addr = Ipv4Addr::new(10, 0, 0, 0); @@ -63,7 +59,6 @@ pub async fn setup_node(tun_addr: Ipv4Addr) -> Result, Box> add_route(handle.clone()).await?; println!("Static route created"); - + Ok(tun) } - diff --git a/src/packet.rs b/src/packet.rs index 3139256..d04b6d4 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -55,8 +55,8 @@ pub struct BabelPacketHeader { #[derive(Debug, PartialEq, Clone)] pub struct BabelPacketBody { pub tlv_type: BabelTLVType, - pub length: u8, // length of the tlv (only the tlv, not tlv_type and length itself) - pub tlv: BabelTLV, + pub length: u8, // length of the tlv (only the tlv, not tlv_type and length itself) + pub tlv: BabelTLV, } impl ControlStruct { @@ -77,23 +77,21 @@ impl BabelPacketHeader { } } - impl ControlPacket { - pub fn new_hello(dest_peer: &mut Peer, interval: u16) -> Self { let header_length = (BabelTLVType::Hello.get_tlv_length(false) + 2) as u16; - dest_peer.increase_hello_seqno(); + dest_peer.increment_hello_seqno(); Self { - header: BabelPacketHeader::new(header_length), - body: BabelPacketBody { - tlv_type: BabelTLVType::Hello, - length: BabelTLVType::Hello.get_tlv_length(false), - tlv: BabelTLV::Hello { - seqno: dest_peer.hello_seqno, - interval, - } + header: BabelPacketHeader::new(header_length), + body: BabelPacketBody { + tlv_type: BabelTLVType::Hello, + length: BabelTLVType::Hello.get_tlv_length(false), + tlv: BabelTLV::Hello { + seqno: dest_peer.hello_seqno(), + interval, + }, }, - } + } } pub fn new_ihu(interval: u16, dest_address: IpAddr) -> Self { @@ -103,37 +101,44 @@ impl ControlPacket { }; let header_length = (BabelTLVType::IHU.get_tlv_length(uses_ipv6) + 2) as u16; Self { - header: BabelPacketHeader::new(header_length), - body: BabelPacketBody { - tlv_type: BabelTLVType::IHU, - length: BabelTLVType::IHU.get_tlv_length(uses_ipv6), - tlv: BabelTLV::IHU { - interval, - address: dest_address, - } + header: BabelPacketHeader::new(header_length), + body: BabelPacketBody { + tlv_type: BabelTLVType::IHU, + length: BabelTLVType::IHU.get_tlv_length(uses_ipv6), + tlv: BabelTLV::IHU { + interval, + address: dest_address, + }, }, } } - pub fn new_update(plen: u8, interval: u16, seqno: u16, metric: u16, prefix: IpAddr, router_id: u64) -> Self { + pub fn new_update( + plen: u8, + interval: u16, + seqno: u16, + metric: u16, + prefix: IpAddr, + router_id: u64, + ) -> Self { let uses_ipv6 = match prefix { IpAddr::V4(_) => false, IpAddr::V6(_) => true, }; let header_length = (BabelTLVType::Update.get_tlv_length(uses_ipv6) + 2) as u16; Self { - header: BabelPacketHeader::new(header_length), - body: BabelPacketBody { - tlv_type: BabelTLVType::Update, - length: BabelTLVType::Update.get_tlv_length(uses_ipv6), - tlv: BabelTLV::Update { - plen, - interval, - seqno, - metric, - prefix, - router_id, - } + header: BabelPacketHeader::new(header_length), + body: BabelPacketBody { + tlv_type: BabelTLVType::Update, + length: BabelTLVType::Update.get_tlv_length(uses_ipv6), + tlv: BabelTLV::Update { + plen, + interval, + seqno, + metric, + prefix, + router_id, + }, }, } } @@ -179,38 +184,45 @@ impl BabelTLVType { Self::Hello => (4, 4), Self::IHU => (18, 6), Self::NextHop => (16, 4), - Self::Update => (31+1, 19+1), // +1 for ae + Self::Update => (31 + 1, 19 + 1), // +1 for ae Self::RouteReq => (17, 5), Self::SeqnoReq => (21, 9), }; - if uses_ipv6 { ipv6 } else { ipv4 } + if uses_ipv6 { + ipv6 + } else { + ipv4 + } } } - #[derive(Debug, Clone, PartialEq)] pub enum BabelTLV { // These TLVs are not implemented as they are used for padding when sending multiple TLVs in one packet. // Pad1, // PadN(u8), - AckReq { - nonce: u16, - interval: u16 - }, - Ack { nonce: u16 }, - Hello { - seqno: u16, + AckReq { + nonce: u16, interval: u16, }, - IHU { + Ack { + nonce: u16, + }, + Hello { + seqno: u16, interval: u16, - address: IpAddr, + }, + IHU { + interval: u16, + address: IpAddr, }, // RouterID TLVs are sent just before Update TLVs and server the purpose of identifying the router that sent the Update TLV. // This is used when multiple Update TLVs are sent where a prefix is included in the first Update TLV and omitted in the subsequent Update TLVs. // As we do not support ommitted prefixes, we do not need to implement this TLV. We pass the router_id as a parameter to the Update TLV instead. // RouterID { router_id: u16 }, - NextHop { address: IpAddr }, + NextHop { + address: IpAddr, + }, Update { plen: u8, interval: u16, @@ -219,11 +231,14 @@ pub enum BabelTLV { prefix: IpAddr, router_id: u64, }, - RouteReq { prefix: IpAddr, plen: u8 }, + RouteReq { + prefix: IpAddr, + plen: u8, + }, SeqnoReq { prefix: IpAddr, plen: u8, seqno: u16, router_id: u16, }, -} \ No newline at end of file +} diff --git a/src/peer.rs b/src/peer.rs index 132beae..493ad32 100644 --- a/src/peer.rs +++ b/src/peer.rs @@ -2,26 +2,22 @@ use futures::{SinkExt, StreamExt}; use std::{ error::Error, net::{IpAddr, Ipv4Addr}, + sync::{Arc, RwLock}, }; use tokio::{net::TcpStream, select, sync::mpsc}; use tokio_util::codec::Framed; -use crate::{packet::{ControlPacket, DataPacket, ControlStruct}, timers::Timer}; use crate::{codec::PacketCodec, packet::Packet}; +use crate::{ + packet::{ControlPacket, ControlStruct, DataPacket}, + timers::Timer, +}; const IHU_INTERVAL: u64 = 10; #[derive(Debug, Clone)] pub struct Peer { - pub stream_ip: IpAddr, - pub to_peer_data: mpsc::UnboundedSender, - pub to_peer_control: mpsc::UnboundedSender, - pub overlay_ip: Ipv4Addr, - pub hello_seqno: u16, - pub time_last_received_hello: tokio::time::Instant, - pub link_cost: u16, - - pub ihu_timer: Timer, + inner: Arc>, } impl Peer { @@ -30,24 +26,116 @@ impl Peer { router_data_tx: mpsc::UnboundedSender, router_control_tx: mpsc::UnboundedSender, stream: TcpStream, - overlay_ip: Ipv4Addr, - + overlay_ip: IpAddr, ) -> Result> { + Ok(Peer { + inner: Arc::new(RwLock::new(PeerInner::new( + stream_ip, + router_data_tx, + router_control_tx, + stream, + overlay_ip, + )?)), + }) + } + /// Get current sequence number for this peer. + pub fn hello_seqno(&self) -> u16 { + self.inner.read().unwrap().hello_seqno + } + + /// Adds 1 to the sequence number of this peer . + pub fn increment_hello_seqno(&self) { + // TODO: Validate this works + self.inner.write().unwrap().hello_seqno += 1 + } + + pub fn time_last_received_hello(&self) -> tokio::time::Instant { + // TODO: Validate this works + self.inner.read().unwrap().time_last_received_hello + } + + pub fn set_time_last_received_hello(&self, time: tokio::time::Instant) { + self.inner.write().unwrap().time_last_received_hello = time + } + + /// Get stream IP (linked to underlay IP) for this peer + pub fn stream_ip(&self) -> IpAddr { + self.inner.read().unwrap().stream_ip + } + + /// Get overlay IP for this peer + pub fn overlay_ip(&self) -> IpAddr { + self.inner.read().unwrap().overlay_ip + } + + /// For sending data packets towards a peer instance on this node. + /// It's send over the to_peer_data channel and read from the corresponding receiver. + /// The receiver sends the packet over the TCP stream towards the destined peer instance on another node + pub fn send_data_packet(&self, data_packet: DataPacket) -> Result<(), Box> { + Ok(self.inner.write().unwrap().to_peer_data.send(data_packet)?) + } + + /// For sending control packets towards a peer instance on this node. + /// It's send over the to_peer_control channel and read from the corresponding receiver. + /// The receiver sends the packet over the TCP stream towards the destined peer instance on another node + pub fn send_control_packet(&self, control_packet: ControlPacket) -> Result<(), Box> { + Ok(self + .inner + .write() + .unwrap() + .to_peer_control + .send(control_packet)?) + } + + pub fn link_cost(&self) -> u16 { + self.inner.read().unwrap().link_cost + } + + pub fn set_link_cost(&self, link_cost: u16) { + self.inner.write().unwrap().link_cost = link_cost + } + + pub fn reset_ihu_timer(&self, duration: tokio::time::Duration) { + self.inner.write().unwrap().ihu_timer.reset(duration) + } +} + +#[derive(Debug)] +struct PeerInner { + stream_ip: IpAddr, + to_peer_data: mpsc::UnboundedSender, + to_peer_control: mpsc::UnboundedSender, + overlay_ip: IpAddr, + hello_seqno: u16, + time_last_received_hello: tokio::time::Instant, + link_cost: u16, + ihu_timer: Timer, +} + +impl PeerInner { + pub fn new( + stream_ip: IpAddr, + router_data_tx: mpsc::UnboundedSender, + router_control_tx: mpsc::UnboundedSender, + stream: TcpStream, + overlay_ip: IpAddr, + ) -> Result> { // Framed for peer // Used to send and receive packets from a TCP stream let mut framed = Framed::new(stream, PacketCodec::new()); - // Data channel for peer + // Data channel for peer let (to_peer_data, mut from_routing_data) = mpsc::unbounded_channel::(); // Control channel for peer - let (to_peer_control, mut from_routing_control) = mpsc::unbounded_channel::(); + let (to_peer_control, mut from_routing_control) = + mpsc::unbounded_channel::(); // Control reply channel for peer let (control_reply_tx, mut control_reply_rx) = mpsc::unbounded_channel::(); // Initialize last_sent_hello_seqno to 0 let hello_seqno = 0; // Initialize last_path_cost to infinity - 1 - let link_cost = u16::MAX -1; + let link_cost = u16::MAX - 1; // Initialize time_last_received_hello to now let time_last_received_hello = tokio::time::Instant::now(); @@ -57,7 +145,7 @@ impl Peer { tokio::spawn(async move { loop { select! { - + // Received over the TCP stream frame = framed.next() => { match frame { @@ -69,11 +157,11 @@ impl Peer { } } Packet::ControlPacket(packet) => { - // Parse the DataPacket into a ControlStruct as the to_routing_control channel expects + // Parse the DataPacket into a ControlStruct as the to_routing_control channel expects let control_struct = ControlStruct { control_packet: packet, control_reply_tx: control_reply_tx.clone(), - src_overlay_ip: IpAddr::V4(overlay_ip), + src_overlay_ip: overlay_ip, // Note: although this control packet is received from the TCP stream // we set the src_overlay_ip to the overlay_ip of the peer // as we 'arrived' in the peer instance of representing the sending node on this current node @@ -113,7 +201,7 @@ impl Peer { if let Err(e) = framed.send(Packet::ControlPacket(packet)).await { eprintln!("Error writing to stream: {}", e); } - } + } } } }); @@ -129,16 +217,18 @@ impl Peer { }) } - pub fn new_dummy(overlay_ip: Ipv4Addr) -> Peer { + pub fn new_dummy(overlay_ip: IpAddr) -> Peer { Peer { - stream_ip: IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), - to_peer_data: mpsc::unbounded_channel::().0, - to_peer_control: mpsc::unbounded_channel::().0, - overlay_ip, - hello_seqno: 0, - link_cost: 100, - ihu_timer: Timer::new_ihu_timer(u64::MAX), - time_last_received_hello: tokio::time::Instant::now(), + inner: Arc::new(RwLock::new(PeerInner { + stream_ip: IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), + to_peer_data: mpsc::unbounded_channel::().0, + to_peer_control: mpsc::unbounded_channel::().0, + overlay_ip, + hello_seqno: 0, + link_cost: 100, + ihu_timer: Timer::new_ihu_timer(u64::MAX), + time_last_received_hello: tokio::time::Instant::now(), + })), } } @@ -146,4 +236,4 @@ impl Peer { self.hello_seqno = self.hello_seqno + 1; println!("last hello seqno increasted to {}", self.hello_seqno); } -} \ No newline at end of file +} diff --git a/src/peer_manager.rs b/src/peer_manager.rs index 847ca7c..568b38f 100644 --- a/src/peer_manager.rs +++ b/src/peer_manager.rs @@ -2,7 +2,7 @@ use crate::peer::Peer; use crate::router::Router; use serde::Deserialize; use tokio::net::TcpListener; -use std::net::{Ipv4Addr, SocketAddr}; +use std::net::{Ipv4Addr, SocketAddr, IpAddr, Ipv6Addr}; use std::sync::{Arc}; use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tokio::{net::TcpStream}; @@ -41,17 +41,38 @@ impl PeerManager { for peer_addr in config.peers { if let Ok(mut peer_stream) = TcpStream::connect(peer_addr).await { - let mut buffer = [0u8; 4]; + let mut buffer = [0u8; 17]; peer_stream.read_exact(&mut buffer).await.unwrap(); - let received_overlay_ip = Ipv4Addr::from(buffer); + let received_overlay_ip = match buffer[0] { + 0 => { + IpAddr::from(<&[u8] as TryInto<[u8;4]>>::try_into(&buffer[1..5]).unwrap()) + }, + 1 => { + IpAddr::from(<&[u8] as TryInto<[u8;16]>>::try_into(&buffer[1..]).unwrap()) + } + _ => { + eprintln!("Invalid address encoding byte"); + continue + } + }; println!( "Received overlay IP from other node: {:?}", received_overlay_ip ); - let ip_bytes = self.router.get_node_tun_address().octets(); - peer_stream.write_all(&ip_bytes).await.unwrap(); + let mut buf = [0u8; 17]; + match self.router.get_node_tun_address() { + IpAddr::V4(tun_addr) => { + buf[0] = 0; + buf[1..5].copy_from_slice(&tun_addr.octets()[..]); + }, + IpAddr::V6(tun_addr) => { + buf[0] = 1; + buf[1..].copy_from_slice(&tun_addr.octets()[..]); + } + } + peer_stream.write_all(&buf).await.unwrap(); let peer_stream_ip = peer_addr.ip(); if let Ok(new_peer) = Peer::new( @@ -77,17 +98,39 @@ impl PeerManager { if let Ok(mut peer_stream) = TcpStream::connect(peer_addr).await { println!("stream established"); - let mut buffer = [0u8; 4]; + let mut buffer = [0u8; 17]; peer_stream.read_exact(&mut buffer).await.unwrap(); - let received_overlay_ip = Ipv4Addr::from(buffer); - + let received_overlay_ip = match buffer[0] { + 0 => { + IpAddr::from(<&[u8] as TryInto<[u8;4]>>::try_into(&buffer[1..5]).unwrap()) + }, + 1 => { + IpAddr::from(<&[u8] as TryInto<[u8;16]>>::try_into(&buffer[1..]).unwrap()) + } + _ => { + eprintln!("Invalid address encoding byte"); + continue + } + }; println!( "3: Received overlay IP from other node: {:?}", received_overlay_ip ); - let ip_bytes = self.router.get_node_tun_address().octets(); - peer_stream.write_all(&ip_bytes).await.unwrap(); + let mut buf = [0u8; 17]; + + match self.router.get_node_tun_address() { + IpAddr::V4(tun_addr) => { + buf[0] = 0; + buf[1..5].copy_from_slice(&tun_addr.octets()[..]); + }, + IpAddr::V6(tun_addr) => { + buf[0] = 1; + buf[1..].copy_from_slice(&tun_addr.octets()[..]); + } + } + + peer_stream.write_all(&buf).await.unwrap(); let peer_stream_ip = peer_addr.ip(); if let Ok(new_peer) = Peer::new( @@ -126,14 +169,41 @@ impl PeerManager { async fn start_reverse_peer_exchange(mut stream: TcpStream, router: Arc) { + // Steps: // 1. Send own TUN address over the stream - let ip_bytes = router.get_node_tun_address().octets(); - stream.write_all(&ip_bytes).await.unwrap(); - // 2. Read other node's TUN address from the stream - let mut buffer = [0u8; 4]; - stream.read_exact(&mut buffer).await.unwrap(); - let received_overlay_ip = Ipv4Addr::from(buffer); + + + let mut buf = [0u8; 17]; + + match router.get_node_tun_address() { + IpAddr::V4(tun_addr) => { + buf[0] = 0; + buf[1..5].copy_from_slice(&tun_addr.octets()[..]); + }, + IpAddr::V6(tun_addr) => { + buf[0] = 1; + buf[1..].copy_from_slice(&tun_addr.octets()[..]); + } + } + + stream.write_all(&buf).await.unwrap(); + + + + stream.read_exact(&mut buf).await.unwrap(); + let received_overlay_ip = match buf[0] { + 0 => { + IpAddr::from(<&[u8] as TryInto<[u8;4]>>::try_into(&buf[1..5]).unwrap()) + }, + 1 => { + IpAddr::from(<&[u8] as TryInto<[u8;16]>>::try_into(&buf[1..]).unwrap()) + } + _ => { + eprintln!("Invalid address encoding byte"); + return; + } + }; println!("Received overlay IP from other node: {:?}", received_overlay_ip); // Create new Peer instance diff --git a/src/router.rs b/src/router.rs index ab8b85e..9834786 100644 --- a/src/router.rs +++ b/src/router.rs @@ -4,15 +4,16 @@ use crate::{ DataPacket, }, peer::Peer, - routing_table::{RouteEntry, RouteKey, RoutingTable, self}, - source_table::{SourceKey, SourceTable, FeasibilityDistance, self}, timers::{Timer, self}, + routing_table::{self, RouteEntry, RouteKey, RoutingTable}, + source_table::{self, FeasibilityDistance, SourceKey, SourceTable}, + timers::{self, Timer}, }; +use rand::Rng; use std::{ collections::HashMap, net::{IpAddr, Ipv4Addr}, sync::{Arc, Mutex}, }; -use rand::Rng; use tokio::sync::mpsc::{self, UnboundedReceiver, UnboundedSender}; use tokio_tun::Tun; @@ -35,7 +36,6 @@ pub struct Router { impl Router { pub fn new(node_tun: Arc) -> Self { - // Tx is passed onto each new peer instance. This enables peers to send control packets to the router. let (router_control_tx, router_control_rx) = mpsc::unbounded_channel::(); // Tx is passed onto each new peer instance. This enables peers to send data packets to the router. @@ -52,21 +52,30 @@ impl Router { router_seqno: 0, }; - tokio::spawn(Router::handle_incoming_control_packet(router.clone(), router_control_rx)); - tokio::spawn(Router::handle_incoming_data_packets(router.clone(), router_data_rx, router_data_tx.clone())); + tokio::spawn(Router::handle_incoming_control_packet( + router.clone(), + router_control_rx, + )); + tokio::spawn(Router::handle_incoming_data_packets( + router.clone(), + router_data_rx, + router_data_tx.clone(), + )); tokio::spawn(Router::start_periodic_hello_sender(router.clone())); // 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 } - async fn handle_incoming_control_packet(self, mut router_control_rx: UnboundedReceiver) { + async fn handle_incoming_control_packet( + self, + mut router_control_rx: UnboundedReceiver, + ) { loop { while let Some(control_struct) = router_control_rx.recv().await { match control_struct.control_packet.body.tlv_type { @@ -74,20 +83,29 @@ 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::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); - }, + Self::handle_incoming_update( + self.clone(), + &mut source_table, + &mut routing_table, + control_struct, + ); + } BabelTLVType::RouteReq => todo!(), BabelTLVType::SeqnoReq => todo!(), } } - } + } } - async fn handle_incoming_data_packets(self, mut router_data_rx: UnboundedReceiver, router_data_tx: UnboundedSender) { + async fn handle_incoming_data_packets( + self, + mut router_data_rx: UnboundedReceiver, + router_data_tx: UnboundedSender, + ) { // If the destination IP of the data packet matches with the IP address of this node's TUN interface // we should forward the data packet towards the TUN interface. // If the destination IP doesn't match, we need to lookup if we have a matching peer instance @@ -98,24 +116,27 @@ impl Router { loop { while let Some(data_packet) = router_data_rx.recv().await { let dest_ip = data_packet.dest_ip; - println!("Received data packet with destination: {}", data_packet.dest_ip); + println!( + "Received data packet with destination: {}", + data_packet.dest_ip + ); if dest_ip == tun_addr { match self.node_tun.send(&data_packet.raw_data).await { - Ok(_) => {}, + Ok(_) => {} Err(e) => eprintln!("Error sending data packet to TUN interface: {:?}", e), } } else { // router_data_tx.send(data_packet).unwrap(); // DO BABEL route selection // kijke nr next-hop en gwn sturenn naar de peer die daarmee overeenkomt - + // select the best route towards the destination let best_route = self.select_best_route(IpAddr::V4(dest_ip)); // get the peer corresponding to the best the best route let peer = self.get_peer_by_ip(best_route.unwrap().next_hop).unwrap(); - if let Err(e) = peer.to_peer_data.send(data_packet) { + if let Err(e) = peer.send_data_packet(data_packet) { eprintln!("Error sending data packet to peer: {:?}", e); } } @@ -123,7 +144,6 @@ impl Router { } } - async fn start_periodic_hello_sender(self) { loop { tokio::time::sleep(tokio::time::Duration::from_secs(HELLO_INTERVAL as u64)).await; @@ -131,13 +151,13 @@ impl Router { // create a new hello packet for this peer let hello = ControlPacket::new_hello(peer, HELLO_INTERVAL); // set the last hello timestamp for this peer - peer.time_last_received_hello = tokio::time::Instant::now(); + peer.set_time_last_received_hello(tokio::time::Instant::now()); // send the hello packet to the peer - println!("Sending hello to peer: {:?}", peer.overlay_ip); - if let Err(error) = peer.to_peer_control.send(hello) { + println!("Sending hello to peer: {:?}", peer.overlay_ip()); + if let Err(error) = peer.send_control_packet(hello) { eprintln!("Error sending hello to peer: {}", error); } - } + } } } @@ -149,69 +169,90 @@ impl Router { fn handle_incoming_ihu(&self, control_struct: ControlStruct) { let mut source_peer = self.get_source_peer_from_control_struct(control_struct); // reset the IHU timer associated with the peer - source_peer.ihu_timer.reset(tokio::time::Duration::from_secs(IHU_INTERVAL as u64)); + source_peer.reset_ihu_timer(tokio::time::Duration::from_secs(IHU_INTERVAL as u64)); // measure time between Hello and and IHU and set the link cost - source_peer.link_cost = tokio::time::Instant::now().duration_since(source_peer.time_last_received_hello).as_millis() as u16; - println!("Link cost for peer {:?} set to {}", source_peer.overlay_ip, source_peer.link_cost); + let time_diff = tokio::time::Instant::now() + .duration_since(source_peer.time_last_received_hello()) + .as_millis(); - println!("IHU timer for peer {:?} reset", source_peer.overlay_ip); + source_peer.set_link_cost(time_diff as u16); + println!( + "Link cost for peer {:?} set to {}", + source_peer.overlay_ip(), source_peer.link_cost() + ); + + 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) { + fn handle_incoming_update( + router: Router, + source_table: &mut SourceTable, + routing_table: &mut RoutingTable, + update: ControlStruct, + ) { if source_table.is_feasible(&update) { println!("incoming update is feasible"); 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 } => { - - + BabelTLV::Update { + plen, + interval, + seqno, + metric, + prefix, + router_id, + } => { let source_ip = update.src_overlay_ip; // get RouteEntry for the source of the update - if let Some(route_entry) = routing_table.table.get_mut(&RouteKey { prefix, plen, neighbor: source_ip }) { + if let Some(route_entry) = routing_table.table.get_mut(&RouteKey { + prefix, + plen, + neighbor: source_ip, + }) { route_entry.update(update); } else { let source_key = SourceKey { prefix, - plen, - router_id, + plen, + router_id, }; - let feas_dist = FeasibilityDistance(metric, seqno); - + let feas_dist = FeasibilityDistance(metric, seqno); + // create the source table entry source_table.insert(source_key.clone(), feas_dist); - + // now we can create the routing table entry let route_key = RouteKey { prefix, // prefix is peer that ANNOUNCED the route - plen, + plen, neighbor: update.src_overlay_ip, }; let peer = router.get_peer_by_ip(update.src_overlay_ip).unwrap(); - let route_entry = RouteEntry { - source: source_key, - metric: metric, // + peer.link_cost, --> TODO!!! - seqno: seqno, - neighbor: peer, - next_hop: update.src_overlay_ip, - selected: true, // set selected always to true for now as we have manually decided the topology to only have p2p links - }; + let route_entry = RouteEntry::new( + source_key, + peer.clone(), + peer.link_cost() + metric, + seqno, + update.src_overlay_ip, + true, + router + ); + // create the routing table entry routing_table.insert(route_key, route_entry); } - }, - _ => {}, + } + _ => {} } - } else { println!("incoming update is NOT feasible"); // received update is not feasible - // unselect to route if it was selected + // unselect to route if it was selected } } @@ -219,8 +260,8 @@ impl Router { self.peer_interfaces.lock().unwrap().push(peer); } - pub fn get_node_tun_address(&self) -> Ipv4Addr { - self.node_tun.address().unwrap() + pub fn get_node_tun_address(&self) -> IpAddr { + self.node_tun.address().unwrap().into() } pub fn get_peer_interfaces(&self) -> Vec { @@ -229,12 +270,9 @@ impl Router { pub fn get_peer_by_ip(&self, peer_ip: IpAddr) -> Option { let peers = self.get_peer_interfaces(); - let matching_peer = peers.iter().find(|peer| peer.overlay_ip == peer_ip); + let matching_peer = peers.iter().find(|peer| peer.overlay_ip() == peer_ip); - match matching_peer { - Some(peer) => Some(peer.clone()), - None => None, - } + matching_peer.map(Clone::clone) } fn get_source_peer_from_control_struct(&self, control_struct: ControlStruct) -> Peer { @@ -246,7 +284,10 @@ impl Router { pub fn print_routes(&self) { let routing_table = self.routing_table.lock().unwrap(); for route in routing_table.table.iter() { - println!("Route: {:?}/{:?} (with next-hop: {:?}, metric: {})", route.0.prefix, route.0.plen, route.1.next_hop, route.1.metric); + println!( + "Route: {:?}/{:?} (with next-hop: {:?}, metric: {})", + route.0.prefix, route.0.plen, route.1.next_hop, route.1.metric + ); println!("As advertised by: {:?}", route.1.source.router_id); } } @@ -261,14 +302,14 @@ impl Router { tokio::time::sleep(tokio::time::Duration::from_secs(10)).await; for peer in self.peer_interfaces.lock().unwrap().iter_mut() { // we check for the u16::MAX - 1 value, as this is the value that the link cost is initialized to - if peer.link_cost == (u16::MAX - 1) { + if peer.link_cost() == (u16::MAX - 1) { // before we can create a routing table entry, we need to create a source table entry let source_key = SourceKey { - prefix: IpAddr::V4(peer.overlay_ip), + prefix: peer.overlay_ip(), plen: 32, // we set the prefix length to 32 for now, this means that each peer is a /32 network (so only route to the peer itself) router_id: 0, // we set all router ids to 0 temporarily }; - let feas_dist = FeasibilityDistance(peer.link_cost, 0); + let feas_dist = FeasibilityDistance(peer.link_cost(), 0); // create the source table entry self.source_table @@ -278,31 +319,32 @@ impl Router { // now we can create the routing table entry let route_key = RouteKey { - prefix: IpAddr::V4(peer.overlay_ip), + prefix: peer.overlay_ip(), plen: 32, // we set the prefix length to 32 for now, this means that each peer is a /32 network (so only route to the peer itself) - neighbor: IpAddr::V4(peer.overlay_ip), + neighbor: peer.overlay_ip(), }; let route_entry = RouteEntry { source: source_key, neighbor: peer.clone(), - metric: peer.link_cost, + metric: peer.link_cost(), seqno: 0, // we set the seqno to 0 for now - next_hop: IpAddr::V4(peer.overlay_ip), + next_hop: peer.overlay_ip(), selected: true, // set selected always to true for now as we have manually decided the topology to only have p2p links }; // create the routing table entry - self.routing_table.lock().unwrap().insert(route_key, route_entry); + self.routing_table + .lock() + .unwrap() + .insert(route_key, route_entry); } } } - } // 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 async fn propagate_routes(self) { - loop { // routes are propagated every 10 secs tokio::time::sleep(tokio::time::Duration::from_secs(10)).await; @@ -312,7 +354,7 @@ impl Router { for (key, entry) in router_table.table.iter() { for peer in peers.iter() { - let update = ControlPacket::new_update ( + let update = ControlPacket::new_update( key.plen, UPDATE_INTERVAL as u16, entry.seqno, @@ -321,21 +363,22 @@ impl Router { entry.source.router_id, ); - if peer.to_peer_control.send(update).is_err() { + if peer.send_control_packet(update).is_err() { println!("route update packet dropped"); } - } + } } } } - pub fn select_best_route(&self, dest_ip: IpAddr) -> Option{ + pub fn select_best_route(&self, dest_ip: IpAddr) -> Option { // first look in the routing table for all routekeys where prefix == dest_ip let routing_table = self.routing_table.lock().unwrap(); let mut matching_routes: Vec<&RouteEntry> = Vec::new(); for route in routing_table.table.iter() { - if route.0.prefix == dest_ip { // NOTE -- this is not correct, we need to check if the dest_ip is in the prefix range + if route.0.prefix == dest_ip { + // NOTE -- this is not correct, we need to check if the dest_ip is in the prefix range matching_routes.push(route.1); println!("Found matching route with next-hop: {:?}", route.1.next_hop); } @@ -359,5 +402,3 @@ impl Router { } } } - - diff --git a/src/routing_table.rs b/src/routing_table.rs index 5a01efa..8f26608 100644 --- a/src/routing_table.rs +++ b/src/routing_table.rs @@ -1,6 +1,12 @@ -use std::{net::IpAddr, collections::HashMap}; +use std::{collections::HashMap, net::IpAddr}; -use crate::{source_table::SourceKey, peer::Peer, timers::Timer, router::Router, packet::{ControlStruct, BabelTLV}}; +use crate::{ + packet::{BabelTLV, ControlStruct}, + peer::Peer, + router::Router, + source_table::SourceKey, + timers::Timer, +}; const HELLO_INTERVAL: u16 = 4; const IHU_INTERVAL: u16 = HELLO_INTERVAL * 3; @@ -25,7 +31,15 @@ pub struct RouteEntry { } impl RouteEntry { - pub fn new(source: SourceKey, neighbor: Peer, metric: u16, seqno: u16, next_hop: IpAddr, selected: bool, router: Router) -> Self { + pub fn new( + source: SourceKey, + neighbor: Peer, + metric: u16, + seqno: u16, + next_hop: IpAddr, + selected: bool, + router: Router, + ) -> Self { Self { source, neighbor, @@ -45,10 +59,17 @@ impl RouteEntry { 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 } => { + BabelTLV::Update { + plen, + interval, + seqno, + metric, + prefix, + router_id, + } => { self.metric = metric; - self.seqno = seqno; - }, + self.seqno = seqno; + } _ => { panic!("Received update with invalid TLV"); } @@ -61,10 +82,9 @@ impl RouteEntry { pub fn is_retracted(&self) -> bool { self.metric == 0xFFFF - } + } } - #[derive(Debug, Clone)] pub struct RoutingTable { pub table: HashMap, @@ -90,6 +110,3 @@ impl RoutingTable { self.table.get(key) } } - - - diff --git a/src/source_table.rs b/src/source_table.rs index 79180f9..1f4d542 100644 --- a/src/source_table.rs +++ b/src/source_table.rs @@ -1,6 +1,6 @@ -use std::{net::IpAddr, collections::HashMap}; +use std::{collections::HashMap, net::IpAddr}; -use crate::packet::{ControlStruct, BabelTLV}; +use crate::packet::{BabelTLV, ControlStruct}; #[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)] pub struct SourceKey { @@ -37,10 +37,15 @@ impl SourceTable { } pub fn update(&mut self, update: &ControlStruct) { - match update.control_packet.body.tlv { - BabelTLV::Update { plen, interval, seqno, metric, prefix, router_id } => { - + BabelTLV::Update { + plen, + interval, + seqno, + metric, + prefix, + router_id, + } => { // first check if the update is feasible if !self.is_feasible(update) { return; @@ -49,19 +54,21 @@ impl SourceTable { let key = SourceKey { prefix: prefix, plen: plen, - router_id: router_id + router_id: router_id, }; let new_distance = FeasibilityDistance(metric, seqno); - let old_distance = self.table.get(&key).cloned(); + 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)); + self.table + .insert(key, FeasibilityDistance(new_distance.0, new_distance.1)); } } None => { - self.table.insert(key, FeasibilityDistance(new_distance.0, new_distance.1)); + self.table + .insert(key, FeasibilityDistance(new_distance.0, new_distance.1)); } } } @@ -70,28 +77,32 @@ impl SourceTable { } } } - pub fn is_feasible(&self, update: &ControlStruct) -> bool { - match update.control_packet.body.tlv { - BabelTLV::Update { plen, interval, seqno, metric, prefix, router_id } => { + BabelTLV::Update { + plen, + interval, + seqno, + metric, + prefix, + router_id, + } => { let key = SourceKey { prefix: prefix, plen: plen, - router_id: router_id + router_id: router_id, }; match self.table.get(&key) { Some(&source_entry) => { - - let metric_2= source_entry.0; + let metric_2 = source_entry.0; let seqno_2 = source_entry.1; if seqno > seqno_2 || (seqno == seqno_2 && metric < metric_2) { - return true + return true; } else { - return false + return false; } } None => return true, @@ -102,4 +113,4 @@ impl SourceTable { } } } -} \ No newline at end of file +} diff --git a/src/timers.rs b/src/timers.rs index a499387..008ad24 100644 --- a/src/timers.rs +++ b/src/timers.rs @@ -1,7 +1,7 @@ use std::sync::{Arc, Mutex}; use std::time::Duration; -use tokio::time::sleep; use tokio::sync::oneshot; +use tokio::time::sleep; use crate::router::Router; @@ -26,11 +26,11 @@ impl Timer { } *self.duration.lock().unwrap() = duration; } - - // on_expire is of a type that implements the Fn trait, which means it's a function or a closure. - // The + Send + 'static part means this function must also satisfy the Send trait (meaning it can be sent between threads safely) - // and have a 'static lifetime (meaning it doesn't capture any non-'static (i.e., temporary) values from its environment). - // This is necessary because the function could be called at any point in the future, + + // on_expire is of a type that implements the Fn trait, which means it's a function or a closure. + // The + Send + 'static part means this function must also satisfy the Send trait (meaning it can be sent between threads safely) + // and have a 'static lifetime (meaning it doesn't capture any non-'static (i.e., temporary) values from its environment). + // This is necessary because the function could be called at any point in the future, // potentially long after the context it was created in has gone away. async fn run(&self, on_expire: impl Fn() + Send + 'static) { @@ -47,24 +47,24 @@ impl Timer { } } - pub fn new_ihu_timer(ihu_interval: u64) -> Timer{ - + pub fn new_ihu_timer(ihu_interval: u64) -> Timer { let timer = Timer::new(Duration::from_secs(ihu_interval)); { let timer = timer.clone(); tokio::spawn(async move { - timer.run(|| { - println!("IHU Timer expired!"); - // node should be assumed as dead - // on expiry the neighbour link should be set to 0xFFFF - // and the route selection process should be run - }).await; + timer + .run(|| { + println!("IHU Timer expired!"); + // node should be assumed as dead + // on expiry the neighbour link should be set to 0xFFFF + // and the route selection process should be run + }) + .await; }); } timer } - } From b367b7828c030b61b231326123be8fc6bdfc4ff7 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Fri, 12 May 2023 15:10:22 +0000 Subject: [PATCH 53/89] leefactor v2 --- src/peer.rs | 9 +++------ src/router.rs | 10 +++++++--- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/peer.rs b/src/peer.rs index 493ad32..b55f026 100644 --- a/src/peer.rs +++ b/src/peer.rs @@ -46,8 +46,10 @@ impl Peer { /// Adds 1 to the sequence number of this peer . pub fn increment_hello_seqno(&self) { + println!("current seqno: {}", self.inner.read().unwrap().hello_seqno); // TODO: Validate this works - self.inner.write().unwrap().hello_seqno += 1 + self.inner.write().unwrap().hello_seqno += 1; + println!("after increment seqno: {}", self.inner.read().unwrap().hello_seqno); } pub fn time_last_received_hello(&self) -> tokio::time::Instant { @@ -231,9 +233,4 @@ impl PeerInner { })), } } - - pub fn increase_hello_seqno(&mut self) { - self.hello_seqno = self.hello_seqno + 1; - println!("last hello seqno increasted to {}", self.hello_seqno); - } } diff --git a/src/router.rs b/src/router.rs index 9834786..103f4b1 100644 --- a/src/router.rs +++ b/src/router.rs @@ -233,10 +233,12 @@ impl Router { let peer = router.get_peer_by_ip(update.src_overlay_ip).unwrap(); + + let current_link_cost = peer.link_cost(); let route_entry = RouteEntry::new( source_key, peer.clone(), - peer.link_cost() + metric, + if current_link_cost > u16::MAX - metric - 1 { u16::MAX-1 } else { current_link_cost + metric }, seqno, update.src_overlay_ip, true, @@ -299,7 +301,7 @@ impl Router { // 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; + tokio::time::sleep(tokio::time::Duration::from_secs(3)).await; for peer in self.peer_interfaces.lock().unwrap().iter_mut() { // we check for the u16::MAX - 1 value, as this is the value that the link cost is initialized to if peer.link_cost() == (u16::MAX - 1) { @@ -347,7 +349,7 @@ impl Router { pub async fn propagate_routes(self) { loop { // routes are propagated every 10 secs - tokio::time::sleep(tokio::time::Duration::from_secs(10)).await; + tokio::time::sleep(tokio::time::Duration::from_secs(3)).await; let router_table = self.routing_table.lock().unwrap(); let peers = self.peer_interfaces.lock().unwrap(); @@ -363,6 +365,8 @@ impl Router { entry.source.router_id, ); + println!("sending udpate packet"); + if peer.send_control_packet(update).is_err() { println!("route update packet dropped"); } From 60843db17e650786d9b28b7c62dd839e1587e299 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Fri, 12 May 2023 15:40:01 +0000 Subject: [PATCH 54/89] Testing seqno update --- src/main.rs | 6 +++- src/peer.rs | 7 ++-- src/peer_manager.rs | 85 ++++++++++++++++++++------------------------ src/router.rs | 28 ++++++++------- src/routing_table.rs | 11 ++---- src/source_table.rs | 10 ++---- 6 files changed, 70 insertions(+), 77 deletions(-) diff --git a/src/main.rs b/src/main.rs index 69c4d43..488c9fe 100644 --- a/src/main.rs +++ b/src/main.rs @@ -121,7 +121,11 @@ async fn main() -> Result<(), Box> { println!("\n----------- Current peers: -----------"); for p in router.get_peer_interfaces() { - println!("Peer: {:?}, with link cost: {}", p.overlay_ip(), p.link_cost()); + println!( + "Peer: {:?}, with link cost: {}", + p.overlay_ip(), + p.link_cost() + ); } println!("\n\n"); diff --git a/src/peer.rs b/src/peer.rs index b55f026..3acee1b 100644 --- a/src/peer.rs +++ b/src/peer.rs @@ -49,14 +49,17 @@ impl Peer { println!("current seqno: {}", self.inner.read().unwrap().hello_seqno); // TODO: Validate this works self.inner.write().unwrap().hello_seqno += 1; - println!("after increment seqno: {}", self.inner.read().unwrap().hello_seqno); + println!( + "after increment seqno: {}", + self.inner.read().unwrap().hello_seqno + ); } pub fn time_last_received_hello(&self) -> tokio::time::Instant { // TODO: Validate this works self.inner.read().unwrap().time_last_received_hello } - + pub fn set_time_last_received_hello(&self, time: tokio::time::Instant) { self.inner.write().unwrap().time_last_received_hello = time } diff --git a/src/peer_manager.rs b/src/peer_manager.rs index 568b38f..9d638d9 100644 --- a/src/peer_manager.rs +++ b/src/peer_manager.rs @@ -1,11 +1,11 @@ use crate::peer::Peer; use crate::router::Router; use serde::Deserialize; -use tokio::net::TcpListener; -use std::net::{Ipv4Addr, SocketAddr, IpAddr, Ipv6Addr}; -use std::sync::{Arc}; +use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}; +use std::sync::Arc; use tokio::io::{AsyncReadExt, AsyncWriteExt}; -use tokio::{net::TcpStream}; +use tokio::net::TcpListener; +use tokio::net::TcpStream; pub const NODE_CONFIG_FILE_PATH: &str = "nodeconfig.toml"; @@ -20,17 +20,18 @@ pub struct PeerManager { } impl PeerManager { - pub fn new(router: Arc, static_peers_sockets: Vec) -> Self { - let peer_manager = PeerManager { router }; - // Start a TCP listener. When a new connection is accepted, the reverse peer exchange is performed. + // Start a TCP listener. When a new connection is accepted, the reverse peer exchange is performed. tokio::spawn(PeerManager::start_listener(peer_manager.clone())); // Reads the nodeconfig.toml file and connects to the peers in the file. tokio::spawn(PeerManager::get_peers_from_config(peer_manager.clone())); // Remote nodes can also be read from CLI arg - tokio::spawn(PeerManager::get_peers_from_cli(peer_manager.clone(), static_peers_sockets)); + tokio::spawn(PeerManager::get_peers_from_cli( + peer_manager.clone(), + static_peers_sockets, + )); peer_manager } @@ -44,15 +45,15 @@ impl PeerManager { let mut buffer = [0u8; 17]; peer_stream.read_exact(&mut buffer).await.unwrap(); let received_overlay_ip = match buffer[0] { - 0 => { - IpAddr::from(<&[u8] as TryInto<[u8;4]>>::try_into(&buffer[1..5]).unwrap()) - }, - 1 => { - IpAddr::from(<&[u8] as TryInto<[u8;16]>>::try_into(&buffer[1..]).unwrap()) - } + 0 => IpAddr::from( + <&[u8] as TryInto<[u8; 4]>>::try_into(&buffer[1..5]).unwrap(), + ), + 1 => IpAddr::from( + <&[u8] as TryInto<[u8; 16]>>::try_into(&buffer[1..]).unwrap(), + ), _ => { eprintln!("Invalid address encoding byte"); - continue + continue; } }; @@ -66,7 +67,7 @@ impl PeerManager { IpAddr::V4(tun_addr) => { buf[0] = 0; buf[1..5].copy_from_slice(&tun_addr.octets()[..]); - }, + } IpAddr::V6(tun_addr) => { buf[0] = 1; buf[1..].copy_from_slice(&tun_addr.octets()[..]); @@ -102,14 +103,14 @@ impl PeerManager { peer_stream.read_exact(&mut buffer).await.unwrap(); let received_overlay_ip = match buffer[0] { 0 => { - IpAddr::from(<&[u8] as TryInto<[u8;4]>>::try_into(&buffer[1..5]).unwrap()) - }, + IpAddr::from(<&[u8] as TryInto<[u8; 4]>>::try_into(&buffer[1..5]).unwrap()) + } 1 => { - IpAddr::from(<&[u8] as TryInto<[u8;16]>>::try_into(&buffer[1..]).unwrap()) + IpAddr::from(<&[u8] as TryInto<[u8; 16]>>::try_into(&buffer[1..]).unwrap()) } _ => { eprintln!("Invalid address encoding byte"); - continue + continue; } }; println!( @@ -123,7 +124,7 @@ impl PeerManager { IpAddr::V4(tun_addr) => { buf[0] = 0; buf[1..5].copy_from_slice(&tun_addr.octets()[..]); - }, + } IpAddr::V6(tun_addr) => { buf[0] = 1; buf[1..].copy_from_slice(&tun_addr.octets()[..]); @@ -146,41 +147,36 @@ impl PeerManager { } } - async fn start_listener(self) { match TcpListener::bind("[::]:9651").await { - Ok(listener) => { - loop { - match listener.accept().await { - Ok((stream, _)) => { - PeerManager::start_reverse_peer_exchange(stream, self.router.clone()).await; - } - Err(e) => { - eprintln!("Error accepting connection: {}", e); - } + Ok(listener) => loop { + match listener.accept().await { + Ok((stream, _)) => { + PeerManager::start_reverse_peer_exchange(stream, self.router.clone()).await; + } + Err(e) => { + eprintln!("Error accepting connection: {}", e); } } - } + }, Err(e) => { eprintln!("Error starting listener: {}", e); } } - } + } async fn start_reverse_peer_exchange(mut stream: TcpStream, router: Arc) { - // Steps: // 1. Send own TUN address over the stream // 2. Read other node's TUN address from the stream - let mut buf = [0u8; 17]; match router.get_node_tun_address() { IpAddr::V4(tun_addr) => { buf[0] = 0; buf[1..5].copy_from_slice(&tun_addr.octets()[..]); - }, + } IpAddr::V6(tun_addr) => { buf[0] = 1; buf[1..].copy_from_slice(&tun_addr.octets()[..]); @@ -189,22 +185,19 @@ impl PeerManager { stream.write_all(&buf).await.unwrap(); - - stream.read_exact(&mut buf).await.unwrap(); let received_overlay_ip = match buf[0] { - 0 => { - IpAddr::from(<&[u8] as TryInto<[u8;4]>>::try_into(&buf[1..5]).unwrap()) - }, - 1 => { - IpAddr::from(<&[u8] as TryInto<[u8;16]>>::try_into(&buf[1..]).unwrap()) - } + 0 => IpAddr::from(<&[u8] as TryInto<[u8; 4]>>::try_into(&buf[1..5]).unwrap()), + 1 => IpAddr::from(<&[u8] as TryInto<[u8; 16]>>::try_into(&buf[1..]).unwrap()), _ => { eprintln!("Invalid address encoding byte"); - return; + return; } }; - println!("Received overlay IP from other node: {:?}", received_overlay_ip); + println!( + "Received overlay IP from other node: {:?}", + received_overlay_ip + ); // Create new Peer instance let peer_stream_ip = stream.peer_addr().unwrap().ip(); diff --git a/src/router.rs b/src/router.rs index 103f4b1..6e6f588 100644 --- a/src/router.rs +++ b/src/router.rs @@ -178,7 +178,8 @@ impl Router { source_peer.set_link_cost(time_diff as u16); println!( "Link cost for peer {:?} set to {}", - source_peer.overlay_ip(), source_peer.link_cost() + source_peer.overlay_ip(), + source_peer.link_cost() ); println!("IHU timer for peer {:?} reset", source_peer.overlay_ip()); @@ -190,6 +191,7 @@ impl Router { routing_table: &mut RoutingTable, update: ControlStruct, ) { + println!("Received update {:?}", update); if source_table.is_feasible(&update) { println!("incoming update is feasible"); source_table.update(&update); @@ -198,12 +200,13 @@ impl Router { match update.control_packet.body.tlv { BabelTLV::Update { plen, - interval, + interval: _, seqno, metric, prefix, router_id, } => { + println!("Received update from {} for {:?} with seqno {}", router_id, prefix, seqno); let source_ip = update.src_overlay_ip; // get RouteEntry for the source of the update @@ -233,18 +236,16 @@ impl Router { let peer = router.get_peer_by_ip(update.src_overlay_ip).unwrap(); - - let current_link_cost = peer.link_cost(); let route_entry = RouteEntry::new( source_key, - peer.clone(), - if current_link_cost > u16::MAX - metric - 1 { u16::MAX-1 } else { current_link_cost + metric }, - seqno, - update.src_overlay_ip, - true, - router + peer.clone(), + metric, + seqno, + update.src_overlay_ip, + true, + router, ); - + // create the routing table entry routing_table.insert(route_key, route_entry); } @@ -351,10 +352,11 @@ impl Router { // routes are propagated every 10 secs tokio::time::sleep(tokio::time::Duration::from_secs(3)).await; - let router_table = self.routing_table.lock().unwrap(); + let mut router_table = self.routing_table.lock().unwrap(); let peers = self.peer_interfaces.lock().unwrap(); - for (key, entry) in router_table.table.iter() { + for (key, entry) in router_table.table.iter_mut() { + entry.seqno += 1; for peer in peers.iter() { let update = ControlPacket::new_update( key.plen, diff --git a/src/routing_table.rs b/src/routing_table.rs index 8f26608..7dc12b6 100644 --- a/src/routing_table.rs +++ b/src/routing_table.rs @@ -59,16 +59,11 @@ impl RouteEntry { 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, - } => { + BabelTLV::Update { seqno, metric, .. } => { + println!("Update starting, entry is now {:?}", self); self.metric = metric; self.seqno = seqno; + println!("Update finished, entry is now {:?}", self); } _ => { panic!("Received update with invalid TLV"); diff --git a/src/source_table.rs b/src/source_table.rs index 1f4d542..03f7455 100644 --- a/src/source_table.rs +++ b/src/source_table.rs @@ -82,7 +82,7 @@ impl SourceTable { match update.control_packet.body.tlv { BabelTLV::Update { plen, - interval, + interval: _, seqno, metric, prefix, @@ -99,13 +99,9 @@ impl SourceTable { 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; - } + seqno > seqno_2 || (seqno == seqno_2 && metric < metric_2) } - None => return true, + None => true, } } _ => { From 07dcae681246988e5706783e680264fcac615ebd Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Fri, 12 May 2023 16:03:11 +0000 Subject: [PATCH 55/89] Leefactor --- src/router.rs | 15 ++++++++------- src/routing_table.rs | 6 ++---- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/router.rs b/src/router.rs index 6e6f588..4d82a71 100644 --- a/src/router.rs +++ b/src/router.rs @@ -191,7 +191,6 @@ impl Router { routing_table: &mut RoutingTable, update: ControlStruct, ) { - println!("Received update {:?}", update); if source_table.is_feasible(&update) { println!("incoming update is feasible"); source_table.update(&update); @@ -305,7 +304,7 @@ impl Router { tokio::time::sleep(tokio::time::Duration::from_secs(3)).await; for peer in self.peer_interfaces.lock().unwrap().iter_mut() { // we check for the u16::MAX - 1 value, as this is the value that the link cost is initialized to - if peer.link_cost() == (u16::MAX - 1) { + //if peer.link_cost() == u16::MAX - 1 { // before we can create a routing table entry, we need to create a source table entry let source_key = SourceKey { prefix: peer.overlay_ip(), @@ -326,11 +325,15 @@ impl Router { plen: 32, // we set the prefix length to 32 for now, this means that each peer is a /32 network (so only route to the peer itself) neighbor: peer.overlay_ip(), }; + + let seqno = if let Some(re) = self.routing_table.lock().unwrap().remove(&route_key) { + re.seqno + } else { 0 }; let route_entry = RouteEntry { source: source_key, neighbor: peer.clone(), metric: peer.link_cost(), - seqno: 0, // we set the seqno to 0 for now + seqno: seqno, // we set the seqno to 0 for now next_hop: peer.overlay_ip(), selected: true, // set selected always to true for now as we have manually decided the topology to only have p2p links }; @@ -339,7 +342,7 @@ impl Router { .lock() .unwrap() .insert(route_key, route_entry); - } + //} } } } @@ -362,13 +365,11 @@ impl Router { key.plen, UPDATE_INTERVAL as u16, entry.seqno, - entry.metric, + entry.metric + entry.neighbor.link_cost(), key.prefix, entry.source.router_id, ); - println!("sending udpate packet"); - if peer.send_control_packet(update).is_err() { println!("route update packet dropped"); } diff --git a/src/routing_table.rs b/src/routing_table.rs index 7dc12b6..c5c207e 100644 --- a/src/routing_table.rs +++ b/src/routing_table.rs @@ -60,10 +60,8 @@ impl RouteEntry { // the update is assumed to be feasible here match update.control_packet.body.tlv { BabelTLV::Update { seqno, metric, .. } => { - println!("Update starting, entry is now {:?}", self); self.metric = metric; self.seqno = seqno; - println!("Update finished, entry is now {:?}", self); } _ => { panic!("Received update with invalid TLV"); @@ -97,8 +95,8 @@ impl RoutingTable { //println!("Added route to routing table: {:?}", self.table); } - pub fn remove(&mut self, key: &RouteKey) { - self.table.remove(key); + pub fn remove(&mut self, key: &RouteKey) -> Option { + self.table.remove(key) } pub fn get(&self, key: &RouteKey) -> Option<&RouteEntry> { From e5233d3e9d4040172f015364e75916e7a169a541 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Fri, 12 May 2023 16:05:50 +0000 Subject: [PATCH 56/89] Leefactor V2 --- src/router.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/router.rs b/src/router.rs index 4d82a71..48966aa 100644 --- a/src/router.rs +++ b/src/router.rs @@ -360,12 +360,15 @@ impl Router { for (key, entry) in router_table.table.iter_mut() { entry.seqno += 1; + let link_cost = entry.neighbor.link_cost(); for peer in peers.iter() { let update = ControlPacket::new_update( key.plen, UPDATE_INTERVAL as u16, entry.seqno, - entry.metric + entry.neighbor.link_cost(), + if entry.metric > u16::MAX - 1 - link_cost { + u16::MAX -1 + } else { entry.metric + link_cost}, key.prefix, entry.source.router_id, ); From f9dad9ccd22d5bbefa200905233658285a8c96c0 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Fri, 12 May 2023 16:12:13 +0000 Subject: [PATCH 57/89] Leebug --- src/router.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/router.rs b/src/router.rs index 48966aa..04f7622 100644 --- a/src/router.rs +++ b/src/router.rs @@ -286,6 +286,7 @@ impl Router { pub fn print_routes(&self) { let routing_table = self.routing_table.lock().unwrap(); for route in routing_table.table.iter() { + println!("Route key: {:?}", route.0); println!( "Route: {:?}/{:?} (with next-hop: {:?}, metric: {})", route.0.prefix, route.0.plen, route.1.next_hop, route.1.metric From 5b1487bb078c3f15bb0abbc6a750eb5ac386d7ff Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Fri, 12 May 2023 16:55:19 +0000 Subject: [PATCH 58/89] TGIF --- src/main.rs | 4 +- src/router.rs | 152 ++++++++++++++++++++++++++++++++------------------ 2 files changed, 101 insertions(+), 55 deletions(-) diff --git a/src/main.rs b/src/main.rs index 488c9fe..d2af836 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,7 +12,7 @@ use std::{ }; use tokio::io::AsyncBufReadExt; -use crate::peer::Peer; +use crate::{peer::Peer, router::StaticRoute}; mod codec; mod node_setup; @@ -52,7 +52,7 @@ async fn main() -> Result<(), Box> { let static_peers = cli.static_peers; // Creating a new Router instance - let router = Arc::new(router::Router::new(node_tun.clone())); + let router = Arc::new(router::Router::new(node_tun.clone(), vec![StaticRoute::new(cli.tun_addr.into())])); // Creating a new PeerManager instance let _peer_manager: peer_manager::PeerManager = peer_manager::PeerManager::new(router.clone(), static_peers); diff --git a/src/router.rs b/src/router.rs index 04f7622..f3d2b80 100644 --- a/src/router.rs +++ b/src/router.rs @@ -21,6 +21,23 @@ const HELLO_INTERVAL: u16 = 4; const IHU_INTERVAL: u16 = HELLO_INTERVAL * 3; const UPDATE_INTERVAL: u16 = HELLO_INTERVAL * 4; +#[derive(Debug,Clone, Copy)] +pub struct StaticRoute { + plen: u8, + prefix: IpAddr, + seqno: u16, +} + +impl StaticRoute { + pub fn new(prefix: IpAddr) -> Self { + Self { + plen: 32, + prefix, + seqno: 0, + } + } +} + #[derive(Clone)] pub struct Router { pub router_id: u64, @@ -32,10 +49,11 @@ pub struct Router { pub routing_table: Arc>, pub source_table: Arc>, pub router_seqno: u16, + static_routes: Arc>>, } impl Router { - pub fn new(node_tun: Arc) -> Self { + pub fn new(node_tun: Arc, static_routes: Vec) -> Self { // Tx is passed onto each new peer instance. This enables peers to send control packets to the router. let (router_control_tx, router_control_rx) = mpsc::unbounded_channel::(); // Tx is passed onto each new peer instance. This enables peers to send data packets to the router. @@ -50,6 +68,7 @@ impl Router { routing_table: Arc::new(Mutex::new(RoutingTable::new())), source_table: Arc::new(Mutex::new(SourceTable::new())), router_seqno: 0, + static_routes: Arc::new(Mutex::new(static_routes)), }; tokio::spawn(Router::handle_incoming_control_packet( @@ -64,7 +83,7 @@ impl Router { tokio::spawn(Router::start_periodic_hello_sender(router.clone())); // loops over all peers and adds routing table entries for each peer - tokio::spawn(Router::initialize_peer_route_entries(router.clone())); + //tokio::spawn(Router::initialize_peer_route_entries(router.clone())); // propagate routes tokio::spawn(Router::propagate_routes(router.clone())); @@ -205,7 +224,10 @@ impl Router { prefix, router_id, } => { - println!("Received update from {} for {:?} with seqno {}", router_id, prefix, seqno); + println!( + "Received update from {} for {:?} with seqno {}", + router_id, prefix, seqno + ); let source_ip = update.src_overlay_ip; // get RouteEntry for the source of the update @@ -298,55 +320,58 @@ impl Router { // loop over the directly connected peers and create routing table entries for them // 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(3)).await; - for peer in self.peer_interfaces.lock().unwrap().iter_mut() { - // we check for the u16::MAX - 1 value, as this is the value that the link cost is initialized to - //if peer.link_cost() == u16::MAX - 1 { - // before we can create a routing table entry, we need to create a source table entry - let source_key = SourceKey { - prefix: peer.overlay_ip(), - plen: 32, // we set the prefix length to 32 for now, this means that each peer is a /32 network (so only route to the peer itself) - router_id: 0, // we set all router ids to 0 temporarily - }; - let feas_dist = FeasibilityDistance(peer.link_cost(), 0); + //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(3)).await; + //for peer in self.peer_interfaces.lock().unwrap().iter_mut() { + //// we check for the u16::MAX - 1 value, as this is the value that the link cost is initialized to + ////if peer.link_cost() == u16::MAX - 1 { + //// before we can create a routing table entry, we need to create a source table entry + //let source_key = SourceKey { + //prefix: peer.overlay_ip(), + //plen: 32, // we set the prefix length to 32 for now, this means that each peer is a /32 network (so only route to the peer itself) + //router_id: 0, // we set all router ids to 0 temporarily + //}; + //let feas_dist = FeasibilityDistance(peer.link_cost(), 0); - // create the source table entry - self.source_table - .lock() - .unwrap() - .insert(source_key.clone(), feas_dist); + //// create the source table entry + //self.source_table + //.lock() + //.unwrap() + //.insert(source_key.clone(), feas_dist); - // now we can create the routing table entry - let route_key = RouteKey { - prefix: peer.overlay_ip(), - plen: 32, // we set the prefix length to 32 for now, this means that each peer is a /32 network (so only route to the peer itself) - neighbor: peer.overlay_ip(), - }; + //// now we can create the routing table entry + //let route_key = RouteKey { + //prefix: peer.overlay_ip(), + //plen: 32, // we set the prefix length to 32 for now, this means that each peer is a /32 network (so only route to the peer itself) + //neighbor: peer.overlay_ip(), + //}; - let seqno = if let Some(re) = self.routing_table.lock().unwrap().remove(&route_key) { - re.seqno - } else { 0 }; - let route_entry = RouteEntry { - source: source_key, - neighbor: peer.clone(), - metric: peer.link_cost(), - seqno: seqno, // we set the seqno to 0 for now - next_hop: peer.overlay_ip(), - selected: true, // set selected always to true for now as we have manually decided the topology to only have p2p links - }; - // create the routing table entry - self.routing_table - .lock() - .unwrap() - .insert(route_key, route_entry); - //} - } - } - } + //let seqno = if let Some(re) = self.routing_table.lock().unwrap().remove(&route_key) + //{ + //re.seqno + //} else { + //0 + //}; + //let route_entry = RouteEntry { + //source: source_key, + //neighbor: peer.clone(), + //metric: peer.link_cost(), + //seqno: seqno, // we set the seqno to 0 for now + //next_hop: peer.overlay_ip(), + //selected: true, // set selected always to true for now as we have manually decided the topology to only have p2p links + //}; + //// create the routing table entry + //self.routing_table + //.lock() + //.unwrap() + //.insert(route_key, route_entry); + ////} + //} + //} + //} // 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) @@ -357,19 +382,40 @@ impl Router { tokio::time::sleep(tokio::time::Duration::from_secs(3)).await; let mut router_table = self.routing_table.lock().unwrap(); + let mut static_routes = self.static_routes.lock().unwrap(); let peers = self.peer_interfaces.lock().unwrap(); + for route in static_routes.iter_mut() { + route.seqno += 1; + for peer in peers.iter() { + let update = ControlPacket::new_update( + route.plen, + UPDATE_INTERVAL as u16, + route.seqno, + peer.link_cost(), + route.prefix, + self.router_id, + ); + + if peer.send_control_packet(update).is_err() { + println!("could not send static route to peer"); + } + } + } + for (key, entry) in router_table.table.iter_mut() { entry.seqno += 1; - let link_cost = entry.neighbor.link_cost(); for peer in peers.iter() { + let link_cost = peer.link_cost(); let update = ControlPacket::new_update( key.plen, UPDATE_INTERVAL as u16, entry.seqno, - if entry.metric > u16::MAX - 1 - link_cost { - u16::MAX -1 - } else { entry.metric + link_cost}, + if entry.metric > u16::MAX - 1 - link_cost { + u16::MAX - 1 + } else { + entry.metric + link_cost + }, key.prefix, entry.source.router_id, ); From 963662b193477d1818d79344ecf415a71c3cc7e6 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Fri, 12 May 2023 17:06:49 +0000 Subject: [PATCH 59/89] time to go --- src/main.rs | 5 ++- src/router.rs | 113 +++++++++++++++++++++++++++----------------------- 2 files changed, 64 insertions(+), 54 deletions(-) diff --git a/src/main.rs b/src/main.rs index d2af836..a316220 100644 --- a/src/main.rs +++ b/src/main.rs @@ -52,7 +52,10 @@ async fn main() -> Result<(), Box> { let static_peers = cli.static_peers; // Creating a new Router instance - let router = Arc::new(router::Router::new(node_tun.clone(), vec![StaticRoute::new(cli.tun_addr.into())])); + let router = Arc::new(router::Router::new( + node_tun.clone(), + vec![StaticRoute::new(cli.tun_addr.into())], + )); // Creating a new PeerManager instance let _peer_manager: peer_manager::PeerManager = peer_manager::PeerManager::new(router.clone(), static_peers); diff --git a/src/router.rs b/src/router.rs index f3d2b80..f561183 100644 --- a/src/router.rs +++ b/src/router.rs @@ -21,7 +21,7 @@ const HELLO_INTERVAL: u16 = 4; const IHU_INTERVAL: u16 = HELLO_INTERVAL * 3; const UPDATE_INTERVAL: u16 = HELLO_INTERVAL * 4; -#[derive(Debug,Clone, Copy)] +#[derive(Debug, Clone, Copy)] pub struct StaticRoute { plen: u8, prefix: IpAddr, @@ -31,9 +31,9 @@ pub struct StaticRoute { impl StaticRoute { pub fn new(prefix: IpAddr) -> Self { Self { - plen: 32, - prefix, - seqno: 0, + plen: 32, + prefix, + seqno: 0, } } } @@ -321,56 +321,56 @@ 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(3)).await; - //for peer in self.peer_interfaces.lock().unwrap().iter_mut() { - //// we check for the u16::MAX - 1 value, as this is the value that the link cost is initialized to - ////if peer.link_cost() == u16::MAX - 1 { - //// before we can create a routing table entry, we need to create a source table entry - //let source_key = SourceKey { - //prefix: peer.overlay_ip(), - //plen: 32, // we set the prefix length to 32 for now, this means that each peer is a /32 network (so only route to the peer itself) - //router_id: 0, // we set all router ids to 0 temporarily - //}; - //let feas_dist = FeasibilityDistance(peer.link_cost(), 0); + //// 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(3)).await; + //for peer in self.peer_interfaces.lock().unwrap().iter_mut() { + //// we check for the u16::MAX - 1 value, as this is the value that the link cost is initialized to + ////if peer.link_cost() == u16::MAX - 1 { + //// before we can create a routing table entry, we need to create a source table entry + //let source_key = SourceKey { + //prefix: peer.overlay_ip(), + //plen: 32, // we set the prefix length to 32 for now, this means that each peer is a /32 network (so only route to the peer itself) + //router_id: 0, // we set all router ids to 0 temporarily + //}; + //let feas_dist = FeasibilityDistance(peer.link_cost(), 0); - //// create the source table entry - //self.source_table - //.lock() - //.unwrap() - //.insert(source_key.clone(), feas_dist); + //// create the source table entry + //self.source_table + //.lock() + //.unwrap() + //.insert(source_key.clone(), feas_dist); - //// now we can create the routing table entry - //let route_key = RouteKey { - //prefix: peer.overlay_ip(), - //plen: 32, // we set the prefix length to 32 for now, this means that each peer is a /32 network (so only route to the peer itself) - //neighbor: peer.overlay_ip(), - //}; + //// now we can create the routing table entry + //let route_key = RouteKey { + //prefix: peer.overlay_ip(), + //plen: 32, // we set the prefix length to 32 for now, this means that each peer is a /32 network (so only route to the peer itself) + //neighbor: peer.overlay_ip(), + //}; - //let seqno = if let Some(re) = self.routing_table.lock().unwrap().remove(&route_key) - //{ - //re.seqno - //} else { - //0 - //}; - //let route_entry = RouteEntry { - //source: source_key, - //neighbor: peer.clone(), - //metric: peer.link_cost(), - //seqno: seqno, // we set the seqno to 0 for now - //next_hop: peer.overlay_ip(), - //selected: true, // set selected always to true for now as we have manually decided the topology to only have p2p links - //}; - //// create the routing table entry - //self.routing_table - //.lock() - //.unwrap() - //.insert(route_key, route_entry); - ////} - //} - //} + //let seqno = if let Some(re) = self.routing_table.lock().unwrap().remove(&route_key) + //{ + //re.seqno + //} else { + //0 + //}; + //let route_entry = RouteEntry { + //source: source_key, + //neighbor: peer.clone(), + //metric: peer.link_cost(), + //seqno: seqno, // we set the seqno to 0 for now + //next_hop: peer.overlay_ip(), + //selected: true, // set selected always to true for now as we have manually decided the topology to only have p2p links + //}; + //// create the routing table entry + //self.routing_table + //.lock() + //.unwrap() + //.insert(route_key, route_entry); + ////} + //} + //} //} // routing table updates are send periodically to all directly connected peers @@ -399,11 +399,18 @@ impl Router { if peer.send_control_packet(update).is_err() { println!("could not send static route to peer"); - } } + } } - for (key, entry) in router_table.table.iter_mut() { + for (key, entry) in router_table.table.iter_mut().filter(|(key, _)| { + for sr in static_routes.iter() { + if key.prefix == sr.prefix && key.plen == sr.plen { + return false; + } + } + true + }) { entry.seqno += 1; for peer in peers.iter() { let link_cost = peer.link_cost(); From 3f762a6b70ae00b0468dcc65ccb462cc94585004 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Mon, 15 May 2023 08:56:43 +0000 Subject: [PATCH 60/89] display selected --- src/router.rs | 20 ++++++++++++-------- src/routing_table.rs | 10 ---------- 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/src/router.rs b/src/router.rs index f561183..5d5a996 100644 --- a/src/router.rs +++ b/src/router.rs @@ -310,8 +310,8 @@ impl Router { for route in routing_table.table.iter() { println!("Route key: {:?}", route.0); println!( - "Route: {:?}/{:?} (with next-hop: {:?}, metric: {})", - route.0.prefix, route.0.plen, route.1.next_hop, route.1.metric + "Route: {:?}/{:?} (with next-hop: {:?}, metric: {}, selected: {})", + route.0.prefix, route.0.plen, route.1.next_hop, route.1.metric, route.1.selected ); println!("As advertised by: {:?}", route.1.source.router_id); } @@ -378,7 +378,7 @@ impl Router { // this function is run when the route_update timer expires pub async fn propagate_routes(self) { loop { - // routes are propagated every 10 secs + // routes are propagated every 3 secs tokio::time::sleep(tokio::time::Duration::from_secs(3)).await; let mut router_table = self.routing_table.lock().unwrap(); @@ -403,12 +403,13 @@ impl Router { } } - for (key, entry) in router_table.table.iter_mut().filter(|(key, _)| { - for sr in static_routes.iter() { - if key.prefix == sr.prefix && key.plen == sr.plen { - return false; + for (key, entry) in router_table.table.iter_mut() + .filter(|(key, _)| { // Filter out the static routes + for sr in static_routes.iter() { + if key.prefix == sr.prefix && key.plen == sr.plen { + return false; + } } - } true }) { entry.seqno += 1; @@ -432,6 +433,9 @@ impl Router { } } } + + + // FILTER VOOR SELECTED ROUTE NODIG --> we sturen nu alle routes maar eignelijk moeten we enkel de selected routes gaan propagaten } } diff --git a/src/routing_table.rs b/src/routing_table.rs index c5c207e..24abe86 100644 --- a/src/routing_table.rs +++ b/src/routing_table.rs @@ -8,10 +8,6 @@ use crate::{ timers::Timer, }; -const HELLO_INTERVAL: u16 = 4; -const IHU_INTERVAL: u16 = HELLO_INTERVAL * 3; -const UPDATE_INTERVAL: u16 = HELLO_INTERVAL * 4; - #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct RouteKey { pub prefix: IpAddr, @@ -50,12 +46,6 @@ impl RouteEntry { } } - // 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 { From 675e6140bf5713827a260e27cd89829b314ef0cb Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Mon, 15 May 2023 09:16:31 +0000 Subject: [PATCH 61/89] route set to selected or not v1 --- src/router.rs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/router.rs b/src/router.rs index 5d5a996..24a6858 100644 --- a/src/router.rs +++ b/src/router.rs @@ -257,16 +257,20 @@ impl Router { let peer = router.get_peer_by_ip(update.src_overlay_ip).unwrap(); - let route_entry = RouteEntry::new( + let should_be_selected = Router::set_incoming_update_selected(routing_table, route_key.clone(), metric); + + + let mut route_entry = RouteEntry::new( source_key, peer.clone(), metric, seqno, update.src_overlay_ip, - true, + should_be_selected, router, ); + // create the routing table entry routing_table.insert(route_key, route_entry); } @@ -279,6 +283,17 @@ impl Router { // unselect to route if it was selected } } + + // this function shoud check if an incoming update should be selected or not + pub fn set_incoming_update_selected(routing_table: &mut RoutingTable, route_key: RouteKey, new_metric: u16) -> bool { + let route_entry = routing_table.table.get_mut(&route_key).unwrap(); + println!("current metric: {}, new metric: {}", route_entry.metric, new_metric); + if route_entry.metric < new_metric { + return false + } + return true + } + pub fn add_directly_connected_peer(&self, peer: Peer) { self.peer_interfaces.lock().unwrap().push(peer); From d2769cc843f85eb3f35cb4da85b49dd7bef1676c Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Mon, 15 May 2023 09:19:46 +0000 Subject: [PATCH 62/89] route set to selected or not v2 --- src/router.rs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/router.rs b/src/router.rs index 24a6858..caff4a1 100644 --- a/src/router.rs +++ b/src/router.rs @@ -256,10 +256,7 @@ impl Router { }; let peer = router.get_peer_by_ip(update.src_overlay_ip).unwrap(); - let should_be_selected = Router::set_incoming_update_selected(routing_table, route_key.clone(), metric); - - let mut route_entry = RouteEntry::new( source_key, peer.clone(), @@ -286,12 +283,18 @@ impl Router { // this function shoud check if an incoming update should be selected or not pub fn set_incoming_update_selected(routing_table: &mut RoutingTable, route_key: RouteKey, new_metric: u16) -> bool { - let route_entry = routing_table.table.get_mut(&route_key).unwrap(); - println!("current metric: {}, new metric: {}", route_entry.metric, new_metric); - if route_entry.metric < new_metric { - return false + + // first check if the routing table has an entry for that key or not, if it has no entry return true + if !routing_table.table.contains_key(&route_key) { + return true + } else { + let route_entry = routing_table.table.get_mut(&route_key).unwrap(); + println!("current metric: {}, new metric: {}", route_entry.metric, new_metric); + if route_entry.metric < new_metric { + return false + } + return true } - return true } From 40093c2dd3cc8eccee60537aef796f7f9d95838e Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Mon, 15 May 2023 11:29:19 +0000 Subject: [PATCH 63/89] route set to selected or not v3 --- src/router.rs | 19 +++++++++++-------- src/routing_table.rs | 3 ++- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/router.rs b/src/router.rs index caff4a1..c0cf5ec 100644 --- a/src/router.rs +++ b/src/router.rs @@ -225,19 +225,22 @@ impl Router { router_id, } => { println!( - "Received update from {} for {:?} with seqno {}", - router_id, prefix, seqno + "Received update from {} for {:?} with seqno {} and metric {}", + router_id, prefix, seqno, metric ); let source_ip = update.src_overlay_ip; // get RouteEntry for the source of the update - if let Some(route_entry) = routing_table.table.get_mut(&RouteKey { + let route_key = &RouteKey { prefix, plen, neighbor: source_ip, - }) { - route_entry.update(update); - } else { + }; + if let Some(route_entry) = routing_table.clone().table.get_mut(route_key) { + let should_be_selected = Router::set_incoming_update_selected(routing_table, route_key.clone(), metric); + route_entry.update(update, should_be_selected); + } + else { let source_key = SourceKey { prefix, plen, @@ -256,14 +259,13 @@ impl Router { }; let peer = router.get_peer_by_ip(update.src_overlay_ip).unwrap(); - let should_be_selected = Router::set_incoming_update_selected(routing_table, route_key.clone(), metric); let mut route_entry = RouteEntry::new( source_key, peer.clone(), metric, seqno, update.src_overlay_ip, - should_be_selected, + true, // for new entries the route is always selected router, ); @@ -286,6 +288,7 @@ impl Router { // first check if the routing table has an entry for that key or not, if it has no entry return true if !routing_table.table.contains_key(&route_key) { + println!("no entry for this route key, returning true"); return true } else { let route_entry = routing_table.table.get_mut(&route_key).unwrap(); diff --git a/src/routing_table.rs b/src/routing_table.rs index 24abe86..becc0c3 100644 --- a/src/routing_table.rs +++ b/src/routing_table.rs @@ -46,12 +46,13 @@ impl RouteEntry { } } - pub fn update(&mut self, update: ControlStruct) { + pub fn update(&mut self, update: ControlStruct, should_be_selected: bool) { // the update is assumed to be feasible here match update.control_packet.body.tlv { BabelTLV::Update { seqno, metric, .. } => { self.metric = metric; self.seqno = seqno; + self.selected = should_be_selected; } _ => { panic!("Received update with invalid TLV"); From ede2f3b3d31176d857e5e36d8820df225289f58a Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Mon, 15 May 2023 11:33:17 +0000 Subject: [PATCH 64/89] route set to selected or not v4 --- src/router.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/router.rs b/src/router.rs index c0cf5ec..8286dbe 100644 --- a/src/router.rs +++ b/src/router.rs @@ -293,7 +293,7 @@ impl Router { } else { let route_entry = routing_table.table.get_mut(&route_key).unwrap(); println!("current metric: {}, new metric: {}", route_entry.metric, new_metric); - if route_entry.metric < new_metric { + if route_entry.metric > new_metric { return false } return true From 0bce73c7de72eb1e1c8593bf21a7c7fc9369673b Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Mon, 15 May 2023 11:41:18 +0000 Subject: [PATCH 65/89] route set to selected or not v5 --- src/router.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/router.rs b/src/router.rs index 8286dbe..ba0fdde 100644 --- a/src/router.rs +++ b/src/router.rs @@ -293,7 +293,7 @@ impl Router { } else { let route_entry = routing_table.table.get_mut(&route_key).unwrap(); println!("current metric: {}, new metric: {}", route_entry.metric, new_metric); - if route_entry.metric > new_metric { + if route_entry.metric < new_metric { return false } return true @@ -436,6 +436,17 @@ impl Router { entry.seqno += 1; for peer in peers.iter() { let link_cost = peer.link_cost(); + + + // DEBUG purposes + if entry.metric > u16::MAX - 1 - link_cost { + println!("SENDING UPDATE WITH METRIC: {}", u16::MAX - 1); + } else { + println!("SENDING UPDATE WITH METRIC: {}", entry.metric + link_cost); + } + + + let update = ControlPacket::new_update( key.plen, UPDATE_INTERVAL as u16, From e03b35a95623fbce6b9cc4b8203fa6e1cfab4e21 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Mon, 15 May 2023 14:58:14 +0000 Subject: [PATCH 66/89] router refactor --- src/main.rs | 22 +- src/node_setup.rs | 3 +- src/peer.rs | 8 + src/peer_manager.rs | 30 +- src/router.rs | 777 +++++++++++++++++++++---------------------- src/routing_table.rs | 4 +- src/source_table.rs | 2 + 7 files changed, 425 insertions(+), 421 deletions(-) diff --git a/src/main.rs b/src/main.rs index a316220..360f8b1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -52,10 +52,17 @@ async fn main() -> Result<(), Box> { let static_peers = cli.static_peers; // Creating a new Router instance - let router = Arc::new(router::Router::new( - node_tun.clone(), - vec![StaticRoute::new(cli.tun_addr.into())], - )); + let router = match router::Router::new(node_tun.clone(), vec![StaticRoute::new(cli.tun_addr.into())]) { + Ok(router) => { + println!("Router created"); + router + } + Err(e) => { + panic!("Error creating router: {}", e); + } + }; + + // Creating a new PeerManager instance let _peer_manager: peer_manager::PeerManager = peer_manager::PeerManager::new(router.clone(), static_peers); @@ -63,8 +70,8 @@ async fn main() -> Result<(), Box> { // 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 { - let node_tun = node_tun.clone(); let router = router.clone(); + let node_tun = node_tun.clone(); tokio::spawn(async move { loop { @@ -97,7 +104,7 @@ async fn main() -> Result<(), Box> { dest_ip: dest_addr, raw_data: buf.to_vec(), }; - if router.router_data_tx.send(data_packet).is_err() { + if router.router_data_tx().send(data_packet).is_err() { eprintln!("Failed to send data_packet"); } } else { @@ -109,7 +116,6 @@ async fn main() -> Result<(), Box> { let mut reader = tokio::io::BufReader::new(tokio::io::stdin()); let mut line = String::new(); - let router = router.clone(); let read_handle = tokio::spawn(async move { loop { @@ -123,7 +129,7 @@ async fn main() -> Result<(), Box> { router.print_routes(); println!("\n----------- Current peers: -----------"); - for p in router.get_peer_interfaces() { + for p in router.peer_interfaces() { println!( "Peer: {:?}, with link cost: {}", p.overlay_ip(), diff --git a/src/node_setup.rs b/src/node_setup.rs index f308b86..6076603 100644 --- a/src/node_setup.rs +++ b/src/node_setup.rs @@ -1,5 +1,6 @@ use futures::stream::TryStreamExt; use rtnetlink::Handle; +use core::fmt; use std::{error::Error, net::Ipv4Addr, sync::Arc}; use tokio_tun::{Tun, TunBuilder}; @@ -61,4 +62,4 @@ pub async fn setup_node(tun_addr: Ipv4Addr) -> Result, Box> println!("Static route created"); Ok(tun) -} +} \ No newline at end of file diff --git a/src/peer.rs b/src/peer.rs index 3acee1b..24a380f 100644 --- a/src/peer.rs +++ b/src/peer.rs @@ -106,6 +106,14 @@ impl Peer { } } +impl PartialEq for Peer { + fn eq(&self, other: &Self) -> bool { + self.overlay_ip() == other.overlay_ip() + } +} + + + #[derive(Debug)] struct PeerInner { stream_ip: IpAddr, diff --git a/src/peer_manager.rs b/src/peer_manager.rs index 9d638d9..26e8ae8 100644 --- a/src/peer_manager.rs +++ b/src/peer_manager.rs @@ -16,11 +16,11 @@ struct PeersConfig { #[derive(Clone)] pub struct PeerManager { - pub router: Arc, + pub router: Router, } impl PeerManager { - pub fn new(router: Arc, static_peers_sockets: Vec) -> Self { + pub fn new(router: Router, static_peers_sockets: Vec) -> Self { let peer_manager = PeerManager { router }; // Start a TCP listener. When a new connection is accepted, the reverse peer exchange is performed. @@ -63,7 +63,7 @@ impl PeerManager { ); let mut buf = [0u8; 17]; - match self.router.get_node_tun_address() { + match self.router.node_tun_addr() { IpAddr::V4(tun_addr) => { buf[0] = 0; buf[1..5].copy_from_slice(&tun_addr.octets()[..]); @@ -78,12 +78,12 @@ impl PeerManager { let peer_stream_ip = peer_addr.ip(); if let Ok(new_peer) = Peer::new( peer_stream_ip, - self.router.router_data_tx.clone(), - self.router.router_control_tx.clone(), + self.router.router_data_tx(), + self.router.router_control_tx(), peer_stream, received_overlay_ip, ) { - self.router.add_directly_connected_peer(new_peer); + self.router.add_peer_interface(new_peer); } } } @@ -120,7 +120,7 @@ impl PeerManager { let mut buf = [0u8; 17]; - match self.router.get_node_tun_address() { + match self.router.node_tun_addr() { IpAddr::V4(tun_addr) => { buf[0] = 0; buf[1..5].copy_from_slice(&tun_addr.octets()[..]); @@ -136,12 +136,12 @@ impl PeerManager { let peer_stream_ip = peer_addr.ip(); if let Ok(new_peer) = Peer::new( peer_stream_ip, - self.router.router_data_tx.clone(), - self.router.router_control_tx.clone(), + self.router.router_data_tx(), + self.router.router_control_tx(), peer_stream, received_overlay_ip, ) { - self.router.add_directly_connected_peer(new_peer); + self.router.add_peer_interface(new_peer); } } } @@ -165,14 +165,14 @@ impl PeerManager { } } - async fn start_reverse_peer_exchange(mut stream: TcpStream, router: Arc) { + async fn start_reverse_peer_exchange(mut stream: TcpStream, router: Router) { // Steps: // 1. Send own TUN address over the stream // 2. Read other node's TUN address from the stream let mut buf = [0u8; 17]; - match router.get_node_tun_address() { + match router.node_tun_addr() { IpAddr::V4(tun_addr) => { buf[0] = 0; buf[1..5].copy_from_slice(&tun_addr.octets()[..]); @@ -203,14 +203,14 @@ impl PeerManager { let peer_stream_ip = stream.peer_addr().unwrap().ip(); let new_peer = Peer::new( peer_stream_ip, - router.router_data_tx.clone(), - router.router_control_tx.clone(), + router.router_data_tx(), + router.router_control_tx(), stream, received_overlay_ip, ); match new_peer { Ok(new_peer) => { - router.add_directly_connected_peer(new_peer); + router.add_peer_interface(new_peer); } Err(e) => { eprintln!("Error creating peer: {}", e); diff --git a/src/router.rs b/src/router.rs index ba0fdde..b88765d 100644 --- a/src/router.rs +++ b/src/router.rs @@ -1,18 +1,15 @@ use crate::{ - packet::{ - BabelPacketBody, BabelPacketHeader, BabelTLV, BabelTLVType, ControlPacket, ControlStruct, - DataPacket, - }, + packet::{BabelTLV, BabelTLVType, ControlPacket, ControlStruct, DataPacket}, peer::Peer, - routing_table::{self, RouteEntry, RouteKey, RoutingTable}, - source_table::{self, FeasibilityDistance, SourceKey, SourceTable}, - timers::{self, Timer}, + routing_table::{RouteEntry, RouteKey, RoutingTable}, + source_table::{FeasibilityDistance, SourceKey, SourceTable}, }; use rand::Rng; use std::{ - collections::HashMap, - net::{IpAddr, Ipv4Addr}, - sync::{Arc, Mutex}, + error::Error, + fmt::Debug, + net::IpAddr, + sync::{Arc, RwLock}, }; use tokio::sync::mpsc::{self, UnboundedReceiver, UnboundedSender}; use tokio_tun::Tun; @@ -40,440 +37,118 @@ impl StaticRoute { #[derive(Clone)] pub struct Router { - pub router_id: u64, - // The peer interfaces are the known neighbors of this node - peer_interfaces: Arc>>, - pub router_control_tx: UnboundedSender, - pub router_data_tx: UnboundedSender, - pub node_tun: Arc, - pub routing_table: Arc>, - pub source_table: Arc>, - pub router_seqno: u16, - static_routes: Arc>>, + inner: Arc>, } impl Router { - pub fn new(node_tun: Arc, static_routes: Vec) -> Self { + pub fn new( + node_tun: Arc, + static_routes: Vec, + ) -> Result> { // Tx is passed onto each new peer instance. This enables peers to send control packets to the router. let (router_control_tx, router_control_rx) = mpsc::unbounded_channel::(); // Tx is passed onto each new peer instance. This enables peers to send data packets to the router. let (router_data_tx, router_data_rx) = mpsc::unbounded_channel::(); let router = Router { - router_id: rand::thread_rng().gen(), - peer_interfaces: Arc::new(Mutex::new(Vec::new())), - router_control_tx, - router_data_tx: router_data_tx.clone(), - node_tun, - routing_table: Arc::new(Mutex::new(RoutingTable::new())), - source_table: Arc::new(Mutex::new(SourceTable::new())), - router_seqno: 0, - static_routes: Arc::new(Mutex::new(static_routes)), + inner: Arc::new(RwLock::new(RouterInner::new( + node_tun, + static_routes, + router_data_tx, + router_control_tx, + )?)), }; + tokio::spawn(Router::start_periodic_hello_sender(router.clone())); tokio::spawn(Router::handle_incoming_control_packet( router.clone(), router_control_rx, )); - tokio::spawn(Router::handle_incoming_data_packets( + tokio::spawn(Router::handle_incoming_data_packet( router.clone(), router_data_rx, - router_data_tx.clone(), )); - tokio::spawn(Router::start_periodic_hello_sender(router.clone())); - - // 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 + Ok(router) } - async fn handle_incoming_control_packet( - self, - mut router_control_rx: UnboundedReceiver, - ) { - loop { - while let Some(control_struct) = router_control_rx.recv().await { - match control_struct.control_packet.body.tlv_type { - BabelTLVType::AckReq => todo!(), - 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 => { - 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!(), - } - } - } + // pub fn source_table(&self) -> SourceTable { + // self.inner.read().unwrap().source_table + // } + + // pub fn routing_table(&self) -> RoutingTable { + // self.inner.read().unwrap().routing_table + // } + + pub fn router_id(&self) -> u64 { + self.inner.read().unwrap().router_id } - async fn handle_incoming_data_packets( - self, - mut router_data_rx: UnboundedReceiver, - router_data_tx: UnboundedSender, - ) { - // If the destination IP of the data packet matches with the IP address of this node's TUN interface - // we should forward the data packet towards the TUN interface. - // If the destination IP doesn't match, we need to lookup if we have a matching peer instance - // where the destination IP matches with the peer's overlay IP. If we do, we should forward the - // data packet to the peer's to_peer_data channel. - - let tun_addr = self.node_tun.address().unwrap(); - loop { - while let Some(data_packet) = router_data_rx.recv().await { - let dest_ip = data_packet.dest_ip; - println!( - "Received data packet with destination: {}", - data_packet.dest_ip - ); - - if dest_ip == tun_addr { - match self.node_tun.send(&data_packet.raw_data).await { - Ok(_) => {} - Err(e) => eprintln!("Error sending data packet to TUN interface: {:?}", e), - } - } else { - // router_data_tx.send(data_packet).unwrap(); - // DO BABEL route selection - // kijke nr next-hop en gwn sturenn naar de peer die daarmee overeenkomt - - // select the best route towards the destination - let best_route = self.select_best_route(IpAddr::V4(dest_ip)); - - // get the peer corresponding to the best the best route - let peer = self.get_peer_by_ip(best_route.unwrap().next_hop).unwrap(); - if let Err(e) = peer.send_data_packet(data_packet) { - eprintln!("Error sending data packet to peer: {:?}", e); - } - } - } - } + pub fn router_control_tx(&self) -> UnboundedSender { + self.inner.read().unwrap().router_control_tx.clone() } - async fn start_periodic_hello_sender(self) { - loop { - tokio::time::sleep(tokio::time::Duration::from_secs(HELLO_INTERVAL as u64)).await; - for peer in self.peer_interfaces.lock().unwrap().iter_mut() { - // create a new hello packet for this peer - let hello = ControlPacket::new_hello(peer, HELLO_INTERVAL); - // set the last hello timestamp for this peer - peer.set_time_last_received_hello(tokio::time::Instant::now()); - // send the hello packet to the peer - println!("Sending hello to peer: {:?}", peer.overlay_ip()); - if let Err(error) = peer.send_control_packet(hello) { - eprintln!("Error sending hello to peer: {}", error); - } - } - } + pub fn router_data_tx(&self) -> UnboundedSender { + self.inner.read().unwrap().router_data_tx.clone() } - fn handle_incoming_hello(control_struct: ControlStruct) { - let destination_ip = control_struct.src_overlay_ip; - control_struct.reply(ControlPacket::new_ihu(IHU_INTERVAL, destination_ip)); + pub fn node_tun_addr(&self) -> IpAddr { + IpAddr::V4(self.inner.read().unwrap().node_tun.address().unwrap()) } - fn handle_incoming_ihu(&self, control_struct: ControlStruct) { - let mut source_peer = self.get_source_peer_from_control_struct(control_struct); - // reset the IHU timer associated with the peer - source_peer.reset_ihu_timer(tokio::time::Duration::from_secs(IHU_INTERVAL as u64)); - // measure time between Hello and and IHU and set the link cost - let time_diff = tokio::time::Instant::now() - .duration_since(source_peer.time_last_received_hello()) - .as_millis(); - - source_peer.set_link_cost(time_diff as u16); - println!( - "Link cost for peer {:?} set to {}", - source_peer.overlay_ip(), - source_peer.link_cost() - ); - - println!("IHU timer for peer {:?} reset", source_peer.overlay_ip()); + pub fn node_tun(&self) -> Arc { + self.inner.read().unwrap().node_tun.clone() } - fn handle_incoming_update( - router: Router, - source_table: &mut SourceTable, - routing_table: &mut RoutingTable, - update: ControlStruct, - ) { - if source_table.is_feasible(&update) { - println!("incoming update is feasible"); - 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, - } => { - println!( - "Received update from {} for {:?} with seqno {} and metric {}", - router_id, prefix, seqno, metric - ); - let source_ip = update.src_overlay_ip; - - // get RouteEntry for the source of the update - let route_key = &RouteKey { - prefix, - plen, - neighbor: source_ip, - }; - if let Some(route_entry) = routing_table.clone().table.get_mut(route_key) { - let should_be_selected = Router::set_incoming_update_selected(routing_table, route_key.clone(), metric); - route_entry.update(update, should_be_selected); - } - else { - let source_key = SourceKey { - prefix, - plen, - router_id, - }; - let feas_dist = FeasibilityDistance(metric, seqno); - - // create the source table entry - source_table.insert(source_key.clone(), feas_dist); - - // now we can create the routing table entry - let route_key = RouteKey { - prefix, // prefix is peer that ANNOUNCED the route - plen, - neighbor: update.src_overlay_ip, - }; - - let peer = router.get_peer_by_ip(update.src_overlay_ip).unwrap(); - let mut route_entry = RouteEntry::new( - source_key, - peer.clone(), - metric, - seqno, - update.src_overlay_ip, - true, // for new entries the route is always selected - router, - ); - - - // create the routing table entry - routing_table.insert(route_key, route_entry); - } - } - _ => {} - } - } else { - println!("incoming update is NOT feasible"); - // received update is not feasible - // unselect to route if it was selected - } - } - - // this function shoud check if an incoming update should be selected or not - pub fn set_incoming_update_selected(routing_table: &mut RoutingTable, route_key: RouteKey, new_metric: u16) -> bool { - - // first check if the routing table has an entry for that key or not, if it has no entry return true - if !routing_table.table.contains_key(&route_key) { - println!("no entry for this route key, returning true"); - return true - } else { - let route_entry = routing_table.table.get_mut(&route_key).unwrap(); - println!("current metric: {}, new metric: {}", route_entry.metric, new_metric); - if route_entry.metric < new_metric { - return false - } - return true - } + pub fn router_seqno(&self) -> u16 { + self.inner.read().unwrap().router_seqno } - - pub fn add_directly_connected_peer(&self, peer: Peer) { - self.peer_interfaces.lock().unwrap().push(peer); + pub fn increment_router_seqno(&self) { + self.inner.write().unwrap().router_seqno += 1; } - pub fn get_node_tun_address(&self) -> IpAddr { - self.node_tun.address().unwrap().into() + pub fn peer_interfaces(&self) -> Vec { + self.inner.read().unwrap().peer_interfaces.clone() } - pub fn get_peer_interfaces(&self) -> Vec { - self.peer_interfaces.lock().unwrap().clone() + pub fn add_peer_interface(&self, peer: Peer) { + self.inner.write().unwrap().peer_interfaces.push(peer); } - pub fn get_peer_by_ip(&self, peer_ip: IpAddr) -> Option { - let peers = self.get_peer_interfaces(); + pub fn remove_peer_interface(&self, peer: Peer) { + let mut peer_interfaces = self.inner.write().unwrap().peer_interfaces.clone(); + peer_interfaces.retain(|p| p != &peer); + self.inner.write().unwrap().peer_interfaces = peer_interfaces; + } + + // pub fn static_routes(&self) -> Vec { + // self.inner.read().unwrap().static_routes.clone() + // } + + pub fn peer_by_ip(&self, peer_ip: IpAddr) -> Option { + let peers = self.peer_interfaces(); let matching_peer = peers.iter().find(|peer| peer.overlay_ip() == peer_ip); matching_peer.map(Clone::clone) } - fn get_source_peer_from_control_struct(&self, control_struct: ControlStruct) -> Peer { - let source = control_struct.src_overlay_ip; + pub fn source_peer_from_control_struct(&self, control_struct: ControlStruct) -> Option { + let peers = self.peer_interfaces(); + let matching_peer = peers + .iter() + .find(|peer| peer.overlay_ip() == control_struct.src_overlay_ip); - self.get_peer_by_ip(source).unwrap() - } - - pub fn print_routes(&self) { - let routing_table = self.routing_table.lock().unwrap(); - for route in routing_table.table.iter() { - println!("Route key: {:?}", route.0); - println!( - "Route: {:?}/{:?} (with next-hop: {:?}, metric: {}, selected: {})", - route.0.prefix, route.0.plen, route.1.next_hop, route.1.metric, route.1.selected - ); - println!("As advertised by: {:?}", route.1.source.router_id); - } - } - - // loop over the directly connected peers and create routing table entries for them - // 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(3)).await; - //for peer in self.peer_interfaces.lock().unwrap().iter_mut() { - //// we check for the u16::MAX - 1 value, as this is the value that the link cost is initialized to - ////if peer.link_cost() == u16::MAX - 1 { - //// before we can create a routing table entry, we need to create a source table entry - //let source_key = SourceKey { - //prefix: peer.overlay_ip(), - //plen: 32, // we set the prefix length to 32 for now, this means that each peer is a /32 network (so only route to the peer itself) - //router_id: 0, // we set all router ids to 0 temporarily - //}; - //let feas_dist = FeasibilityDistance(peer.link_cost(), 0); - - //// create the source table entry - //self.source_table - //.lock() - //.unwrap() - //.insert(source_key.clone(), feas_dist); - - //// now we can create the routing table entry - //let route_key = RouteKey { - //prefix: peer.overlay_ip(), - //plen: 32, // we set the prefix length to 32 for now, this means that each peer is a /32 network (so only route to the peer itself) - //neighbor: peer.overlay_ip(), - //}; - - //let seqno = if let Some(re) = self.routing_table.lock().unwrap().remove(&route_key) - //{ - //re.seqno - //} else { - //0 - //}; - //let route_entry = RouteEntry { - //source: source_key, - //neighbor: peer.clone(), - //metric: peer.link_cost(), - //seqno: seqno, // we set the seqno to 0 for now - //next_hop: peer.overlay_ip(), - //selected: true, // set selected always to true for now as we have manually decided the topology to only have p2p links - //}; - //// create the routing table entry - //self.routing_table - //.lock() - //.unwrap() - //.insert(route_key, route_entry); - ////} - //} - //} - //} - - // 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 async fn propagate_routes(self) { - loop { - // routes are propagated every 3 secs - tokio::time::sleep(tokio::time::Duration::from_secs(3)).await; - - let mut router_table = self.routing_table.lock().unwrap(); - let mut static_routes = self.static_routes.lock().unwrap(); - let peers = self.peer_interfaces.lock().unwrap(); - - for route in static_routes.iter_mut() { - route.seqno += 1; - for peer in peers.iter() { - let update = ControlPacket::new_update( - route.plen, - UPDATE_INTERVAL as u16, - route.seqno, - peer.link_cost(), - route.prefix, - self.router_id, - ); - - if peer.send_control_packet(update).is_err() { - println!("could not send static route to peer"); - } - } - } - - for (key, entry) in router_table.table.iter_mut() - .filter(|(key, _)| { // Filter out the static routes - for sr in static_routes.iter() { - if key.prefix == sr.prefix && key.plen == sr.plen { - return false; - } - } - true - }) { - entry.seqno += 1; - for peer in peers.iter() { - let link_cost = peer.link_cost(); - - - // DEBUG purposes - if entry.metric > u16::MAX - 1 - link_cost { - println!("SENDING UPDATE WITH METRIC: {}", u16::MAX - 1); - } else { - println!("SENDING UPDATE WITH METRIC: {}", entry.metric + link_cost); - } - - - - let update = ControlPacket::new_update( - key.plen, - UPDATE_INTERVAL as u16, - entry.seqno, - if entry.metric > u16::MAX - 1 - link_cost { - u16::MAX - 1 - } else { - entry.metric + link_cost - }, - key.prefix, - entry.source.router_id, - ); - - if peer.send_control_packet(update).is_err() { - println!("route update packet dropped"); - } - } - } - - - // FILTER VOOR SELECTED ROUTE NODIG --> we sturen nu alle routes maar eignelijk moeten we enkel de selected routes gaan propagaten - } + matching_peer.map(Clone::clone) } pub fn select_best_route(&self, dest_ip: IpAddr) -> Option { + + let inner = self.inner.read().unwrap(); + // first look in the routing table for all routekeys where prefix == dest_ip - let routing_table = self.routing_table.lock().unwrap(); + let routing_table = &inner.routing_table; let mut matching_routes: Vec<&RouteEntry> = Vec::new(); for route in routing_table.table.iter() { @@ -501,4 +176,318 @@ impl Router { None => None, } } + + pub fn add_static_route(&self, static_route: StaticRoute) { + let mut static_routes = self.inner.write().unwrap().static_routes.clone(); + static_routes.push(static_route); + self.inner.write().unwrap().static_routes = static_routes; + } + + pub fn print_routes(&self) { + + let inner = self.inner.read().unwrap(); + + let routing_table = &inner.routing_table; + for route in routing_table.table.iter() { + println!("Route key: {:?}", route.0); + println!( + "Route: {:?}/{:?} (with next-hop: {:?}, metric: {}, selected: {})", + route.0.prefix, route.0.plen, route.1.next_hop, route.1.metric, route.1.selected + ); + println!("As advertised by: {:?}", route.1.source.router_id); + } + } + + async fn handle_incoming_control_packet( + self, + mut router_control_rx: UnboundedReceiver, + ) { + while let Some(control_struct) = router_control_rx.recv().await { + match control_struct.control_packet.body.tlv_type { + BabelTLVType::AckReq => todo!(), + 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 => { + //let mut source_table = self.source_table(); + //let mut routing_table = self.routing_table.lock().unwrap(); + Self::handle_incoming_update(&self, control_struct); + } + BabelTLVType::RouteReq => todo!(), + BabelTLVType::SeqnoReq => todo!(), + } + } + } + + fn handle_incoming_hello(control_struct: ControlStruct) { + let destination_ip = control_struct.src_overlay_ip; + control_struct.reply(ControlPacket::new_ihu(IHU_INTERVAL, destination_ip)); + } + + fn handle_incoming_ihu(&self, control_struct: ControlStruct) { + if let Some(mut source_peer) = self.source_peer_from_control_struct(control_struct) { + // reset the IHU timer associated with the peer + source_peer.reset_ihu_timer(tokio::time::Duration::from_secs(IHU_INTERVAL as u64)); + // measure time between Hello and and IHU and set the link cost + let time_diff = tokio::time::Instant::now() + .duration_since(source_peer.time_last_received_hello()) + .as_millis(); + + source_peer.set_link_cost(time_diff as u16); + } + } + + fn handle_incoming_update(&self, update: ControlStruct) { + + let mut inner = self.inner.write().unwrap(); + + if inner.source_table.is_feasible(&update) { + println!("incoming update is feasible"); + inner.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, + } => { + println!( + "Received update from {} for {:?} with seqno {} and metric {}", + router_id, prefix, seqno, metric + ); + let source_ip = update.src_overlay_ip; + + // get RouteEntry for the source of the update + let route_key = &RouteKey { + prefix, + plen, + neighbor: source_ip, + }; + if let Some(route_entry) = inner.routing_table.clone().table.get_mut(route_key) + { + // let should_be_selected = Router::set_incoming_update_selected( + // routing_table, + // route_key.clone(), + // metric, + // ); + route_entry.update(update); + } else { + let source_key = SourceKey { + prefix, + plen, + router_id, + }; + let feas_dist = FeasibilityDistance(metric, seqno); + + // create the source table entry + inner.source_table.insert(source_key.clone(), feas_dist); + + // now we can create the routing table entry + let route_key = RouteKey { + prefix, // prefix is peer that ANNOUNCED the route + plen, + neighbor: update.src_overlay_ip, + }; + + let peer = self.peer_by_ip(update.src_overlay_ip).unwrap(); + let mut route_entry = RouteEntry::new( + source_key, + peer.clone(), + metric, + seqno, + update.src_overlay_ip, + true, // for new entries the route is always selected + ); + + // create the routing table entry + inner.routing_table.insert(route_key, route_entry); + } + } + _ => {} + } + } else { + println!("incoming update is NOT feasible"); + // received update is not feasible + // unselect to route if it was selected + } + } + + // fn set_incoming_update_selected( + // routing_table: &mut RoutingTable, + // route_key: RouteKey, + // new_metric: u16, + // ) -> bool { + // // first check if the routing table has an entry for that key or not, if it has no entry return true + // if !routing_table.table.contains_key(&route_key) { + // println!("no entry for this route key, returning true"); + // return true; + // } else { + // let route_entry = routing_table.table.get_mut(&route_key).unwrap(); + // println!( + // "current metric: {}, new metric: {}", + // route_entry.metric, new_metric + // ); + // if route_entry.metric < new_metric { + // return false; + // } + // return true; + // } + // } + + async fn handle_incoming_data_packet(self, mut router_data_rx: UnboundedReceiver) { + // If destination IP of packet is same as TUN interface IP, send to TUN interface + // If destination IP of packet is not same as TUN interface IP, send to peer with matching overlay IP + let node_tun_addr = self.node_tun_addr(); + loop { + while let Some(data_packet) = router_data_rx.recv().await { + match data_packet.dest_ip { + x if x == node_tun_addr => { + match self.node_tun().send(&data_packet.raw_data).await { + Ok(_) => {} + Err(e) => { + eprintln!("Error sending data packet to TUN interface: {:?}", e) + } + } + } + _ => { + let best_route = self.select_best_route(IpAddr::V4(data_packet.dest_ip)); + let peer = self.peer_by_ip(best_route.unwrap().next_hop).unwrap(); + if let Err(e) = peer.send_data_packet(data_packet) { + eprintln!("Error sending data packet to peer: {:?}", e); + } + } + } + } + } + } + + // 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 async fn propagate_routes(self) { + + + loop { + // routes are propagated every 3 secs + tokio::time::sleep(tokio::time::Duration::from_secs(3)).await; + + let mut inner = self.inner.write().unwrap(); + + let peers = inner.peer_interfaces.clone(); + for route in inner.static_routes.iter_mut() { + route.seqno += 1; + for peer in peers.iter() { + let update = ControlPacket::new_update( + route.plen, + UPDATE_INTERVAL as u16, + route.seqno, + peer.link_cost(), + route.prefix, + self.router_id(), + ); + + if peer.send_control_packet(update).is_err() { + println!("could not send static route to peer"); + } + } + } + + let static_routes = inner.static_routes.clone(); + for (key, entry) in inner.routing_table.table.iter_mut().filter(|(key, _)| { + // Filter out the static routes + for sr in static_routes.iter() { + if key.prefix == sr.prefix && key.plen == sr.plen { + return false; + } + } + true + }) { + entry.seqno += 1; + for peer in peers.iter() { + let link_cost = peer.link_cost(); + + // DEBUG purposes + if entry.metric > u16::MAX - 1 - link_cost { + println!("SENDING UPDATE WITH METRIC: {}", u16::MAX - 1); + } else { + println!("SENDING UPDATE WITH METRIC: {}", entry.metric + link_cost); + } + + let update = ControlPacket::new_update( + key.plen, + UPDATE_INTERVAL as u16, + entry.seqno, + if entry.metric > u16::MAX - 1 - link_cost { + u16::MAX - 1 + } else { + entry.metric + link_cost + }, + key.prefix, + entry.source.router_id, + ); + + if peer.send_control_packet(update).is_err() { + println!("route update packet dropped"); + } + } + } + + // FILTER VOOR SELECTED ROUTE NODIG --> we sturen nu alle routes maar eignelijk moeten we enkel de selected routes gaan propagaten + } + } + + async fn start_periodic_hello_sender(self) { + loop { + tokio::time::sleep(tokio::time::Duration::from_secs(HELLO_INTERVAL as u64)).await; + + for peer in self.peer_interfaces().iter_mut() { + let hello = ControlPacket::new_hello(peer, HELLO_INTERVAL); + peer.set_time_last_received_hello(tokio::time::Instant::now()); + + if let Err(error) = peer.send_control_packet(hello) { + eprintln!("Error sending hello to peer: {}", error); + } + } + } + } +} + +pub struct RouterInner { + pub router_id: u64, + peer_interfaces: Vec, + router_control_tx: UnboundedSender, + router_data_tx: UnboundedSender, + node_tun: Arc, + routing_table: RoutingTable, + source_table: SourceTable, + router_seqno: u16, + static_routes: Vec, +} + +impl RouterInner { + pub fn new( + node_tun: Arc, + static_routes: Vec, + router_data_tx: UnboundedSender, + router_control_tx: UnboundedSender, + ) -> Result> { + let router_inner = RouterInner { + router_id: rand::thread_rng().gen(), + peer_interfaces: Vec::new(), + router_control_tx, + router_data_tx, + node_tun: node_tun, + routing_table: RoutingTable::new(), + source_table: SourceTable::new(), + router_seqno: 0, + static_routes: static_routes, + }; + + Ok(router_inner) + } } diff --git a/src/routing_table.rs b/src/routing_table.rs index becc0c3..028e6e5 100644 --- a/src/routing_table.rs +++ b/src/routing_table.rs @@ -34,7 +34,6 @@ impl RouteEntry { seqno: u16, next_hop: IpAddr, selected: bool, - router: Router, ) -> Self { Self { source, @@ -46,13 +45,12 @@ impl RouteEntry { } } - pub fn update(&mut self, update: ControlStruct, should_be_selected: bool) { + pub fn update(&mut self, update: ControlStruct) { // the update is assumed to be feasible here match update.control_packet.body.tlv { BabelTLV::Update { seqno, metric, .. } => { self.metric = metric; self.seqno = seqno; - self.selected = should_be_selected; } _ => { panic!("Received update with invalid TLV"); diff --git a/src/source_table.rs b/src/source_table.rs index 03f7455..29e9fc7 100644 --- a/src/source_table.rs +++ b/src/source_table.rs @@ -13,6 +13,8 @@ pub struct SourceKey { pub struct FeasibilityDistance(pub u16, pub u16); // (metric, seqno) // Store (prefix, plen, router_id) -> feasibility distance mapping + +#[derive(Debug)] pub struct SourceTable { pub table: HashMap, } From 7f140094be3f7d60d1cb910a1f11647320a861a1 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Mon, 15 May 2023 16:05:49 +0000 Subject: [PATCH 67/89] resolved deadlock issue --- src/router.rs | 39 ++++++++++++++++----------------------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/src/router.rs b/src/router.rs index b88765d..6d515be 100644 --- a/src/router.rs +++ b/src/router.rs @@ -73,14 +73,6 @@ impl Router { Ok(router) } - // pub fn source_table(&self) -> SourceTable { - // self.inner.read().unwrap().source_table - // } - - // pub fn routing_table(&self) -> RoutingTable { - // self.inner.read().unwrap().routing_table - // } - pub fn router_id(&self) -> u64 { self.inner.read().unwrap().router_id } @@ -128,10 +120,7 @@ impl Router { // } pub fn peer_by_ip(&self, peer_ip: IpAddr) -> Option { - let peers = self.peer_interfaces(); - let matching_peer = peers.iter().find(|peer| peer.overlay_ip() == peer_ip); - - matching_peer.map(Clone::clone) + self.inner.read().unwrap().peer_by_ip(peer_ip) } pub fn source_peer_from_control_struct(&self, control_struct: ControlStruct) -> Option { @@ -177,11 +166,7 @@ impl Router { } } - pub fn add_static_route(&self, static_route: StaticRoute) { - let mut static_routes = self.inner.write().unwrap().static_routes.clone(); - static_routes.push(static_route); - self.inner.write().unwrap().static_routes = static_routes; - } + pub fn print_routes(&self) { @@ -226,7 +211,7 @@ impl Router { } fn handle_incoming_ihu(&self, control_struct: ControlStruct) { - if let Some(mut source_peer) = self.source_peer_from_control_struct(control_struct) { + if let Some(source_peer) = self.source_peer_from_control_struct(control_struct) { // reset the IHU timer associated with the peer source_peer.reset_ihu_timer(tokio::time::Duration::from_secs(IHU_INTERVAL as u64)); // measure time between Hello and and IHU and set the link cost @@ -294,8 +279,8 @@ impl Router { neighbor: update.src_overlay_ip, }; - let peer = self.peer_by_ip(update.src_overlay_ip).unwrap(); - let mut route_entry = RouteEntry::new( + let peer = inner.peer_by_ip(update.src_overlay_ip).unwrap(); + let route_entry = RouteEntry::new( source_key, peer.clone(), metric, @@ -342,12 +327,13 @@ impl Router { async fn handle_incoming_data_packet(self, mut router_data_rx: UnboundedReceiver) { // If destination IP of packet is same as TUN interface IP, send to TUN interface // If destination IP of packet is not same as TUN interface IP, send to peer with matching overlay IP - let node_tun_addr = self.node_tun_addr(); + let node_tun = self.node_tun(); + let node_tun_addr = node_tun.address().unwrap(); loop { while let Some(data_packet) = router_data_rx.recv().await { match data_packet.dest_ip { x if x == node_tun_addr => { - match self.node_tun().send(&data_packet.raw_data).await { + match node_tun.send(&data_packet.raw_data).await { Ok(_) => {} Err(e) => { eprintln!("Error sending data packet to TUN interface: {:?}", e) @@ -378,6 +364,7 @@ impl Router { let mut inner = self.inner.write().unwrap(); + let router_id = inner.router_id; let peers = inner.peer_interfaces.clone(); for route in inner.static_routes.iter_mut() { route.seqno += 1; @@ -388,7 +375,7 @@ impl Router { route.seqno, peer.link_cost(), route.prefix, - self.router_id(), + router_id, ); if peer.send_control_packet(update).is_err() { @@ -490,4 +477,10 @@ impl RouterInner { Ok(router_inner) } + + fn peer_by_ip(&self, peer_ip: IpAddr) -> Option { + let matching_peer = self.peer_interfaces.iter().find(|peer| peer.overlay_ip() == peer_ip); + + matching_peer.map(Clone::clone) + } } From aef2c24d9e0212de77788315e37262fa8e65ec1b Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Tue, 16 May 2023 15:21:19 +0000 Subject: [PATCH 68/89] route acquisition update --- src/main.rs | 10 +- src/peer.rs | 9 +- src/router.rs | 600 +++++++++++++++++++++++++++++-------------- src/routing_table.rs | 45 ++-- src/source_table.rs | 147 ++++++----- 5 files changed, 522 insertions(+), 289 deletions(-) diff --git a/src/main.rs b/src/main.rs index 360f8b1..4df3885 100644 --- a/src/main.rs +++ b/src/main.rs @@ -54,7 +54,7 @@ async fn main() -> Result<(), Box> { // Creating a new Router instance let router = match router::Router::new(node_tun.clone(), vec![StaticRoute::new(cli.tun_addr.into())]) { Ok(router) => { - println!("Router created"); + println!("Router created. ID: {}", router.router_id()); router } Err(e) => { @@ -125,8 +125,8 @@ async fn main() -> Result<(), Box> { Ok(_) => { // Remove trailing newline line.pop(); - println!("----------- Current routes -----------{}\n", line); - router.print_routes(); + println!("----------- Current selected routes -----------{}\n", line); + router.print_selected_routes(); println!("\n----------- Current peers: -----------"); for p in router.peer_interfaces() { @@ -137,6 +137,10 @@ async fn main() -> Result<(), Box> { ); } + + println!("\n----------- Current source table: -----------"); + router.print_source_table(); + println!("\n\n"); } Err(e) => { diff --git a/src/peer.rs b/src/peer.rs index 24a380f..19d2a90 100644 --- a/src/peer.rs +++ b/src/peer.rs @@ -7,7 +7,7 @@ use std::{ use tokio::{net::TcpStream, select, sync::mpsc}; use tokio_util::codec::Framed; -use crate::{codec::PacketCodec, packet::Packet}; +use crate::{codec::PacketCodec, packet::{Packet, BabelTLV}}; use crate::{ packet::{ControlPacket, ControlStruct, DataPacket}, timers::Timer, @@ -46,13 +46,7 @@ impl Peer { /// Adds 1 to the sequence number of this peer . pub fn increment_hello_seqno(&self) { - println!("current seqno: {}", self.inner.read().unwrap().hello_seqno); - // TODO: Validate this works self.inner.write().unwrap().hello_seqno += 1; - println!( - "after increment seqno: {}", - self.inner.read().unwrap().hello_seqno - ); } pub fn time_last_received_hello(&self) -> tokio::time::Instant { @@ -85,6 +79,7 @@ impl Peer { /// It's send over the to_peer_control channel and read from the corresponding receiver. /// The receiver sends the packet over the TCP stream towards the destined peer instance on another node pub fn send_control_packet(&self, control_packet: ControlPacket) -> Result<(), Box> { + Ok(self .inner .write() diff --git a/src/router.rs b/src/router.rs index 6d515be..42b8d16 100644 --- a/src/router.rs +++ b/src/router.rs @@ -2,7 +2,7 @@ use crate::{ packet::{BabelTLV, BabelTLVType, ControlPacket, ControlStruct, DataPacket}, peer::Peer, routing_table::{RouteEntry, RouteKey, RoutingTable}, - source_table::{FeasibilityDistance, SourceKey, SourceTable}, + source_table::{self, FeasibilityDistance, SourceKey, SourceTable}, }; use rand::Rng; use std::{ @@ -68,7 +68,8 @@ impl Router { router.clone(), router_data_rx, )); - tokio::spawn(Router::propagate_routes(router.clone())); + tokio::spawn(Router::propagate_static_route(router.clone())); + //tokio::spawn(Router::propagate_routes(router.clone())); Ok(router) } @@ -115,9 +116,9 @@ impl Router { self.inner.write().unwrap().peer_interfaces = peer_interfaces; } - // pub fn static_routes(&self) -> Vec { - // self.inner.read().unwrap().static_routes.clone() - // } + pub fn static_routes(&self) -> Vec { + self.inner.read().unwrap().static_routes.clone() + } pub fn peer_by_ip(&self, peer_ip: IpAddr) -> Option { self.inner.read().unwrap().peer_by_ip(peer_ip) @@ -132,47 +133,44 @@ impl Router { matching_peer.map(Clone::clone) } - pub fn select_best_route(&self, dest_ip: IpAddr) -> Option { + // pub fn select_best_route(&self, dest_ip: IpAddr) -> Option { + // let inner = self.inner.read().unwrap(); + + // // first look in the routing table for all routekeys where prefix == dest_ip + // let routing_table = &inner.routing_table; + // let mut matching_routes: Vec<&RouteEntry> = Vec::new(); + + // for route in routing_table.table.iter() { + // if route.0.prefix == dest_ip { + // // NOTE -- this is not correct, we need to check if the dest_ip is in the prefix range + // matching_routes.push(route.1); + // println!("Found matching route with next-hop: {:?}", route.1.next_hop); + // } + // } + + // // now we have all routes that match the destination ip + // // we need to select the route with the lowest metric + // let mut best_route: Option<&RouteEntry> = None; + // let mut best_metric: u16 = u16::MAX; + + // for route in matching_routes.iter() { + // if route.metric < best_metric { + // best_route = Some(route); + // best_metric = route.metric; + // } + // } + + // match best_route { + // Some(route) => Some(route.clone()), + // None => None, + // } + // } + + pub fn print_selected_routes(&self) { let inner = self.inner.read().unwrap(); - // first look in the routing table for all routekeys where prefix == dest_ip - let routing_table = &inner.routing_table; - let mut matching_routes: Vec<&RouteEntry> = Vec::new(); - - for route in routing_table.table.iter() { - if route.0.prefix == dest_ip { - // NOTE -- this is not correct, we need to check if the dest_ip is in the prefix range - matching_routes.push(route.1); - println!("Found matching route with next-hop: {:?}", route.1.next_hop); - } - } - - // now we have all routes that match the destination ip - // we need to select the route with the lowest metric - let mut best_route: Option<&RouteEntry> = None; - let mut best_metric: u16 = u16::MAX; - - for route in matching_routes.iter() { - if route.metric < best_metric { - best_route = Some(route); - best_metric = route.metric; - } - } - - match best_route { - Some(route) => Some(route.clone()), - None => None, - } - } - - - - pub fn print_routes(&self) { - - let inner = self.inner.read().unwrap(); - - let routing_table = &inner.routing_table; + let routing_table = &inner.selected_routing_table; for route in routing_table.table.iter() { println!("Route key: {:?}", route.0); println!( @@ -183,6 +181,17 @@ impl Router { } } + pub fn print_source_table(&self) { + let inner = self.inner.read().unwrap(); + + let source_table = &inner.source_table; + for (sk, se) in source_table.table.iter() { + println!("Source key: {:?}", sk); + println!("Source entry: {:?}", se); + println!("\n"); + } + } + async fn handle_incoming_control_packet( self, mut router_control_rx: UnboundedReceiver, @@ -194,11 +203,7 @@ impl Router { BabelTLVType::Hello => Self::handle_incoming_hello(control_struct), BabelTLVType::IHU => Self::handle_incoming_ihu(&self, control_struct), BabelTLVType::NextHop => todo!(), - BabelTLVType::Update => { - //let mut source_table = self.source_table(); - //let mut routing_table = self.routing_table.lock().unwrap(); - Self::handle_incoming_update(&self, control_struct); - } + BabelTLVType::Update => Self::handle_incoming_update(&self, control_struct), BabelTLVType::RouteReq => todo!(), BabelTLVType::SeqnoReq => todo!(), } @@ -223,85 +228,217 @@ impl Router { } } + // incoming update can only be received by a Peer this node has a direct link to fn handle_incoming_update(&self, update: ControlStruct) { - - let mut inner = self.inner.write().unwrap(); - if inner.source_table.is_feasible(&update) { - println!("incoming update is feasible"); - inner.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, + match update.control_packet.body.tlv { + BabelTLV::Update { plen, interval: _, seqno, metric, prefix, router_id } => { + + // create route key from incoming update control struct + // we need the address of the neighbour; this corresponds to the source ip of the control struct as the update is received from the neighbouring peer + let neighbor_ip = update.src_overlay_ip; + let route_key_from_update = RouteKey { + neighbor: neighbor_ip, + plen, prefix, - router_id, - } => { - println!( - "Received update from {} for {:?} with seqno {} and metric {}", - router_id, prefix, seqno, metric - ); - let source_ip = update.src_overlay_ip; + }; - // get RouteEntry for the source of the update - let route_key = &RouteKey { - prefix, - plen, - neighbor: source_ip, - }; - if let Some(route_entry) = inner.routing_table.clone().table.get_mut(route_key) - { - // let should_be_selected = Router::set_incoming_update_selected( - // routing_table, - // route_key.clone(), - // metric, - // ); - route_entry.update(update); - } else { - let source_key = SourceKey { - prefix, - plen, - router_id, - }; - let feas_dist = FeasibilityDistance(metric, seqno); + let inner = self.inner.read().unwrap(); + let source_table = &inner.source_table; + let fallback_routing_table = &inner.fallback_routing_table; + let selected_routing_table = &inner.selected_routing_table; - // create the source table entry - inner.source_table.insert(source_key.clone(), feas_dist); - - // now we can create the routing table entry - let route_key = RouteKey { - prefix, // prefix is peer that ANNOUNCED the route - plen, - neighbor: update.src_overlay_ip, - }; - - let peer = inner.peer_by_ip(update.src_overlay_ip).unwrap(); - let route_entry = RouteEntry::new( - source_key, - peer.clone(), - metric, - seqno, - update.src_overlay_ip, - true, // for new entries the route is always selected - ); - - // create the routing table entry - inner.routing_table.insert(route_key, route_entry); + // check if a route entry with the same route key exists in both routing tables + let mut route_entry_exists = false; + for (route_key, _) in selected_routing_table + .table + .iter() + .zip(fallback_routing_table.table.iter()) + { + if route_key.0 == &route_key_from_update { + route_entry_exists = true; } } - _ => {} + + let mut inner = self.inner.write().unwrap(); + let selected_routing_table = &mut inner.selected_routing_table; + + // if no entry exists + if !route_entry_exists { + // if the update is unfeasible, or the metric is inifinite, we ignore the update + if metric == u16::MAX || !self.update_feasible(&update, &source_table) { + return; + } + else { + // this means that the update is feasible and the metric is not infinite + // create a new route entry and add it to the routing table + let route_key = RouteKey { + prefix, + plen, + neighbor: neighbor_ip, + }; + let route_entry = RouteEntry { + source: SourceKey { prefix, plen, router_id }, // CHECK IF THIS MEANS WE ALSO NEED TO CREATE A NEW SOURCE ENTRY + neighbor: self.peer_by_ip(neighbor_ip).unwrap(), + metric, + seqno, + next_hop: neighbor_ip, // CHECK IF THIS IS CORRECT!!! + selected: true, + }; + // if no entry exists, it should be added to the selected routing table as new entries are always selected + selected_routing_table.table.insert(route_key, route_entry); + + } + } + // entry exists + else { + // if the entry is currently selected, the update is unfeasible, and the router-id of the update is equal + // to the router-id of the entry, then we ignore the update + if inner.selected_routing_table.table.contains_key(&route_key_from_update) { + let route_entry = inner.selected_routing_table.table.get(&route_key_from_update).unwrap(); + if !self.update_feasible(&update, &source_table) && route_entry.source.router_id == router_id { + return; + } + } + // otherwise + else { + let route_entry = inner.fallback_routing_table.table.get_mut(&route_key_from_update).unwrap(); + // update the entry's seqno, metric and router-id + route_entry.update_seqno(seqno); + route_entry.update_metric(metric); + route_entry.update_router_id(router_id); + + if !self.update_feasible(&update, &source_table) { + // if the update is unfeasible, we remove the entry from the selected routing table + inner.selected_routing_table.table.remove(&route_key_from_update); + // TODO: if the updated caused the router ID of the entry to change, we should also sent triggered update + } + } + } + // RUN ROUTE SELECTION + + }, + _ => { + panic!("Received update with wrong TLV type"); + } + } + + } + + // we gebruiken self niet in de functie --> daarop functie eigenllijk beter op de source table implementeren + fn update_feasible(&self, update: &ControlStruct, source_table: &SourceTable) -> bool { + // Before an update is accepted it should be checked against the feasbility condition + // If an entry in the source table with the same source key exists, we perform the feasbility check + // If no entry exists yet, the update is accepted as there is no better alternative available (yet) + match update.control_packet.body.tlv { + BabelTLV::Update { + plen, + interval: _, + seqno, + metric, + prefix, + router_id, + } => { + let source_key = SourceKey { + prefix, + plen, + router_id, + }; + match source_table.get(&source_key) { + Some(&entry) => { + return seqno > entry.seqno + || (seqno == entry.seqno && metric < entry.metric); + } + None => return true, + } + } + _ => { + eprintln!("Error accepting update, control struct did not match update packet"); + return false; } - } else { - println!("incoming update is NOT feasible"); - // received update is not feasible - // unselect to route if it was selected } } + // fn handle_incoming_update(&self, update: ControlStruct) { + + // let mut inner = self.inner.write().unwrap(); + + // if inner.source_table.is_feasible(&update) { + // println!("incoming update is feasible"); + // inner.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, + // } => { + // println!( + // "Received update from {} for {:?} with seqno {} and metric {}", + // router_id, prefix, seqno, metric + // ); + // let source_ip = update.src_overlay_ip; + + // // get RouteEntry for the source of the update + // let route_key = &RouteKey { + // prefix, + // plen, + // neighbor: source_ip, + // }; + // if let Some(route_entry) = inner.routing_table.clone().table.get_mut(route_key) + // { + // // let should_be_selected = Router::set_incoming_update_selected( + // // routing_table, + // // route_key.clone(), + // // metric, + // // ); + // route_entry.update(update); + // } else { + // let source_key = SourceKey { + // prefix, + // plen, + // router_id, + // }; + // let feas_dist = FeasibilityDistance(metric, seqno); + + // // create the source table entry + // inner.source_table.insert(source_key.clone(), feas_dist); + + // // now we can create the routing table entry + // let route_key = RouteKey { + // prefix, // prefix is peer that ANNOUNCED the route + // plen, + // neighbor: update.src_overlay_ip, + // }; + + // let peer = inner.peer_by_ip(update.src_overlay_ip).unwrap(); + // let route_entry = RouteEntry::new( + // source_key, + // peer.clone(), + // metric, + // seqno, + // update.src_overlay_ip, + // true, // for new entries the route is always selected + // ); + + // // create the routing table entry + // inner.routing_table.insert(route_key, route_entry); + // } + // } + // _ => {} + // } + // } else { + // println!("incoming update is NOT feasible"); + // // received update is not feasible + // // unselect to route if it was selected + // } + // } + // fn set_incoming_update_selected( // routing_table: &mut RoutingTable, // route_key: RouteKey, @@ -332,101 +469,98 @@ impl Router { loop { while let Some(data_packet) = router_data_rx.recv().await { match data_packet.dest_ip { - x if x == node_tun_addr => { - match node_tun.send(&data_packet.raw_data).await { - Ok(_) => {} - Err(e) => { - eprintln!("Error sending data packet to TUN interface: {:?}", e) - } + x if x == node_tun_addr => match node_tun.send(&data_packet.raw_data).await { + Ok(_) => {} + Err(e) => { + eprintln!("Error sending data packet to TUN interface: {:?}", e) } - } + }, _ => { - let best_route = self.select_best_route(IpAddr::V4(data_packet.dest_ip)); - let peer = self.peer_by_ip(best_route.unwrap().next_hop).unwrap(); - if let Err(e) = peer.send_data_packet(data_packet) { - eprintln!("Error sending data packet to peer: {:?}", e); - } + // let best_route = self.select_best_route(IpAddr::V4(data_packet.dest_ip)); + // let peer = self.peer_by_ip(best_route.unwrap().next_hop).unwrap(); + // if let Err(e) = peer.send_data_packet(data_packet) { + // eprintln!("Error sending data packet to peer: {:?}", e); + // } } } } } } + pub async fn propagate_static_route(self) { + loop { + tokio::time::sleep(tokio::time::Duration::from_secs(3)).await; + + let mut inner = self.inner.write().unwrap(); + inner.propagate_static_route(); + } + } + + pub async fn propagate_routes(self) { + loop { + tokio::time::sleep(tokio::time::Duration::from_secs(3)).await; + + let mut inner = self.inner.write().unwrap(); + inner.propagate_routes(); + } + } + // 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 async fn propagate_routes(self) { + // pub async fn propagate_selected_routes(self) { + // loop { + // tokio::time::sleep(tokio::time::Duration::from_secs(3)).await; - loop { - // routes are propagated every 3 secs - tokio::time::sleep(tokio::time::Duration::from_secs(3)).await; + // let mut inner = self.inner.write().unwrap(); - let mut inner = self.inner.write().unwrap(); + // let router_id = inner.router_id; + // let router_seqno = inner.router_seqno; - let router_id = inner.router_id; - let peers = inner.peer_interfaces.clone(); - for route in inner.static_routes.iter_mut() { - route.seqno += 1; - for peer in peers.iter() { - let update = ControlPacket::new_update( - route.plen, - UPDATE_INTERVAL as u16, - route.seqno, - peer.link_cost(), - route.prefix, - router_id, - ); + // let static_routes = inner.static_routes.clone(); + // for (key, entry) in inner.routing_table.table.iter_mut().filter(|(key, _)| { + // // Filter out the static routes + // for sr in static_routes.iter() { + // if key.prefix == sr.prefix && key.plen == sr.plen { + // return false; + // } + // } + // true + // }) { + // entry.seqno += 1; + // for peer in peers.iter() { + // let link_cost = peer.link_cost(); - if peer.send_control_packet(update).is_err() { - println!("could not send static route to peer"); - } - } - } + // // DEBUG purposes + // if entry.metric > u16::MAX - 1 - link_cost { + // println!("SENDING UPDATE WITH METRIC: {}", u16::MAX - 1); + // } else { + // println!("SENDING UPDATE WITH METRIC: {}", entry.metric + link_cost); + // } - let static_routes = inner.static_routes.clone(); - for (key, entry) in inner.routing_table.table.iter_mut().filter(|(key, _)| { - // Filter out the static routes - for sr in static_routes.iter() { - if key.prefix == sr.prefix && key.plen == sr.plen { - return false; - } - } - true - }) { - entry.seqno += 1; - for peer in peers.iter() { - let link_cost = peer.link_cost(); + // let update = ControlPacket::new_update( + // key.plen, + // UPDATE_INTERVAL as u16, + // entry.seqno, + // if entry.metric > u16::MAX - 1 - link_cost { + // u16::MAX - 1 + // } else { + // entry.metric + link_cost + // }, + // key.prefix, + // entry.source.router_id, + // ); - // DEBUG purposes - if entry.metric > u16::MAX - 1 - link_cost { - println!("SENDING UPDATE WITH METRIC: {}", u16::MAX - 1); - } else { - println!("SENDING UPDATE WITH METRIC: {}", entry.metric + link_cost); - } + // if peer.send_control_packet(update).is_err() { + // println!("route update packet dropped"); + // } + // } + // } - let update = ControlPacket::new_update( - key.plen, - UPDATE_INTERVAL as u16, - entry.seqno, - if entry.metric > u16::MAX - 1 - link_cost { - u16::MAX - 1 - } else { - entry.metric + link_cost - }, - key.prefix, - entry.source.router_id, - ); - - if peer.send_control_packet(update).is_err() { - println!("route update packet dropped"); - } - } - } - - // FILTER VOOR SELECTED ROUTE NODIG --> we sturen nu alle routes maar eignelijk moeten we enkel de selected routes gaan propagaten - } - } + // // FILTER VOOR SELECTED ROUTE NODIG --> we sturen nu alle routes maar eignelijk moeten we enkel de selected routes gaan propagaten + // } + // } async fn start_periodic_hello_sender(self) { loop { @@ -450,7 +584,8 @@ pub struct RouterInner { router_control_tx: UnboundedSender, router_data_tx: UnboundedSender, node_tun: Arc, - routing_table: RoutingTable, + selected_routing_table: RoutingTable, + fallback_routing_table: RoutingTable, source_table: SourceTable, router_seqno: u16, static_routes: Vec, @@ -469,7 +604,8 @@ impl RouterInner { router_control_tx, router_data_tx, node_tun: node_tun, - routing_table: RoutingTable::new(), + selected_routing_table: RoutingTable::new(), + fallback_routing_table: RoutingTable::new(), source_table: SourceTable::new(), router_seqno: 0, static_routes: static_routes, @@ -479,8 +615,84 @@ impl RouterInner { } fn peer_by_ip(&self, peer_ip: IpAddr) -> Option { - let matching_peer = self.peer_interfaces.iter().find(|peer| peer.overlay_ip() == peer_ip); + let matching_peer = self + .peer_interfaces + .iter() + .find(|peer| peer.overlay_ip() == peer_ip); matching_peer.map(Clone::clone) } + + fn send_update(&mut self, peer: &Peer, update: ControlPacket) { + // before sending an update, the source table might need to be updated + match update.body.tlv { + BabelTLV::Update { + plen, + interval: _, + seqno, + metric, + prefix, + router_id, + } => { + let source_key = SourceKey { + prefix, + plen, + router_id, + }; + + if let Some(source_entry) = self.source_table.get(&source_key) { + // if seqno of the update is greater than the seqno in the source table, update the source table + if seqno > source_entry.metric { + self.source_table + .insert(source_key, FeasibilityDistance::new(metric, seqno)); + } + // if seqno of the update is equal to the seqno in the source table, update the source table if the metric (of the update) is lower + else if seqno == source_entry.seqno && source_entry.metric > metric { + self.source_table.insert( + source_key, + FeasibilityDistance::new(metric, source_entry.seqno), + ); + } + } + // no entry for this source key, so insert it + else { + self.source_table + .insert(source_key, FeasibilityDistance::new(metric, seqno)); + } + + // send the update to the peer + if let Err(e) = peer.send_control_packet(update) { + println!("Error sending update to peer: {:?}", e); + } + } + _ => { + panic!("Control packet is not a correct Update packet"); + } + } + } + + fn propagate_static_route(&mut self) { + let mut updates = vec![]; + for sr in self.static_routes.iter() { + for peer in self.peer_interfaces.iter() { + let update = ControlPacket::new_update( + sr.plen, // static routes have plen 32 + UPDATE_INTERVAL as u16, + self.router_seqno, // updates receive the seqno of the router + peer.link_cost(), // direct connection to other peer, so the only cost is the cost towards the peer + sr.prefix, // the prefix of a static route corresponds to the TUN addr of the node + self.router_id, + ); + + println!("Propagting static route update: {:?}", update); + updates.push((peer.clone(), update)); + } + } + + for (peer, update) in updates { + self.send_update(&peer, update); + } + } + + fn propagate_routes(&self) {} } diff --git a/src/routing_table.rs b/src/routing_table.rs index 028e6e5..d69cf48 100644 --- a/src/routing_table.rs +++ b/src/routing_table.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, net::IpAddr}; +use std::{collections::{HashMap, BTreeMap}, net::IpAddr}; use crate::{ packet::{BabelTLV, ControlStruct}, @@ -8,13 +8,14 @@ use crate::{ timers::Timer, }; -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct RouteKey { pub prefix: IpAddr, pub plen: u8, pub neighbor: IpAddr, } + #[derive(Debug, Clone)] pub struct RouteEntry { pub source: SourceKey, @@ -45,18 +46,18 @@ impl RouteEntry { } } - pub fn update(&mut self, update: ControlStruct) { - // the update is assumed to be feasible here - match update.control_packet.body.tlv { - BabelTLV::Update { seqno, metric, .. } => { - self.metric = metric; - self.seqno = seqno; - } - _ => { - panic!("Received update with invalid TLV"); - } - } - } + // pub fn update(&mut self, update: ControlStruct) { + // // the update is assumed to be feasible here + // match update.control_packet.body.tlv { + // BabelTLV::Update { seqno, metric, .. } => { + // self.metric = metric; + // self.seqno = seqno; + // } + // _ => { + // panic!("Received update with invalid TLV"); + // } + // } + // } pub fn retracted(&mut self) { self.metric = 0xFFFF; @@ -65,17 +66,29 @@ impl RouteEntry { pub fn is_retracted(&self) -> bool { self.metric == 0xFFFF } + + pub fn update_metric(&mut self, metric: u16) { + self.metric = metric; + } + + pub fn update_seqno(&mut self, seqno: u16) { + self.seqno = seqno; + } + + pub fn update_router_id(&mut self, router_id: u64) { + self.source.router_id = router_id; + } } #[derive(Debug, Clone)] pub struct RoutingTable { - pub table: HashMap, + pub table: BTreeMap, } impl RoutingTable { pub fn new() -> Self { Self { - table: HashMap::new(), + table: BTreeMap::new(), } } diff --git a/src/source_table.rs b/src/source_table.rs index 29e9fc7..e1db0e2 100644 --- a/src/source_table.rs +++ b/src/source_table.rs @@ -10,7 +10,16 @@ pub struct SourceKey { } #[derive(Debug, Clone, Copy)] -pub struct FeasibilityDistance(pub u16, pub u16); // (metric, seqno) +pub struct FeasibilityDistance { + pub metric: u16, + pub seqno: u16, +} + +impl FeasibilityDistance { + pub fn new(metric: u16, seqno: u16) -> Self { + FeasibilityDistance { metric, seqno } + } +} // Store (prefix, plen, router_id) -> feasibility distance mapping @@ -38,77 +47,77 @@ impl SourceTable { 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; - } + // 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 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"); - } - } - } + // 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, - }; + // 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; + // match self.table.get(&key) { + // Some(&source_entry) => { + // let metric_2 = source_entry.0; + // let seqno_2 = source_entry.1; - seqno > seqno_2 || (seqno == seqno_2 && metric < metric_2) - } - None => true, - } - } - _ => { - panic!("not an update"); - } - } - } + // seqno > seqno_2 || (seqno == seqno_2 && metric < metric_2) + // } + // None => true, + // } + // } + // _ => { + // panic!("not an update"); + // } + // } + // } } From 223fe60a3a2787c10d50e2e0eeb04f0a540d3a70 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Tue, 16 May 2023 15:33:59 +0000 Subject: [PATCH 69/89] route acquisition update v2 --- src/router.rs | 141 ++++++-------------------------------------------- 1 file changed, 17 insertions(+), 124 deletions(-) diff --git a/src/router.rs b/src/router.rs index 42b8d16..b8de5af 100644 --- a/src/router.rs +++ b/src/router.rs @@ -133,37 +133,37 @@ impl Router { matching_peer.map(Clone::clone) } - // pub fn select_best_route(&self, dest_ip: IpAddr) -> Option { + // pub fn select_best_route(&self, dest_ip: ipaddr) -> option { // let inner = self.inner.read().unwrap(); // // first look in the routing table for all routekeys where prefix == dest_ip // let routing_table = &inner.routing_table; - // let mut matching_routes: Vec<&RouteEntry> = Vec::new(); + // let mut matching_routes: vec<&routeentry> = vec::new(); // for route in routing_table.table.iter() { // if route.0.prefix == dest_ip { - // // NOTE -- this is not correct, we need to check if the dest_ip is in the prefix range + // // note -- this is not correct, we need to check if the dest_ip is in the prefix range // matching_routes.push(route.1); - // println!("Found matching route with next-hop: {:?}", route.1.next_hop); + // println!("found matching route with next-hop: {:?}", route.1.next_hop); // } // } // // now we have all routes that match the destination ip // // we need to select the route with the lowest metric - // let mut best_route: Option<&RouteEntry> = None; - // let mut best_metric: u16 = u16::MAX; + // let mut best_route: option<&routeentry> = none; + // let mut best_metric: u16 = u16::max; // for route in matching_routes.iter() { // if route.metric < best_metric { - // best_route = Some(route); + // best_route = some(route); // best_metric = route.metric; // } // } // match best_route { - // Some(route) => Some(route.clone()), - // None => None, + // some(route) => some(route.clone()), + // none => none, // } // } @@ -230,7 +230,7 @@ impl Router { // incoming update can only be received by a Peer this node has a direct link to fn handle_incoming_update(&self, update: ControlStruct) { - + println!("entering handle_incoming_update"); match update.control_packet.body.tlv { BabelTLV::Update { plen, interval: _, seqno, metric, prefix, router_id } => { @@ -244,30 +244,24 @@ impl Router { prefix, }; - let inner = self.inner.read().unwrap(); - let source_table = &inner.source_table; - let fallback_routing_table = &inner.fallback_routing_table; - let selected_routing_table = &inner.selected_routing_table; + let mut inner = self.inner.write().unwrap(); // check if a route entry with the same route key exists in both routing tables let mut route_entry_exists = false; - for (route_key, _) in selected_routing_table + for (route_key, _) in inner.selected_routing_table .table .iter() - .zip(fallback_routing_table.table.iter()) + .zip(inner.fallback_routing_table.table.iter()) { if route_key.0 == &route_key_from_update { route_entry_exists = true; } } - let mut inner = self.inner.write().unwrap(); - let selected_routing_table = &mut inner.selected_routing_table; - // if no entry exists if !route_entry_exists { // if the update is unfeasible, or the metric is inifinite, we ignore the update - if metric == u16::MAX || !self.update_feasible(&update, &source_table) { + if metric == u16::MAX || !self.update_feasible(&update, &inner.source_table) { return; } else { @@ -287,7 +281,7 @@ impl Router { selected: true, }; // if no entry exists, it should be added to the selected routing table as new entries are always selected - selected_routing_table.table.insert(route_key, route_entry); + inner.selected_routing_table.table.insert(route_key, route_entry); } } @@ -297,7 +291,7 @@ impl Router { // to the router-id of the entry, then we ignore the update if inner.selected_routing_table.table.contains_key(&route_key_from_update) { let route_entry = inner.selected_routing_table.table.get(&route_key_from_update).unwrap(); - if !self.update_feasible(&update, &source_table) && route_entry.source.router_id == router_id { + if !self.update_feasible(&update, &inner.source_table) && route_entry.source.router_id == router_id { return; } } @@ -309,7 +303,7 @@ impl Router { route_entry.update_metric(metric); route_entry.update_router_id(router_id); - if !self.update_feasible(&update, &source_table) { + if !self.update_feasible(&update, &inner.source_table) { // if the update is unfeasible, we remove the entry from the selected routing table inner.selected_routing_table.table.remove(&route_key_from_update); // TODO: if the updated caused the router ID of the entry to change, we should also sent triggered update @@ -360,107 +354,6 @@ impl Router { } } - // fn handle_incoming_update(&self, update: ControlStruct) { - - // let mut inner = self.inner.write().unwrap(); - - // if inner.source_table.is_feasible(&update) { - // println!("incoming update is feasible"); - // inner.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, - // } => { - // println!( - // "Received update from {} for {:?} with seqno {} and metric {}", - // router_id, prefix, seqno, metric - // ); - // let source_ip = update.src_overlay_ip; - - // // get RouteEntry for the source of the update - // let route_key = &RouteKey { - // prefix, - // plen, - // neighbor: source_ip, - // }; - // if let Some(route_entry) = inner.routing_table.clone().table.get_mut(route_key) - // { - // // let should_be_selected = Router::set_incoming_update_selected( - // // routing_table, - // // route_key.clone(), - // // metric, - // // ); - // route_entry.update(update); - // } else { - // let source_key = SourceKey { - // prefix, - // plen, - // router_id, - // }; - // let feas_dist = FeasibilityDistance(metric, seqno); - - // // create the source table entry - // inner.source_table.insert(source_key.clone(), feas_dist); - - // // now we can create the routing table entry - // let route_key = RouteKey { - // prefix, // prefix is peer that ANNOUNCED the route - // plen, - // neighbor: update.src_overlay_ip, - // }; - - // let peer = inner.peer_by_ip(update.src_overlay_ip).unwrap(); - // let route_entry = RouteEntry::new( - // source_key, - // peer.clone(), - // metric, - // seqno, - // update.src_overlay_ip, - // true, // for new entries the route is always selected - // ); - - // // create the routing table entry - // inner.routing_table.insert(route_key, route_entry); - // } - // } - // _ => {} - // } - // } else { - // println!("incoming update is NOT feasible"); - // // received update is not feasible - // // unselect to route if it was selected - // } - // } - - // fn set_incoming_update_selected( - // routing_table: &mut RoutingTable, - // route_key: RouteKey, - // new_metric: u16, - // ) -> bool { - // // first check if the routing table has an entry for that key or not, if it has no entry return true - // if !routing_table.table.contains_key(&route_key) { - // println!("no entry for this route key, returning true"); - // return true; - // } else { - // let route_entry = routing_table.table.get_mut(&route_key).unwrap(); - // println!( - // "current metric: {}, new metric: {}", - // route_entry.metric, new_metric - // ); - // if route_entry.metric < new_metric { - // return false; - // } - // return true; - // } - // } - async fn handle_incoming_data_packet(self, mut router_data_rx: UnboundedReceiver) { // If destination IP of packet is same as TUN interface IP, send to TUN interface // If destination IP of packet is not same as TUN interface IP, send to peer with matching overlay IP From 6305af275a73238fe78536528c4db9580e3ec223 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Tue, 16 May 2023 15:41:40 +0000 Subject: [PATCH 70/89] route acquisition update v3 --- src/router.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/router.rs b/src/router.rs index b8de5af..3ddc1af 100644 --- a/src/router.rs +++ b/src/router.rs @@ -274,7 +274,7 @@ impl Router { }; let route_entry = RouteEntry { source: SourceKey { prefix, plen, router_id }, // CHECK IF THIS MEANS WE ALSO NEED TO CREATE A NEW SOURCE ENTRY - neighbor: self.peer_by_ip(neighbor_ip).unwrap(), + neighbor: inner.peer_by_ip(neighbor_ip).unwrap(), metric, seqno, next_hop: neighbor_ip, // CHECK IF THIS IS CORRECT!!! From 2a2aa7e12d3318a42586e3332f2bd8516705b3f7 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Tue, 16 May 2023 15:54:19 +0000 Subject: [PATCH 71/89] added source entry if no route entry exists --- src/router.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/router.rs b/src/router.rs index 3ddc1af..059543f 100644 --- a/src/router.rs +++ b/src/router.rs @@ -266,14 +266,19 @@ impl Router { } else { // this means that the update is feasible and the metric is not infinite - // create a new route entry and add it to the routing table + // create a new route entry and add it to the routing table (which requires a new source entry to be created as well) + + let source_key = SourceKey { prefix, plen, router_id }; + let fd = FeasibilityDistance{ metric, seqno }; + inner.source_table.insert(source_key, fd); + let route_key = RouteKey { prefix, plen, neighbor: neighbor_ip, }; let route_entry = RouteEntry { - source: SourceKey { prefix, plen, router_id }, // CHECK IF THIS MEANS WE ALSO NEED TO CREATE A NEW SOURCE ENTRY + source: source_key, neighbor: inner.peer_by_ip(neighbor_ip).unwrap(), metric, seqno, From 30b8097859c7d97aeb618a941f40a6eef69d1edf Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Tue, 16 May 2023 16:16:19 +0000 Subject: [PATCH 72/89] propagate selected routes --- src/router.rs | 87 +++++++++++++++------------------------------------ 1 file changed, 26 insertions(+), 61 deletions(-) diff --git a/src/router.rs b/src/router.rs index 059543f..44b04b7 100644 --- a/src/router.rs +++ b/src/router.rs @@ -69,7 +69,7 @@ impl Router { router_data_rx, )); tokio::spawn(Router::propagate_static_route(router.clone())); - //tokio::spawn(Router::propagate_routes(router.clone())); + tokio::spawn(Router::propagate_selected_routes(router.clone())); Ok(router) } @@ -394,72 +394,15 @@ impl Router { } } - pub async fn propagate_routes(self) { + pub async fn propagate_selected_routes(self) { loop { tokio::time::sleep(tokio::time::Duration::from_secs(3)).await; let mut inner = self.inner.write().unwrap(); - inner.propagate_routes(); + inner.propagate_selected_routes(); } } - // 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 async fn propagate_selected_routes(self) { - - // loop { - // tokio::time::sleep(tokio::time::Duration::from_secs(3)).await; - - // let mut inner = self.inner.write().unwrap(); - - // let router_id = inner.router_id; - // let router_seqno = inner.router_seqno; - - // let static_routes = inner.static_routes.clone(); - // for (key, entry) in inner.routing_table.table.iter_mut().filter(|(key, _)| { - // // Filter out the static routes - // for sr in static_routes.iter() { - // if key.prefix == sr.prefix && key.plen == sr.plen { - // return false; - // } - // } - // true - // }) { - // entry.seqno += 1; - // for peer in peers.iter() { - // let link_cost = peer.link_cost(); - - // // DEBUG purposes - // if entry.metric > u16::MAX - 1 - link_cost { - // println!("SENDING UPDATE WITH METRIC: {}", u16::MAX - 1); - // } else { - // println!("SENDING UPDATE WITH METRIC: {}", entry.metric + link_cost); - // } - - // let update = ControlPacket::new_update( - // key.plen, - // UPDATE_INTERVAL as u16, - // entry.seqno, - // if entry.metric > u16::MAX - 1 - link_cost { - // u16::MAX - 1 - // } else { - // entry.metric + link_cost - // }, - // key.prefix, - // entry.source.router_id, - // ); - - // if peer.send_control_packet(update).is_err() { - // println!("route update packet dropped"); - // } - // } - // } - - // // FILTER VOOR SELECTED ROUTE NODIG --> we sturen nu alle routes maar eignelijk moeten we enkel de selected routes gaan propagaten - // } - // } - async fn start_periodic_hello_sender(self) { loop { tokio::time::sleep(tokio::time::Duration::from_secs(HELLO_INTERVAL as u64)).await; @@ -592,5 +535,27 @@ impl RouterInner { } } - fn propagate_routes(&self) {} + fn propagate_selected_routes(&mut self) { + + let mut updates = vec![]; + for sr in self.selected_routing_table.table.iter() { + for peer in self.peer_interfaces.iter() { + let update = ControlPacket::new_update( + sr.0.plen, + UPDATE_INTERVAL as u16, + self.router_seqno, // updates receive the seqno of the router + peer.link_cost() + sr.1.metric, + sr.0.prefix, // the prefix of a static route corresponds to the TUN addr of the node + self.router_id, + ); + + println!("Propagting selected route update: {:?}", update); + updates.push((peer.clone(), update)); + } + } + + for (peer, update) in updates { + self.send_update(&peer, update); + } + } } From 1c35cd61d9ca1e5840c2cfbb21cc42c0b6c59ca0 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Tue, 16 May 2023 16:22:04 +0000 Subject: [PATCH 73/89] propagate selected routes v3 --- src/router.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/router.rs b/src/router.rs index 44b04b7..7947802 100644 --- a/src/router.rs +++ b/src/router.rs @@ -544,7 +544,7 @@ impl RouterInner { sr.0.plen, UPDATE_INTERVAL as u16, self.router_seqno, // updates receive the seqno of the router - peer.link_cost() + sr.1.metric, + if sr.1.metric == u16::MAX - 1 { u16::MAX } else { sr.1.metric + peer.link_cost() }, sr.0.prefix, // the prefix of a static route corresponds to the TUN addr of the node self.router_id, ); From 6c0c6237241376f459333bf8df5e4fea2b9970bf Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Tue, 16 May 2023 16:29:14 +0000 Subject: [PATCH 74/89] propagate selected routes v4 --- src/router.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/router.rs b/src/router.rs index 7947802..9b89b7f 100644 --- a/src/router.rs +++ b/src/router.rs @@ -544,7 +544,7 @@ impl RouterInner { sr.0.plen, UPDATE_INTERVAL as u16, self.router_seqno, // updates receive the seqno of the router - if sr.1.metric == u16::MAX - 1 { u16::MAX } else { sr.1.metric + peer.link_cost() }, + sr.1.metric.checked_add(peer.link_cost()).unwrap_or(u16::MAX - 1), sr.0.prefix, // the prefix of a static route corresponds to the TUN addr of the node self.router_id, ); From d24651f53c33aab9cbb4913ca3227d357f0d877d Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Tue, 16 May 2023 17:06:47 +0000 Subject: [PATCH 75/89] add filter for route key of own static route --- src/router.rs | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/router.rs b/src/router.rs index 9b89b7f..4fbe9fd 100644 --- a/src/router.rs +++ b/src/router.rs @@ -244,6 +244,12 @@ impl Router { prefix, }; + // used later to filter out static route + let route_key_is_from_static_route = self.route_key_is_from_static_route(&route_key_from_update); + if route_key_is_from_static_route { + println!("Found route key that matches that of the static route"); + } + let mut inner = self.inner.write().unwrap(); // check if a route entry with the same route key exists in both routing tables @@ -261,7 +267,8 @@ impl Router { // if no entry exists if !route_entry_exists { // if the update is unfeasible, or the metric is inifinite, we ignore the update - if metric == u16::MAX || !self.update_feasible(&update, &inner.source_table) { + // we also ignore the update it's announcing it's own static route entry + if metric == u16::MAX || !self.update_feasible(&update, &inner.source_table) || route_key_is_from_static_route { return; } else { @@ -286,6 +293,12 @@ impl Router { selected: true, }; // if no entry exists, it should be added to the selected routing table as new entries are always selected + + // ADD ADDITIONAL CHECK TO INSERT INTO SELECTED_ROUTING_TABLE OR FALLBACK_ROUTING_TABLE + // ADD A FILTER TO NOT ADD THE STATIC ROUTE + + + inner.selected_routing_table.table.insert(route_key, route_entry); } @@ -325,6 +338,17 @@ impl Router { } + fn route_key_is_from_static_route(&self, route_key: &RouteKey) -> bool { + let inner = self.inner.read().unwrap(); + + for sr in inner.static_routes.iter() { + if sr.plen == route_key.plen && sr.prefix == route_key.prefix { + return true; + } + } + return false; + } + // we gebruiken self niet in de functie --> daarop functie eigenllijk beter op de source table implementeren fn update_feasible(&self, update: &ControlStruct, source_table: &SourceTable) -> bool { // Before an update is accepted it should be checked against the feasbility condition From ff448bfec2f7b1f5006d897ee760559aa05f8157 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Tue, 16 May 2023 18:13:47 +0000 Subject: [PATCH 76/89] fix too much selected routes v1 --- src/router.rs | 58 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 52 insertions(+), 6 deletions(-) diff --git a/src/router.rs b/src/router.rs index 4fbe9fd..56a869b 100644 --- a/src/router.rs +++ b/src/router.rs @@ -264,7 +264,7 @@ impl Router { } } - // if no entry exists + // if no entry exists (not skipping neighbor field) if !route_entry_exists { // if the update is unfeasible, or the metric is inifinite, we ignore the update // we also ignore the update it's announcing it's own static route entry @@ -289,18 +289,62 @@ impl Router { neighbor: inner.peer_by_ip(neighbor_ip).unwrap(), metric, seqno, - next_hop: neighbor_ip, // CHECK IF THIS IS CORRECT!!! + next_hop: neighbor_ip, selected: true, }; - // if no entry exists, it should be added to the selected routing table as new entries are always selected - - // ADD ADDITIONAL CHECK TO INSERT INTO SELECTED_ROUTING_TABLE OR FALLBACK_ROUTING_TABLE - // ADD A FILTER TO NOT ADD THE STATIC ROUTE + // first check if there exists a routing entry for the same prefix, plen (skipping neighbor field) in selected + // if the metric of the update is lower, we should remove the entry from selected and add it to fallback + // if the metric of the update is higher, we should add it to fallback + /* MORE CLEAR BUT GIVES IDIOT ERROR */ + // for r in inner.selected_routing_table.table.iter_mut() { + // if r.0.plen == plen && r.0.prefix == prefix { + // if metric < r.1.metric { + // let old_selected = inner.selected_routing_table.remove(r.0); + // if old_selected.is_some() { + // let rk = RouteKey { prefix: r.0.prefix, plen: r.0.plen, neighbor: r.0.neighbor }; + // inner.fallback_routing_table.insert(rk, old_selected.unwrap()); + // break; // we can break out of the for, as there will be max one better route in the selected at any point in time + // } + // } + // else if metric > r.1.metric { + // // this means that there is already a better route in our selected routing table, so we should add it to fallback instead + // inner.fallback_routing_table.table.insert(route_key, route_entry); + // return; // quit the function, work is done here + // } + // } + // } + // // insert the route into selected (we might he placed one other route, that was previously the best, in the fallback) + // inner.selected_routing_table.table.insert(route_key, route_entry); + + /* LESS CLEAR BUT NO IDIOT ERROR */ + // Collect keys of routes to be removed + let mut to_remove = Vec::new(); + for r in inner.selected_routing_table.table.iter() { + if r.0.plen == plen && r.0.prefix == prefix { + if metric < r.1.metric { + to_remove.push(r.0.clone()); + } else if metric > r.1.metric { + // This means that there is already a better route in our selected routing table, + // so we should add it to fallback instead + inner.fallback_routing_table.table.insert(route_key.clone(), route_entry.clone()); + return; // quit the function, work is done here + } + } + } + // Remove better routes from selected and insert into fallback + for rk in to_remove { + if let Some(old_selected) = inner.selected_routing_table.remove(&rk) { + inner.fallback_routing_table.insert(rk, old_selected); + } + } + // insert the route into selected (we might have placed one other route, that was previously the best, in the fallback) inner.selected_routing_table.table.insert(route_key, route_entry); + + } } // entry exists @@ -324,6 +368,8 @@ impl Router { if !self.update_feasible(&update, &inner.source_table) { // if the update is unfeasible, we remove the entry from the selected routing table inner.selected_routing_table.table.remove(&route_key_from_update); + println!("\n\n\n\n\n\n\nremoved entry from selected routing table"); + // should we remove it from the selected and add it to fallback here??? // TODO: if the updated caused the router ID of the entry to change, we should also sent triggered update } } From 7e3eb538d86c2137726456bd6d86a9d4e02d4810 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Wed, 17 May 2023 07:11:08 +0000 Subject: [PATCH 77/89] enhanced selected-fallback RT insertion --- src/router.rs | 36 ++++++------------------------------ 1 file changed, 6 insertions(+), 30 deletions(-) diff --git a/src/router.rs b/src/router.rs index 56a869b..1e541d8 100644 --- a/src/router.rs +++ b/src/router.rs @@ -293,41 +293,19 @@ impl Router { selected: true, }; - - // first check if there exists a routing entry for the same prefix, plen (skipping neighbor field) in selected - // if the metric of the update is lower, we should remove the entry from selected and add it to fallback - // if the metric of the update is higher, we should add it to fallback - - /* MORE CLEAR BUT GIVES IDIOT ERROR */ - // for r in inner.selected_routing_table.table.iter_mut() { - // if r.0.plen == plen && r.0.prefix == prefix { - // if metric < r.1.metric { - // let old_selected = inner.selected_routing_table.remove(r.0); - // if old_selected.is_some() { - // let rk = RouteKey { prefix: r.0.prefix, plen: r.0.plen, neighbor: r.0.neighbor }; - // inner.fallback_routing_table.insert(rk, old_selected.unwrap()); - // break; // we can break out of the for, as there will be max one better route in the selected at any point in time - // } - // } - // else if metric > r.1.metric { - // // this means that there is already a better route in our selected routing table, so we should add it to fallback instead - // inner.fallback_routing_table.table.insert(route_key, route_entry); - // return; // quit the function, work is done here - // } - // } - // } - // // insert the route into selected (we might he placed one other route, that was previously the best, in the fallback) - // inner.selected_routing_table.table.insert(route_key, route_entry); - - /* LESS CLEAR BUT NO IDIOT ERROR */ // Collect keys of routes to be removed let mut to_remove = Vec::new(); for r in inner.selected_routing_table.table.iter() { + // filter based on prefix and plen, skipping neighbor if r.0.plen == plen && r.0.prefix == prefix { + // metric of update is smaller than entry's metric if metric < r.1.metric { + // this means we should remove the entry from the selected routing table to_remove.push(r.0.clone()); + break; // we can break, as there will be max 1 better route in selected table at any point in time (hence 'selected') + // metric of update is greater than entry's metric } else if metric > r.1.metric { - // This means that there is already a better route in our selected routing table, + // this means that there is already a better route in our selected routing table, // so we should add it to fallback instead inner.fallback_routing_table.table.insert(route_key.clone(), route_entry.clone()); return; // quit the function, work is done here @@ -343,8 +321,6 @@ impl Router { // insert the route into selected (we might have placed one other route, that was previously the best, in the fallback) inner.selected_routing_table.table.insert(route_key, route_entry); - - } } // entry exists From 891a920fb6bad0510972fd8411a4180fbc136b14 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Wed, 17 May 2023 07:42:30 +0000 Subject: [PATCH 78/89] added data packet routing with best route selection --- src/router.rs | 84 ++++++++++++++++++++++---------------------- src/routing_table.rs | 13 ------- 2 files changed, 42 insertions(+), 55 deletions(-) diff --git a/src/router.rs b/src/router.rs index 1e541d8..418965a 100644 --- a/src/router.rs +++ b/src/router.rs @@ -133,39 +133,7 @@ impl Router { matching_peer.map(Clone::clone) } - // pub fn select_best_route(&self, dest_ip: ipaddr) -> option { - - // let inner = self.inner.read().unwrap(); - - // // first look in the routing table for all routekeys where prefix == dest_ip - // let routing_table = &inner.routing_table; - // let mut matching_routes: vec<&routeentry> = vec::new(); - - // for route in routing_table.table.iter() { - // if route.0.prefix == dest_ip { - // // note -- this is not correct, we need to check if the dest_ip is in the prefix range - // matching_routes.push(route.1); - // println!("found matching route with next-hop: {:?}", route.1.next_hop); - // } - // } - - // // now we have all routes that match the destination ip - // // we need to select the route with the lowest metric - // let mut best_route: option<&routeentry> = none; - // let mut best_metric: u16 = u16::max; - - // for route in matching_routes.iter() { - // if route.metric < best_metric { - // best_route = some(route); - // best_metric = route.metric; - // } - // } - - // match best_route { - // some(route) => some(route.clone()), - // none => none, - // } - // } + pub fn print_selected_routes(&self) { let inner = self.inner.read().unwrap(); @@ -230,8 +198,6 @@ impl Router { // incoming update can only be received by a Peer this node has a direct link to fn handle_incoming_update(&self, update: ControlStruct) { - println!("entering handle_incoming_update"); - match update.control_packet.body.tlv { BabelTLV::Update { plen, interval: _, seqno, metric, prefix, router_id } => { @@ -264,7 +230,7 @@ impl Router { } } - // if no entry exists (not skipping neighbor field) + // if no entry exists (based on prefix, plen AND neighbor field) if !route_entry_exists { // if the update is unfeasible, or the metric is inifinite, we ignore the update // we also ignore the update it's announcing it's own static route entry @@ -325,11 +291,13 @@ impl Router { } // entry exists else { + println!("received update where entry alread exists"); // if the entry is currently selected, the update is unfeasible, and the router-id of the update is equal // to the router-id of the entry, then we ignore the update if inner.selected_routing_table.table.contains_key(&route_key_from_update) { let route_entry = inner.selected_routing_table.table.get(&route_key_from_update).unwrap(); if !self.update_feasible(&update, &inner.source_table) && route_entry.source.router_id == router_id { + println!("Received update for exisiting entry with same router_id but worse metric"); return; } } @@ -350,7 +318,7 @@ impl Router { } } } - // RUN ROUTE SELECTION + // RUN ROUTE SELECTION? }, _ => { @@ -420,15 +388,47 @@ impl Router { } }, _ => { - // let best_route = self.select_best_route(IpAddr::V4(data_packet.dest_ip)); - // let peer = self.peer_by_ip(best_route.unwrap().next_hop).unwrap(); - // if let Err(e) = peer.send_data_packet(data_packet) { - // eprintln!("Error sending data packet to peer: {:?}", e); - // } + let best_route = self.select_best_route(IpAddr::V4(data_packet.dest_ip)); + match best_route { + Some (route_entry) => { + let peer = self.peer_by_ip(route_entry.next_hop).unwrap(); + if let Err(e) = peer.send_data_packet(data_packet) { + eprintln!("Error sending data packet to peer: {:?}", e); + } + }, + None => { + eprintln!("Error sending data packet, no route found"); + } + } } } } } + } + + pub fn select_best_route(&self, dest_ip: IpAddr) -> Option { + + let inner = self.inner.read().unwrap(); + let mut best_route = None; + // first look in the selected routing table for a match on the prefix of dest_ip + for (route_key, route_entry) in inner.selected_routing_table.table.iter() { + if route_key.prefix == dest_ip { + best_route = Some(route_entry.clone()); + } + } + // if no match was found, look in the fallback routing table + if best_route.is_none() { + println!("no match in selected routing table, looking in fallback routing table"); + for (route_key, route_entry) in inner.fallback_routing_table.table.iter() { + if route_key.prefix == dest_ip { + best_route = Some(route_entry.clone()); + } + } + } + + println!("\n\n best route towards {}: {:?}", dest_ip, best_route); + + return best_route } pub async fn propagate_static_route(self) { diff --git a/src/routing_table.rs b/src/routing_table.rs index d69cf48..806f5b5 100644 --- a/src/routing_table.rs +++ b/src/routing_table.rs @@ -46,19 +46,6 @@ impl RouteEntry { } } - // pub fn update(&mut self, update: ControlStruct) { - // // the update is assumed to be feasible here - // match update.control_packet.body.tlv { - // BabelTLV::Update { seqno, metric, .. } => { - // self.metric = metric; - // self.seqno = seqno; - // } - // _ => { - // panic!("Received update with invalid TLV"); - // } - // } - // } - pub fn retracted(&mut self) { self.metric = 0xFFFF; } From 1a847d948d9de6ba3dabe8e3f04c42306b7ef949 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Wed, 17 May 2023 09:30:44 +0000 Subject: [PATCH 79/89] check for dead peer v1 --- src/peer.rs | 38 ++++++++++++++---------------- src/peer_manager.rs | 7 ++++++ src/router.rs | 57 ++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 75 insertions(+), 27 deletions(-) diff --git a/src/peer.rs b/src/peer.rs index 19d2a90..432e38e 100644 --- a/src/peer.rs +++ b/src/peer.rs @@ -50,7 +50,6 @@ impl Peer { } pub fn time_last_received_hello(&self) -> tokio::time::Instant { - // TODO: Validate this works self.inner.read().unwrap().time_last_received_hello } @@ -96,9 +95,19 @@ impl Peer { self.inner.write().unwrap().link_cost = link_cost } - pub fn reset_ihu_timer(&self, duration: tokio::time::Duration) { - self.inner.write().unwrap().ihu_timer.reset(duration) + // pub fn reset_ihu_timer(&self, duration: tokio::time::Duration) { + // self.inner.write().unwrap().ihu_timer.reset(duration) + // } + + + pub fn time_last_received_ihu(&self) -> tokio::time::Instant { + self.inner.read().unwrap().time_last_received_ihu } + + pub fn set_time_last_received_ihu(&self, time: tokio::time::Instant) { + self.inner.write().unwrap().time_last_received_ihu = time + } + } impl PartialEq for Peer { @@ -118,7 +127,7 @@ struct PeerInner { hello_seqno: u16, time_last_received_hello: tokio::time::Instant, link_cost: u16, - ihu_timer: Timer, + time_last_received_ihu: tokio::time::Instant, } impl PeerInner { @@ -146,9 +155,11 @@ impl PeerInner { let link_cost = u16::MAX - 1; // Initialize time_last_received_hello to now let time_last_received_hello = tokio::time::Instant::now(); + // Initialiwe time_last_send_ihu + let time_last_received_ihu = tokio::time::Instant::now(); // Intialize the timers - let ihu_timer = Timer::new_ihu_timer(IHU_INTERVAL); + // let ihu_timer = Timer::new_ihu_timer(IHU_INTERVAL); tokio::spawn(async move { loop { @@ -220,23 +231,8 @@ impl PeerInner { overlay_ip, hello_seqno, link_cost, - ihu_timer, + time_last_received_ihu, time_last_received_hello, }) } - - pub fn new_dummy(overlay_ip: IpAddr) -> Peer { - Peer { - inner: Arc::new(RwLock::new(PeerInner { - stream_ip: IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), - to_peer_data: mpsc::unbounded_channel::().0, - to_peer_control: mpsc::unbounded_channel::().0, - overlay_ip, - hello_seqno: 0, - link_cost: 100, - ihu_timer: Timer::new_ihu_timer(u64::MAX), - time_last_received_hello: tokio::time::Instant::now(), - })), - } - } } diff --git a/src/peer_manager.rs b/src/peer_manager.rs index 26e8ae8..bf9d40c 100644 --- a/src/peer_manager.rs +++ b/src/peer_manager.rs @@ -33,6 +33,8 @@ impl PeerManager { static_peers_sockets, )); + tokio::spawn(PeerManager::check_peer_connections(peer_manager.clone())); + peer_manager } @@ -217,4 +219,9 @@ impl PeerManager { } } } + + async fn check_peer_connections(self) { + // TODO: Check if peer connections are still alive + } + } diff --git a/src/router.rs b/src/router.rs index 418965a..d6fd907 100644 --- a/src/router.rs +++ b/src/router.rs @@ -71,6 +71,8 @@ impl Router { tokio::spawn(Router::propagate_static_route(router.clone())); tokio::spawn(Router::propagate_selected_routes(router.clone())); + tokio::spawn(Router::check_for_dead_peers(router.clone())); + Ok(router) } @@ -122,7 +124,7 @@ impl Router { pub fn peer_by_ip(&self, peer_ip: IpAddr) -> Option { self.inner.read().unwrap().peer_by_ip(peer_ip) - } + } pub fn source_peer_from_control_struct(&self, control_struct: ControlStruct) -> Option { let peers = self.peer_interfaces(); @@ -159,6 +161,32 @@ impl Router { println!("\n"); } } + + async fn check_for_dead_peers(self) { + + let ihu_threshold = tokio::time::Duration::from_secs(8); + + loop { + + let inner = self.inner.read().unwrap(); + + // check for dead peers every second + tokio::time::sleep(tokio::time::Duration::from_secs(1)).await; + + // a peer is assumed dead when the peer's last sent ihu exceeds a threshold + for peer in inner.peer_interfaces.iter() { + // check if the peer's last_received_ihu is greater than the threshold + if peer.time_last_received_ihu().elapsed() > ihu_threshold { + // peer is dead + println!("Peer {:?} is dead", peer.overlay_ip()); + // remove the peer from the peer_interfaces + // self.remove_peer_interface(peer.clone()); + // remove the peer's routes from the routing table + } + } + + } + } async fn handle_incoming_control_packet( self, @@ -168,7 +196,7 @@ impl Router { match control_struct.control_packet.body.tlv_type { BabelTLVType::AckReq => todo!(), BabelTLVType::Ack => todo!(), - BabelTLVType::Hello => Self::handle_incoming_hello(control_struct), + BabelTLVType::Hello => Self::handle_incoming_hello(&self, control_struct), BabelTLVType::IHU => Self::handle_incoming_ihu(&self, control_struct), BabelTLVType::NextHop => todo!(), BabelTLVType::Update => Self::handle_incoming_update(&self, control_struct), @@ -178,21 +206,38 @@ impl Router { } } - fn handle_incoming_hello(control_struct: ControlStruct) { - let destination_ip = control_struct.src_overlay_ip; - control_struct.reply(ControlPacket::new_ihu(IHU_INTERVAL, destination_ip)); + fn handle_incoming_hello(&self, control_struct: ControlStruct) { + // let destination_ip = control_struct.src_overlay_ip; + // control_struct.reply(ControlPacket::new_ihu(IHU_INTERVAL, destination_ip)); + + // Upon receiving and Hello message from a peer, this node has to send a IHU back + if let Some(source_peer) = self.source_peer_from_control_struct(control_struct) { + let ihu = ControlPacket::new_ihu(IHU_INTERVAL, source_peer.overlay_ip()); + match source_peer.send_control_packet(ihu) { + Ok(()) => { + }, + Err(e) => { + eprintln!("Error sending IHU to peer: {e}"); + } + } + } } fn handle_incoming_ihu(&self, control_struct: ControlStruct) { if let Some(source_peer) = self.source_peer_from_control_struct(control_struct) { // reset the IHU timer associated with the peer - source_peer.reset_ihu_timer(tokio::time::Duration::from_secs(IHU_INTERVAL as u64)); + // source_peer.reset_ihu_timer(tokio::time::Duration::from_secs(IHU_INTERVAL as u64)); // measure time between Hello and and IHU and set the link cost let time_diff = tokio::time::Instant::now() .duration_since(source_peer.time_last_received_hello()) .as_millis(); source_peer.set_link_cost(time_diff as u16); + + + + // set the last_received_ihu for this peer + source_peer.set_time_last_received_ihu(tokio::time::Instant::now()); } } From 1ea15c402fe94bb3807bec09bc448d090551421a Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Wed, 17 May 2023 09:37:13 +0000 Subject: [PATCH 80/89] check for dead peer v2 --- src/router.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/router.rs b/src/router.rs index d6fd907..24e1579 100644 --- a/src/router.rs +++ b/src/router.rs @@ -168,11 +168,11 @@ impl Router { loop { - let inner = self.inner.read().unwrap(); - // check for dead peers every second tokio::time::sleep(tokio::time::Duration::from_secs(1)).await; + let inner = self.inner.read().unwrap(); + // a peer is assumed dead when the peer's last sent ihu exceeds a threshold for peer in inner.peer_interfaces.iter() { // check if the peer's last_received_ihu is greater than the threshold @@ -181,7 +181,7 @@ impl Router { println!("Peer {:?} is dead", peer.overlay_ip()); // remove the peer from the peer_interfaces // self.remove_peer_interface(peer.clone()); - // remove the peer's routes from the routing table + // remove the peer's routes from the routing table (= all the peers that use the peer as next-hop) } } From bc83213a04c36d375ced29ebde06bfabe3cf2642 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Wed, 17 May 2023 12:39:52 +0000 Subject: [PATCH 81/89] added retraction updates --- src/router.rs | 99 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 78 insertions(+), 21 deletions(-) diff --git a/src/router.rs b/src/router.rs index 24e1579..b581214 100644 --- a/src/router.rs +++ b/src/router.rs @@ -113,9 +113,7 @@ impl Router { } pub fn remove_peer_interface(&self, peer: Peer) { - let mut peer_interfaces = self.inner.write().unwrap().peer_interfaces.clone(); - peer_interfaces.retain(|p| p != &peer); - self.inner.write().unwrap().peer_interfaces = peer_interfaces; + self.inner.write().unwrap().remove_peer_interface(peer); } pub fn static_routes(&self) -> Vec { @@ -135,7 +133,6 @@ impl Router { matching_peer.map(Clone::clone) } - pub fn print_selected_routes(&self) { let inner = self.inner.read().unwrap(); @@ -165,28 +162,67 @@ impl Router { async fn check_for_dead_peers(self) { let ihu_threshold = tokio::time::Duration::from_secs(8); - + loop { - + // check for dead peers every second tokio::time::sleep(tokio::time::Duration::from_secs(1)).await; + let mut inner = self.inner.write().unwrap(); - let inner = self.inner.read().unwrap(); - - // a peer is assumed dead when the peer's last sent ihu exceeds a threshold - for peer in inner.peer_interfaces.iter() { - // check if the peer's last_received_ihu is greater than the threshold - if peer.time_last_received_ihu().elapsed() > ihu_threshold { - // peer is dead - println!("Peer {:?} is dead", peer.overlay_ip()); - // remove the peer from the peer_interfaces - // self.remove_peer_interface(peer.clone()); - // remove the peer's routes from the routing table (= all the peers that use the peer as next-hop) + let dead_peers = { + // a peer is assumed dead when the peer's last sent ihu exceeds a threshold + let mut dead_peers = Vec::new(); + for peer in inner.peer_interfaces.iter() { + // check if the peer's last_received_ihu is greater than the threshold + if peer.time_last_received_ihu().elapsed() > ihu_threshold { + // peer is dead + println!("Peer {:?} is dead", peer.overlay_ip()); + dead_peers.push(peer.clone()); + } } - } + dead_peers + }; + + // vec to store retraction update that need to be sent + let mut retraction_updates = Vec::::new(); + + // remove the peer from the peer_interfaces and the routes + for dead_peer in dead_peers { + inner.remove_peer_interface(dead_peer.clone()); + // remove the peer's routes from all routing tables (= all the peers that use the peer as next-hop) + inner.selected_routing_table.table.retain(|_, route_entry| { + route_entry.next_hop != dead_peer.overlay_ip() + }); + inner.fallback_routing_table.table.retain(|_, route_entry| { + route_entry.next_hop != dead_peer.overlay_ip() + }); + + // create retraction update for each dead peer + let retraction_update = ControlPacket::new_update( + 32, + UPDATE_INTERVAL as u16, + inner.router_seqno, + 0xFFFF, + dead_peer.overlay_ip(), // todo: fix to use actual prefix, not IP + inner.router_id, + ); + retraction_updates.push(retraction_update); + } + + // send retraction update for the dead peer + // when other nodes receive this update (with metric 0XFFFF), they should also remove the routing tables entries with that peer as neighbor + for peer in inner.peer_interfaces.iter() { + for ru in retraction_updates.iter() { + if let Err(e) = peer.send_control_packet(ru.clone()) { + eprintln!("Error sending retraction update to peer"); + } + } + } } } + + async fn handle_incoming_control_packet( self, @@ -336,7 +372,22 @@ impl Router { } // entry exists else { - println!("received update where entry alread exists"); + + // check if update is a retraction + if self.update_feasible(&update, &inner.source_table) && metric == u16::MAX { + println!("RECEIVED RETRACTION UPDATE!!!!!!!!!!!!!"); + // if the update is a retraction, we remove the entry from the routing tables + // we also remove the corresponding source entry??? + if inner.selected_routing_table.table.contains_key(&route_key_from_update) { + inner.selected_routing_table.remove(&route_key_from_update); + } + if inner.fallback_routing_table.table.contains_key(&route_key_from_update) { + inner.fallback_routing_table.remove(&route_key_from_update); + } + return; + } + + println!("received update where entry already exists"); // if the entry is currently selected, the update is unfeasible, and the router-id of the update is equal // to the router-id of the entry, then we ignore the update if inner.selected_routing_table.table.contains_key(&route_key_from_update) { @@ -405,8 +456,11 @@ impl Router { }; match source_table.get(&source_key) { Some(&entry) => { - return seqno > entry.seqno - || (seqno == entry.seqno && metric < entry.metric); + // debug purposes + if metric == 0xFFFF { + println!("metric is 0xFFFF, so update is a RETRACTION"); + } + return (seqno > entry.seqno|| (seqno == entry.seqno && metric < entry.metric)) || metric == 0xFFFF; } None => return true, } @@ -545,6 +599,9 @@ impl RouterInner { Ok(router_inner) } + fn remove_peer_interface(&mut self, peer: Peer) { + self.peer_interfaces.retain(|p| p != &peer); + } fn peer_by_ip(&self, peer_ip: IpAddr) -> Option { let matching_peer = self From 0dd9014a7392b49800f755f959eb82c3ebe26f8f Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Wed, 17 May 2023 12:55:08 +0000 Subject: [PATCH 82/89] removed some debug messages --- src/router.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/router.rs b/src/router.rs index b581214..892b537 100644 --- a/src/router.rs +++ b/src/router.rs @@ -672,12 +672,9 @@ impl RouterInner { sr.prefix, // the prefix of a static route corresponds to the TUN addr of the node self.router_id, ); - - println!("Propagting static route update: {:?}", update); updates.push((peer.clone(), update)); } } - for (peer, update) in updates { self.send_update(&peer, update); } @@ -696,8 +693,6 @@ impl RouterInner { sr.0.prefix, // the prefix of a static route corresponds to the TUN addr of the node self.router_id, ); - - println!("Propagting selected route update: {:?}", update); updates.push((peer.clone(), update)); } } From 76dcad6c6027bb5bf9a18e7e9d8bb56f8d5a9223 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Wed, 17 May 2023 13:22:38 +0000 Subject: [PATCH 83/89] removed source entry on update retraction --- src/router.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/router.rs b/src/router.rs index 892b537..ab532d3 100644 --- a/src/router.rs +++ b/src/router.rs @@ -384,6 +384,10 @@ impl Router { if inner.fallback_routing_table.table.contains_key(&route_key_from_update) { inner.fallback_routing_table.remove(&route_key_from_update); } + // remove the corresponding source entry + let source_key = SourceKey { prefix, plen, router_id }; + inner.source_table.remove(&source_key); + return; } From c66d51268a45d8421afced62e18d1ab9775e7f4c Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Wed, 17 May 2023 16:22:10 +0000 Subject: [PATCH 84/89] add support reconnect to original peers v1 --- src/peer.rs | 7 ++--- src/peer_manager.rs | 73 ++++++++++++++++++++++++++++++++++++++++----- src/router.rs | 21 ++++++------- 3 files changed, 80 insertions(+), 21 deletions(-) diff --git a/src/peer.rs b/src/peer.rs index 432e38e..bb05050 100644 --- a/src/peer.rs +++ b/src/peer.rs @@ -95,10 +95,9 @@ impl Peer { self.inner.write().unwrap().link_cost = link_cost } - // pub fn reset_ihu_timer(&self, duration: tokio::time::Duration) { - // self.inner.write().unwrap().ihu_timer.reset(duration) - // } - + pub fn underlay_ip(&self) -> IpAddr { + self.inner.read().unwrap().stream_ip + } pub fn time_last_received_ihu(&self) -> tokio::time::Instant { self.inner.read().unwrap().time_last_received_ihu diff --git a/src/peer_manager.rs b/src/peer_manager.rs index bf9d40c..36ce07a 100644 --- a/src/peer_manager.rs +++ b/src/peer_manager.rs @@ -17,12 +17,15 @@ struct PeersConfig { #[derive(Clone)] pub struct PeerManager { pub router: Router, + pub initial_peers: Vec, } impl PeerManager { pub fn new(router: Router, static_peers_sockets: Vec) -> Self { - let peer_manager = PeerManager { router }; - + let peer_manager = PeerManager { + router, + initial_peers: static_peers_sockets.clone(), + }; // Start a TCP listener. When a new connection is accepted, the reverse peer exchange is performed. tokio::spawn(PeerManager::start_listener(peer_manager.clone())); // Reads the nodeconfig.toml file and connects to the peers in the file. @@ -33,7 +36,7 @@ impl PeerManager { static_peers_sockets, )); - tokio::spawn(PeerManager::check_peer_connections(peer_manager.clone())); + tokio::spawn(PeerManager::reconnect_to_initial_peers(peer_manager.clone())); peer_manager } @@ -149,6 +152,66 @@ impl PeerManager { } } + // this is used to reconnect to the provided static peers in case the connection is lost + async fn reconnect_to_initial_peers(self) { + + loop { + tokio::time::sleep(tokio::time::Duration::from_secs(5)).await; + + // check if there is an entry for the peer in the router's peer list + for peer in self.initial_peers.iter() { + if !self.router.peer_exists(peer.ip()) { + if let Ok(mut peer_stream) = TcpStream::connect(peer).await { + let mut buffer = [0u8; 17]; + peer_stream.read_exact(&mut buffer).await.unwrap(); + let received_overlay_ip = match buffer[0] { + 0 => IpAddr::from( + <&[u8] as TryInto<[u8; 4]>>::try_into(&buffer[1..5]).unwrap(), + ), + 1 => IpAddr::from( + <&[u8] as TryInto<[u8; 16]>>::try_into(&buffer[1..]).unwrap(), + ), + _ => { + eprintln!("Invalid address encoding byte"); + continue; + } + }; + + println!( + "Received overlay IP from other node: {:?}", + received_overlay_ip + ); + + let mut buf = [0u8; 17]; + match self.router.node_tun_addr() { + IpAddr::V4(tun_addr) => { + buf[0] = 0; + buf[1..5].copy_from_slice(&tun_addr.octets()[..]); + } + IpAddr::V6(tun_addr) => { + buf[0] = 1; + buf[1..].copy_from_slice(&tun_addr.octets()[..]); + } + } + peer_stream.write_all(&buf).await.unwrap(); + + let peer_stream_ip = peer.ip(); + if let Ok(new_peer) = Peer::new( + peer_stream_ip, + self.router.router_data_tx(), + self.router.router_control_tx(), + peer_stream, + received_overlay_ip, + ) { + self.router.add_peer_interface(new_peer); + } + } + } + } + } + + } + async fn start_listener(self) { match TcpListener::bind("[::]:9651").await { Ok(listener) => loop { @@ -220,8 +283,4 @@ impl PeerManager { } } - async fn check_peer_connections(self) { - // TODO: Check if peer connections are still alive - } - } diff --git a/src/router.rs b/src/router.rs index ab532d3..b48474d 100644 --- a/src/router.rs +++ b/src/router.rs @@ -122,7 +122,11 @@ impl Router { pub fn peer_by_ip(&self, peer_ip: IpAddr) -> Option { self.inner.read().unwrap().peer_by_ip(peer_ip) - } + } + + pub fn peer_exists(&self, peer_underlay_ip: IpAddr) -> bool { + self.inner.read().unwrap().peer_exists(peer_underlay_ip) + } pub fn source_peer_from_control_struct(&self, control_struct: ControlStruct) -> Option { let peers = self.peer_interfaces(); @@ -375,7 +379,6 @@ impl Router { // check if update is a retraction if self.update_feasible(&update, &inner.source_table) && metric == u16::MAX { - println!("RECEIVED RETRACTION UPDATE!!!!!!!!!!!!!"); // if the update is a retraction, we remove the entry from the routing tables // we also remove the corresponding source entry??? if inner.selected_routing_table.table.contains_key(&route_key_from_update) { @@ -390,14 +393,11 @@ impl Router { return; } - - println!("received update where entry already exists"); // if the entry is currently selected, the update is unfeasible, and the router-id of the update is equal // to the router-id of the entry, then we ignore the update if inner.selected_routing_table.table.contains_key(&route_key_from_update) { let route_entry = inner.selected_routing_table.table.get(&route_key_from_update).unwrap(); if !self.update_feasible(&update, &inner.source_table) && route_entry.source.router_id == router_id { - println!("Received update for exisiting entry with same router_id but worse metric"); return; } } @@ -412,14 +412,10 @@ impl Router { if !self.update_feasible(&update, &inner.source_table) { // if the update is unfeasible, we remove the entry from the selected routing table inner.selected_routing_table.table.remove(&route_key_from_update); - println!("\n\n\n\n\n\n\nremoved entry from selected routing table"); // should we remove it from the selected and add it to fallback here??? - // TODO: if the updated caused the router ID of the entry to change, we should also sent triggered update } } } - // RUN ROUTE SELECTION? - }, _ => { panic!("Received update with wrong TLV type"); @@ -462,7 +458,6 @@ impl Router { Some(&entry) => { // debug purposes if metric == 0xFFFF { - println!("metric is 0xFFFF, so update is a RETRACTION"); } return (seqno > entry.seqno|| (seqno == entry.seqno && metric < entry.metric)) || metric == 0xFFFF; } @@ -705,4 +700,10 @@ impl RouterInner { self.send_update(&peer, update); } } + + fn peer_exists(&self, peer_underlay_ip: IpAddr) -> bool { + self.peer_interfaces + .iter() + .any(|peer| peer.underlay_ip() == peer_underlay_ip) + } } From f178fb267ba39615481bfc11efbd98944bb6afab Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Wed, 17 May 2023 16:48:18 +0000 Subject: [PATCH 85/89] fixed little bug with >= --- src/router.rs | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/src/router.rs b/src/router.rs index b48474d..d1948f3 100644 --- a/src/router.rs +++ b/src/router.rs @@ -304,16 +304,7 @@ impl Router { let mut inner = self.inner.write().unwrap(); // check if a route entry with the same route key exists in both routing tables - let mut route_entry_exists = false; - for (route_key, _) in inner.selected_routing_table - .table - .iter() - .zip(inner.fallback_routing_table.table.iter()) - { - if route_key.0 == &route_key_from_update { - route_entry_exists = true; - } - } + let route_entry_exists = inner.selected_routing_table.table.contains_key(&route_key_from_update) || inner.fallback_routing_table.table.contains_key(&route_key_from_update); // if no entry exists (based on prefix, plen AND neighbor field) if !route_entry_exists { @@ -355,7 +346,7 @@ impl Router { to_remove.push(r.0.clone()); break; // we can break, as there will be max 1 better route in selected table at any point in time (hence 'selected') // metric of update is greater than entry's metric - } else if metric > r.1.metric { + } else if metric >= r.1.metric { // this means that there is already a better route in our selected routing table, // so we should add it to fallback instead inner.fallback_routing_table.table.insert(route_key.clone(), route_entry.clone()); @@ -376,7 +367,6 @@ impl Router { } // entry exists else { - // check if update is a retraction if self.update_feasible(&update, &inner.source_table) && metric == u16::MAX { // if the update is a retraction, we remove the entry from the routing tables @@ -680,15 +670,17 @@ impl RouterInner { } fn propagate_selected_routes(&mut self) { - let mut updates = vec![]; for sr in self.selected_routing_table.table.iter() { for peer in self.peer_interfaces.iter() { + + let peer_link_cost = peer.link_cost(); + let update = ControlPacket::new_update( sr.0.plen, UPDATE_INTERVAL as u16, self.router_seqno, // updates receive the seqno of the router - sr.1.metric.checked_add(peer.link_cost()).unwrap_or(u16::MAX - 1), + if sr.1.metric > u16::MAX -1 - peer_link_cost {u16::MAX - 1 } else { sr.1.metric + peer_link_cost }, // the cost of the route is the cost of the route + the cost of the link to the peer sr.0.prefix, // the prefix of a static route corresponds to the TUN addr of the node self.router_id, ); From 35b0d3f97ca2ca1bd6ca7b07b8ad94ad62dd79d7 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Wed, 17 May 2023 17:38:08 +0000 Subject: [PATCH 86/89] bug fixed in selected and fallback route --- src/main.rs | 2 ++ src/router.rs | 30 ++++++++++++++++++++++-------- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/main.rs b/src/main.rs index 4df3885..85d2311 100644 --- a/src/main.rs +++ b/src/main.rs @@ -127,6 +127,8 @@ async fn main() -> Result<(), Box> { line.pop(); println!("----------- Current selected routes -----------{}\n", line); router.print_selected_routes(); + println!("----------- Current fallback routes -----------{}\n", line); + router.print_fallback_routes(); println!("\n----------- Current peers: -----------"); for p in router.peer_interfaces() { diff --git a/src/router.rs b/src/router.rs index d1948f3..46780c7 100644 --- a/src/router.rs +++ b/src/router.rs @@ -152,6 +152,20 @@ impl Router { } } + pub fn print_fallback_routes(&self) { + let inner = self.inner.read().unwrap(); + + let routing_table = &inner.fallback_routing_table; + for route in routing_table.table.iter() { + println!("Route key: {:?}", route.0); + println!( + "Route: {:?}/{:?} (with next-hop: {:?}, metric: {}, selected: {})", + route.0.prefix, route.0.plen, route.1.next_hop, route.1.metric, route.1.selected + ); + println!("As advertised by: {:?}", route.1.source.router_id); + } + } + pub fn print_source_table(&self) { let inner = self.inner.read().unwrap(); @@ -296,9 +310,8 @@ impl Router { }; // used later to filter out static route - let route_key_is_from_static_route = self.route_key_is_from_static_route(&route_key_from_update); - if route_key_is_from_static_route { - println!("Found route key that matches that of the static route"); + if self.route_key_is_from_static_route(&route_key_from_update) { + return; } let mut inner = self.inner.write().unwrap(); @@ -309,8 +322,7 @@ impl Router { // if no entry exists (based on prefix, plen AND neighbor field) if !route_entry_exists { // if the update is unfeasible, or the metric is inifinite, we ignore the update - // we also ignore the update it's announcing it's own static route entry - if metric == u16::MAX || !self.update_feasible(&update, &inner.source_table) || route_key_is_from_static_route { + if metric == u16::MAX || !self.update_feasible(&update, &inner.source_table) { return; } else { @@ -390,6 +402,11 @@ impl Router { if !self.update_feasible(&update, &inner.source_table) && route_entry.source.router_id == router_id { return; } + // update the entry's seqno, metric and router-id + let route_entry = inner.selected_routing_table.table.get_mut(&route_key_from_update).unwrap(); + route_entry.update_seqno(seqno); + route_entry.update_metric(metric); + route_entry.update_router_id(router_id); } // otherwise else { @@ -446,9 +463,6 @@ impl Router { }; match source_table.get(&source_key) { Some(&entry) => { - // debug purposes - if metric == 0xFFFF { - } return (seqno > entry.seqno|| (seqno == entry.seqno && metric < entry.metric)) || metric == 0xFFFF; } None => return true, From e0cbb7fdd66cb9978411c7ae4ff3164d1ef57a1f Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Fri, 19 May 2023 17:57:32 +0200 Subject: [PATCH 87/89] cleanup with clippy --- src/codec.rs | 24 +++-- src/main.rs | 21 ++--- src/node_setup.rs | 3 +- src/packet.rs | 42 +-------- src/peer.rs | 22 +---- src/peer_manager.rs | 20 ++-- src/router.rs | 211 ++++++++++++++++++++++++++----------------- src/routing_table.rs | 19 +--- src/source_table.rs | 2 - src/timers.rs | 70 -------------- 10 files changed, 169 insertions(+), 265 deletions(-) delete mode 100644 src/timers.rs diff --git a/src/codec.rs b/src/codec.rs index 5f8e68f..66c8ae7 100644 --- a/src/codec.rs +++ b/src/codec.rs @@ -36,7 +36,7 @@ impl Decoder for PacketCodec { packet_type } else { // Check we can read the packet type (1 byte) - if src.len() < 1 { + if src.is_empty() { return Ok(None); } @@ -249,12 +249,12 @@ impl Decoder for ControlPacketCodec { BabelTLVType::Hello => { let seqno = buf.get_u16(); let interval = buf.get_u16(); - let body = BabelPacketBody { + + BabelPacketBody { tlv_type, length, tlv: BabelTLV::Hello { seqno, interval }, - }; - body + } } BabelTLVType::IHU => { let interval = buf.get_u16(); @@ -264,12 +264,12 @@ impl Decoder for ControlPacketCodec { buf.get_u8(), buf.get_u8(), )); - let body = BabelPacketBody { + + BabelPacketBody { tlv_type, length, tlv: BabelTLV::IHU { interval, address }, - }; - body + } } BabelTLVType::Update => { let ae = buf.get_u8(); @@ -309,7 +309,8 @@ impl Decoder for ControlPacketCodec { } }; let router_id = buf.get_u64(); - let body = BabelPacketBody { + + BabelPacketBody { tlv_type, length, tlv: BabelTLV::Update { @@ -320,8 +321,7 @@ impl Decoder for ControlPacketCodec { prefix, router_id, }, - }; - body + } } BabelTLVType::AckReq => todo!(), BabelTLVType::Ack => todo!(), @@ -398,9 +398,7 @@ impl Encoder for ControlPacketCodec { } } buf.put_u64(router_id); - } - // Add encoding logic for other TLV types. - _ => {} + } // Add encoding logic for other TLV types. } Ok(()) diff --git a/src/main.rs b/src/main.rs index 85d2311..9a2e424 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,19 +1,14 @@ +use crate::packet::DataPacket; +use crate::router::StaticRoute; use bytes::BytesMut; use clap::Parser; use etherparse::{IpHeader, PacketHeaders}; -use packet::DataPacket; -use router::Router; -use routing_table::{RouteEntry, RouteKey}; -use source_table::{FeasibilityDistance, SourceKey}; use std::{ error::Error, - net::{IpAddr, Ipv4Addr, SocketAddr}, - sync::Arc, + net::{Ipv4Addr, SocketAddr}, }; use tokio::io::AsyncBufReadExt; -use crate::{peer::Peer, router::StaticRoute}; - mod codec; mod node_setup; mod packet; @@ -22,7 +17,6 @@ mod peer_manager; mod router; mod routing_table; mod source_table; -mod timers; const LINK_MTU: usize = 1420; @@ -52,7 +46,10 @@ async fn main() -> Result<(), Box> { let static_peers = cli.static_peers; // Creating a new Router instance - let router = match router::Router::new(node_tun.clone(), vec![StaticRoute::new(cli.tun_addr.into())]) { + let router = match router::Router::new( + node_tun.clone(), + vec![StaticRoute::new(cli.tun_addr.into())], + ) { Ok(router) => { println!("Router created. ID: {}", router.router_id()); router @@ -62,7 +59,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); @@ -139,9 +135,8 @@ async fn main() -> Result<(), Box> { ); } - println!("\n----------- Current source table: -----------"); - router.print_source_table(); + router.print_source_table(); println!("\n\n"); } diff --git a/src/node_setup.rs b/src/node_setup.rs index 6076603..f308b86 100644 --- a/src/node_setup.rs +++ b/src/node_setup.rs @@ -1,6 +1,5 @@ use futures::stream::TryStreamExt; use rtnetlink::Handle; -use core::fmt; use std::{error::Error, net::Ipv4Addr, sync::Arc}; use tokio_tun::{Tun, TunBuilder}; @@ -62,4 +61,4 @@ pub async fn setup_node(tun_addr: Ipv4Addr) -> Result, Box> println!("Static route created"); Ok(tun) -} \ No newline at end of file +} diff --git a/src/packet.rs b/src/packet.rs index d04b6d4..3ac404e 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -59,14 +59,6 @@ pub struct BabelPacketBody { pub tlv: BabelTLV, } -impl ControlStruct { - pub fn reply(self, control_packet: ControlPacket) { - if let Err(e) = self.control_reply_tx.send(control_packet) { - eprintln!("Error reply: {:?}", e); - } - } -} - impl BabelPacketHeader { pub fn new(body_length: u16) -> Self { Self { @@ -95,10 +87,7 @@ impl ControlPacket { } pub fn new_ihu(interval: u16, dest_address: IpAddr) -> Self { - let uses_ipv6 = match dest_address { - IpAddr::V4(_) => false, - IpAddr::V6(_) => true, - }; + let uses_ipv6 = dest_address.is_ipv6(); let header_length = (BabelTLVType::IHU.get_tlv_length(uses_ipv6) + 2) as u16; Self { header: BabelPacketHeader::new(header_length), @@ -121,10 +110,7 @@ impl ControlPacket { prefix: IpAddr, router_id: u64, ) -> Self { - let uses_ipv6 = match prefix { - IpAddr::V4(_) => false, - IpAddr::V6(_) => true, - }; + let uses_ipv6 = prefix.is_ipv6(); let header_length = (BabelTLVType::Update.get_tlv_length(uses_ipv6) + 2) as u16; Self { header: BabelPacketHeader::new(header_length), @@ -201,13 +187,6 @@ pub enum BabelTLV { // These TLVs are not implemented as they are used for padding when sending multiple TLVs in one packet. // Pad1, // PadN(u8), - AckReq { - nonce: u16, - interval: u16, - }, - Ack { - nonce: u16, - }, Hello { seqno: u16, interval: u16, @@ -216,13 +195,6 @@ pub enum BabelTLV { interval: u16, address: IpAddr, }, - // RouterID TLVs are sent just before Update TLVs and server the purpose of identifying the router that sent the Update TLV. - // This is used when multiple Update TLVs are sent where a prefix is included in the first Update TLV and omitted in the subsequent Update TLVs. - // As we do not support ommitted prefixes, we do not need to implement this TLV. We pass the router_id as a parameter to the Update TLV instead. - // RouterID { router_id: u16 }, - NextHop { - address: IpAddr, - }, Update { plen: u8, interval: u16, @@ -231,14 +203,4 @@ pub enum BabelTLV { prefix: IpAddr, router_id: u64, }, - RouteReq { - prefix: IpAddr, - plen: u8, - }, - SeqnoReq { - prefix: IpAddr, - plen: u8, - seqno: u16, - router_id: u16, - }, } diff --git a/src/peer.rs b/src/peer.rs index bb05050..d6db5b0 100644 --- a/src/peer.rs +++ b/src/peer.rs @@ -1,19 +1,14 @@ use futures::{SinkExt, StreamExt}; use std::{ error::Error, - net::{IpAddr, Ipv4Addr}, + net::IpAddr, sync::{Arc, RwLock}, }; use tokio::{net::TcpStream, select, sync::mpsc}; use tokio_util::codec::Framed; -use crate::{codec::PacketCodec, packet::{Packet, BabelTLV}}; -use crate::{ - packet::{ControlPacket, ControlStruct, DataPacket}, - timers::Timer, -}; - -const IHU_INTERVAL: u64 = 10; +use crate::packet::{ControlPacket, ControlStruct, DataPacket}; +use crate::{codec::PacketCodec, packet::Packet}; #[derive(Debug, Clone)] pub struct Peer { @@ -57,11 +52,6 @@ impl Peer { self.inner.write().unwrap().time_last_received_hello = time } - /// Get stream IP (linked to underlay IP) for this peer - pub fn stream_ip(&self) -> IpAddr { - self.inner.read().unwrap().stream_ip - } - /// Get overlay IP for this peer pub fn overlay_ip(&self) -> IpAddr { self.inner.read().unwrap().overlay_ip @@ -78,7 +68,6 @@ impl Peer { /// It's send over the to_peer_control channel and read from the corresponding receiver. /// The receiver sends the packet over the TCP stream towards the destined peer instance on another node pub fn send_control_packet(&self, control_packet: ControlPacket) -> Result<(), Box> { - Ok(self .inner .write() @@ -106,7 +95,6 @@ impl Peer { pub fn set_time_last_received_ihu(&self, time: tokio::time::Instant) { self.inner.write().unwrap().time_last_received_ihu = time } - } impl PartialEq for Peer { @@ -115,8 +103,6 @@ impl PartialEq for Peer { } } - - #[derive(Debug)] struct PeerInner { stream_ip: IpAddr, @@ -126,7 +112,7 @@ struct PeerInner { hello_seqno: u16, time_last_received_hello: tokio::time::Instant, link_cost: u16, - time_last_received_ihu: tokio::time::Instant, + time_last_received_ihu: tokio::time::Instant, } impl PeerInner { diff --git a/src/peer_manager.rs b/src/peer_manager.rs index 36ce07a..829ab6c 100644 --- a/src/peer_manager.rs +++ b/src/peer_manager.rs @@ -1,8 +1,7 @@ use crate::peer::Peer; use crate::router::Router; use serde::Deserialize; -use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}; -use std::sync::Arc; +use std::net::{IpAddr, SocketAddr}; use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tokio::net::TcpListener; use tokio::net::TcpStream; @@ -22,10 +21,10 @@ pub struct PeerManager { impl PeerManager { pub fn new(router: Router, static_peers_sockets: Vec) -> Self { - let peer_manager = PeerManager { - router, - initial_peers: static_peers_sockets.clone(), - }; + let peer_manager = PeerManager { + router, + initial_peers: static_peers_sockets.clone(), + }; // Start a TCP listener. When a new connection is accepted, the reverse peer exchange is performed. tokio::spawn(PeerManager::start_listener(peer_manager.clone())); // Reads the nodeconfig.toml file and connects to the peers in the file. @@ -36,7 +35,9 @@ impl PeerManager { static_peers_sockets, )); - tokio::spawn(PeerManager::reconnect_to_initial_peers(peer_manager.clone())); + tokio::spawn(PeerManager::reconnect_to_initial_peers( + peer_manager.clone(), + )); peer_manager } @@ -154,7 +155,6 @@ impl PeerManager { // this is used to reconnect to the provided static peers in case the connection is lost async fn reconnect_to_initial_peers(self) { - loop { tokio::time::sleep(tokio::time::Duration::from_secs(5)).await; @@ -207,9 +207,8 @@ impl PeerManager { } } } - } + } } - } async fn start_listener(self) { @@ -282,5 +281,4 @@ impl PeerManager { } } } - } diff --git a/src/router.rs b/src/router.rs index 46780c7..93c31e2 100644 --- a/src/router.rs +++ b/src/router.rs @@ -2,7 +2,7 @@ use crate::{ packet::{BabelTLV, BabelTLVType, ControlPacket, ControlStruct, DataPacket}, peer::Peer, routing_table::{RouteEntry, RouteKey, RoutingTable}, - source_table::{self, FeasibilityDistance, SourceKey, SourceTable}, + source_table::{FeasibilityDistance, SourceKey, SourceTable}, }; use rand::Rng; use std::{ @@ -95,7 +95,7 @@ impl Router { pub fn node_tun(&self) -> Arc { self.inner.read().unwrap().node_tun.clone() } - + /* pub fn router_seqno(&self) -> u16 { self.inner.read().unwrap().router_seqno } @@ -103,7 +103,7 @@ impl Router { pub fn increment_router_seqno(&self) { self.inner.write().unwrap().router_seqno += 1; } - + */ pub fn peer_interfaces(&self) -> Vec { self.inner.read().unwrap().peer_interfaces.clone() } @@ -111,7 +111,7 @@ impl Router { pub fn add_peer_interface(&self, peer: Peer) { self.inner.write().unwrap().peer_interfaces.push(peer); } - + /* pub fn remove_peer_interface(&self, peer: Peer) { self.inner.write().unwrap().remove_peer_interface(peer); } @@ -119,7 +119,7 @@ impl Router { pub fn static_routes(&self) -> Vec { self.inner.read().unwrap().static_routes.clone() } - + */ pub fn peer_by_ip(&self, peer_ip: IpAddr) -> Option { self.inner.read().unwrap().peer_by_ip(peer_ip) } @@ -137,7 +137,6 @@ impl Router { matching_peer.map(Clone::clone) } - pub fn print_selected_routes(&self) { let inner = self.inner.read().unwrap(); @@ -176,13 +175,11 @@ impl Router { println!("\n"); } } - - async fn check_for_dead_peers(self) { + async fn check_for_dead_peers(self) { let ihu_threshold = tokio::time::Duration::from_secs(8); - + loop { - // check for dead peers every second tokio::time::sleep(tokio::time::Duration::from_secs(1)).await; let mut inner = self.inner.write().unwrap(); @@ -203,25 +200,27 @@ impl Router { // vec to store retraction update that need to be sent let mut retraction_updates = Vec::::new(); - + // remove the peer from the peer_interfaces and the routes for dead_peer in dead_peers { inner.remove_peer_interface(dead_peer.clone()); // remove the peer's routes from all routing tables (= all the peers that use the peer as next-hop) - inner.selected_routing_table.table.retain(|_, route_entry| { - route_entry.next_hop != dead_peer.overlay_ip() - }); - inner.fallback_routing_table.table.retain(|_, route_entry| { - route_entry.next_hop != dead_peer.overlay_ip() - }); + inner + .selected_routing_table + .table + .retain(|_, route_entry| route_entry.next_hop != dead_peer.overlay_ip()); + inner + .fallback_routing_table + .table + .retain(|_, route_entry| route_entry.next_hop != dead_peer.overlay_ip()); - // create retraction update for each dead peer + // create retraction update for each dead peer let retraction_update = ControlPacket::new_update( - 32, - UPDATE_INTERVAL as u16, - inner.router_seqno, - 0xFFFF, - dead_peer.overlay_ip(), // todo: fix to use actual prefix, not IP + 32, + UPDATE_INTERVAL, + inner.router_seqno, + 0xFFFF, + dead_peer.overlay_ip(), // todo: fix to use actual prefix, not IP inner.router_id, ); retraction_updates.push(retraction_update); @@ -232,15 +231,12 @@ impl Router { for peer in inner.peer_interfaces.iter() { for ru in retraction_updates.iter() { if let Err(e) = peer.send_control_packet(ru.clone()) { - eprintln!("Error sending retraction update to peer"); + eprintln!("Error sending retraction update to peer: {e}"); } } } - } } - - async fn handle_incoming_control_packet( self, @@ -263,13 +259,12 @@ impl Router { fn handle_incoming_hello(&self, control_struct: ControlStruct) { // let destination_ip = control_struct.src_overlay_ip; // control_struct.reply(ControlPacket::new_ihu(IHU_INTERVAL, destination_ip)); - + // Upon receiving and Hello message from a peer, this node has to send a IHU back if let Some(source_peer) = self.source_peer_from_control_struct(control_struct) { let ihu = ControlPacket::new_ihu(IHU_INTERVAL, source_peer.overlay_ip()); match source_peer.send_control_packet(ihu) { - Ok(()) => { - }, + Ok(()) => {} Err(e) => { eprintln!("Error sending IHU to peer: {e}"); } @@ -288,8 +283,6 @@ impl Router { source_peer.set_link_cost(time_diff as u16); - - // set the last_received_ihu for this peer source_peer.set_time_last_received_ihu(tokio::time::Instant::now()); } @@ -298,39 +291,55 @@ impl Router { // incoming update can only be received by a Peer this node has a direct link to fn handle_incoming_update(&self, update: ControlStruct) { match update.control_packet.body.tlv { - BabelTLV::Update { plen, interval: _, seqno, metric, prefix, router_id } => { - + BabelTLV::Update { + plen, + interval: _, + seqno, + metric, + prefix, + router_id, + } => { // create route key from incoming update control struct // we need the address of the neighbour; this corresponds to the source ip of the control struct as the update is received from the neighbouring peer let neighbor_ip = update.src_overlay_ip; - let route_key_from_update = RouteKey { - neighbor: neighbor_ip, - plen, + let route_key_from_update = RouteKey { + neighbor: neighbor_ip, + plen, prefix, }; - // used later to filter out static route + // used later to filter out static route if self.route_key_is_from_static_route(&route_key_from_update) { - return; + return; } let mut inner = self.inner.write().unwrap(); // check if a route entry with the same route key exists in both routing tables - let route_entry_exists = inner.selected_routing_table.table.contains_key(&route_key_from_update) || inner.fallback_routing_table.table.contains_key(&route_key_from_update); + let route_entry_exists = inner + .selected_routing_table + .table + .contains_key(&route_key_from_update) + || inner + .fallback_routing_table + .table + .contains_key(&route_key_from_update); // if no entry exists (based on prefix, plen AND neighbor field) if !route_entry_exists { // if the update is unfeasible, or the metric is inifinite, we ignore the update if metric == u16::MAX || !self.update_feasible(&update, &inner.source_table) { - return; - } - else { + // do nothing, just ignore + } else { // this means that the update is feasible and the metric is not infinite // create a new route entry and add it to the routing table (which requires a new source entry to be created as well) - let source_key = SourceKey { prefix, plen, router_id }; - let fd = FeasibilityDistance{ metric, seqno }; + let source_key = SourceKey { + prefix, + plen, + router_id, + }; + let fd = FeasibilityDistance { metric, seqno }; inner.source_table.insert(source_key, fd); let route_key = RouteKey { @@ -343,7 +352,7 @@ impl Router { neighbor: inner.peer_by_ip(neighbor_ip).unwrap(), metric, seqno, - next_hop: neighbor_ip, + next_hop: neighbor_ip, selected: true, }; @@ -357,11 +366,14 @@ impl Router { // this means we should remove the entry from the selected routing table to_remove.push(r.0.clone()); break; // we can break, as there will be max 1 better route in selected table at any point in time (hence 'selected') - // metric of update is greater than entry's metric + // metric of update is greater than entry's metric } else if metric >= r.1.metric { // this means that there is already a better route in our selected routing table, - // so we should add it to fallback instead - inner.fallback_routing_table.table.insert(route_key.clone(), route_entry.clone()); + // so we should add it to fallback instead + inner + .fallback_routing_table + .table + .insert(route_key, route_entry); return; // quit the function, work is done here } } @@ -373,8 +385,10 @@ impl Router { } } // insert the route into selected (we might have placed one other route, that was previously the best, in the fallback) - inner.selected_routing_table.table.insert(route_key, route_entry); - + inner + .selected_routing_table + .table + .insert(route_key, route_entry); } } // entry exists @@ -383,34 +397,64 @@ impl Router { if self.update_feasible(&update, &inner.source_table) && metric == u16::MAX { // if the update is a retraction, we remove the entry from the routing tables // we also remove the corresponding source entry??? - if inner.selected_routing_table.table.contains_key(&route_key_from_update) { + if inner + .selected_routing_table + .table + .contains_key(&route_key_from_update) + { inner.selected_routing_table.remove(&route_key_from_update); } - if inner.fallback_routing_table.table.contains_key(&route_key_from_update) { + if inner + .fallback_routing_table + .table + .contains_key(&route_key_from_update) + { inner.fallback_routing_table.remove(&route_key_from_update); } // remove the corresponding source entry - let source_key = SourceKey { prefix, plen, router_id }; + let source_key = SourceKey { + prefix, + plen, + router_id, + }; inner.source_table.remove(&source_key); return; } // if the entry is currently selected, the update is unfeasible, and the router-id of the update is equal // to the router-id of the entry, then we ignore the update - if inner.selected_routing_table.table.contains_key(&route_key_from_update) { - let route_entry = inner.selected_routing_table.table.get(&route_key_from_update).unwrap(); - if !self.update_feasible(&update, &inner.source_table) && route_entry.source.router_id == router_id { + if inner + .selected_routing_table + .table + .contains_key(&route_key_from_update) + { + let route_entry = inner + .selected_routing_table + .table + .get(&route_key_from_update) + .unwrap(); + if !self.update_feasible(&update, &inner.source_table) + && route_entry.source.router_id == router_id + { return; } // update the entry's seqno, metric and router-id - let route_entry = inner.selected_routing_table.table.get_mut(&route_key_from_update).unwrap(); + let route_entry = inner + .selected_routing_table + .table + .get_mut(&route_key_from_update) + .unwrap(); route_entry.update_seqno(seqno); route_entry.update_metric(metric); route_entry.update_router_id(router_id); } // otherwise else { - let route_entry = inner.fallback_routing_table.table.get_mut(&route_key_from_update).unwrap(); + let route_entry = inner + .fallback_routing_table + .table + .get_mut(&route_key_from_update) + .unwrap(); // update the entry's seqno, metric and router-id route_entry.update_seqno(seqno); route_entry.update_metric(metric); @@ -418,17 +462,19 @@ impl Router { if !self.update_feasible(&update, &inner.source_table) { // if the update is unfeasible, we remove the entry from the selected routing table - inner.selected_routing_table.table.remove(&route_key_from_update); + inner + .selected_routing_table + .table + .remove(&route_key_from_update); // should we remove it from the selected and add it to fallback here??? } } } - }, + } _ => { panic!("Received update with wrong TLV type"); } } - } fn route_key_is_from_static_route(&self, route_key: &RouteKey) -> bool { @@ -439,7 +485,7 @@ impl Router { return true; } } - return false; + false } // we gebruiken self niet in de functie --> daarop functie eigenllijk beter op de source table implementeren @@ -463,14 +509,15 @@ impl Router { }; match source_table.get(&source_key) { Some(&entry) => { - return (seqno > entry.seqno|| (seqno == entry.seqno && metric < entry.metric)) || metric == 0xFFFF; + (seqno > entry.seqno || (seqno == entry.seqno && metric < entry.metric)) + || metric == 0xFFFF } - None => return true, + None => true, } } _ => { eprintln!("Error accepting update, control struct did not match update packet"); - return false; + false } } } @@ -492,12 +539,12 @@ impl Router { _ => { let best_route = self.select_best_route(IpAddr::V4(data_packet.dest_ip)); match best_route { - Some (route_entry) => { + Some(route_entry) => { let peer = self.peer_by_ip(route_entry.next_hop).unwrap(); if let Err(e) = peer.send_data_packet(data_packet) { eprintln!("Error sending data packet to peer: {:?}", e); } - }, + } None => { eprintln!("Error sending data packet, no route found"); } @@ -506,16 +553,15 @@ impl Router { } } } - } + } pub fn select_best_route(&self, dest_ip: IpAddr) -> Option { - let inner = self.inner.read().unwrap(); let mut best_route = None; // first look in the selected routing table for a match on the prefix of dest_ip for (route_key, route_entry) in inner.selected_routing_table.table.iter() { if route_key.prefix == dest_ip { - best_route = Some(route_entry.clone()); + best_route = Some(route_entry.clone()); } } // if no match was found, look in the fallback routing table @@ -523,14 +569,14 @@ impl Router { println!("no match in selected routing table, looking in fallback routing table"); for (route_key, route_entry) in inner.fallback_routing_table.table.iter() { if route_key.prefix == dest_ip { - best_route = Some(route_entry.clone()); + best_route = Some(route_entry.clone()); } } } println!("\n\n best route towards {}: {:?}", dest_ip, best_route); - return best_route + best_route } pub async fn propagate_static_route(self) { @@ -592,12 +638,12 @@ impl RouterInner { peer_interfaces: Vec::new(), router_control_tx, router_data_tx, - node_tun: node_tun, + node_tun, selected_routing_table: RoutingTable::new(), fallback_routing_table: RoutingTable::new(), source_table: SourceTable::new(), router_seqno: 0, - static_routes: static_routes, + static_routes, }; Ok(router_inner) @@ -669,7 +715,7 @@ impl RouterInner { for peer in self.peer_interfaces.iter() { let update = ControlPacket::new_update( sr.plen, // static routes have plen 32 - UPDATE_INTERVAL as u16, + UPDATE_INTERVAL, self.router_seqno, // updates receive the seqno of the router peer.link_cost(), // direct connection to other peer, so the only cost is the cost towards the peer sr.prefix, // the prefix of a static route corresponds to the TUN addr of the node @@ -687,14 +733,17 @@ impl RouterInner { let mut updates = vec![]; for sr in self.selected_routing_table.table.iter() { for peer in self.peer_interfaces.iter() { - let peer_link_cost = peer.link_cost(); let update = ControlPacket::new_update( - sr.0.plen, - UPDATE_INTERVAL as u16, + sr.0.plen, + UPDATE_INTERVAL, self.router_seqno, // updates receive the seqno of the router - if sr.1.metric > u16::MAX -1 - peer_link_cost {u16::MAX - 1 } else { sr.1.metric + peer_link_cost }, // the cost of the route is the cost of the route + the cost of the link to the peer + if sr.1.metric > u16::MAX - 1 - peer_link_cost { + u16::MAX - 1 + } else { + sr.1.metric + peer_link_cost + }, // the cost of the route is the cost of the route + the cost of the link to the peer sr.0.prefix, // the prefix of a static route corresponds to the TUN addr of the node self.router_id, ); @@ -710,6 +759,6 @@ impl RouterInner { fn peer_exists(&self, peer_underlay_ip: IpAddr) -> bool { self.peer_interfaces .iter() - .any(|peer| peer.underlay_ip() == peer_underlay_ip) + .any(|peer| peer.underlay_ip() == peer_underlay_ip) } } diff --git a/src/routing_table.rs b/src/routing_table.rs index 806f5b5..728edf5 100644 --- a/src/routing_table.rs +++ b/src/routing_table.rs @@ -1,12 +1,5 @@ -use std::{collections::{HashMap, BTreeMap}, net::IpAddr}; - -use crate::{ - packet::{BabelTLV, ControlStruct}, - peer::Peer, - router::Router, - source_table::SourceKey, - timers::Timer, -}; +use crate::{peer::Peer, source_table::SourceKey}; +use std::{collections::BTreeMap, net::IpAddr}; #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct RouteKey { @@ -15,7 +8,6 @@ pub struct RouteKey { pub neighbor: IpAddr, } - #[derive(Debug, Clone)] pub struct RouteEntry { pub source: SourceKey, @@ -28,6 +20,7 @@ pub struct RouteEntry { } impl RouteEntry { + /* pub fn new( source: SourceKey, neighbor: Peer, @@ -53,7 +46,7 @@ impl RouteEntry { pub fn is_retracted(&self) -> bool { self.metric == 0xFFFF } - + */ pub fn update_metric(&mut self, metric: u16) { self.metric = metric; } @@ -87,8 +80,4 @@ impl RoutingTable { pub fn remove(&mut self, key: &RouteKey) -> Option { self.table.remove(key) } - - pub fn get(&self, key: &RouteKey) -> Option<&RouteEntry> { - self.table.get(key) - } } diff --git a/src/source_table.rs b/src/source_table.rs index e1db0e2..2486a0d 100644 --- a/src/source_table.rs +++ b/src/source_table.rs @@ -1,7 +1,5 @@ use std::{collections::HashMap, net::IpAddr}; -use crate::packet::{BabelTLV, ControlStruct}; - #[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)] pub struct SourceKey { pub prefix: IpAddr, diff --git a/src/timers.rs b/src/timers.rs deleted file mode 100644 index 008ad24..0000000 --- a/src/timers.rs +++ /dev/null @@ -1,70 +0,0 @@ -use std::sync::{Arc, Mutex}; -use std::time::Duration; -use tokio::sync::oneshot; -use tokio::time::sleep; - -use crate::router::Router; - -#[derive(Clone, Debug)] -pub struct Timer { - duration: Arc>, - cancel_tx: Arc>>>, -} - -impl Timer { - pub fn new(duration: Duration) -> Self { - Self { - duration: Arc::new(Mutex::new(duration)), - cancel_tx: Arc::new(Mutex::new(None)), - } - } - - pub fn reset(&self, duration: Duration) { - let mut cancel_tx = self.cancel_tx.lock().unwrap(); - if let Some(tx) = cancel_tx.take() { - let _ = tx.send(()); - } - *self.duration.lock().unwrap() = duration; - } - - // on_expire is of a type that implements the Fn trait, which means it's a function or a closure. - // The + Send + 'static part means this function must also satisfy the Send trait (meaning it can be sent between threads safely) - // and have a 'static lifetime (meaning it doesn't capture any non-'static (i.e., temporary) values from its environment). - // This is necessary because the function could be called at any point in the future, - // potentially long after the context it was created in has gone away. - - async fn run(&self, on_expire: impl Fn() + Send + 'static) { - loop { - let (tx, rx) = oneshot::channel(); - *self.cancel_tx.lock().unwrap() = Some(tx); - let duration = *self.duration.lock().unwrap(); - tokio::select! { - _ = sleep(duration) => { - on_expire(); - } - _ = rx => {} - } - } - } - - pub fn new_ihu_timer(ihu_interval: u64) -> Timer { - let timer = Timer::new(Duration::from_secs(ihu_interval)); - - { - let timer = timer.clone(); - - tokio::spawn(async move { - timer - .run(|| { - println!("IHU Timer expired!"); - // node should be assumed as dead - // on expiry the neighbour link should be set to 0xFFFF - // and the route selection process should be run - }) - .await; - }); - } - - timer - } -} From a92087a8786af300653e4362233d1306610f1fde Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Mon, 22 May 2023 08:50:36 +0000 Subject: [PATCH 88/89] removed control_struct reply method --- src/packet.rs | 9 --------- src/peer.rs | 1 - 2 files changed, 10 deletions(-) diff --git a/src/packet.rs b/src/packet.rs index d04b6d4..0ed5b59 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -34,7 +34,6 @@ impl DataPacket {} #[derive(Debug, Clone)] pub struct ControlStruct { pub control_packet: ControlPacket, - pub control_reply_tx: mpsc::UnboundedSender, pub src_overlay_ip: IpAddr, } @@ -59,14 +58,6 @@ pub struct BabelPacketBody { pub tlv: BabelTLV, } -impl ControlStruct { - pub fn reply(self, control_packet: ControlPacket) { - if let Err(e) = self.control_reply_tx.send(control_packet) { - eprintln!("Error reply: {:?}", e); - } - } -} - impl BabelPacketHeader { pub fn new(body_length: u16) -> Self { Self { diff --git a/src/peer.rs b/src/peer.rs index bb05050..090bc6f 100644 --- a/src/peer.rs +++ b/src/peer.rs @@ -178,7 +178,6 @@ impl PeerInner { // Parse the DataPacket into a ControlStruct as the to_routing_control channel expects let control_struct = ControlStruct { control_packet: packet, - control_reply_tx: control_reply_tx.clone(), src_overlay_ip: overlay_ip, // Note: although this control packet is received from the TCP stream // we set the src_overlay_ip to the overlay_ip of the peer From 1c7e754784885edc4d4b533dfc9ba5a0c812c3b5 Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Mon, 22 May 2023 09:05:25 +0000 Subject: [PATCH 89/89] small refactor --- src/packet.rs | 1 - src/peer.rs | 9 --- src/router.rs | 211 +++++++++++++++++++------------------------------- 3 files changed, 81 insertions(+), 140 deletions(-) diff --git a/src/packet.rs b/src/packet.rs index 4d57471..89935e8 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -1,5 +1,4 @@ use std::net::{IpAddr, Ipv4Addr}; -use tokio::sync::mpsc; use crate::peer::Peer; diff --git a/src/peer.rs b/src/peer.rs index 192980b..1423185 100644 --- a/src/peer.rs +++ b/src/peer.rs @@ -131,8 +131,6 @@ impl PeerInner { // Control channel for peer let (to_peer_control, mut from_routing_control) = mpsc::unbounded_channel::(); - // Control reply channel for peer - let (control_reply_tx, mut control_reply_rx) = mpsc::unbounded_channel::(); // Initialize last_sent_hello_seqno to 0 let hello_seqno = 0; @@ -149,7 +147,6 @@ impl PeerInner { tokio::spawn(async move { loop { select! { - // Received over the TCP stream frame = framed.next() => { match frame { @@ -199,12 +196,6 @@ impl PeerInner { eprintln!("Error writing to stream: {}", e); } } - Some(packet) = control_reply_rx.recv() => { - // Send it over the TCP stream - if let Err(e) = framed.send(Packet::ControlPacket(packet)).await { - eprintln!("Error writing to stream: {}", e); - } - } } } }); diff --git a/src/router.rs b/src/router.rs index 93c31e2..46780c7 100644 --- a/src/router.rs +++ b/src/router.rs @@ -2,7 +2,7 @@ use crate::{ packet::{BabelTLV, BabelTLVType, ControlPacket, ControlStruct, DataPacket}, peer::Peer, routing_table::{RouteEntry, RouteKey, RoutingTable}, - source_table::{FeasibilityDistance, SourceKey, SourceTable}, + source_table::{self, FeasibilityDistance, SourceKey, SourceTable}, }; use rand::Rng; use std::{ @@ -95,7 +95,7 @@ impl Router { pub fn node_tun(&self) -> Arc { self.inner.read().unwrap().node_tun.clone() } - /* + pub fn router_seqno(&self) -> u16 { self.inner.read().unwrap().router_seqno } @@ -103,7 +103,7 @@ impl Router { pub fn increment_router_seqno(&self) { self.inner.write().unwrap().router_seqno += 1; } - */ + pub fn peer_interfaces(&self) -> Vec { self.inner.read().unwrap().peer_interfaces.clone() } @@ -111,7 +111,7 @@ impl Router { pub fn add_peer_interface(&self, peer: Peer) { self.inner.write().unwrap().peer_interfaces.push(peer); } - /* + pub fn remove_peer_interface(&self, peer: Peer) { self.inner.write().unwrap().remove_peer_interface(peer); } @@ -119,7 +119,7 @@ impl Router { pub fn static_routes(&self) -> Vec { self.inner.read().unwrap().static_routes.clone() } - */ + pub fn peer_by_ip(&self, peer_ip: IpAddr) -> Option { self.inner.read().unwrap().peer_by_ip(peer_ip) } @@ -137,6 +137,7 @@ impl Router { matching_peer.map(Clone::clone) } + pub fn print_selected_routes(&self) { let inner = self.inner.read().unwrap(); @@ -175,11 +176,13 @@ impl Router { println!("\n"); } } - + async fn check_for_dead_peers(self) { - let ihu_threshold = tokio::time::Duration::from_secs(8); + let ihu_threshold = tokio::time::Duration::from_secs(8); + loop { + // check for dead peers every second tokio::time::sleep(tokio::time::Duration::from_secs(1)).await; let mut inner = self.inner.write().unwrap(); @@ -200,27 +203,25 @@ impl Router { // vec to store retraction update that need to be sent let mut retraction_updates = Vec::::new(); - + // remove the peer from the peer_interfaces and the routes for dead_peer in dead_peers { inner.remove_peer_interface(dead_peer.clone()); // remove the peer's routes from all routing tables (= all the peers that use the peer as next-hop) - inner - .selected_routing_table - .table - .retain(|_, route_entry| route_entry.next_hop != dead_peer.overlay_ip()); - inner - .fallback_routing_table - .table - .retain(|_, route_entry| route_entry.next_hop != dead_peer.overlay_ip()); + inner.selected_routing_table.table.retain(|_, route_entry| { + route_entry.next_hop != dead_peer.overlay_ip() + }); + inner.fallback_routing_table.table.retain(|_, route_entry| { + route_entry.next_hop != dead_peer.overlay_ip() + }); - // create retraction update for each dead peer + // create retraction update for each dead peer let retraction_update = ControlPacket::new_update( - 32, - UPDATE_INTERVAL, - inner.router_seqno, - 0xFFFF, - dead_peer.overlay_ip(), // todo: fix to use actual prefix, not IP + 32, + UPDATE_INTERVAL as u16, + inner.router_seqno, + 0xFFFF, + dead_peer.overlay_ip(), // todo: fix to use actual prefix, not IP inner.router_id, ); retraction_updates.push(retraction_update); @@ -231,12 +232,15 @@ impl Router { for peer in inner.peer_interfaces.iter() { for ru in retraction_updates.iter() { if let Err(e) = peer.send_control_packet(ru.clone()) { - eprintln!("Error sending retraction update to peer: {e}"); + eprintln!("Error sending retraction update to peer"); } } } + } } + + async fn handle_incoming_control_packet( self, @@ -259,12 +263,13 @@ impl Router { fn handle_incoming_hello(&self, control_struct: ControlStruct) { // let destination_ip = control_struct.src_overlay_ip; // control_struct.reply(ControlPacket::new_ihu(IHU_INTERVAL, destination_ip)); - + // Upon receiving and Hello message from a peer, this node has to send a IHU back if let Some(source_peer) = self.source_peer_from_control_struct(control_struct) { let ihu = ControlPacket::new_ihu(IHU_INTERVAL, source_peer.overlay_ip()); match source_peer.send_control_packet(ihu) { - Ok(()) => {} + Ok(()) => { + }, Err(e) => { eprintln!("Error sending IHU to peer: {e}"); } @@ -283,6 +288,8 @@ impl Router { source_peer.set_link_cost(time_diff as u16); + + // set the last_received_ihu for this peer source_peer.set_time_last_received_ihu(tokio::time::Instant::now()); } @@ -291,55 +298,39 @@ impl Router { // incoming update can only be received by a Peer this node has a direct link to fn handle_incoming_update(&self, update: ControlStruct) { match update.control_packet.body.tlv { - BabelTLV::Update { - plen, - interval: _, - seqno, - metric, - prefix, - router_id, - } => { + BabelTLV::Update { plen, interval: _, seqno, metric, prefix, router_id } => { + // create route key from incoming update control struct // we need the address of the neighbour; this corresponds to the source ip of the control struct as the update is received from the neighbouring peer let neighbor_ip = update.src_overlay_ip; - let route_key_from_update = RouteKey { - neighbor: neighbor_ip, - plen, + let route_key_from_update = RouteKey { + neighbor: neighbor_ip, + plen, prefix, }; - // used later to filter out static route + // used later to filter out static route if self.route_key_is_from_static_route(&route_key_from_update) { - return; + return; } let mut inner = self.inner.write().unwrap(); // check if a route entry with the same route key exists in both routing tables - let route_entry_exists = inner - .selected_routing_table - .table - .contains_key(&route_key_from_update) - || inner - .fallback_routing_table - .table - .contains_key(&route_key_from_update); + let route_entry_exists = inner.selected_routing_table.table.contains_key(&route_key_from_update) || inner.fallback_routing_table.table.contains_key(&route_key_from_update); // if no entry exists (based on prefix, plen AND neighbor field) if !route_entry_exists { // if the update is unfeasible, or the metric is inifinite, we ignore the update if metric == u16::MAX || !self.update_feasible(&update, &inner.source_table) { - // do nothing, just ignore - } else { + return; + } + else { // this means that the update is feasible and the metric is not infinite // create a new route entry and add it to the routing table (which requires a new source entry to be created as well) - let source_key = SourceKey { - prefix, - plen, - router_id, - }; - let fd = FeasibilityDistance { metric, seqno }; + let source_key = SourceKey { prefix, plen, router_id }; + let fd = FeasibilityDistance{ metric, seqno }; inner.source_table.insert(source_key, fd); let route_key = RouteKey { @@ -352,7 +343,7 @@ impl Router { neighbor: inner.peer_by_ip(neighbor_ip).unwrap(), metric, seqno, - next_hop: neighbor_ip, + next_hop: neighbor_ip, selected: true, }; @@ -366,14 +357,11 @@ impl Router { // this means we should remove the entry from the selected routing table to_remove.push(r.0.clone()); break; // we can break, as there will be max 1 better route in selected table at any point in time (hence 'selected') - // metric of update is greater than entry's metric + // metric of update is greater than entry's metric } else if metric >= r.1.metric { // this means that there is already a better route in our selected routing table, - // so we should add it to fallback instead - inner - .fallback_routing_table - .table - .insert(route_key, route_entry); + // so we should add it to fallback instead + inner.fallback_routing_table.table.insert(route_key.clone(), route_entry.clone()); return; // quit the function, work is done here } } @@ -385,10 +373,8 @@ impl Router { } } // insert the route into selected (we might have placed one other route, that was previously the best, in the fallback) - inner - .selected_routing_table - .table - .insert(route_key, route_entry); + inner.selected_routing_table.table.insert(route_key, route_entry); + } } // entry exists @@ -397,64 +383,34 @@ impl Router { if self.update_feasible(&update, &inner.source_table) && metric == u16::MAX { // if the update is a retraction, we remove the entry from the routing tables // we also remove the corresponding source entry??? - if inner - .selected_routing_table - .table - .contains_key(&route_key_from_update) - { + if inner.selected_routing_table.table.contains_key(&route_key_from_update) { inner.selected_routing_table.remove(&route_key_from_update); } - if inner - .fallback_routing_table - .table - .contains_key(&route_key_from_update) - { + if inner.fallback_routing_table.table.contains_key(&route_key_from_update) { inner.fallback_routing_table.remove(&route_key_from_update); } // remove the corresponding source entry - let source_key = SourceKey { - prefix, - plen, - router_id, - }; + let source_key = SourceKey { prefix, plen, router_id }; inner.source_table.remove(&source_key); return; } // if the entry is currently selected, the update is unfeasible, and the router-id of the update is equal // to the router-id of the entry, then we ignore the update - if inner - .selected_routing_table - .table - .contains_key(&route_key_from_update) - { - let route_entry = inner - .selected_routing_table - .table - .get(&route_key_from_update) - .unwrap(); - if !self.update_feasible(&update, &inner.source_table) - && route_entry.source.router_id == router_id - { + if inner.selected_routing_table.table.contains_key(&route_key_from_update) { + let route_entry = inner.selected_routing_table.table.get(&route_key_from_update).unwrap(); + if !self.update_feasible(&update, &inner.source_table) && route_entry.source.router_id == router_id { return; } // update the entry's seqno, metric and router-id - let route_entry = inner - .selected_routing_table - .table - .get_mut(&route_key_from_update) - .unwrap(); + let route_entry = inner.selected_routing_table.table.get_mut(&route_key_from_update).unwrap(); route_entry.update_seqno(seqno); route_entry.update_metric(metric); route_entry.update_router_id(router_id); } // otherwise else { - let route_entry = inner - .fallback_routing_table - .table - .get_mut(&route_key_from_update) - .unwrap(); + let route_entry = inner.fallback_routing_table.table.get_mut(&route_key_from_update).unwrap(); // update the entry's seqno, metric and router-id route_entry.update_seqno(seqno); route_entry.update_metric(metric); @@ -462,19 +418,17 @@ impl Router { if !self.update_feasible(&update, &inner.source_table) { // if the update is unfeasible, we remove the entry from the selected routing table - inner - .selected_routing_table - .table - .remove(&route_key_from_update); + inner.selected_routing_table.table.remove(&route_key_from_update); // should we remove it from the selected and add it to fallback here??? } } } - } + }, _ => { panic!("Received update with wrong TLV type"); } } + } fn route_key_is_from_static_route(&self, route_key: &RouteKey) -> bool { @@ -485,7 +439,7 @@ impl Router { return true; } } - false + return false; } // we gebruiken self niet in de functie --> daarop functie eigenllijk beter op de source table implementeren @@ -509,15 +463,14 @@ impl Router { }; match source_table.get(&source_key) { Some(&entry) => { - (seqno > entry.seqno || (seqno == entry.seqno && metric < entry.metric)) - || metric == 0xFFFF + return (seqno > entry.seqno|| (seqno == entry.seqno && metric < entry.metric)) || metric == 0xFFFF; } - None => true, + None => return true, } } _ => { eprintln!("Error accepting update, control struct did not match update packet"); - false + return false; } } } @@ -539,12 +492,12 @@ impl Router { _ => { let best_route = self.select_best_route(IpAddr::V4(data_packet.dest_ip)); match best_route { - Some(route_entry) => { + Some (route_entry) => { let peer = self.peer_by_ip(route_entry.next_hop).unwrap(); if let Err(e) = peer.send_data_packet(data_packet) { eprintln!("Error sending data packet to peer: {:?}", e); } - } + }, None => { eprintln!("Error sending data packet, no route found"); } @@ -553,15 +506,16 @@ impl Router { } } } - } + } pub fn select_best_route(&self, dest_ip: IpAddr) -> Option { + let inner = self.inner.read().unwrap(); let mut best_route = None; // first look in the selected routing table for a match on the prefix of dest_ip for (route_key, route_entry) in inner.selected_routing_table.table.iter() { if route_key.prefix == dest_ip { - best_route = Some(route_entry.clone()); + best_route = Some(route_entry.clone()); } } // if no match was found, look in the fallback routing table @@ -569,14 +523,14 @@ impl Router { println!("no match in selected routing table, looking in fallback routing table"); for (route_key, route_entry) in inner.fallback_routing_table.table.iter() { if route_key.prefix == dest_ip { - best_route = Some(route_entry.clone()); + best_route = Some(route_entry.clone()); } } } println!("\n\n best route towards {}: {:?}", dest_ip, best_route); - best_route + return best_route } pub async fn propagate_static_route(self) { @@ -638,12 +592,12 @@ impl RouterInner { peer_interfaces: Vec::new(), router_control_tx, router_data_tx, - node_tun, + node_tun: node_tun, selected_routing_table: RoutingTable::new(), fallback_routing_table: RoutingTable::new(), source_table: SourceTable::new(), router_seqno: 0, - static_routes, + static_routes: static_routes, }; Ok(router_inner) @@ -715,7 +669,7 @@ impl RouterInner { for peer in self.peer_interfaces.iter() { let update = ControlPacket::new_update( sr.plen, // static routes have plen 32 - UPDATE_INTERVAL, + UPDATE_INTERVAL as u16, self.router_seqno, // updates receive the seqno of the router peer.link_cost(), // direct connection to other peer, so the only cost is the cost towards the peer sr.prefix, // the prefix of a static route corresponds to the TUN addr of the node @@ -733,17 +687,14 @@ impl RouterInner { let mut updates = vec![]; for sr in self.selected_routing_table.table.iter() { for peer in self.peer_interfaces.iter() { + let peer_link_cost = peer.link_cost(); let update = ControlPacket::new_update( - sr.0.plen, - UPDATE_INTERVAL, + sr.0.plen, + UPDATE_INTERVAL as u16, self.router_seqno, // updates receive the seqno of the router - if sr.1.metric > u16::MAX - 1 - peer_link_cost { - u16::MAX - 1 - } else { - sr.1.metric + peer_link_cost - }, // the cost of the route is the cost of the route + the cost of the link to the peer + if sr.1.metric > u16::MAX -1 - peer_link_cost {u16::MAX - 1 } else { sr.1.metric + peer_link_cost }, // the cost of the route is the cost of the route + the cost of the link to the peer sr.0.prefix, // the prefix of a static route corresponds to the TUN addr of the node self.router_id, ); @@ -759,6 +710,6 @@ impl RouterInner { fn peer_exists(&self, peer_underlay_ip: IpAddr) -> bool { self.peer_interfaces .iter() - .any(|peer| peer.underlay_ip() == peer_underlay_ip) + .any(|peer| peer.underlay_ip() == peer_underlay_ip) } }