use ospf route to propogate foreign network info
Some checks are pending
EasyTier Core / pre_job (push) Waiting to run
EasyTier Core / build (freebsd-13.2-x86_64, 13.2, ubuntu-latest, x86_64-unknown-freebsd) (push) Blocked by required conditions
EasyTier Core / build (linux-aarch64, ubuntu-latest, aarch64-unknown-linux-musl) (push) Blocked by required conditions
EasyTier Core / build (linux-arm, ubuntu-latest, arm-unknown-linux-musleabi) (push) Blocked by required conditions
EasyTier Core / build (linux-armhf, ubuntu-latest, arm-unknown-linux-musleabihf) (push) Blocked by required conditions
EasyTier Core / build (linux-armv7, ubuntu-latest, armv7-unknown-linux-musleabi) (push) Blocked by required conditions
EasyTier Core / build (linux-armv7hf, ubuntu-latest, armv7-unknown-linux-musleabihf) (push) Blocked by required conditions
EasyTier Core / build (linux-mips, ubuntu-latest, mips-unknown-linux-musl) (push) Blocked by required conditions
EasyTier Core / build (linux-mipsel, ubuntu-latest, mipsel-unknown-linux-musl) (push) Blocked by required conditions
EasyTier Core / build (linux-x86_64, ubuntu-latest, x86_64-unknown-linux-musl) (push) Blocked by required conditions
EasyTier Core / build (macos-aarch64, macos-latest, aarch64-apple-darwin) (push) Blocked by required conditions
EasyTier Core / build (macos-x86_64, macos-latest, x86_64-apple-darwin) (push) Blocked by required conditions
EasyTier Core / build (windows-x86_64, windows-latest, x86_64-pc-windows-msvc) (push) Blocked by required conditions
EasyTier Core / core-result (push) Blocked by required conditions
EasyTier GUI / pre_job (push) Waiting to run
EasyTier GUI / build-gui (linux-aarch64, aarch64-unknown-linux-gnu, ubuntu-latest, aarch64-unknown-linux-musl) (push) Blocked by required conditions
EasyTier GUI / build-gui (linux-x86_64, x86_64-unknown-linux-gnu, ubuntu-latest, x86_64-unknown-linux-musl) (push) Blocked by required conditions
EasyTier GUI / build-gui (macos-aarch64, aarch64-apple-darwin, macos-latest, aarch64-apple-darwin) (push) Blocked by required conditions
EasyTier GUI / build-gui (macos-x86_64, x86_64-apple-darwin, macos-latest, x86_64-apple-darwin) (push) Blocked by required conditions
EasyTier GUI / build-gui (windows-x86_64, x86_64-pc-windows-msvc, windows-latest, x86_64-pc-windows-msvc) (push) Blocked by required conditions
EasyTier GUI / gui-result (push) Blocked by required conditions
EasyTier Mobile / pre_job (push) Waiting to run
EasyTier Mobile / build-mobile (android, ubuntu-latest, android) (push) Blocked by required conditions
EasyTier Mobile / mobile-result (push) Blocked by required conditions
EasyTier Test / pre_job (push) Waiting to run
EasyTier Test / test (push) Blocked by required conditions

This commit is contained in:
sijie.sun 2024-09-22 10:10:32 +08:00 committed by Sijie.Sun
parent fb8d262554
commit aca9a0e35b
7 changed files with 449 additions and 175 deletions

View File

@ -151,6 +151,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
) )
.type_attribute("peer_rpc.DirectConnectedPeerInfo", "#[derive(Hash)]") .type_attribute("peer_rpc.DirectConnectedPeerInfo", "#[derive(Hash)]")
.type_attribute("peer_rpc.PeerInfoForGlobalMap", "#[derive(Hash)]") .type_attribute("peer_rpc.PeerInfoForGlobalMap", "#[derive(Hash)]")
.type_attribute("peer_rpc.ForeignNetworkRouteInfoKey", "#[derive(Hash, Eq)]")
.type_attribute("common.RpcDescriptor", "#[derive(Hash, Eq)]") .type_attribute("common.RpcDescriptor", "#[derive(Hash, Eq)]")
.service_generator(Box::new(rpc_build::ServiceGenerator::new())) .service_generator(Box::new(rpc_build::ServiceGenerator::new()))
.btree_map(&["."]) .btree_map(&["."])

View File

