From 6773640a395d5c26df574f709c19708ec21bf14e Mon Sep 17 00:00:00 2001 From: Alex Zenla Date: Sun, 11 Feb 2024 07:06:01 +0000 Subject: [PATCH] hypha: more work on IPv6 support --- container/src/init.rs | 113 ++++++++++++++++++++++++-------------- controller/src/ctl/mod.rs | 22 ++++++-- shared/src/lib.rs | 8 ++- 3 files changed, 97 insertions(+), 46 deletions(-) diff --git a/container/src/init.rs b/container/src/init.rs index 16a4310..d0a5ca9 100644 --- a/container/src/init.rs +++ b/container/src/init.rs @@ -9,7 +9,7 @@ use oci_spec::image::{Config, ImageConfiguration}; use std::ffi::{CStr, CString}; use std::fs; use std::fs::{File, OpenOptions, Permissions}; -use std::net::Ipv4Addr; +use std::net::{Ipv4Addr, Ipv6Addr}; use std::os::fd::AsRawFd; use std::os::linux::fs::MetadataExt; use std::os::unix::fs::{chroot, PermissionsExt}; @@ -283,52 +283,83 @@ impl ContainerInit { } async fn network_setup(&mut self, network: &LaunchNetwork) -> Result<()> { - trace!( - "setting up network for link {} with ipv4 address {} and gateway {}", - network.link, - network.ipv4.address, - network.ipv4.gateway, - ); - - let (connection, handle, _) = rtnetlink::new_connection()?; - tokio::spawn(connection); - - let ipnet: IpNetwork = network.ipv4.address.parse()?; - let gateway: Ipv4Addr = network.ipv4.gateway.parse()?; - - let mut links = handle - .link() - .get() - .match_name(network.link.clone()) - .execute(); - if let Some(link) = links.try_next().await? { - handle - .address() - .add(link.header.index, ipnet.ip(), ipnet.prefix()) - .execute() - .await?; - - handle.link().set(link.header.index).up().execute().await?; - - handle - .route() - .add() - .v4() - .destination_prefix(Ipv4Addr::new(0, 0, 0, 0), 0) - .output_interface(link.header.index) - .gateway(gateway) - .execute() - .await?; - } else { - warn!("unable to find link named {}", network.link); - } + trace!("setting up network for link"); let etc = PathBuf::from_str("/etc")?; if !etc.exists() { fs::create_dir(etc)?; } let resolv = PathBuf::from_str("/etc/resolv.conf")?; - fs::write(resolv, "nameserver 1.1.1.1\n")?; + let mut lines = vec!["# hypha resolver configuration".to_string()]; + for nameserver in &network.resolver.nameservers { + lines.push(format!("nameserver {}", nameserver)); + } + + let mut conf = lines.join("\n"); + conf.push('\n'); + fs::write(resolv, conf)?; + + let (connection, handle, _) = rtnetlink::new_connection()?; + tokio::spawn(connection); + + let ipv4_network: IpNetwork = network.ipv4.address.parse()?; + let ipv4_gateway: Ipv4Addr = network.ipv4.gateway.parse()?; + let ipv6_network: IpNetwork = network.ipv6.address.parse()?; + let ipv6_gateway: Ipv6Addr = network.ipv6.gateway.parse()?; + + let mut links = handle + .link() + .get() + .match_name(network.link.clone()) + .execute(); + let Some(link) = links.try_next().await? else { + warn!("unable to find link named {}", network.link); + return Ok(()); + }; + + handle + .address() + .add(link.header.index, ipv4_network.ip(), ipv4_network.prefix()) + .execute() + .await?; + + let ipv6_result = handle + .address() + .add(link.header.index, ipv6_network.ip(), ipv6_network.prefix()) + .execute() + .await; + + let ipv6_ready = match ipv6_result { + Ok(()) => true, + Err(error) => { + warn!("unable to setup ipv6 network: {}", error); + false + } + }; + + handle.link().set(link.header.index).up().execute().await?; + + handle + .route() + .add() + .v4() + .destination_prefix(Ipv4Addr::UNSPECIFIED, 0) + .output_interface(link.header.index) + .gateway(ipv4_gateway) + .execute() + .await?; + + if ipv6_ready { + handle + .route() + .add() + .v6() + .destination_prefix(Ipv6Addr::UNSPECIFIED, 0) + .output_interface(link.header.index) + .gateway(ipv6_gateway) + .execute() + .await?; + } Ok(()) } diff --git a/controller/src/ctl/mod.rs b/controller/src/ctl/mod.rs index 85b071b..1b716fb 100644 --- a/controller/src/ctl/mod.rs +++ b/controller/src/ctl/mod.rs @@ -7,7 +7,9 @@ use crate::image::name::ImageName; use crate::image::{ImageCompiler, ImageInfo}; use advmac::MacAddr6; use anyhow::{anyhow, Result}; -use hypha::{LaunchInfo, LaunchNetwork, LaunchNetworkIpv4}; +use hypha::{ + LaunchInfo, LaunchNetwork, LaunchNetworkIpv4, LaunchNetworkIpv6, LaunchNetworkResolver, +}; use ipnetwork::Ipv4Network; use loopdev::LoopControl; use std::io::{Read, Write}; @@ -81,7 +83,10 @@ impl Controller { let name = format!("hypha-{uuid}"); let image_info = self.compile(image)?; + let mut mac = MacAddr6::random(); + mac.set_local(true); let ipv4 = self.allocate_ipv4()?; + let ipv6 = mac.to_link_local_ipv6(); let launch_config = LaunchInfo { network: Some(LaunchNetwork { link: "eth0".to_string(), @@ -89,7 +94,18 @@ impl Controller { address: format!("{}/24", ipv4), gateway: "192.168.42.1".to_string(), }, - ipv6: None, + ipv6: LaunchNetworkIpv6 { + address: format!("{}/10", ipv6), + gateway: "fe80::1".to_string(), + }, + resolver: LaunchNetworkResolver { + nameservers: vec![ + "1.1.1.1".to_string(), + "1.0.0.1".to_string(), + "2606:4700:4700::1111".to_string(), + "2606:4700:4700::1001".to_string(), + ], + }, }), env, run, @@ -118,8 +134,6 @@ impl Controller { let cmdline_options = [if debug { "debug" } else { "quiet" }, "elevator=noop"]; let cmdline = cmdline_options.join(" "); - let mut mac = MacAddr6::random(); - mac.set_local(true); let mac = mac.to_string().replace('-', ":"); let config = DomainConfig { backend_domid: 0, diff --git a/shared/src/lib.rs b/shared/src/lib.rs index 4567233..8dae750 100644 --- a/shared/src/lib.rs +++ b/shared/src/lib.rs @@ -12,11 +12,17 @@ pub struct LaunchNetworkIpv6 { pub gateway: String, } +#[derive(Serialize, Deserialize, Debug)] +pub struct LaunchNetworkResolver { + pub nameservers: Vec, +} + #[derive(Serialize, Deserialize, Debug)] pub struct LaunchNetwork { pub link: String, pub ipv4: LaunchNetworkIpv4, - pub ipv6: Option, + pub ipv6: LaunchNetworkIpv6, + pub resolver: LaunchNetworkResolver, } #[derive(Serialize, Deserialize, Debug)]