Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ log = "0.4.30"
serde = { version = "1.0.229", features = ["derive"] }
serde_json = "1.0.146"
zbus = { version = "5.19.0" }
nix = { version = "0.31.3", features = ["net", "sched", "signal", "socket", "user"] }
nix = { version = "0.31.3", features = ["net", "sched", "signal", "socket", "uio", "user"] }
rand = "0.10.3"
sha2 = "0.11.1"
base16ct = "1.0.0"
Expand Down
10 changes: 6 additions & 4 deletions examples/host-device-plugin.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
//! This is just an example plugin, do not use it in production!

use std::{collections::HashMap, os::fd::AsFd};
use std::collections::HashMap;

use netavark::{
network::{
core_utils::{open_netlink_sockets, CoreUtils},
netlink_route, types,
netlink_route,
netns::NetnsExt,
types,
},
new_error,
plugin::{Info, Plugin, PluginExec, API_VERSION},
Expand Down Expand Up @@ -69,7 +71,7 @@ impl Plugin for Exec {
}

host.netlink
.set_link_ns(link.header.index, netns.file.as_fd())?;
.set_link_ns(link.header.index, netns.file.netns_ref())?;

// interfaces map, but we only ever expect one, for response
let mut interfaces: HashMap<String, types::NetInterface> = HashMap::new();
Expand Down Expand Up @@ -104,7 +106,7 @@ impl Plugin for Exec {

netns
.netlink
.set_link_ns(link.header.index, host.file.as_fd())?;
.set_link_ns(link.header.index, host.file.netns_ref())?;

Ok(())
}
Expand Down
6 changes: 3 additions & 3 deletions src/commands/setup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::firewall;
use crate::network::driver::{get_network_driver, DriverInfo, NetworkDriver};
use crate::network::netlink::Socket;
use crate::network::netlink_route::{LinkID, NetlinkRoute};
use crate::network::netns::NetnsExt;
use crate::network::{self};
use crate::network::{core_utils, types};

Expand All @@ -15,7 +16,6 @@ use log::{debug, error, info};
use std::collections::HashMap;
use std::ffi::OsString;
use std::fs::{self};
use std::os::fd::AsFd;
use std::path::Path;

#[derive(Parser, Debug)]
Expand Down Expand Up @@ -85,8 +85,8 @@ impl Setup {
container_name: &network_options.container_name,
container_hostname: &network_options.container_hostname,
container_dns_servers: &network_options.dns_servers,
netns_host: hostns.file.as_fd(),
netns_container: Some(netns.file.as_fd()),
netns_host: hostns.file.netns_ref(),
netns_container: Some(netns.file.netns_ref()),
netns_path: &self.network_namespace_path,
network,
per_network_opts,
Expand Down
6 changes: 3 additions & 3 deletions src/commands/teardown.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ use crate::error::{NetavarkError, NetavarkErrorList, NetavarkResult};
use crate::network::constants::DRIVER_BRIDGE;
use crate::network::core_utils;
use crate::network::driver::{get_network_driver, DriverInfo};
use crate::network::netns::NetnsExt;

use crate::{firewall, network};
use clap::builder::NonEmptyStringValueParser;
use clap::Parser;
use log::debug;
use nix::sys::signal;
use std::ffi::OsString;
use std::os::fd::AsFd;
use std::path::Path;

#[derive(Parser, Debug)]
Expand Down Expand Up @@ -131,8 +131,8 @@ impl Teardown {
container_name: &network_options.container_name,
container_hostname: &network_options.container_hostname,
container_dns_servers: &network_options.dns_servers,
netns_host: hostns.file.as_fd(),
netns_container: netns_file.as_ref().map(|f| f.as_fd()), // None when no netns
netns_host: hostns.file.netns_ref(),
netns_container: netns_file.as_ref().map(|f| f.netns_ref()), // None when no netns
netns_path: &self.network_namespace_path,
network,
per_network_opts,
Expand Down
5 changes: 5 additions & 0 deletions src/dhcp_proxy/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@ use g_rpc::netavark_proxy_client::NetavarkProxyClient;
use hyper_util::rt::TokioIo;
use log::debug;
use std::fs::File;
#[cfg(target_os = "linux")]
use std::net::AddrParseError;
#[cfg(target_os = "linux")]
use std::net::Ipv4Addr;
#[cfg(target_os = "linux")]
use std::str::FromStr;
use tokio::net::UnixStream;
use tonic::transport::{Channel, Endpoint};
Expand Down Expand Up @@ -286,10 +289,12 @@ impl NetworkConfig {
}
}

#[cfg(target_os = "linux")]
trait VectorConv {
fn to_v4_addrs(&self) -> Result<Option<Vec<Ipv4Addr>>, AddrParseError>;
}

#[cfg(target_os = "linux")]
impl VectorConv for Vec<String> {
fn to_v4_addrs(&self) -> Result<Option<Vec<Ipv4Addr>>, AddrParseError> {
if self.is_empty() {
Expand Down
14 changes: 8 additions & 6 deletions src/network/bridge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ use std::{
collections::HashMap,
fs,
net::{IpAddr, Ipv4Addr, Ipv6Addr},
os::fd::BorrowedFd,
};

use crate::dns::aardvark::SafeString;
Expand Down Expand Up @@ -41,7 +40,7 @@ use super::{
OPTION_MODE, OPTION_MTU, OPTION_NO_DEFAULT_ROUTE, OPTION_OUTBOUND_ADDR4,
OPTION_OUTBOUND_ADDR6, OPTION_VLAN, OPTION_VRF, VALID_BRIDGE_OPTS,
},
core_utils::{self, get_ipam_addresses, is_using_systemd, join_netns, parse_option, CoreUtils},
core_utils::{self, get_ipam_addresses, is_using_systemd, parse_option, CoreUtils},
driver::{self, DriverInfo},
internal_types::{
IPAMAddresses, IsolateOption, PortForwardConfig, SetupNetwork, TearDownNetwork,
Expand All @@ -50,6 +49,9 @@ use super::{
sysctl,
types::StatusBlock,
};
#[cfg(target_os = "linux")]
use crate::network::core_utils::join_netns;
use crate::network::netns::NetnsRef;

const NO_BRIDGE_NAME_ERROR: &str = "no bridge interface name given";

Expand Down Expand Up @@ -737,8 +739,8 @@ fn create_interfaces(
data: &InternalData,
internal: bool,
rootless: bool,
hostns_fd: BorrowedFd<'_>,
netns_fd: BorrowedFd<'_>,
hostns_fd: NetnsRef<'_>,
netns_fd: NetnsRef<'_>,
) -> NetavarkResult<CreateInterfacesResult> {
let mut sysctl_writer = None;
let (bridge_index, mtu, mac) = match host
Expand Down Expand Up @@ -938,8 +940,8 @@ fn create_veth_pair<'fd>(
primary_index: u32,
bridge_mac: Option<Vec<u8>>,
internal: bool,
hostns_fd: BorrowedFd<'fd>,
netns_fd: BorrowedFd<'fd>,
hostns_fd: NetnsRef<'fd>,
netns_fd: NetnsRef<'fd>,
mtu: u32,
) -> NetavarkResult<String> {
let mut peer_opts =
Expand Down
61 changes: 57 additions & 4 deletions src/network/core_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,26 @@ use base16ct::HexDisplay;
use ipnet::IpNet;
use netlink_packet_route::link::{IpVlanMode, LinkMessage, MacVlanMode};
use netlink_packet_route::route::RouteType;
#[cfg(target_os = "linux")]
use nix::sched;
use sha2::{Digest, Sha512};
use std::collections::HashMap;
use std::env;
use std::fmt::Display;
use std::fs::File;
#[cfg(target_os = "linux")]
use std::io;
use std::net::IpAddr;
use std::net::Ipv4Addr;
use std::net::Ipv6Addr;
#[cfg(target_os = "linux")]
use std::os::unix::prelude::*;
use std::path::Path;
use std::str::FromStr;

use super::netlink;
use crate::network::netlink::Socket;
use crate::network::netlink_route::{LinkID, NetlinkRoute, Route};
use crate::network::netns::Netns;

use netlink_packet_route::link::LinkAttribute;

Expand Down Expand Up @@ -292,6 +295,7 @@ impl CoreUtils {
}
}

#[cfg(target_os = "linux")]
pub fn join_netns<Fd: AsFd>(fd: Fd) -> NetavarkResult<()> {
match sched::setns(fd, sched::CloneFlags::CLONE_NEWNET) {
Ok(_) => Ok(()),
Expand All @@ -305,6 +309,7 @@ pub fn join_netns<Fd: AsFd>(fd: Fd) -> NetavarkResult<()> {
/// safe way to join the namespace and join back to the host after the task is done
/// This first arg should be the hostns fd, the second is the container ns fd.
/// The third and last the closure that should be executed in the ns.
#[cfg(target_os = "linux")]
#[macro_export]
macro_rules! exec_netns {
($host:expr, $netns:expr, $exec:expr) => {{
Expand All @@ -315,13 +320,25 @@ macro_rules! exec_netns {
}};
}

/// Run the closure inside the jail in a forked child, see [`Netns::run`].
/// The closure must return `NetavarkResult<()>`.
#[cfg(target_os = "freebsd")]
#[macro_export]
macro_rules! exec_netns {
($host:expr, $netns:expr, $exec:expr) => {{
let _ = &$host;
$netns.run(|| $exec)
}};
}

pub struct NamespaceOptions {
/// Note we have to return the File object since the fd is only valid
/// as long as the File object is valid
pub file: File,
pub file: Netns,
pub netlink: Socket<NetlinkRoute>,
}

#[cfg(target_os = "linux")]
pub fn open_netlink_sockets(
netns_path: &str,
) -> NetavarkResult<(NamespaceOptions, NamespaceOptions)> {
Expand Down Expand Up @@ -349,6 +366,7 @@ pub fn open_netlink_sockets(

/// Open the host netlink socket. Used during teardown when the
/// container network namespace is no longer available.
#[cfg(target_os = "linux")]
pub fn open_host_netlink_socket() -> NetavarkResult<NamespaceOptions> {
let hostns = open_netlink_socket("/proc/self/ns/net").wrap("open host netns")?;
let host_socket = netlink::Socket::<NetlinkRoute>::new().wrap("host netlink socket")?;
Expand All @@ -359,6 +377,7 @@ pub fn open_host_netlink_socket() -> NetavarkResult<NamespaceOptions> {
}

/// Open the container netns netlink socket, given an already-opened host ns.
#[cfg(target_os = "linux")]
pub fn open_netns_netlink_socket(
netns_path: &str,
hostns: &NamespaceOptions,
Expand All @@ -375,8 +394,42 @@ pub fn open_netns_netlink_socket(
})
}

fn open_netlink_socket(netns_path: &str) -> NetavarkResult<File> {
wrap!(File::open(netns_path), format!("open {netns_path}"))
#[cfg(target_os = "linux")]
fn open_netlink_socket(netns_path: &str) -> NetavarkResult<Netns> {
wrap!(
std::fs::File::open(netns_path),
format!("open {netns_path}")
)
}

#[cfg(target_os = "freebsd")]
pub fn open_netlink_sockets(
netns_path: &str,
) -> NetavarkResult<(NamespaceOptions, NamespaceOptions)> {
let hostns = open_host_netlink_socket()?;
let netns = open_netns_netlink_socket(netns_path, &hostns)?;
Ok((hostns, netns))
}

#[cfg(target_os = "freebsd")]
pub fn open_host_netlink_socket() -> NetavarkResult<NamespaceOptions> {
Ok(NamespaceOptions {
file: Netns::host(),
netlink: netlink::Socket::<NetlinkRoute>::new().wrap("host netlink socket")?,
})
}

/// Open the netlink socket for the jail named `netns_path`.
#[cfg(target_os = "freebsd")]
pub fn open_netns_netlink_socket(
netns_path: &str,
_hostns: &NamespaceOptions,
) -> NetavarkResult<NamespaceOptions> {
let jail = wrap!(Netns::open(netns_path), format!("open jail {netns_path}"))?;
Ok(NamespaceOptions {
netlink: jail.netlink_socket().wrap("netns netlink socket")?,
file: jail,
})
}

pub fn add_default_routes(
Expand Down
7 changes: 4 additions & 3 deletions src/network/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::{
firewall::FirewallDriver,
};

use std::{ffi::OsString, net::IpAddr, os::fd::BorrowedFd, path::Path};
use std::{ffi::OsString, net::IpAddr, path::Path};

use super::{
bridge::Bridge,
Expand All @@ -15,15 +15,16 @@ use super::{
};
use crate::network::netlink::Socket;
use crate::network::netlink_route::NetlinkRoute;
use crate::network::netns::NetnsRef;
use std::os::unix::fs::PermissionsExt;

pub struct DriverInfo<'a> {
pub firewall: &'a dyn FirewallDriver,
pub container_id: &'a String,
pub container_name: &'a String,
pub container_dns_servers: &'a Option<Vec<IpAddr>>,
pub netns_host: BorrowedFd<'a>,
pub netns_container: Option<BorrowedFd<'a>>,
pub netns_host: NetnsRef<'a>,
pub netns_container: Option<NetnsRef<'a>>,
pub netns_path: &'a str,
pub network: &'a Network,
pub per_network_opts: &'a PerNetworkOptions,
Expand Down
1 change: 1 addition & 0 deletions src/network/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ pub mod internal_types;
pub mod netlink;
pub mod netlink_route;
mod netlink_socket;
pub mod netns;

pub mod plugin;
pub mod sysctl;
Expand Down
7 changes: 6 additions & 1 deletion src/network/netlink.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,12 @@ where
P: NetlinkFamily,
{
pub fn new() -> NetavarkResult<Socket<P>> {
let mut socket = wrap!(RawSocket::new(P::PROTOCOL), "open")?;
Self::from_raw(wrap!(RawSocket::new(P::PROTOCOL), "open")?)
}

/// Finish setting up a socket that was opened elsewhere, for example
/// inside a FreeBSD jail.
pub(crate) fn from_raw(mut socket: RawSocket) -> NetavarkResult<Socket<P>> {
let addr = &SocketAddr::new(0, 0);
// Needs to be enabled for dump filtering to work
socket.set_netlink_get_strict_chk(true)?;
Expand Down
Loading
Loading