@ -5,7 +5,10 @@ only forward packets of peers that directly connected to this node.
in future, with the help wo peer center we can forward packets of peers that in future, with the help wo peer center we can forward packets of peers that
connected to any node in the local network. connected to any node in the local network.
*/ */
use std::sync::{Arc, Weak}; use std::{
sync::{Arc, Weak},
time::SystemTime,
};
use dashmap::DashMap; use dashmap::DashMap;
use tokio::{ use tokio::{
@ -44,33 +47,33 @@ use super::{
}; };
struct ForeignNetworkEntry { struct ForeignNetworkEntry {
my_peer_id: PeerId,
global_ctx: ArcGlobalCtx, global_ctx: ArcGlobalCtx,
network: NetworkIdentity, network: NetworkIdentity,
peer_map: Arc<PeerMap>, peer_map: Arc<PeerMap>,
relay_data: bool, relay_data: bool,
route: ArcRoute, route: ArcRoute,
peer_rpc: Weak<PeerRpcManager>, peer_rpc: Weak<PeerRpcManager>,
rpc_sender: UnboundedSender<ZCPacket>,
packet_recv: Mutex<Option<PacketRecvChanReceiver>>,
tasks: Mutex<JoinSet<()>>,
} }
impl ForeignNetworkEntry { impl ForeignNetworkEntry {
fn new( fn new(
network: NetworkIdentity, network: NetworkIdentity,
packet_sender: PacketRecvChan,
global_ctx: ArcGlobalCtx, global_ctx: ArcGlobalCtx,
my_peer_id: PeerId, my_peer_id: PeerId,
relay_data: bool, relay_data: bool,
peer_rpc: Arc<PeerRpcManager>,
) -> Self { ) -> Self {
let config = TomlConfigLoader::default(); let foreign_global_ctx = Self::build_foreign_global_ctx(&network, global_ctx.clone());
config.set_network_identity(network.clone());
config.set_hostname(Some(format!("PublicServer_{}", global_ctx.get_hostname()))); let (packet_sender, packet_recv) = mpsc::channel(1000);
let foreign_global_ctx = Arc::new(GlobalCtx::new(config));
foreign_global_ctx.replace_stun_info_collector(Box::new(MockStunInfoCollector {
udp_nat_type: NatType::Unknown,
}));
let mut feature_flag = global_ctx.get_feature_flags();
feature_flag.is_public_server = true;
global_ctx.set_feature_flags(feature_flag);
let peer_map = Arc::new(PeerMap::new( let peer_map = Arc::new(PeerMap::new(
packet_sender, packet_sender,
@ -78,11 +81,9 @@ impl ForeignNetworkEntry {
my_peer_id, my_peer_id,
)); ));
let route = PeerRoute::new(my_peer_id, foreign_global_ctx.clone(), peer_rpc.clone()); let (peer_rpc, rpc_transport_sender) = Self::build_rpc_tspt(my_peer_id, peer_map.clone());
for u in global_ctx.get_running_listeners().into_iter() { let route = PeerRoute::new(my_peer_id, foreign_global_ctx.clone(), peer_rpc.clone());
foreign_global_ctx.add_running_listener(u);
}
peer_rpc.rpc_server().registry().register( peer_rpc.rpc_server().registry().register(
DirectConnectorRpcServer::new(DirectConnectorManagerRpcServer::new( DirectConnectorRpcServer::new(DirectConnectorManagerRpcServer::new(
foreign_global_ctx.clone(), foreign_global_ctx.clone(),
@ -91,16 +92,101 @@ impl ForeignNetworkEntry {
); );
Self { Self {
my_peer_id,
global_ctx: foreign_global_ctx, global_ctx: foreign_global_ctx,
network, network,
peer_map, peer_map,
relay_data, relay_data,
route: Arc::new(Box::new(route)), route: Arc::new(Box::new(route)),
peer_rpc: Arc::downgrade(&peer_rpc), peer_rpc: Arc::downgrade(&peer_rpc),
rpc_sender: rpc_transport_sender,
packet_recv: Mutex::new(Some(packet_recv)),
tasks: Mutex::new(JoinSet::new()),
} }
} }
async fn prepare(&self, my_peer_id: PeerId) { fn build_foreign_global_ctx(
network: &NetworkIdentity,
global_ctx: ArcGlobalCtx,
) -> ArcGlobalCtx {
let config = TomlConfigLoader::default();
config.set_network_identity(network.clone());
config.set_hostname(Some(format!("PublicServer_{}", global_ctx.get_hostname())));
let foreign_global_ctx = Arc::new(GlobalCtx::new(config));
foreign_global_ctx.replace_stun_info_collector(Box::new(MockStunInfoCollector {
udp_nat_type: NatType::Unknown,
}));
let mut feature_flag = global_ctx.get_feature_flags();
feature_flag.is_public_server = true;
foreign_global_ctx.set_feature_flags(feature_flag);
for u in global_ctx.get_running_listeners().into_iter() {
foreign_global_ctx.add_running_listener(u);
}
foreign_global_ctx
}
fn build_rpc_tspt(
my_peer_id: PeerId,
peer_map: Arc<PeerMap>,
) -> (Arc<PeerRpcManager>, UnboundedSender<ZCPacket>) {
struct RpcTransport {
my_peer_id: PeerId,
peer_map: Weak<PeerMap>,
packet_recv: Mutex<UnboundedReceiver<ZCPacket>>,
}
#[async_trait::async_trait]
impl PeerRpcManagerTransport for RpcTransport {
fn my_peer_id(&self) -> PeerId {
self.my_peer_id
}
async fn send(&self, msg: ZCPacket, dst_peer_id: PeerId) -> Result<(), Error> {
tracing::debug!(
"foreign network manager send rpc to peer: {:?}",
dst_peer_id
);
let peer_map = self
.peer_map
.upgrade()
.ok_or(anyhow::anyhow!("peer map is gone"))?;
peer_map
.send_msg(msg, dst_peer_id, NextHopPolicy::LeastHop)
.await
}
async fn recv(&self) -> Result<ZCPacket, Error> {
if let Some(o) = self.packet_recv.lock().await.recv().await {
tracing::info!("recv rpc packet in foreign network manager rpc transport");
Ok(o)
} else {
Err(Error::Unknown)
}
}
}
let (rpc_transport_sender, peer_rpc_tspt_recv) = mpsc::unbounded_channel();
let tspt = RpcTransport {
my_peer_id,
peer_map: Arc::downgrade(&peer_map),
packet_recv: Mutex::new(peer_rpc_tspt_recv),
};
let peer_rpc = Arc::new(PeerRpcManager::new(tspt));
(peer_rpc, rpc_transport_sender)
}
async fn prepare_route(&self, my_peer_id: PeerId) {
struct Interface { struct Interface {
my_peer_id: PeerId, my_peer_id: PeerId,
peer_map: Weak<PeerMap>, peer_map: Weak<PeerMap>,
@ -131,6 +217,52 @@ impl ForeignNetworkEntry {
self.peer_map.add_route(self.route.clone()).await; self.peer_map.add_route(self.route.clone()).await;
} }
async fn start_packet_recv(&self) {
let mut recv = self.packet_recv.lock().await.take().unwrap();
let my_node_id = self.my_peer_id;
let rpc_sender = self.rpc_sender.clone();
let peer_map = self.peer_map.clone();
let relay_data = self.relay_data;
self.tasks.lock().await.spawn(async move {
while let Some(packet_bytes) = recv.recv().await {
let Some(hdr) = packet_bytes.peer_manager_header() else {
tracing::warn!("invalid packet, skip");
continue;
};
tracing::info!(?hdr, "recv packet in foreign network manager");
let to_peer_id = hdr.to_peer_id.get();
if to_peer_id == my_node_id {
if hdr.packet_type == PacketType::TaRpc as u8
|| hdr.packet_type == PacketType::RpcReq as u8
|| hdr.packet_type == PacketType::RpcResp as u8
{
rpc_sender.send(packet_bytes).unwrap();
continue;
}
tracing::trace!(?hdr, "ignore packet in foreign network");
} else {
if !relay_data && hdr.packet_type == PacketType::Data as u8 {
continue;
}
let ret = peer_map
.send_msg(packet_bytes, to_peer_id, NextHopPolicy::LeastHop)
.await;
if ret.is_err() {
tracing::error!("forward packet to peer failed: {:?}", ret.err());
}
}
}
});
}
async fn prepare(&self, my_peer_id: PeerId) {
self.prepare_route(my_peer_id).await;
self.start_packet_recv().await;
self.peer_rpc.upgrade().unwrap().run();
}
} }
impl Drop for ForeignNetworkEntry { impl Drop for ForeignNetworkEntry {
@ -147,27 +279,11 @@ impl Drop for ForeignNetworkEntry {
struct ForeignNetworkManagerData { struct ForeignNetworkManagerData {
network_peer_maps: DashMap<String, Arc<ForeignNetworkEntry>>, network_peer_maps: DashMap<String, Arc<ForeignNetworkEntry>>,
peer_network_map: DashMap<PeerId, String>, peer_network_map: DashMap<PeerId, String>,
network_peer_last_update: DashMap<String, SystemTime>,
lock: std::sync::Mutex<()>, lock: std::sync::Mutex<()>,
} }
impl ForeignNetworkManagerData { impl ForeignNetworkManagerData {
async fn send_msg(&self, msg: ZCPacket, dst_peer_id: PeerId) -> Result<(), Error> {
let network_name = self
.peer_network_map
.get(&dst_peer_id)
.ok_or_else(|| Error::RouteError(Some("network not found".to_string())))?
.clone();
let entry = self
.network_peer_maps
.get(&network_name)
.ok_or_else(|| Error::RouteError(Some("no peer in network".to_string())))?
.clone();
entry
.peer_map
.send_msg(msg, dst_peer_id, NextHopPolicy::LeastHop)
.await
}
fn get_peer_network(&self, peer_id: PeerId) -> Option<String> { fn get_peer_network(&self, peer_id: PeerId) -> Option<String> {
self.peer_network_map.get(&peer_id).map(|v| v.clone()) self.peer_network_map.get(&peer_id).map(|v| v.clone())
} }
@ -179,8 +295,12 @@ impl ForeignNetworkManagerData {
fn remove_peer(&self, peer_id: PeerId, network_name: &String) { fn remove_peer(&self, peer_id: PeerId, network_name: &String) {
let _l = self.lock.lock().unwrap(); let _l = self.lock.lock().unwrap();
self.peer_network_map.remove(&peer_id); self.peer_network_map.remove(&peer_id);
self.network_peer_maps if let Some(_) = self
.remove_if(network_name, |_, v| v.peer_map.is_empty()); .network_peer_maps
.remove_if(network_name, |_, v| v.peer_map.is_empty())
{
self.network_peer_last_update.remove(network_name);
}
} }
async fn clear_no_conn_peer(&self, network_name: &String) { async fn clear_no_conn_peer(&self, network_name: &String) {
@ -197,37 +317,7 @@ impl ForeignNetworkManagerData {
let _l = self.lock.lock().unwrap(); let _l = self.lock.lock().unwrap();
self.peer_network_map.retain(|_, v| v != network_name); self.peer_network_map.retain(|_, v| v != network_name);
self.network_peer_maps.remove(network_name); self.network_peer_maps.remove(network_name);
} self.network_peer_last_update.remove(network_name);
}
struct RpcTransport {
my_peer_id: PeerId,
data: Arc<ForeignNetworkManagerData>,
packet_recv: Mutex<UnboundedReceiver<ZCPacket>>,
}
#[async_trait::async_trait]
impl PeerRpcManagerTransport for RpcTransport {
fn my_peer_id(&self) -> PeerId {
self.my_peer_id
}
async fn send(&self, msg: ZCPacket, dst_peer_id: PeerId) -> Result<(), Error> {
tracing::debug!(
"foreign network manager send rpc to peer: {:?}",
dst_peer_id
);
self.data.send_msg(msg, dst_peer_id).await
}
async fn recv(&self) -> Result<ZCPacket, Error> {
if let Some(o) = self.packet_recv.lock().await.recv().await {
tracing::info!("recv rpc packet in foreign network manager rpc transport");
Ok(o)
} else {
Err(Error::Unknown)
}
} }
} }
@ -238,12 +328,7 @@ pub struct ForeignNetworkManager {
global_ctx: ArcGlobalCtx, global_ctx: ArcGlobalCtx,
packet_sender_to_mgr: PacketRecvChan, packet_sender_to_mgr: PacketRecvChan,
packet_sender: PacketRecvChan,
packet_recv: Mutex<Option<PacketRecvChanReceiver>>,
data: Arc<ForeignNetworkManagerData>, data: Arc<ForeignNetworkManagerData>,
rpc_mgr: Arc<PeerRpcManager>,
rpc_transport_sender: UnboundedSender<ZCPacket>,
tasks: Mutex<JoinSet<()>>, tasks: Mutex<JoinSet<()>>,
} }
@ -254,34 +339,19 @@ impl ForeignNetworkManager {
global_ctx: ArcGlobalCtx, global_ctx: ArcGlobalCtx,
packet_sender_to_mgr: PacketRecvChan, packet_sender_to_mgr: PacketRecvChan,
) -> Self { ) -> Self {
// recv packet from all foreign networks
let (packet_sender, packet_recv) = mpsc::channel(1000);
let data = Arc::new(ForeignNetworkManagerData { let data = Arc::new(ForeignNetworkManagerData {
network_peer_maps: DashMap::new(), network_peer_maps: DashMap::new(),
peer_network_map: DashMap::new(), peer_network_map: DashMap::new(),
network_peer_last_update: DashMap::new(),
lock: std::sync::Mutex::new(()), lock: std::sync::Mutex::new(()),
}); });
// handle rpc from foreign networks
let (rpc_transport_sender, peer_rpc_tspt_recv) = mpsc::unbounded_channel();
let rpc_mgr = Arc::new(PeerRpcManager::new(RpcTransport {
my_peer_id,
data: data.clone(),
packet_recv: Mutex::new(peer_rpc_tspt_recv),
}));
Self { Self {
my_peer_id, my_peer_id,
global_ctx, global_ctx,
packet_sender_to_mgr, packet_sender_to_mgr,
packet_sender,
packet_recv: Mutex::new(Some(packet_recv)),
data, data,
rpc_mgr,
rpc_transport_sender,
tasks: Mutex::new(JoinSet::new()), tasks: Mutex::new(JoinSet::new()),
} }
@ -323,11 +393,9 @@ impl ForeignNetworkManager {
new_added = true; new_added = true;
Arc::new(ForeignNetworkEntry::new( Arc::new(ForeignNetworkEntry::new(
peer_conn.get_network_identity(), peer_conn.get_network_identity(),
self.packet_sender.clone(),
self.global_ctx.clone(), self.global_ctx.clone(),
self.my_peer_id, self.my_peer_id,
!ret.is_err(), !ret.is_err(),
self.rpc_mgr.clone(),
)) ))
}) })
.clone(); .clone();
@ -337,6 +405,11 @@ impl ForeignNetworkManager {
peer_conn.get_network_identity().network_name.clone(), peer_conn.get_network_identity().network_name.clone(),
); );
self.data.network_peer_last_update.insert(
peer_conn.get_network_identity().network_name.clone(),
SystemTime::now(),
);
entry entry
}; };
@ -363,83 +436,29 @@ impl ForeignNetworkManager {
let mut s = entry.global_ctx.subscribe(); let mut s = entry.global_ctx.subscribe();
self.tasks.lock().await.spawn(async move { self.tasks.lock().await.spawn(async move {
while let Ok(e) = s.recv().await { while let Ok(e) = s.recv().await {
if let GlobalCtxEvent::PeerRemoved(peer_id) = &e { match &e {
GlobalCtxEvent::PeerRemoved(peer_id) => {
tracing::info!(?e, "remove peer from foreign network manager"); tracing::info!(?e, "remove peer from foreign network manager");
data.remove_peer(*peer_id, &network_name); data.remove_peer(*peer_id, &network_name);
} else if let GlobalCtxEvent::PeerConnRemoved(..) = &e { data.network_peer_last_update
.insert(network_name.clone(), SystemTime::now());
}
GlobalCtxEvent::PeerConnRemoved(..) => {
tracing::info!(?e, "clear no conn peer from foreign network manager"); tracing::info!(?e, "clear no conn peer from foreign network manager");
data.clear_no_conn_peer(&network_name).await; data.clear_no_conn_peer(&network_name).await;
} }
GlobalCtxEvent::PeerAdded(_) => {
tracing::info!(?e, "add peer to foreign network manager");
data.network_peer_last_update
.insert(network_name.clone(), SystemTime::now());
}
_ => continue,
}
} }
// if lagged or recv done just remove the network // if lagged or recv done just remove the network
tracing::error!("global event handler at foreign network manager exit"); tracing::error!("global event handler at foreign network manager exit");
data.remove_network(&network_name); data.remove_network(&network_name);
}); });
self.tasks.lock().await.spawn(async move {});
}
async fn start_packet_recv(&self) {
let mut recv = self.packet_recv.lock().await.take().unwrap();
let sender_to_mgr = self.packet_sender_to_mgr.clone();
let my_node_id = self.my_peer_id;
let rpc_sender = self.rpc_transport_sender.clone();
let data = self.data.clone();
self.tasks.lock().await.spawn(async move {
while let Some(packet_bytes) = recv.recv().await {
let Some(hdr) = packet_bytes.peer_manager_header() else {
tracing::warn!("invalid packet, skip");
continue;
};
tracing::info!(?hdr, "recv packet in foreign network manager");
let from_peer_id = hdr.from_peer_id.get();
let to_peer_id = hdr.to_peer_id.get();
if to_peer_id == my_node_id {
if hdr.packet_type == PacketType::TaRpc as u8
|| hdr.packet_type == PacketType::RpcReq as u8
|| hdr.packet_type == PacketType::RpcResp as u8
{
rpc_sender.send(packet_bytes).unwrap();
continue;
}
if let Err(e) = sender_to_mgr.send(packet_bytes).await {
tracing::error!("send packet to mgr failed: {:?}", e);
}
} else {
let Some(from_network) = data.get_peer_network(from_peer_id) else {
continue;
};
let Some(to_network) = data.get_peer_network(to_peer_id) else {
continue;
};
if from_network != to_network {
continue;
}
if let Some(entry) = data.get_network_entry(&from_network) {
if !entry.relay_data && hdr.packet_type == PacketType::Data as u8 {
continue;
}
let ret = entry
.peer_map
.send_msg(packet_bytes, to_peer_id, NextHopPolicy::LeastHop)
.await;
if ret.is_err() {
tracing::error!("forward packet to peer failed: {:?}", ret.err());
}
} else {
tracing::error!("foreign network not found: {}", from_network);
}
}
}
});
}
pub async fn run(&self) {
self.start_packet_recv().await;
self.rpc_mgr.run();
} }
pub async fn list_foreign_networks(&self) -> ListForeignNetworkResponse { pub async fn list_foreign_networks(&self) -> ListForeignNetworkResponse {
@ -473,6 +492,13 @@ impl ForeignNetworkManager {
} }
ret ret
} }
pub fn get_foreign_network_last_update(&self, network_name: &str) -> Option<SystemTime> {
self.data
.network_peer_last_update
.get(network_name)
.map(|v| v.clone())
}
} }
impl Drop for ForeignNetworkManager { impl Drop for ForeignNetworkManager {
@ -496,7 +522,7 @@ mod tests {
tests::{connect_peer_manager, wait_route_appear}, tests::{connect_peer_manager, wait_route_appear},
}, },
proto::common::NatType, proto::common::NatType,
tunnel::common::tests::wait_for_condition, tunnel::common::tests::{enable_log, wait_for_condition},
}; };
use super::*; use super::*;

View File

@ -2,11 +2,13 @@ use std::{
fmt::Debug, fmt::Debug,
net::Ipv4Addr, net::Ipv4Addr,
sync::{Arc, Weak}, sync::{Arc, Weak},
time::{Instant, SystemTime},
}; };
use anyhow::Context; use anyhow::Context;
use async_trait::async_trait; use async_trait::async_trait;
use dashmap::DashMap;
use futures::StreamExt; use futures::StreamExt;
use tokio::{ use tokio::{
@ -26,10 +28,13 @@ use crate::{
peers::{ peers::{
peer_conn::PeerConn, peer_conn::PeerConn,
peer_rpc::PeerRpcManagerTransport, peer_rpc::PeerRpcManagerTransport,
route_trait::{NextHopPolicy, RouteInterface}, route_trait::{ForeignNetworkRouteInfoMap, NextHopPolicy, RouteInterface},
PeerPacketFilter, PeerPacketFilter,
}, },
proto::cli, proto::{
cli,
peer_rpc::{ForeignNetworkRouteInfoEntry, ForeignNetworkRouteInfoKey},
},
tunnel::{ tunnel::{
self, self,
packet_def::{PacketType, ZCPacket}, packet_def::{PacketType, ZCPacket},
@ -463,6 +468,7 @@ impl PeerManager {
my_peer_id: PeerId, my_peer_id: PeerId,
peers: Weak<PeerMap>, peers: Weak<PeerMap>,
foreign_network_client: Weak<ForeignNetworkClient>, foreign_network_client: Weak<ForeignNetworkClient>,
foreign_network_manager: Weak<ForeignNetworkManager>,
} }
#[async_trait] #[async_trait]
@ -484,6 +490,32 @@ impl PeerManager {
fn my_peer_id(&self) -> PeerId { fn my_peer_id(&self) -> PeerId {
self.my_peer_id self.my_peer_id
} }
async fn list_foreign_networks(&self) -> ForeignNetworkRouteInfoMap {
let ret = DashMap::new();
let Some(foreign_mgr) = self.foreign_network_manager.upgrade() else {
return ret;
};
let networks = foreign_mgr.list_foreign_networks().await;
for (network_name, info) in networks.foreign_networks.iter() {
let last_update = foreign_mgr
.get_foreign_network_last_update(network_name)
.unwrap_or(SystemTime::now());
ret.insert(
ForeignNetworkRouteInfoKey {
network_name: network_name.clone(),
peer_id: self.my_peer_id,
},
ForeignNetworkRouteInfoEntry {
foreign_peer_ids: info.peers.iter().map(|x| x.peer_id).collect(),
last_update: Some(last_update.into()),
version: 0,
},
);
}
ret
}
} }
let my_peer_id = self.my_peer_id; let my_peer_id = self.my_peer_id;
@ -492,6 +524,7 @@ impl PeerManager {
my_peer_id, my_peer_id,
peers: Arc::downgrade(&self.peers), peers: Arc::downgrade(&self.peers),
foreign_network_client: Arc::downgrade(&self.foreign_network_client), foreign_network_client: Arc::downgrade(&self.foreign_network_client),
foreign_network_manager: Arc::downgrade(&self.foreign_network_manager),
})) }))
.await .await
.unwrap(); .unwrap();
@ -672,7 +705,6 @@ impl PeerManager {
.await .await
.replace(Arc::downgrade(&self.foreign_network_client)); .replace(Arc::downgrade(&self.foreign_network_client));
self.foreign_network_manager.run().await;
self.foreign_network_client.run().await; self.foreign_network_client.run().await;
} }

