9
9
use std:: io:: Read ;
10
10
use std:: mem;
11
11
use std:: net:: Ipv4Addr ;
12
+ use std:: num:: Wrapping ;
12
13
use std:: sync:: atomic:: AtomicU32 ;
13
14
use std:: sync:: { Arc , Mutex } ;
14
15
15
- use libc:: EAGAIN ;
16
+ use libc:: { iovec , EAGAIN } ;
16
17
use log:: { error, warn} ;
17
18
use utils:: eventfd:: EventFd ;
18
19
use utils:: net:: mac:: MacAddr ;
19
20
use utils:: u64_to_usize;
20
- use vm_memory:: GuestMemoryError ;
21
+ use vm_memory:: { GuestMemory , GuestMemoryError } ;
21
22
22
23
use crate :: devices:: virtio:: device:: { DeviceState , IrqTrigger , IrqType , VirtioDevice } ;
23
24
use crate :: devices:: virtio:: gen:: virtio_blk:: VIRTIO_F_VERSION_1 ;
@@ -33,7 +34,7 @@ use crate::devices::virtio::net::tap::Tap;
33
34
use crate :: devices:: virtio:: net:: {
34
35
gen, NetError , NetQueue , MAX_BUFFER_SIZE , NET_QUEUE_SIZES , RX_INDEX , TX_INDEX ,
35
36
} ;
36
- use crate :: devices:: virtio:: queue:: { DescriptorChain , Queue } ;
37
+ use crate :: devices:: virtio:: queue:: { Descriptor , DescriptorChain , Queue } ;
37
38
use crate :: devices:: virtio:: { ActivateError , TYPE_NET } ;
38
39
use crate :: devices:: { report_net_event_fail, DeviceError } ;
39
40
use crate :: dumbo:: pdu:: arp:: ETH_IPV4_FRAME_LEN ;
@@ -128,6 +129,8 @@ pub struct Net {
128
129
129
130
rx_bytes_read : usize ,
130
131
rx_frame_buf : [ u8 ; MAX_BUFFER_SIZE ] ,
132
+ rx_iov : Vec < iovec > ,
133
+ rx_heads_info : Vec < ( u16 , u32 , usize ) > ,
131
134
132
135
tx_frame_headers : [ u8 ; frame_hdr_len ( ) ] ,
133
136
@@ -145,6 +148,12 @@ pub struct Net {
145
148
pub ( crate ) metrics : Arc < NetDeviceMetrics > ,
146
149
}
147
150
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
+
148
157
impl Net {
149
158
/// Create a new virtio network device with the given TAP interface.
150
159
pub fn new_with_tap (
@@ -161,6 +170,7 @@ impl Net {
161
170
| 1 << VIRTIO_NET_F_HOST_TSO4
162
171
| 1 << VIRTIO_NET_F_HOST_UFO
163
172
| 1 << VIRTIO_F_VERSION_1
173
+ | 1 << VIRTIO_NET_F_MRG_RXBUF
164
174
| 1 << VIRTIO_RING_F_EVENT_IDX ;
165
175
166
176
let mut config_space = ConfigSpace :: default ( ) ;
@@ -190,6 +200,8 @@ impl Net {
190
200
rx_deferred_frame : false ,
191
201
rx_bytes_read : 0 ,
192
202
rx_frame_buf : [ 0u8 ; MAX_BUFFER_SIZE ] ,
203
+ rx_iov : Vec :: new ( ) ,
204
+ rx_heads_info : Vec :: new ( ) ,
193
205
tx_frame_headers : [ 0u8 ; frame_hdr_len ( ) ] ,
194
206
irq_trigger : IrqTrigger :: new ( ) . map_err ( NetError :: EventFd ) ?,
195
207
config_space,
@@ -528,7 +540,7 @@ impl Net {
528
540
if !self . has_feature ( u64:: from ( VIRTIO_NET_F_MRG_RXBUF ) ) {
529
541
self . process_rx_orig ( )
530
542
} else {
531
- unimplemented ! ( ) ;
543
+ self . process_rx_iov ( )
532
544
}
533
545
}
534
546
@@ -568,6 +580,167 @@ impl Net {
568
580
self . signal_used_queue ( NetQueue :: Rx )
569
581
}
570
582
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
+
571
744
// Process the deferred frame first, then continue reading from tap.
572
745
fn handle_deferred_frame ( & mut self ) -> Result < ( ) , DeviceError > {
573
746
if self . rate_limited_rx_single_frame ( ) {
0 commit comments