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.
This commit is contained in:
sijie.sun
2026-06-13 01:16:17 +08:00
parent 09780c1698
commit 122fb9b54e
2 changed files with 116 additions and 1 deletions
+69 -1
View File
@@ -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<Mutex<SharedVirtualNic>>,
close_notifier: Arc<Notify>,
}
impl SharedVirtualNicMember {
pub fn new(
member_id: SharedVirtualNicMemberId,
shared_nic: Arc<Mutex<SharedVirtualNic>>,
close_notifier: Arc<Notify>,
) -> Self {
Self {
member_id,
shared_nic,
close_notifier,
}
}
pub fn member_id(&self) -> SharedVirtualNicMemberId {
self.member_id.clone()
}
pub fn shared_nic(&self) -> Arc<Mutex<SharedVirtualNic>> {
self.shared_nic.clone()
}
pub fn close_notifier(&self) -> Arc<Notify> {
self.close_notifier.clone()
}
pub async fn create_dev(&self) -> Result<Box<dyn Tunnel>, Error> {
Err(anyhow::anyhow!("shared virtual nic member tunnel is not implemented").into())
}
}
#[derive(Default)]
pub struct SharedVirtualNicRegistry {
nics: BTreeMap<String, SharedVirtualNicRegistryEntry>,
@@ -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<Notify>,
) -> SharedVirtualNicMember {
let shared_nic = self.get_or_create(dev_name, config);
SharedVirtualNicMember::new(member_id, shared_nic, close_notifier)
}
}
fn update_owned_items<T>(
@@ -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));
}
}
+47
View File
@@ -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<Mutex<VirtualNic>>),
Shared(SharedVirtualNicMember),
}
impl NicBackend {
pub fn dedicated(nic: Arc<Mutex<VirtualNic>>) -> Self {
Self::Dedicated(nic)
}
pub fn shared(member: SharedVirtualNicMember) -> Self {
Self::Shared(member)
}
pub async fn create_dev(&self) -> Result<Box<dyn Tunnel>, 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<String> {
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<PeerManager>,