View File

@ -9,6 +9,7 @@ use std::{
time::{Duration, SystemTime}, time::{Duration, SystemTime},
}; };
use crossbeam::atomic::AtomicCell;
use dashmap::DashMap; use dashmap::DashMap;
use petgraph::{ use petgraph::{
algo::{all_simple_paths, astar, dijkstra}, algo::{all_simple_paths, astar, dijkstra},
@ -30,9 +31,10 @@ use crate::{
proto::{ proto::{
common::{NatType, StunInfo}, common::{NatType, StunInfo},
peer_rpc::{ peer_rpc::{
route_foreign_network_infos, ForeignNetworkRouteInfoEntry, ForeignNetworkRouteInfoKey,
OspfRouteRpc, OspfRouteRpcClientFactory, OspfRouteRpcServer, PeerIdVersion, OspfRouteRpc, OspfRouteRpcClientFactory, OspfRouteRpcServer, PeerIdVersion,
RoutePeerInfo, RoutePeerInfos, SyncRouteInfoError, SyncRouteInfoRequest, RouteForeignNetworkInfos, RoutePeerInfo, RoutePeerInfos, SyncRouteInfoError,
SyncRouteInfoResponse, SyncRouteInfoRequest, SyncRouteInfoResponse,
}, },
rpc_types::{ rpc_types::{
self, self,
@ -44,7 +46,7 @@ use crate::{
use super::{ use super::{
peer_rpc::PeerRpcManager, peer_rpc::PeerRpcManager,
route_trait::{ route_trait::{
DefaultRouteCostCalculator, NextHopPolicy, RouteCostCalculator, DefaultRouteCostCalculator, ForeignNetworkRouteInfoMap, NextHopPolicy, RouteCostCalculator,
RouteCostCalculatorInterface, RouteCostCalculatorInterface,
}, },
PeerPacketFilter, PeerPacketFilter,
@ -89,6 +91,16 @@ impl From<Version> for AtomicVersion {
} }
} }
fn is_foreign_network_info_newer(
next: &ForeignNetworkRouteInfoEntry,
prev: &ForeignNetworkRouteInfoEntry,
) -> Option<bool> {
Some(
SystemTime::try_from(next.last_update?).ok()?
> SystemTime::try_from(prev.last_update?).ok()?,
)
}
impl RoutePeerInfo { impl RoutePeerInfo {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
@ -243,6 +255,7 @@ type Error = SyncRouteInfoError;
struct SyncedRouteInfo { struct SyncedRouteInfo {
peer_infos: DashMap<PeerId, RoutePeerInfo>, peer_infos: DashMap<PeerId, RoutePeerInfo>,
conn_map: DashMap<PeerId, (BTreeSet<PeerId>, AtomicVersion)>, conn_map: DashMap<PeerId, (BTreeSet<PeerId>, AtomicVersion)>,
foreign_network: DashMap<ForeignNetworkRouteInfoKey, ForeignNetworkRouteInfoEntry>,
} }
impl SyncedRouteInfo { impl SyncedRouteInfo {
@ -256,6 +269,7 @@ impl SyncedRouteInfo {
tracing::warn!(?peer_id, "remove_peer from synced_route_info"); tracing::warn!(?peer_id, "remove_peer from synced_route_info");
self.peer_infos.remove(&peer_id); self.peer_infos.remove(&peer_id);
self.conn_map.remove(&peer_id); self.conn_map.remove(&peer_id);
self.foreign_network.retain(|k, _| k.peer_id != peer_id);
} }
fn fill_empty_peer_info(&self, peer_ids: &BTreeSet<PeerId>) { fn fill_empty_peer_info(&self, peer_ids: &BTreeSet<PeerId>) {
@ -353,6 +367,28 @@ impl SyncedRouteInfo {
} }
} }
fn update_foreign_network(&self, foreign_network: &RouteForeignNetworkInfos) {
for item in foreign_network.infos.iter().map(Clone::clone) {
let Some(key) = item.key else {
continue;
};
let Some(mut entry) = item.value else {
continue;
};
entry.last_update = Some(SystemTime::now().into());
self.foreign_network
.entry(key.clone())
.and_modify(|old_entry| {
if entry.version > old_entry.version {
*old_entry = entry.clone();
}
})
.or_insert_with(|| entry.clone());
}
}
fn update_my_peer_info(&self, my_peer_id: PeerId, global_ctx: &ArcGlobalCtx) -> bool { fn update_my_peer_info(&self, my_peer_id: PeerId, global_ctx: &ArcGlobalCtx) -> bool {
let mut old = self let mut old = self
.peer_infos .peer_infos
@ -383,6 +419,51 @@ impl SyncedRouteInfo {
} }
} }
fn update_my_foreign_network(
&self,
my_peer_id: PeerId,
foreign_networks: ForeignNetworkRouteInfoMap,
) -> bool {
let mut updated = false;
for mut item in self
.foreign_network
.iter_mut()
.filter(|x| x.key().peer_id == my_peer_id)
{
let (key, entry) = item.pair_mut();
if let Some(mut new_entry) = foreign_networks.get_mut(key) {
if let Some(is_newer) = is_foreign_network_info_newer(&new_entry, entry) {
if is_newer {
new_entry.version = entry.version + 1;
*entry = new_entry.clone();
updated = true;
}
}
drop(new_entry);
foreign_networks.remove(key).unwrap();
} else if !item.foreign_peer_ids.is_empty() {
item.foreign_peer_ids.clear();
item.last_update = Some(SystemTime::now().into());
item.version += 1;
updated = true;
}
}
for item in foreign_networks.iter() {
self.foreign_network
.entry(item.key().clone())
.and_modify(|v| panic!("key should not exist, {:?}", v))
.or_insert_with(|| {
let mut v = item.value().clone();
v.version = 1;
v
});
updated = true;
}
updated
}
fn is_peer_bidirectly_connected(&self, src_peer_id: PeerId, dst_peer_id: PeerId) -> bool { fn is_peer_bidirectly_connected(&self, src_peer_id: PeerId, dst_peer_id: PeerId) -> bool {
self.conn_map self.conn_map
.get(&src_peer_id) .get(&src_peer_id)
@ -670,6 +751,7 @@ struct SyncRouteSession {
dst_peer_id: PeerId, dst_peer_id: PeerId,
dst_saved_peer_info_versions: DashMap<PeerId, AtomicVersion>, dst_saved_peer_info_versions: DashMap<PeerId, AtomicVersion>,
dst_saved_conn_bitmap_version: DashMap<PeerId, AtomicVersion>, dst_saved_conn_bitmap_version: DashMap<PeerId, AtomicVersion>,
dst_saved_foreign_network_versions: DashMap<ForeignNetworkRouteInfoKey, AtomicVersion>,
my_session_id: AtomicSessionId, my_session_id: AtomicSessionId,
dst_session_id: AtomicSessionId, dst_session_id: AtomicSessionId,
@ -692,6 +774,7 @@ impl SyncRouteSession {
dst_peer_id, dst_peer_id,
dst_saved_peer_info_versions: DashMap::new(), dst_saved_peer_info_versions: DashMap::new(),
dst_saved_conn_bitmap_version: DashMap::new(), dst_saved_conn_bitmap_version: DashMap::new(),
dst_saved_foreign_network_versions: DashMap::new(),
my_session_id: AtomicSessionId::new(rand::random()), my_session_id: AtomicSessionId::new(rand::random()),
dst_session_id: AtomicSessionId::new(0), dst_session_id: AtomicSessionId::new(0),
@ -737,6 +820,15 @@ impl SyncRouteSession {
} }
} }
fn update_dst_saved_foreign_network_version(&self, foreign_network: &RouteForeignNetworkInfos) {
for item in foreign_network.infos.iter() {
self.dst_saved_foreign_network_versions
.entry(item.key.clone().unwrap())
.or_insert_with(|| AtomicVersion::new())
.set_if_larger(item.value.as_ref().unwrap().version);
}
}
fn update_initiator_flag(&self, is_initiator: bool) { fn update_initiator_flag(&self, is_initiator: bool) {
self.we_are_initiator.store(is_initiator, Ordering::Relaxed); self.we_are_initiator.store(is_initiator, Ordering::Relaxed);
self.need_sync_initiator_info.store(true, Ordering::Relaxed); self.need_sync_initiator_info.store(true, Ordering::Relaxed);
@ -778,6 +870,8 @@ struct PeerRouteServiceImpl {
route_table_with_cost: RouteTable, route_table_with_cost: RouteTable,
synced_route_info: Arc<SyncedRouteInfo>, synced_route_info: Arc<SyncedRouteInfo>,
cached_local_conn_map: std::sync::Mutex<RouteConnBitmap>, cached_local_conn_map: std::sync::Mutex<RouteConnBitmap>,
last_update_my_foreign_network: AtomicCell<Option<std::time::Instant>>,
} }
impl Debug for PeerRouteServiceImpl { impl Debug for PeerRouteServiceImpl {
@ -815,8 +909,11 @@ impl PeerRouteServiceImpl {
synced_route_info: Arc::new(SyncedRouteInfo { synced_route_info: Arc::new(SyncedRouteInfo {
peer_infos: DashMap::new(), peer_infos: DashMap::new(),
conn_map: DashMap::new(), conn_map: DashMap::new(),
foreign_network: DashMap::new(),
}), }),
cached_local_conn_map: std::sync::Mutex::new(RouteConnBitmap::new()), cached_local_conn_map: std::sync::Mutex::new(RouteConnBitmap::new()),
last_update_my_foreign_network: AtomicCell::new(None),
} }
} }
@ -876,6 +973,31 @@ impl PeerRouteServiceImpl {
updated updated
} }
async fn update_my_foreign_network(&self) -> bool {
let last_time = self.last_update_my_foreign_network.load();
if last_time.is_some() && last_time.unwrap().elapsed().as_secs() < 10 {
return false;
}
self.last_update_my_foreign_network
.store(Some(std::time::Instant::now()));
let foreign_networks = self
.interface
.lock()
.await
.as_ref()
.unwrap()
.list_foreign_networks()
.await;
let updated = self
.synced_route_info
.update_my_foreign_network(self.my_peer_id, foreign_networks);
updated
}
fn update_route_table(&self) { fn update_route_table(&self) {
let mut calc_locked = self.cost_calculator.lock().unwrap(); let mut calc_locked = self.cost_calculator.lock().unwrap();
@ -991,20 +1113,56 @@ impl PeerRouteServiceImpl {
Some(self.cached_local_conn_map.lock().unwrap().clone()) Some(self.cached_local_conn_map.lock().unwrap().clone())
} }
fn build_foreign_network_info(
&self,
session: &SyncRouteSession,
) -> Option<RouteForeignNetworkInfos> {
let mut foreign_networks = RouteForeignNetworkInfos::default();
for item in self.synced_route_info.foreign_network.iter() {
if session
.dst_saved_foreign_network_versions
.get(&item.key())
.map(|x| x.get() >= item.value().version)
.unwrap_or(false)
{
continue;
}
foreign_networks
.infos
.push(route_foreign_network_infos::Info {
key: Some(item.key().clone()),
value: Some(item.value().clone()),
});
}
if foreign_networks.infos.is_empty() {
None
} else {
Some(foreign_networks)
}
}
async fn update_my_infos(&self) -> bool { async fn update_my_infos(&self) -> bool {
let mut ret = self.update_my_peer_info(); let mut ret = self.update_my_peer_info();
ret |= self.update_my_conn_info().await; ret |= self.update_my_conn_info().await;
ret |= self.update_my_foreign_network().await;
ret ret
} }
fn build_sync_request( fn build_sync_request(
&self, &self,
session: &SyncRouteSession, session: &SyncRouteSession,
) -> (Option<Vec<RoutePeerInfo>>, Option<RouteConnBitmap>) { ) -> (
Option<Vec<RoutePeerInfo>>,
Option<RouteConnBitmap>,
Option<RouteForeignNetworkInfos>,
) {
let route_infos = self.build_route_info(&session); let route_infos = self.build_route_info(&session);
let conn_bitmap = self.build_conn_bitmap(&session); let conn_bitmap = self.build_conn_bitmap(&session);
let foreign_network = self.build_foreign_network_info(&session);
(route_infos, conn_bitmap) (route_infos, conn_bitmap, foreign_network)
} }
fn clear_expired_peer(&self) { fn clear_expired_peer(&self) {
@ -1022,6 +1180,28 @@ impl PeerRouteServiceImpl {
for p in to_remove.iter() { for p in to_remove.iter() {
self.synced_route_info.remove_peer(*p); self.synced_route_info.remove_peer(*p);
} }
// clear expired foreign network info
let mut to_remove = Vec::new();
for item in self.synced_route_info.foreign_network.iter() {
let Some(since_last_update) = item
.value()
.last_update
.and_then(|x| SystemTime::try_from(x).ok())
.and_then(|x| now.duration_since(x).ok())
else {
to_remove.push(item.key().clone());
continue;
};
if since_last_update > REMOVE_DEAD_PEER_INFO_AFTER {
to_remove.push(item.key().clone());
}
}
for p in to_remove.iter() {
self.synced_route_info.foreign_network.remove(p);
}
} }
async fn sync_route_with_peer( async fn sync_route_with_peer(
@ -1036,8 +1216,8 @@ impl PeerRouteServiceImpl {
let my_peer_id = self.my_peer_id; let my_peer_id = self.my_peer_id;
let (peer_infos, conn_bitmap) = self.build_sync_request(&session); let (peer_infos, conn_bitmap, foreign_network) = self.build_sync_request(&session);
tracing::info!("building sync_route request. my_id {:?}, pper_id: {:?}, peer_infos: {:?}, conn_bitmap: {:?}, synced_route_info: {:?} session: {:?}", tracing::info!(?foreign_network, "building sync_route request. my_id {:?}, pper_id: {:?}, peer_infos: {:?}, conn_bitmap: {:?}, synced_route_info: {:?} session: {:?}",
my_peer_id, dst_peer_id, peer_infos, conn_bitmap, self.synced_route_info, session); my_peer_id, dst_peer_id, peer_infos, conn_bitmap, self.synced_route_info, session);
if peer_infos.is_none() if peer_infos.is_none()
@ -1070,6 +1250,7 @@ impl PeerRouteServiceImpl {
is_initiator: session.we_are_initiator.load(Ordering::Relaxed), is_initiator: session.we_are_initiator.load(Ordering::Relaxed),
peer_infos: peer_infos.clone().map(|x| RoutePeerInfos { items: x }), peer_infos: peer_infos.clone().map(|x| RoutePeerInfos { items: x }),
conn_bitmap: conn_bitmap.clone().map(Into::into), conn_bitmap: conn_bitmap.clone().map(Into::into),
foreign_network_infos: foreign_network,
}, },
) )
.await; .await;

View File

@ -1,6 +1,11 @@
use std::{net::Ipv4Addr, sync::Arc}; use std::{net::Ipv4Addr, sync::Arc};
use crate::common::PeerId; use dashmap::DashMap;
use crate::{
common::PeerId,
proto::peer_rpc::{ForeignNetworkRouteInfoEntry, ForeignNetworkRouteInfoKey},
};
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum NextHopPolicy { pub enum NextHopPolicy {
@ -14,10 +19,16 @@ impl Default for NextHopPolicy {
} }
} }
pub type ForeignNetworkRouteInfoMap =
DashMap<ForeignNetworkRouteInfoKey, ForeignNetworkRouteInfoEntry>;
#[async_trait::async_trait] #[async_trait::async_trait]
pub trait RouteInterface { pub trait RouteInterface {
async fn list_peers(&self) -> Vec<PeerId>; async fn list_peers(&self) -> Vec<PeerId>;
fn my_peer_id(&self) -> PeerId; fn my_peer_id(&self) -> PeerId;
async fn list_foreign_networks(&self) -> ForeignNetworkRouteInfoMap {
DashMap::new()
}
} }
pub type RouteInterfaceBox = Box<dyn RouteInterface + Send + Sync>; pub type RouteInterfaceBox = Box<dyn RouteInterface + Send + Sync>;

View File

@ -33,12 +33,32 @@ message RouteConnBitmap {
message RoutePeerInfos { repeated RoutePeerInfo items = 1; } message RoutePeerInfos { repeated RoutePeerInfo items = 1; }
message ForeignNetworkRouteInfoKey {
uint32 peer_id = 1;
string network_name = 2;
}
message ForeignNetworkRouteInfoEntry {
repeated uint32 foreign_peer_ids = 1;
google.protobuf.Timestamp last_update = 2;
uint32 version = 3;
}
message RouteForeignNetworkInfos {
message Info {
ForeignNetworkRouteInfoKey key = 1;
ForeignNetworkRouteInfoEntry value = 2;
}
repeated Info infos = 1;
}
message SyncRouteInfoRequest { message SyncRouteInfoRequest {
uint32 my_peer_id = 1; uint32 my_peer_id = 1;
uint64 my_session_id = 2; uint64 my_session_id = 2;
bool is_initiator = 3; bool is_initiator = 3;
RoutePeerInfos peer_infos = 4; RoutePeerInfos peer_infos = 4;
RouteConnBitmap conn_bitmap = 5; RouteConnBitmap conn_bitmap = 5;
RouteForeignNetworkInfos foreign_network_infos = 6;
} }
enum SyncRouteInfoError { enum SyncRouteInfoError {

View File

@ -716,7 +716,10 @@ pub async fn manual_reconnector(#[values(true, false)] is_foreign: bool) {
} }
let mut center_inst = Instance::new(center_node_config); let mut center_inst = Instance::new(center_node_config);
let mut inst1 = Instance::new(get_inst_config("inst1", Some("net_b"), "10.144.145.1")); let inst1_config = get_inst_config("inst1", Some("net_b"), "10.144.145.1");
inst1_config.set_listeners(vec![]);
let mut inst1 = Instance::new(inst1_config);
let mut inst2 = Instance::new(get_inst_config("inst2", Some("net_c"), "10.144.145.2")); let mut inst2 = Instance::new(get_inst_config("inst2", Some("net_c"), "10.144.145.2"));
center_inst.run().await.unwrap(); center_inst.run().await.unwrap();