minor link handling improvements

This commit is contained in:
Robin Appelman 2026-02-23 20:02:25 +01:00
commit 35c8f5cc6c
2 changed files with 28 additions and 30 deletions

View file

@ -1,4 +1,3 @@
use crate::namespace::{NamespaceEnterError, NamespaceHandle};
use neli::consts::nl::NlmF;
use neli::consts::rtnl::Ifla;
use neli::consts::rtnl::RtAddrFamily;
@ -12,25 +11,28 @@ use neli::rtnl::{Ifinfomsg, RtattrBuilder};
use neli::types::{Buffer, RtBuffer};
use neli::utils::Groups;
use nix::libc::c_int;
use std::fmt::Debug;
use std::os::fd::AsRawFd;
use thiserror::Error;
use tracing::info;
#[derive(Debug, Error)]
pub enum LinkError {
#[error("failed to communicate with netlink")]
Netlink,
#[error("failed to code netlink response")]
Parse,
#[error("Failed to communicate with netlink:")]
Netlink(String),
#[error("Failed to parse netlink response")]
Parse(String),
#[error("Link not found: {0}")]
NotFound(String),
#[error(transparent)]
Enter(#[from] NamespaceEnterError),
}
impl<T, P> From<RouterError<T, P>> for LinkError {
fn from(_value: RouterError<T, P>) -> Self {
LinkError::Netlink
impl<T, P> From<RouterError<T, P>> for LinkError
where
T: Debug,
P: Debug,
{
fn from(value: RouterError<T, P>) -> Self {
LinkError::Netlink(value.to_string())
}
}
@ -89,7 +91,7 @@ impl LinkManager {
.rtattrs()
.get_attr_handle()
.get_attr_payload_as_with_len::<String>(Ifla::Ifname)
.map_err(|_| LinkError::Parse)?;
.map_err(|e| LinkError::Parse(e.to_string()))?;
Ok(Some(Link {
family: *payload.ifi_family(),
index: *payload.ifi_index(),
@ -103,7 +105,7 @@ impl LinkManager {
}
/// Move a link to a namespace
pub fn move_link<Fd: AsRawFd>(&self, link: &Link, namespace: Fd) -> Result<(), LinkError> {
pub fn move_link<Fd: AsRawFd>(&self, link: &Link, namespace: &Fd) -> Result<(), LinkError> {
let ns_handle = namespace.as_raw_fd();
let mut info_attrs = RtBuffer::<Ifla, Buffer>::new();
@ -143,27 +145,21 @@ pub fn link_up(link_name: &str) -> Result<(), LinkError> {
}
/// Move a link into a namespace
pub fn move_link_into(link_name: &str, namespace: &NamespaceHandle) -> Result<(), LinkError> {
pub fn move_link_into<Fd: AsRawFd>(link_name: &str, namespace: &Fd) -> Result<(), LinkError> {
let manager = LinkManager::new()?;
let link = manager.get_link(link_name)?;
info!(name = &link.name, "moving link into namespace");
manager.move_link(&link, namespace)
}
/// Move all links out of a namespace, except for lo
pub fn move_all_links_out(
namespace: &NamespaceHandle,
parent: &NamespaceHandle,
) -> Result<(), LinkError> {
namespace.run_in(|| {
let manager = LinkManager::new()?;
for link in manager.get_links()?.flatten() {
if link.name != "lo" {
info!(name = &link.name, "moving link out of namespace");
manager.move_link(&link, parent)?
}
/// Move all links from the current namespace (except lo) into a namespace
pub fn move_all_links<Fd: AsRawFd>(namespace: &Fd) -> Result<(), LinkError> {
let manager = LinkManager::new()?;
for link in manager.get_links()?.flatten() {
if link.name != "lo" {
info!(name = &link.name, "moving link");
manager.move_link(&link, namespace)?
}
Ok::<_, LinkError>(())
})??;
Ok(())
}
Ok::<_, LinkError>(())
}

View file

@ -2,7 +2,7 @@ mod handle;
mod raw;
use crate::config::{DeviceName, NamespaceName};
use crate::link::{link_up, move_all_links_out, move_link_into, LinkError};
use crate::link::{link_up, move_all_links, move_link_into, LinkError};
pub use crate::namespace::handle::{NamespaceHandle, NamespaceHandleError};
use crate::namespace::raw::{create_network_namespace, NamespaceSetupError};
use either::Either;
@ -162,7 +162,9 @@ impl NetNs {
pub fn delete(self) -> Result<(), NamespaceError> {
let parent_namespace = NamespaceHandle::parent()?;
move_all_links_out(self.handle(), &parent_namespace)?;
self.handle.run_in(|| {
move_all_links(&parent_namespace)
})??;
let name = self.path.file_name().unwrap().to_str().unwrap();
info!(name, "deleting network namespace");
match umount2(&self.path, MntFlags::MNT_DETACH) {