feat: wire shared nic into instance setup

Route normal, DHCP, and mobile nic creation through one helper that
selects the shared backend when dev_name is configured.

Keep dedicated nic creation as the default for configs without a
dev_name, and keep no_tun handling in the existing callers.

Store a process-wide shared virtual nic registry behind each instance
so networks with the same dev_name attach to the same shared device.
This commit is contained in:
sijie.sun
2026-06-13 16:45:08 +08:00
parent 62e43855cb
commit 47a2fb19a6
2 changed files with 96 additions and 6 deletions
+94 -6
View File
@@ -2,6 +2,8 @@
use std::any::Any;
use std::collections::HashSet;
use std::net::{IpAddr, Ipv4Addr};
#[cfg(feature = "tun")]
use std::sync::OnceLock;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Weak};
#[cfg(all(feature = "tun", not(mobile)))]
@@ -71,6 +73,8 @@ use super::public_ipv6_provider::{
should_run_public_ipv6_provider_reconcile, validate_public_ipv6_config,
validate_public_ipv6_config_values,
};
#[cfg(feature = "tun")]
use super::shared_virtual_nic::SharedVirtualNicRegistry;
#[cfg(feature = "socks5")]
use crate::gateway::socks5::Socks5Server;
@@ -197,6 +201,17 @@ impl NicCtxContainer {
#[cfg(feature = "tun")]
type ArcNicCtx = Arc<Mutex<Option<NicCtxContainer>>>;
#[cfg(feature = "tun")]
type ArcSharedVirtualNicRegistry = Arc<Mutex<SharedVirtualNicRegistry>>;
#[cfg(feature = "tun")]
fn default_shared_virtual_nic_registry() -> ArcSharedVirtualNicRegistry {
static REGISTRY: OnceLock<ArcSharedVirtualNicRegistry> = OnceLock::new();
REGISTRY
.get_or_init(|| Arc::new(Mutex::new(SharedVirtualNicRegistry::new())))
.clone()
}
pub struct InstanceRpcServerHook {
rpc_portal_whitelist: Vec<IpCidr>,
}
@@ -618,6 +633,8 @@ pub struct Instance {
#[cfg(feature = "tun")]
nic_ctx: ArcNicCtx,
#[cfg(feature = "tun")]
shared_virtual_nic_registry: ArcSharedVirtualNicRegistry,
peer_packet_receiver: Arc<Mutex<PacketRecvChanReceiver>>,
peer_manager: Arc<PeerManager>,
@@ -707,6 +724,8 @@ impl Instance {
peer_packet_receiver: Arc::new(Mutex::new(peer_packet_receiver)),
#[cfg(feature = "tun")]
nic_ctx: Arc::new(Mutex::new(None)),
#[cfg(feature = "tun")]
shared_virtual_nic_registry: default_shared_virtual_nic_registry(),
peer_manager,
listener_manager,
@@ -822,6 +841,34 @@ impl Instance {
tracing::debug!("nic ctx updated.");
}
#[cfg(feature = "tun")]
async fn new_nic_ctx(
global_ctx: ArcGlobalCtx,
peer_manager: &Arc<PeerManager>,
peer_packet_receiver: Arc<Mutex<PacketRecvChanReceiver>>,
close_notifier: Arc<Notify>,
shared_virtual_nic_registry: ArcSharedVirtualNicRegistry,
) -> Result<NicCtx, Error> {
if global_ctx.get_flags().dev_name.is_empty() {
return Ok(NicCtx::new(
global_ctx,
peer_manager,
peer_packet_receiver,
close_notifier,
));
}
NicCtx::new_shared(
global_ctx,
peer_manager,
peer_packet_receiver,
close_notifier,
shared_virtual_nic_registry,
uuid::Uuid::new_v4(),
)
.await
}
// Warning, if there is an IP conflict in the network when using DHCP, the IP will be automatically changed.
fn check_dhcp_ip_conflict(&self) {
use rand::Rng;
@@ -829,6 +876,8 @@ impl Instance {
let global_ctx_c = self.get_global_ctx();
#[cfg(feature = "tun")]
let nic_ctx = self.nic_ctx.clone();
#[cfg(all(not(mobile), feature = "tun"))]
let shared_virtual_nic_registry = self.shared_virtual_nic_registry.clone();
let _peer_packet_receiver = self.peer_packet_receiver.clone();
tokio::spawn(async move {
let default_ipv4_addr = Ipv4Inet::new(Ipv4Addr::new(10, 126, 126, 0), 24).unwrap();
@@ -907,12 +956,27 @@ impl Instance {
#[cfg(all(not(mobile), feature = "tun"))]
{
let mut new_nic_ctx = NicCtx::new(
let mut new_nic_ctx = match Self::new_nic_ctx(
global_ctx_c.clone(),
&peer_manager_c,
_peer_packet_receiver.clone(),
nic_closed_notifier.clone(),
);
shared_virtual_nic_registry.clone(),
)
.await
{
Ok(nic_ctx) => nic_ctx,
Err(e) => {
tracing::error!(
?current_dhcp_ip,
?candidate_ipv4_addr,
?e,
"create nic ctx failed"
);
global_ctx_c.set_ipv4(None);
continue;
}
};
if let Err(e) = new_nic_ctx.run(Some(ip), global_ctx_c.get_ipv6()).await {
tracing::error!(
?current_dhcp_ip,
@@ -960,6 +1024,7 @@ impl Instance {
let nic_ctx = self.nic_ctx.clone();
let peer_mgr = Arc::downgrade(&self.peer_manager);
let peer_packet_receiver = self.peer_packet_receiver.clone();
let shared_virtual_nic_registry = self.shared_virtual_nic_registry.clone();
tokio::spawn(async move {
let mut output_tx = Some(first_round_output);
@@ -975,12 +1040,26 @@ impl Instance {
return;
};
let mut new_nic_ctx = NicCtx::new(
let mut new_nic_ctx = match Self::new_nic_ctx(
peer_mgr.get_global_ctx(),
&peer_mgr,
peer_packet_receiver.clone(),
close_notifier.clone(),
);
shared_virtual_nic_registry.clone(),
)
.await
{
Ok(nic_ctx) => nic_ctx,
Err(e) => {
if let Some(output_tx) = output_tx.take() {
let _ = output_tx.send(Err(e));
return;
}
tracing::error!("failed to create new nic ctx, err: {:?}", e);
tokio::time::sleep(Duration::from_secs(1)).await;
continue;
}
};
if let Err(e) = new_nic_ctx.run(ipv4_addr, ipv6_addr).await {
if let Some(output_tx) = output_tx.take() {
@@ -1561,6 +1640,11 @@ impl Instance {
self.nic_ctx.clone()
}
#[cfg(feature = "tun")]
pub fn get_shared_virtual_nic_registry(&self) -> ArcSharedVirtualNicRegistry {
self.shared_virtual_nic_registry.clone()
}
pub fn get_peer_packet_receiver(&self) -> Arc<Mutex<PacketRecvChanReceiver>> {
self.peer_packet_receiver.clone()
}
@@ -1571,6 +1655,7 @@ impl Instance {
global_ctx: ArcGlobalCtx,
peer_manager: Arc<PeerManager>,
peer_packet_receiver: Arc<Mutex<PacketRecvChanReceiver>>,
shared_virtual_nic_registry: ArcSharedVirtualNicRegistry,
fd: i32,
) -> Result<(), anyhow::Error> {
tracing::info!("setup_nic_ctx_for_mobile, fd: {}", fd);
@@ -1579,12 +1664,15 @@ impl Instance {
return Ok(());
}
let close_notifier = Arc::new(Notify::new());
let mut new_nic_ctx = NicCtx::new(
let mut new_nic_ctx = Self::new_nic_ctx(
global_ctx.clone(),
&peer_manager,
peer_packet_receiver.clone(),
close_notifier.clone(),
);
shared_virtual_nic_registry,
)
.await
.with_context(|| "create nic ctx failed")?;
new_nic_ctx
.run_for_mobile(fd)
.await
+2
View File
@@ -121,6 +121,7 @@ impl EasyTierLauncher {
let peer_mgr = instance.get_peer_manager();
let nic_ctx = instance.get_nic_ctx();
let peer_packet_receiver = instance.get_peer_packet_receiver();
let shared_virtual_nic_registry = instance.get_shared_virtual_nic_registry();
let mut tun_fd_receiver = data.tun_fd.1.lock().unwrap().take().unwrap();
tasks.spawn(async move {
@@ -133,6 +134,7 @@ impl EasyTierLauncher {
global_ctx.clone(),
peer_mgr.clone(),
peer_packet_receiver.clone(),
shared_virtual_nic_registry.clone(),
tun_fd,
)
.await;