Commit a7a7f9d9 authored by nanamicat's avatar nanamicat

route table

parent 1ccde179
...@@ -249,6 +249,12 @@ dependencies = [ ...@@ -249,6 +249,12 @@ dependencies = [
"const-random", "const-random",
] ]
[[package]]
name = "either"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
[[package]] [[package]]
name = "encoding_rs" name = "encoding_rs"
version = "0.8.35" version = "0.8.35"
...@@ -625,6 +631,18 @@ name = "ipnet" ...@@ -625,6 +631,18 @@ name = "ipnet"
version = "2.11.0" version = "2.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130"
dependencies = [
"serde",
]
[[package]]
name = "itertools"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
dependencies = [
"either",
]
[[package]] [[package]]
name = "itoa" name = "itoa"
...@@ -963,6 +981,8 @@ dependencies = [ ...@@ -963,6 +981,8 @@ dependencies = [
"bincode", "bincode",
"config", "config",
"hickory-resolver", "hickory-resolver",
"ipnet",
"itertools",
"netlink-packet-route", "netlink-packet-route",
"netlink-sys", "netlink-sys",
"rand", "rand",
......
...@@ -21,3 +21,5 @@ tracing = "0.1.44" ...@@ -21,3 +21,5 @@ tracing = "0.1.44"
tracing-subscriber = "0.3.22" tracing-subscriber = "0.3.22"
rand = "0.9.2" rand = "0.9.2"
saturating_cast = "0.1.0" saturating_cast = "0.1.0"
ipnet = { version = "2.11.0", features = ["serde"] }
itertools = "0.14.0"
max_width = 180 max_width = 200
\ No newline at end of file \ No newline at end of file
use std::net::Ipv4Addr; use std::net::Ipv4Addr;
use ipnet::Ipv4Net;
use serde::Deserialize; use serde::Deserialize;
#[derive(Deserialize)] #[derive(Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct Router { pub struct Router {
pub id: u8, pub id: u8,
// pub name: String, pub name: String,
pub address: Ipv4Addr, pub address: Ipv4Addr,
// pub location: String, // pub location: String,
// pub user: String, // pub user: String,
...@@ -38,3 +39,14 @@ pub struct Router { ...@@ -38,3 +39,14 @@ pub struct Router {
// pub include_routers: HashSet<String>, // pub include_routers: HashSet<String>,
// pub exclude_routers: HashSet<String>, // pub exclude_routers: HashSet<String>,
// } // }
#[derive(Clone, Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Subnet {
// pub id: u32,
pub router: String,
pub subnet: Ipv4Net,
// pub interface: Option<String>,
// pub comment: Option<String>,
// pub oc_server: Option<String>,
}
...@@ -8,7 +8,6 @@ mod settings; ...@@ -8,7 +8,6 @@ mod settings;
use crate::{ use crate::{
connection::Connection, connection::Connection,
data::Router as RouterData,
protocol::{Hello, MessageType, Uplink}, protocol::{Hello, MessageType, Uplink},
router::Router, router::Router,
server::Server, server::Server,
...@@ -16,6 +15,7 @@ use crate::{ ...@@ -16,6 +15,7 @@ use crate::{
}; };
use config::Config; use config::Config;
use hickory_resolver::Resolver; use hickory_resolver::Resolver;
use itertools::Itertools;
use std::{collections::BTreeMap, fs, time::SystemTime}; use std::{collections::BTreeMap, fs, time::SystemTime};
use tokio::{ use tokio::{
net::UdpSocket, net::UdpSocket,
...@@ -26,14 +26,22 @@ use tokio::{ ...@@ -26,14 +26,22 @@ use tokio::{
async fn main() -> anyhow::Result<()> { async fn main() -> anyhow::Result<()> {
tracing_subscriber::fmt::init(); tracing_subscriber::fmt::init();
let config: Settings = Config::builder().add_source(config::Environment::default()).build()?.try_deserialize()?; let config: Settings = Config::builder().add_source(config::Environment::default()).build()?.try_deserialize()?;
let routers_data = serde_json::from_slice::<Vec<RouterData>>(&fs::read("import/data/Router.json")?)?; let mut routers = {
let mut routers: BTreeMap<u8, Router> = routers_data.into_iter().map(|r| (r.id, Router::new(r, &config))).collect(); let routers_data = serde_json::from_slice::<Vec<data::Router>>(&fs::read("import/data/Router.json")?)?;
let subnets_data = serde_json::from_slice::<Vec<data::Subnet>>(&fs::read("import/data/Subnet.json")?)?;
let mut subnets_map = subnets_data.into_iter().into_group_map_by(|s| s.router.clone());
routers_data
.into_iter()
.map(|r| (r.id, Router::new(subnets_map.remove(&r.name).unwrap_or_default().into_iter().map(|s| s.subnet).collect(), r, &config)))
.collect::<BTreeMap<u8, Router>>()
};
let connections = serde_json::from_slice::<BTreeMap<u8, BTreeMap<u8, Connection>>>(&fs::read("import/connections.json")?)?; let connections = serde_json::from_slice::<BTreeMap<u8, BTreeMap<u8, Connection>>>(&fs::read("import/connections.json")?)?;
// let groups: Vec<GatewayGroup> = serde_json::from_slice(&fs::read("import/GatewayGroup.json")?)?; // let groups: Vec<GatewayGroup> = serde_json::from_slice(&fs::read("import/GatewayGroup.json")?)?;
let mut server = Server::new( let mut server = Server::new(
config.id, config.id, &routers,
&routers,
// groups // groups
// .iter() // .iter()
// .map(|g| (g.id, g.routers(&groups, &routers_data))) // .map(|g| (g.id, g.routers(&groups, &routers_data)))
......
use crate::{data, data::Router as RouterData, protocol::{Hello, PeerQuality}, settings::{Settings, INTERVAL, WINDOW}}; use crate::{
data,
protocol::{Hello, PeerQuality},
settings::{INTERVAL, Settings, WINDOW},
};
use ipnet::Ipv4Net;
use saturating_cast::SaturatingCast; use saturating_cast::SaturatingCast;
use std::{ use std::{
collections::BTreeMap, collections::BTreeMap,
...@@ -15,26 +20,31 @@ pub struct Router { ...@@ -15,26 +20,31 @@ pub struct Router {
receive: u64, receive: u64,
remote_time: u32, remote_time: u32,
local_time: Instant, local_time: Instant,
pub(crate) data: data::Router pub(crate) data: data::Router,
pub(crate) subnets: Vec<Ipv4Net>,
} }
impl Router { impl Router {
pub fn link_address(from: u8, to: u8) -> Ipv4Addr {
Ipv4Addr::from([10, 200, to, from])
}
pub fn get(routers: &mut BTreeMap<u8, Router>, link_address: SocketAddr) -> Option<&mut Router> { pub fn get(routers: &mut BTreeMap<u8, Router>, link_address: SocketAddr) -> Option<&mut Router> {
match link_address { match link_address {
SocketAddr::V4(addr) => routers.get_mut(&addr.ip().octets()[2]), SocketAddr::V4(addr) => routers.get_mut(&addr.ip().octets()[2]),
SocketAddr::V6(_) => None, SocketAddr::V6(_) => None,
} }
} }
pub fn new(data: RouterData, config: &Settings) -> Router { pub fn new(subnets: Vec<Ipv4Net>, data: data::Router, config: &Settings) -> Router {
Router { Router {
link_address: SocketAddr::new(IpAddr::V4(Ipv4Addr::from([10, 200, data.id, config.id])), config.bind.port()), link_address: SocketAddr::new(IpAddr::V4(Router::link_address(config.id, data.id)), config.bind.port()),
remote_time: rand::random(), remote_time: rand::random(),
receive: 0, receive: 0,
jitter: 0, jitter: 0,
prev_delay: 0, prev_delay: 0,
delay: 0, delay: 0,
local_time: Instant::now(), local_time: Instant::now(),
data data,
subnets,
} }
} }
......
use crate::connection::Connection; use crate::{
use crate::protocol::{Downlink, MessageType, Uplink}; connection::Connection,
use crate::router::Router; protocol::{Downlink, MessageType, Uplink},
use crate::settings::{ROUTE_PROTOCOL, Settings}; router::Router,
settings::{ROUTE_PROTOCOL, Settings},
};
use rtnetlink::RouteMessageBuilder; use rtnetlink::RouteMessageBuilder;
use std::collections::BTreeMap; use std::{collections::BTreeMap, net::Ipv4Addr};
use std::net::Ipv4Addr;
pub struct Server { pub struct Server {
pub(crate) online: bool, pub(crate) online: bool,
...@@ -16,7 +17,7 @@ pub struct Server { ...@@ -16,7 +17,7 @@ pub struct Server {
impl Server { impl Server {
pub fn new(id: u8, routers: &BTreeMap<u8, Router>) -> Self { pub fn new(id: u8, routers: &BTreeMap<u8, Router>) -> Self {
let (connection, handle) = rtnetlink::new_connection().unwrap(); let (connection, handle, _) = rtnetlink::new_connection().unwrap();
tokio::spawn(connection); tokio::spawn(connection);
Server { Server {
online: false, online: false,
...@@ -27,14 +28,7 @@ impl Server { ...@@ -27,14 +28,7 @@ impl Server {
} }
} }
pub async fn on_message( pub async fn on_message(&mut self, mut message: Downlink, routers: &BTreeMap<u8, Router>, connections: &BTreeMap<u8, Connection>, config: &Settings) -> Option<Uplink> {
&mut self,
mut message: Downlink,
routers: &BTreeMap<u8, Router>,
connections: &BTreeMap<u8, Connection>,
config: &Settings, // routers: &mut HashMap<u8, Router>,
// self_peer: &Hello,
) -> Option<Uplink> {
if message.ack != self.version { if message.ack != self.version {
return None; return None;
} }
...@@ -48,6 +42,7 @@ impl Server { ...@@ -48,6 +42,7 @@ impl Server {
} }
self.via.append(&mut message.via); self.via.append(&mut message.via);
self.plan.append(&mut message.plan); self.plan.append(&mut message.plan);
self.write(&self.via, routers, connections, config).await;
Some(Uplink { Some(Uplink {
id: config.id, id: config.id,
action: MessageType::Update, action: MessageType::Update,
...@@ -68,6 +63,7 @@ impl Server { ...@@ -68,6 +63,7 @@ impl Server {
(true, MessageType::Update) => { (true, MessageType::Update) => {
self.via.append(&mut message.via); self.via.append(&mut message.via);
self.plan.append(&mut message.plan); self.plan.append(&mut message.plan);
self.write(&self.via, routers, connections, config).await;
Some(Uplink { Some(Uplink {
id: config.id, id: config.id,
action: MessageType::Update, action: MessageType::Update,
...@@ -80,24 +76,17 @@ impl Server { ...@@ -80,24 +76,17 @@ impl Server {
_ => None, _ => None,
} }
} }
pub async fn write(&self, via: &BTreeMap<u8, u8>, routers: &BTreeMap<u8, Router>, connections: &BTreeMap<u8, Connection>, config: &Settings) { pub async fn write(&self, via: &BTreeMap<u8, u8>, routers: &BTreeMap<u8, Router>, connections: &BTreeMap<u8, Connection>, config: &Settings) {
for (to_id, via_id) in via.iter() { for (to_id, via_id) in via.iter() {
let to = routers[to_id]; let to = &routers[to_id];
let via = routers[via_id]; for (destination, prefix) in std::iter::once((to.data.address, 32)).chain(to.subnets.iter().map(|s| (s.addr(), s.prefix_len()))) {
if connections.contains_key(via_id) { let builder = RouteMessageBuilder::<Ipv4Addr>::new().destination_prefix(destination, prefix).protocol(ROUTE_PROTOCOL);
self.handle let msg = if connections.contains_key(via_id) {
.route() builder.gateway(Router::link_address(config.id, *via_id)).build()
.add( } else {
RouteMessageBuilder::<Ipv4Addr>::new() builder.kind(netlink_packet_route::route::RouteType::Unreachable).build()
.destination_prefix(to.data.address, 32) };
.gateway(via.link_address.ip()) self.handle.route().add(msg).replace().execute().await.unwrap_or_else(|e| panic!("{}", e));
.protocol(ROUTE_PROTOCOL)
.build(),
)
.execute()
.await
.unwrap();
} }
} }
} }
......
use hickory_resolver::Resolver;
use hickory_resolver::name_server::GenericConnector; use hickory_resolver::name_server::GenericConnector;
use hickory_resolver::proto::runtime::TokioRuntimeProvider; use hickory_resolver::proto::runtime::TokioRuntimeProvider;
use hickory_resolver::Resolver;
use netlink_packet_route::route::RouteProtocol; use netlink_packet_route::route::RouteProtocol;
use serde::Deserialize; use serde::Deserialize;
use std::net::SocketAddr; use std::net::SocketAddr;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment