Skip to content

Commit 3ae6a25

Browse files
committed
feat: support read_iovec for tap device
Add read_iovec for Tap. Signed-off-by: ihciah <[email protected]>
1 parent c845d28 commit 3ae6a25

File tree

2 files changed

+57
-3
lines changed

2 files changed

+57
-3
lines changed

src/vmm/src/devices/virtio/iovec.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,24 @@ mod tests {
470470
}
471471
}
472472

473+
impl<'a> From<Vec<&'a mut [u8]>> for IoVecBufferMut {
474+
fn from(buffer: Vec<&'a mut [u8]>) -> Self {
475+
let mut len = 0_u32;
476+
let vecs = buffer
477+
.into_iter()
478+
.map(|slice| {
479+
len += TryInto::<u32>::try_into(slice.len()).unwrap();
480+
iovec {
481+
iov_base: slice.as_ptr() as *mut c_void,
482+
iov_len: slice.len(),
483+
}
484+
})
485+
.collect();
486+
487+
Self { vecs, len }
488+
}
489+
}
490+
473491
fn default_mem() -> GuestMemoryMmap {
474492
multi_region_mem(&[
475493
(GuestAddress(0), 0x10000),

src/vmm/src/devices/virtio/net/tap.rs

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
1414
use utils::ioctl::{ioctl_with_mut_ref, ioctl_with_ref, ioctl_with_val};
1515
use utils::{ioctl_ioc_nr, ioctl_iow_nr};
1616

17-
use crate::devices::virtio::iovec::IoVecBuffer;
17+
use crate::devices::virtio::iovec::{IoVecBuffer, IoVecBufferMut};
1818
use crate::devices::virtio::net::gen;
1919
#[cfg(test)]
2020
use crate::devices::virtio::net::test_utils::Mocks;
@@ -185,8 +185,22 @@ impl Tap {
185185
Ok(())
186186
}
187187

188+
/// Read an `IoVecBufferMut` from tap
189+
pub(crate) fn read_iovec(&self, buffer: &mut IoVecBufferMut) -> Result<usize, IoError> {
190+
let iovcnt = i32::try_from(buffer.iovec_count()).unwrap();
191+
let iov = buffer.as_iovec_ptr();
192+
193+
// SAFETY: `readv` is safe. Called with a valid tap fd, the iovec pointer and length
194+
// is provide by the `IoVecBufferMut` implementation and we check the return value.
195+
let ret = unsafe { libc::readv(self.tap_file.as_raw_fd(), iov, iovcnt) };
196+
if ret == -1 {
197+
return Err(IoError::last_os_error());
198+
}
199+
Ok(usize::try_from(ret).unwrap())
200+
}
201+
188202
/// Write an `IoVecBuffer` to tap
189-
pub(crate) fn write_iovec(&mut self, buffer: &IoVecBuffer) -> Result<usize, IoError> {
203+
pub(crate) fn write_iovec(&self, buffer: &IoVecBuffer) -> Result<usize, IoError> {
190204
let iovcnt = i32::try_from(buffer.iovec_count()).unwrap();
191205
let iov = buffer.as_iovec_ptr();
192206

@@ -323,6 +337,28 @@ pub mod tests {
323337
);
324338
}
325339

340+
#[test]
341+
fn test_read_iovec() {
342+
let tap = Tap::open_named("").unwrap();
343+
enable(&tap);
344+
let tap_traffic_simulator = TapTrafficSimulator::new(if_index(&tap));
345+
346+
let packet = utils::rand::rand_alphanumerics(PAYLOAD_SIZE);
347+
tap_traffic_simulator.push_tx_packet(packet.as_bytes());
348+
349+
let mut fragment1 = [0_u8; VNET_HDR_SIZE];
350+
let mut fragment2 = [0_u8; PAYLOAD_SIZE];
351+
352+
let mut scattered =
353+
IoVecBufferMut::from(vec![fragment1.as_mut_slice(), fragment2.as_mut_slice()]);
354+
355+
assert_eq!(
356+
tap.read_iovec(&mut scattered).unwrap(),
357+
PAYLOAD_SIZE + VNET_HDR_SIZE
358+
);
359+
assert_eq!(fragment2, packet.as_bytes());
360+
}
361+
326362
#[test]
327363
fn test_write() {
328364
let mut tap = Tap::open_named("").unwrap();
@@ -345,7 +381,7 @@ pub mod tests {
345381

346382
#[test]
347383
fn test_write_iovec() {
348-
let mut tap = Tap::open_named("").unwrap();
384+
let tap = Tap::open_named("").unwrap();
349385
enable(&tap);
350386
let tap_traffic_simulator = TapTrafficSimulator::new(if_index(&tap));
351387

0 commit comments

Comments
 (0)