From 122fb9b54e5f39f848aa78357a49389a8c6a24ef Mon Sep 17 00:00:00 2001 From: "sijie.sun" Date: Sat, 13 Jun 2026 01:16:17 +0800 Subject: [PATCH] refactor: add shared nic backend skeleton Introduce SharedVirtualNicMember as the per-instance handle for a shared virtual NIC and add a registry helper to create members. Add NicBackend so NicCtx can later choose between dedicated VirtualNic and shared member-backed tunnel creation without changing the existing dedicated path. --- easytier/src/instance/shared_virtual_nic.rs | 70 ++++++++++++++++++++- easytier/src/instance/virtual_nic.rs | 47 ++++++++++++++ 2 files changed, 116 insertions(+), 1 deletion(-) diff --git a/easytier/src/instance/shared_virtual_nic.rs b/easytier/src/instance/shared_virtual_nic.rs index 202d0242..c5a4ecbc 100644 --- a/easytier/src/instance/shared_virtual_nic.rs +++ b/easytier/src/instance/shared_virtual_nic.rs @@ -6,7 +6,9 @@ use std::{ }; use cidr::{Ipv4Inet, Ipv6Inet}; -use tokio::sync::Mutex; +use tokio::sync::{Mutex, Notify}; + +use crate::{common::error::Error, tunnel::Tunnel}; use super::virtual_nic::{VirtualNic, VirtualNicConfig}; @@ -270,6 +272,43 @@ impl SharedVirtualNic { } } +#[derive(Clone)] +pub struct SharedVirtualNicMember { + member_id: SharedVirtualNicMemberId, + shared_nic: Arc>, + close_notifier: Arc, +} + +impl SharedVirtualNicMember { + pub fn new( + member_id: SharedVirtualNicMemberId, + shared_nic: Arc>, + close_notifier: Arc, + ) -> Self { + Self { + member_id, + shared_nic, + close_notifier, + } + } + + pub fn member_id(&self) -> SharedVirtualNicMemberId { + self.member_id.clone() + } + + pub fn shared_nic(&self) -> Arc> { + self.shared_nic.clone() + } + + pub fn close_notifier(&self) -> Arc { + self.close_notifier.clone() + } + + pub async fn create_dev(&self) -> Result, Error> { + Err(anyhow::anyhow!("shared virtual nic member tunnel is not implemented").into()) + } +} + #[derive(Default)] pub struct SharedVirtualNicRegistry { nics: BTreeMap, @@ -323,6 +362,17 @@ impl SharedVirtualNicRegistry { self.nics.insert(dev_name, entry); nic } + + pub fn create_member( + &mut self, + dev_name: String, + config: VirtualNicConfig, + member_id: SharedVirtualNicMemberId, + close_notifier: Arc, + ) -> SharedVirtualNicMember { + let shared_nic = self.get_or_create(dev_name, config); + SharedVirtualNicMember::new(member_id, shared_nic, close_notifier) + } } fn update_owned_items( @@ -439,6 +489,7 @@ mod tests { use std::str::FromStr as _; use crate::common::netns::NetNS; + use tokio::sync::Notify; use super::*; @@ -591,4 +642,21 @@ mod tests { .is_some_and(|nic| Arc::ptr_eq(&nic, &second)) ); } + + #[test] + fn registry_create_member_uses_registered_shared_virtual_nic() { + let mut registry = SharedVirtualNicRegistry::new(); + let member_id = member_id(1); + + let member = registry.create_member( + "et0".to_string(), + virtual_nic_config(), + member_id, + Arc::new(Notify::new()), + ); + let shared_nic = registry.get("et0").unwrap(); + + assert_eq!(member.member_id(), member_id); + assert!(Arc::ptr_eq(&member.shared_nic(), &shared_nic)); + } } diff --git a/easytier/src/instance/virtual_nic.rs b/easytier/src/instance/virtual_nic.rs index 16826474..0835a3a8 100644 --- a/easytier/src/instance/virtual_nic.rs +++ b/easytier/src/instance/virtual_nic.rs @@ -44,6 +44,8 @@ use zerocopy::{NativeEndian, NetworkEndian}; #[cfg(target_os = "windows")] use crate::common::ifcfg::RegistryManager; +use super::shared_virtual_nic::SharedVirtualNicMember; + pin_project! { pub struct TunStream { #[pin] @@ -803,6 +805,51 @@ impl VirtualNic { } } +pub enum NicBackend { + Dedicated(Arc>), + Shared(SharedVirtualNicMember), +} + +impl NicBackend { + pub fn dedicated(nic: Arc>) -> Self { + Self::Dedicated(nic) + } + + pub fn shared(member: SharedVirtualNicMember) -> Self { + Self::Shared(member) + } + + pub async fn create_dev(&self) -> Result, Error> { + match self { + Self::Dedicated(nic) => nic.lock().await.create_dev().await, + Self::Shared(member) => member.create_dev().await, + } + } + + pub async fn ifname(&self) -> Option { + match self { + Self::Dedicated(nic) => nic + .lock() + .await + .ifname + .as_ref() + .map(|ifname| ifname.to_owned()), + Self::Shared(member) => { + let shared_nic = member.shared_nic(); + let nic = { + let shared_nic = shared_nic.lock().await; + shared_nic.nic() + }; + nic.lock() + .await + .ifname + .as_ref() + .map(|ifname| ifname.to_owned()) + } + } + } +} + pub struct NicCtx { global_ctx: ArcGlobalCtx, peer_mgr: Weak,