mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-08-21 23:41:15 +00:00
virtio-devices: net: Cleanup the MQ handling in the control queue
Cleanup the control queue handling in preparation for supporting alternative commands. Note that this change does not make the MQ handling spec compliant. According to the specification MQ should only be enabled once the number of queue pairs the guest would like to use has been specified. The only improvement towards the specication in this change is correct error handling if the guest specifies an inappropriate number of queues (out of range.) Signed-off-by: Rob Bradford <robert.bradford@intel.com>
This commit is contained in:
parent
72d67fe96d
commit
4806357f52
@ -513,7 +513,6 @@ impl VirtioDevice for Net {
|
|||||||
kill_evt,
|
kill_evt,
|
||||||
pause_evt,
|
pause_evt,
|
||||||
ctrl_q: CtrlVirtio::new(cvq_queue, cvq_queue_evt),
|
ctrl_q: CtrlVirtio::new(cvq_queue, cvq_queue_evt),
|
||||||
epoll_fd: 0,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let paused = self.common.paused.clone();
|
let paused = self.common.paused.clone();
|
||||||
|
@ -2,13 +2,10 @@
|
|||||||
//
|
//
|
||||||
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
||||||
|
|
||||||
use super::{
|
use super::{EpollHelper, EpollHelperError, EpollHelperHandler, Queue, EPOLL_HELPER_EVENT_LAST};
|
||||||
DescriptorChain, EpollHelper, EpollHelperError, EpollHelperHandler, Queue,
|
|
||||||
EPOLL_HELPER_EVENT_LAST,
|
|
||||||
};
|
|
||||||
use net_util::MacAddr;
|
use net_util::MacAddr;
|
||||||
use std::os::raw::c_uint;
|
use std::os::raw::c_uint;
|
||||||
use std::os::unix::io::{AsRawFd, RawFd};
|
use std::os::unix::io::AsRawFd;
|
||||||
use std::sync::atomic::AtomicBool;
|
use std::sync::atomic::AtomicBool;
|
||||||
use std::sync::{Arc, Barrier};
|
use std::sync::{Arc, Barrier};
|
||||||
use virtio_bindings::bindings::virtio_net::*;
|
use virtio_bindings::bindings::virtio_net::*;
|
||||||
@ -40,22 +37,16 @@ unsafe impl ByteValued for VirtioNetConfig {}
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// Read process MQ.
|
|
||||||
FailedProcessMq,
|
|
||||||
/// Read queue failed.
|
/// Read queue failed.
|
||||||
GuestMemory(GuestMemoryError),
|
GuestMemory(GuestMemoryError),
|
||||||
/// Invalid ctrl class
|
/// Invalid ctrl class
|
||||||
InvalidCtlClass,
|
InvalidCtlClass,
|
||||||
/// Invalid ctrl command
|
/// Invalid ctrl command
|
||||||
InvalidCtlCmd,
|
InvalidCtlCmd,
|
||||||
/// Invalid descriptor
|
/// No queue pairs number.
|
||||||
InvalidDesc,
|
NoQueuePairsDescriptor,
|
||||||
/// Invalid queue pairs number
|
/// No status descriptor
|
||||||
InvalidQueuePairsNum,
|
NoStatusDescriptor,
|
||||||
/// No memory passed in.
|
|
||||||
NoMemory,
|
|
||||||
/// No ueue pairs number.
|
|
||||||
NoQueuePairsNum,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CtrlVirtio {
|
pub struct CtrlVirtio {
|
||||||
@ -72,61 +63,60 @@ impl std::clone::Clone for CtrlVirtio {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[repr(C, packed)]
|
||||||
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
|
pub struct ControlHeader {
|
||||||
|
pub class: u8,
|
||||||
|
pub cmd: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl ByteValued for ControlHeader {}
|
||||||
|
|
||||||
impl CtrlVirtio {
|
impl CtrlVirtio {
|
||||||
pub fn new(queue: Queue, queue_evt: EventFd) -> Self {
|
pub fn new(queue: Queue, queue_evt: EventFd) -> Self {
|
||||||
CtrlVirtio { queue_evt, queue }
|
CtrlVirtio { queue_evt, queue }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_mq(&self, mem: &GuestMemoryMmap, avail_desc: DescriptorChain) -> Result<()> {
|
|
||||||
let mq_desc = if avail_desc.has_next() {
|
|
||||||
avail_desc.next_descriptor().unwrap()
|
|
||||||
} else {
|
|
||||||
return Err(Error::NoQueuePairsNum);
|
|
||||||
};
|
|
||||||
let queue_pairs = mem
|
|
||||||
.read_obj::<u16>(mq_desc.addr)
|
|
||||||
.map_err(Error::GuestMemory)?;
|
|
||||||
if (queue_pairs < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN as u16)
|
|
||||||
|| (queue_pairs > VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX as u16)
|
|
||||||
{
|
|
||||||
return Err(Error::InvalidQueuePairsNum);
|
|
||||||
}
|
|
||||||
let status_desc = if mq_desc.has_next() {
|
|
||||||
mq_desc.next_descriptor().unwrap()
|
|
||||||
} else {
|
|
||||||
return Err(Error::NoQueuePairsNum);
|
|
||||||
};
|
|
||||||
mem.write_obj::<u8>(0, status_desc.addr)
|
|
||||||
.map_err(Error::GuestMemory)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn process_cvq(&mut self, mem: &GuestMemoryMmap) -> Result<()> {
|
pub fn process_cvq(&mut self, mem: &GuestMemoryMmap) -> Result<()> {
|
||||||
let mut used_desc_heads = [(0, 0); QUEUE_SIZE];
|
let mut used_desc_heads = [(0, 0); QUEUE_SIZE];
|
||||||
let mut used_count = 0;
|
let mut used_count = 0;
|
||||||
if let Some(avail_desc) = self.queue.iter(&mem).next() {
|
let queue = &mut self.queue;
|
||||||
used_desc_heads[used_count] = (avail_desc.index, avail_desc.len);
|
for avail_desc in queue.iter(&mem) {
|
||||||
used_count += 1;
|
let ctrl_hdr: ControlHeader =
|
||||||
let ctrl_hdr = mem
|
mem.read_obj(avail_desc.addr).map_err(Error::GuestMemory)?;
|
||||||
.read_obj::<u16>(avail_desc.addr)
|
match u32::from(ctrl_hdr.class) {
|
||||||
.map_err(Error::GuestMemory)?;
|
|
||||||
let ctrl_hdr_v = ctrl_hdr.as_slice();
|
|
||||||
let class = ctrl_hdr_v[0];
|
|
||||||
let cmd = ctrl_hdr_v[1];
|
|
||||||
match u32::from(class) {
|
|
||||||
VIRTIO_NET_CTRL_MQ => {
|
VIRTIO_NET_CTRL_MQ => {
|
||||||
if u32::from(cmd) != VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET {
|
let mq_desc = avail_desc
|
||||||
return Err(Error::InvalidCtlCmd);
|
.next_descriptor()
|
||||||
}
|
.ok_or(Error::NoQueuePairsDescriptor)?;
|
||||||
if let Err(_e) = self.process_mq(&mem, avail_desc) {
|
let queue_pairs = mem
|
||||||
return Err(Error::FailedProcessMq);
|
.read_obj::<u16>(mq_desc.addr)
|
||||||
}
|
.map_err(Error::GuestMemory)?;
|
||||||
|
let status_desc = mq_desc.next_descriptor().ok_or(Error::NoStatusDescriptor)?;
|
||||||
|
|
||||||
|
let ok = if u32::from(ctrl_hdr.cmd) != VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET {
|
||||||
|
warn!("Unsupported command: {}", ctrl_hdr.cmd);
|
||||||
|
false
|
||||||
|
} else if (queue_pairs < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN as u16)
|
||||||
|
|| (queue_pairs > VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX as u16)
|
||||||
|
{
|
||||||
|
warn!("Number of MQ pairs out of range: {}", queue_pairs);
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
info!("Number of MQ pairs requested: {}", queue_pairs);
|
||||||
|
true
|
||||||
|
};
|
||||||
|
|
||||||
|
mem.write_obj(
|
||||||
|
if ok { VIRTIO_NET_OK } else { VIRTIO_NET_ERR } as u8,
|
||||||
|
status_desc.addr,
|
||||||
|
)
|
||||||
|
.map_err(Error::GuestMemory)?;
|
||||||
}
|
}
|
||||||
_ => return Err(Error::InvalidCtlClass),
|
_ => return Err(Error::InvalidCtlClass),
|
||||||
}
|
}
|
||||||
} else {
|
used_desc_heads[used_count] = (avail_desc.index, avail_desc.len);
|
||||||
return Err(Error::InvalidDesc);
|
used_count += 1;
|
||||||
}
|
}
|
||||||
for &(desc_index, len) in &used_desc_heads[..used_count] {
|
for &(desc_index, len) in &used_desc_heads[..used_count] {
|
||||||
self.queue.add_used(&mem, desc_index, len);
|
self.queue.add_used(&mem, desc_index, len);
|
||||||
@ -142,7 +132,6 @@ pub struct NetCtrlEpollHandler {
|
|||||||
pub kill_evt: EventFd,
|
pub kill_evt: EventFd,
|
||||||
pub pause_evt: EventFd,
|
pub pause_evt: EventFd,
|
||||||
pub ctrl_q: CtrlVirtio,
|
pub ctrl_q: CtrlVirtio,
|
||||||
pub epoll_fd: RawFd,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NetCtrlEpollHandler {
|
impl NetCtrlEpollHandler {
|
||||||
|
@ -378,12 +378,13 @@ fn virtio_vhost_net_ctl_thread_rules() -> Vec<SyscallRuleSet> {
|
|||||||
allow_syscall(libc::SYS_epoll_pwait),
|
allow_syscall(libc::SYS_epoll_pwait),
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
allow_syscall(libc::SYS_epoll_wait),
|
allow_syscall(libc::SYS_epoll_wait),
|
||||||
|
allow_syscall(libc::SYS_exit),
|
||||||
allow_syscall(libc::SYS_futex),
|
allow_syscall(libc::SYS_futex),
|
||||||
allow_syscall(libc::SYS_read),
|
|
||||||
allow_syscall(libc::SYS_sigaltstack),
|
|
||||||
allow_syscall(libc::SYS_munmap),
|
allow_syscall(libc::SYS_munmap),
|
||||||
allow_syscall(libc::SYS_madvise),
|
allow_syscall(libc::SYS_madvise),
|
||||||
allow_syscall(libc::SYS_exit),
|
allow_syscall(libc::SYS_read),
|
||||||
|
allow_syscall(libc::SYS_sigaltstack),
|
||||||
|
allow_syscall(libc::SYS_write),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,7 +248,6 @@ impl VirtioDevice for Net {
|
|||||||
kill_evt,
|
kill_evt,
|
||||||
pause_evt,
|
pause_evt,
|
||||||
ctrl_q: CtrlVirtio::new(cvq_queue, cvq_queue_evt),
|
ctrl_q: CtrlVirtio::new(cvq_queue, cvq_queue_evt),
|
||||||
epoll_fd: 0,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let paused = self.common.paused.clone();
|
let paused = self.common.paused.clone();
|
||||||
|
Loading…
Reference in New Issue
Block a user