Commit a07d1f23 authored by nanamicat's avatar nanamicat

delay

parent 43872183
Pipeline #42420 passed with stages
in 53 seconds
......@@ -66,6 +66,7 @@ async fn main() -> Result<()> {
let socket = UdpSocket::bind(config.udp_bind).await?;
println!("UDP listening on {}", config.udp_bind);
let mut buf = [0u8; u16::MAX as usize]; // Max UDP size
let start = Instant::now();
loop {
let (len, addr) = socket.recv_from(&mut buf).await?;
......@@ -81,14 +82,15 @@ async fn main() -> Result<()> {
if updating.router_id != 0 && !routers.get(&updating.router_id).context("router not found")?.is_online() {
updating.router_id = 0;
}
tracing::info!("recv {:?}", uplink);
tracing::debug!("recv {:?}", uplink);
// 处理收到的消息
if let Some(router) = routers.get_mut(&uplink.id)
&& let Some(downlink) = router.on_message(&mut uplink, addr, &mut updating, now)
{
tracing::info!("sync to {}: {:?}", router.id, downlink);
tracing::debug!("sync to {}: {:?}", router.id, downlink);
send(&downlink, &mut buf, &socket, &addr).await?;
} else if updating.router_id == 0
&& now.duration_since(start) >= TIMEOUT // 刚启动时静默,先学习
&& let Some(router) = routers.get(&uplink.id)
&& let Some(downlink) = router.update(&routers, &connections)
{
......
......@@ -10,13 +10,6 @@ pub struct Quality {
}
impl Quality {
pub const UNREACHABLE: Quality = Quality {
delay: 0,
jitter: 0,
reliability: 0.0,
cost: 0,
};
pub fn concat(&mut self, next: &PeerQuality, cost: u32) {
self.delay += next.delay as i32;
self.jitter += next.jitter as u32;
......@@ -33,8 +26,10 @@ impl Quality {
self.delay + ((1.0 - self.reliability) * 10000.0).round() as i32 + self.cost as i32
}
}
}
pub(crate) fn default() -> Self {
impl Default for Quality {
fn default() -> Self {
Self {
delay: 0,
jitter: 0,
......
......@@ -97,6 +97,7 @@ impl Router {
self.via.append(&mut uplink.via);
self.plan.append(&mut uplink.plan);
self.online(addr, now);
tracing::info!("router {} full via={:?}", self.id, self.via);
}
None
}
......@@ -136,19 +137,24 @@ impl Router {
for to in routers.values().filter(|&r| r != self) {
let current_router = routers.get(self.via.get(&to.id).unwrap()).unwrap();
let current_metric = self.route_quality(to, current_router, routers, connections).metric();
let current_metric = self.route_quality(to, current_router, routers, connections).map_or(i32::MAX, |r| r.metric());
let candidate: Vec<(&Router, i32)> = connections[&self.id]
.keys()
.map(|id| routers.get(id).unwrap())
.map(|r| (r, self.route_quality(to, r, routers, connections).metric()))
.filter_map(|r| self.route_quality(to, r, routers, connections).map(|q| (r, q.metric())))
.collect();
let (best_router, best_metric) = candidate.iter().min_by_key(|(_, m)| m).unwrap();
let best_router = if *best_metric == i32::MAX { to } else { best_router };
match candidate.iter().min_by_key(|(_, m)| m) {
None if current_router != to => {
// 无论如何都不可达就标记为直连
if current_router != best_router && (*best_metric == i32::MAX || *best_metric + THROTTLE < current_metric) {
changed_via.insert(to.id, to.id);
}
Some((best_router, best_metric)) if current_router != *best_router && (*best_metric + THROTTLE < current_metric) => {
changed_via.insert(to.id, best_router.id);
}
_ => {}
}
}
if changed_via.len() > 0 {
......@@ -164,34 +170,23 @@ impl Router {
}
}
pub fn route_quality(&self, to: &Router, via: &Router, routers: &BTreeMap<u8, Router>, connections: &BTreeMap<u8, BTreeMap<u8, ConnectionData>>) -> Quality {
pub fn route_quality(&self, to: &Router, via: &Router, routers: &BTreeMap<u8, Router>, connections: &BTreeMap<u8, BTreeMap<u8, ConnectionData>>) -> Option<Quality> {
assert!(self != to);
assert!(self != via);
let mut result: Quality = Quality::default();
let mut route = vec![self, via];
let mut result: Quality = Default::default();
let mut route = vec![self];
let mut current = self;
let mut next = via;
loop {
if !next.is_online() {
return Quality::UNREACHABLE;
}
// 不通的情况 via 会标记为直连,实际不可达
match next.peers.get(&current.id) {
None => return Quality::UNREACHABLE,
while current != to {
let next = if current == self { via } else { &routers[&current.via[&to.id]] };
match next.peers.get(&current.id).filter(|_| next.is_online() && !route.contains(&next)) {
None => return None,
Some(quality) if quality.reliability == 0 => return None,
Some(quality) => result.concat(quality, connections[&current.id][&next.id].metric),
}
// Next hop
current = next;
next = &routers[&current.via[&to.id]];
// 检查环路
if route.contains(&next) {
return Quality::UNREACHABLE;
}
route.push(next);
current = next;
}
Some(result)
}
}
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