99use std:: io:: Read ;
1010use std:: mem;
1111use std:: net:: Ipv4Addr ;
12+ use std:: num:: Wrapping ;
1213use std:: sync:: atomic:: AtomicU32 ;
1314use std:: sync:: { Arc , Mutex } ;
1415
15- use libc:: EAGAIN ;
16+ use libc:: { iovec , EAGAIN } ;
1617use log:: { error, warn} ;
1718use utils:: eventfd:: EventFd ;
1819use utils:: net:: mac:: MacAddr ;
1920use utils:: u64_to_usize;
20- use vm_memory:: GuestMemoryError ;
21+ use vm_memory:: { GuestMemory , GuestMemoryError } ;
2122
2223use crate :: devices:: virtio:: device:: { DeviceState , IrqTrigger , IrqType , VirtioDevice } ;
2324use crate :: devices:: virtio:: gen:: virtio_blk:: VIRTIO_F_VERSION_1 ;
@@ -33,7 +34,7 @@ use crate::devices::virtio::net::tap::Tap;
3334use crate :: devices:: virtio:: net:: {
3435 gen, NetError , NetQueue , MAX_BUFFER_SIZE , NET_QUEUE_SIZES , RX_INDEX , TX_INDEX ,
3536} ;
36- use crate :: devices:: virtio:: queue:: { DescriptorChain , Queue } ;
37+ use crate :: devices:: virtio:: queue:: { Descriptor , DescriptorChain , Queue } ;
3738use crate :: devices:: virtio:: { ActivateError , TYPE_NET } ;
3839use crate :: devices:: { report_net_event_fail, DeviceError } ;
3940use crate :: dumbo:: pdu:: arp:: ETH_IPV4_FRAME_LEN ;
@@ -128,6 +129,8 @@ pub struct Net {
128129
129130 rx_bytes_read : usize ,
130131 rx_frame_buf : [ u8 ; MAX_BUFFER_SIZE ] ,
132+ rx_iov : Vec < iovec > ,
133+ rx_heads_info : Vec < ( u16 , u32 , usize ) > ,
131134
132135 tx_frame_headers : [ u8 ; frame_hdr_len ( ) ] ,
133136
@@ -145,6 +148,12 @@ pub struct Net {
145148 pub ( crate ) metrics : Arc < NetDeviceMetrics > ,
146149}
147150
151+ // This is needed for rx_iov as it uses iovec struct
152+ // which contains *mut c_void type.
153+ // SAFETY:
154+ // Safe as only vmm thread will access rx_iov field.
155+ unsafe impl Send for Net { }
156+
148157impl Net {
149158 /// Create a new virtio network device with the given TAP interface.
150159 pub fn new_with_tap (
@@ -161,6 +170,7 @@ impl Net {
161170 | 1 << VIRTIO_NET_F_HOST_TSO4
162171 | 1 << VIRTIO_NET_F_HOST_UFO
163172 | 1 << VIRTIO_F_VERSION_1
173+ | 1 << VIRTIO_NET_F_MRG_RXBUF
164174 | 1 << VIRTIO_RING_F_EVENT_IDX ;
165175
166176 let mut config_space = ConfigSpace :: default ( ) ;
@@ -190,6 +200,8 @@ impl Net {
190200 rx_deferred_frame : false ,
191201 rx_bytes_read : 0 ,
192202 rx_frame_buf : [ 0u8 ; MAX_BUFFER_SIZE ] ,
203+ rx_iov : Vec :: new ( ) ,
204+ rx_heads_info : Vec :: new ( ) ,
193205 tx_frame_headers : [ 0u8 ; frame_hdr_len ( ) ] ,
194206 irq_trigger : IrqTrigger :: new ( ) . map_err ( NetError :: EventFd ) ?,
195207 config_space,
@@ -528,7 +540,7 @@ impl Net {
528540 if !self . has_feature ( u64:: from ( VIRTIO_NET_F_MRG_RXBUF ) ) {
529541 self . process_rx_orig ( )
530542 } else {
531- unimplemented ! ( ) ;
543+ self . process_rx_iov ( )
532544 }
533545 }
534546
@@ -568,6 +580,167 @@ impl Net {
568580 self . signal_used_queue ( NetQueue :: Rx )
569581 }
570582
583+ fn process_rx_iov ( & mut self ) -> Result < ( ) , DeviceError > {
584+ self . rx_iov . clear ( ) ;
585+ self . rx_heads_info . clear ( ) ;
586+
587+ let mem = self . device_state . mem ( ) . unwrap ( ) ;
588+
589+ // Preparing iov vector with all available buffers
590+ // from all available descriptor chains
591+ #[ repr( C ) ]
592+ struct AvailRing {
593+ flags : u16 ,
594+ idx : u16 ,
595+ ring : [ u16 ; 256 ] ,
596+ used_element : u16 ,
597+ }
598+ // SAFETY:
599+ // avail_ring in the queue is a valid guest address
600+ let avail_ring: & AvailRing = unsafe {
601+ std:: mem:: transmute (
602+ mem. get_host_address ( self . queues [ RX_INDEX ] . avail_ring )
603+ . unwrap ( ) ,
604+ )
605+ } ;
606+ // SAFETY:
607+ // desc_table in the queue is a valid guest address
608+ let desc_table: & [ Descriptor ; 256 ] = unsafe {
609+ std:: mem:: transmute (
610+ mem. get_host_address ( self . queues [ RX_INDEX ] . desc_table )
611+ . unwrap ( ) ,
612+ )
613+ } ;
614+
615+ let avail_idx = self . queues [ RX_INDEX ] . avail_idx ( mem) ;
616+ let actual_size = self . queues [ RX_INDEX ] . actual_size ( ) ;
617+ let mut next_avail = self . queues [ RX_INDEX ] . next_avail ;
618+
619+ while next_avail. 0 != avail_idx. 0 {
620+ let index = next_avail. 0 % actual_size;
621+ let desc_index = avail_ring. ring [ index as usize ] ;
622+
623+ let mut desc = & desc_table[ desc_index as usize ] ;
624+
625+ let mut chain_capacity = desc. len ;
626+ let mut iov_len = 1 ;
627+ self . rx_iov . push ( iovec {
628+ iov_base : mem
629+ . get_host_address ( vm_memory:: GuestAddress ( desc. addr ) )
630+ . unwrap ( )
631+ . cast ( ) ,
632+ iov_len : desc. len as usize ,
633+ } ) ;
634+
635+ while desc. flags & crate :: devices:: virtio:: queue:: VIRTQ_DESC_F_NEXT != 0 {
636+ desc = & desc_table[ desc. next as usize ] ;
637+ chain_capacity += desc. len ;
638+ iov_len += 1 ;
639+ self . rx_iov . push ( iovec {
640+ iov_base : mem
641+ . get_host_address ( vm_memory:: GuestAddress ( desc. addr ) )
642+ . unwrap ( )
643+ . cast ( ) ,
644+ iov_len : desc. len as usize ,
645+ } ) ;
646+ }
647+
648+ self . rx_heads_info
649+ . push ( ( desc_index, chain_capacity, iov_len) ) ;
650+
651+ next_avail += Wrapping ( 1 ) ;
652+ }
653+
654+ // If threre are no buffers, there is
655+ // nothing for us to do.
656+ if self . rx_iov . is_empty ( ) {
657+ return Ok ( ( ) ) ;
658+ }
659+
660+ let mut iov_slice = & self . rx_iov [ ..] ;
661+ let mut heads_info_slice = & self . rx_heads_info [ ..] ;
662+ loop {
663+ // If we used all iovs, we cannot read
664+ // anything else.
665+ if iov_slice. is_empty ( ) {
666+ break ;
667+ }
668+
669+ match self . tap . read_iovec ( iov_slice) . map_err ( NetError :: IO ) {
670+ Ok ( mut bytes_written) => {
671+ let mut used_iovs = 0 ;
672+ let mut used_heads = 0 ;
673+ // Calculate how manu descriptor heads we used for this write.
674+ loop {
675+ if used_heads == heads_info_slice. len ( ) {
676+ break ;
677+ }
678+
679+ let ( head_index, iov_capacity, iov_len) = heads_info_slice[ used_heads] ;
680+ used_heads += 1 ;
681+ used_iovs += iov_len;
682+
683+ if bytes_written < iov_capacity as usize {
684+ self . queues [ RX_INDEX ]
685+ . add_used ( mem, head_index, bytes_written as u32 )
686+ . unwrap ( ) ;
687+ break ;
688+ } else {
689+ self . queues [ RX_INDEX ]
690+ . add_used ( mem, head_index, iov_capacity)
691+ . unwrap ( ) ;
692+ bytes_written -= iov_capacity as usize ;
693+ } ;
694+ }
695+
696+ // Update number of descrptor heads used to store
697+ // a packet.
698+ // SAFETY:
699+ // The iov_base is valid userspace address.
700+ #[ allow( clippy:: transmute_ptr_to_ref) ]
701+ let header: & mut virtio_net_hdr_v1 =
702+ unsafe { std:: mem:: transmute ( iov_slice[ 0 ] . iov_base ) } ;
703+ header. num_buffers = used_heads as u16 ;
704+
705+ iov_slice = & iov_slice[ used_iovs..] ;
706+ heads_info_slice = & heads_info_slice[ used_heads..] ;
707+
708+ // Update the number of used descriptor heads
709+ self . queues [ RX_INDEX ] . next_avail += Wrapping ( used_heads as u16 ) ;
710+
711+ // Tell the guest about used descriptor heads.
712+ if self . queues [ RX_INDEX ] . uses_notif_suppression {
713+ if self . queues [ RX_INDEX ] . len ( mem) == 0 {
714+ let next_avail = self . queues [ RX_INDEX ] . next_avail . 0 ;
715+ self . queues [ RX_INDEX ] . set_avail_event ( next_avail, mem) ;
716+ }
717+ } else {
718+ let next_avail = self . queues [ RX_INDEX ] . next_avail . 0 ;
719+ self . queues [ RX_INDEX ] . set_avail_event ( next_avail, mem) ;
720+ }
721+ }
722+ Err ( NetError :: IO ( err) ) => {
723+ // The tap device is non-blocking, so any error aside from EAGAIN is
724+ // unexpected.
725+ match err. raw_os_error ( ) {
726+ Some ( err) if err == EAGAIN => ( ) ,
727+ _ => {
728+ error ! ( "Failed to read tap: {:?}" , err) ;
729+ self . metrics . tap_read_fails . inc ( ) ;
730+ return Err ( DeviceError :: FailedReadTap ) ;
731+ }
732+ } ;
733+ break ;
734+ }
735+ Err ( err) => {
736+ error ! ( "Spurious error in network RX: {:?}" , err) ;
737+ }
738+ }
739+ }
740+ self . signal_used_queue ( NetQueue :: Rx ) ?;
741+ Ok ( ( ) )
742+ }
743+
571744 // Process the deferred frame first, then continue reading from tap.
572745 fn handle_deferred_frame ( & mut self ) -> Result < ( ) , DeviceError > {
573746 if self . rate_limited_rx_single_frame ( ) {
0 commit comments