From f36b5f3e3c14e0566c2c1c6dde9ead64d09932d1 Mon Sep 17 00:00:00 2001 From: Sebastien Boeuf Date: Wed, 19 May 2021 23:58:02 +0200 Subject: [PATCH] virtio-devices: vhost_user: Factorize features negotiation Factorize the virtio features and vhost-user protocol features negotiation through a common function that blk, fs and net implementations can directly rely on. Signed-off-by: Sebastien Boeuf --- virtio-devices/src/vhost_user/blk.rs | 43 ++++--------------- virtio-devices/src/vhost_user/fs.rs | 42 +++--------------- virtio-devices/src/vhost_user/net.rs | 38 +++------------- .../src/vhost_user/vu_common_ctrl.rs | 37 ++++++++++++++++ 4 files changed, 58 insertions(+), 102 deletions(-) diff --git a/virtio-devices/src/vhost_user/blk.rs b/virtio-devices/src/vhost_user/blk.rs index d6469711e..ba0779c49 100644 --- a/virtio-devices/src/vhost_user/blk.rs +++ b/virtio-devices/src/vhost_user/blk.rs @@ -46,6 +46,9 @@ impl Blk { pub fn new(id: String, vu_cfg: VhostUserConfig) -> Result { let num_queues = vu_cfg.num_queues; + let mut vhost_user_blk = Master::connect(&vu_cfg.socket, num_queues as u64) + .map_err(Error::VhostUserCreateMaster)?; + // Filling device and vring features VMM supports. let mut avail_features = 1 << VIRTIO_BLK_F_SEG_MAX | 1 << VIRTIO_BLK_F_RO @@ -61,46 +64,16 @@ impl Blk { avail_features |= 1 << VIRTIO_BLK_F_MQ; } - let mut vhost_user_blk = Master::connect(&vu_cfg.socket, num_queues as u64) - .map_err(Error::VhostUserCreateMaster)?; - - // Set vhost-user owner. - vhost_user_blk - .set_owner() - .map_err(Error::VhostUserSetOwner)?; - - // Get features from backend, do negotiation to get a feature collection which - // both VMM and backend support. - let backend_features = vhost_user_blk - .get_features() - .map_err(Error::VhostUserGetFeatures)?; - let acked_features = avail_features & backend_features; - // Set features back is required by the vhost crate mechanism, since the - // later vhost call will check if features is filled in master before execution. - vhost_user_blk - .set_features(acked_features) - .map_err(Error::VhostUserSetFeatures)?; - let avail_protocol_features = VhostUserProtocolFeatures::CONFIG | VhostUserProtocolFeatures::MQ | VhostUserProtocolFeatures::CONFIGURE_MEM_SLOTS | VhostUserProtocolFeatures::REPLY_ACK; - let acked_protocol_features = - if acked_features & VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits() != 0 { - let backend_protocol_features = vhost_user_blk - .get_protocol_features() - .map_err(Error::VhostUserGetProtocolFeatures)?; - let acked_protocol_features = avail_protocol_features & backend_protocol_features; - - vhost_user_blk - .set_protocol_features(acked_protocol_features) - .map_err(Error::VhostUserSetProtocolFeatures)?; - - acked_protocol_features.bits() - } else { - 0 - }; + let (acked_features, acked_protocol_features) = negotiate_features_vhost_user( + &mut vhost_user_blk, + avail_features, + avail_protocol_features, + )?; let backend_num_queues = if acked_protocol_features & VhostUserProtocolFeatures::MQ.bits() != 0 { diff --git a/virtio-devices/src/vhost_user/fs.rs b/virtio-devices/src/vhost_user/fs.rs index 8363c5dab..8d37b1f5a 100644 --- a/virtio-devices/src/vhost_user/fs.rs +++ b/virtio-devices/src/vhost_user/fs.rs @@ -2,7 +2,8 @@ // SPDX-License-Identifier: Apache-2.0 use super::vu_common_ctrl::{ - add_memory_region, reset_vhost_user, setup_vhost_user, update_mem_table, + add_memory_region, negotiate_features_vhost_user, reset_vhost_user, setup_vhost_user, + update_mem_table, }; use super::{Error, Result}; use crate::seccomp_filters::{get_seccomp_filter, Thread}; @@ -26,7 +27,6 @@ use vhost::vhost_user::message::{ use vhost::vhost_user::{ HandlerResult, Master, MasterReqHandler, VhostUserMaster, VhostUserMasterReqHandler, }; -use vhost::VhostBackend; use virtio_bindings::bindings::virtio_ring::{ VIRTIO_RING_F_EVENT_IDX, VIRTIO_RING_F_INDIRECT_DESC, }; @@ -312,23 +312,6 @@ impl Fs { | 1 << VIRTIO_RING_F_INDIRECT_DESC | VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits(); - // Set vhost-user owner. - vhost_user_fs - .set_owner() - .map_err(Error::VhostUserSetOwner)?; - - // Get features from backend, do negotiation to get a feature collection which - // both VMM and backend support. - let backend_features = vhost_user_fs - .get_features() - .map_err(Error::VhostUserGetFeatures)?; - let acked_features = avail_features & backend_features; - // Set features back is required by the vhost crate mechanism, since the - // later vhost call will check if features is filled in master before execution. - vhost_user_fs - .set_features(acked_features) - .map_err(Error::VhostUserSetFeatures)?; - let mut avail_protocol_features = VhostUserProtocolFeatures::MQ | VhostUserProtocolFeatures::CONFIGURE_MEM_SLOTS | VhostUserProtocolFeatures::REPLY_ACK; @@ -338,22 +321,11 @@ impl Fs { avail_protocol_features |= slave_protocol_features; } - let acked_protocol_features = - if acked_features & VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits() != 0 { - let backend_protocol_features = vhost_user_fs - .get_protocol_features() - .map_err(Error::VhostUserGetProtocolFeatures)?; - - let acked_protocol_features = avail_protocol_features & backend_protocol_features; - - vhost_user_fs - .set_protocol_features(acked_protocol_features) - .map_err(Error::VhostUserSetProtocolFeatures)?; - - acked_protocol_features.bits() - } else { - 0 - }; + let (acked_features, acked_protocol_features) = negotiate_features_vhost_user( + &mut vhost_user_fs, + avail_features, + avail_protocol_features, + )?; let backend_num_queues = if acked_protocol_features & VhostUserProtocolFeatures::MQ.bits() != 0 { diff --git a/virtio-devices/src/vhost_user/net.rs b/virtio-devices/src/vhost_user/net.rs index 09f4396e7..406e5a55d 100644 --- a/virtio-devices/src/vhost_user/net.rs +++ b/virtio-devices/src/vhost_user/net.rs @@ -91,41 +91,15 @@ impl Net { .map_err(Error::VhostUserCreateMaster)? }; - vhost_user_net - .set_owner() - .map_err(Error::VhostUserSetOwner)?; - - // Get features from backend, do negotiation to get a feature collection which - // both VMM and backend support. - let backend_features = vhost_user_net - .get_features() - .map_err(Error::VhostUserGetFeatures)?; - let acked_features = avail_features & backend_features; - // Set features back is required by the vhost crate mechanism, since the - // later vhost call will check if features is filled in master before execution. - vhost_user_net - .set_features(acked_features) - .map_err(Error::VhostUserSetFeatures)?; - let avail_protocol_features = VhostUserProtocolFeatures::MQ | VhostUserProtocolFeatures::CONFIGURE_MEM_SLOTS | VhostUserProtocolFeatures::REPLY_ACK; - let acked_protocol_features = - if acked_features & VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits() != 0 { - let backend_protocol_features = vhost_user_net - .get_protocol_features() - .map_err(Error::VhostUserGetProtocolFeatures)?; - let acked_protocol_features = avail_protocol_features & backend_protocol_features; - - vhost_user_net - .set_protocol_features(acked_protocol_features) - .map_err(Error::VhostUserSetProtocolFeatures)?; - - acked_protocol_features.bits() - } else { - 0 - }; + let (acked_features, acked_protocol_features) = negotiate_features_vhost_user( + &mut vhost_user_net, + avail_features, + avail_protocol_features, + )?; // If the control queue feature has not been negotiated, let's decrease // the number of queues. @@ -138,7 +112,7 @@ impl Net { vhost_user_net .get_queue_num() .map_err(Error::VhostUserGetQueueMaxNum)? as usize - } else if backend_features & (1 << virtio_net::VIRTIO_NET_F_CTRL_VQ) != 0 { + } else if acked_features & (1 << virtio_net::VIRTIO_NET_F_CTRL_VQ) != 0 { DEFAULT_QUEUE_NUMBER + 1 } else { DEFAULT_QUEUE_NUMBER diff --git a/virtio-devices/src/vhost_user/vu_common_ctrl.rs b/virtio-devices/src/vhost_user/vu_common_ctrl.rs index aca14033f..a2560ef4a 100644 --- a/virtio-devices/src/vhost_user/vu_common_ctrl.rs +++ b/virtio-devices/src/vhost_user/vu_common_ctrl.rs @@ -8,6 +8,7 @@ use std::convert::TryInto; use std::os::unix::io::AsRawFd; use std::sync::Arc; use std::vec::Vec; +use vhost::vhost_user::message::{VhostUserProtocolFeatures, VhostUserVirtioFeatures}; use vhost::vhost_user::{Master, VhostUserMaster}; use vhost::{VhostBackend, VhostUserMemoryRegionInfo, VringConfigData}; use vm_memory::{ @@ -68,6 +69,42 @@ pub fn add_memory_region(vu: &mut Master, region: &Arc) -> Resu .map_err(Error::VhostUserAddMemReg) } +pub fn negotiate_features_vhost_user( + vu: &mut Master, + avail_features: u64, + avail_protocol_features: VhostUserProtocolFeatures, +) -> Result<(u64, u64)> { + // Set vhost-user owner. + vu.set_owner().map_err(Error::VhostUserSetOwner)?; + + // Get features from backend, do negotiation to get a feature collection which + // both VMM and backend support. + let backend_features = vu.get_features().map_err(Error::VhostUserGetFeatures)?; + let acked_features = avail_features & backend_features; + // Set features back is required by the vhost crate mechanism, since the + // later vhost call will check if features is filled in master before execution. + vu.set_features(acked_features) + .map_err(Error::VhostUserSetFeatures)?; + + let acked_protocol_features = + if acked_features & VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits() != 0 { + let backend_protocol_features = vu + .get_protocol_features() + .map_err(Error::VhostUserGetProtocolFeatures)?; + + let acked_protocol_features = avail_protocol_features & backend_protocol_features; + + vu.set_protocol_features(acked_protocol_features) + .map_err(Error::VhostUserSetProtocolFeatures)?; + + acked_protocol_features.bits() + } else { + 0 + }; + + Ok((acked_features, acked_protocol_features)) +} + pub fn setup_vhost_user( vu: &mut Master, mem: &GuestMemoryMmap,