Commit a7a7f9d9 authored by nanamicat's avatar nanamicat

route table

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