Skip to content

Commit ed54276

Browse files
Nikita Zakirovgit-Zink
authored andcommitted
fix(net): Apply only supported TAP offloading features
virtio-net driver may not support all offloading features supported by a TAP device. This commit setup only those features, that got acknowledged by the driver. Signed-off-by: Nikita Zakirov <[email protected]>
1 parent 826831d commit ed54276

File tree

3 files changed

+92
-10
lines changed

3 files changed

+92
-10
lines changed

src/vmm/src/devices/virtio/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
use std::any::Any;
1111
use std::io::Error as IOError;
1212

13+
use crate::devices::virtio::net::TapError;
14+
1315
pub mod balloon;
1416
pub mod block_common;
1517
pub mod device;
@@ -68,6 +70,8 @@ pub enum ActivateError {
6870
BadActivate,
6971
/// Vhost user: {0}
7072
VhostUser(vhost_user::VhostUserError),
73+
/// Setting tap interface offload flags failed: {0}
74+
TapSetOffload(TapError),
7175
}
7276

7377
/// Trait that helps in upcasting an object to Any

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

Lines changed: 88 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,10 @@ use vm_memory::GuestMemoryError;
2323
use crate::devices::virtio::device::{DeviceState, IrqTrigger, IrqType, VirtioDevice};
2424
use crate::devices::virtio::gen::virtio_blk::VIRTIO_F_VERSION_1;
2525
use crate::devices::virtio::gen::virtio_net::{
26-
virtio_net_hdr_v1, VIRTIO_NET_F_CSUM, VIRTIO_NET_F_GUEST_CSUM, VIRTIO_NET_F_GUEST_TSO4,
27-
VIRTIO_NET_F_GUEST_UFO, VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_MAC,
26+
virtio_net_hdr_v1, VIRTIO_NET_F_CSUM, VIRTIO_NET_F_GUEST_CSUM, VIRTIO_NET_F_GUEST_ECN,
27+
VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_TSO6, VIRTIO_NET_F_GUEST_UFO,
28+
VIRTIO_NET_F_HOST_ECN, VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_TSO6, VIRTIO_NET_F_HOST_UFO,
29+
VIRTIO_NET_F_MAC,
2830
};
2931
use crate::devices::virtio::gen::virtio_ring::VIRTIO_RING_F_EVENT_IDX;
3032
use crate::devices::virtio::iovec::IoVecBuffer;
@@ -160,7 +162,11 @@ impl Net {
160162
| 1 << VIRTIO_NET_F_HOST_TSO4
161163
| 1 << VIRTIO_NET_F_HOST_UFO
162164
| 1 << VIRTIO_F_VERSION_1
163-
| 1 << VIRTIO_RING_F_EVENT_IDX;
165+
| 1 << VIRTIO_RING_F_EVENT_IDX
166+
| 1 << VIRTIO_NET_F_GUEST_TSO6
167+
| 1 << VIRTIO_NET_F_HOST_TSO6
168+
| 1 << VIRTIO_NET_F_GUEST_ECN
169+
| 1 << VIRTIO_NET_F_HOST_ECN;
164170

165171
let mut config_space = ConfigSpace::default();
166172
if let Some(mac) = guest_mac {
@@ -210,10 +216,6 @@ impl Net {
210216
) -> Result<Self, NetError> {
211217
let tap = Tap::open_named(tap_if_name).map_err(NetError::TapOpen)?;
212218

213-
// Set offload flags to match the virtio features below.
214-
tap.set_offload(gen::TUN_F_CSUM | gen::TUN_F_UFO | gen::TUN_F_TSO4 | gen::TUN_F_TSO6)
215-
.map_err(NetError::TapSetOffload)?;
216-
217219
let vnet_hdr_size = i32::try_from(vnet_hdr_len()).unwrap();
218220
tap.set_vnet_hdr_size(vnet_hdr_size)
219221
.map_err(NetError::TapSetVnetHdrSize)?;
@@ -644,6 +646,44 @@ impl Net {
644646
}
645647
}
646648

649+
fn build_tap_supported_features(virtio_supported_features: u64) -> u32 {
650+
let add_if_supported =
651+
|tap_features: &mut u32, virtio_features: u64, tap_flag: u32, virtio_flag: u32| {
652+
if virtio_features & (1 << virtio_flag) != 0 {
653+
*tap_features |= tap_flag;
654+
}
655+
};
656+
657+
let mut tap_features: u32 = 0;
658+
659+
add_if_supported(
660+
&mut tap_features,
661+
virtio_supported_features,
662+
gen::TUN_F_CSUM,
663+
VIRTIO_NET_F_CSUM,
664+
);
665+
add_if_supported(
666+
&mut tap_features,
667+
virtio_supported_features,
668+
gen::TUN_F_UFO,
669+
VIRTIO_NET_F_GUEST_UFO,
670+
);
671+
add_if_supported(
672+
&mut tap_features,
673+
virtio_supported_features,
674+
gen::TUN_F_TSO4,
675+
VIRTIO_NET_F_GUEST_TSO4,
676+
);
677+
add_if_supported(
678+
&mut tap_features,
679+
virtio_supported_features,
680+
gen::TUN_F_TSO6,
681+
VIRTIO_NET_F_GUEST_TSO6,
682+
);
683+
684+
tap_features
685+
}
686+
647687
/// Updates the parameters for the rate limiters
648688
pub fn patch_rate_limiters(
649689
&mut self,
@@ -859,6 +899,11 @@ impl VirtioDevice for Net {
859899
}
860900
}
861901

902+
let supported_flags: u32 = Net::build_tap_supported_features(self.acked_features);
903+
self.tap
904+
.set_offload(supported_flags)
905+
.map_err(super::super::ActivateError::TapSetOffload)?;
906+
862907
if self.activate_evt.write(1).is_err() {
863908
error!("Net: Cannot write to activate_evt");
864909
return Err(super::super::ActivateError::BadActivate);
@@ -978,7 +1023,11 @@ pub mod tests {
9781023
| 1 << VIRTIO_NET_F_HOST_TSO4
9791024
| 1 << VIRTIO_NET_F_HOST_UFO
9801025
| 1 << VIRTIO_F_VERSION_1
981-
| 1 << VIRTIO_RING_F_EVENT_IDX;
1026+
| 1 << VIRTIO_RING_F_EVENT_IDX
1027+
| 1 << VIRTIO_NET_F_GUEST_TSO6
1028+
| 1 << VIRTIO_NET_F_HOST_TSO6
1029+
| 1 << VIRTIO_NET_F_GUEST_ECN
1030+
| 1 << VIRTIO_NET_F_HOST_ECN;
9821031

9831032
assert_eq!(
9841033
net.avail_features_by_page(0),
@@ -996,6 +1045,37 @@ pub mod tests {
9961045
assert_eq!(net.acked_features, features);
9971046
}
9981047

1048+
#[test]
1049+
// We can't get offload features, that were set up to a TAP device by ioctl,
1050+
// hence that we have to validate, that we sort out unsupported features correctly
1051+
fn test_build_tap_supported_features_all() {
1052+
let supported_features = 1 << VIRTIO_NET_F_CSUM
1053+
| 1 << VIRTIO_NET_F_GUEST_UFO
1054+
| 1 << VIRTIO_NET_F_GUEST_TSO4
1055+
| 1 << VIRTIO_NET_F_GUEST_TSO6;
1056+
1057+
let expected_tap_features =
1058+
gen::TUN_F_CSUM | gen::TUN_F_UFO | gen::TUN_F_TSO4 | gen::TUN_F_TSO6;
1059+
1060+
let supported_flags = Net::build_tap_supported_features(supported_features);
1061+
1062+
assert_eq!(supported_flags, expected_tap_features);
1063+
}
1064+
1065+
#[test]
1066+
fn test_build_tap_supported_features_one_by_one() {
1067+
let features = [
1068+
(1 << VIRTIO_NET_F_CSUM, gen::TUN_F_CSUM),
1069+
(1 << VIRTIO_NET_F_GUEST_UFO, gen::TUN_F_UFO),
1070+
(1 << VIRTIO_NET_F_GUEST_TSO4, gen::TUN_F_TSO4),
1071+
(1 << VIRTIO_NET_F_GUEST_TSO6, gen::TUN_F_TSO6),
1072+
];
1073+
for (virtio_flag, tap_flag) in features {
1074+
let supported_flags = Net::build_tap_supported_features(virtio_flag);
1075+
assert_eq!(supported_flags, tap_flag);
1076+
}
1077+
}
1078+
9991079
#[test]
10001080
fn test_virtio_device_read_config() {
10011081
let mut net = default_net();

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,6 @@ pub enum NetQueue {
4545
pub enum NetError {
4646
/// Open tap device failed: {0}
4747
TapOpen(TapError),
48-
/// Setting tap interface offload flags failed: {0}
49-
TapSetOffload(TapError),
5048
/// Setting vnet header size failed: {0}
5149
TapSetVnetHdrSize(TapError),
5250
/// EventFd error: {0}

0 commit comments

Comments
 (0)