Skip to content

Commit 0a03a33

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 a267a0c commit 0a03a33

File tree

2 files changed

+301
-33
lines changed

2 files changed

+301
-33
lines changed

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

Lines changed: 133 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use crate::devices::virtio::gen::virtio_blk::VIRTIO_F_VERSION_1;
2020
use crate::devices::virtio::gen::virtio_net::{
2121
virtio_net_hdr_v1, VIRTIO_NET_F_CSUM, VIRTIO_NET_F_GUEST_CSUM, VIRTIO_NET_F_GUEST_TSO4,
2222
VIRTIO_NET_F_GUEST_TSO6, VIRTIO_NET_F_GUEST_UFO, VIRTIO_NET_F_HOST_TSO4,
23-
VIRTIO_NET_F_HOST_TSO6, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_MAC,
23+
VIRTIO_NET_F_HOST_TSO6, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_MAC, VIRTIO_NET_F_MRG_RXBUF,
2424
};
2525
use crate::devices::virtio::gen::virtio_ring::VIRTIO_RING_F_EVENT_IDX;
2626
use crate::devices::virtio::iovec::IoVecBuffer;
@@ -150,6 +150,7 @@ impl Net {
150150
| 1 << VIRTIO_NET_F_HOST_TSO6
151151
| 1 << VIRTIO_NET_F_HOST_UFO
152152
| 1 << VIRTIO_F_VERSION_1
153+
| 1 << VIRTIO_NET_F_MRG_RXBUF
153154
| 1 << VIRTIO_RING_F_EVENT_IDX;
154155

155156
let mut config_space = ConfigSpace::default();
@@ -646,7 +647,11 @@ impl Net {
646647
}
647648

648649
fn read_tap(&mut self) -> std::io::Result<usize> {
649-
self.tap.read_iovec(self.rx_buffer.one_chain_mut_slice())
650+
if self.has_feature(u64::from(VIRTIO_NET_F_MRG_RXBUF)) {
651+
self.tap.read_iovec(self.rx_buffer.all_chains_mut_slice())
652+
} else {
653+
self.tap.read_iovec(self.rx_buffer.one_chain_mut_slice())
654+
}
650655
}
651656

652657
/// Process a single RX queue event.
@@ -858,7 +863,7 @@ pub mod tests {
858863
use crate::devices::virtio::net::device::{
859864
frame_bytes_from_buf, frame_bytes_from_buf_mut, frame_hdr_len, init_vnet_hdr, vnet_hdr_len,
860865
};
861-
use crate::devices::virtio::net::rx_buffer::ChainInfo;
866+
use crate::devices::virtio::net::rx_buffer::{header_set_num_buffers, ChainInfo};
862867
use crate::devices::virtio::net::test_utils::test::TestHelper;
863868
use crate::devices::virtio::net::test_utils::{
864869
default_net, if_index, inject_tap_tx_frame, set_mac, NetEvent, NetQueue,
@@ -925,6 +930,7 @@ pub mod tests {
925930
| 1 << VIRTIO_NET_F_HOST_TSO6
926931
| 1 << VIRTIO_NET_F_HOST_UFO
927932
| 1 << VIRTIO_F_VERSION_1
933+
| 1 << VIRTIO_NET_F_MRG_RXBUF
928934
| 1 << VIRTIO_RING_F_EVENT_IDX;
929935

930936
assert_eq!(
@@ -1046,10 +1052,9 @@ pub mod tests {
10461052
assert_eq!(th.rxq.used.idx.get(), 0);
10471053
}
10481054

1049-
#[test]
1050-
fn test_rx_read_only_descriptor() {
1051-
let mem = single_region_mem(2 * MAX_BUFFER_SIZE);
1052-
let mut th = TestHelper::get_default(&mem);
1055+
fn rx_read_only_descriptor(mut th: TestHelper) {
1056+
// let mem = single_region_mem(2 * MAX_BUFFER_SIZE);
1057+
// let mut th = TestHelper::get_default(&mem);
10531058
th.activate_net();
10541059

10551060
th.add_desc_chain(
@@ -1068,9 +1073,22 @@ pub mod tests {
10681073
}
10691074

10701075
#[test]
1071-
fn test_rx_partial_write() {
1076+
fn test_rx_read_only_descriptor() {
1077+
let mem = single_region_mem(2 * MAX_BUFFER_SIZE);
1078+
let th = TestHelper::get_default(&mem);
1079+
rx_read_only_descriptor(th);
1080+
}
1081+
1082+
#[test]
1083+
fn test_rx_read_only_descriptor_mrg_buf() {
10721084
let mem = single_region_mem(2 * MAX_BUFFER_SIZE);
10731085
let mut th = TestHelper::get_default(&mem);
1086+
// VIRTIO_NET_F_MRG_RXBUF is not enabled by default
1087+
th.net().acked_features = 1 << VIRTIO_NET_F_MRG_RXBUF;
1088+
rx_read_only_descriptor(th);
1089+
}
1090+
1091+
fn rx_partial_write(mut th: TestHelper) {
10741092
th.activate_net();
10751093

10761094
// The descriptor chain is created so that the last descriptor doesn't fit in the
@@ -1092,9 +1110,22 @@ pub mod tests {
10921110
}
10931111

10941112
#[test]
1095-
fn test_rx_retry() {
1113+
fn test_rx_partial_write() {
1114+
let mem = single_region_mem(2 * MAX_BUFFER_SIZE);
1115+
let th = TestHelper::get_default(&mem);
1116+
rx_partial_write(th);
1117+
}
1118+
1119+
#[test]
1120+
fn test_rx_partial_write_mrg_buf() {
10961121
let mem = single_region_mem(2 * MAX_BUFFER_SIZE);
10971122
let mut th = TestHelper::get_default(&mem);
1123+
// VIRTIO_NET_F_MRG_RXBUF is not enabled by default
1124+
th.net().acked_features = 1 << VIRTIO_NET_F_MRG_RXBUF;
1125+
rx_partial_write(th);
1126+
}
1127+
1128+
fn rx_retry(mut th: TestHelper) {
10981129
th.activate_net();
10991130

11001131
// Even though too short descriptor chains are also
@@ -1144,9 +1175,22 @@ pub mod tests {
11441175
}
11451176

11461177
#[test]
1147-
fn test_rx_complex_desc_chain() {
1178+
fn test_rx_retry() {
1179+
let mem = single_region_mem(2 * MAX_BUFFER_SIZE);
1180+
let th = TestHelper::get_default(&mem);
1181+
rx_retry(th);
1182+
}
1183+
1184+
#[test]
1185+
fn test_rx_retry_mrg_buf() {
11481186
let mem = single_region_mem(2 * MAX_BUFFER_SIZE);
11491187
let mut th = TestHelper::get_default(&mem);
1188+
// VIRTIO_NET_F_MRG_RXBUF is not enabled by default
1189+
th.net().acked_features = 1 << VIRTIO_NET_F_MRG_RXBUF;
1190+
rx_retry(th);
1191+
}
1192+
1193+
fn rx_complex_desc_chain(mut th: TestHelper) {
11501194
th.activate_net();
11511195

11521196
// Create a valid Rx avail descriptor chain with multiple descriptors.
@@ -1183,9 +1227,22 @@ pub mod tests {
11831227
}
11841228

11851229
#[test]
1186-
fn test_rx_multiple_frames() {
1230+
fn test_rx_complex_desc_chain() {
1231+
let mem = single_region_mem(2 * MAX_BUFFER_SIZE);
1232+
let th = TestHelper::get_default(&mem);
1233+
rx_complex_desc_chain(th);
1234+
}
1235+
1236+
#[test]
1237+
fn test_rx_complex_desc_chain_mrg_buf() {
11871238
let mem = single_region_mem(2 * MAX_BUFFER_SIZE);
11881239
let mut th = TestHelper::get_default(&mem);
1240+
// VIRTIO_NET_F_MRG_RXBUF is not enabled by default
1241+
th.net().acked_features = 1 << VIRTIO_NET_F_MRG_RXBUF;
1242+
rx_complex_desc_chain(th);
1243+
}
1244+
1245+
fn rx_multiple_frames(mut th: TestHelper) {
11891246
th.activate_net();
11901247

11911248
// Create 2 valid Rx avail descriptor chains. Each one has enough space to fit the
@@ -1226,6 +1283,70 @@ pub mod tests {
12261283
th.rxq.dtable[3].check_data(&[0; 500]);
12271284
}
12281285

1286+
#[test]
1287+
fn test_rx_multiple_frames() {
1288+
let mem = single_region_mem(2 * MAX_BUFFER_SIZE);
1289+
let th = TestHelper::get_default(&mem);
1290+
rx_multiple_frames(th);
1291+
}
1292+
1293+
#[test]
1294+
fn test_rx_multiple_frames_mrg_buf() {
1295+
let mem = single_region_mem(2 * MAX_BUFFER_SIZE);
1296+
let mut th = TestHelper::get_default(&mem);
1297+
// VIRTIO_NET_F_MRG_RXBUF is not enabled by default
1298+
th.net().acked_features = 1 << VIRTIO_NET_F_MRG_RXBUF;
1299+
rx_multiple_frames(th);
1300+
}
1301+
1302+
#[test]
1303+
fn test_rx_multiple_frames_mrg() {
1304+
let mem = single_region_mem(2 * MAX_BUFFER_SIZE);
1305+
let mut th = TestHelper::get_default(&mem);
1306+
1307+
// VIRTIO_NET_F_MRG_RXBUF is not enabled by default
1308+
th.net().acked_features = 1 << VIRTIO_NET_F_MRG_RXBUF;
1309+
1310+
th.activate_net();
1311+
1312+
// Create 2 valid avail descriptor chains. We will send
1313+
// one packet that shuld be split amound these 2 chains.
1314+
th.add_desc_chain(
1315+
NetQueue::Rx,
1316+
0,
1317+
&[(0, 100, VIRTQ_DESC_F_WRITE), (1, 100, VIRTQ_DESC_F_WRITE)],
1318+
);
1319+
th.add_desc_chain(
1320+
NetQueue::Rx,
1321+
1000,
1322+
&[(2, 100, VIRTQ_DESC_F_WRITE), (3, 100, VIRTQ_DESC_F_WRITE)],
1323+
);
1324+
// Inject frame into tap and run epoll.
1325+
let mut frame = inject_tap_tx_frame(&th.net(), 400);
1326+
// SAFETY: frame is big enough and has correct alingment.
1327+
unsafe {
1328+
header_set_num_buffers(frame.as_mut_ptr().cast(), 2);
1329+
}
1330+
check_metric_after_block!(
1331+
th.net().metrics.rx_packets_count,
1332+
1,
1333+
th.event_manager.run_with_timeout(100).unwrap()
1334+
);
1335+
1336+
// Check that the frame wasn't deferred.
1337+
assert!(th.net().deferred_rx_bytes.is_none());
1338+
// Check that the used queue has advanced.
1339+
assert_eq!(th.rxq.used.idx.get(), 2);
1340+
assert!(&th.net().irq_trigger.has_pending_irq(IrqType::Vring));
1341+
// Check that the frame was written successfully into both descriptor chains.
1342+
th.rxq.check_used_elem(0, 0, 200);
1343+
th.rxq.check_used_elem(1, 2, 200);
1344+
th.rxq.dtable[0].check_data(&frame[0..100]);
1345+
th.rxq.dtable[1].check_data(&frame[100..200]);
1346+
th.rxq.dtable[2].check_data(&frame[200..300]);
1347+
th.rxq.dtable[3].check_data(&frame[300..400]);
1348+
}
1349+
12291350
#[test]
12301351
fn test_tx_missing_queue_signal() {
12311352
let mem = single_region_mem(2 * MAX_BUFFER_SIZE);
@@ -1520,6 +1641,7 @@ pub mod tests {
15201641
net.rx_buffer.chain_infos.push_back(ChainInfo {
15211642
head_index: 0,
15221643
chain_len: 1,
1644+
chain_capacity: 128,
15231645
});
15241646

15251647
let src_mac = MacAddr::from_str("11:11:11:11:11:11").unwrap();

0 commit comments

Comments
 (0)