Skip to content

Commit e817bee

Browse files
authored
Merge pull request #196 from epilys/accept-version1-feature-bit
Accept `VIRTIO_F_VERSION_1` if offered
2 parents d812330 + 97f5982 commit e817bee

File tree

12 files changed

+161
-46
lines changed

12 files changed

+161
-46
lines changed

src/device/blk.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ const QUEUE_SIZE: u16 = 16;
1414
const SUPPORTED_FEATURES: BlkFeature = BlkFeature::RO
1515
.union(BlkFeature::FLUSH)
1616
.union(BlkFeature::RING_INDIRECT_DESC)
17-
.union(BlkFeature::RING_EVENT_IDX);
17+
.union(BlkFeature::RING_EVENT_IDX)
18+
.union(BlkFeature::VERSION_1);
1819

1920
/// Driver for a VirtIO block device.
2021
///

src/device/console.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ const QUEUE_SIZE: usize = 2;
2020
const SUPPORTED_FEATURES: Features = Features::RING_EVENT_IDX
2121
.union(Features::RING_INDIRECT_DESC)
2222
.union(Features::SIZE)
23-
.union(Features::EMERG_WRITE);
23+
.union(Features::EMERG_WRITE)
24+
.union(Features::VERSION_1);
2425

2526
/// Driver for a VirtIO console device.
2627
///

src/device/gpu.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ use log::info;
1111
use zerocopy::{FromBytes, FromZeros, Immutable, IntoBytes, KnownLayout};
1212

1313
const QUEUE_SIZE: u16 = 2;
14-
const SUPPORTED_FEATURES: Features = Features::RING_EVENT_IDX.union(Features::RING_INDIRECT_DESC);
14+
const SUPPORTED_FEATURES: Features = Features::RING_EVENT_IDX
15+
.union(Features::RING_INDIRECT_DESC)
16+
.union(Features::VERSION_1);
1517

1618
/// A virtio based graphics adapter.
1719
///

src/device/input.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,9 @@ pub struct InputEvent {
301301

302302
const QUEUE_EVENT: u16 = 0;
303303
const QUEUE_STATUS: u16 = 1;
304-
const SUPPORTED_FEATURES: Feature = Feature::RING_EVENT_IDX.union(Feature::RING_INDIRECT_DESC);
304+
const SUPPORTED_FEATURES: Feature = Feature::RING_EVENT_IDX
305+
.union(Feature::RING_INDIRECT_DESC)
306+
.union(Feature::VERSION_1);
305307

306308
// a parameter that can change
307309
const QUEUE_SIZE: usize = 32;

src/device/net/dev.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ impl<H: Hal, T: Transport, const QUEUE_SIZE: usize> VirtIONet<H, T, QUEUE_SIZE>
3131
const NONE_BUF: Option<RxBuffer> = None;
3232
let mut rx_buffers = [NONE_BUF; QUEUE_SIZE];
3333
for (i, rx_buf_place) in rx_buffers.iter_mut().enumerate() {
34-
let mut rx_buf = RxBuffer::new(i, buf_len);
34+
let mut rx_buf = RxBuffer::new(i, buf_len, inner.legacy_header);
3535
// SAFETY: The buffer lives as long as the queue.
3636
let token = unsafe { inner.receive_begin(rx_buf.as_bytes_mut())? };
3737
assert_eq!(token, i as u16);

src/device/net/dev_raw.rs

Lines changed: 60 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
use super::{Config, EthernetAddress, Features, VirtioNetHdr};
2-
use super::{MIN_BUFFER_LEN, NET_HDR_SIZE, QUEUE_RECEIVE, QUEUE_TRANSMIT, SUPPORTED_FEATURES};
1+
use super::{Config, EthernetAddress, Features, VirtioNetHdr, VirtioNetHdrLegacy};
2+
use super::{MIN_BUFFER_LEN, QUEUE_RECEIVE, QUEUE_TRANSMIT, SUPPORTED_FEATURES};
33
use crate::config::read_config;
44
use crate::hal::Hal;
55
use crate::queue::VirtQueue;
66
use crate::transport::{InterruptStatus, Transport};
77
use crate::{Error, Result};
8+
use core::mem::size_of;
89
use log::{debug, info, warn};
910
use zerocopy::IntoBytes;
1011

@@ -21,6 +22,8 @@ pub struct VirtIONetRaw<H: Hal, T: Transport, const QUEUE_SIZE: usize> {
2122
mac: EthernetAddress,
2223
recv_queue: VirtQueue<H, QUEUE_SIZE>,
2324
send_queue: VirtQueue<H, QUEUE_SIZE>,
25+
/// Whether `num_buffers` is missing in the `virtio_net_hdr` struct.
26+
pub(crate) legacy_header: bool,
2427
}
2528

2629
impl<H: Hal, T: Transport, const QUEUE_SIZE: usize> VirtIONetRaw<H, T, QUEUE_SIZE> {
@@ -54,6 +57,8 @@ impl<H: Hal, T: Transport, const QUEUE_SIZE: usize> VirtIONetRaw<H, T, QUEUE_SIZ
5457
mac,
5558
recv_queue,
5659
send_queue,
60+
legacy_header: !negotiated_features.contains(Features::VERSION_1)
61+
&& !negotiated_features.contains(Features::MRG_RXBUF),
5762
})
5863
}
5964

