add support for moving devices into the namespace

This commit is contained in:
Robin Appelman 2026-02-14 15:59:47 +01:00
commit 3fa69dc434
11 changed files with 411 additions and 88 deletions

View file

@ -1,5 +1,8 @@
use crate::config::{Config, ForwardConfig, NamespaceConfig, NamespaceName};
use crate::namespace::{NamespaceError, NetNs};
use crate::config::{Config, DeviceName, ForwardConfig, NamespaceConfig, NamespaceName};
use crate::link::{LinkError, LinkManager};
use crate::namespace::{
NamespaceEnterError, NamespaceError, NamespaceHandle, NamespaceHandleError, NetNs,
};
use crate::proxy::{ActiveProxy, ProxyError};
use futures::FutureExt;
use futures::StreamExt;
@ -124,6 +127,7 @@ impl State {
for namespace in &mut self.namespaces {
let config = config.get_namespace(namespace.name()).unwrap();
namespace.update_proxies(config)?;
namespace.update_devices(config)?;
}
Ok(())
@ -139,6 +143,7 @@ impl State {
struct ActiveNamespace {
ns: NetNs,
proxies: Vec<ActiveProxy>,
devices: Vec<DeviceName>,
}
impl ActiveNamespace {
@ -148,6 +153,7 @@ impl ActiveNamespace {
Ok(ActiveNamespace {
ns,
proxies: Vec::default(),
devices: Vec::default(),
})
}
@ -164,10 +170,56 @@ impl ActiveNamespace {
Ok(())
}
pub fn update_devices(&mut self, config: &NamespaceConfig) -> Result<(), DaemonError> {
let parent_namespace = NamespaceHandle::parent()?;
let removed: Vec<_> = self
.devices
.extract_if(.., |existing| {
!config.devices.iter().any(|new| existing == new)
})
.collect();
self.ns.handle().run_in(move || {
let link_manager = LinkManager::new()?;
for link in link_manager.get_links()?.flatten() {
if removed.iter().any(|name| *name == link.name.as_str()) {
info!(namespace = %config.name, link = link.name , "moving link out of namespace");
link_manager.move_link(&link, &parent_namespace)?
}
}
Ok::<_, LinkError>(())
})??;
let mut added = Vec::new();
for new in &config.devices {
if !self.has_device(new) {
added.push(new.clone());
}
}
let link_manager = LinkManager::new()?;
for link in link_manager.get_links()?.flatten() {
if added.iter().any(|name| *name == link.name.as_str()) {
info!(namespace = %config.name, link = link.name , "moving link into namespace");
link_manager.move_link(&link, self.ns.handle())?
}
}
for new in added {
self.devices.push(new);
}
Ok(())
}
fn has_forward(&self, config: &ForwardConfig) -> bool {
self.proxies.iter().any(|existing| existing == config)
}
fn has_device(&self, name: &DeviceName) -> bool {
self.devices.iter().any(|existing| existing == name)
}
pub fn name(&self) -> &NamespaceName {
self.ns.name()
}
@ -183,4 +235,10 @@ pub enum DaemonError {
Signal(IoError),
#[error(transparent)]
Proxy(#[from] ProxyError),
#[error(transparent)]
Handle(#[from] NamespaceHandleError),
#[error(transparent)]
Enter(#[from] NamespaceEnterError),
#[error(transparent)]
Link(#[from] LinkError),
}