network: inter-container networking support

This commit is contained in:
Alex Zenla
2024-02-12 14:24:38 +00:00
parent 31c4c0fe72
commit 59bdd8d80d
9 changed files with 515 additions and 166 deletions

View File

@ -1,14 +1,13 @@
use advmac::MacAddr6;
use anyhow::Result;
use futures::TryStreamExt;
use log::{error, info, warn};
use netlink_packet_route::link::LinkAttribute;
use std::sync::{Arc, Mutex};
use std::time::Duration;
use anyhow::Result;
use autonet::{AutoNetworkChangeset, AutoNetworkCollector, NetworkMetadata};
use tokio::time::sleep;
use vbridge::VirtualBridge;
use crate::backend::NetworkBackend;
pub mod autonet;
pub mod backend;
pub mod chandev;
pub mod icmp;
@ -16,99 +15,45 @@ pub mod nat;
pub mod pkt;
pub mod proxynat;
pub mod raw_socket;
pub mod vbridge;
pub struct NetworkService {
pub ipv4: String,
pub ipv6: String,
pub force_mac_address: Option<MacAddr6>,
pub bridge: VirtualBridge,
}
impl NetworkService {
pub fn new(
ipv4: String,
ipv6: String,
force_mac_address: Option<MacAddr6>,
) -> Result<NetworkService> {
pub fn new() -> Result<NetworkService> {
Ok(NetworkService {
ipv4,
ipv6,
force_mac_address,
bridge: VirtualBridge::new()?,
})
}
}
impl NetworkService {
pub async fn watch(&mut self) -> Result<()> {
let spawned: Arc<Mutex<Vec<String>>> = Arc::new(Mutex::new(Vec::new()));
let (connection, handle, _) = rtnetlink::new_connection()?;
tokio::spawn(connection);
let mut collector = AutoNetworkCollector::new()?;
loop {
let mut stream = handle.link().get().execute();
while let Some(message) = stream.try_next().await? {
let mut name: Option<String> = None;
for attribute in &message.attributes {
if let LinkAttribute::IfName(if_name) = attribute {
name = Some(if_name.clone());
}
}
if name.is_none() {
continue;
}
let name = name.unwrap();
if !name.starts_with("vif") {
continue;
}
if let Ok(spawns) = spawned.lock() {
if spawns.contains(&name) {
continue;
}
}
if let Err(error) = self.add_network_backend(&name, spawned.clone()).await {
warn!(
"failed to initialize network backend for interface {}: {}",
name, error
);
}
if let Ok(mut spawns) = spawned.lock() {
spawns.push(name.clone());
}
}
let changeset = collector.read_changes()?;
self.process_network_changeset(changeset)?;
sleep(Duration::from_secs(2)).await;
}
}
async fn add_network_backend(
&mut self,
interface: &str,
spawned: Arc<Mutex<Vec<String>>>,
) -> Result<()> {
let interface = interface.to_string();
let mut network =
NetworkBackend::new(&self.ipv4, &self.ipv6, &self.force_mac_address, &interface)?;
info!("initializing network backend for interface {}", interface);
fn process_network_changeset(&mut self, changeset: AutoNetworkChangeset) -> Result<()> {
for metadata in &changeset.added {
futures::executor::block_on(async {
self.add_network_backend(metadata.clone()).await
})?;
}
Ok(())
}
async fn add_network_backend(&mut self, metadata: NetworkMetadata) -> Result<()> {
let mut network = NetworkBackend::new(metadata, self.bridge.clone())?;
network.init().await?;
tokio::time::sleep(Duration::from_secs(1)).await;
info!("spawning network backend for interface {}", interface);
tokio::spawn(async move {
if let Err(error) = network.run().await {
error!(
"network backend for interface {} has been stopped: {}",
interface, error
);
}
if let Ok(mut spawns) = spawned.lock() {
if let Some(position) = spawns.iter().position(|x| *x == interface) {
spawns.remove(position);
}
}
});
network.launch().await?;
Ok(())
}
}