mirror of
https://github.com/edera-dev/krata.git
synced 2025-08-02 12:50:54 +00:00
hypha: implement basic networking support
This commit is contained in:
parent
70dc2f943f
commit
21c6a27097
@ -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 "${@}"
|
Loading…
Reference in New Issue
Block a user