Skip to content

Commit 1e5d3db

Browse files
Nikita Zakirovbchalios
Nikita Zakirov
authored andcommitted
fix(net): Apply only supported TAP offloading features
Currently, we assume that the guest virtio-net driver acknowledges all the offload features we offer to it and then subsequently set the corresponding TAP features. This might be the case for the Linux guest kernel drivers we are currently using, but it is not necessarily the case. FreeBSD for example, might try to NACK some of them in some cases: #3905. This commit, changes the Firecracker implementation of VirtIO device to only setup the TAP offload features that correspond to the ones that the guest driver acknowledged. Signed-off-by: Nikita Zakirov <[email protected]> Signed-off-by: Babis Chalios <[email protected]>
1 parent cc78a1e commit 1e5d3db

File tree

3 files changed

+69
-6
lines changed

3 files changed

+69
-6
lines changed

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

+4
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
1010
use std::any::Any;
1111

12+
use crate::devices::virtio::net::TapError;
13+
1214
pub mod balloon;
1315
pub mod block;
1416
pub mod device;
@@ -66,6 +68,8 @@ pub enum ActivateError {
6668
EventFd,
6769
/// Vhost user: {0}
6870
VhostUser(vhost_user::VhostUserError),
71+
/// Setting tap interface offload flags failed: {0}
72+
TapSetOffload(TapError),
6973
}
7074

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

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

+65-4
Original file line numberDiff line numberDiff line change
@@ -209,10 +209,6 @@ impl Net {
209209
) -> Result<Self, NetError> {
210210
let tap = Tap::open_named(tap_if_name).map_err(NetError::TapOpen)?;
211211

212-
// Set offload flags to match the virtio features below.
213-
tap.set_offload(gen::TUN_F_CSUM | gen::TUN_F_UFO | gen::TUN_F_TSO4 | gen::TUN_F_TSO6)
214-
.map_err(NetError::TapSetOffload)?;
215-
216212
let vnet_hdr_size = i32::try_from(vnet_hdr_len()).unwrap();
217213
tap.set_vnet_hdr_size(vnet_hdr_size)
218214
.map_err(NetError::TapSetVnetHdrSize)?;
@@ -658,6 +654,40 @@ impl Net {
658654
}
659655
}
660656

657+
/// Builds the offload features we will setup on the TAP device based on the features that the
658+
/// guest supports.
659+
fn build_tap_offload_features(guest_supported_features: u64) -> u32 {
660+
let add_if_supported =
661+
|tap_features: &mut u32, supported_features: u64, tap_flag: u32, virtio_flag: u32| {
662+
if supported_features & (1 << virtio_flag) != 0 {
663+
*tap_features |= tap_flag;
664+
}
665+
};
666+
667+
let mut tap_features: u32 = 0;
668+
669+
add_if_supported(
670+
&mut tap_features,
671+
guest_supported_features,
672+
gen::TUN_F_CSUM,
673+
VIRTIO_NET_F_CSUM,
674+
);
675+
add_if_supported(
676+
&mut tap_features,
677+
guest_supported_features,
678+
gen::TUN_F_UFO,
679+
VIRTIO_NET_F_GUEST_UFO,
680+
);
681+
add_if_supported(
682+
&mut tap_features,
683+
guest_supported_features,
684+
gen::TUN_F_TSO4,
685+
VIRTIO_NET_F_GUEST_TSO4,
686+
);
687+
688+
tap_features
689+
}
690+
661691
/// Updates the parameters for the rate limiters
662692
pub fn patch_rate_limiters(
663693
&mut self,
@@ -861,6 +891,11 @@ impl VirtioDevice for Net {
861891
}
862892
}
863893

894+
let supported_flags: u32 = Net::build_tap_offload_features(self.acked_features);
895+
self.tap
896+
.set_offload(supported_flags)
897+
.map_err(super::super::ActivateError::TapSetOffload)?;
898+
864899
if self.activate_evt.write(1).is_err() {
865900
self.metrics.activate_fails.inc();
866901
return Err(ActivateError::EventFd);
@@ -998,6 +1033,32 @@ pub mod tests {
9981033
assert_eq!(net.acked_features, features);
9991034
}
10001035

1036+
#[test]
1037+
// Test that `Net::build_tap_offload_features` creates the TAP offload features that we expect
1038+
// it to do, based on the available guest features
1039+
fn test_build_tap_offload_features_all() {
1040+
let supported_features =
1041+
1 << VIRTIO_NET_F_CSUM | 1 << VIRTIO_NET_F_GUEST_UFO | 1 << VIRTIO_NET_F_GUEST_TSO4;
1042+
let expected_tap_features = gen::TUN_F_CSUM | gen::TUN_F_UFO | gen::TUN_F_TSO4;
1043+
let supported_flags = Net::build_tap_offload_features(supported_features);
1044+
1045+
assert_eq!(supported_flags, expected_tap_features);
1046+
}
1047+
1048+
#[test]
1049+
// Same as before, however, using each supported feature one by one.
1050+
fn test_build_tap_offload_features_one_by_one() {
1051+
let features = [
1052+
(1 << VIRTIO_NET_F_CSUM, gen::TUN_F_CSUM),
1053+
(1 << VIRTIO_NET_F_GUEST_UFO, gen::TUN_F_UFO),
1054+
(1 << VIRTIO_NET_F_GUEST_TSO4, gen::TUN_F_TSO4),
1055+
];
1056+
for (virtio_flag, tap_flag) in features {
1057+
let supported_flags = Net::build_tap_offload_features(virtio_flag);
1058+
assert_eq!(supported_flags, tap_flag);
1059+
}
1060+
}
1061+
10011062
#[test]
10021063
fn test_virtio_device_read_config() {
10031064
let mut net = default_net();

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

-2
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,6 @@ pub enum NetQueue {
4444
pub enum NetError {
4545
/// Open tap device failed: {0}
4646
TapOpen(TapError),
47-
/// Setting tap interface offload flags failed: {0}
48-
TapSetOffload(TapError),
4947
/// Setting vnet header size failed: {0}
5048
TapSetVnetHdrSize(TapError),
5149
/// EventFd error: {0}

0 commit comments

Comments
 (0)