@@ -1046,8 +1046,8 @@ pub mod tests {
1046
1046
} ;
1047
1047
use crate :: devices:: virtio:: net:: test_utils:: test:: TestHelper ;
1048
1048
use crate :: devices:: virtio:: net:: test_utils:: {
1049
- default_net, if_index, inject_tap_tx_frame, set_mac , NetEvent , NetQueue , ReadTapMock ,
1050
- TapTrafficSimulator , WriteTapMock ,
1049
+ default_net, if_index, inject_tap_tx_frame, mock_frame_set_num_buffers , set_mac , NetEvent ,
1050
+ NetQueue , ReadTapMock , TapTrafficSimulator , WriteTapMock ,
1051
1051
} ;
1052
1052
use crate :: devices:: virtio:: net:: NET_QUEUE_SIZES ;
1053
1053
use crate :: devices:: virtio:: queue:: VIRTQ_DESC_F_WRITE ;
@@ -1288,7 +1288,40 @@ pub mod tests {
1288
1288
}
1289
1289
1290
1290
#[ test]
1291
- fn test_rx_partial_write ( ) {
1291
+ fn test_rx_mrg_buf_multiple_short_writable_descriptors ( ) {
1292
+ let mut th = TestHelper :: get_default ( ) ;
1293
+ th. activate_net ( ) ;
1294
+ th. net ( ) . tap . mocks . set_read_tap ( ReadTapMock :: TapFrame ) ;
1295
+
1296
+ // VIRTIO_NET_F_MRG_RXBUF is not enabled by default
1297
+ th. net ( ) . acked_features = 1 << VIRTIO_NET_F_MRG_RXBUF ;
1298
+
1299
+ th. add_desc_chain ( NetQueue :: Rx , 0 , & [ ( 0 , 500 , VIRTQ_DESC_F_WRITE ) ] ) ;
1300
+ th. add_desc_chain ( NetQueue :: Rx , 500 , & [ ( 1 , 500 , VIRTQ_DESC_F_WRITE ) ] ) ;
1301
+
1302
+ // There will be 2 heads used.
1303
+ let mut frame = inject_tap_tx_frame ( & th. net ( ) , 1000 ) ;
1304
+ mock_frame_set_num_buffers ( & mut frame, 2 ) ;
1305
+
1306
+ check_metric_after_block ! (
1307
+ th. net( ) . metrics. rx_packets_count,
1308
+ 1 ,
1309
+ th. event_manager. run_with_timeout( 100 ) . unwrap( )
1310
+ ) ;
1311
+
1312
+ assert_eq ! ( th. rxq. used. idx. get( ) , 2 ) ;
1313
+ assert ! ( th. net( ) . irq_trigger. has_pending_irq( IrqType :: Vring ) ) ;
1314
+ assert ! ( !th. net( ) . rx_deferred_frame) ;
1315
+
1316
+ th. rxq . check_used_elem ( 0 , 0 , 500 ) ;
1317
+ th. rxq . check_used_elem ( 1 , 1 , 500 ) ;
1318
+
1319
+ th. rxq . dtable [ 0 ] . check_data ( & frame[ ..500 ] ) ;
1320
+ th. rxq . dtable [ 1 ] . check_data ( & frame[ 500 ..] ) ;
1321
+ }
1322
+
1323
+ #[ test]
1324
+ fn test_rx_invalid_desc_chain ( ) {
1292
1325
let mut th = TestHelper :: get_default ( ) ;
1293
1326
th. activate_net ( ) ;
1294
1327
@@ -1310,6 +1343,79 @@ pub mod tests {
1310
1343
th. check_rx_queue_resume ( & frame) ;
1311
1344
}
1312
1345
1346
+ #[ test]
1347
+ fn test_rx_mrg_buf_invalid_desc_chain ( ) {
1348
+ let mut th = TestHelper :: get_default ( ) ;
1349
+ th. activate_net ( ) ;
1350
+
1351
+ // VIRTIO_NET_F_MRG_RXBUF is not enabled by default
1352
+ th. net ( ) . acked_features = 1 << VIRTIO_NET_F_MRG_RXBUF ;
1353
+
1354
+ // The descriptor chain is created so that the last descriptor doesn't fit in the
1355
+ // guest memory.
1356
+ let offset = th. mem . last_addr ( ) . raw_value ( ) - th. data_addr ( ) - 300 ;
1357
+ th. add_desc_chain (
1358
+ NetQueue :: Rx ,
1359
+ offset,
1360
+ & [
1361
+ ( 0 , 100 , VIRTQ_DESC_F_WRITE ) ,
1362
+ ( 1 , 50 , VIRTQ_DESC_F_WRITE ) ,
1363
+ ( 2 , 4096 , VIRTQ_DESC_F_WRITE ) ,
1364
+ ] ,
1365
+ ) ;
1366
+ let frame = th. check_rx_deferred_frame ( 1000 ) ;
1367
+ th. rxq . check_used_elem ( 0 , 0 , 0 ) ;
1368
+
1369
+ th. check_rx_queue_resume ( & frame) ;
1370
+ }
1371
+
1372
+ #[ test]
1373
+ fn test_rx_mrg_buf_partial_write ( ) {
1374
+ let mut th = TestHelper :: get_default ( ) ;
1375
+ th. activate_net ( ) ;
1376
+ th. net ( ) . tap . mocks . set_read_tap ( ReadTapMock :: TapFrame ) ;
1377
+
1378
+ // VIRTIO_NET_F_MRG_RXBUF is not enabled by default
1379
+ th. net ( ) . acked_features = 1 << VIRTIO_NET_F_MRG_RXBUF ;
1380
+
1381
+ // Add descriptor that is not big enough to store the
1382
+ // whole packet.
1383
+ th. add_desc_chain ( NetQueue :: Rx , 0 , & [ ( 0 , 500 , VIRTQ_DESC_F_WRITE ) ] ) ;
1384
+
1385
+ // There will be 2 heads used.
1386
+ let mut frame = inject_tap_tx_frame ( & th. net ( ) , 1000 ) ;
1387
+ mock_frame_set_num_buffers ( & mut frame, 2 ) ;
1388
+
1389
+ // For now only 1 descriptor chain is used,
1390
+ // but the packet is not fully written yet.
1391
+ check_metric_after_block ! (
1392
+ th. net( ) . metrics. rx_packets_count,
1393
+ 0 ,
1394
+ th. event_manager. run_with_timeout( 100 ) . unwrap( )
1395
+ ) ;
1396
+ th. rxq . check_used_elem ( 0 , 0 , 500 ) ;
1397
+
1398
+ // The write was converted to partial write
1399
+ assert ! ( th. net( ) . rx_partial_write. is_some( ) ) ;
1400
+
1401
+ // Continuing writing.
1402
+ th. add_desc_chain ( NetQueue :: Rx , 500 , & [ ( 1 , 500 , VIRTQ_DESC_F_WRITE ) ] ) ;
1403
+ check_metric_after_block ! (
1404
+ th. net( ) . metrics. rx_packets_count,
1405
+ 1 ,
1406
+ th. event_manager. run_with_timeout( 100 ) . unwrap( )
1407
+ ) ;
1408
+ assert ! ( th. net( ) . rx_partial_write. is_none( ) ) ;
1409
+ assert_eq ! ( th. rxq. used. idx. get( ) , 2 ) ;
1410
+ assert ! ( th. net( ) . irq_trigger. has_pending_irq( IrqType :: Vring ) ) ;
1411
+
1412
+ th. rxq . check_used_elem ( 0 , 0 , 500 ) ;
1413
+ th. rxq . check_used_elem ( 1 , 1 , 500 ) ;
1414
+
1415
+ th. rxq . dtable [ 0 ] . check_data ( & frame[ ..500 ] ) ;
1416
+ th. rxq . dtable [ 1 ] . check_data ( & frame[ 500 ..] ) ;
1417
+ }
1418
+
1313
1419
#[ test]
1314
1420
fn test_rx_retry ( ) {
1315
1421
let mut th = TestHelper :: get_default ( ) ;
@@ -1361,6 +1467,62 @@ pub mod tests {
1361
1467
th. rxq . dtable [ 5 ] . check_data ( & frame) ;
1362
1468
}
1363
1469
1470
+ #[ test]
1471
+ fn test_rx_mrg_buf_retry ( ) {
1472
+ let mut th = TestHelper :: get_default ( ) ;
1473
+ th. activate_net ( ) ;
1474
+ th. net ( ) . tap . mocks . set_read_tap ( ReadTapMock :: TapFrame ) ;
1475
+
1476
+ // VIRTIO_NET_F_MRG_RXBUF is not enabled by default
1477
+ th. net ( ) . acked_features = 1 << VIRTIO_NET_F_MRG_RXBUF ;
1478
+
1479
+ // Add invalid descriptor chain - read only descriptor.
1480
+ th. add_desc_chain (
1481
+ NetQueue :: Rx ,
1482
+ 0 ,
1483
+ & [
1484
+ ( 0 , 100 , VIRTQ_DESC_F_WRITE ) ,
1485
+ ( 1 , 100 , 0 ) ,
1486
+ ( 2 , 1000 , VIRTQ_DESC_F_WRITE ) ,
1487
+ ] ,
1488
+ ) ;
1489
+ // Add valid descriptor chain but too short. This one will be used
1490
+ // and the write will be converted to partial write.
1491
+ th. add_desc_chain ( NetQueue :: Rx , 1200 , & [ ( 3 , 100 , VIRTQ_DESC_F_WRITE ) ] ) ;
1492
+ // Add invalid descriptor chain - invalid memory offset.
1493
+ // The partial write stated with previous descriptor should halt here.
1494
+ th. add_desc_chain (
1495
+ NetQueue :: Rx ,
1496
+ th. mem . last_addr ( ) . raw_value ( ) ,
1497
+ & [ ( 4 , 1000 , VIRTQ_DESC_F_WRITE ) ] ,
1498
+ ) ;
1499
+
1500
+ // Add valid descriptor chain.
1501
+ th. add_desc_chain ( NetQueue :: Rx , 1300 , & [ ( 5 , 1000 , VIRTQ_DESC_F_WRITE ) ] ) ;
1502
+
1503
+ // Inject frame to tap and run epoll.
1504
+ let frame = inject_tap_tx_frame ( & th. net ( ) , 1000 ) ;
1505
+ check_metric_after_block ! (
1506
+ th. net( ) . metrics. rx_packets_count,
1507
+ 1 ,
1508
+ th. event_manager. run_with_timeout( 100 ) . unwrap( )
1509
+ ) ;
1510
+
1511
+ // Check that the used queue has advanced.
1512
+ assert_eq ! ( th. rxq. used. idx. get( ) , 4 ) ;
1513
+ assert ! ( & th. net( ) . irq_trigger. has_pending_irq( IrqType :: Vring ) ) ;
1514
+ // Check that the invalid descriptor chains have been discarded
1515
+ th. rxq . check_used_elem ( 0 , 0 , 0 ) ;
1516
+ th. rxq . check_used_elem ( 1 , 3 , 0 ) ;
1517
+ th. rxq . check_used_elem ( 2 , 4 , 0 ) ;
1518
+ // Check that the frame wasn't deferred.
1519
+ assert ! ( !th. net( ) . rx_deferred_frame) ;
1520
+ // Check that the frame has been written successfully to the valid Rx descriptor chain.
1521
+ th. rxq
1522
+ . check_used_elem ( 3 , 5 , frame. len ( ) . try_into ( ) . unwrap ( ) ) ;
1523
+ th. rxq . dtable [ 5 ] . check_data ( & frame) ;
1524
+ }
1525
+
1364
1526
#[ test]
1365
1527
fn test_rx_complex_desc_chain ( ) {
1366
1528
let mut th = TestHelper :: get_default ( ) ;
0 commit comments