Skip to content

Commit ec7a706

Browse files
committed
feat(net): add MRG_RXBUF support to virtio-net device
Now virtio-net device VIRTIO_NET_F_MRG_RXBUF feature which allows it to write single packet into multiple descriptor chains. The amount of descriptor chains (also known as heads) is written into the `virtio_net_hdr_v1` structure which is located at the very begging of the packet. Signed-off-by: Egor Lazarchuk <[email protected]>
1 parent d1bef09 commit ec7a706

File tree

3 files changed

+306
-36
lines changed

3 files changed

+306
-36
lines changed

src/vmm/src/devices/virtio/net/device.rs

Lines changed: 129 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use crate::devices::virtio::gen::virtio_blk::VIRTIO_F_VERSION_1;
1919
use crate::devices::virtio::gen::virtio_net::{
2020
virtio_net_hdr_v1, VIRTIO_NET_F_CSUM, VIRTIO_NET_F_GUEST_CSUM, VIRTIO_NET_F_GUEST_TSO4,
2121
VIRTIO_NET_F_GUEST_TSO6, VIRTIO_NET_F_GUEST_UFO, VIRTIO_NET_F_HOST_TSO4,
22-
VIRTIO_NET_F_HOST_TSO6, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_MAC,
22+
VIRTIO_NET_F_HOST_TSO6, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_MAC, VIRTIO_NET_F_MRG_RXBUF,
2323
};
2424
use crate::devices::virtio::gen::virtio_ring::VIRTIO_RING_F_EVENT_IDX;
2525
use crate::devices::virtio::iovec::IoVecBuffer;
@@ -149,6 +149,7 @@ impl Net {
149149
| 1 << VIRTIO_NET_F_HOST_TSO6
150150
| 1 << VIRTIO_NET_F_HOST_UFO
151151
| 1 << VIRTIO_F_VERSION_1
152+
| 1 << VIRTIO_NET_F_MRG_RXBUF
152153
| 1 << VIRTIO_RING_F_EVENT_IDX;
153154

154155
let mut config_space = ConfigSpace::default();
@@ -659,7 +660,11 @@ impl Net {
659660
}
660661

661662
fn read_tap(&mut self) -> std::io::Result<usize> {
662-
self.tap.read_iovec(self.rx_buffer.one_chain_mut_slice())
663+
if self.has_feature(u64::from(VIRTIO_NET_F_MRG_RXBUF)) {
664+
self.tap.read_iovec(self.rx_buffer.all_chains_mut_slice())
665+
} else {
666+
self.tap.read_iovec(self.rx_buffer.one_chain_mut_slice())
667+
}
663668
}
664669

665670
/// Process a single RX queue event.
@@ -891,8 +896,8 @@ pub mod tests {
891896
use crate::devices::virtio::net::rx_buffer::ChainInfo;
892897
use crate::devices::virtio::net::test_utils::test::TestHelper;
893898
use crate::devices::virtio::net::test_utils::{
894-
default_net, if_index, inject_tap_tx_frame, set_mac, NetEvent, NetQueue,
895-
TapTrafficSimulator,
899+
default_net, if_index, inject_tap_tx_frame, mock_frame_set_num_buffers, set_mac, NetEvent,
900+
NetQueue, TapTrafficSimulator,
896901
};
897902
use crate::devices::virtio::net::NET_QUEUE_SIZES;
898903
use crate::devices::virtio::queue::VIRTQ_DESC_F_WRITE;
@@ -1077,10 +1082,9 @@ pub mod tests {
10771082
assert_eq!(th.rxq.used.idx.get(), 0);
10781083
}
10791084

1080-
#[test]
1081-
fn test_rx_read_only_descriptor() {
1082-
let mem = single_region_mem(2 * MAX_BUFFER_SIZE);
1083-
let mut th = TestHelper::get_default(&mem);
1085+
fn rx_read_only_descriptor(mut th: TestHelper) {
1086+
// let mem = single_region_mem(2 * MAX_BUFFER_SIZE);
1087+
// let mut th = TestHelper::get_default(&mem);
10841088
th.activate_net();
10851089

10861090
th.add_desc_chain(
@@ -1099,9 +1103,22 @@ pub mod tests {
10991103
}
11001104

11011105
#[test]
1102-
fn test_rx_partial_write() {
1106+
fn test_rx_read_only_descriptor() {
1107+
let mem = single_region_mem(2 * MAX_BUFFER_SIZE);
1108+
let th = TestHelper::get_default(&mem);
1109+
rx_read_only_descriptor(th);
1110+
}
1111+
1112+
#[test]
1113+
fn test_rx_read_only_descriptor_mrg_buf() {
11031114
let mem = single_region_mem(2 * MAX_BUFFER_SIZE);
11041115
let mut th = TestHelper::get_default(&mem);
1116+
// VIRTIO_NET_F_MRG_RXBUF is not enabled by default
1117+
th.net().acked_features = 1 << VIRTIO_NET_F_MRG_RXBUF;
1118+
rx_read_only_descriptor(th);
1119+
}
1120+
1121+
fn rx_partial_write(mut th: TestHelper) {
11051122
th.activate_net();
11061123

11071124
// The descriptor chain is created so that the last descriptor doesn't fit in the
@@ -1123,9 +1140,22 @@ pub mod tests {
11231140
}
11241141

11251142
#[test]
1126-
fn test_rx_retry() {
1143+
fn test_rx_partial_write() {
1144+
let mem = single_region_mem(2 * MAX_BUFFER_SIZE);
1145+
let th = TestHelper::get_default(&mem);
1146+
rx_partial_write(th);
1147+
}
1148+
1149+
#[test]
1150+
fn test_rx_partial_write_mrg_buf() {
11271151
let mem = single_region_mem(2 * MAX_BUFFER_SIZE);
11281152
let mut th = TestHelper::get_default(&mem);
1153+
// VIRTIO_NET_F_MRG_RXBUF is not enabled by default
1154+
th.net().acked_features = 1 << VIRTIO_NET_F_MRG_RXBUF;
1155+
rx_partial_write(th);
1156+
}
1157+
1158+
fn rx_retry(mut th: TestHelper) {
11291159
th.activate_net();
11301160

11311161
// Even though too short descriptor chains are also
@@ -1175,9 +1205,22 @@ pub mod tests {
11751205
}
11761206

11771207
#[test]
1178-
fn test_rx_complex_desc_chain() {
1208+
fn test_rx_retry() {
1209+
let mem = single_region_mem(2 * MAX_BUFFER_SIZE);
1210+
let th = TestHelper::get_default(&mem);
1211+
rx_retry(th);
1212+
}
1213+
1214+
#[test]
1215+
fn test_rx_retry_mrg_buf() {
11791216
let mem = single_region_mem(2 * MAX_BUFFER_SIZE);
11801217
let mut th = TestHelper::get_default(&mem);
1218+
// VIRTIO_NET_F_MRG_RXBUF is not enabled by default
1219+
th.net().acked_features = 1 << VIRTIO_NET_F_MRG_RXBUF;
1220+
rx_retry(th);
1221+
}
1222+
1223+
fn rx_complex_desc_chain(mut th: TestHelper) {
11811224
th.activate_net();
11821225

11831226
// Create a valid Rx avail descriptor chain with multiple descriptors.
@@ -1214,9 +1257,22 @@ pub mod tests {
12141257
}
12151258

12161259
#[test]
1217-
fn test_rx_multiple_frames() {
1260+
fn test_rx_complex_desc_chain() {
1261+
let mem = single_region_mem(2 * MAX_BUFFER_SIZE);
1262+
let th = TestHelper::get_default(&mem);
1263+
rx_complex_desc_chain(th);
1264+
}
1265+
1266+
#[test]
1267+
fn test_rx_complex_desc_chain_mrg_buf() {
12181268
let mem = single_region_mem(2 * MAX_BUFFER_SIZE);
12191269
let mut th = TestHelper::get_default(&mem);
1270+
// VIRTIO_NET_F_MRG_RXBUF is not enabled by default
1271+
th.net().acked_features = 1 << VIRTIO_NET_F_MRG_RXBUF;
1272+
rx_complex_desc_chain(th);
1273+
}
1274+
1275+
fn rx_multiple_frames(mut th: TestHelper) {
12201276
th.activate_net();
12211277

12221278
// Create 2 valid Rx avail descriptor chains. Each one has enough space to fit the
@@ -1257,6 +1313,67 @@ pub mod tests {
12571313
th.rxq.dtable[3].check_data(&[0; 500]);
12581314
}
12591315

1316+
#[test]
1317+
fn test_rx_multiple_frames() {
1318+
let mem = single_region_mem(2 * MAX_BUFFER_SIZE);
1319+
let th = TestHelper::get_default(&mem);
1320+
rx_multiple_frames(th);
1321+
}
1322+
1323+
#[test]
1324+
fn test_rx_multiple_frames_mrg_buf() {
1325+
let mem = single_region_mem(2 * MAX_BUFFER_SIZE);
1326+
let mut th = TestHelper::get_default(&mem);
1327+
// VIRTIO_NET_F_MRG_RXBUF is not enabled by default
1328+
th.net().acked_features = 1 << VIRTIO_NET_F_MRG_RXBUF;
1329+
rx_multiple_frames(th);
1330+
}
1331+
1332+
#[test]
1333+
fn test_rx_multiple_frames_mrg() {
1334+
let mem = single_region_mem(2 * MAX_BUFFER_SIZE);
1335+
let mut th = TestHelper::get_default(&mem);
1336+
1337+
// VIRTIO_NET_F_MRG_RXBUF is not enabled by default
1338+
th.net().acked_features = 1 << VIRTIO_NET_F_MRG_RXBUF;
1339+
1340+
th.activate_net();
1341+
1342+
// Create 2 valid avail descriptor chains. We will send
1343+
// one packet that shuld be split amound these 2 chains.
1344+
th.add_desc_chain(
1345+
NetQueue::Rx,
1346+
0,
1347+
&[(0, 100, VIRTQ_DESC_F_WRITE), (1, 100, VIRTQ_DESC_F_WRITE)],
1348+
);
1349+
th.add_desc_chain(
1350+
NetQueue::Rx,
1351+
1000,
1352+
&[(2, 100, VIRTQ_DESC_F_WRITE), (3, 100, VIRTQ_DESC_F_WRITE)],
1353+
);
1354+
// Inject frame into tap and run epoll.
1355+
let mut frame = inject_tap_tx_frame(&th.net(), 400);
1356+
mock_frame_set_num_buffers(&mut frame, 2);
1357+
check_metric_after_block!(
1358+
th.net().metrics.rx_packets_count,
1359+
1,
1360+
th.event_manager.run_with_timeout(100).unwrap()
1361+
);
1362+
1363+
// Check that the frame wasn't deferred.
1364+
assert!(!th.net().rx_deferred_frame);
1365+
// Check that the used queue has advanced.
1366+
assert_eq!(th.rxq.used.idx.get(), 2);
1367+
assert!(&th.net().irq_trigger.has_pending_irq(IrqType::Vring));
1368+
// Check that the frame was written successfully into both descriptor chains.
1369+
th.rxq.check_used_elem(0, 0, 200);
1370+
th.rxq.check_used_elem(1, 2, 200);
1371+
th.rxq.dtable[0].check_data(&frame[0..100]);
1372+
th.rxq.dtable[1].check_data(&frame[100..200]);
1373+
th.rxq.dtable[2].check_data(&frame[200..300]);
1374+
th.rxq.dtable[3].check_data(&frame[300..400]);
1375+
}
1376+
12601377
#[test]
12611378
fn test_tx_missing_queue_signal() {
12621379
let mem = single_region_mem(2 * MAX_BUFFER_SIZE);

0 commit comments

Comments
 (0)