Move the overlay interface to the system level
One agent, one interface, owned by the agent rather than by a protocol. That is what makes several protocols able to be live at once: a packet leaving the interface is routed to whichever peer owns its destination, over whichever protocol has a link to that peer, and neither protocol has to hold the address because the agent holds it. This commit moves the pieces without changing behaviour: provisioning, the TUN itself, IP header parsing and interface naming are now crates/tsunagi/src/overlay, and the WireGuard module re-exports them while its callers are moved over. They were never WireGuard-specific — netlink, capabilities and `ip tuntap` have nothing to do with the protocol running on top. They also get their own error type. An interface that cannot be created is not a plugin failing, and now that the two belong to different levels they should not share a word for it. Routing, addressing and the reduced plugin contract come next. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -67,6 +67,20 @@ pub enum PluginError {
|
|||||||
Other(String),
|
Other(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Scaffolding while the interface moves out of the plugin.
|
||||||
|
///
|
||||||
|
/// The overlay interface belongs to the system level now, so a plugin has no
|
||||||
|
/// business failing because of it. This exists only for the callers that
|
||||||
|
/// have not been moved over yet and goes when the last of them does.
|
||||||
|
impl From<crate::overlay::OverlayError> for PluginError {
|
||||||
|
fn from(err: crate::overlay::OverlayError) -> Self {
|
||||||
|
match err {
|
||||||
|
crate::overlay::OverlayError::Unavailable(reason) => PluginError::Unavailable(reason),
|
||||||
|
crate::overlay::OverlayError::Other(reason) => PluginError::Other(reason),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A request a plugin makes of the agent that owns it.
|
/// A request a plugin makes of the agent that owns it.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) enum PluginRequest {
|
pub(crate) enum PluginRequest {
|
||||||
|
|||||||
@@ -43,8 +43,8 @@ use crate::identity::NetworkId;
|
|||||||
|
|
||||||
use super::keys::{WgPublicKey, WgSecretKey};
|
use super::keys::{WgPublicKey, WgSecretKey};
|
||||||
use super::overlay::overlay_address;
|
use super::overlay::overlay_address;
|
||||||
use super::packet::IpHeader;
|
use crate::overlay::packet::IpHeader;
|
||||||
use super::tun::TunDevice;
|
use crate::overlay::tun::TunDevice;
|
||||||
use crate::state::Ipv4Range;
|
use crate::state::Ipv4Range;
|
||||||
|
|
||||||
/// How often WireGuard's own timers are driven.
|
/// How often WireGuard's own timers are driven.
|
||||||
|
|||||||
@@ -42,34 +42,34 @@
|
|||||||
//! See `docs/wireguard.md` for the full picture.
|
//! See `docs/wireguard.md` for the full picture.
|
||||||
|
|
||||||
pub mod announcement;
|
pub mod announcement;
|
||||||
pub mod config;
|
|
||||||
pub mod device;
|
pub mod device;
|
||||||
pub mod keys;
|
pub mod keys;
|
||||||
pub mod overlay;
|
pub mod overlay;
|
||||||
pub mod packet;
|
|
||||||
pub mod plugin;
|
pub mod plugin;
|
||||||
pub mod provision;
|
|
||||||
pub mod store;
|
pub mod store;
|
||||||
pub mod tun;
|
|
||||||
|
|
||||||
pub use crate::state::Ipv4Range;
|
pub use crate::state::Ipv4Range;
|
||||||
pub use announcement::{ValidatedAnnouncement, WgAnnouncement};
|
pub use announcement::{ValidatedAnnouncement, WgAnnouncement};
|
||||||
pub use config::{Cidr, DEFAULT_INTERFACE_PREFIX, MAX_INTERFACE_NAME_LEN, interface_name};
|
// The interface, its addresses and how it is created belong to the system
|
||||||
pub use device::{PeerHealth, PeerStats, PeerSummary, WireguardDevice};
|
// level now: one agent has one interface, and no protocol owns it. Re-exported
|
||||||
pub use keys::{WgPublicKey, WgSecretKey};
|
// here while callers are moved over.
|
||||||
pub use overlay::{OVERLAY_PREFIX_LEN, overlay_address, overlay_address_v4, overlay_prefix};
|
pub use crate::overlay::provision::{
|
||||||
pub use packet::IpHeader;
|
|
||||||
pub use plugin::{
|
|
||||||
DEFAULT_MTU, MIN_MTU, NetworkOverview, PeerOverview, WIREGUARD_OVERHEAD, WIREGUARD_PROTOCOL,
|
|
||||||
WireguardConfig, WireguardPlugin,
|
|
||||||
};
|
|
||||||
pub use provision::{
|
|
||||||
Changes, InterfacePlan, InterfaceProvisioner, InterfaceState, LinkKind, ManagedTunFactory,
|
Changes, InterfacePlan, InterfaceProvisioner, InterfaceState, LinkKind, ManagedTunFactory,
|
||||||
MockHost, MockProvisioner, Privilege, Provisioned, UnsupportedProvisioner, plan_changes,
|
MockHost, MockProvisioner, Privilege, Provisioned, UnsupportedProvisioner, plan_changes,
|
||||||
probe_net_admin,
|
probe_net_admin,
|
||||||
};
|
};
|
||||||
|
pub use crate::overlay::{
|
||||||
|
Cidr, DEFAULT_INTERFACE_PREFIX, IpHeader, MAX_INTERFACE_NAME_LEN, MemoryTun, MemoryTunFactory,
|
||||||
|
TunDevice, TunFactory, TunRequest, address_is_local, interface_name,
|
||||||
|
};
|
||||||
|
pub use device::{PeerHealth, PeerStats, PeerSummary, WireguardDevice};
|
||||||
|
pub use keys::{WgPublicKey, WgSecretKey};
|
||||||
|
pub use overlay::{OVERLAY_PREFIX_LEN, overlay_address, overlay_address_v4, overlay_prefix};
|
||||||
|
pub use plugin::{
|
||||||
|
DEFAULT_MTU, MIN_MTU, NetworkOverview, PeerOverview, WIREGUARD_OVERHEAD, WIREGUARD_PROTOCOL,
|
||||||
|
WireguardConfig, WireguardPlugin,
|
||||||
|
};
|
||||||
pub use store::WgKeyStore;
|
pub use store::WgKeyStore;
|
||||||
pub use tun::{MemoryTun, MemoryTunFactory, TunDevice, TunFactory, TunRequest, address_is_local};
|
|
||||||
|
|
||||||
#[cfg(all(feature = "tun-device", target_os = "linux"))]
|
#[cfg(all(feature = "tun-device", target_os = "linux"))]
|
||||||
pub use provision::NetlinkProvisioner;
|
pub use crate::overlay::NetlinkProvisioner;
|
||||||
|
|||||||
@@ -40,12 +40,12 @@ use crate::dataplane::{IpPlugin, PluginCapability, PluginContext, PluginError};
|
|||||||
use crate::identity::NetworkId;
|
use crate::identity::NetworkId;
|
||||||
|
|
||||||
use super::announcement::{ValidatedAnnouncement, WgAnnouncement};
|
use super::announcement::{ValidatedAnnouncement, WgAnnouncement};
|
||||||
use super::config::{DEFAULT_INTERFACE_PREFIX, interface_name};
|
|
||||||
use super::device::{PeerSummary, WireguardDevice};
|
use super::device::{PeerSummary, WireguardDevice};
|
||||||
use super::keys::{WgPublicKey, WgSecretKey};
|
use super::keys::{WgPublicKey, WgSecretKey};
|
||||||
use super::overlay::{OVERLAY_PREFIX_LEN, overlay_address, overlay_prefix};
|
use super::overlay::{OVERLAY_PREFIX_LEN, overlay_address, overlay_prefix};
|
||||||
use super::store::WgKeyStore;
|
use super::store::WgKeyStore;
|
||||||
use super::tun::{TunFactory, TunRequest};
|
use crate::overlay::config::{DEFAULT_INTERFACE_PREFIX, interface_name};
|
||||||
|
use crate::overlay::tun::{TunFactory, TunRequest};
|
||||||
use crate::state::Ipv4Range;
|
use crate::state::Ipv4Range;
|
||||||
|
|
||||||
/// The protocol identifier this plugin announces.
|
/// The protocol identifier this plugin announces.
|
||||||
@@ -603,7 +603,7 @@ impl Worker {
|
|||||||
// kind that has been wrong here before.
|
// kind that has been wrong here before.
|
||||||
let missing_v4 = match (own_v4, interface.as_deref(), range) {
|
let missing_v4 = match (own_v4, interface.as_deref(), range) {
|
||||||
(Some(address), Some(interface), Some(range))
|
(Some(address), Some(interface), Some(range))
|
||||||
if !super::tun::address_is_local(IpAddr::V4(address)) =>
|
if !crate::overlay::tun::address_is_local(IpAddr::V4(address)) =>
|
||||||
{
|
{
|
||||||
let already = state_reported == Some(address);
|
let already = state_reported == Some(address);
|
||||||
if let Some(state) = shared.networks.get_mut(&network) {
|
if let Some(state) = shared.networks.get_mut(&network) {
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ pub mod error;
|
|||||||
pub mod identity;
|
pub mod identity;
|
||||||
pub mod ipc;
|
pub mod ipc;
|
||||||
pub mod net;
|
pub mod net;
|
||||||
|
pub mod overlay;
|
||||||
pub mod proto;
|
pub mod proto;
|
||||||
pub mod state;
|
pub mod state;
|
||||||
pub mod storage;
|
pub mod storage;
|
||||||
|
|||||||
+10
-9
@@ -11,10 +11,11 @@
|
|||||||
|
|
||||||
use std::net::{IpAddr, Ipv6Addr};
|
use std::net::{IpAddr, Ipv6Addr};
|
||||||
|
|
||||||
use crate::dataplane::PluginError;
|
|
||||||
use crate::identity::NetworkId;
|
use crate::identity::NetworkId;
|
||||||
|
use crate::overlay::OverlayError;
|
||||||
|
|
||||||
use super::overlay::OVERLAY_HOST_PREFIX_LEN;
|
/// Prefix length of a single IPv6 host address.
|
||||||
|
const HOST_PREFIX_LEN: u8 = 128;
|
||||||
|
|
||||||
/// Longest interface name Linux accepts, excluding the terminating NUL.
|
/// Longest interface name Linux accepts, excluding the terminating NUL.
|
||||||
pub const MAX_INTERFACE_NAME_LEN: usize = 15;
|
pub const MAX_INTERFACE_NAME_LEN: usize = 15;
|
||||||
@@ -33,13 +34,13 @@ pub struct Cidr {
|
|||||||
|
|
||||||
impl Cidr {
|
impl Cidr {
|
||||||
/// Builds a CIDR, rejecting an impossible prefix length.
|
/// Builds a CIDR, rejecting an impossible prefix length.
|
||||||
pub fn new(addr: IpAddr, prefix_len: u8) -> Result<Self, PluginError> {
|
pub fn new(addr: IpAddr, prefix_len: u8) -> Result<Self, OverlayError> {
|
||||||
let max = match addr {
|
let max = match addr {
|
||||||
IpAddr::V4(_) => 32,
|
IpAddr::V4(_) => 32,
|
||||||
IpAddr::V6(_) => 128,
|
IpAddr::V6(_) => 128,
|
||||||
};
|
};
|
||||||
if prefix_len > max {
|
if prefix_len > max {
|
||||||
return Err(PluginError::Other(format!(
|
return Err(OverlayError::Other(format!(
|
||||||
"prefix length /{prefix_len} is impossible for {addr}"
|
"prefix length /{prefix_len} is impossible for {addr}"
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
@@ -50,7 +51,7 @@ impl Cidr {
|
|||||||
pub fn host(addr: Ipv6Addr) -> Self {
|
pub fn host(addr: Ipv6Addr) -> Self {
|
||||||
Self {
|
Self {
|
||||||
addr: IpAddr::V6(addr),
|
addr: IpAddr::V6(addr),
|
||||||
prefix_len: OVERLAY_HOST_PREFIX_LEN,
|
prefix_len: HOST_PREFIX_LEN,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -66,9 +67,9 @@ impl std::fmt::Display for Cidr {
|
|||||||
/// The name is stable across restarts and short enough for the platform. Two
|
/// The name is stable across restarts and short enough for the platform. Two
|
||||||
/// agents on the same host in the same network must be given different
|
/// agents on the same host in the same network must be given different
|
||||||
/// prefixes, or they would derive the same name.
|
/// prefixes, or they would derive the same name.
|
||||||
pub fn interface_name(prefix: &str, network: NetworkId) -> Result<String, PluginError> {
|
pub fn interface_name(prefix: &str, network: NetworkId) -> Result<String, OverlayError> {
|
||||||
if prefix.is_empty() {
|
if prefix.is_empty() {
|
||||||
return Err(PluginError::Other(
|
return Err(OverlayError::Other(
|
||||||
"interface prefix must not be empty".into(),
|
"interface prefix must not be empty".into(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@@ -76,12 +77,12 @@ pub fn interface_name(prefix: &str, network: NetworkId) -> Result<String, Plugin
|
|||||||
.chars()
|
.chars()
|
||||||
.all(|c| c.is_ascii_lowercase() || c.is_ascii_digit())
|
.all(|c| c.is_ascii_lowercase() || c.is_ascii_digit())
|
||||||
{
|
{
|
||||||
return Err(PluginError::Other(
|
return Err(OverlayError::Other(
|
||||||
"interface prefix must be lowercase ASCII letters and digits".into(),
|
"interface prefix must be lowercase ASCII letters and digits".into(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
if prefix.len() >= MAX_INTERFACE_NAME_LEN {
|
if prefix.len() >= MAX_INTERFACE_NAME_LEN {
|
||||||
return Err(PluginError::Other(format!(
|
return Err(OverlayError::Other(format!(
|
||||||
"interface prefix must be shorter than {MAX_INTERFACE_NAME_LEN} characters"
|
"interface prefix must be shorter than {MAX_INTERFACE_NAME_LEN} characters"
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
//! The overlay interface: the one network interface an agent owns.
|
||||||
|
//!
|
||||||
|
//! One agent, one interface. It belongs to the system level rather than to
|
||||||
|
//! any protocol, and that is the whole point: a packet leaving it is routed
|
||||||
|
//! to whichever peer owns its destination address, over whichever protocol
|
||||||
|
//! currently has a link to that peer. Several protocols can be live at once
|
||||||
|
//! without arguing over who holds the address, because neither of them
|
||||||
|
//! holds it — the agent does.
|
||||||
|
//!
|
||||||
|
//! What lives here:
|
||||||
|
//!
|
||||||
|
//! * [`provision`] creates the interface and configures it, and removes it
|
||||||
|
//! again. Platform mechanics behind one decision function.
|
||||||
|
//! * [`tun`] is the packet interface itself, real or in memory.
|
||||||
|
//! * [`packet`] reads just enough of an IP header to route by it.
|
||||||
|
//! * [`config`] names interfaces and describes addresses.
|
||||||
|
//!
|
||||||
|
//! What does not live here: encryption, peer discovery, and how a packet
|
||||||
|
//! actually reaches another machine. Those belong to a protocol plugin,
|
||||||
|
//! which this level hands packets to and takes packets from.
|
||||||
|
|
||||||
|
/// Why the overlay interface cannot be brought into the state asked for.
|
||||||
|
///
|
||||||
|
/// Its own error rather than the plugin one it used to borrow: this level
|
||||||
|
/// owns the interface now, and a plugin failing is a different event from
|
||||||
|
/// the interface failing.
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub enum OverlayError {
|
||||||
|
/// The interface cannot be created or configured right now, with the
|
||||||
|
/// reason and, where there is one, what to do about it.
|
||||||
|
#[error("overlay unavailable: {0}")]
|
||||||
|
Unavailable(String),
|
||||||
|
/// Anything else.
|
||||||
|
#[error("{0}")]
|
||||||
|
Other(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod config;
|
||||||
|
pub mod packet;
|
||||||
|
pub mod provision;
|
||||||
|
pub mod tun;
|
||||||
|
|
||||||
|
pub use config::{Cidr, DEFAULT_INTERFACE_PREFIX, MAX_INTERFACE_NAME_LEN, interface_name};
|
||||||
|
pub use packet::IpHeader;
|
||||||
|
pub use provision::{
|
||||||
|
Changes, InterfacePlan, InterfaceProvisioner, InterfaceState, LinkKind, ManagedTunFactory,
|
||||||
|
MockHost, MockProvisioner, Privilege, Provisioned, UnsupportedProvisioner, plan_changes,
|
||||||
|
probe_net_admin,
|
||||||
|
};
|
||||||
|
pub use tun::{MemoryTun, MemoryTunFactory, TunDevice, TunFactory, TunRequest, address_is_local};
|
||||||
|
|
||||||
|
#[cfg(all(feature = "tun-device", target_os = "linux"))]
|
||||||
|
pub use provision::NetlinkProvisioner;
|
||||||
+5
-5
@@ -9,14 +9,14 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::BoxFuture;
|
use crate::BoxFuture;
|
||||||
use crate::dataplane::PluginError;
|
use crate::overlay::OverlayError;
|
||||||
|
|
||||||
use super::super::config::Cidr;
|
use super::super::config::Cidr;
|
||||||
use super::super::tun::{TunDevice, TunFactory, TunRequest};
|
use super::super::tun::{TunDevice, TunFactory, TunRequest};
|
||||||
use super::{InterfacePlan, InterfaceProvisioner};
|
use super::{InterfacePlan, InterfaceProvisioner};
|
||||||
|
|
||||||
/// Turns a [`TunRequest`] into the plan for a host interface.
|
/// Turns a [`TunRequest`] into the plan for a host interface.
|
||||||
fn plan_for(request: &TunRequest) -> Result<InterfacePlan, PluginError> {
|
fn plan_for(request: &TunRequest) -> Result<InterfacePlan, OverlayError> {
|
||||||
let mut addresses = vec![Cidr::new(request.address.into(), request.prefix_len)?];
|
let mut addresses = vec![Cidr::new(request.address.into(), request.prefix_len)?];
|
||||||
if let Some(address) = request.address_v4 {
|
if let Some(address) = request.address_v4 {
|
||||||
addresses.push(Cidr::new(address.into(), request.prefix_len_v4)?);
|
addresses.push(Cidr::new(address.into(), request.prefix_len_v4)?);
|
||||||
@@ -54,7 +54,7 @@ impl TunFactory for ManagedTunFactory {
|
|||||||
fn create<'a>(
|
fn create<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
request: TunRequest,
|
request: TunRequest,
|
||||||
) -> BoxFuture<'a, Result<Arc<dyn TunDevice>, PluginError>> {
|
) -> BoxFuture<'a, Result<Arc<dyn TunDevice>, OverlayError>> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let plan = plan_for(&request)?;
|
let plan = plan_for(&request)?;
|
||||||
let provisioned = self.provisioner.reconcile(&plan).await?;
|
let provisioned = self.provisioner.reconcile(&plan).await?;
|
||||||
@@ -67,7 +67,7 @@ impl TunFactory for ManagedTunFactory {
|
|||||||
// Reaching here would mean the interface already existed and
|
// Reaching here would mean the interface already existed and
|
||||||
// was held open by us, which cannot be true on the path that
|
// was held open by us, which cannot be true on the path that
|
||||||
// creates a device.
|
// creates a device.
|
||||||
PluginError::Other(format!(
|
OverlayError::Other(format!(
|
||||||
"interface `{}` was reconciled but no device came back",
|
"interface `{}` was reconciled but no device came back",
|
||||||
plan.name
|
plan.name
|
||||||
))
|
))
|
||||||
@@ -75,7 +75,7 @@ impl TunFactory for ManagedTunFactory {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reconfigure<'a>(&'a self, request: TunRequest) -> BoxFuture<'a, Result<(), PluginError>> {
|
fn reconfigure<'a>(&'a self, request: TunRequest) -> BoxFuture<'a, Result<(), OverlayError>> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let plan = plan_for(&request)?;
|
let plan = plan_for(&request)?;
|
||||||
let provisioned = self.provisioner.reconcile(&plan).await?;
|
let provisioned = self.provisioner.reconcile(&plan).await?;
|
||||||
+27
-27
@@ -50,7 +50,7 @@ use rtnetlink::packet_route::link::{InfoKind, LinkAttribute, LinkFlags, LinkInfo
|
|||||||
use rtnetlink::{LinkMessageBuilder, LinkUnspec};
|
use rtnetlink::{LinkMessageBuilder, LinkUnspec};
|
||||||
|
|
||||||
use crate::BoxFuture;
|
use crate::BoxFuture;
|
||||||
use crate::dataplane::PluginError;
|
use crate::overlay::OverlayError;
|
||||||
|
|
||||||
use super::super::config::Cidr;
|
use super::super::config::Cidr;
|
||||||
use super::super::tun::{TunDevice, TunRequest};
|
use super::super::tun::{TunDevice, TunRequest};
|
||||||
@@ -71,7 +71,7 @@ enum Command {
|
|||||||
Stop,
|
Stop,
|
||||||
}
|
}
|
||||||
|
|
||||||
type Reply<T> = mpsc::Sender<Result<T, PluginError>>;
|
type Reply<T> = mpsc::Sender<Result<T, OverlayError>>;
|
||||||
|
|
||||||
/// The configuration half of a reconciliation.
|
/// The configuration half of a reconciliation.
|
||||||
struct Configure {
|
struct Configure {
|
||||||
@@ -97,17 +97,17 @@ pub struct NetlinkProvisioner {
|
|||||||
|
|
||||||
impl NetlinkProvisioner {
|
impl NetlinkProvisioner {
|
||||||
/// Starts the netlink thread, after checking this process can use it.
|
/// Starts the netlink thread, after checking this process can use it.
|
||||||
pub fn new() -> Result<Self, PluginError> {
|
pub fn new() -> Result<Self, OverlayError> {
|
||||||
match probe_net_admin() {
|
match probe_net_admin() {
|
||||||
Privilege::Available => {}
|
Privilege::Available => {}
|
||||||
Privilege::Missing(reason) => {
|
Privilege::Missing(reason) => {
|
||||||
return Err(PluginError::Unavailable(format!(
|
return Err(OverlayError::Unavailable(format!(
|
||||||
"{reason}. {}",
|
"{reason}. {}",
|
||||||
Privilege::how_to_grant(¤t_program())
|
Privilege::how_to_grant(¤t_program())
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
Privilege::Unsupported => {
|
Privilege::Unsupported => {
|
||||||
return Err(PluginError::Unavailable(
|
return Err(OverlayError::Unavailable(
|
||||||
"interface management is not compiled in".to_string(),
|
"interface management is not compiled in".to_string(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@@ -118,7 +118,7 @@ impl NetlinkProvisioner {
|
|||||||
.name("tsunagi-netlink".to_string())
|
.name("tsunagi-netlink".to_string())
|
||||||
.spawn(move || netlink_thread(requests))
|
.spawn(move || netlink_thread(requests))
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
PluginError::Unavailable(format!("cannot start the netlink thread: {err}"))
|
OverlayError::Unavailable(format!("cannot start the netlink thread: {err}"))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
@@ -132,13 +132,13 @@ impl NetlinkProvisioner {
|
|||||||
fn call<T: Send + 'static>(
|
fn call<T: Send + 'static>(
|
||||||
&self,
|
&self,
|
||||||
make: impl FnOnce(Reply<T>) -> Command,
|
make: impl FnOnce(Reply<T>) -> Command,
|
||||||
) -> Result<T, PluginError> {
|
) -> Result<T, OverlayError> {
|
||||||
let (reply_tx, reply_rx) = mpsc::channel();
|
let (reply_tx, reply_rx) = mpsc::channel();
|
||||||
self.commands
|
self.commands
|
||||||
.send(make(reply_tx))
|
.send(make(reply_tx))
|
||||||
.map_err(|_| PluginError::Unavailable("the netlink thread has stopped".to_string()))?;
|
.map_err(|_| OverlayError::Unavailable("the netlink thread has stopped".to_string()))?;
|
||||||
reply_rx.recv().map_err(|_| {
|
reply_rx.recv().map_err(|_| {
|
||||||
PluginError::Unavailable("the netlink thread stopped mid-request".to_string())
|
OverlayError::Unavailable("the netlink thread stopped mid-request".to_string())
|
||||||
})?
|
})?
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,7 +150,7 @@ impl NetlinkProvisioner {
|
|||||||
///
|
///
|
||||||
/// Synchronous on purpose: the capability guard is raised and lowered
|
/// Synchronous on purpose: the capability guard is raised and lowered
|
||||||
/// without an `await` in between, so it cannot outlive this thread.
|
/// without an `await` in between, so it cannot outlive this thread.
|
||||||
fn create_device(&self, plan: &InterfacePlan) -> Result<Arc<dyn TunDevice>, PluginError> {
|
fn create_device(&self, plan: &InterfacePlan) -> Result<Arc<dyn TunDevice>, OverlayError> {
|
||||||
let request = TunRequest::bare(plan.name.clone(), plan.mtu);
|
let request = TunRequest::bare(plan.name.clone(), plan.mtu);
|
||||||
let _guard = NetAdmin::acquire()?;
|
let _guard = NetAdmin::acquire()?;
|
||||||
super::super::tun::open_tun(&request)
|
super::super::tun::open_tun(&request)
|
||||||
@@ -174,7 +174,7 @@ impl InterfaceProvisioner for NetlinkProvisioner {
|
|||||||
fn reconcile<'a>(
|
fn reconcile<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
plan: &'a InterfacePlan,
|
plan: &'a InterfacePlan,
|
||||||
) -> BoxFuture<'a, Result<Provisioned, PluginError>> {
|
) -> BoxFuture<'a, Result<Provisioned, OverlayError>> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let current = self.call(|reply| Command::Observe(plan.name.clone(), reply))?;
|
let current = self.call(|reply| Command::Observe(plan.name.clone(), reply))?;
|
||||||
let changes = plan_changes(¤t, plan, self.is_ours(&plan.name))?;
|
let changes = plan_changes(¤t, plan, self.is_ours(&plan.name))?;
|
||||||
@@ -224,7 +224,7 @@ impl InterfaceProvisioner for NetlinkProvisioner {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove<'a>(&'a self, name: &'a str) -> BoxFuture<'a, Result<(), PluginError>> {
|
fn remove<'a>(&'a self, name: &'a str) -> BoxFuture<'a, Result<(), OverlayError>> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
// Dropping the device is what removes the interface; the explicit
|
// Dropping the device is what removes the interface; the explicit
|
||||||
// delete is only so it is gone by the time this returns rather
|
// delete is only so it is gone by the time this returns rather
|
||||||
@@ -271,10 +271,10 @@ fn netlink_thread(requests: mpsc::Receiver<Command>) {
|
|||||||
let message = format!("the netlink thread has no runtime: {err}");
|
let message = format!("the netlink thread has no runtime: {err}");
|
||||||
match command {
|
match command {
|
||||||
Command::Observe(_, reply) => {
|
Command::Observe(_, reply) => {
|
||||||
let _ = reply.send(Err(PluginError::Unavailable(message)));
|
let _ = reply.send(Err(OverlayError::Unavailable(message)));
|
||||||
}
|
}
|
||||||
Command::Delete(_, reply) | Command::Configure(_, reply) => {
|
Command::Delete(_, reply) | Command::Configure(_, reply) => {
|
||||||
let _ = reply.send(Err(PluginError::Unavailable(message)));
|
let _ = reply.send(Err(OverlayError::Unavailable(message)));
|
||||||
}
|
}
|
||||||
Command::Stop => return,
|
Command::Stop => return,
|
||||||
}
|
}
|
||||||
@@ -311,12 +311,12 @@ fn netlink_thread(requests: mpsc::Receiver<Command>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Opens a netlink connection and runs one unit of work over it.
|
/// Opens a netlink connection and runs one unit of work over it.
|
||||||
async fn with_netlink<T, F>(work: impl FnOnce(rtnetlink::Handle) -> F) -> Result<T, PluginError>
|
async fn with_netlink<T, F>(work: impl FnOnce(rtnetlink::Handle) -> F) -> Result<T, OverlayError>
|
||||||
where
|
where
|
||||||
F: std::future::Future<Output = Result<T, PluginError>>,
|
F: std::future::Future<Output = Result<T, OverlayError>>,
|
||||||
{
|
{
|
||||||
let (connection, handle, _messages) = rtnetlink::new_connection()
|
let (connection, handle, _messages) = rtnetlink::new_connection()
|
||||||
.map_err(|err| PluginError::Unavailable(format!("cannot open netlink: {err}")))?;
|
.map_err(|err| OverlayError::Unavailable(format!("cannot open netlink: {err}")))?;
|
||||||
let pump = tokio::spawn(connection);
|
let pump = tokio::spawn(connection);
|
||||||
let result = work(handle).await;
|
let result = work(handle).await;
|
||||||
pump.abort();
|
pump.abort();
|
||||||
@@ -361,7 +361,7 @@ fn link_kind(message: &LinkMessage, name: &str) -> LinkKind {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn observe(name: &str) -> Result<InterfaceState, PluginError> {
|
async fn observe(name: &str) -> Result<InterfaceState, OverlayError> {
|
||||||
with_netlink(|handle| async move {
|
with_netlink(|handle| async move {
|
||||||
let mut links = handle.link().get().match_name(name.to_string()).execute();
|
let mut links = handle.link().get().match_name(name.to_string()).execute();
|
||||||
let message = match links.try_next().await {
|
let message = match links.try_next().await {
|
||||||
@@ -373,7 +373,7 @@ async fn observe(name: &str) -> Result<InterfaceState, PluginError> {
|
|||||||
if !std::path::Path::new(&format!("/sys/class/net/{name}")).exists() {
|
if !std::path::Path::new(&format!("/sys/class/net/{name}")).exists() {
|
||||||
return Ok(InterfaceState::absent());
|
return Ok(InterfaceState::absent());
|
||||||
}
|
}
|
||||||
return Err(PluginError::Unavailable(format!(
|
return Err(OverlayError::Unavailable(format!(
|
||||||
"cannot read interface `{name}`: {err}"
|
"cannot read interface `{name}`: {err}"
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
@@ -397,7 +397,7 @@ async fn observe(name: &str) -> Result<InterfaceState, PluginError> {
|
|||||||
.set_link_index_filter(index)
|
.set_link_index_filter(index)
|
||||||
.execute();
|
.execute();
|
||||||
while let Some(message) = stream.try_next().await.map_err(|err| {
|
while let Some(message) = stream.try_next().await.map_err(|err| {
|
||||||
PluginError::Unavailable(format!("cannot read the addresses of `{name}`: {err}"))
|
OverlayError::Unavailable(format!("cannot read the addresses of `{name}`: {err}"))
|
||||||
})? {
|
})? {
|
||||||
if let Some(cidr) = address_of(&message)
|
if let Some(cidr) = address_of(&message)
|
||||||
&& !is_link_local(cidr.addr)
|
&& !is_link_local(cidr.addr)
|
||||||
@@ -440,7 +440,7 @@ fn cidr(addr: IpAddr, prefix_len: u8) -> Option<Cidr> {
|
|||||||
Cidr::new(addr, prefix_len).ok()
|
Cidr::new(addr, prefix_len).ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn delete_link(name: &str) -> Result<(), PluginError> {
|
async fn delete_link(name: &str) -> Result<(), OverlayError> {
|
||||||
with_netlink(|handle| async move {
|
with_netlink(|handle| async move {
|
||||||
let mut links = handle.link().get().match_name(name.to_string()).execute();
|
let mut links = handle.link().get().match_name(name.to_string()).execute();
|
||||||
let index = match links.try_next().await {
|
let index = match links.try_next().await {
|
||||||
@@ -449,13 +449,13 @@ async fn delete_link(name: &str) -> Result<(), PluginError> {
|
|||||||
Ok(None) | Err(_) => return Ok(()),
|
Ok(None) | Err(_) => return Ok(()),
|
||||||
};
|
};
|
||||||
handle.link().del(index).execute().await.map_err(|err| {
|
handle.link().del(index).execute().await.map_err(|err| {
|
||||||
PluginError::Unavailable(format!("cannot remove interface `{name}`: {err}"))
|
OverlayError::Unavailable(format!("cannot remove interface `{name}`: {err}"))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn configure_link(configure: &Configure) -> Result<(), PluginError> {
|
async fn configure_link(configure: &Configure) -> Result<(), OverlayError> {
|
||||||
let name = configure.name.as_str();
|
let name = configure.name.as_str();
|
||||||
with_netlink(|handle| async move {
|
with_netlink(|handle| async move {
|
||||||
let mut links = handle.link().get().match_name(name.to_string()).execute();
|
let mut links = handle.link().get().match_name(name.to_string()).execute();
|
||||||
@@ -466,7 +466,7 @@ async fn configure_link(configure: &Configure) -> Result<(), PluginError> {
|
|||||||
.flatten()
|
.flatten()
|
||||||
.map(|message| message.header.index)
|
.map(|message| message.header.index)
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| {
|
||||||
PluginError::Unavailable(format!(
|
OverlayError::Unavailable(format!(
|
||||||
"interface `{name}` disappeared before it could be configured"
|
"interface `{name}` disappeared before it could be configured"
|
||||||
))
|
))
|
||||||
})?;
|
})?;
|
||||||
@@ -485,7 +485,7 @@ async fn configure_link(configure: &Configure) -> Result<(), PluginError> {
|
|||||||
.execute()
|
.execute()
|
||||||
.await
|
.await
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
PluginError::Unavailable(format!("cannot configure interface `{name}`: {err}"))
|
OverlayError::Unavailable(format!("cannot configure interface `{name}`: {err}"))
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -512,7 +512,7 @@ async fn configure_link(configure: &Configure) -> Result<(), PluginError> {
|
|||||||
.execute()
|
.execute()
|
||||||
.await
|
.await
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
PluginError::Unavailable(format!(
|
OverlayError::Unavailable(format!(
|
||||||
"cannot remove {cidr} from interface `{name}`: {err}"
|
"cannot remove {cidr} from interface `{name}`: {err}"
|
||||||
))
|
))
|
||||||
})?;
|
})?;
|
||||||
@@ -526,7 +526,7 @@ async fn configure_link(configure: &Configure) -> Result<(), PluginError> {
|
|||||||
.execute()
|
.execute()
|
||||||
.await
|
.await
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
PluginError::Unavailable(format!(
|
OverlayError::Unavailable(format!(
|
||||||
"cannot add {cidr} to interface `{name}`: {err}"
|
"cannot add {cidr} to interface `{name}`: {err}"
|
||||||
))
|
))
|
||||||
})?;
|
})?;
|
||||||
+5
-5
@@ -9,7 +9,7 @@ use std::collections::HashMap;
|
|||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use crate::BoxFuture;
|
use crate::BoxFuture;
|
||||||
use crate::dataplane::PluginError;
|
use crate::overlay::OverlayError;
|
||||||
|
|
||||||
use super::super::config::Cidr;
|
use super::super::config::Cidr;
|
||||||
use super::super::tun::{MemoryTun, MemoryTunFactory, TunFactory, TunRequest};
|
use super::super::tun::{MemoryTun, MemoryTunFactory, TunFactory, TunRequest};
|
||||||
@@ -125,9 +125,9 @@ impl MockProvisioner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply(&self, plan: &InterfacePlan) -> Result<Changes, PluginError> {
|
fn apply(&self, plan: &InterfacePlan) -> Result<Changes, OverlayError> {
|
||||||
if let Some(reason) = &self.failure {
|
if let Some(reason) = &self.failure {
|
||||||
return Err(PluginError::Unavailable(reason.clone()));
|
return Err(OverlayError::Unavailable(reason.clone()));
|
||||||
}
|
}
|
||||||
|
|
||||||
let ours = self.owned().iter().any(|name| name == &plan.name);
|
let ours = self.owned().iter().any(|name| name == &plan.name);
|
||||||
@@ -179,7 +179,7 @@ impl InterfaceProvisioner for MockProvisioner {
|
|||||||
fn reconcile<'a>(
|
fn reconcile<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
plan: &'a InterfacePlan,
|
plan: &'a InterfacePlan,
|
||||||
) -> BoxFuture<'a, Result<Provisioned, PluginError>> {
|
) -> BoxFuture<'a, Result<Provisioned, OverlayError>> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let changes = self.apply(plan)?;
|
let changes = self.apply(plan)?;
|
||||||
let device = if changes.create_link {
|
let device = if changes.create_link {
|
||||||
@@ -195,7 +195,7 @@ impl InterfaceProvisioner for MockProvisioner {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove<'a>(&'a self, name: &'a str) -> BoxFuture<'a, Result<(), PluginError>> {
|
fn remove<'a>(&'a self, name: &'a str) -> BoxFuture<'a, Result<(), OverlayError>> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
self.host.lock().remove(name);
|
self.host.lock().remove(name);
|
||||||
self.owned().retain(|owned| owned != name);
|
self.owned().retain(|owned| owned != name);
|
||||||
+6
-6
@@ -38,7 +38,7 @@ use std::collections::BTreeSet;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::BoxFuture;
|
use crate::BoxFuture;
|
||||||
use crate::dataplane::PluginError;
|
use crate::overlay::OverlayError;
|
||||||
|
|
||||||
use super::config::Cidr;
|
use super::config::Cidr;
|
||||||
use super::tun::TunDevice;
|
use super::tun::TunDevice;
|
||||||
@@ -203,19 +203,19 @@ pub fn plan_changes(
|
|||||||
current: &InterfaceState,
|
current: &InterfaceState,
|
||||||
plan: &InterfacePlan,
|
plan: &InterfacePlan,
|
||||||
ours: bool,
|
ours: bool,
|
||||||
) -> Result<Changes, PluginError> {
|
) -> Result<Changes, OverlayError> {
|
||||||
let mut changes = Changes::default();
|
let mut changes = Changes::default();
|
||||||
|
|
||||||
match ¤t.kind {
|
match ¤t.kind {
|
||||||
LinkKind::Foreign(kind) => {
|
LinkKind::Foreign(kind) => {
|
||||||
return Err(PluginError::Unavailable(format!(
|
return Err(OverlayError::Unavailable(format!(
|
||||||
"`{}` already exists and is a {kind} interface, not one of ours. \
|
"`{}` already exists and is a {kind} interface, not one of ours. \
|
||||||
Refusing to touch it. Run with a different interface prefix.",
|
Refusing to touch it. Run with a different interface prefix.",
|
||||||
plan.name
|
plan.name
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
LinkKind::Tun if !ours && current.attached => {
|
LinkKind::Tun if !ours && current.attached => {
|
||||||
return Err(PluginError::Unavailable(format!(
|
return Err(OverlayError::Unavailable(format!(
|
||||||
"`{}` already exists and another process is attached to it. \
|
"`{}` already exists and another process is attached to it. \
|
||||||
That is most likely a second agent on this host in the same \
|
That is most likely a second agent on this host in the same \
|
||||||
network; give one of them a different interface prefix.",
|
network; give one of them a different interface prefix.",
|
||||||
@@ -293,13 +293,13 @@ pub trait InterfaceProvisioner: Send + Sync + std::fmt::Debug + 'static {
|
|||||||
fn reconcile<'a>(
|
fn reconcile<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
plan: &'a InterfacePlan,
|
plan: &'a InterfacePlan,
|
||||||
) -> BoxFuture<'a, Result<Provisioned, PluginError>>;
|
) -> BoxFuture<'a, Result<Provisioned, OverlayError>>;
|
||||||
|
|
||||||
/// Removes an interface this provisioner created.
|
/// Removes an interface this provisioner created.
|
||||||
///
|
///
|
||||||
/// Removing one that is already gone succeeds: this runs on the shutdown
|
/// Removing one that is already gone succeeds: this runs on the shutdown
|
||||||
/// path, where the interface having vanished is the desired outcome.
|
/// path, where the interface having vanished is the desired outcome.
|
||||||
fn remove<'a>(&'a self, name: &'a str) -> BoxFuture<'a, Result<(), PluginError>>;
|
fn remove<'a>(&'a self, name: &'a str) -> BoxFuture<'a, Result<(), OverlayError>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
+4
-4
@@ -78,7 +78,7 @@ mod linux_impl {
|
|||||||
use caps::{CapSet, Capability};
|
use caps::{CapSet, Capability};
|
||||||
|
|
||||||
use super::Privilege;
|
use super::Privilege;
|
||||||
use crate::dataplane::PluginError;
|
use crate::overlay::OverlayError;
|
||||||
|
|
||||||
/// Whether this thread holds `CAP_NET_ADMIN` in its permitted set.
|
/// Whether this thread holds `CAP_NET_ADMIN` in its permitted set.
|
||||||
pub fn probe_net_admin() -> Privilege {
|
pub fn probe_net_admin() -> Privilege {
|
||||||
@@ -108,16 +108,16 @@ mod linux_impl {
|
|||||||
|
|
||||||
impl NetAdmin {
|
impl NetAdmin {
|
||||||
/// Raises `CAP_NET_ADMIN` into the effective set.
|
/// Raises `CAP_NET_ADMIN` into the effective set.
|
||||||
pub fn acquire() -> Result<Self, PluginError> {
|
pub fn acquire() -> Result<Self, OverlayError> {
|
||||||
let already = caps::has_cap(None, CapSet::Effective, Capability::CAP_NET_ADMIN)
|
let already = caps::has_cap(None, CapSet::Effective, Capability::CAP_NET_ADMIN)
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
PluginError::Unavailable(format!("cannot read capabilities: {err}"))
|
OverlayError::Unavailable(format!("cannot read capabilities: {err}"))
|
||||||
})?;
|
})?;
|
||||||
if already {
|
if already {
|
||||||
return Ok(Self { raised: false });
|
return Ok(Self { raised: false });
|
||||||
}
|
}
|
||||||
caps::raise(None, CapSet::Effective, Capability::CAP_NET_ADMIN).map_err(|err| {
|
caps::raise(None, CapSet::Effective, Capability::CAP_NET_ADMIN).map_err(|err| {
|
||||||
PluginError::Unavailable(format!(
|
OverlayError::Unavailable(format!(
|
||||||
"cannot raise CAP_NET_ADMIN: {err}. {}",
|
"cannot raise CAP_NET_ADMIN: {err}. {}",
|
||||||
Privilege::how_to_grant("tsunagi")
|
Privilege::how_to_grant("tsunagi")
|
||||||
))
|
))
|
||||||
+5
-5
@@ -7,7 +7,7 @@
|
|||||||
//! of provisioning and says what to do instead.
|
//! of provisioning and says what to do instead.
|
||||||
|
|
||||||
use crate::BoxFuture;
|
use crate::BoxFuture;
|
||||||
use crate::dataplane::PluginError;
|
use crate::overlay::OverlayError;
|
||||||
|
|
||||||
use super::{InterfacePlan, InterfaceProvisioner, Provisioned};
|
use super::{InterfacePlan, InterfaceProvisioner, Provisioned};
|
||||||
|
|
||||||
@@ -31,8 +31,8 @@ impl UnsupportedProvisioner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn refusal(&self) -> PluginError {
|
fn refusal(&self) -> OverlayError {
|
||||||
PluginError::Unavailable(format!(
|
OverlayError::Unavailable(format!(
|
||||||
"managing the overlay interface is not implemented on {} yet. \
|
"managing the overlay interface is not implemented on {} yet. \
|
||||||
Run with `--no-tun` until it is: the tunnels still form, they just \
|
Run with `--no-tun` until it is: the tunnels still form, they just \
|
||||||
do not reach the operating system.",
|
do not reach the operating system.",
|
||||||
@@ -49,11 +49,11 @@ impl InterfaceProvisioner for UnsupportedProvisioner {
|
|||||||
fn reconcile<'a>(
|
fn reconcile<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
_plan: &'a InterfacePlan,
|
_plan: &'a InterfacePlan,
|
||||||
) -> BoxFuture<'a, Result<Provisioned, PluginError>> {
|
) -> BoxFuture<'a, Result<Provisioned, OverlayError>> {
|
||||||
Box::pin(async move { Err(self.refusal()) })
|
Box::pin(async move { Err(self.refusal()) })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove<'a>(&'a self, _name: &'a str) -> BoxFuture<'a, Result<(), PluginError>> {
|
fn remove<'a>(&'a self, _name: &'a str) -> BoxFuture<'a, Result<(), OverlayError>> {
|
||||||
// Nothing was ever created, so there is nothing to clean up and no
|
// Nothing was ever created, so there is nothing to clean up and no
|
||||||
// reason to fail a shutdown path.
|
// reason to fail a shutdown path.
|
||||||
Box::pin(async move { Ok(()) })
|
Box::pin(async move { Ok(()) })
|
||||||
@@ -19,7 +19,7 @@ use std::sync::Arc;
|
|||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
|
|
||||||
use crate::BoxFuture;
|
use crate::BoxFuture;
|
||||||
use crate::dataplane::PluginError;
|
use crate::overlay::OverlayError;
|
||||||
|
|
||||||
/// What a device should look like once created.
|
/// What a device should look like once created.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
@@ -71,7 +71,7 @@ pub trait TunDevice: Send + Sync + std::fmt::Debug + 'static {
|
|||||||
fn recv(&self) -> BoxFuture<'_, Option<Bytes>>;
|
fn recv(&self) -> BoxFuture<'_, Option<Bytes>>;
|
||||||
|
|
||||||
/// Delivers a packet to the operating system.
|
/// Delivers a packet to the operating system.
|
||||||
fn send<'a>(&'a self, packet: Bytes) -> BoxFuture<'a, Result<(), PluginError>>;
|
fn send<'a>(&'a self, packet: Bytes) -> BoxFuture<'a, Result<(), OverlayError>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates packet interfaces.
|
/// Creates packet interfaces.
|
||||||
@@ -83,7 +83,7 @@ pub trait TunFactory: Send + Sync + std::fmt::Debug + 'static {
|
|||||||
fn create<'a>(
|
fn create<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
request: TunRequest,
|
request: TunRequest,
|
||||||
) -> BoxFuture<'a, Result<Arc<dyn TunDevice>, PluginError>>;
|
) -> BoxFuture<'a, Result<Arc<dyn TunDevice>, OverlayError>>;
|
||||||
|
|
||||||
/// Applies a changed request to an interface that already exists.
|
/// Applies a changed request to an interface that already exists.
|
||||||
///
|
///
|
||||||
@@ -94,7 +94,7 @@ pub trait TunFactory: Send + Sync + std::fmt::Debug + 'static {
|
|||||||
///
|
///
|
||||||
/// The default does nothing, which is right for a factory that only
|
/// The default does nothing, which is right for a factory that only
|
||||||
/// attaches to an interface somebody else prepared.
|
/// attaches to an interface somebody else prepared.
|
||||||
fn reconfigure<'a>(&'a self, _request: TunRequest) -> BoxFuture<'a, Result<(), PluginError>> {
|
fn reconfigure<'a>(&'a self, _request: TunRequest) -> BoxFuture<'a, Result<(), OverlayError>> {
|
||||||
Box::pin(async move { Ok(()) })
|
Box::pin(async move { Ok(()) })
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,7 +162,7 @@ impl TunDevice for MemoryTun {
|
|||||||
Box::pin(async move { self.from_os_rx.lock().await.recv().await })
|
Box::pin(async move { self.from_os_rx.lock().await.recv().await })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send<'a>(&'a self, packet: Bytes) -> BoxFuture<'a, Result<(), PluginError>> {
|
fn send<'a>(&'a self, packet: Bytes) -> BoxFuture<'a, Result<(), OverlayError>> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let _ = self.to_os_tx.send(packet);
|
let _ = self.to_os_tx.send(packet);
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -223,7 +223,7 @@ impl TunFactory for MemoryTunFactory {
|
|||||||
fn create<'a>(
|
fn create<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
request: TunRequest,
|
request: TunRequest,
|
||||||
) -> BoxFuture<'a, Result<Arc<dyn TunDevice>, PluginError>> {
|
) -> BoxFuture<'a, Result<Arc<dyn TunDevice>, OverlayError>> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let device = MemoryTun::new(request.name, request.mtu);
|
let device = MemoryTun::new(request.name, request.mtu);
|
||||||
let mut guard = match self.created.lock() {
|
let mut guard = match self.created.lock() {
|
||||||
@@ -248,7 +248,7 @@ mod system {
|
|||||||
|
|
||||||
use super::{TunDevice, TunRequest};
|
use super::{TunDevice, TunRequest};
|
||||||
use crate::BoxFuture;
|
use crate::BoxFuture;
|
||||||
use crate::dataplane::PluginError;
|
use crate::overlay::OverlayError;
|
||||||
|
|
||||||
/// A real TUN interface.
|
/// A real TUN interface.
|
||||||
///
|
///
|
||||||
@@ -303,14 +303,14 @@ mod system {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send<'a>(&'a self, packet: Bytes) -> BoxFuture<'a, Result<(), PluginError>> {
|
fn send<'a>(&'a self, packet: Bytes) -> BoxFuture<'a, Result<(), OverlayError>> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
use tokio::io::AsyncWriteExt;
|
use tokio::io::AsyncWriteExt;
|
||||||
let mut writer = self.writer.lock().await;
|
let mut writer = self.writer.lock().await;
|
||||||
writer
|
writer
|
||||||
.write_all(&packet)
|
.write_all(&packet)
|
||||||
.await
|
.await
|
||||||
.map_err(|err| PluginError::Other(format!("tun write failed: {err}")))
|
.map_err(|err| OverlayError::Other(format!("tun write failed: {err}")))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -320,7 +320,7 @@ mod system {
|
|||||||
/// Synchronous, and deliberately so: the caller holds a capability guard
|
/// Synchronous, and deliberately so: the caller holds a capability guard
|
||||||
/// across this call, and such a guard must not span an `await` because
|
/// across this call, and such a guard must not span an `await` because
|
||||||
/// Linux capabilities are per thread.
|
/// Linux capabilities are per thread.
|
||||||
pub(crate) fn open_tun(request: &TunRequest) -> Result<Arc<dyn TunDevice>, PluginError> {
|
pub(crate) fn open_tun(request: &TunRequest) -> Result<Arc<dyn TunDevice>, OverlayError> {
|
||||||
let mut config = tun::Configuration::default();
|
let mut config = tun::Configuration::default();
|
||||||
config.tun_name(&request.name);
|
config.tun_name(&request.name);
|
||||||
config.platform_config(|platform| {
|
config.platform_config(|platform| {
|
||||||
@@ -334,7 +334,7 @@ mod system {
|
|||||||
// information, so the flags match when attaching to one.
|
// information, so the flags match when attaching to one.
|
||||||
|
|
||||||
let device = tun::create_as_async(&config).map_err(|err| {
|
let device = tun::create_as_async(&config).map_err(|err| {
|
||||||
PluginError::Unavailable(format!(
|
OverlayError::Unavailable(format!(
|
||||||
"cannot create the TUN interface `{}`: {err}. Creating one needs \
|
"cannot create the TUN interface `{}`: {err}. Creating one needs \
|
||||||
CAP_NET_ADMIN; grant it with `setcap cap_net_admin+p`, or run with \
|
CAP_NET_ADMIN; grant it with `setcap cap_net_admin+p`, or run with \
|
||||||
`--no-tun` to keep the tunnels off the operating system.",
|
`--no-tun` to keep the tunnels off the operating system.",
|
||||||
Reference in New Issue
Block a user