mirror of
				https://github.com/edera-dev/krata.git
				synced 2025-11-03 23:29:39 +00:00 
			
		
		
		
	hypha: implement basic networking support
This commit is contained in:
		@ -43,6 +43,10 @@ url = "2.5.0"
 | 
				
			|||||||
cli-tables = "0.2.1"
 | 
					cli-tables = "0.2.1"
 | 
				
			||||||
rand = "0.8.5"
 | 
					rand = "0.8.5"
 | 
				
			||||||
arrayvec = "0.7.4"
 | 
					arrayvec = "0.7.4"
 | 
				
			||||||
 | 
					rtnetlink = "0.14.1"
 | 
				
			||||||
 | 
					futures = "0.3.30"
 | 
				
			||||||
 | 
					ipnetwork = "0.20.0"
 | 
				
			||||||
 | 
					smoltcp = "0.11.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[workspace.dependencies.uuid]
 | 
					[workspace.dependencies.uuid]
 | 
				
			||||||
version = "1.6.1"
 | 
					version = "1.6.1"
 | 
				
			||||||
@ -55,3 +59,7 @@ default-features = false
 | 
				
			|||||||
[workspace.dependencies.clap]
 | 
					[workspace.dependencies.clap]
 | 
				
			||||||
version = "4.4.18"
 | 
					version = "4.4.18"
 | 
				
			||||||
features = ["derive"]
 | 
					features = ["derive"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[workspace.dependencies.tokio]
 | 
				
			||||||
 | 
					version = "1.35.1"
 | 
				
			||||||
 | 
					features = ["macros", "rt", "rt-multi-thread"]
 | 
				
			||||||
 | 
				
			|||||||
@ -26,6 +26,11 @@ sys-mount = { workspace = true }
 | 
				
			|||||||
oci-spec = { workspace = true }
 | 
					oci-spec = { workspace = true }
 | 
				
			||||||
backhand = { workspace = true }
 | 
					backhand = { workspace = true }
 | 
				
			||||||
uuid = { workspace = true }
 | 
					uuid = { workspace = true }
 | 
				
			||||||
 | 
					rtnetlink = { workspace = true }
 | 
				
			||||||
 | 
					tokio = { workspace = true }
 | 
				
			||||||
 | 
					futures = { workspace = true }
 | 
				
			||||||
 | 
					ipnetwork = { workspace = true }
 | 
				
			||||||
 | 
					smoltcp = { workspace = true }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[dependencies.nix]
 | 
					[dependencies.nix]
 | 
				
			||||||
workspace = true
 | 
					workspace = true
 | 
				
			||||||
@ -53,3 +58,7 @@ path = "bin/controller.rs"
 | 
				
			|||||||
[[bin]]
 | 
					[[bin]]
 | 
				
			||||||
name = "hyphactr"
 | 
					name = "hyphactr"
 | 
				
			||||||
path = "bin/container.rs"
 | 
					path = "bin/container.rs"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[bin]]
 | 
				
			||||||
 | 
					name = "hyphanet"
 | 
				
			||||||
 | 
					path = "bin/network.rs"
 | 
				
			||||||
 | 
				
			|||||||
@ -3,7 +3,8 @@ use env_logger::Env;
 | 
				
			|||||||
use hypha::container::init::ContainerInit;
 | 
					use hypha::container::init::ContainerInit;
 | 
				
			||||||