@@ -95,8 +100,13 @@ impl<H: Hal, T: Transport, const QUEUE_SIZE: usize> VirtIONetRaw<H, T, QUEUE_SIZ
95100
}
96101

97102
/// Whether the length of the transmit buffer is valid.
98-
fn check_tx_buf_len(tx_buf: &[u8]) -> Result<()> {
99-
if tx_buf.len() < NET_HDR_SIZE {
103+
fn check_tx_buf_len(&self, tx_buf: &[u8]) -> Result<()> {
104+
let hdr_size = if self.legacy_header {
105+
size_of::<VirtioNetHdrLegacy>()
106+
} else {
107+
size_of::<VirtioNetHdr>()
108+
};
109+
if tx_buf.len() < hdr_size {
100110
warn!("Transmit buffer len {} is too small", tx_buf.len());
101111
Err(Error::InvalidParam)
102112
} else {
@@ -108,12 +118,21 @@ impl<H: Hal, T: Transport, const QUEUE_SIZE: usize> VirtIONetRaw<H, T, QUEUE_SIZ
108118
///
109119
/// If the `buffer` is not large enough, it returns [`Error::InvalidParam`].
110120
pub fn fill_buffer_header(&self, buffer: &mut [u8]) -> Result<usize> {
111-
if buffer.len() < NET_HDR_SIZE {
112-
return Err(Error::InvalidParam);
121+
macro_rules! fill {
122+
($hdr:ty) => {{
123+
if buffer.len() < size_of::<$hdr>() {
124+
return Err(Error::InvalidParam);
125+
}
126+
let header = <$hdr>::default();
127+
buffer[..size_of::<$hdr>()].copy_from_slice(header.as_bytes());
128+
Ok(size_of::<$hdr>())
129+
}};
130+
}
131+
if self.legacy_header {
132+
fill!(VirtioNetHdrLegacy)
133+
} else {
134+
fill!(VirtioNetHdr)
113135
}
114-
let header = VirtioNetHdr::default();
115-
buffer[..NET_HDR_SIZE].copy_from_slice(header.as_bytes());
116-
Ok(NET_HDR_SIZE)
117136
}
118137

119138
/// Submits a request to transmit a buffer immediately without waiting for
@@ -141,7 +160,7 @@ impl<H: Hal, T: Transport, const QUEUE_SIZE: usize> VirtIONetRaw<H, T, QUEUE_SIZ
141160
/// [`poll_transmit`]: Self::poll_transmit
142161
/// [`transmit_complete`]: Self::transmit_complete
143162
pub unsafe fn transmit_begin(&mut self, tx_buf: &[u8]) -> Result<u16> {
144-
Self::check_tx_buf_len(tx_buf)?;
163+
self.check_tx_buf_len(tx_buf)?;
145164
let token = self.send_queue.add(&[tx_buf], &mut [])?;
146165
if self.send_queue.should_notify() {
147166
self.transport.notify(QUEUE_TRANSMIT);
@@ -226,28 +245,42 @@ impl<H: Hal, T: Transport, const QUEUE_SIZE: usize> VirtIONetRaw<H, T, QUEUE_SIZ
226245
rx_buf: &mut [u8],
227246
) -> Result<(usize, usize)> {
228247
let len = self.recv_queue.pop_used(token, &[], &mut [rx_buf])? as usize;
229-
let packet_len = len.checked_sub(NET_HDR_SIZE).ok_or(Error::IoError)?;
230-
Ok((NET_HDR_SIZE, packet_len))
248+
let hdr_size = if self.legacy_header {
249+
size_of::<VirtioNetHdrLegacy>()
250+
} else {
251+
size_of::<VirtioNetHdr>()
252+
};
253+
let packet_len = len.checked_sub(hdr_size).ok_or(Error::IoError)?;
254+
Ok((hdr_size, packet_len))
231255
}
232256

233257
/// Sends a packet to the network, and blocks until the request completed.
234258
pub fn send(&mut self, tx_buf: &[u8]) -> Result {
235-
let header = VirtioNetHdr::default();
236-
if tx_buf.is_empty() {
237-
// Special case sending an empty packet, to avoid adding an empty buffer to the
238-
// virtqueue.
239-
self.send_queue.add_notify_wait_pop(
240-
&[header.as_bytes()],
241-
&mut [],
242-
&mut self.transport,
243-
)?;
244-
} else {
245-
self.send_queue.add_notify_wait_pop(
246-
&[header.as_bytes(), tx_buf],
247-
&mut [],
248-
&mut self.transport,
249-
)?;
259+
macro_rules! send {
260+
($header:expr) => {{
261+
let header = $header;
262+
if tx_buf.is_empty() {
263+
// Special case sending an empty packet, to avoid adding an empty buffer to the
264+
// virtqueue.
265+
self.send_queue.add_notify_wait_pop(
266+
&[header.as_bytes()],
267+
&mut [],
268+
&mut self.transport,
269+
)?;
270+
} else {
271+
self.send_queue.add_notify_wait_pop(
272+
&[header.as_bytes(), tx_buf],
273+
&mut [],
274+
&mut self.transport,
275+
)?;
276+
}
277+
}};
250278
}
279+
if self.legacy_header {
280+
send!(VirtioNetHdrLegacy::default())
281+
} else {
282+
send!(VirtioNetHdr::default())
283+
};
251284
Ok(())
252285
}
253286

src/device/net/mod.rs

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
1616

1717
const MAX_BUFFER_LEN: usize = 65535;
1818
const MIN_BUFFER_LEN: usize = 1526;
19-
const NET_HDR_SIZE: usize = core::mem::size_of::<VirtioNetHdr>();
2019

2120
bitflags! {
2221
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
@@ -119,17 +118,56 @@ type EthernetAddress = [u8; 6];
119118
/// In each case, the packet itself is preceded by a header.
120119
#[repr(C)]
121120
#[derive(Debug, Default, FromBytes, Immutable, IntoBytes, KnownLayout)]
121+
pub(crate) struct VirtioNetHdrLegacy {
122+
flags: Flags,
123+
gso_type: GsoType,
124+
hdr_len: u16, // cannot rely on this
125+
gso_size: u16,
126+
csum_start: u16,
127+
csum_offset: u16,
128+
}
129+
130+
/// VirtIO 5.1.6 Device Operation:
131+
///
132+
/// Packets are transmitted by placing them in the transmitq1. . .transmitqN,
133+
/// and buffers for incoming packets are placed in the receiveq1. . .receiveqN.
134+
/// In each case, the packet itself is preceded by a header.
135+
#[repr(C)]
136+
#[derive(Copy, Clone, Debug, Default, FromBytes, Immutable, IntoBytes, KnownLayout)]
122137
pub struct VirtioNetHdr {
123138
flags: Flags,
124139
gso_type: GsoType,
125140
hdr_len: u16, // cannot rely on this
126141
gso_size: u16,
127142
csum_start: u16,
128143
csum_offset: u16,
129-
// num_buffers: u16, // only available when the feature MRG_RXBUF is negotiated.
144+
num_buffers: u16,
130145
// payload starts from here
131146
}
132147

148+
impl From<&VirtioNetHdrLegacy> for VirtioNetHdr {
149+
fn from(legacy: &VirtioNetHdrLegacy) -> Self {
150+
let VirtioNetHdrLegacy {
151+
flags,
152+
gso_type,
153+
hdr_len,
154+
gso_size,
155+
csum_start,
156+
csum_offset,
157+
} = *legacy;
158+
159+
Self {
160+
flags,
161+
gso_type,
162+
hdr_len,
163+
gso_size,
164+
csum_start,
165+
csum_offset,
166+
num_buffers: 0,
167+
}
168+
}
169+
}
170+
133171
#[derive(
134172
IntoBytes, Copy, Clone, Debug, Default, Eq, FromBytes, Immutable, KnownLayout, PartialEq,
135173
)]
@@ -163,4 +201,5 @@ const QUEUE_TRANSMIT: u16 = 1;
163201
const SUPPORTED_FEATURES: Features = Features::MAC
164202
.union(Features::STATUS)
165203
.union(Features::RING_EVENT_IDX)
166-
.union(Features::RING_INDIRECT_DESC);
204+
.union(Features::RING_INDIRECT_DESC)
205+
.union(Features::VERSION_1);

src/device/net/net_buf.rs

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use super::{VirtioNetHdr, NET_HDR_SIZE};
1+
use super::{VirtioNetHdr, VirtioNetHdrLegacy};
22
use alloc::{vec, vec::Vec};
33
use core::{convert::TryInto, mem::size_of};
44
use zerocopy::{FromBytes, IntoBytes};
@@ -11,6 +11,8 @@ pub struct RxBuffer {
1111
pub(crate) buf: Vec<usize>, // for alignment
1212
pub(crate) packet_len: usize,
1313
pub(crate) idx: u16,
14+
/// Whether `num_buffers` is missing in the `virtio_net_hdr` struct.
15+
legacy_header: bool,
1416
}
1517

1618
impl TxBuffer {
@@ -37,11 +39,12 @@ impl TxBuffer {
3739

3840
impl RxBuffer {
3941
/// Allocates a new buffer with length `buf_len`.
40-
pub(crate) fn new(idx: usize, buf_len: usize) -> Self {
42+
pub(crate) fn new(idx: usize, buf_len: usize, legacy_header: bool) -> Self {
4143
Self {
4244
buf: vec![0; buf_len / size_of::<usize>()],
4345
packet_len: 0,
4446
idx: idx.try_into().unwrap(),
47+
legacy_header,
4548
}
4649
}
4750

@@ -66,18 +69,36 @@ impl RxBuffer {
6669
self.buf.as_mut_bytes()
6770
}
6871

69-
/// Returns the reference of the header.
70-
pub fn header(&self) -> &VirtioNetHdr {
71-
FromBytes::ref_from_prefix(self.as_bytes()).unwrap().0
72+
/// Returns a copy of the header.
73+
pub fn header(&self) -> VirtioNetHdr {
74+
if self.legacy_header {
75+
VirtioNetHdrLegacy::ref_from_prefix(self.as_bytes())
76+
.unwrap()
77+
.0
78+
.into()
79+
} else {
80+
*VirtioNetHdr::ref_from_prefix(self.as_bytes()).unwrap().0
81+
}
7282
}
7383

7484
/// Returns the network packet as a slice.
7585
pub fn packet(&self) -> &[u8] {
76-
&self.buf.as_bytes()[NET_HDR_SIZE..NET_HDR_SIZE + self.packet_len]
86+
let hdr_size = if self.legacy_header {
87+
size_of::<VirtioNetHdrLegacy>()
88+
} else {
89+
size_of::<VirtioNetHdr>()
90+
};
91+
92+
&self.buf.as_bytes()[hdr_size..hdr_size + self.packet_len]
7793
}
7894

7995
/// Returns the network packet as a mutable slice.
8096
pub fn packet_mut(&mut self) -> &mut [u8] {
81-
&mut self.buf.as_mut_bytes()[NET_HDR_SIZE..NET_HDR_SIZE + self.packet_len]
97+
let hdr_size = if self.legacy_header {
98+
size_of::<VirtioNetHdrLegacy>()
99+
} else {
100+
size_of::<VirtioNetHdr>()
101+
};
102+
&mut self.buf.as_mut_bytes()[hdr_size..hdr_size + self.packet_len]
82103
}
83104
}

src/device/rng.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ use crate::{
99
// VirtioRNG only uses one queue
1010
const QUEUE_IDX: u16 = 0;
1111
const QUEUE_SIZE: usize = 8;
12-
const SUPPORTED_FEATURES: Feature = Feature::RING_INDIRECT_DESC.union(Feature::RING_EVENT_IDX);
12+
const SUPPORTED_FEATURES: Feature = Feature::RING_INDIRECT_DESC
13+
.union(Feature::RING_EVENT_IDX)
14+
.union(Feature::VERSION_1);
1315

1416
/// Driver for a VirtIO random number generator device.
1517
pub struct VirtIORng<H: Hal, T: Transport> {

src/device/socket/vsock.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ pub(crate) const TX_QUEUE_IDX: u16 = 1;
2020
const EVENT_QUEUE_IDX: u16 = 2;
2121

2222
pub(crate) const QUEUE_SIZE: usize = 8;
23-
const SUPPORTED_FEATURES: Feature = Feature::RING_EVENT_IDX.union(Feature::RING_INDIRECT_DESC);
23+
const SUPPORTED_FEATURES: Feature = Feature::RING_EVENT_IDX
24+
.union(Feature::RING_INDIRECT_DESC)
25+
.union(Feature::VERSION_1);
2426

2527
/// Information about a particular vsock connection.
2628
#[derive(Clone, Debug, Default, PartialEq, Eq)]

0 commit comments

Comments
 (0)