vmm: config: Switch NetConfig to use PciDeviceCommonConfig

Switch NetConfig over to using the newly extracted struct members as
used by all PCI based devices. The use of #[serde(flatten)] means that
this change has no impact on the JSON format that the data is stored as.

Signed-off-by: Rob Bradford <rbradford@meta.com>
This commit is contained in:
Rob Bradford
2026-04-03 11:49:54 -07:00
parent d2ce7667bc
commit 92c2cf0103
5 changed files with 61 additions and 61 deletions

View File

@@ -122,7 +122,7 @@ mod fds_helper {
impl ConfigWithFDs for NetConfig {
fn id(&self) -> Option<&str> {
self.id.as_deref()
self.pci_common.id.as_deref()
}
fn fds_from_http_body(&self) -> Option<&[RawFd]> {

View File

@@ -1554,11 +1554,6 @@ impl NetConfig {
.unwrap_or(Toggle(true))
.0;
let mtu = parser.convert("mtu").map_err(Error::ParseNetwork)?;
let iommu = parser
.convert::<Toggle>("iommu")
.map_err(Error::ParseNetwork)?
.unwrap_or(Toggle(false))
.0;
let queue_size = parser
.convert("queue_size")
.map_err(Error::ParseNetwork)?
@@ -1577,15 +1572,10 @@ impl NetConfig {
.convert("vhost_mode")
.map_err(Error::ParseNetwork)?
.unwrap_or_default();
let id = parser.get("id");
let fds = parser
.convert::<IntegerList>("fd")
.map_err(Error::ParseNetwork)?
.map(|v| v.0.iter().map(|e| *e as i32).collect());
let pci_segment = parser
.convert("pci_segment")
.map_err(Error::ParseNetwork)?
.unwrap_or_default();
let bw_size = parser
.convert("bw_size")
.map_err(Error::ParseNetwork)?
@@ -1637,23 +1627,23 @@ impl NetConfig {
None
};
let pci_common = PciDeviceCommonConfig::parse(net)?;
let config = NetConfig {
pci_common,
tap,
ip,
mask,
mac,
host_mac,
mtu,
iommu,
num_queues,
queue_size,
vhost_user,
vhost_socket,
vhost_mode,
id,
fds,
rate_limiter_config,
pci_segment,
offload_tso,
offload_ufo,
offload_csum,
@@ -1662,6 +1652,8 @@ impl NetConfig {
}
pub fn validate(&self, vm_config: &VmConfig) -> ValidationResult<()> {
self.pci_common.validate(vm_config)?;
if self.num_queues < 2 {
return Err(ValidationError::VnetQueueLowerThan2(self.num_queues));
}
@@ -1689,23 +1681,10 @@ impl NetConfig {
));
}
if self.vhost_user && self.iommu {
if self.vhost_user && self.pci_common.iommu {
return Err(ValidationError::IommuNotSupported);
}
if let Some(platform_config) = vm_config.platform.as_ref() {
if self.pci_segment >= platform_config.num_pci_segments {
return Err(ValidationError::InvalidPciSegment(self.pci_segment));
}
if let Some(iommu_segments) = platform_config.iommu_segments.as_ref()
&& iommu_segments.contains(&self.pci_segment)
&& !self.iommu
{
return Err(ValidationError::OnIommuSegment(self.pci_segment));
}
}
if let Some(mtu) = self.mtu
&& mtu < virtio_devices::net::MIN_MTU
{
@@ -2778,6 +2757,7 @@ impl RestoreConfig {
for net_fds in vm_config.net.iter().flatten() {
if let Some(expected_fds) = &net_fds.fds {
let expected_id = net_fds
.pci_common
.id
.as_ref()
.expect("Invalid 'NetConfig' with empty 'id' for VM restore.");
@@ -3066,9 +3046,9 @@ impl VmConfig {
return Err(ValidationError::VhostUserRequiresSharedMemory);
}
net.validate(self)?;
self.iommu |= net.iommu;
self.iommu |= net.pci_common.iommu;
Self::validate_identifier(&mut id_list, &net.id)?;
Self::validate_identifier(&mut id_list, &net.pci_common.id)?;
}
}
@@ -3564,7 +3544,7 @@ impl VmConfig {
// Remove if net device
if let Some(net) = self.net.as_mut() {
let len = net.len();
net.retain(|dev| dev.id.as_ref().map(|id| id.as_ref()) != Some(id));
net.retain(|dev| dev.pci_common.id.as_ref().map(|id| id.as_ref()) != Some(id));
removed |= net.len() != len;
}
@@ -4148,22 +4128,20 @@ mod unit_tests {
fn net_fixture() -> NetConfig {
NetConfig {
pci_common: PciDeviceCommonConfig::default(),
tap: None,
ip: None,
mask: None,
mac: MacAddr::parse_str("de:ad:be:ef:12:34").unwrap(),
host_mac: Some(MacAddr::parse_str("12:34:de:ad:be:ef").unwrap()),
mtu: None,
iommu: false,
num_queues: 2,
queue_size: 256,
vhost_user: false,
vhost_socket: None,
vhost_mode: VhostMode::Client,
id: None,
fds: None,
rate_limiter_config: None,
pci_segment: 0,
offload_tso: true,
offload_ufo: true,
offload_csum: true,
@@ -4181,7 +4159,10 @@ mod unit_tests {
assert_eq!(
NetConfig::parse("mac=de:ad:be:ef:12:34,host_mac=12:34:de:ad:be:ef,id=mynet0")?,
NetConfig {
id: Some("mynet0".to_owned()),
pci_common: PciDeviceCommonConfig {
id: Some("mynet0".to_owned()),
..Default::default()
},
..net_fixture()
}
);
@@ -4214,9 +4195,12 @@ mod unit_tests {
"mac=de:ad:be:ef:12:34,host_mac=12:34:de:ad:be:ef,num_queues=4,queue_size=1024,iommu=on"
)?,
NetConfig {
pci_common: PciDeviceCommonConfig {
iommu: true,
..Default::default()
},
num_queues: 4,
queue_size: 1024,
iommu: true,
..net_fixture()
}
);
@@ -4840,19 +4824,28 @@ id=\"{id}\",pci_segment={pci_segment},queue_sizes={queue_sizes}"
preserved_fds: None,
net: Some(vec![
NetConfig {
id: Some("net0".to_owned()),
pci_common: PciDeviceCommonConfig {
id: Some("net0".to_owned()),
..Default::default()
},
num_queues: 2,
fds: Some(vec![-1, -1, -1, -1]),
..net_fixture()
},
NetConfig {
id: Some("net1".to_owned()),
pci_common: PciDeviceCommonConfig {
id: Some("net1".to_owned()),
..Default::default()
},
num_queues: 1,
fds: Some(vec![-1, -1]),
..net_fixture()
},
NetConfig {
id: Some("net2".to_owned()),
pci_common: PciDeviceCommonConfig {
id: Some("net2".to_owned()),
..Default::default()
},
fds: None,
..net_fixture()
},
@@ -4947,7 +4940,10 @@ id=\"{id}\",pci_segment={pci_segment},queue_sizes={queue_sizes}"
resume: false,
};
snapshot_vm_config.net = Some(vec![NetConfig {
id: Some("net2".to_owned()),
pci_common: PciDeviceCommonConfig {
id: Some("net2".to_owned()),
..Default::default()
},
fds: None,
..net_fixture()
}]);
@@ -5330,8 +5326,11 @@ id=\"{id}\",pci_segment={pci_segment},queue_sizes={queue_sizes}"
..platform_fixture()
});
still_valid_config.net = Some(vec![NetConfig {
iommu: true,
pci_segment: 1,
pci_common: PciDeviceCommonConfig {
iommu: true,
pci_segment: 1,
..Default::default()
},
..net_fixture()
}]);
still_valid_config.validate().unwrap();
@@ -5398,8 +5397,11 @@ id=\"{id}\",pci_segment={pci_segment},queue_sizes={queue_sizes}"
..platform_fixture()
});
invalid_config.net = Some(vec![NetConfig {
iommu: false,
pci_segment: 1,
pci_common: PciDeviceCommonConfig {
iommu: false,
pci_segment: 1,
..Default::default()
},
..net_fixture()
}]);
assert_eq!(

View File

@@ -2937,11 +2937,11 @@ impl DeviceManager {
&mut self,
net_cfg: &mut NetConfig,
) -> DeviceManagerResult<MetaVirtioDevice> {
let id = if let Some(id) = &net_cfg.id {
let id = if let Some(id) = &net_cfg.pci_common.id {
id.clone()
} else {
let id = self.next_device_name(NET_DEVICE_NAME_PREFIX)?;
net_cfg.id = Some(id.clone());
net_cfg.pci_common.id = Some(id.clone());
id
};
info!("Creating virtio-net device: {net_cfg:?}");
@@ -2999,7 +2999,7 @@ impl DeviceManager {
Some(net_cfg.mac),
&mut net_cfg.host_mac,
net_cfg.mtu,
self.force_iommu | net_cfg.iommu,
self.force_iommu | net_cfg.pci_common.iommu,
net_cfg.num_queues,
net_cfg.queue_size,
self.seccomp_action.clone(),
@@ -3020,7 +3020,7 @@ impl DeviceManager {
fds,
Some(net_cfg.mac),
net_cfg.mtu,
self.force_iommu | net_cfg.iommu,
self.force_iommu | net_cfg.pci_common.iommu,
net_cfg.queue_size,
self.seccomp_action.clone(),
net_cfg.rate_limiter_config,
@@ -3050,7 +3050,7 @@ impl DeviceManager {
Some(net_cfg.mac),
&mut net_cfg.host_mac,
net_cfg.mtu,
self.force_iommu | net_cfg.iommu,
self.force_iommu | net_cfg.pci_common.iommu,
net_cfg.num_queues,
net_cfg.queue_size,
self.seccomp_action.clone(),
@@ -3083,9 +3083,9 @@ impl DeviceManager {
Ok(MetaVirtioDevice {
virtio_device,
iommu: net_cfg.iommu,
iommu: net_cfg.pci_common.iommu,
id,
pci_segment: net_cfg.pci_segment,
pci_segment: net_cfg.pci_common.pci_segment,
dma_handler: None,
})
}
@@ -4737,7 +4737,7 @@ impl DeviceManager {
let nets = config.net.as_deref_mut().unwrap();
let net_dev_cfg = nets
.iter_mut()
.find(|net| net.id.as_deref() == Some(id))
.find(|net| net.pci_common.id.as_deref() == Some(id))
// unwrap: the device could not have been removed without an ID
.unwrap();
let fds = net_dev_cfg.fds.take().unwrap_or(Vec::new());
@@ -5067,9 +5067,9 @@ impl DeviceManager {
}
pub fn add_net(&mut self, net_cfg: &mut NetConfig) -> DeviceManagerResult<PciDeviceInfo> {
self.validate_identifier(&net_cfg.id)?;
self.validate_identifier(&net_cfg.pci_common.id)?;
if net_cfg.iommu && !self.is_iommu_segment(net_cfg.pci_segment) {
if net_cfg.pci_common.iommu && !self.is_iommu_segment(net_cfg.pci_common.pci_segment) {
return Err(DeviceManagerError::InvalidIommuHotplug);
}

View File

@@ -1879,7 +1879,9 @@ impl RequestHandler for Vmm {
for net in restored_nets.iter() {
for net_config in vm_net_configs.iter_mut() {
// update only if the net dev is backed by FDs
if net_config.id.as_ref() == Some(&net.id) && net_config.fds.is_some() {
if net_config.pci_common.id.as_ref() == Some(&net.id)
&& net_config.fds.is_some()
{
net_config.fds.clone_from(&net.fds);
}
}

View File

@@ -350,6 +350,8 @@ pub fn default_diskconfig_sparse() -> bool {
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub struct NetConfig {
#[serde(flatten)]
pub pci_common: PciDeviceCommonConfig,
#[serde(default = "default_netconfig_tap")]
pub tap: Option<String>,
pub ip: Option<IpAddr>,
@@ -360,8 +362,6 @@ pub struct NetConfig {
pub host_mac: Option<MacAddr>,
#[serde(default)]
pub mtu: Option<u16>,
#[serde(default)]
pub iommu: bool,
#[serde(default = "default_netconfig_num_queues")]
pub num_queues: usize,
#[serde(default = "default_netconfig_queue_size")]
@@ -371,8 +371,6 @@ pub struct NetConfig {
pub vhost_socket: Option<String>,
#[serde(default)]
pub vhost_mode: VhostMode,
#[serde(default)]
pub id: Option<String>,
// Special deserialize handling:
// Therefore, we don't serialize FDs, and whatever value is here after
// deserialization is invalid.
@@ -383,8 +381,6 @@ pub struct NetConfig {
pub fds: Option<Vec<i32>>,
#[serde(default)]
pub rate_limiter_config: Option<RateLimiterConfig>,
#[serde(default)]
pub pci_segment: u16,
#[serde(default = "default_netconfig_true")]
pub offload_tso: bool,
#[serde(default = "default_netconfig_true")]