virtio-devices, vmm: vhost: net: Add client mode support

Adding the support for an OVS vhost-user backend to connect as the
vhost-user client. This means we introduce with this patch a new
option to our `--net` parameter. This option is called 'server' in order
to ask the VMM to run as the server for the vhost-user socket.

Fixes #1745

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
Sebastien Boeuf 2021-05-04 10:33:35 +02:00
parent 656b9f97f9
commit b5c6b04b36
5 changed files with 80 additions and 7 deletions

View File

@ -24,10 +24,14 @@ pub use self::vu_common_ctrl::VhostUserConfig;
#[derive(Debug)]
pub enum Error {
/// Failed accepting connection.
AcceptConnection(io::Error),
/// Invalid available address.
AvailAddress,
/// Queue number is not correct
BadQueueNum,
/// Failed binding vhost-user socket.
BindSocket(io::Error),
/// Creating kill eventfd failed.
CreateKillEventFd(io::Error),
/// Cloning kill eventfd failed.

View File

@ -16,6 +16,7 @@ use net_util::MacAddr;
use seccomp::{SeccompAction, SeccompFilter};
use std::ops::Deref;
use std::os::unix::io::AsRawFd;
use std::os::unix::net::UnixListener;
use std::result;
use std::sync::{Arc, Barrier};
use std::thread;
@ -46,6 +47,7 @@ pub struct Net {
seccomp_action: SeccompAction,
guest_memory: Option<GuestMemoryAtomic<GuestMemoryMmap>>,
acked_protocol_features: u64,
socket_path: Option<String>,
}
impl Net {
@ -56,9 +58,23 @@ impl Net {
mac_addr: MacAddr,
vu_cfg: VhostUserConfig,
seccomp_action: SeccompAction,
server: bool,
) -> Result<Net> {
let mut vhost_user_net = Master::connect(&vu_cfg.socket, vu_cfg.num_queues as u64)
.map_err(Error::VhostUserCreateMaster)?;
let mut socket_path: Option<String> = None;
let mut vhost_user_net = if server {
info!("Binding vhost-user-net listener...");
let listener = UnixListener::bind(&vu_cfg.socket).map_err(Error::BindSocket)?;
info!("Waiting for incoming vhost-user-net connection...");
let (stream, _) = listener.accept().map_err(Error::AcceptConnection)?;
socket_path = Some(vu_cfg.socket.clone());
Master::from_stream(stream, vu_cfg.num_queues as u64)
} else {
Master::connect(&vu_cfg.socket, vu_cfg.num_queues as u64)
.map_err(Error::VhostUserCreateMaster)?
};
// Filling device and vring features VMM supports.
let mut avail_features = 1 << virtio_net::VIRTIO_NET_F_GUEST_CSUM
@ -166,6 +182,7 @@ impl Net {
seccomp_action,
guest_memory: None,
acked_protocol_features,
socket_path,
})
}
}
@ -368,6 +385,11 @@ impl VirtioDevice for Net {
fn shutdown(&mut self) {
let _ = unsafe { libc::close(self.vhost_user_net.as_raw_fd()) };
// Remove socket path if needed
if let Some(socket_path) = &self.socket_path {
let _ = std::fs::remove_file(socket_path);
}
}
fn add_memory_region(

View File

@ -712,6 +712,9 @@ components:
default: false
vhost_socket:
type: string
vhost_mode:
type: string
default: "client"
id:
type: string
fd:

View File

@ -878,6 +878,35 @@ impl DiskConfig {
}
}
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub enum VhostMode {
Client,
Server,
}
impl Default for VhostMode {
fn default() -> Self {
VhostMode::Client
}
}
#[derive(Debug)]
pub enum ParseVhostModeError {
InvalidValue(String),
}
impl FromStr for VhostMode {
type Err = ParseVhostModeError;
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
match s.to_lowercase().as_str() {
"client" => Ok(VhostMode::Client),
"server" => Ok(VhostMode::Server),
_ => Err(ParseVhostModeError::InvalidValue(s.to_owned())),
}
}
}
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub struct NetConfig {
#[serde(default = "default_netconfig_tap")]
@ -900,6 +929,8 @@ pub struct NetConfig {
pub vhost_user: bool,
pub vhost_socket: Option<String>,
#[serde(default)]
pub vhost_mode: VhostMode,
#[serde(default)]
pub id: Option<String>,
#[serde(default)]
pub fds: Option<Vec<i32>>,
@ -944,6 +975,7 @@ impl Default for NetConfig {
queue_size: default_netconfig_queue_size(),
vhost_user: false,
vhost_socket: None,
vhost_mode: VhostMode::Client,
id: None,
fds: None,
rate_limiter_config: None,
@ -954,8 +986,8 @@ impl Default for NetConfig {
impl NetConfig {
pub const SYNTAX: &'static str = "Network parameters \
\"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>,\
vhost_user=<vhost_user_enable>,socket=<vhost_user_socket_path>,id=<device_id>,\
num_queues=<number_of_queues>,queue_size=<size_of_each_queue>,id=<device_id>,\
vhost_user=<vhost_user_enable>,socket=<vhost_user_socket_path>,vhost_mode=client|server,\
bw_size=<bytes>,bw_one_time_burst=<bytes>,bw_refill_time=<ms>,\
ops_size=<io_ops>,ops_one_time_burst=<io_ops>,ops_refill_time=<ms>\"";
@ -973,6 +1005,7 @@ impl NetConfig {
.add("num_queues")
.add("vhost_user")
.add("socket")
.add("vhost_mode")
.add("id")
.add("fd")
.add("bw_size")
@ -1016,6 +1049,10 @@ impl NetConfig {
.unwrap_or(Toggle(false))
.0;
let vhost_socket = parser.get("socket");
let vhost_mode = parser
.convert("vhost_mode")
.map_err(Error::ParseNetwork)?
.unwrap_or_default();
let id = parser.get("id");
let fds = parser
.convert::<IntegerList>("fd")
@ -1084,6 +1121,7 @@ impl NetConfig {
queue_size,
vhost_user,
vhost_socket,
vhost_mode,
id,
fds,
rate_limiter_config,

View File

@ -9,9 +9,10 @@
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
//
use crate::config::ConsoleOutputMode;
use crate::config::DeviceConfig;
use crate::config::{DiskConfig, FsConfig, NetConfig, PmemConfig, VmConfig, VsockConfig};
use crate::config::{
ConsoleOutputMode, DeviceConfig, DiskConfig, FsConfig, NetConfig, PmemConfig, VhostMode,
VmConfig, VsockConfig,
};
use crate::device_tree::{DeviceNode, DeviceTree};
#[cfg(feature = "kvm")]
use crate::interrupt::kvm::KvmMsiInterruptManager as MsiInterruptManager;
@ -2035,12 +2036,17 @@ impl DeviceManager {
num_queues: net_cfg.num_queues,
queue_size: net_cfg.queue_size,
};
let server = match net_cfg.vhost_mode {
VhostMode::Client => false,
VhostMode::Server => true,
};
let vhost_user_net_device = Arc::new(Mutex::new(
match virtio_devices::vhost_user::Net::new(
id.clone(),
net_cfg.mac,
vu_cfg,
self.seccomp_action.clone(),
server,
) {
Ok(vun_device) => vun_device,
Err(e) => {