diff --git a/vm-virtio/src/vhost_user/net.rs b/vm-virtio/src/vhost_user/net.rs index 9fc77ba3d..85ddca4ba 100644 --- a/vm-virtio/src/vhost_user/net.rs +++ b/vm-virtio/src/vhost_user/net.rs @@ -30,12 +30,14 @@ impl VhostUserMasterReqHandler for SlaveReqHandler {} pub struct Net { vhost_user_net: Master, - kill_evt: EventFd, + kill_evt: Option, avail_features: u64, acked_features: u64, backend_features: u64, config_space: Vec, queue_sizes: Vec, + queue_evts: Option>, + interrupt_cb: Option>, } 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_evts: Vec, ) -> 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 = 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::::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, Vec)> { + 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(), + )) + } }