From 5934f30fde4df4152c7f6b9eb3ef5acd86b5ad29 Mon Sep 17 00:00:00 2001 From: Sebastien Boeuf Date: Thu, 9 May 2019 11:21:15 -0700 Subject: [PATCH] vmm: Add support for letting the VMM create the TAP interface Until now, the only way to get some networking with cloud-hypervisor was to let the user create a TAP interface first, and then to provide the name of this interface to the VMM. This patch extend the previous behavior by adding the support for the creation of a brand new TAP interface from the VMM itself. In case no interface name is provided through "tap=", we will assume the user wants the VMM to create and set the interface on its behalf, no matter the value of other parameters (ip, mask, and mac). In this same scenario, because the user expects the VMM to create the TAP interface, he can also provide the associated IP address and subnet mask associated with it. In case those values are not provided, some default ones will be picked. No matter the value of "tap", the MAC address will always be set, and if no value is provided, the VMM will come up with a default value for it. Signed-off-by: Sebastien Boeuf --- src/main.rs | 10 ++++--- vmm/src/vm.rs | 74 +++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 67 insertions(+), 17 deletions(-) diff --git a/src/main.rs b/src/main.rs index 1ac3c28b6..c5624e27c 100755 --- a/src/main.rs +++ b/src/main.rs @@ -40,7 +40,7 @@ fn main() { .arg( Arg::with_name("net") .long("net") - .help("Network parameters \"tap=,mac=\"") + .help("Network parameters \"tap=,ip=,mask=,mac=\"") .takes_value(true), ) .arg( @@ -81,8 +81,12 @@ fn main() { let disk_path = disk_arg.as_path(); let mut net_params = None; - if let Some(net) = cmd_arguments.value_of("net") { - net_params = Some(net.to_string()); + if cmd_arguments.is_present("net") { + if let Some(net) = cmd_arguments.value_of("net") { + net_params = Some(net.to_string()); + } else { + net_params = Some(String::new()) + } } let rng_path = match cmd_arguments.occurrences_of("rng") { diff --git a/vmm/src/vm.rs b/vmm/src/vm.rs index 714fbd964..706ba8090 100755 --- a/vmm/src/vm.rs +++ b/vmm/src/vm.rs @@ -31,6 +31,7 @@ use pci::{PciConfigIo, PciDevice, PciInterruptPin, PciRoot}; use std::ffi::CString; use std::fs::{File, OpenOptions}; use std::io::{self, stdout}; +use std::net::Ipv4Addr; use std::os::unix::io::{AsRawFd, RawFd}; use std::path::Path; use std::sync::{Arc, Barrier, Mutex}; @@ -166,6 +167,9 @@ pub enum Error { /// Failed parsing network parameters ParseNetworkParameters, + + /// Cannot open tap interface + OpenTap(net_util::TapError), } pub type Result = result::Result; @@ -262,28 +266,59 @@ impl<'a> VmConfig<'a> { } } -fn parse_net_params(net_params: &str) -> Result<(&str, &str)> { +#[derive(Debug)] +struct NetParams<'a> { + tap_if_name: Option<&'a str>, + ip_addr: Ipv4Addr, + net_mask: Ipv4Addr, + mac_addr: MacAddr, +} + +fn parse_net_params(net_params: &str) -> Result { // Split the parameters based on the comma delimiter let params_list: Vec<&str> = net_params.split(',').collect(); - let mut if_name: Option<&str> = None; - let mut mac: Option<&str> = None; + let mut tap: &str = ""; + let mut ip: &str = ""; + let mut mask: &str = ""; + let mut mac: &str = ""; for param in params_list.iter() { if param.starts_with("tap=") { - if_name = Some(¶m[4..]); + tap = ¶m[4..]; + } else if param.starts_with("ip=") { + ip = ¶m[3..]; + } else if param.starts_with("mask=") { + mask = ¶m[5..]; } else if param.starts_with("mac=") { - mac = Some(¶m[4..]); + mac = ¶m[4..]; } } - if let Some(if_name) = if_name { - if let Some(mac) = mac { - return Ok((if_name, mac)); - } + let mut tap_if_name: Option<&str> = None; + let mut ip_addr: Ipv4Addr = "192.168.249.1".parse().unwrap(); + let mut net_mask: Ipv4Addr = "255.255.255.0".parse().unwrap(); + let mut mac_addr: MacAddr = MacAddr::parse_str("12:34:56:78:90:ab").unwrap(); + + if !tap.is_empty() { + tap_if_name = Some(tap); + } + if !ip.is_empty() { + ip_addr = ip.parse().unwrap(); + } + if !mask.is_empty() { + net_mask = mask.parse().unwrap(); + } + if !mac.is_empty() { + mac_addr = MacAddr::parse_str(mac).unwrap(); } - Err(Error::ParseNetworkParameters) + Ok(NetParams { + tap_if_name, + ip_addr, + net_mask, + mac_addr, + }) } struct DeviceManager { @@ -346,11 +381,22 @@ impl DeviceManager { // Add virtio-net if required if let Some(net_params) = &vm_cfg.net_params { - if let Ok((tap_if_name, mac_addr)) = parse_net_params(net_params) { - let mac = MacAddr::parse_str(mac_addr).unwrap(); - let tap = Tap::open_named(tap_if_name).unwrap(); - let virtio_net_device = vm_virtio::Net::new_with_tap(tap, Some(&mac)) + if let Ok(net_params) = parse_net_params(net_params) { + let mut virtio_net_device: vm_virtio::Net; + + if let Some(tap_if_name) = net_params.tap_if_name { + let tap = Tap::open_named(tap_if_name).map_err(Error::OpenTap)?; + virtio_net_device = + vm_virtio::Net::new_with_tap(tap, Some(&net_params.mac_addr)) + .map_err(Error::CreateVirtioNet)?; + } else { + virtio_net_device = vm_virtio::Net::new( + net_params.ip_addr, + net_params.net_mask, + Some(&net_params.mac_addr), + ) .map_err(Error::CreateVirtioNet)?; + } DeviceManager::add_virtio_pci_device( Box::new(virtio_net_device),