diff --git a/vmm/src/config.rs b/vmm/src/config.rs index 6acbe9361..2f38a7f9c 100644 --- a/vmm/src/config.rs +++ b/vmm/src/config.rs @@ -821,6 +821,8 @@ pub struct DiskConfig { // For testing use only. Not exposed in API. #[serde(default)] pub disable_io_uring: bool, + #[serde(default)] + pub pci_segment: u16, } fn default_diskconfig_num_queues() -> usize { @@ -850,6 +852,7 @@ impl Default for DiskConfig { id: None, disable_io_uring: false, rate_limiter_config: None, + pci_segment: 0, } } } @@ -861,7 +864,7 @@ impl DiskConfig { vhost_user=on|off,socket=,poll_queue=on|off,\ bw_size=,bw_one_time_burst=,bw_refill_time=,\ ops_size=,ops_one_time_burst=,ops_refill_time=,\ - id=\""; + id=,pci_segment=\""; pub fn parse(disk: &str) -> Result { let mut parser = OptionParser::new(); @@ -882,7 +885,8 @@ impl DiskConfig { .add("ops_one_time_burst") .add("ops_refill_time") .add("id") - .add("_disable_io_uring"); + .add("_disable_io_uring") + .add("pci_segment"); parser.parse(disk).map_err(Error::ParseDisk)?; let path = parser.get("path").map(PathBuf::from); @@ -926,6 +930,10 @@ impl DiskConfig { .map_err(Error::ParseDisk)? .unwrap_or(Toggle(false)) .0; + let pci_segment = parser + .convert("pci_segment") + .map_err(Error::ParseDisk)? + .unwrap_or_default(); let bw_size = parser .convert("bw_size") .map_err(Error::ParseDisk)? @@ -994,6 +1002,7 @@ impl DiskConfig { rate_limiter_config, id, disable_io_uring, + pci_segment, }) } @@ -1064,6 +1073,8 @@ pub struct NetConfig { pub fds: Option>, #[serde(default)] pub rate_limiter_config: Option, + #[serde(default)] + pub pci_segment: u16, } fn default_netconfig_tap() -> Option { @@ -1107,6 +1118,7 @@ impl Default for NetConfig { id: None, fds: None, rate_limiter_config: None, + pci_segment: 0, } } } @@ -1117,7 +1129,7 @@ impl NetConfig { num_queues=,queue_size=,id=,\ vhost_user=,socket=,vhost_mode=client|server,\ bw_size=,bw_one_time_burst=,bw_refill_time=,\ - ops_size=,ops_one_time_burst=,ops_refill_time=\""; + ops_size=,ops_one_time_burst=,ops_refill_time=,pci_segment=\""; pub fn parse(net: &str) -> Result { let mut parser = OptionParser::new(); @@ -1141,7 +1153,8 @@ impl NetConfig { .add("bw_refill_time") .add("ops_size") .add("ops_one_time_burst") - .add("ops_refill_time"); + .add("ops_refill_time") + .add("pci_segment"); parser.parse(net).map_err(Error::ParseNetwork)?; let tap = parser.get("tap"); @@ -1186,7 +1199,10 @@ impl NetConfig { .convert::("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::ParseDisk)? @@ -1253,6 +1269,7 @@ impl NetConfig { id, fds, rate_limiter_config, + pci_segment, }; Ok(config) } @@ -1370,6 +1387,8 @@ pub struct FsConfig { pub cache_size: u64, #[serde(default)] pub id: Option, + #[serde(default)] + pub pci_segment: u16, } fn default_fsconfig_num_queues() -> usize { @@ -1398,6 +1417,7 @@ impl Default for FsConfig { dax: default_fsconfig_dax(), cache_size: default_fsconfig_cache_size(), id: None, + pci_segment: 0, } } } @@ -1406,7 +1426,7 @@ impl FsConfig { pub const SYNTAX: &'static str = "virtio-fs parameters \ \"tag=,socket=,num_queues=,\ queue_size=,dax=on|off,cache_size=,id=\""; + default 8Gib>,id=,pci_segment=\""; pub fn parse(fs: &str) -> Result { let mut parser = OptionParser::new(); @@ -1417,7 +1437,8 @@ impl FsConfig { .add("queue_size") .add("num_queues") .add("socket") - .add("id"); + .add("id") + .add("pci_segment"); parser.parse(fs).map_err(Error::ParseFileSystem)?; let tag = parser.get("tag").ok_or(Error::ParseFsTagMissing)?; @@ -1450,6 +1471,11 @@ impl FsConfig { let id = parser.get("id"); + let pci_segment = parser + .convert("pci_segment") + .map_err(Error::ParseFileSystem)? + .unwrap_or_default(); + Ok(FsConfig { tag, socket, @@ -1458,6 +1484,7 @@ impl FsConfig { dax, cache_size, id, + pci_segment, }) } @@ -1483,12 +1510,14 @@ pub struct PmemConfig { pub discard_writes: bool, #[serde(default)] pub id: Option, + #[serde(default)] + pub pci_segment: u16, } impl PmemConfig { pub const SYNTAX: &'static str = "Persistent memory parameters \ \"file=,size=,iommu=on|off,\ - mergeable=on|off,discard_writes=on|off,id=\""; + mergeable=on|off,discard_writes=on|off,id=,pci_segment=\""; pub fn parse(pmem: &str) -> Result { let mut parser = OptionParser::new(); parser @@ -1497,7 +1526,8 @@ impl PmemConfig { .add("mergeable") .add("iommu") .add("discard_writes") - .add("id"); + .add("id") + .add("pci_segment"); parser.parse(pmem).map_err(Error::ParsePersistentMemory)?; let file = PathBuf::from(parser.get("file").ok_or(Error::ParsePmemFileMissing)?); @@ -1521,6 +1551,10 @@ impl PmemConfig { .unwrap_or(Toggle(false)) .0; let id = parser.get("id"); + let pci_segment = parser + .convert("pci_segment") + .map_err(Error::ParsePersistentMemory)? + .unwrap_or_default(); Ok(PmemConfig { file, @@ -1529,6 +1563,7 @@ impl PmemConfig { mergeable, discard_writes, id, + pci_segment, }) } } @@ -1675,14 +1710,21 @@ pub struct VsockConfig { pub iommu: bool, #[serde(default)] pub id: Option, + #[serde(default)] + pub pci_segment: u16, } impl VsockConfig { pub const SYNTAX: &'static str = "Virtio VSOCK parameters \ - \"cid=,socket=,iommu=on|off,id=\""; + \"cid=,socket=,iommu=on|off,id=,pci_segment=\""; pub fn parse(vsock: &str) -> Result { let mut parser = OptionParser::new(); - parser.add("socket").add("cid").add("iommu").add("id"); + parser + .add("socket") + .add("cid") + .add("iommu") + .add("id") + .add("pci_segment"); parser.parse(vsock).map_err(Error::ParseVsock)?; let socket = parser @@ -1699,12 +1741,17 @@ impl VsockConfig { .map_err(Error::ParseVsock)? .ok_or(Error::ParseVsockCidMissing)?; let id = parser.get("id"); + let pci_segment = parser + .convert("pci_segment") + .map_err(Error::ParseVsock)? + .unwrap_or_default(); Ok(VsockConfig { cid, socket, iommu, id, + pci_segment, }) } } @@ -2743,6 +2790,7 @@ mod tests { socket: PathBuf::from("/tmp/sock"), iommu: false, id: None, + ..Default::default() } ); assert_eq!( @@ -2752,6 +2800,7 @@ mod tests { socket: PathBuf::from("/tmp/sock"), iommu: true, id: None, + ..Default::default() } ); Ok(()) diff --git a/vmm/src/device_manager.rs b/vmm/src/device_manager.rs index 0d053dad6..e658919c2 100644 --- a/vmm/src/device_manager.rs +++ b/vmm/src/device_manager.rs @@ -818,7 +818,7 @@ pub struct DeviceManager { memory_manager: Arc>, // The virtio devices on the system - virtio_devices: Vec<(VirtioDeviceArc, bool, String)>, + virtio_devices: Vec<(VirtioDeviceArc, bool, String, u16)>, // List of bus devices // Let the DeviceManager keep strong references to the BusDevice devices. @@ -1056,7 +1056,7 @@ impl DeviceManager { console_pty: Option, console_resize_pipe: Option, ) -> DeviceManagerResult<()> { - let mut virtio_devices: Vec<(VirtioDeviceArc, bool, String)> = Vec::new(); + let mut virtio_devices: Vec<(VirtioDeviceArc, bool, String, u16)> = Vec::new(); let interrupt_controller = self.add_interrupt_controller()?; @@ -1158,7 +1158,7 @@ impl DeviceManager { #[allow(unused_variables)] fn add_pci_devices( &mut self, - virtio_devices: Vec<(VirtioDeviceArc, bool, String)>, + virtio_devices: Vec<(VirtioDeviceArc, bool, String, u16)>, ) -> DeviceManagerResult<()> { let iommu_id = String::from(IOMMU_DEVICE_NAME); @@ -1190,14 +1190,14 @@ impl DeviceManager { let mut iommu_attached_devices = Vec::new(); { - for (device, iommu_attached, id) in virtio_devices { + for (device, iommu_attached, id, pci_segment_id) in virtio_devices { let mapping: &Option> = if iommu_attached { &iommu_mapping } else { &None }; - let dev_id = self.add_virtio_pci_device(device, mapping, id, 0)?; + let dev_id = self.add_virtio_pci_device(device, mapping, id, pci_segment_id)?; if iommu_attached { iommu_attached_devices.push(dev_id); @@ -1679,7 +1679,7 @@ impl DeviceManager { fn add_virtio_console_device( &mut self, - virtio_devices: &mut Vec<(VirtioDeviceArc, bool, String)>, + virtio_devices: &mut Vec<(VirtioDeviceArc, bool, String, u16)>, console_pty: Option, resize_pipe: Option, ) -> DeviceManagerResult>> { @@ -1746,6 +1746,7 @@ impl DeviceManager { Arc::clone(&virtio_console_device) as VirtioDeviceArc, console_config.iommu, id.clone(), + 0, )); // Fill the device tree with a new node. In case of restore, we @@ -1767,7 +1768,7 @@ impl DeviceManager { fn add_console_device( &mut self, interrupt_manager: &Arc>, - virtio_devices: &mut Vec<(VirtioDeviceArc, bool, String)>, + virtio_devices: &mut Vec<(VirtioDeviceArc, bool, String, u16)>, serial_pty: Option, console_pty: Option, console_resize_pipe: Option, @@ -1825,8 +1826,10 @@ impl DeviceManager { Ok(Arc::new(Console { console_resizer })) } - fn make_virtio_devices(&mut self) -> DeviceManagerResult> { - let mut devices: Vec<(VirtioDeviceArc, bool, String)> = Vec::new(); + fn make_virtio_devices( + &mut self, + ) -> DeviceManagerResult> { + let mut devices: Vec<(VirtioDeviceArc, bool, String, u16)> = Vec::new(); // Create "standard" virtio devices (net/block/rng) devices.append(&mut self.make_virtio_block_devices()?); @@ -1856,7 +1859,7 @@ impl DeviceManager { fn make_virtio_block_device( &mut self, disk_cfg: &mut DiskConfig, - ) -> DeviceManagerResult<(VirtioDeviceArc, bool, String)> { + ) -> DeviceManagerResult<(VirtioDeviceArc, bool, String, u16)> { let id = if let Some(id) = &disk_cfg.id { id.clone() } else { @@ -1903,6 +1906,7 @@ impl DeviceManager { Arc::clone(&vhost_user_block_device) as VirtioDeviceArc, false, id, + disk_cfg.pci_segment, )) } else { let mut options = OpenOptions::new(); @@ -2002,13 +2006,13 @@ impl DeviceManager { .unwrap() .insert(id.clone(), device_node!(id, migratable_device)); - Ok((virtio_device, disk_cfg.iommu, id)) + Ok((virtio_device, disk_cfg.iommu, id, disk_cfg.pci_segment)) } } fn make_virtio_block_devices( &mut self, - ) -> DeviceManagerResult> { + ) -> DeviceManagerResult> { let mut devices = Vec::new(); let mut block_devices = self.config.lock().unwrap().disks.clone(); @@ -2025,7 +2029,7 @@ impl DeviceManager { fn make_virtio_net_device( &mut self, net_cfg: &mut NetConfig, - ) -> DeviceManagerResult<(VirtioDeviceArc, bool, String)> { + ) -> DeviceManagerResult<(VirtioDeviceArc, bool, String, u16)> { let id = if let Some(id) = &net_cfg.id { id.clone() } else { @@ -2077,6 +2081,7 @@ impl DeviceManager { Arc::clone(&vhost_user_net_device) as VirtioDeviceArc, net_cfg.iommu, id, + net_cfg.pci_segment, )) } else { let virtio_net_device = if let Some(ref tap_if_name) = net_cfg.tap { @@ -2149,6 +2154,7 @@ impl DeviceManager { Arc::clone(&virtio_net_device) as VirtioDeviceArc, net_cfg.iommu, id, + net_cfg.pci_segment, )) } } @@ -2156,7 +2162,7 @@ impl DeviceManager { /// Add virto-net and vhost-user-net devices fn make_virtio_net_devices( &mut self, - ) -> DeviceManagerResult> { + ) -> DeviceManagerResult> { let mut devices = Vec::new(); let mut net_devices = self.config.lock().unwrap().net.clone(); if let Some(net_list_cfg) = &mut net_devices { @@ -2171,7 +2177,7 @@ impl DeviceManager { fn make_virtio_rng_devices( &mut self, - ) -> DeviceManagerResult> { + ) -> DeviceManagerResult> { let mut devices = Vec::new(); // Add virtio-rng if required @@ -2196,6 +2202,7 @@ impl DeviceManager { Arc::clone(&virtio_rng_device) as VirtioDeviceArc, rng_config.iommu, id.clone(), + 0, )); // Fill the device tree with a new node. In case of restore, we @@ -2213,7 +2220,7 @@ impl DeviceManager { fn make_virtio_fs_device( &mut self, fs_cfg: &mut FsConfig, - ) -> DeviceManagerResult<(VirtioDeviceArc, bool, String)> { + ) -> DeviceManagerResult<(VirtioDeviceArc, bool, String, u16)> { let id = if let Some(id) = &fs_cfg.id { id.clone() } else { @@ -2348,7 +2355,12 @@ impl DeviceManager { node.migratable = Some(Arc::clone(&virtio_fs_device) as Arc>); self.device_tree.lock().unwrap().insert(id.clone(), node); - Ok((Arc::clone(&virtio_fs_device) as VirtioDeviceArc, false, id)) + Ok(( + Arc::clone(&virtio_fs_device) as VirtioDeviceArc, + false, + id, + fs_cfg.pci_segment, + )) } else { Err(DeviceManagerError::NoVirtioFsSock) } @@ -2356,7 +2368,7 @@ impl DeviceManager { fn make_virtio_fs_devices( &mut self, - ) -> DeviceManagerResult> { + ) -> DeviceManagerResult> { let mut devices = Vec::new(); let mut fs_devices = self.config.lock().unwrap().fs.clone(); @@ -2373,7 +2385,7 @@ impl DeviceManager { fn make_virtio_pmem_device( &mut self, pmem_cfg: &mut PmemConfig, - ) -> DeviceManagerResult<(VirtioDeviceArc, bool, String)> { + ) -> DeviceManagerResult<(VirtioDeviceArc, bool, String, u16)> { let id = if let Some(id) = &pmem_cfg.id { id.clone() } else { @@ -2542,12 +2554,13 @@ impl DeviceManager { Arc::clone(&virtio_pmem_device) as VirtioDeviceArc, pmem_cfg.iommu, id, + pmem_cfg.pci_segment, )) } fn make_virtio_pmem_devices( &mut self, - ) -> DeviceManagerResult> { + ) -> DeviceManagerResult> { let mut devices = Vec::new(); // Add virtio-pmem if required let mut pmem_devices = self.config.lock().unwrap().pmem.clone(); @@ -2564,7 +2577,7 @@ impl DeviceManager { fn make_virtio_vsock_device( &mut self, vsock_cfg: &mut VsockConfig, - ) -> DeviceManagerResult<(VirtioDeviceArc, bool, String)> { + ) -> DeviceManagerResult<(VirtioDeviceArc, bool, String, u16)> { let id = if let Some(id) = &vsock_cfg.id { id.clone() } else { @@ -2610,12 +2623,13 @@ impl DeviceManager { Arc::clone(&vsock_device) as VirtioDeviceArc, vsock_cfg.iommu, id, + vsock_cfg.pci_segment, )) } fn make_virtio_vsock_devices( &mut self, - ) -> DeviceManagerResult> { + ) -> DeviceManagerResult> { let mut devices = Vec::new(); let mut vsock = self.config.lock().unwrap().vsock.clone(); @@ -2629,7 +2643,7 @@ impl DeviceManager { fn make_virtio_mem_devices( &mut self, - ) -> DeviceManagerResult> { + ) -> DeviceManagerResult> { let mut devices = Vec::new(); let mm = self.memory_manager.clone(); @@ -2670,6 +2684,7 @@ impl DeviceManager { Arc::clone(&virtio_mem_device) as VirtioDeviceArc, false, memory_zone_id.clone(), + 0, )); // Fill the device tree with a new node. In case of restore, we @@ -2687,7 +2702,7 @@ impl DeviceManager { fn make_virtio_balloon_devices( &mut self, - ) -> DeviceManagerResult> { + ) -> DeviceManagerResult> { let mut devices = Vec::new(); if let Some(balloon_config) = &self.config.lock().unwrap().balloon { @@ -2713,6 +2728,7 @@ impl DeviceManager { Arc::clone(&virtio_balloon_device) as VirtioDeviceArc, false, id.clone(), + 0, )); self.device_tree @@ -2726,7 +2742,7 @@ impl DeviceManager { fn make_virtio_watchdog_devices( &mut self, - ) -> DeviceManagerResult> { + ) -> DeviceManagerResult> { let mut devices = Vec::new(); if !self.config.lock().unwrap().watchdog { @@ -2751,6 +2767,7 @@ impl DeviceManager { Arc::clone(&virtio_watchdog_device) as VirtioDeviceArc, false, id.clone(), + 0, )); self.device_tree @@ -3334,7 +3351,7 @@ impl DeviceManager { } pub fn update_memory(&self, new_region: &Arc) -> DeviceManagerResult<()> { - for (virtio_device, _, _) in self.virtio_devices.iter() { + for (virtio_device, _, _, _) in self.virtio_devices.iter() { virtio_device .lock() .unwrap() @@ -3628,7 +3645,7 @@ impl DeviceManager { virtio_device.lock().unwrap().shutdown(); self.virtio_devices - .retain(|(d, _, _)| !Arc::ptr_eq(d, &virtio_device)); + .retain(|(d, _, _, _)| !Arc::ptr_eq(d, &virtio_device)); } // At this point, the device has been removed from all the list and @@ -3653,7 +3670,7 @@ impl DeviceManager { // as the list is used to notify virtio devices about memory updates // for instance. self.virtio_devices - .push((device.clone(), iommu_attached, id.clone())); + .push((device.clone(), iommu_attached, id.clone(), pci_segment_id)); let device_id = self.add_virtio_pci_device(device, &None, id.clone(), pci_segment_id)?; @@ -3664,34 +3681,37 @@ impl DeviceManager { } pub fn add_disk(&mut self, disk_cfg: &mut DiskConfig) -> DeviceManagerResult { - let (device, iommu_attached, id) = self.make_virtio_block_device(disk_cfg)?; - self.hotplug_virtio_pci_device(device, iommu_attached, id, 0) + let (device, iommu_attached, id, pci_segment_id) = + self.make_virtio_block_device(disk_cfg)?; + self.hotplug_virtio_pci_device(device, iommu_attached, id, pci_segment_id) } pub fn add_fs(&mut self, fs_cfg: &mut FsConfig) -> DeviceManagerResult { - let (device, iommu_attached, id) = self.make_virtio_fs_device(fs_cfg)?; - self.hotplug_virtio_pci_device(device, iommu_attached, id, 0) + let (device, iommu_attached, id, pci_segment_id) = self.make_virtio_fs_device(fs_cfg)?; + self.hotplug_virtio_pci_device(device, iommu_attached, id, pci_segment_id) } pub fn add_pmem(&mut self, pmem_cfg: &mut PmemConfig) -> DeviceManagerResult { - let (device, iommu_attached, id) = self.make_virtio_pmem_device(pmem_cfg)?; - self.hotplug_virtio_pci_device(device, iommu_attached, id, 0) + let (device, iommu_attached, id, pci_segment_id) = + self.make_virtio_pmem_device(pmem_cfg)?; + self.hotplug_virtio_pci_device(device, iommu_attached, id, pci_segment_id) } pub fn add_net(&mut self, net_cfg: &mut NetConfig) -> DeviceManagerResult { - let (device, iommu_attached, id) = self.make_virtio_net_device(net_cfg)?; - self.hotplug_virtio_pci_device(device, iommu_attached, id, 0) + let (device, iommu_attached, id, pci_segment_id) = self.make_virtio_net_device(net_cfg)?; + self.hotplug_virtio_pci_device(device, iommu_attached, id, pci_segment_id) } pub fn add_vsock(&mut self, vsock_cfg: &mut VsockConfig) -> DeviceManagerResult { - let (device, iommu_attached, id) = self.make_virtio_vsock_device(vsock_cfg)?; - self.hotplug_virtio_pci_device(device, iommu_attached, id, 0) + let (device, iommu_attached, id, pci_segment_id) = + self.make_virtio_vsock_device(vsock_cfg)?; + self.hotplug_virtio_pci_device(device, iommu_attached, id, pci_segment_id) } pub fn counters(&self) -> HashMap>> { let mut counters = HashMap::new(); - for (virtio_device, _, id) in &self.virtio_devices { + for (virtio_device, _, id, _) in &self.virtio_devices { let virtio_device = virtio_device.lock().unwrap(); if let Some(device_counters) = virtio_device.counters() { counters.insert(id.clone(), device_counters.clone()); @@ -4247,7 +4267,7 @@ impl BusDevice for DeviceManager { impl Drop for DeviceManager { fn drop(&mut self) { - for (device, _, _) in self.virtio_devices.drain(..) { + for (device, _, _, _) in self.virtio_devices.drain(..) { device.lock().unwrap().shutdown(); } }