vm-virtio: Implement reset() for vhost-user-net

The virtio specification defines a device can be reset, which was not
supported by this vhost-user-net implementation. The reason it is needed
is to support unbinding this device from the guest driver, and rebind it
to vfio-pci driver.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
Sebastien Boeuf 2019-10-04 09:56:35 -07:00 committed by Samuel Ortiz
parent 8225d4cd6e
commit 4b1328a29c

View File

@ -30,12 +30,14 @@ impl VhostUserMasterReqHandler for SlaveReqHandler {}
pub struct Net {
vhost_user_net: Master,
kill_evt: EventFd,
kill_evt: Option<EventFd>,
avail_features: u64,
acked_features: u64,
backend_features: u64,
config_space: Vec<u8>,
queue_sizes: Vec<u16>,
queue_evts: Option<Vec<EventFd>>,
interrupt_cb: Option<Arc<VirtioInterrupt>>,
}
impl Net {
@ -44,8 +46,6 @@ impl Net {
let mut vhost_user_net = Master::connect(&vu_cfg.sock, vu_cfg.num_queues as u64)
.map_err(Error::VhostUserCreateMaster)?;
let kill_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::CreateKillEventFd)?;
// Filling device and vring features VMM supports.
let mut avail_features = 1 << virtio_net::VIRTIO_NET_F_GUEST_CSUM
| 1 << virtio_net::VIRTIO_NET_F_CSUM
@ -108,20 +108,24 @@ impl Net {
Ok(Net {
vhost_user_net,
kill_evt,
kill_evt: None,
avail_features,
acked_features,
backend_features,
config_space,
queue_sizes: vec![vu_cfg.queue_size; vu_cfg.num_queues],
queue_evts: None,
interrupt_cb: None,
})
}
}
impl Drop for Net {
fn drop(&mut self) {
if let Err(_e) = self.kill_evt.write(1) {
error!("failed to kill vhost-user-net with error {}", _e);
if let Some(kill_evt) = self.kill_evt.take() {
if let Err(e) = kill_evt.write(1) {
error!("failed to kill vhost-user-net: {:?}", e);
}
}
}
}
@ -197,10 +201,30 @@ impl VirtioDevice for Net {
queues: Vec<Queue>,
queue_evts: Vec<EventFd>,
) -> ActivateResult {
let handler_kill_evt = self
.kill_evt
.try_clone()
.map_err(|_| ActivateError::CloneKillEventFd)?;
let (self_kill_evt, kill_evt) =
match EventFd::new(EFD_NONBLOCK).and_then(|e| Ok((e.try_clone()?, e))) {
Ok(v) => v,
Err(e) => {
error!("failed creating kill EventFd pair: {}", e);
return Err(ActivateError::BadActivate);
}
};
self.kill_evt = Some(self_kill_evt);
// Save the interrupt EventFD as we need to return it on reset
// but clone it to pass into the thread.
self.interrupt_cb = Some(interrupt_cb.clone());
let mut tmp_queue_evts: Vec<EventFd> = Vec::new();
for queue_evt in queue_evts.iter() {
// Save the queue EventFD as we need to return it on reset
// but clone it to pass into the thread.
tmp_queue_evts.push(queue_evt.try_clone().map_err(|e| {
error!("failed to clone queue EventFd: {}", e);
ActivateError::BadActivate
})?);
}
self.queue_evts = Some(tmp_queue_evts);
let vu_interrupt_list = setup_vhost_user(
&mut self.vhost_user_net,
@ -213,7 +237,7 @@ impl VirtioDevice for Net {
let mut handler = VhostUserEpollHandler::<SlaveReqHandler>::new(VhostUserEpollConfig {
interrupt_cb,
kill_evt: handler_kill_evt,
kill_evt,
vu_interrupt_list,
slave_req_handler: None,
});
@ -230,4 +254,22 @@ impl VirtioDevice for Net {
}
Ok(())
}
fn reset(&mut self) -> Option<(Arc<VirtioInterrupt>, Vec<EventFd>)> {
if let Err(e) = reset_vhost_user(&mut self.vhost_user_net, self.queue_sizes.len()) {
error!("Failed to reset vhost-user daemon: {:?}", e);
return None;
}
if let Some(kill_evt) = self.kill_evt.take() {
// Ignore the result because there is nothing we can do about it.
let _ = kill_evt.write(1);
}
// Return the interrupt and queue EventFDs
Some((
self.interrupt_cb.take().unwrap(),
self.queue_evts.take().unwrap(),
))
}
}