fix ospf route (#970)

- **fix deadlock in ospf route introducd by #958 **
- **use random peer id for foreign network entry, because ospf route algo need peer id change after peer info version reset. this may interfere route propagation and cause node residual**
- **allow multiple nodes broadcast same network ranges for subnet proxy**
- **bump version to v2.3.2**
This commit is contained in:
Sijie.Sun
2025-06-11 09:44:03 +08:00
committed by GitHub
parent ecebbecd3b
commit 870353c499
18 changed files with 316 additions and 72 deletions

View File

@@ -70,13 +70,16 @@ struct ForeignNetworkEntry {
packet_recv: Mutex<Option<PacketRecvChanReceiver>>,
tasks: Mutex<JoinSet<()>>,
pub lock: Mutex<()>,
}
impl ForeignNetworkEntry {
fn new(
network: NetworkIdentity,
global_ctx: ArcGlobalCtx,
// NOTICE: ospf route need my_peer_id be changed after restart.
my_peer_id: PeerId,
global_ctx: ArcGlobalCtx,
relay_data: bool,
pm_packet_sender: PacketRecvChan,
) -> Self {
@@ -114,6 +117,8 @@ impl ForeignNetworkEntry {
packet_recv: Mutex::new(Some(packet_recv)),
tasks: Mutex::new(JoinSet::new()),
lock: Mutex::new(()),
}
}
@@ -202,11 +207,7 @@ impl ForeignNetworkEntry {
(peer_rpc, rpc_transport_sender)
}
async fn prepare_route(
&self,
my_peer_id: PeerId,
accessor: Box<dyn GlobalForeignNetworkAccessor>,
) {
async fn prepare_route(&self, accessor: Box<dyn GlobalForeignNetworkAccessor>) {
struct Interface {
my_peer_id: PeerId,
peer_map: Weak<PeerMap>,
@@ -238,10 +239,14 @@ impl ForeignNetworkEntry {
}
}
let route = PeerRoute::new(my_peer_id, self.global_ctx.clone(), self.peer_rpc.clone());
let route = PeerRoute::new(
self.my_peer_id,
self.global_ctx.clone(),
self.peer_rpc.clone(),
);
route
.open(Box::new(Interface {
my_peer_id,
my_peer_id: self.my_peer_id,
network_identity: self.network.clone(),
peer_map: Arc::downgrade(&self.peer_map),
accessor,
@@ -317,8 +322,8 @@ impl ForeignNetworkEntry {
});
}
async fn prepare(&self, my_peer_id: PeerId, accessor: Box<dyn GlobalForeignNetworkAccessor>) {
self.prepare_route(my_peer_id, accessor).await;
async fn prepare(&self, accessor: Box<dyn GlobalForeignNetworkAccessor>) {
self.prepare_route(accessor).await;
self.start_packet_recv().await;
self.peer_rpc.run();
}
@@ -400,8 +405,8 @@ impl ForeignNetworkManagerData {
new_added = true;
Arc::new(ForeignNetworkEntry::new(
network_identity.clone(),
global_ctx.clone(),
my_peer_id,
global_ctx.clone(),
relay_data,
pm_packet_sender.clone(),
))
@@ -417,9 +422,7 @@ impl ForeignNetworkManagerData {
drop(l);
if new_added {
entry
.prepare(my_peer_id, Box::new(self.accessor.clone()))
.await;
entry.prepare(Box::new(self.accessor.clone())).await;
}
(entry, new_added)
@@ -467,6 +470,13 @@ impl ForeignNetworkManager {
}
}
pub fn get_network_peer_id(&self, network_name: &str) -> Option<PeerId> {
self.data
.network_peer_maps
.get(network_name)
.and_then(|v| Some(v.my_peer_id))
}
pub async fn add_peer_conn(&self, peer_conn: PeerConn) -> Result<(), Error> {
tracing::info!(peer_conn = ?peer_conn.get_conn_info(), network = ?peer_conn.get_network_identity(), "add new peer conn in foreign network manager");
@@ -483,7 +493,7 @@ impl ForeignNetworkManager {
.data
.get_or_insert_entry(
&peer_conn.get_network_identity(),
self.my_peer_id,
peer_conn.get_my_peer_id(),
peer_conn.get_peer_id(),
!ret.is_err(),
&self.global_ctx,
@@ -491,17 +501,30 @@ impl ForeignNetworkManager {
)
.await;
if entry.network != peer_conn.get_network_identity() {
let _g = entry.lock.lock().await;
if entry.network != peer_conn.get_network_identity()
|| entry.my_peer_id != peer_conn.get_my_peer_id()
{
if new_added {
self.data
.remove_network(&entry.network.network_name.clone());
}
return Err(anyhow::anyhow!(
"network secret not match. exp: {:?} real: {:?}",
entry.network,
peer_conn.get_network_identity()
)
.into());
let err = if entry.my_peer_id != peer_conn.get_my_peer_id() {
anyhow::anyhow!(
"my peer id not match. exp: {:?} real: {:?}, need retry connect",
entry.my_peer_id,
peer_conn.get_my_peer_id()
)
} else {
anyhow::anyhow!(
"network secret not match. exp: {:?} real: {:?}",
entry.network,
peer_conn.get_network_identity()
)
};
tracing::error!(?err, "foreign network entry not match, disconnect peer");
return Err(err.into());
}
if new_added {
@@ -567,7 +590,8 @@ impl ForeignNetworkManager {
.network_secret_digest
.unwrap_or_default()
.to_vec(),
..Default::default()
my_peer_id_for_this_network: item.my_peer_id,
peers: Default::default(),
};
for peer in item.peer_map.list_peers().await {
let mut peer_info = PeerInfo::default();
@@ -614,8 +638,6 @@ impl Drop for ForeignNetworkManager {
#[cfg(test)]
mod tests {
use std::time::Duration;
use crate::{
common::global_ctx::tests::get_mock_global_ctx_with_network,
connector::udp_hole_punch::tests::{
@@ -629,6 +651,7 @@ mod tests {
set_global_var,
tunnel::common::tests::wait_for_condition,
};
use std::time::Duration;
use super::*;
@@ -769,7 +792,10 @@ mod tests {
.unwrap();
assert_eq!(
vec![pm_center.my_peer_id()],
vec![pm_center
.get_foreign_network_manager()
.get_network_peer_id("net1")
.unwrap()],
pma_net1
.get_foreign_network_client()
.get_peer_map()
@@ -777,7 +803,10 @@ mod tests {
.await
);
assert_eq!(
vec![pm_center.my_peer_id()],
vec![pm_center
.get_foreign_network_manager()
.get_network_peer_id("net1")
.unwrap()],
pmb_net1
.get_foreign_network_client()
.get_peer_map()
@@ -894,6 +923,75 @@ mod tests {
.await;
}
#[tokio::test]
async fn test_foreign_network_manager_cluster_simple() {
set_global_var!(OSPF_UPDATE_MY_GLOBAL_FOREIGN_NETWORK_INTERVAL_SEC, 1);
let pm_center1 = create_mock_peer_manager_with_mock_stun(NatType::Unknown).await;
let pm_center2 = create_mock_peer_manager_with_mock_stun(NatType::Unknown).await;
connect_peer_manager(pm_center1.clone(), pm_center2.clone()).await;
let pma_net1 = create_mock_peer_manager_for_foreign_network("net1").await;
let pmb_net1 = create_mock_peer_manager_for_foreign_network("net1").await;
connect_peer_manager(pma_net1.clone(), pm_center1.clone()).await;
connect_peer_manager(pmb_net1.clone(), pm_center2.clone()).await;
wait_route_appear(pma_net1.clone(), pmb_net1.clone())
.await
.unwrap();
let pma_net2 = create_mock_peer_manager_for_foreign_network("net2").await;
let pmb_net2 = create_mock_peer_manager_for_foreign_network("net2").await;
connect_peer_manager(pma_net2.clone(), pm_center1.clone()).await;
connect_peer_manager(pmb_net2.clone(), pm_center2.clone()).await;
wait_route_appear(pma_net2.clone(), pmb_net2.clone())
.await
.unwrap();
}
#[tokio::test]
async fn test_foreign_network_manager_cluster_multiple_hops() {
set_global_var!(OSPF_UPDATE_MY_GLOBAL_FOREIGN_NETWORK_INTERVAL_SEC, 1);
let pm_center1 = create_mock_peer_manager_with_mock_stun(NatType::Unknown).await;
let pm_center2 = create_mock_peer_manager_with_mock_stun(NatType::Unknown).await;
let pm_center3 = create_mock_peer_manager_with_mock_stun(NatType::Unknown).await;
let pm_center4 = create_mock_peer_manager_with_mock_stun(NatType::Unknown).await;
connect_peer_manager(pm_center1.clone(), pm_center2.clone()).await;
connect_peer_manager(pm_center2.clone(), pm_center3.clone()).await;
connect_peer_manager(pm_center3.clone(), pm_center4.clone()).await;
let pma_net1 = create_mock_peer_manager_for_foreign_network("net1").await;
let pmb_net1 = create_mock_peer_manager_for_foreign_network("net1").await;
connect_peer_manager(pma_net1.clone(), pm_center1.clone()).await;
connect_peer_manager(pmb_net1.clone(), pm_center3.clone()).await;
wait_route_appear(pma_net1.clone(), pmb_net1.clone())
.await
.unwrap();
let pmc_net1 = create_mock_peer_manager_for_foreign_network("net1").await;
connect_peer_manager(pmc_net1.clone(), pm_center4.clone()).await;
wait_route_appear(pma_net1.clone(), pmc_net1.clone())
.await
.unwrap();
let pma_net2 = create_mock_peer_manager_for_foreign_network("net2").await;
let pmb_net2 = create_mock_peer_manager_for_foreign_network("net2").await;
connect_peer_manager(pma_net2.clone(), pm_center1.clone()).await;
connect_peer_manager(pmb_net2.clone(), pm_center4.clone()).await;
wait_route_appear(pma_net2.clone(), pmb_net2.clone())
.await
.unwrap();
drop(pmb_net2);
wait_for_condition(
|| async { pma_net2.list_routes().await.len() == 1 },
Duration::from_secs(5),
)
.await;
}
#[tokio::test]
async fn test_foreign_network_manager_cluster() {
set_global_var!(OSPF_UPDATE_MY_GLOBAL_FOREIGN_NETWORK_INTERVAL_SEC, 1);