@@ -25,7 +25,7 @@ use volatile::access::ReadOnly;
2525use self :: constants:: MAX_NUM_VQ ;
2626use self :: error:: VirtioNetError ;
2727use crate :: config:: VIRTIO_MAX_QUEUE_SIZE ;
28- use crate :: drivers:: net:: NetworkDriver ;
28+ use crate :: drivers:: net:: { NetworkDriver , mtu } ;
2929#[ cfg( not( feature = "pci" ) ) ]
3030use crate :: drivers:: virtio:: transport:: mmio:: { ComCfg , IsrStatus , NotifCfg } ;
3131#[ cfg( feature = "pci" ) ]
@@ -48,22 +48,53 @@ pub(crate) struct NetDevCfg {
4848 pub features : virtio:: net:: F ,
4949}
5050
51+ fn determine_mtu ( dev_cfg : & NetDevCfg ) -> u16 {
52+ // If VIRTIO_NET_F_MTU is negotiated, "the driver uses mtu as the maximum MTU value"
53+ // (VirtIO specification, 5.1.3, "Feature bits")
54+ if dev_cfg. features . contains ( virtio:: net:: F :: MTU ) {
55+ dev_cfg. raw . as_ptr ( ) . mtu ( ) . read ( ) . to_ne ( )
56+ } else {
57+ // Otherwise, we can just use the MTU we want to use
58+ mtu ( )
59+ }
60+ }
61+
62+ fn determine_buf_size ( dev_cfg : & NetDevCfg ) -> u32 {
63+ // See Virtio specification v1.1 - 5.1.6.3.1 and 5.1.4.2
64+
65+ // Our desired minimum buffer size - we want it to be at least the MTU generally
66+ let mut min_buf_size = determine_mtu ( dev_cfg) . into ( ) ;
67+
68+ // If VIRTIO_NET_F_MRG_RXBUF is negotiated, each buffer MUST be at least the size of the struct virtio_net_hdr.
69+ if dev_cfg. features . contains ( virtio:: net:: F :: MRG_RXBUF ) {
70+ min_buf_size = u32:: max ( min_buf_size, size_of :: < Hdr > ( ) as u32 ) ;
71+ } else {
72+ // If [...] are negotiated, the driver SHOULD populate the receive queue(s) with buffers of at least 65562 bytes.
73+ if dev_cfg. features . contains ( virtio:: net:: F :: GUEST_TSO4 )
74+ || dev_cfg. features . contains ( virtio:: net:: F :: GUEST_TSO6 )
75+ || dev_cfg. features . contains ( virtio:: net:: F :: GUEST_UFO )
76+ {
77+ min_buf_size = u32:: max ( min_buf_size, 65562 - size_of :: < Hdr > ( ) as u32 ) ;
78+ } else {
79+ // Otherwise, the driver SHOULD populate the receive queue(s) with buffers of at least 1526 bytes.
80+ min_buf_size = u32:: max ( min_buf_size, 1526 - size_of :: < Hdr > ( ) as u32 ) ;
81+ }
82+ }
83+
84+ min_buf_size
85+ }
86+
5187pub struct RxQueues {
5288 vqs : Vec < VirtQueue > ,
53- packet_size : u32 ,
89+ buf_size : u32 ,
5490}
5591
5692impl RxQueues {
5793 pub fn new ( vqs : Vec < VirtQueue > , dev_cfg : & NetDevCfg ) -> Self {
58- // See Virtio specification v1.1 - 5.1.6.3.1
59- //
60- let packet_size = if dev_cfg. features . contains ( virtio:: net:: F :: MRG_RXBUF ) {
61- 1514
62- } else {
63- dev_cfg. raw . as_ptr ( ) . mtu ( ) . read ( ) . to_ne ( ) . into ( )
64- } ;
65-
66- Self { vqs, packet_size }
94+ Self {
95+ vqs,
96+ buf_size : determine_buf_size ( dev_cfg) ,
97+ }
6798 }
6899
69100 /// Takes care of handling packets correctly which need some processing after being received.
@@ -79,8 +110,8 @@ impl RxQueues {
79110 /// Queues are all populated according to Virtio specification v1.1. - 5.1.6.3.1
80111 fn add ( & mut self , mut vq : VirtQueue ) {
81112 const BUFF_PER_PACKET : u16 = 2 ;
82- let num_packets : u16 = u16:: from ( vq. size ( ) ) / BUFF_PER_PACKET ;
83- fill_queue ( & mut vq, num_packets , self . packet_size ) ;
113+ let num_bufs : u16 = u16:: from ( vq. size ( ) ) / BUFF_PER_PACKET ;
114+ fill_queue ( & mut vq, num_bufs , self . buf_size ) ;
84115 self . vqs . push ( vq) ;
85116 }
86117
@@ -107,24 +138,23 @@ impl RxQueues {
107138
108139fn buffer_token_from_hdr (
109140 hdr : Box < MaybeUninit < Hdr > , DeviceAlloc > ,
110- packet_size : u32 ,
141+ buf_size : u32 ,
111142) -> AvailBufferToken {
112143 AvailBufferToken :: new ( SmallVec :: new ( ) , {
113144 SmallVec :: from_buf ( [
114145 BufferElem :: Sized ( hdr) ,
115146 BufferElem :: Vector ( Vec :: with_capacity_in (
116- packet_size . try_into ( ) . unwrap ( ) ,
147+ buf_size . try_into ( ) . unwrap ( ) ,
117148 DeviceAlloc ,
118149 ) ) ,
119150 ] )
120151 } )
121152 . unwrap ( )
122153}
123154
124- fn fill_queue ( vq : & mut VirtQueue , num_packets : u16 , packet_size : u32 ) {
125- for _ in 0 ..num_packets {
126- let buff_tkn =
127- buffer_token_from_hdr ( Box :: < Hdr , _ > :: new_uninit_in ( DeviceAlloc ) , packet_size) ;
155+ fn fill_queue ( vq : & mut VirtQueue , num_bufs : u16 , buf_size : u32 ) {
156+ for _ in 0 ..num_bufs {
157+ let buff_tkn = buffer_token_from_hdr ( Box :: < Hdr , _ > :: new_uninit_in ( DeviceAlloc ) , buf_size) ;
128158
129159 // BufferTokens are directly provided to the queue
130160 // TransferTokens are directly dispatched
@@ -142,22 +172,17 @@ pub struct TxQueues {
142172 vqs : Vec < VirtQueue > ,
143173 /// Indicates, whether the Driver/Device are using multiple
144174 /// queues for communication.
145- packet_length : u32 ,
175+ buf_size : u32 ,
146176}
147177
148178impl TxQueues {
149179 pub fn new ( vqs : Vec < VirtQueue > , dev_cfg : & NetDevCfg ) -> Self {
150- let packet_length = if dev_cfg. features . contains ( virtio:: net:: F :: GUEST_TSO4 )
151- | dev_cfg. features . contains ( virtio:: net:: F :: GUEST_TSO6 )
152- | dev_cfg. features . contains ( virtio:: net:: F :: GUEST_UFO )
153- {
154- 0x0001_000e
155- } else {
156- dev_cfg. raw . as_ptr ( ) . mtu ( ) . read ( ) . to_ne ( ) . into ( )
157- } ;
158-
159- Self { vqs, packet_length }
180+ Self {
181+ vqs,
182+ buf_size : determine_buf_size ( dev_cfg) ,
183+ }
160184 }
185+
161186 #[ allow( dead_code) ]
162187 fn enable_notifs ( & mut self ) {
163188 for vq in & mut self . vqs {
@@ -189,6 +214,7 @@ impl TxQueues {
189214
190215pub ( crate ) struct Uninit ;
191216pub ( crate ) struct Init {
217+ pub ( super ) mtu : u16 ,
192218 pub ( super ) ctrl_vq : Option < VirtQueue > ,
193219 pub ( super ) recv_vqs : RxQueues ,
194220 pub ( super ) send_vqs : TxQueues ,
@@ -207,7 +233,6 @@ pub(crate) struct VirtioNetDriver<T = Init> {
207233 pub ( super ) inner : T ,
208234
209235 pub ( super ) num_vqs : u16 ,
210- pub ( super ) mtu : u16 ,
211236 pub ( super ) irq : InterruptLine ,
212237 pub ( super ) checksums : ChecksumCapabilities ,
213238}
@@ -227,7 +252,7 @@ impl NetworkDriver for VirtioNetDriver<Init> {
227252
228253 /// Returns the current MTU of the device.
229254 fn get_mtu ( & self ) -> u16 {
230- self . mtu
255+ self . inner . mtu
231256 }
232257
233258 fn get_checksums ( & self ) -> ChecksumCapabilities {
@@ -249,7 +274,7 @@ impl NetworkDriver for VirtioNetDriver<Init> {
249274 // what we are about to add
250275 self . inner . send_vqs . poll ( ) ;
251276
252- assert ! ( len < usize :: try_from( self . inner. send_vqs. packet_length ) . unwrap( ) ) ;
277+ assert ! ( len < usize :: try_from( self . inner. send_vqs. buf_size ) . unwrap( ) ) ;
253278 let mut packet = Vec :: with_capacity_in ( len, DeviceAlloc ) ;
254279 let result = unsafe {
255280 let result = f ( packet. spare_capacity_mut ( ) . assume_init_mut ( ) ) ;
@@ -323,7 +348,7 @@ impl NetworkDriver for VirtioNetDriver<Init> {
323348 unsafe {
324349 transmute :: < Box < Hdr , DeviceAlloc > , Box < MaybeUninit < Hdr > , DeviceAlloc > > ( first_header)
325350 } ,
326- self . inner . recv_vqs . packet_size ,
351+ self . inner . recv_vqs . buf_size ,
327352 ) ;
328353 self . inner . recv_vqs . vqs [ 0 ]
329354 . dispatch ( first_tkn, false , BufferType :: Direct )
@@ -338,7 +363,7 @@ impl NetworkDriver for VirtioNetDriver<Init> {
338363 unsafe {
339364 transmute :: < Box < Hdr , DeviceAlloc > , Box < MaybeUninit < Hdr > , DeviceAlloc > > ( header)
340365 } ,
341- self . inner . recv_vqs . packet_size ,
366+ self . inner . recv_vqs . buf_size ,
342367 ) ;
343368 self . inner . recv_vqs . vqs [ 0 ]
344369 . dispatch ( tkn, false , BufferType :: Direct )
@@ -609,11 +634,14 @@ impl VirtioNetDriver<Uninit> {
609634 }
610635
611636 let mut inner = Init {
637+ mtu : determine_mtu ( & self . dev_cfg ) ,
612638 ctrl_vq : None ,
613639 recv_vqs : RxQueues :: new ( Vec :: new ( ) , & self . dev_cfg ) ,
614640 send_vqs : TxQueues :: new ( Vec :: new ( ) , & self . dev_cfg ) ,
615641 } ;
616642
643+ debug ! ( "Using RX buffer size of {}" , inner. recv_vqs. buf_size) ;
644+
617645 self . dev_spec_init ( & mut inner) ?;
618646 info ! (
619647 "Device specific initialization for Virtio network device {:x} finished" ,
@@ -637,18 +665,13 @@ impl VirtioNetDriver<Uninit> {
637665 }
638666 debug ! ( "{:?}" , self . checksums) ;
639667
640- if self . dev_cfg . features . contains ( virtio:: net:: F :: MTU ) {
641- self . mtu = self . dev_cfg . raw . as_ptr ( ) . mtu ( ) . read ( ) . to_ne ( ) ;
642- }
643-
644668 Ok ( VirtioNetDriver {
645669 dev_cfg : self . dev_cfg ,
646670 com_cfg : self . com_cfg ,
647671 isr_stat : self . isr_stat ,
648672 notif_cfg : self . notif_cfg ,
649673 inner,
650674 num_vqs : self . num_vqs ,
651- mtu : self . mtu ,
652675 irq : self . irq ,
653676 checksums : self . checksums ,
654677 } )
0 commit comments