From e533b482441aede8fbcad899397055983b8f64f8 Mon Sep 17 00:00:00 2001 From: "sijie.sun" Date: Sat, 13 Jun 2026 00:51:39 +0800 Subject: [PATCH] refactor: decouple virtual nic from global ctx Move TUN-specific configuration into VirtualNicConfig so VirtualNic and SharedVirtualNic no longer depend on ArcGlobalCtx. Keep global context side effects in NicCtx, including the Windows generated device-name writeback. --- easytier/src/instance/shared_virtual_nic.rs | 51 ++++-------- easytier/src/instance/virtual_nic.rs | 91 +++++++++++++-------- 2 files changed, 77 insertions(+), 65 deletions(-) diff --git a/easytier/src/instance/shared_virtual_nic.rs b/easytier/src/instance/shared_virtual_nic.rs index b24b536e..80bb1fc0 100644 --- a/easytier/src/instance/shared_virtual_nic.rs +++ b/easytier/src/instance/shared_virtual_nic.rs @@ -7,9 +7,7 @@ use std::{ use cidr::{Ipv4Inet, Ipv6Inet}; use tokio::sync::Mutex; -use crate::common::global_ctx::ArcGlobalCtx; - -use super::virtual_nic::VirtualNic; +use super::virtual_nic::{VirtualNic, VirtualNicConfig}; pub type SharedVirtualNicMemberId = uuid::Uuid; @@ -237,40 +235,21 @@ pub struct SharedVirtualNic { } impl SharedVirtualNic { - pub fn new(global_ctx: ArcGlobalCtx) -> Self { + pub fn new(config: VirtualNicConfig) -> Self { Self { - nic: Arc::new(Mutex::new(VirtualNic::new(global_ctx))), + nic: Arc::new(Mutex::new(VirtualNic::new(config))), ifcfg: SharedIfConfig::default(), } } - pub fn attach_member( - &mut self, - member_id: SharedVirtualNicMemberId, - claims: SharedIfConfigClaims, - ) -> SharedIfConfigDelta { - self.ifcfg.apply_member_claims(member_id, claims) - } - - pub fn update_member_claims( - &mut self, - member_id: SharedVirtualNicMemberId, - claims: SharedIfConfigClaims, - ) -> SharedIfConfigDelta { - self.ifcfg.apply_member_claims(member_id, claims) - } - - pub fn detach_member( - &mut self, - member_id: SharedVirtualNicMemberId, - ) -> Option { - self.ifcfg.remove_member(member_id) - } - pub fn ifcfg(&self) -> &SharedIfConfig { &self.ifcfg } + pub fn ifcfg_mut(&mut self) -> &mut SharedIfConfig { + &mut self.ifcfg + } + pub fn nic(&self) -> Arc> { self.nic.clone() } @@ -389,7 +368,7 @@ where mod tests { use std::str::FromStr as _; - use crate::common::global_ctx::tests::get_mock_global_ctx; + use crate::common::netns::NetNS; use super::*; @@ -405,6 +384,10 @@ mod tests { } } + fn virtual_nic_config() -> VirtualNicConfig { + VirtualNicConfig::new(String::new(), 1500, NetNS::new(None)) + } + #[test] fn duplicate_routes_keep_owner_sets_and_single_os_delta() { let route = SharedIpv4Route::new(Ipv4Addr::new(10, 10, 0, 0), 24, None); @@ -486,13 +469,15 @@ mod tests { ); } - #[tokio::test] - async fn shared_virtual_nic_wraps_virtual_nic_and_tracks_ifcfg() { - let mut shared_nic = SharedVirtualNic::new(get_mock_global_ctx()); + #[test] + fn shared_virtual_nic_wraps_virtual_nic_and_tracks_ifcfg() { + let mut shared_nic = SharedVirtualNic::new(virtual_nic_config()); let member = member_id(1); let route = SharedIpv4Route::new(Ipv4Addr::new(10, 40, 0, 0), 24, None); - shared_nic.attach_member(member, claims_with_ipv4_route(route.clone(), None)); + shared_nic + .ifcfg_mut() + .apply_member_claims(member, claims_with_ipv4_route(route.clone(), None)); assert_eq!( shared_nic.ifcfg().owners_of_ipv4_route(&route), diff --git a/easytier/src/instance/virtual_nic.rs b/easytier/src/instance/virtual_nic.rs index 1faa1fd5..16826474 100644 --- a/easytier/src/instance/virtual_nic.rs +++ b/easytier/src/instance/virtual_nic.rs @@ -13,6 +13,7 @@ use crate::{ global_ctx::{ArcGlobalCtx, GlobalCtxEvent}, ifcfg::{IfConfiger, IfConfiguerTrait}, log, + netns::NetNS, }, instance::proxy_cidrs_monitor::ProxyCidrsMonitor, peers::{PacketRecvChanReceiver, peer_manager::PeerManager, recv_packet_from_chan}, @@ -239,8 +240,24 @@ impl AsyncWrite for TunAsyncWrite { } } +pub struct VirtualNicConfig { + dev_name: String, + mtu: u32, + net_ns: NetNS, +} + +impl VirtualNicConfig { + pub fn new(dev_name: String, mtu: u32, net_ns: NetNS) -> Self { + Self { + dev_name, + mtu, + net_ns, + } + } +} + pub struct VirtualNic { - global_ctx: ArcGlobalCtx, + config: VirtualNicConfig, ifname: Option, ifcfg: Box, @@ -265,9 +282,9 @@ impl Drop for VirtualNic { } impl VirtualNic { - pub fn new(global_ctx: ArcGlobalCtx) -> Self { + pub fn new(config: VirtualNicConfig) -> Self { Self { - global_ctx, + config, ifname: None, ifcfg: Box::new(IfConfiger {}), } @@ -492,14 +509,14 @@ impl VirtualNic { Ok(()) } - async fn create_tun(&self) -> Result { + async fn create_tun(&mut self) -> Result { let mut config = Configuration::default(); config.layer(Layer::L3); // FreeBSD specific: Check and restore TUN interfaces before creating new one #[cfg(target_os = "freebsd")] { - let dev_name = self.global_ctx.get_flags().dev_name; + let dev_name = self.config.dev_name.clone(); if !dev_name.is_empty() { // Restore TUN interface name if needed, ignoring errors as it's not critical @@ -512,7 +529,7 @@ impl VirtualNic { // Check and create TUN device node if necessary (Linux only) Self::ensure_tun_device_node().await; - let dev_name = self.global_ctx.get_flags().dev_name; + let dev_name = self.config.dev_name.clone(); if !dev_name.is_empty() { config.tun_name(&dev_name); } @@ -526,7 +543,7 @@ impl VirtualNic { #[cfg(target_os = "windows")] { - let dev_name = self.global_ctx.get_flags().dev_name; + let dev_name = self.config.dev_name.clone(); match crate::arch::windows::add_self_to_firewall_allowlist() { Ok(_) => tracing::info!("add_self_to_firewall_allowlist successful!"), @@ -558,10 +575,7 @@ impl VirtualNic { let random_dev_name = format!("et_{}_{}", c, s); config.tun_name(random_dev_name.clone()); - - let mut flags = self.global_ctx.get_flags(); - flags.dev_name = random_dev_name.clone(); - self.global_ctx.set_flags(flags); + self.config.dev_name = random_dev_name; } config.platform_config(|config| { @@ -575,7 +589,7 @@ impl VirtualNic { config.up(); - let _g = self.global_ctx.net_ns.guard(); + let _g = self.config.net_ns.guard(); Ok(tun::create(&config)?) } @@ -632,7 +646,7 @@ impl VirtualNic { // FreeBSD TUN interface rename functionality #[cfg(target_os = "freebsd")] { - let dev_name = self.global_ctx.get_flags().dev_name; + let dev_name = self.config.dev_name.clone(); if !dev_name.is_empty() && dev_name != ifname { // Use ifconfig to rename the TUN interface @@ -668,15 +682,10 @@ impl VirtualNic { let dev = AsyncDevice::new(dev)?; - let flags = self.global_ctx.config.get_flags(); - let mut mtu_in_config = flags.mtu; - if flags.enable_encryption { - mtu_in_config -= 20; - } { // set mtu by ourselves, rust-tun does not handle it correctly on windows - let _g = self.global_ctx.net_ns.guard(); - self.ifcfg.set_mtu(ifname.as_str(), mtu_in_config).await?; + let _g = self.config.net_ns.guard(); + self.ifcfg.set_mtu(ifname.as_str(), self.config.mtu).await?; } let has_packet_info = cfg!(all(target_os = "macos", not(feature = "macos-ne"))); @@ -723,13 +732,13 @@ impl VirtualNic { } pub async fn link_up(&self) -> Result<(), Error> { - let _g = self.global_ctx.net_ns.guard(); + let _g = self.config.net_ns.guard(); self.ifcfg.set_link_status(self.ifname(), true).await?; Ok(()) } pub async fn add_route(&self, address: Ipv4Addr, cidr: u8) -> Result<(), Error> { - let _g = self.global_ctx.net_ns.guard(); + let _g = self.config.net_ns.guard(); self.ifcfg .add_ipv4_route(self.ifname(), address, cidr, None) .await?; @@ -746,7 +755,7 @@ impl VirtualNic { cidr: u8, cost: Option, ) -> Result<(), Error> { - let _g = self.global_ctx.net_ns.guard(); + let _g = self.config.net_ns.guard(); self.ifcfg .add_ipv6_route(self.ifname(), address, cidr, cost) .await?; @@ -754,7 +763,7 @@ impl VirtualNic { } pub async fn remove_ipv6_route(&self, address: Ipv6Addr, cidr: u8) -> Result<(), Error> { - let _g = self.global_ctx.net_ns.guard(); + let _g = self.config.net_ns.guard(); self.ifcfg .remove_ipv6_route(self.ifname(), address, cidr) .await?; @@ -762,19 +771,19 @@ impl VirtualNic { } pub async fn remove_ip(&self, ip: Option) -> Result<(), Error> { - let _g = self.global_ctx.net_ns.guard(); + let _g = self.config.net_ns.guard(); self.ifcfg.remove_ip(self.ifname(), ip).await?; Ok(()) } pub async fn remove_ipv6(&self, ip: Option) -> Result<(), Error> { - let _g = self.global_ctx.net_ns.guard(); + let _g = self.config.net_ns.guard(); self.ifcfg.remove_ipv6(self.ifname(), ip).await?; Ok(()) } pub async fn add_ip(&self, ip: Ipv4Addr, cidr: i32) -> Result<(), Error> { - let _g = self.global_ctx.net_ns.guard(); + let _g = self.config.net_ns.guard(); self.ifcfg .add_ipv4_ip(self.ifname(), ip, cidr as u8) .await?; @@ -782,7 +791,7 @@ impl VirtualNic { } pub async fn add_ipv6(&self, ip: Ipv6Addr, cidr: i32) -> Result<(), Error> { - let _g = self.global_ctx.net_ns.guard(); + let _g = self.config.net_ns.guard(); self.ifcfg .add_ipv6_ip(self.ifname(), ip, cidr as u8) .await?; @@ -809,12 +818,24 @@ pub struct NicCtx { } impl NicCtx { + fn virtual_nic_config(global_ctx: &ArcGlobalCtx) -> VirtualNicConfig { + let flags = global_ctx.get_flags(); + let mut mtu = flags.mtu; + if flags.enable_encryption { + mtu -= 20; + } + + VirtualNicConfig::new(flags.dev_name, mtu, global_ctx.net_ns.clone()) + } + pub fn new( global_ctx: ArcGlobalCtx, peer_manager: &Arc, peer_packet_receiver: Arc>, close_notifier: Arc, ) -> Self { + let nic_config = Self::virtual_nic_config(&global_ctx); + NicCtx { global_ctx: global_ctx.clone(), peer_mgr: Arc::downgrade(peer_manager), @@ -822,7 +843,7 @@ impl NicCtx { close_notifier, - nic: Arc::new(Mutex::new(VirtualNic::new(global_ctx))), + nic: Arc::new(Mutex::new(VirtualNic::new(nic_config))), tasks: JoinSet::new(), #[cfg(target_os = "windows")] @@ -1344,7 +1365,12 @@ impl NicCtx { Ok(ret) => { #[cfg(target_os = "windows")] { - let dev_name = self.global_ctx.get_flags().dev_name; + let dev_name = nic.ifname().to_string(); + let mut flags = self.global_ctx.get_flags(); + if flags.dev_name.is_empty() { + flags.dev_name = dev_name.clone(); + self.global_ctx.set_flags(flags); + } let _ = RegistryManager::reg_change_catrgory_in_profile(&dev_name); } @@ -1429,10 +1455,11 @@ impl NicCtx { mod tests { use crate::common::{error::Error, global_ctx::tests::get_mock_global_ctx}; - use super::VirtualNic; + use super::{NicCtx, VirtualNic}; async fn run_test_helper() -> Result { - let mut dev = VirtualNic::new(get_mock_global_ctx()); + let global_ctx = get_mock_global_ctx(); + let mut dev = VirtualNic::new(NicCtx::virtual_nic_config(&global_ctx)); let _tunnel = dev.create_dev().await?; tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;