pub use crate::netlink::{Ipv4Route, Neighbor, get_ipv4_routes, get_neighbors};
use ipnet::Ipv4Net;
use prefix_trie::PrefixMap;
use std::collections::HashMap;
use std::io;
use std::net::Ipv4Addr;
#[derive(Debug)]
pub struct Router {
pub if_index: u32,
pub neighbors: HashMap<Ipv4Addr, Neighbor>,
pub routes: PrefixMap<Ipv4Net, Ipv4Route>,
}
impl Router {
pub fn new(if_index: u32) -> Self {
Router {
if_index,
routes: PrefixMap::new(),
neighbors: HashMap::new(),
}
}
pub fn route(&mut self, dest_ip: &Ipv4Addr) -> Option<NextHop> {
let dest_net = Ipv4Net::from(*dest_ip);
if let Some((_, route)) = self.routes.get_lpm(&dest_net) {
let ip = route.gateway.as_ref().unwrap_or(dest_ip);
if let Some(neighbour) = self.neighbors.get(ip) {
return Some(NextHop {
ip_addr: *ip,
mac_addr: Some(neighbour.mac),
});
}
};
if let Some(neighbour) = self.neighbors.get(dest_ip) {
return Some(NextHop {
ip_addr: *dest_ip,
mac_addr: Some(neighbour.mac),
});
}
None
}
pub fn refresh(&mut self) -> Result<(), io::Error> {
let mut routes = get_ipv4_routes(Some(self.if_index))?;
let neighbors = get_neighbors(Some(self.if_index))?;
let mut prefix_map = PrefixMap::new();
for route in routes.drain(..) {
let dest_net = Ipv4Net::new(route.destination, route.dest_prefix).map_err(|_| {
io::Error::new(io::ErrorKind::InvalidData, "Invalid destination prefix")
})?;
if route.gateway.is_some() {
prefix_map.insert(dest_net, route);
}
}
self.neighbors = neighbors.into_iter().map(|n| (n.ip, n)).collect();
self.routes = prefix_map;
Ok(())
}
}
#[derive(Clone, Debug)]
pub struct NextHop {
pub ip_addr: Ipv4Addr,
pub mac_addr: Option<[u8; 6]>,
}