Skip to content

Commit b42da4a

Browse files
committed
Splitted Network Interface trait and fixed mutex related network performance issue
1 parent 4b86804 commit b42da4a

3 files changed

Lines changed: 62 additions & 36 deletions

File tree

src/net/mod.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,31 @@ pub const UHYVE_PCI_CLASS_INFO: [u8; 3] = [
1616

1717
pub(crate) mod tap;
1818

19-
// TODO: Remove Sync and split in two
20-
pub(crate) trait NetworkInterface: Sync + Send {
19+
pub(crate) trait NetworkInterface {
20+
type RX: NetworkInterfaceRX;
21+
type TX: NetworkInterfaceTX;
22+
2123
/// Return the MAC address as a byte array
2224
fn mac_address_as_bytes(&self) -> [u8; 6];
2325

26+
/// Split off a tx and rx object.
27+
fn split(self) -> (Self::RX, Self::TX);
28+
}
29+
30+
pub(crate) trait NetworkInterfaceTX: Send {
2431
/// Sends a packet to the interface.
2532
///
2633
/// **NOTE**: ensure the packet has the appropriate format and header.
2734
/// Incorrect packets will be dropped without warning.
28-
fn send(&self, buf: &[u8]) -> io::Result<usize>;
35+
fn send(&mut self, buf: &[u8]) -> io::Result<usize>;
36+
}
2937

38+
pub(crate) trait NetworkInterfaceRX: Send {
3039
/// Receives a packet from the interface.
3140
///
3241
/// Blocks until a packet is sent into the virtual interface. At that point, the content of the
3342
/// packet is copied into the provided buffer.
3443
///
3544
/// Returns the size of the received packet
36-
fn recv(&self, buf: &mut [u8]) -> io::Result<usize>;
45+
fn recv(&mut self, buf: &mut [u8]) -> io::Result<usize>;
3746
}

src/net/tap.rs

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,12 @@ use std::{
22
fs::{File, OpenOptions},
33
io::{self, Error, Read, Write},
44
os::unix::io::AsRawFd,
5-
sync::Mutex,
65
};
76

87
use libc::{IFF_NO_PI, IFF_TAP, ifreq};
98
use nix::{ifaddrs::getifaddrs, ioctl_write_int};
109

11-
use crate::net::NetworkInterface;
10+
use crate::net::{NetworkInterface, NetworkInterfaceRX, NetworkInterfaceTX};
1211

1312
/// An existing (externally created) TAP device
1413
pub struct Tap {
@@ -73,21 +72,47 @@ impl Tap {
7372
})
7473
}
7574
}
76-
impl NetworkInterface for Mutex<Tap> {
75+
impl NetworkInterface for Tap {
76+
type RX = TapRX;
77+
type TX = TapTX;
78+
7779
fn mac_address_as_bytes(&self) -> [u8; 6] {
78-
self.lock().unwrap().mac
80+
self.mac
7981
}
8082

81-
fn send(&self, buf: &[u8]) -> io::Result<usize> {
82-
let mut guard = self.lock().unwrap();
83-
trace!("sending {} bytes on {}", buf.len(), guard.name);
84-
guard.fd.write(buf)
83+
fn split(self) -> (Self::RX, Self::TX) {
84+
(
85+
Self::RX {
86+
fd: self.fd.try_clone().unwrap(),
87+
name: self.name.clone(),
88+
},
89+
Self::TX {
90+
fd: self.fd.try_clone().unwrap(),
91+
name: self.name.clone(),
92+
},
93+
)
8594
}
95+
}
8696

87-
fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
88-
let mut guard = self.lock().unwrap();
89-
let res = guard.fd.read(buf);
90-
trace!("receiving {res:?} bytes on {}", guard.name);
97+
pub struct TapTX {
98+
fd: File,
99+
name: String,
100+
}
101+
impl NetworkInterfaceTX for TapTX {
102+
fn send(&mut self, buf: &[u8]) -> io::Result<usize> {
103+
trace!("sending {} bytes on {}", buf.len(), self.name);
104+
self.fd.write(buf)
105+
}
106+
}
107+
108+
pub struct TapRX {
109+
fd: File,
110+
name: String,
111+
}
112+
impl NetworkInterfaceRX for TapRX {
113+
fn recv(&mut self, buf: &mut [u8]) -> io::Result<usize> {
114+
let res = self.fd.read(buf);
115+
trace!("receiving {res:?} bytes on {}", self.name);
91116
res
92117
}
93118
}

src/virtio/net.rs

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::{
55
io::{Read, Write},
66
mem,
77
sync::{
8-
self, Arc,
8+
Arc,
99
atomic::{AtomicBool, Ordering},
1010
},
1111
thread, time,
@@ -23,7 +23,7 @@ use vmm_sys_util::eventfd::EventFd;
2323

2424
use crate::{
2525
consts::{UHYVE_IRQ_NET, UHYVE_NET_MTU},
26-
net::{NetworkInterface, UHYVE_QUEUE_SIZE, tap::Tap},
26+
net::{NetworkInterface, NetworkInterfaceRX, NetworkInterfaceTX, UHYVE_QUEUE_SIZE, tap::Tap},
2727
pci::{MemoryBar64, PciDevice},
2828
virtio::{
2929
DeviceStatus, IOBASE, NET_DEVICE_ID,
@@ -65,8 +65,6 @@ pub struct VirtioNetPciDevice {
6565
rx_queue: Arc<Mutex<Queue>>,
6666
/// transmitted virtqueue
6767
tx_queue: Arc<Mutex<Queue>>,
68-
/// virtual network interface
69-
iface: Option<Arc<dyn NetworkInterface>>,
7068
/// File Descriptor for IRQ event signalling to guest
7169
irq_evtfd: Option<EventFd>,
7270
/// File Descriptor for polling guest (MMIO) IOEventFD signals
@@ -112,7 +110,6 @@ impl VirtioNetPciDevice {
112110
isr_changed: Arc::new(AtomicBool::new(false)),
113111
rx_queue,
114112
tx_queue,
115-
iface: None,
116113
irq_evtfd: None,
117114
notify_evtfd_rx: None,
118115
notify_evtfd_tx: None,
@@ -248,12 +245,6 @@ impl VirtioNetPciDevice {
248245
self.header_caps.pci_config_hdr.status.bits() as u8
249246
}
250247

251-
/// Gets the mac address from the TAP device.
252-
/// This function is reliant on tap devices as the underlying packet sending mechanism
253-
fn get_mac_addr(&mut self) {
254-
self.header_caps.dev.mac = self.iface.as_ref().unwrap().mac_address_as_bytes();
255-
}
256-
257248
/// Write the MAC address to the input slice.
258249
pub fn read_mac_address(&self, data: &mut [u8]) {
259250
for (d, m) in data.iter_mut().zip(self.header_caps.dev.mac.iter()).take(6) {
@@ -273,10 +264,13 @@ impl VirtioNetPciDevice {
273264

274265
fn start_network_interface(&mut self) {
275266
// Create a TAP device without packet info headers.
276-
let iface = self.iface.insert(Arc::new(sync::Mutex::new(
277-
Tap::new().expect("Could not create TAP device"),
278-
)));
279-
let sink = iface.clone();
267+
// TODO: Create network dynamically
268+
let iface = Tap::new().expect("Could not create TAP device");
269+
270+
// store the interfaces MAC address
271+
self.header_caps.dev.mac = iface.mac_address_as_bytes();
272+
273+
let (mut rx, mut tx) = iface.split();
280274

281275
let notify_evtfd_tx = self.notify_evtfd_tx.take().unwrap();
282276

@@ -289,7 +283,7 @@ impl VirtioNetPciDevice {
289283
debug!("Starting notification watcher.");
290284
loop {
291285
if notify_evtfd_tx.read().is_ok() {
292-
match send_available_packets(&(*sink), &poll_tx_queue, &mmap) {
286+
match send_available_packets(&mut tx, &poll_tx_queue, &mmap) {
293287
Ok(_) => {}
294288
Err(VirtIOError::QueueNotReady) => {
295289
error!("Sending before queue is ready!")
@@ -303,7 +297,6 @@ impl VirtioNetPciDevice {
303297
});
304298

305299
let poll_rx_queue = self.rx_queue.clone();
306-
let stream = self.iface.as_mut().unwrap().clone();
307300
let alert = Arc::clone(&self.isr_changed);
308301
let mut frame_queue: VecDeque<([u8; 1500], usize)> =
309302
VecDeque::with_capacity(QUEUE_LIMIT / 2);
@@ -317,7 +310,7 @@ impl VirtioNetPciDevice {
317310
let mut _delay = time::Instant::now();
318311

319312
let mut buf = [0u8; UHYVE_NET_MTU];
320-
let len = stream.recv(&mut buf).unwrap();
313+
let len = rx.recv(&mut buf).unwrap();
321314
let mmap = mmap.as_ref().clone();
322315
frame_queue.push_back((buf, len));
323316

@@ -340,7 +333,6 @@ impl VirtioNetPciDevice {
340333
});
341334

342335
// "should've would've panicked by now, if no mac existed!" BAD!
343-
self.get_mac_addr();
344336
self.header_caps.dev.status = NetDevStatus::VIRTIO_NET_S_LINK_UP;
345337
self.update_config_generation();
346338
}
@@ -612,7 +604,7 @@ fn write_packet(
612604

613605
/// Sends the packets received from the guest to the network interface
614606
fn send_available_packets(
615-
sink: &dyn NetworkInterface,
607+
sink: &mut dyn NetworkInterfaceTX,
616608
tx_queue_locked: &Arc<Mutex<Queue>>,
617609
mem: &GuestMemoryMmap,
618610
) -> std::result::Result<bool, VirtIOError> {

0 commit comments

Comments
 (0)