mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-09-16 06:18:58 +00:00
dragonball: Wrap config space into set_config_space
Config space of network device is shared and accord with virtio 1.1 spec. It is a good way to abstract the common part into one function. `set_config_space()` implements this. Plus, this patch removes `vq_pairs` from vhost-net devices, since there is a possibility of data inconsistency. For example, some places read that from `self.vq_pairs`, others read from `queue_sizes.len() / 2`. Signed-off-by: Xuewei Niu <niuxuewei.nxw@antgroup.com>
This commit is contained in:
@@ -176,7 +176,6 @@ impl From<&NetworkInterfaceConfig> for VhostNetDeviceConfigInfo {
|
||||
iface_id: config.iface_id.clone(),
|
||||
host_dev_name: config.host_dev_name.clone(),
|
||||
num_queues,
|
||||
vq_pairs: num_queues / 2,
|
||||
queue_size,
|
||||
guest_mac: value.guest_mac,
|
||||
allow_duplicate_mac: config.allow_duplicate_mac,
|
||||
|
@@ -55,6 +55,73 @@ const PATCH_RATE_LIMITER_EVENT: u32 = 5;
|
||||
// Number of DeviceEventT events supported by this implementation.
|
||||
pub const NET_EVENTS_COUNT: u32 = 6;
|
||||
|
||||
// Config space of network config:
|
||||
// https://docs.oasis-open.org/virtio/virtio/v1.1/csprd01/virtio-v1.1-csprd01.html#x1-2000004
|
||||
// MAC
|
||||
const CONFIG_SPACE_MAC: usize = 0;
|
||||
// Status
|
||||
const CONFIG_SPACE_STATUS: usize = CONFIG_SPACE_MAC + MAC_ADDR_LEN;
|
||||
const CONFIG_SPACE_STATUS_SIZE: usize = 2;
|
||||
// Max virtqueue pairs
|
||||
const CONFIG_SPACE_MAX_VIRTQUEUE_PAIRS: usize = CONFIG_SPACE_STATUS + CONFIG_SPACE_STATUS_SIZE;
|
||||
const CONFIG_SPACE_MAX_VIRTQUEUE_PAIRS_SIZE: usize = 2;
|
||||
// MTU
|
||||
const CONFIG_SPACE_MTU: usize =
|
||||
CONFIG_SPACE_MAX_VIRTQUEUE_PAIRS + CONFIG_SPACE_MAX_VIRTQUEUE_PAIRS_SIZE;
|
||||
const CONFIG_SPACE_MTU_SIZE: usize = 2;
|
||||
// Size of config space
|
||||
const CONFIG_SPACE_SIZE: usize = MAC_ADDR_LEN
|
||||
+ CONFIG_SPACE_STATUS_SIZE
|
||||
+ CONFIG_SPACE_MAX_VIRTQUEUE_PAIRS_SIZE
|
||||
+ CONFIG_SPACE_MTU_SIZE;
|
||||
|
||||
// Default MTU for network device
|
||||
pub const DEFAULT_MTU: u16 = 1500;
|
||||
|
||||
/// Setup config space for network device.
|
||||
pub fn setup_config_space(
|
||||
device_name: &str,
|
||||
guest_mac: &Option<&MacAddr>,
|
||||
avail_features: &mut u64,
|
||||
vq_pairs: u16,
|
||||
mtu: u16,
|
||||
) -> Result<Vec<u8>> {
|
||||
let mut config_space = vec![0u8; CONFIG_SPACE_SIZE];
|
||||
if let Some(mac) = guest_mac.as_ref() {
|
||||
config_space[CONFIG_SPACE_MAC..CONFIG_SPACE_MAC + MAC_ADDR_LEN]
|
||||
.copy_from_slice(mac.get_bytes());
|
||||
// When this feature isn't available, the driver generates a random MAC address.
|
||||
// Otherwise, it should attempt to read the device MAC address from the config space.
|
||||
*avail_features |= 1u64 << VIRTIO_NET_F_MAC;
|
||||
}
|
||||
|
||||
// Mark link as up: status only exists if VIRTIO_NET_F_STATUS is set.
|
||||
if *avail_features & (1 << VIRTIO_NET_F_STATUS) != 0 {
|
||||
config_space[CONFIG_SPACE_STATUS..CONFIG_SPACE_STATUS + CONFIG_SPACE_STATUS_SIZE]
|
||||
.copy_from_slice(&(VIRTIO_NET_S_LINK_UP as u16).to_le_bytes());
|
||||
}
|
||||
|
||||
// Set max virtqueue pairs, which only exists if VIRTIO_NET_F_MQ is set.
|
||||
if *avail_features & (1 << VIRTIO_NET_F_MQ) != 0 {
|
||||
if vq_pairs <= 1 {
|
||||
return Err(Error::InvalidInput);
|
||||
}
|
||||
config_space[CONFIG_SPACE_MAX_VIRTQUEUE_PAIRS
|
||||
..CONFIG_SPACE_MAX_VIRTQUEUE_PAIRS + CONFIG_SPACE_MAX_VIRTQUEUE_PAIRS_SIZE]
|
||||
.copy_from_slice(&vq_pairs.to_le_bytes());
|
||||
}
|
||||
|
||||
config_space[CONFIG_SPACE_MTU..CONFIG_SPACE_MTU + CONFIG_SPACE_MTU_SIZE]
|
||||
.copy_from_slice(&mtu.to_le_bytes());
|
||||
|
||||
debug!(
|
||||
"{}: config space is set to {:X?}, guest_mac: {:?}, avail_feature: 0x{:X}, vq_pairs: {}, mtu: {}",
|
||||
device_name, config_space, guest_mac, avail_features, vq_pairs, mtu
|
||||
);
|
||||
|
||||
Ok(config_space)
|
||||
}
|
||||
|
||||
/// Error for virtio-net devices to handle requests from guests.
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum NetError {
|
||||
@@ -632,14 +699,13 @@ impl<AS: GuestAddressSpace> Net<AS> {
|
||||
| 1u64 << VIRTIO_NET_F_HOST_UFO
|
||||
| 1u64 << VIRTIO_F_VERSION_1;
|
||||
|
||||
let mut config_space = Vec::new();
|
||||
if let Some(mac) = guest_mac {
|
||||
config_space.resize(MAC_ADDR_LEN, 0);
|
||||
config_space[..].copy_from_slice(mac.get_bytes());
|
||||
// When this feature isn't available, the driver generates a random MAC address.
|
||||
// Otherwise, it should attempt to read the device MAC address from the config space.
|
||||
avail_features |= 1u64 << VIRTIO_NET_F_MAC;
|
||||
}
|
||||
let config_space = setup_config_space(
|
||||
NET_DRIVER_NAME,
|
||||
&guest_mac,
|
||||
&mut avail_features,
|
||||
1,
|
||||
DEFAULT_MTU,
|
||||
)?;
|
||||
|
||||
let device_info = VirtioDeviceInfo::new(
|
||||
NET_DRIVER_NAME.to_string(),
|
||||
@@ -843,6 +909,7 @@ where
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::convert::TryInto;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
@@ -948,24 +1015,20 @@ mod tests {
|
||||
VirtioDevice::<Arc<GuestMemoryMmap<()>>, QueueSync, GuestRegionMmap>::get_avail_features(&dev, 2),
|
||||
0
|
||||
);
|
||||
// device config length is 0 because guest_mac is None
|
||||
let mut config: [u8; 1] = [0];
|
||||
assert_eq!(
|
||||
VirtioDevice::<Arc<GuestMemoryMmap<()>>, QueueSync, GuestRegionMmap>::read_config(
|
||||
&mut dev,
|
||||
0,
|
||||
&mut config,
|
||||
)
|
||||
.unwrap_err(),
|
||||
ConfigError::InvalidOffset(0)
|
||||
);
|
||||
let config: [u8; 16] = [0; 16];
|
||||
// Config with correct size
|
||||
let config: [u8; CONFIG_SPACE_SIZE] = [0; CONFIG_SPACE_SIZE];
|
||||
VirtioDevice::<Arc<GuestMemoryMmap<()>>, QueueSync, GuestRegionMmap>::write_config(
|
||||
&mut dev, 0, &config,
|
||||
)
|
||||
.unwrap();
|
||||
// Config with invalid size
|
||||
let config: [u8; CONFIG_SPACE_SIZE + 1] = [0; CONFIG_SPACE_SIZE + 1];
|
||||
assert_eq!(
|
||||
VirtioDevice::<Arc<GuestMemoryMmap<()>>, QueueSync, GuestRegionMmap>::write_config(
|
||||
&mut dev, 0, &config,
|
||||
)
|
||||
.unwrap_err(),
|
||||
ConfigError::InvalidOffset(0)
|
||||
ConfigError::InvalidOffsetPlusDataLen(CONFIG_SPACE_SIZE as u64 + 1)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1408,4 +1471,109 @@ mod tests {
|
||||
assert!(!handler.rx.rate_limiter.is_blocked());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_set_config_space() {
|
||||
let mac = MacAddr::parse_str("bf:b7:72:50:82:00").unwrap();
|
||||
let mut afeatures: u64;
|
||||
let mut vq_pairs: u16;
|
||||
// Avail features: VIRTIO_NET_F_STATUS + VIRTIO_NET_F_MQ
|
||||
{
|
||||
afeatures = 0;
|
||||
vq_pairs = 2;
|
||||
afeatures |= 1 << VIRTIO_NET_F_STATUS | 1 << VIRTIO_NET_F_MQ;
|
||||
|
||||
let cs = setup_config_space(
|
||||
"virtio-net",
|
||||
&Some(&mac),
|
||||
&mut afeatures,
|
||||
vq_pairs,
|
||||
DEFAULT_MTU,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// Mac
|
||||
assert_eq!(
|
||||
mac.get_bytes(),
|
||||
&cs[CONFIG_SPACE_MAC..CONFIG_SPACE_MAC + MAC_ADDR_LEN]
|
||||
);
|
||||
// Status
|
||||
assert_eq!(
|
||||
VIRTIO_NET_S_LINK_UP as u16,
|
||||
u16::from_le_bytes(
|
||||
cs[CONFIG_SPACE_STATUS..CONFIG_SPACE_STATUS + CONFIG_SPACE_STATUS_SIZE]
|
||||
.try_into()
|
||||
.unwrap()
|
||||
)
|
||||
);
|
||||
// Max virtqueue pairs
|
||||
assert_eq!(
|
||||
vq_pairs,
|
||||
u16::from_le_bytes(
|
||||
cs[CONFIG_SPACE_MAX_VIRTQUEUE_PAIRS
|
||||
..CONFIG_SPACE_MAX_VIRTQUEUE_PAIRS + CONFIG_SPACE_MAX_VIRTQUEUE_PAIRS_SIZE]
|
||||
.try_into()
|
||||
.unwrap()
|
||||
)
|
||||
);
|
||||
// MTU
|
||||
assert_eq!(
|
||||
DEFAULT_MTU,
|
||||
u16::from_le_bytes(
|
||||
cs[CONFIG_SPACE_MTU..CONFIG_SPACE_MTU + CONFIG_SPACE_MTU_SIZE]
|
||||
.try_into()
|
||||
.unwrap()
|
||||
)
|
||||
);
|
||||
}
|
||||
// No avail features
|
||||
{
|
||||
afeatures = 0;
|
||||
vq_pairs = 1;
|
||||
|
||||
let cs = setup_config_space(
|
||||
"virtio-net",
|
||||
&Some(&mac),
|
||||
&mut afeatures,
|
||||
vq_pairs,
|
||||
DEFAULT_MTU,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// Status
|
||||
assert_eq!(
|
||||
0,
|
||||
u16::from_le_bytes(
|
||||
cs[CONFIG_SPACE_STATUS..CONFIG_SPACE_STATUS + CONFIG_SPACE_STATUS_SIZE]
|
||||
.try_into()
|
||||
.unwrap()
|
||||
)
|
||||
);
|
||||
// Max virtqueue pairs
|
||||
assert_eq!(
|
||||
0,
|
||||
u16::from_le_bytes(
|
||||
cs[CONFIG_SPACE_MAX_VIRTQUEUE_PAIRS
|
||||
..CONFIG_SPACE_MAX_VIRTQUEUE_PAIRS + CONFIG_SPACE_MAX_VIRTQUEUE_PAIRS_SIZE]
|
||||
.try_into()
|
||||
.unwrap()
|
||||
)
|
||||
);
|
||||
}
|
||||
// Avail features: VIRTIO_NET_F_MQ and invalid value of vq_pairs
|
||||
{
|
||||
afeatures = 0;
|
||||
vq_pairs = 1;
|
||||
afeatures |= 1 << VIRTIO_NET_F_MQ;
|
||||
|
||||
let cs = setup_config_space(
|
||||
"virtio-net",
|
||||
&Some(&mac),
|
||||
&mut afeatures,
|
||||
vq_pairs,
|
||||
DEFAULT_MTU,
|
||||
);
|
||||
assert!(cs.is_err());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -31,6 +31,7 @@ use virtio_bindings::bindings::virtio_ring::*;
|
||||
use virtio_queue::{DescriptorChain, QueueT};
|
||||
use vm_memory::{Address, GuestMemory, GuestMemoryRegion, MemoryRegionAddress};
|
||||
|
||||
use crate::net::{setup_config_space, DEFAULT_MTU};
|
||||
use crate::vhost::net::{virtio_handle_ctrl_mq, virtio_handle_ctrl_status, FromNetCtrl};
|
||||
#[cfg(test)]
|
||||
use crate::vhost::vhost_kern::test_utils::{
|
||||
@@ -65,7 +66,6 @@ where
|
||||
R: GuestMemoryRegion + Sync + Send + 'static,
|
||||
{
|
||||
taps: Vec<Tap>,
|
||||
vq_pairs: usize,
|
||||
handles: Vec<VhostNet<AS>>,
|
||||
device_info: VirtioDeviceInfo,
|
||||
queue_sizes: Arc<Vec<u16>>,
|
||||
@@ -134,13 +134,14 @@ where
|
||||
/// Create a new vhost-net device with a given tap interface.
|
||||
pub fn new_with_tap(
|
||||
tap: Tap,
|
||||
vq_pairs: usize,
|
||||
guest_mac: Option<&MacAddr>,
|
||||
queue_sizes: Arc<Vec<u16>>,
|
||||
event_mgr: EpollManager,
|
||||
) -> VirtioResult<Self> {
|
||||
trace!(target: "vhost-net", "{}: Net::new_with_tap()", NET_DRIVER_NAME);
|
||||
|
||||
let vq_pairs = queue_sizes.len() / 2;
|
||||
|
||||
let taps = tap
|
||||
.into_mq_taps(vq_pairs)
|
||||
.map_err(|err| VirtioError::VhostNet(Error::TapError(TapError::Open(err))))?;
|
||||
@@ -163,41 +164,14 @@ where
|
||||
if vq_pairs > 1 {
|
||||
avail_features |= (1 << VIRTIO_NET_F_MQ | 1 << VIRTIO_NET_F_CTRL_VQ) as u64;
|
||||
}
|
||||
// Network device configuration layout:
|
||||
// https://docs.oasis-open.org/virtio/virtio/v1.1/csprd01/virtio-v1.1-csprd01.html#x1-2000004
|
||||
// - [u8; 6]: mac address
|
||||
// - u16: status
|
||||
// - u16: max_virtqueue_pairs
|
||||
// - u16: mtu
|
||||
// - u32: speed
|
||||
// - u8: duplex
|
||||
let mut config_space = vec![0u8; 17];
|
||||
if let Some(mac) = guest_mac {
|
||||
// When this feature isn't available, the driver generates a random
|
||||
// MAC address. Otherwise, it should attempt to read the device MAC
|
||||
// address from the config space.
|
||||
avail_features |= 1u64 << VIRTIO_NET_F_MAC;
|
||||
config_space[0..6].copy_from_slice(mac.get_bytes());
|
||||
} else {
|
||||
avail_features &= !(1 << VIRTIO_NET_F_MAC) as u64;
|
||||
}
|
||||
|
||||
// status: mark link as up
|
||||
config_space[6] = VIRTIO_NET_S_LINK_UP as u8;
|
||||
config_space[7] = 0;
|
||||
// max_virtqueue_pairs: only support one rx/tx pair
|
||||
config_space[8] = vq_pairs as u8;
|
||||
config_space[9] = 0;
|
||||
// mtu: 1500 = 1536 - vxlan header?
|
||||
config_space[10] = 220;
|
||||
config_space[11] = 5;
|
||||
// speed: 1000Mb
|
||||
config_space[12] = 232;
|
||||
config_space[13] = 3;
|
||||
config_space[14] = 0;
|
||||
config_space[15] = 0;
|
||||
// duplex: full duplex: 0x01
|
||||
config_space[16] = 1;
|
||||
let config_space = setup_config_space(
|
||||
NET_DRIVER_NAME,
|
||||
&guest_mac,
|
||||
&mut avail_features,
|
||||
vq_pairs as u16,
|
||||
DEFAULT_MTU,
|
||||
)?;
|
||||
|
||||
let device_info = VirtioDeviceInfo::new(
|
||||
NET_DRIVER_NAME.to_owned(),
|
||||
@@ -210,7 +184,6 @@ where
|
||||
|
||||
Ok(Net {
|
||||
taps,
|
||||
vq_pairs,
|
||||
handles: Vec::new(),
|
||||
device_info,
|
||||
queue_sizes,
|
||||
@@ -233,18 +206,19 @@ where
|
||||
/// Create a vhost network with the Tap name
|
||||
pub fn new(
|
||||
host_dev_name: String,
|
||||
vq_pairs: usize,
|
||||
guest_mac: Option<&MacAddr>,
|
||||
queue_sizes: Arc<Vec<u16>>,
|
||||
event_mgr: EpollManager,
|
||||
) -> VirtioResult<Self> {
|
||||
let vq_pairs = queue_sizes.len() / 2;
|
||||
|
||||
// Open a TAP interface
|
||||
let tap = Tap::open_named(&host_dev_name, vq_pairs > 1)
|
||||
.map_err(|err| VirtioError::VhostNet(Error::TapError(TapError::Open(err))))?;
|
||||
tap.enable()
|
||||
.map_err(|err| VirtioError::VhostNet(Error::TapError(TapError::Enable(err))))?;
|
||||
|
||||
Self::new_with_tap(tap, vq_pairs, guest_mac, queue_sizes, event_mgr)
|
||||
Self::new_with_tap(tap, guest_mac, queue_sizes, event_mgr)
|
||||
}
|
||||
|
||||
fn do_device_activate(
|
||||
@@ -284,30 +258,31 @@ where
|
||||
Q: QueueT + Send + 'static,
|
||||
R: GuestMemoryRegion + Sync + Send + 'static,
|
||||
{
|
||||
trace!(target: "vhost-net", "{}: Net::setup_vhost_backend(vq_pairs: {})", NET_DRIVER_NAME, self.vq_pairs);
|
||||
let vq_pairs = self.queue_sizes.len() / 2;
|
||||
trace!(target: "vhost-net", "{}: Net::setup_vhost_backend(vq_pairs: {})", NET_DRIVER_NAME, vq_pairs);
|
||||
|
||||
if self.vq_pairs < 1 {
|
||||
if vq_pairs < 1 {
|
||||
error!(
|
||||
"{}: Invalid virtio queue pairs, expected a value greater than 0, but got {}",
|
||||
NET_DRIVER_NAME, self.vq_pairs
|
||||
NET_DRIVER_NAME, vq_pairs
|
||||
);
|
||||
return Err(VirtioError::ActivateError(Box::new(
|
||||
ActivateError::InvalidParam,
|
||||
)));
|
||||
}
|
||||
|
||||
if self.handles.len() != self.vq_pairs || self.taps.len() != self.vq_pairs {
|
||||
if self.handles.len() != vq_pairs || self.taps.len() != vq_pairs {
|
||||
error!("{}: Invalid handlers or taps, handlers length {}, taps length {}, virtio queue pairs = {}",
|
||||
NET_DRIVER_NAME,
|
||||
self.handles.len(),
|
||||
self.taps.len(),
|
||||
self.vq_pairs);
|
||||
vq_pairs);
|
||||
return Err(VirtioError::ActivateError(Box::new(
|
||||
ActivateError::InternalError,
|
||||
)));
|
||||
}
|
||||
|
||||
for idx in 0..self.vq_pairs {
|
||||
for idx in 0..vq_pairs {
|
||||
self.init_vhost_dev(idx, config, mem)?;
|
||||
}
|
||||
|
||||
@@ -755,7 +730,6 @@ mod tests {
|
||||
let epoll_mgr = EpollManager::default();
|
||||
let mut dev: Net<Arc<GuestMemoryMmap>, QueueSync, GuestRegionMmap> = Net::new(
|
||||
String::from("test_vhosttap"),
|
||||
2,
|
||||
Some(&guest_mac),
|
||||
queue_sizes,
|
||||
epoll_mgr,
|
||||
@@ -791,49 +765,12 @@ mod tests {
|
||||
fn test_vhost_kern_net_virtio_activate() {
|
||||
let guest_mac_str = "11:22:33:44:55:66";
|
||||
let guest_mac = MacAddr::parse_str(guest_mac_str).unwrap();
|
||||
// Invalid vq_pairs
|
||||
{
|
||||
let queue_sizes = Arc::new(vec![128, 128]);
|
||||
let epoll_mgr = EpollManager::default();
|
||||
let mut dev: Net<Arc<GuestMemoryMmap>, QueueSync, GuestRegionMmap> = Net::new(
|
||||
String::from("test_vhosttap"),
|
||||
2,
|
||||
Some(&guest_mac),
|
||||
queue_sizes,
|
||||
epoll_mgr,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// The length of queues should be 4.
|
||||
let queues = vec![
|
||||
VirtioQueueConfig::create(128, 0).unwrap(),
|
||||
VirtioQueueConfig::create(128, 0).unwrap(),
|
||||
];
|
||||
|
||||
let mem = GuestMemoryMmap::from_ranges(&[(GuestAddress(0), 0x10000)]).unwrap();
|
||||
let kvm = Kvm::new().unwrap();
|
||||
let vm_fd = Arc::new(kvm.create_vm().unwrap());
|
||||
let resources = DeviceResources::new();
|
||||
let address_space = create_address_space();
|
||||
let config = VirtioDeviceConfig::new(
|
||||
Arc::new(mem),
|
||||
address_space,
|
||||
vm_fd,
|
||||
resources,
|
||||
queues,
|
||||
None,
|
||||
Arc::new(NoopNotifier::default()),
|
||||
);
|
||||
|
||||
assert!(dev.activate(config).is_err())
|
||||
}
|
||||
// Invalid queue sizes
|
||||
{
|
||||
let queue_sizes = Arc::new(vec![128]);
|
||||
let epoll_mgr = EpollManager::default();
|
||||
let mut dev: Net<Arc<GuestMemoryMmap>, QueueSync, GuestRegionMmap> = Net::new(
|
||||
String::from("test_vhosttap"),
|
||||
1,
|
||||
Some(&guest_mac),
|
||||
queue_sizes,
|
||||
epoll_mgr,
|
||||
@@ -878,7 +815,6 @@ mod tests {
|
||||
let epoll_mgr = EpollManager::default();
|
||||
let mut dev: Net<Arc<GuestMemoryMmap>, Queue, GuestRegionMmap> = Net::new(
|
||||
String::from("test_vhosttap"),
|
||||
1,
|
||||
Some(&guest_mac),
|
||||
queue_sizes,
|
||||
epoll_mgr,
|
||||
|
@@ -17,14 +17,15 @@ use vhost_rs::vhost_user::{
|
||||
use vhost_rs::Error as VhostError;
|
||||
use virtio_bindings::bindings::virtio_net::{
|
||||
virtio_net_ctrl_hdr, VIRTIO_NET_CTRL_MQ, VIRTIO_NET_F_CTRL_MAC_ADDR, VIRTIO_NET_F_CTRL_RX,
|
||||
VIRTIO_NET_F_CTRL_VLAN, VIRTIO_NET_F_CTRL_VQ, VIRTIO_NET_F_GUEST_ANNOUNCE, VIRTIO_NET_F_MAC,
|
||||
VIRTIO_NET_F_MQ, VIRTIO_NET_F_MTU, VIRTIO_NET_OK, VIRTIO_NET_S_LINK_UP,
|
||||
VIRTIO_NET_F_CTRL_VLAN, VIRTIO_NET_F_CTRL_VQ, VIRTIO_NET_F_GUEST_ANNOUNCE, VIRTIO_NET_F_MQ,
|
||||
VIRTIO_NET_F_MTU, VIRTIO_NET_OK,
|
||||
};
|
||||
use virtio_queue::{DescriptorChain, QueueT};
|
||||
use vm_memory::GuestMemoryRegion;
|
||||
use vmm_sys_util::epoll::EventSet;
|
||||
|
||||
use super::connection::{Endpoint, Listener};
|
||||
use crate::net::{setup_config_space, DEFAULT_MTU};
|
||||
use crate::vhost::net::{virtio_handle_ctrl_mq, virtio_handle_ctrl_status, FromNetCtrl};
|
||||
use crate::vhost::vhost_user::connection::EndpointParam;
|
||||
use crate::{
|
||||
@@ -65,58 +66,34 @@ impl VhostUserNetDevice {
|
||||
queue_sizes: Arc<Vec<u16>>,
|
||||
epoll_mgr: EpollManager,
|
||||
) -> VirtioResult<Self> {
|
||||
// hard-coding MTU
|
||||
info!(
|
||||
"{}: slave support features 0x{:x}",
|
||||
NET_DRIVER_NAME, avail_features
|
||||
);
|
||||
|
||||
avail_features |= (1 << VIRTIO_NET_F_MTU) as u64;
|
||||
// All these features depends on availability of control
|
||||
// channel (VIRTIO_NET_F_CTRL_VQ).
|
||||
// All these features depends on availability of control channel
|
||||
// (VIRTIO_NET_F_CTRL_VQ).
|
||||
avail_features &= !(1 << VIRTIO_NET_F_CTRL_VQ
|
||||
| 1 << VIRTIO_NET_F_CTRL_RX
|
||||
| 1 << VIRTIO_NET_F_CTRL_VLAN
|
||||
| 1 << VIRTIO_NET_F_GUEST_ANNOUNCE
|
||||
| 1 << VIRTIO_NET_F_MQ
|
||||
| 1 << VIRTIO_NET_F_CTRL_MAC_ADDR) as u64;
|
||||
|
||||
// Multi-queue features
|
||||
if queue_sizes.len() > 2 {
|
||||
avail_features |= (1 << VIRTIO_NET_F_MQ | 1 << VIRTIO_NET_F_CTRL_VQ) as u64;
|
||||
}
|
||||
// Network device configuration layout:
|
||||
// https://docs.oasis-open.org/virtio/virtio/v1.1/csprd01/virtio-v1.1-csprd01.html#x1-2000004
|
||||
// - [u8; 6]: mac address
|
||||
// - u16: status
|
||||
// - u16: max_virtqueue_pairs
|
||||
// - u16: mtu
|
||||
// - u32: speed
|
||||
// - u8: duplex
|
||||
let mut config_space = vec![0u8; 17];
|
||||
if let Some(mac) = guest_mac {
|
||||
// When this feature isn't available, the driver generates a random
|
||||
// MAC address. Otherwise, it should attempt to read the device MAC
|
||||
// address from the config space.
|
||||
avail_features |= 1u64 << VIRTIO_NET_F_MAC;
|
||||
config_space[0..6].copy_from_slice(mac.get_bytes());
|
||||
} else {
|
||||
avail_features &= !(1 << VIRTIO_NET_F_MAC) as u64;
|
||||
}
|
||||
// status: mark link as up
|
||||
config_space[6] = VIRTIO_NET_S_LINK_UP as u8;
|
||||
config_space[7] = 0;
|
||||
// max_virtqueue_pairs: only support one rx/tx pair
|
||||
config_space[8] = (queue_sizes.len() / 2) as u8;
|
||||
config_space[9] = 0;
|
||||
// mtu: 1500 = 1536 - vxlan header?
|
||||
config_space[10] = 220;
|
||||
config_space[11] = 5;
|
||||
// speed: 1000Mb
|
||||
config_space[12] = 232;
|
||||
config_space[13] = 3;
|
||||
config_space[14] = 0;
|
||||
config_space[15] = 0;
|
||||
// duplex: full duplex: 0x01
|
||||
config_space[16] = 1;
|
||||
|
||||
let config_space = setup_config_space(
|
||||
NET_DRIVER_NAME,
|
||||
&guest_mac,
|
||||
&mut avail_features,
|
||||
(queue_sizes.len() / 2) as u16,
|
||||
DEFAULT_MTU,
|
||||
)?;
|
||||
|
||||
Ok(VhostUserNetDevice {
|
||||
id: NET_DRIVER_NAME.to_owned(),
|
||||
device_info: VirtioDeviceInfo::new(
|
||||
|
@@ -69,8 +69,6 @@ pub struct VhostNetDeviceConfigInfo {
|
||||
pub host_dev_name: String,
|
||||
/// Number of virtqueues to use.
|
||||
pub num_queues: usize,
|
||||
/// Number of vq pairs to use.
|
||||
pub vq_pairs: usize,
|
||||
/// Size of each virtqueue.
|
||||
pub queue_size: u16,
|
||||
/// Guest MAC address.
|
||||
@@ -159,7 +157,6 @@ impl VhostNetDeviceMgr {
|
||||
let epoll_mgr = ctx.epoll_mgr.clone().ok_or(VirtioError::InvalidInput)?;
|
||||
Ok(Box::new(Net::new(
|
||||
cfg.host_dev_name.clone(),
|
||||
cfg.vq_pairs,
|
||||
cfg.guest_mac(),
|
||||
Arc::new(cfg.queue_sizes()),
|
||||
epoll_mgr,
|
||||
@@ -302,7 +299,6 @@ mod tests {
|
||||
iface_id: id_1,
|
||||
host_dev_name: host_dev_name_1,
|
||||
num_queues: 2,
|
||||
vq_pairs: 0,
|
||||
queue_size: 128,
|
||||
guest_mac: Some(MacAddr::parse_str(guest_mac_1).unwrap()),
|
||||
allow_duplicate_mac: false,
|
||||
@@ -345,7 +341,6 @@ mod tests {
|
||||
iface_id: id_1,
|
||||
host_dev_name: host_dev_name_1,
|
||||
num_queues: 2,
|
||||
vq_pairs: 0,
|
||||
queue_size: 128,
|
||||
guest_mac: Some(MacAddr::parse_str(guest_mac_1).unwrap()),
|
||||
allow_duplicate_mac: false,
|
||||
@@ -390,7 +385,6 @@ mod tests {
|
||||
iface_id: id_1,
|
||||
host_dev_name: host_dev_name_1,
|
||||
num_queues: 2,
|
||||
vq_pairs: 0,
|
||||
queue_size: 128,
|
||||
guest_mac: Some(MacAddr::parse_str(guest_mac_1).unwrap()),
|
||||
allow_duplicate_mac: false,
|
||||
@@ -464,7 +458,6 @@ mod tests {
|
||||
iface_id: String::from("id_1"),
|
||||
host_dev_name: String::from("dev_1"),
|
||||
num_queues: 1,
|
||||
vq_pairs: 0,
|
||||
queue_size: 128,
|
||||
guest_mac: Some(MacAddr::parse_str(guest_mac_1).unwrap()),
|
||||
allow_duplicate_mac: false,
|
||||
@@ -539,7 +532,6 @@ mod tests {
|
||||
iface_id: String::from("id_2"),
|
||||
host_dev_name: String::from("dev_2"),
|
||||
num_queues: 2,
|
||||
vq_pairs: 0,
|
||||
queue_size: 128,
|
||||
guest_mac: Some(MacAddr::parse_str(guest_mac_2).unwrap()),
|
||||
allow_duplicate_mac: false,
|
||||
@@ -601,7 +593,6 @@ mod tests {
|
||||
iface_id: String::from("id_3"),
|
||||
host_dev_name: String::from("dev_3"),
|
||||
num_queues: 2,
|
||||
vq_pairs: 0,
|
||||
queue_size: 128,
|
||||
guest_mac: Some(MacAddr::parse_str(guest_mac_1).unwrap()),
|
||||
allow_duplicate_mac: true,
|
||||
|
Reference in New Issue
Block a user