use std::env;
 | 
					use std::env;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn main() -> Result<()> {
 | 
					#[tokio::main]
 | 
				
			||||||
 | 
					async fn main() -> Result<()> {
 | 
				
			||||||
    env::set_var("RUST_BACKTRACE", "1");
 | 
					    env::set_var("RUST_BACKTRACE", "1");
 | 
				
			||||||
    env_logger::Builder::from_env(Env::default().default_filter_or("warn")).init();
 | 
					    env_logger::Builder::from_env(Env::default().default_filter_or("warn")).init();
 | 
				
			||||||
    if env::var("HYPHA_UNSAFE_ALWAYS_ALLOW_INIT").unwrap_or("0".to_string()) != "1" {
 | 
					    if env::var("HYPHA_UNSAFE_ALWAYS_ALLOW_INIT").unwrap_or("0".to_string()) != "1" {
 | 
				
			||||||
@ -18,6 +19,6 @@ fn main() -> Result<()> {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    let mut container = ContainerInit::new();
 | 
					    let mut container = ContainerInit::new();
 | 
				
			||||||
    container.init()?;
 | 
					    container.init().await?;
 | 
				
			||||||
    Ok(())
 | 
					    Ok(())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -110,12 +110,13 @@ fn main() -> Result<()> {
 | 
				
			|||||||
        Commands::List { .. } => {
 | 
					        Commands::List { .. } => {
 | 
				
			||||||
            let containers = controller.list()?;
 | 
					            let containers = controller.list()?;
 | 
				
			||||||
            let mut table = cli_tables::Table::new();
 | 
					            let mut table = cli_tables::Table::new();
 | 
				
			||||||
            let header = vec!["domain", "uuid", "image"];
 | 
					            let header = vec!["domain", "uuid", "ipv4", "image"];
 | 
				
			||||||
            table.push_row(&header)?;
 | 
					            table.push_row(&header)?;
 | 
				
			||||||
            for container in containers {
 | 
					            for container in containers {
 | 
				
			||||||
                let row = vec![
 | 
					                let row = vec![
 | 
				
			||||||
                    container.domid.to_string(),
 | 
					                    container.domid.to_string(),
 | 
				
			||||||
                    container.uuid.to_string(),
 | 
					                    container.uuid.to_string(),
 | 
				
			||||||
 | 
					                    container.ipv4,
 | 
				
			||||||
                    container.image,
 | 
					                    container.image,
 | 
				
			||||||
                ];
 | 
					                ];
 | 
				
			||||||
                table.push_row_string(&row)?;
 | 
					                table.push_row_string(&row)?;
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										20
									
								
								hypha/bin/network.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								hypha/bin/network.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					use anyhow::Result;
 | 
				
			||||||
 | 
					use clap::Parser;
 | 
				
			||||||
 | 
					use env_logger::Env;
 | 
				
			||||||
 | 
					use hypha::network::HyphaNetwork;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Parser, Debug)]
 | 
				
			||||||
 | 
					struct NetworkArgs {
 | 
				
			||||||
 | 
					    #[arg(short, long)]
 | 
				
			||||||
 | 
					    interface: String,
 | 
				
			||||||
 | 
					    #[arg(short, long, default_value = "192.168.42.1/24")]
 | 
				
			||||||
 | 
					    network: String,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn main() -> Result<()> {
 | 
				
			||||||
 | 
					    env_logger::Builder::from_env(Env::default().default_filter_or("warn")).init();
 | 
				
			||||||
 | 
					    let args = NetworkArgs::parse();
 | 
				
			||||||
 | 
					    let mut network = HyphaNetwork::new(&args.interface, &[&args.network])?;
 | 
				
			||||||
 | 
					    network.run()?;
 | 
				
			||||||
 | 
					    Ok(())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,5 +1,7 @@
 | 
				
			|||||||
use crate::shared::LaunchInfo;
 | 
					use crate::shared::{LaunchInfo, LaunchNetwork};
 | 
				
			||||||
use anyhow::{anyhow, Result};
 | 
					use anyhow::{anyhow, Result};
 | 
				
			||||||
 | 
					use futures::stream::TryStreamExt;
 | 
				
			||||||
 | 
					use ipnetwork::IpNetwork;
 | 
				
			||||||
use log::{trace, warn};
 | 
					use log::{trace, warn};
 | 
				
			||||||
use nix::libc::{c_int, dup2, wait};
 | 
					use nix::libc::{c_int, dup2, wait};
 | 
				
			||||||
use nix::unistd::{execve, fork, ForkResult, Pid};
 | 
					use nix::unistd::{execve, fork, ForkResult, Pid};
 | 
				
			||||||
@ -53,7 +55,7 @@ impl ContainerInit {
 | 
				
			|||||||
        ContainerInit {}
 | 
					        ContainerInit {}
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn init(&mut self) -> Result<()> {
 | 
					    pub async fn init(&mut self) -> Result<()> {
 | 
				
			||||||
        self.early_init()?;
 | 
					        self.early_init()?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        trace!("opening console descriptor");
 | 
					        trace!("opening console descriptor");
 | 
				
			||||||
@ -72,6 +74,13 @@ impl ContainerInit {
 | 
				
			|||||||
        self.mount_new_root()?;
 | 
					        self.mount_new_root()?;
 | 
				
			||||||
        self.nuke_initrd()?;
 | 
					        self.nuke_initrd()?;
 | 
				
			||||||
        self.bind_new_root()?;
 | 
					        self.bind_new_root()?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if let Some(network) = &launch.network {
 | 
				
			||||||
 | 
					            if let Err(error) = self.network_setup(network).await {
 | 
				
			||||||
 | 
					                warn!("failed to initialize network: {}", error);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if let Some(cfg) = config.config() {
 | 
					        if let Some(cfg) = config.config() {
 | 
				
			||||||
            self.run(cfg, &launch)?;
 | 
					            self.run(cfg, &launch)?;
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
@ -271,6 +280,38 @@ impl ContainerInit {
 | 
				
			|||||||
        Ok(())
 | 
					        Ok(())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    async fn network_setup(&mut self, network: &LaunchNetwork) -> Result<()> {
 | 
				
			||||||
 | 
					        trace!(
 | 
				
			||||||
 | 
					            "setting up network with link {} and ipv4 {}",
 | 
				
			||||||
 | 
					            network.link,
 | 
				
			||||||
 | 
					            network.ipv4
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let (connection, handle, _) = rtnetlink::new_connection()?;
 | 
				
			||||||
 | 
					        tokio::spawn(connection);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let ip: IpNetwork = network.ipv4.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, ip.ip(), ip.prefix())
 | 
				
			||||||
 | 
					                .execute()
 | 
				
			||||||
 | 
					                .await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            handle.link().set(link.header.index).up().execute().await?;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            warn!("unable to find link named {}", network.link);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Ok(())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn run(&mut self, config: &Config, launch: &LaunchInfo) -> Result<()> {
 | 
					    fn run(&mut self, config: &Config, launch: &LaunchInfo) -> Result<()> {
 | 
				
			||||||
        let mut cmd = match config.cmd() {
 | 
					        let mut cmd = match config.cmd() {
 | 
				
			||||||
            None => vec![],
 | 
					            None => vec![],
 | 
				
			||||||
 | 
				
			|||||||
@ -5,11 +5,13 @@ use crate::ctl::cfgblk::ConfigBlock;
 | 
				
			|||||||
use crate::image::cache::ImageCache;
 | 
					use crate::image::cache::ImageCache;
 | 
				
			||||||
use crate::image::name::ImageName;
 | 
					use crate::image::name::ImageName;
 | 
				
			||||||
use crate::image::{ImageCompiler, ImageInfo};
 | 
					use crate::image::{ImageCompiler, ImageInfo};
 | 
				
			||||||
use crate::shared::LaunchInfo;
 | 
					use crate::shared::{LaunchInfo, LaunchNetwork};
 | 
				
			||||||
use advmac::MacAddr6;
 | 
					use advmac::MacAddr6;
 | 
				
			||||||
use anyhow::{anyhow, Result};
 | 
					use anyhow::{anyhow, Result};
 | 
				
			||||||
 | 
					use ipnetwork::Ipv4Network;
 | 
				
			||||||
use loopdev::LoopControl;
 | 
					use loopdev::LoopControl;
 | 
				
			||||||
use std::io::{Read, Write};
 | 
					use std::io::{Read, Write};
 | 
				
			||||||
 | 
					use std::net::Ipv4Addr;
 | 
				
			||||||
use std::path::PathBuf;
 | 
					use std::path::PathBuf;
 | 
				
			||||||
use std::process::exit;
 | 
					use std::process::exit;
 | 
				
			||||||
use std::str::FromStr;
 | 
					use std::str::FromStr;
 | 
				
			||||||
@ -36,6 +38,7 @@ pub struct ContainerInfo {
 | 
				
			|||||||
    pub domid: u32,
 | 
					    pub domid: u32,
 | 
				
			||||||
    pub image: String,
 | 
					    pub image: String,
 | 
				
			||||||
    pub loops: Vec<ContainerLoopInfo>,
 | 
					    pub loops: Vec<ContainerLoopInfo>,
 | 
				
			||||||
 | 
					    pub ipv4: String,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Controller {
 | 
					impl Controller {
 | 
				
			||||||
@ -77,7 +80,16 @@ impl Controller {
 | 
				
			|||||||
        let uuid = Uuid::new_v4();
 | 
					        let uuid = Uuid::new_v4();
 | 
				
			||||||
        let name = format!("hypha-{uuid}");
 | 
					        let name = format!("hypha-{uuid}");
 | 
				
			||||||
        let image_info = self.compile(image)?;
 | 
					        let image_info = self.compile(image)?;
 | 
				
			||||||
        let launch_config = LaunchInfo { env, run };
 | 
					
 | 
				
			||||||
 | 
					        let ipv4 = self.allocate_ipv4()?;
 | 
				
			||||||
 | 
					        let launch_config = LaunchInfo {
 | 
				
			||||||
 | 
					            network: Some(LaunchNetwork {
 | 
				
			||||||
 | 
					                link: "eth0".to_string(),
 | 
				
			||||||
 | 
					                ipv4: format!("{}/24", ipv4),
 | 
				
			||||||
 | 
					            }),
 | 
				
			||||||
 | 
					            env,
 | 
				
			||||||
 | 
					            run,
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let cfgblk = ConfigBlock::new(&uuid, &image_info, config_bundle_path)?;
 | 
					        let cfgblk = ConfigBlock::new(&uuid, &image_info, config_bundle_path)?;
 | 
				
			||||||
        cfgblk.build(&launch_config)?;
 | 
					        cfgblk.build(&launch_config)?;
 | 
				
			||||||
@ -102,7 +114,10 @@ impl Controller {
 | 
				
			|||||||
        let cmdline_options = [if debug { "debug" } else { "quiet" }, "elevator=noop"];
 | 
					        let cmdline_options = [if debug { "debug" } else { "quiet" }, "elevator=noop"];
 | 
				
			||||||
        let cmdline = cmdline_options.join(" ");
 | 
					        let cmdline = cmdline_options.join(" ");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let mac = MacAddr6::random().to_string().replace('-', ":");
 | 
					        let mac = MacAddr6::random()
 | 
				
			||||||
 | 
					            .to_string()
 | 
				
			||||||
 | 
					            .replace('-', ":")
 | 
				
			||||||
 | 
					            .to_lowercase();
 | 
				
			||||||
        let config = DomainConfig {
 | 
					        let config = DomainConfig {
 | 
				
			||||||
            backend_domid: 0,
 | 
					            backend_domid: 0,
 | 
				
			||||||
            name: &name,
 | 
					            name: &name,
 | 
				
			||||||
@ -126,8 +141,8 @@ impl Controller {
 | 
				
			|||||||
            vifs: vec![DomainNetworkInterface {
 | 
					            vifs: vec![DomainNetworkInterface {
 | 
				
			||||||
                mac: &mac,
 | 
					                mac: &mac,
 | 
				
			||||||
                mtu: 1500,
 | 
					                mtu: 1500,
 | 
				
			||||||
                bridge: "xenbr0",
 | 
					                bridge: None,
 | 
				
			||||||
                script: "/etc/xen/scripts/vif-bridge",
 | 
					                script: None,
 | 
				
			||||||
            }],
 | 
					            }],
 | 
				
			||||||
            filesystems: vec![],
 | 
					            filesystems: vec![],
 | 
				
			||||||
            extra_keys: vec![
 | 
					            extra_keys: vec![
 | 
				
			||||||
@ -144,6 +159,7 @@ impl Controller {
 | 
				
			|||||||
                    ),
 | 
					                    ),
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
                ("hypha/image".to_string(), image.to_string()),
 | 
					                ("hypha/image".to_string(), image.to_string()),
 | 
				
			||||||
 | 
					                ("hypha/ipv4".to_string(), ipv4.to_string()),
 | 
				
			||||||
            ],
 | 
					            ],
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        match self.client.create(&config) {
 | 
					        match self.client.create(&config) {
 | 
				
			||||||
@ -267,12 +283,18 @@ impl Controller {
 | 
				
			|||||||
                .store
 | 
					                .store
 | 
				
			||||||
                .read_string_optional(&format!("{}/hypha/loops", &dom_path))?
 | 
					                .read_string_optional(&format!("{}/hypha/loops", &dom_path))?
 | 
				
			||||||
                .unwrap_or("".to_string());
 | 
					                .unwrap_or("".to_string());
 | 
				
			||||||
 | 
					            let ipv4 = self
 | 
				
			||||||
 | 
					                .client
 | 
				
			||||||
 | 
					                .store
 | 
				
			||||||
 | 
					                .read_string_optional(&format!("{}/hypha/ipv4", &dom_path))?
 | 
				
			||||||
 | 
					                .unwrap_or("unknown".to_string());
 | 
				
			||||||
            let loops = Controller::parse_loop_set(&loops);
 | 
					            let loops = Controller::parse_loop_set(&loops);
 | 
				
			||||||
            containers.push(ContainerInfo {
 | 
					            containers.push(ContainerInfo {
 | 
				
			||||||
                uuid,
 | 
					                uuid,
 | 
				
			||||||
                domid,
 | 
					                domid,
 | 
				
			||||||
                image,
 | 
					                image,
 | 
				
			||||||
                loops,
 | 
					                loops,
 | 
				
			||||||
 | 
					                ipv4,
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        Ok(containers)
 | 
					        Ok(containers)
 | 
				
			||||||
@ -308,4 +330,37 @@ impl Controller {
 | 
				
			|||||||
            })
 | 
					            })
 | 
				
			||||||
            .collect::<Vec<ContainerLoopInfo>>()
 | 
					            .collect::<Vec<ContainerLoopInfo>>()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn allocate_ipv4(&mut self) -> Result<Ipv4Addr> {
 | 
				
			||||||
 | 
					        let network = Ipv4Network::new(Ipv4Addr::new(192, 168, 42, 0), 24)?;
 | 
				
			||||||
 | 
					        let mut used: Vec<Ipv4Addr> = vec![
 | 
				
			||||||
 | 
					            Ipv4Addr::new(192, 168, 42, 0),
 | 
				
			||||||
 | 
					            Ipv4Addr::new(192, 168, 42, 1),
 | 
				
			||||||
 | 
					            Ipv4Addr::new(192, 168, 42, 255),
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					        for domid_candidate in self.client.store.list_any("/local/domain")? {
 | 
				
			||||||
 | 
					            let dom_path = format!("/local/domain/{}", domid_candidate);
 | 
				
			||||||
 | 
					            let ip_path = format!("{}/hypha/ipv4", dom_path);
 | 
				
			||||||
 | 
					            let existing_ip = self.client.store.read_string_optional(&ip_path)?;
 | 
				
			||||||
 | 
					            if let Some(existing_ip) = existing_ip {
 | 
				
			||||||
 | 
					                used.push(Ipv4Addr::from_str(&existing_ip)?);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let mut found: Option<Ipv4Addr> = None;
 | 
				
			||||||
 | 
					        for ip in network.iter() {
 | 
				
			||||||
 | 
					            if !used.contains(&ip) {
 | 
				
			||||||
 | 
					                found = Some(ip);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if found.is_none() {
 | 
				
			||||||
 | 
					            return Err(anyhow!(
 | 
				
			||||||
 | 
					                "unable to find ipv4 to allocate to container, ipv4 addresses are exhausted"
 | 
				
			||||||
 | 
					            ));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Ok(found.unwrap())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -2,4 +2,5 @@ pub mod autoloop;
 | 
				
			|||||||
pub mod container;
 | 
					pub mod container;
 | 
				
			||||||
pub mod ctl;
 | 
					pub mod ctl;
 | 
				
			||||||
pub mod image;
 | 
					pub mod image;
 | 
				
			||||||
 | 
					pub mod network;
 | 
				
			||||||
pub mod shared;
 | 
					pub mod shared;
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										47
									
								
								hypha/src/network/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								hypha/src/network/mod.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,47 @@
 | 
				
			|||||||
 | 
					use std::os::fd::AsRawFd;
 | 
				
			||||||
 | 
					use std::str::FromStr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use advmac::MacAddr6;
 | 
				
			||||||
 | 
					use anyhow::{anyhow, Result};
 | 
				
			||||||
 | 
					use smoltcp::iface::{Config, Interface, SocketSet};
 | 
				
			||||||
 | 
					use smoltcp::phy::{self, RawSocket};
 | 
				
			||||||
 | 
					use smoltcp::time::Instant;
 | 
				
			||||||
 | 
					use smoltcp::wire::{EthernetAddress, HardwareAddress, IpCidr};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub struct HyphaNetwork {
 | 
				
			||||||
 | 
					    pub device: RawSocket,
 | 
				
			||||||
 | 
					    pub addresses: Vec<IpCidr>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl HyphaNetwork {
 | 
				
			||||||
 | 
					    pub fn new(iface: &str, cidrs: &[&str]) -> Result<HyphaNetwork> {
 | 
				
			||||||
 | 
					        let device = RawSocket::new(iface, smoltcp::phy::Medium::Ethernet)?;
 | 
				
			||||||
 | 
					        let mut addresses: Vec<IpCidr> = Vec::new();
 | 
				
			||||||
 | 
					        for cidr in cidrs {
 | 
				
			||||||
 | 
					            let address =
 | 
				
			||||||
 | 
					                IpCidr::from_str(cidr).map_err(|_| anyhow!("failed to parse cidr: {}", *cidr))?;
 | 
				
			||||||
 | 
					            addresses.push(address);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Ok(HyphaNetwork { device, addresses })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn run(&mut self) -> Result<()> {
 | 
				
			||||||
 | 
					        let mac = MacAddr6::random();
 | 
				
			||||||
 | 
					        let mac = HardwareAddress::Ethernet(EthernetAddress(mac.to_array()));
 | 
				
			||||||
 | 
					        let config = Config::new(mac);
 | 
				
			||||||
 | 
					        let mut iface = Interface::new(config, &mut self.device, Instant::now());
 | 
				
			||||||
 | 
					        iface.update_ip_addrs(|addrs| {
 | 
				
			||||||
 | 
					            addrs
 | 
				
			||||||
 | 
					                .extend_from_slice(&self.addresses)
 | 
				
			||||||
 | 
					                .expect("failed to set ip addresses");
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let mut sockets = SocketSet::new(vec![]);
 | 
				
			||||||
 | 
					        let fd = self.device.as_raw_fd();
 | 
				
			||||||
 | 
					        loop {
 | 
				
			||||||
 | 
					            let timestamp = Instant::now();
 | 
				
			||||||
 | 
					            iface.poll(timestamp, &mut self.device, &mut sockets);
 | 
				
			||||||
 | 
					            phy::wait(fd, iface.poll_delay(timestamp, &sockets))?;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,7 +1,14 @@
 | 
				
			|||||||
use serde::{Deserialize, Serialize};
 | 
					use serde::{Deserialize, Serialize};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Serialize, Deserialize, Debug)]
 | 
				
			||||||
 | 
					pub struct LaunchNetwork {
 | 
				
			||||||
 | 
					    pub link: String,
 | 
				
			||||||
 | 
					    pub ipv4: String,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Serialize, Deserialize, Debug)]
 | 
					#[derive(Serialize, Deserialize, Debug)]
 | 
				
			||||||
pub struct LaunchInfo {
 | 
					pub struct LaunchInfo {
 | 
				
			||||||
 | 
					    pub network: Option<LaunchNetwork>,
 | 
				
			||||||
    pub env: Option<Vec<String>>,
 | 
					    pub env: Option<Vec<String>>,
 | 
				
			||||||
    pub run: Option<Vec<String>>,
 | 
					    pub run: Option<Vec<String>>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,7 @@
 | 
				
			|||||||
#!/usr/bin/env bash
 | 
					#!/usr/bin/env bash
 | 
				
			||||||
set -e
 | 
					set -e
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TARGET="x86_64-unknown-linux-gnu"
 | 
					TARGET="x86_64-unknown-linux-musl"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export RUSTFLAGS="-Ctarget-feature=+crt-static"
 | 
					export RUSTFLAGS="-Ctarget-feature=+crt-static"
 | 
				
			||||||
cd "$(dirname "${0}")/.."
 | 
					cd "$(dirname "${0}")/.."
 | 
				
			||||||
 | 
				
			|||||||
@ -52,8 +52,8 @@ pub struct DomainFilesystem<'a> {
 | 
				
			|||||||
pub struct DomainNetworkInterface<'a> {
 | 
					pub struct DomainNetworkInterface<'a> {
 | 
				
			||||||
    pub mac: &'a str,
 | 
					    pub mac: &'a str,
 | 
				
			||||||
    pub mtu: u32,
 | 
					    pub mtu: u32,
 | 
				
			||||||
    pub bridge: &'a str,
 | 
					    pub bridge: Option<&'a str>,
 | 
				
			||||||
    pub script: &'a str,
 | 
					    pub script: Option<&'a str>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug)]
 | 
				
			||||||
@ -524,24 +524,38 @@ impl XenClient {
 | 
				
			|||||||
        vif: &DomainNetworkInterface,
 | 
					        vif: &DomainNetworkInterface,
 | 
				
			||||||
    ) -> Result<()> {
 | 
					    ) -> Result<()> {
 | 
				
			||||||
        let id = 20 + index as u64;
 | 
					        let id = 20 + index as u64;
 | 
				
			||||||
        let backend_items: Vec<(&str, String)> = vec![
 | 
					        let mut backend_items: Vec<(&str, String)> = vec![
 | 
				
			||||||
            ("frontend-id", domid.to_string()),
 | 
					            ("frontend-id", domid.to_string()),
 | 
				
			||||||
            ("online", "1".to_string()),
 | 
					            ("online", "1".to_string()),
 | 
				
			||||||
            ("state", "1".to_string()),
 | 
					            ("state", "1".to_string()),
 | 
				
			||||||
            ("mac", vif.mac.to_string()),
 | 
					            ("mac", vif.mac.to_string()),
 | 
				
			||||||
            ("mtu", vif.mtu.to_string()),
 | 
					            ("mtu", vif.mtu.to_string()),
 | 
				
			||||||
            ("type", "vif".to_string()),
 | 
					            ("type", "vif".to_string()),
 | 
				
			||||||
            ("bridge", vif.bridge.to_string()),
 | 
					 | 
				
			||||||
            ("handle", id.to_string()),
 | 
					            ("handle", id.to_string()),
 | 
				
			||||||
            ("script", vif.script.to_string()),
 | 
					 | 
				
			||||||
            ("hotplug-status", "".to_string()),
 | 
					 | 
				
			||||||
        ];
 | 
					        ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if vif.bridge.is_some() {
 | 
				
			||||||
 | 
					            backend_items.extend_from_slice(&[("bridge", vif.bridge.unwrap().to_string())]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if vif.script.is_some() {
 | 
				
			||||||
 | 
					            backend_items.extend_from_slice(&[
 | 
				
			||||||
 | 
					                ("script", vif.script.unwrap().to_string()),
 | 
				
			||||||
 | 
					                ("hotplug-status", "".to_string()),
 | 
				
			||||||
 | 
					            ]);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            backend_items.extend_from_slice(&[
 | 
				
			||||||
 | 
					                ("script", "".to_string()),
 | 
				
			||||||
 | 
					                ("hotplug-status", "connected".to_string()),
 | 
				
			||||||
 | 
					            ]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let frontend_items: Vec<(&str, String)> = vec![
 | 
					        let frontend_items: Vec<(&str, String)> = vec![
 | 
				
			||||||
            ("backend-id", backend_domid.to_string()),
 | 
					            ("backend-id", backend_domid.to_string()),
 | 
				
			||||||
            ("state", "1".to_string()),
 | 
					            ("state", "1".to_string()),
 | 
				
			||||||
            ("mac", vif.mac.to_string()),
 | 
					            ("mac", vif.mac.to_string()),
 | 
				
			||||||
            ("trusted", "1".to_string()),
 | 
					            ("trusted", "1".to_string()),
 | 
				
			||||||
 | 
					            ("mtu", vif.mtu.to_string()),
 | 
				
			||||||
        ];
 | 
					        ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.device_add(
 | 
					        self.device_add(
 | 
				
			||||||
 | 
				
			|||||||
@ -2,5 +2,5 @@
 | 
				
			|||||||
set -e
 | 
					set -e
 | 
				
			||||||
 | 
					
 | 
				
			||||||
cd "$(dirname "${0}")/.."
 | 
					cd "$(dirname "${0}")/.."
 | 
				
			||||||
cargo fmt --all
 | 
					 | 
				
			||||||
cargo clippy --target x86_64-unknown-linux-gnu --fix --allow-dirty --allow-staged
 | 
					cargo clippy --target x86_64-unknown-linux-gnu --fix --allow-dirty --allow-staged
 | 
				
			||||||
 | 
					cargo fmt --all
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										11
									
								
								scripts/hyphanet-debug.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										11
									
								
								scripts/hyphanet-debug.sh
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					#!/bin/sh
 | 
				
			||||||
 | 
					set -e
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if [ -z "${RUST_LOG}" ]
 | 
				
			||||||
 | 
					then
 | 
				
			||||||
 | 
					  RUST_LOG="INFO"
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cd "$(dirname "${0}")/.."
 | 
				
			||||||
 | 
					cargo build --target x86_64-unknown-linux-gnu --bin hyphanet
 | 
				
			||||||
 | 
					exec sudo RUST_LOG="${RUST_LOG}" target/x86_64-unknown-linux-gnu/debug/hyphanet "${@}"
 | 
				
			||||||
		Reference in New Issue
	
	Block a user