@@ -14,7 +14,7 @@ use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
1414use utils:: ioctl:: { ioctl_with_mut_ref, ioctl_with_ref, ioctl_with_val} ;
1515use utils:: { ioctl_ioc_nr, ioctl_iow_nr} ;
1616
17- use crate :: devices:: virtio:: iovec:: IoVecBuffer ;
17+ use crate :: devices:: virtio:: iovec:: { IoVecBuffer , IoVecBufferMut } ;
1818use crate :: devices:: virtio:: net:: gen;
1919#[ cfg( test) ]
2020use 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