mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2025-02-22 11:22:26 +00:00
net_util, virtio-devices, vmm: Accept multiple TAP fds
This patch enables multi-queue support for creating virtio-net devices by accepting multiple TAP fds, e.g. '--net fds=3:7'. Fixes: #2164 Signed-off-by: Bo Chen <chen.bo@intel.com>
This commit is contained in:
parent
5209026f52
commit
6664e5a6e7
@ -153,7 +153,7 @@ impl Tap {
|
|||||||
Self::open_named("vmtap%d", num_queue_pairs, None)
|
Self::open_named("vmtap%d", num_queue_pairs, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_tap_fd(fd: RawFd) -> Result<Tap> {
|
pub fn from_tap_fd(fd: RawFd, num_queue_pairs: usize) -> Result<Tap> {
|
||||||
// Ensure that the file is opened non-blocking, this is particularly
|
// Ensure that the file is opened non-blocking, this is particularly
|
||||||
// needed when opened via the shell for macvtap.
|
// needed when opened via the shell for macvtap.
|
||||||
let ret = unsafe {
|
let ret = unsafe {
|
||||||
@ -181,6 +181,9 @@ impl Tap {
|
|||||||
let ifru_flags = ifreq.ifr_ifru.ifru_flags.as_mut();
|
let ifru_flags = ifreq.ifr_ifru.ifru_flags.as_mut();
|
||||||
*ifru_flags =
|
*ifru_flags =
|
||||||
(net_gen::IFF_TAP | net_gen::IFF_NO_PI | net_gen::IFF_VNET_HDR) as c_short;
|
(net_gen::IFF_TAP | net_gen::IFF_NO_PI | net_gen::IFF_VNET_HDR) as c_short;
|
||||||
|
if num_queue_pairs > 1 {
|
||||||
|
*ifru_flags |= net_gen::IFF_MULTI_QUEUE as c_short;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let ret = unsafe { ioctl_with_mut_ref(&tap_file, net_gen::TUNSETIFF(), &mut ifreq) };
|
let ret = unsafe { ioctl_with_mut_ref(&tap_file, net_gen::TUNSETIFF(), &mut ifreq) };
|
||||||
if ret < 0 && IoError::last_os_error().raw_os_error().unwrap() != libc::EEXIST {
|
if ret < 0 && IoError::last_os_error().raw_os_error().unwrap() != libc::EEXIST {
|
||||||
@ -591,7 +594,7 @@ mod tests {
|
|||||||
|
|
||||||
let orig_tap = Tap::new(1).unwrap();
|
let orig_tap = Tap::new(1).unwrap();
|
||||||
let fd = orig_tap.as_raw_fd();
|
let fd = orig_tap.as_raw_fd();
|
||||||
let _new_tap = Tap::from_tap_fd(fd).unwrap();
|
let _new_tap = Tap::from_tap_fd(fd, 1).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -297,21 +297,28 @@ impl Net {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_tap_fd(
|
pub fn from_tap_fds(
|
||||||
id: String,
|
id: String,
|
||||||
fd: RawFd,
|
fds: &[RawFd],
|
||||||
guest_mac: Option<MacAddr>,
|
guest_mac: Option<MacAddr>,
|
||||||
iommu: bool,
|
iommu: bool,
|
||||||
queue_size: u16,
|
queue_size: u16,
|
||||||
seccomp_action: SeccompAction,
|
seccomp_action: SeccompAction,
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
let tap = Tap::from_tap_fd(fd).map_err(Error::TapError)?;
|
let mut taps: Vec<Tap> = Vec::new();
|
||||||
|
let num_queue_pairs = fds.len();
|
||||||
|
|
||||||
|
for fd in fds.iter() {
|
||||||
|
let tap = Tap::from_tap_fd(*fd, num_queue_pairs).map_err(Error::TapError)?;
|
||||||
|
taps.push(tap);
|
||||||
|
}
|
||||||
|
|
||||||
Self::new_with_tap(
|
Self::new_with_tap(
|
||||||
id,
|
id,
|
||||||
vec![tap],
|
taps,
|
||||||
guest_mac,
|
guest_mac,
|
||||||
iommu,
|
iommu,
|
||||||
2,
|
num_queue_pairs * 2,
|
||||||
queue_size,
|
queue_size,
|
||||||
seccomp_action,
|
seccomp_action,
|
||||||
)
|
)
|
||||||
|
@ -107,6 +107,8 @@ pub enum ValidationError {
|
|||||||
CpuTopologyZeroPart,
|
CpuTopologyZeroPart,
|
||||||
/// Virtio needs a min of 2 queues
|
/// Virtio needs a min of 2 queues
|
||||||
VnetQueueLowerThan2,
|
VnetQueueLowerThan2,
|
||||||
|
/// The input queue number for virtio_net must match the number of input fds
|
||||||
|
VnetQueueFdMismatch,
|
||||||
}
|
}
|
||||||
|
|
||||||
type ValidationResult<T> = std::result::Result<T, ValidationError>;
|
type ValidationResult<T> = std::result::Result<T, ValidationError>;
|
||||||
@ -132,6 +134,10 @@ impl fmt::Display for ValidationError {
|
|||||||
"Product of CPU topology parts does not match maximum vCPUs"
|
"Product of CPU topology parts does not match maximum vCPUs"
|
||||||
),
|
),
|
||||||
VnetQueueLowerThan2 => write!(f, "Number of queues to virtio_net less than 2"),
|
VnetQueueLowerThan2 => write!(f, "Number of queues to virtio_net less than 2"),
|
||||||
|
VnetQueueFdMismatch => write!(
|
||||||
|
f,
|
||||||
|
"Number of queues to virtio_net does not match the number of input FDs"
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -765,7 +771,7 @@ pub struct NetConfig {
|
|||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub id: Option<String>,
|
pub id: Option<String>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub fd: Option<i32>,
|
pub fds: Option<Vec<i32>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_netconfig_tap() -> Option<String> {
|
fn default_netconfig_tap() -> Option<String> {
|
||||||
@ -806,14 +812,14 @@ impl Default for NetConfig {
|
|||||||
vhost_user: false,
|
vhost_user: false,
|
||||||
vhost_socket: None,
|
vhost_socket: None,
|
||||||
id: None,
|
id: None,
|
||||||
fd: None,
|
fds: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NetConfig {
|
impl NetConfig {
|
||||||
pub const SYNTAX: &'static str = "Network parameters \
|
pub const SYNTAX: &'static str = "Network parameters \
|
||||||
\"tap=<if_name>,ip=<ip_addr>,mask=<net_mask>,mac=<mac_addr>,fd=<fd>,iommu=on|off,\
|
\"tap=<if_name>,ip=<ip_addr>,mask=<net_mask>,mac=<mac_addr>,fd=<fd1:fd2...>,iommu=on|off,\
|
||||||
num_queues=<number_of_queues>,queue_size=<size_of_each_queue>,\
|
num_queues=<number_of_queues>,queue_size=<size_of_each_queue>,\
|
||||||
vhost_user=<vhost_user_enable>,socket=<vhost_user_socket_path>,id=<device_id>\"";
|
vhost_user=<vhost_user_enable>,socket=<vhost_user_socket_path>,id=<device_id>\"";
|
||||||
|
|
||||||
@ -869,7 +875,11 @@ impl NetConfig {
|
|||||||
.0;
|
.0;
|
||||||
let vhost_socket = parser.get("socket");
|
let vhost_socket = parser.get("socket");
|
||||||
let id = parser.get("id");
|
let id = parser.get("id");
|
||||||
let fd = parser.convert("fd").map_err(Error::ParseNetwork)?;
|
let fds = parser
|
||||||
|
.convert::<IntegerList>("fd")
|
||||||
|
.map_err(Error::ParseNetwork)?
|
||||||
|
.map(|v| v.0.iter().map(|e| *e as i32).collect());
|
||||||
|
|
||||||
let config = NetConfig {
|
let config = NetConfig {
|
||||||
tap,
|
tap,
|
||||||
ip,
|
ip,
|
||||||
@ -882,7 +892,7 @@ impl NetConfig {
|
|||||||
vhost_user,
|
vhost_user,
|
||||||
vhost_socket,
|
vhost_socket,
|
||||||
id,
|
id,
|
||||||
fd,
|
fds,
|
||||||
};
|
};
|
||||||
config.validate().map_err(Error::Validation)?;
|
config.validate().map_err(Error::Validation)?;
|
||||||
Ok(config)
|
Ok(config)
|
||||||
@ -891,6 +901,11 @@ impl NetConfig {
|
|||||||
if self.num_queues < 2 {
|
if self.num_queues < 2 {
|
||||||
return Err(ValidationError::VnetQueueLowerThan2);
|
return Err(ValidationError::VnetQueueLowerThan2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.fds.is_some() && self.fds.as_ref().unwrap().len() * 2 != self.num_queues {
|
||||||
|
return Err(ValidationError::VnetQueueFdMismatch);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1949,10 +1964,11 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
NetConfig::parse("mac=de:ad:be:ef:12:34,fd=3")?,
|
NetConfig::parse("mac=de:ad:be:ef:12:34,fd=3:7,num_queues=4")?,
|
||||||
NetConfig {
|
NetConfig {
|
||||||
mac: MacAddr::parse_str("de:ad:be:ef:12:34").unwrap(),
|
mac: MacAddr::parse_str("de:ad:be:ef:12:34").unwrap(),
|
||||||
fd: Some(3),
|
fds: Some(vec![3, 7]),
|
||||||
|
num_queues: 4,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -1790,11 +1790,11 @@ impl DeviceManager {
|
|||||||
)
|
)
|
||||||
.map_err(DeviceManagerError::CreateVirtioNet)?,
|
.map_err(DeviceManagerError::CreateVirtioNet)?,
|
||||||
))
|
))
|
||||||
} else if let Some(fd) = net_cfg.fd {
|
} else if let Some(fds) = &net_cfg.fds {
|
||||||
Arc::new(Mutex::new(
|
Arc::new(Mutex::new(
|
||||||
virtio_devices::Net::from_tap_fd(
|
virtio_devices::Net::from_tap_fds(
|
||||||
id.clone(),
|
id.clone(),
|
||||||
fd,
|
fds,
|
||||||
Some(net_cfg.mac),
|
Some(net_cfg.mac),
|
||||||
net_cfg.iommu,
|
net_cfg.iommu,
|
||||||
net_cfg.queue_size,
|
net_cfg.queue_size,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user