diff --git a/vhost_user_net/src/lib.rs b/vhost_user_net/src/lib.rs index 2cc43a065..79656fb37 100644 --- a/vhost_user_net/src/lib.rs +++ b/vhost_user_net/src/lib.rs @@ -30,7 +30,7 @@ use virtio_bindings::bindings::virtio_net::*; use virtio_bindings::bindings::virtio_ring::VIRTIO_RING_F_EVENT_IDX; use vm_memory::{GuestMemoryAtomic, GuestMemoryMmap}; use vm_virtio::net_util::{open_tap, RxVirtio, TxVirtio}; -use vm_virtio::NetQueuePair; +use vm_virtio::{NetCounters, NetQueuePair}; use vmm::config::{OptionParser, OptionParserError}; use vmm_sys_util::eventfd::EventFd; @@ -111,6 +111,7 @@ impl VhostUserNetThread { tx: TxVirtio::new(), rx_tap_listening: false, epoll_fd: None, + counters: NetCounters::default(), }, }) } diff --git a/vm-virtio/src/net.rs b/vm-virtio/src/net.rs index 4277ec9a6..5db3f173c 100644 --- a/vm-virtio/src/net.rs +++ b/vm-virtio/src/net.rs @@ -24,9 +24,10 @@ use std::fs::File; use std::io::Read; use std::io::{self, Write}; use std::net::Ipv4Addr; +use std::num::Wrapping; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::result; -use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; use std::sync::Arc; use std::thread; use std::vec::Vec; @@ -54,6 +55,7 @@ pub struct NetQueuePair { pub tx: TxVirtio, pub epoll_fd: Option, pub rx_tap_listening: bool, + pub counters: NetCounters, } impl NetQueuePair { @@ -112,6 +114,19 @@ impl NetQueuePair { } } } + + // Consume the counters from the Rx/Tx queues and accumulate into + // the counters for the device as whole. This consumption is needed + // to handle MQ. + self.counters + .rx_bytes + .fetch_add(self.rx.counter_bytes.0, Ordering::AcqRel); + self.counters + .rx_frames + .fetch_add(self.rx.counter_frames.0, Ordering::AcqRel); + self.rx.counter_bytes = Wrapping(0); + self.rx.counter_frames = Wrapping(0); + if self.rx.deferred_irqs { self.rx.deferred_irqs = false; let mem = self @@ -166,6 +181,16 @@ impl NetQueuePair { .ok_or(DeviceError::NoMemoryConfigured) .map(|m| m.memory())?; self.tx.process_desc_chain(&mem, &mut self.tap, &mut queue); + + self.counters + .tx_bytes + .fetch_add(self.tx.counter_bytes.0, Ordering::AcqRel); + self.counters + .tx_frames + .fetch_add(self.tx.counter_frames.0, Ordering::AcqRel); + self.tx.counter_bytes = Wrapping(0); + self.tx.counter_frames = Wrapping(0); + Ok(queue.needs_notification(&mem, queue.next_used)) } @@ -390,6 +415,14 @@ impl NetEpollHandler { } } +#[derive(Default, Clone)] +pub struct NetCounters { + tx_bytes: Arc, + tx_frames: Arc, + rx_bytes: Arc, + rx_frames: Arc, +} + pub struct Net { id: String, kill_evt: Option, @@ -404,6 +437,7 @@ pub struct Net { ctrl_queue_epoll_thread: Option>>, paused: Arc, queue_size: Vec, + counters: NetCounters, } #[derive(Serialize, Deserialize)] @@ -461,6 +495,7 @@ impl Net { ctrl_queue_epoll_thread: None, paused: Arc::new(AtomicBool::new(false)), queue_size: vec![queue_size; queue_num], + counters: NetCounters::default(), }) } @@ -661,6 +696,7 @@ impl VirtioDevice for Net { tx, epoll_fd: None, rx_tap_listening, + counters: self.counters.clone(), }, interrupt_cb: interrupt_cb.clone(), kill_evt: kill_evt.try_clone().unwrap(), diff --git a/vm-virtio/src/net_util.rs b/vm-virtio/src/net_util.rs index 61e1d51c6..4bfd2287e 100644 --- a/vm-virtio/src/net_util.rs +++ b/vm-virtio/src/net_util.rs @@ -12,6 +12,7 @@ use std::fs::File; use std::io::{self, Write}; use std::mem; use std::net::Ipv4Addr; +use std::num::Wrapping; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::path::Path; use std::sync::atomic::{AtomicBool, Ordering}; @@ -340,6 +341,8 @@ impl NetCtrlEpollHandler { pub struct TxVirtio { pub iovec: Vec<(GuestAddress, usize)>, pub frame_buf: [u8; MAX_BUFFER_SIZE], + pub counter_bytes: Wrapping, + pub counter_frames: Wrapping, } impl Default for TxVirtio { @@ -353,6 +356,8 @@ impl TxVirtio { TxVirtio { iovec: Vec::new(), frame_buf: [0u8; MAX_BUFFER_SIZE], + counter_bytes: Wrapping(0), + counter_frames: Wrapping(0), } } @@ -400,6 +405,10 @@ impl TxVirtio { println!("net: tx: error failed to write to tap: {}", e); } }; + + self.counter_bytes += Wrapping((read_count - vnet_hdr_len()) as u64); + self.counter_frames += Wrapping(1); + queue.add_used(&mem, head_index, 0); queue.update_avail_event(&mem); } @@ -412,6 +421,8 @@ pub struct RxVirtio { pub deferred_irqs: bool, pub bytes_read: usize, pub frame_buf: [u8; MAX_BUFFER_SIZE], + pub counter_bytes: Wrapping, + pub counter_frames: Wrapping, } impl Default for RxVirtio { @@ -427,6 +438,8 @@ impl RxVirtio { deferred_irqs: false, bytes_read: 0, frame_buf: [0u8; MAX_BUFFER_SIZE], + counter_bytes: Wrapping(0), + counter_frames: Wrapping(0), } } @@ -472,6 +485,9 @@ impl RxVirtio { } } + self.counter_bytes += Wrapping((write_count - vnet_hdr_len()) as u64); + self.counter_frames += Wrapping(1); + queue.add_used(&mem, head_index, write_count as u32); queue.update_avail_event(&mem);