diff --git a/vmm/src/device_manager.rs b/vmm/src/device_manager.rs index 8bd673af5..172a6313e 100644 --- a/vmm/src/device_manager.rs +++ b/vmm/src/device_manager.rs @@ -13,11 +13,12 @@ use crate::config::ConsoleOutputMode; #[cfg(feature = "pci_support")] use crate::config::DeviceConfig; use crate::config::{DiskConfig, FsConfig, NetConfig, PmemConfig, VmConfig, VsockConfig}; +use crate::device_tree::{DeviceNode, DeviceTree}; use crate::interrupt::{ KvmLegacyUserspaceInterruptManager, KvmMsiInterruptManager, KvmRoutingEntry, }; use crate::memory_manager::{Error as MemoryManagerError, MemoryManager}; -use crate::DEVICE_MANAGER_SNAPSHOT_ID; +use crate::{device_node, DEVICE_MANAGER_SNAPSHOT_ID}; #[cfg(feature = "acpi")] use acpi_tables::{aml, aml::Aml}; use anyhow::anyhow; @@ -559,127 +560,6 @@ impl Drop for ActivatedBackend { } } -#[derive(Clone, Serialize, Deserialize)] -struct DeviceNode { - id: String, - resources: Vec, - parent: Option, - children: Vec, - #[serde(skip)] - migratable: Option>>, -} - -impl DeviceNode { - fn new(id: String, migratable: Option>>) -> Self { - DeviceNode { - id, - resources: Vec::new(), - parent: None, - children: Vec::new(), - migratable, - } - } -} - -macro_rules! device_node { - ($id:ident) => { - DeviceNode::new($id.clone(), None) - }; - ($id:ident, $device:ident) => { - DeviceNode::new( - $id.clone(), - Some(Arc::clone(&$device) as Arc>), - ) - }; -} - -#[derive(Clone, Serialize, Deserialize)] -struct DeviceTree(HashMap); - -impl DeviceTree { - fn new() -> Self { - DeviceTree(HashMap::new()) - } - fn get(&self, k: &str) -> Option<&DeviceNode> { - self.0.get(k) - } - fn get_mut(&mut self, k: &str) -> Option<&mut DeviceNode> { - self.0.get_mut(k) - } - fn insert(&mut self, k: String, v: DeviceNode) -> Option { - self.0.insert(k, v) - } - #[cfg(feature = "pci_support")] - fn remove(&mut self, k: &str) -> Option { - self.0.remove(k) - } - fn iter(&self) -> std::collections::hash_map::Iter { - self.0.iter() - } - fn breadth_first_traversal(&self) -> BftIter { - BftIter::new(&self.0) - } -} - -// Breadth first traversal iterator. -struct BftIter<'a> { - nodes: Vec<&'a DeviceNode>, -} - -impl<'a> BftIter<'a> { - fn new(hash_map: &'a HashMap) -> Self { - let mut nodes = Vec::new(); - - for (_, node) in hash_map.iter() { - if node.parent.is_none() { - nodes.push(node); - } - } - - let mut node_layer = nodes.as_slice(); - loop { - let mut next_node_layer = Vec::new(); - - for node in node_layer.iter() { - for child_node_id in node.children.iter() { - if let Some(child_node) = hash_map.get(child_node_id) { - next_node_layer.push(child_node); - } - } - } - - if next_node_layer.is_empty() { - break; - } - - let pos = nodes.len(); - nodes.extend(next_node_layer); - - node_layer = &nodes[pos..]; - } - - BftIter { nodes } - } -} - -impl<'a> Iterator for BftIter<'a> { - type Item = &'a DeviceNode; - - fn next(&mut self) -> Option { - if self.nodes.is_empty() { - None - } else { - Some(self.nodes.remove(0)) - } - } -} - -impl<'a> DoubleEndedIterator for BftIter<'a> { - fn next_back(&mut self) -> Option { - self.nodes.pop() - } -} - #[derive(Serialize, Deserialize)] struct DeviceManagerState { device_tree: DeviceTree, diff --git a/vmm/src/device_tree.rs b/vmm/src/device_tree.rs new file mode 100644 index 000000000..0202fe541 --- /dev/null +++ b/vmm/src/device_tree.rs @@ -0,0 +1,130 @@ +// Copyright © 2020 Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 + +use std::collections::HashMap; +use std::sync::{Arc, Mutex}; +use vm_device::Resource; +use vm_migration::Migratable; + +#[derive(Clone, Serialize, Deserialize)] +pub struct DeviceNode { + pub id: String, + pub resources: Vec, + pub parent: Option, + pub children: Vec, + #[serde(skip)] + pub migratable: Option>>, +} + +impl DeviceNode { + pub fn new(id: String, migratable: Option>>) -> Self { + DeviceNode { + id, + resources: Vec::new(), + parent: None, + children: Vec::new(), + migratable, + } + } +} + +#[macro_export] +macro_rules! device_node { + ($id:ident) => { + DeviceNode::new($id.clone(), None) + }; + ($id:ident, $device:ident) => { + DeviceNode::new( + $id.clone(), + Some(Arc::clone(&$device) as Arc>), + ) + }; +} + +#[derive(Clone, Default, Serialize, Deserialize)] +pub struct DeviceTree(HashMap); + +impl DeviceTree { + pub fn new() -> Self { + DeviceTree(HashMap::new()) + } + pub fn get(&self, k: &str) -> Option<&DeviceNode> { + self.0.get(k) + } + pub fn get_mut(&mut self, k: &str) -> Option<&mut DeviceNode> { + self.0.get_mut(k) + } + pub fn insert(&mut self, k: String, v: DeviceNode) -> Option { + self.0.insert(k, v) + } + #[cfg(feature = "pci_support")] + pub fn remove(&mut self, k: &str) -> Option { + self.0.remove(k) + } + pub fn iter(&self) -> std::collections::hash_map::Iter { + self.0.iter() + } + pub fn breadth_first_traversal(&self) -> BftIter { + BftIter::new(&self.0) + } +} + +// Breadth first traversal iterator. +pub struct BftIter<'a> { + nodes: Vec<&'a DeviceNode>, +} + +impl<'a> BftIter<'a> { + fn new(hash_map: &'a HashMap) -> Self { + let mut nodes = Vec::new(); + + for (_, node) in hash_map.iter() { + if node.parent.is_none() { + nodes.push(node); + } + } + + let mut node_layer = nodes.as_slice(); + loop { + let mut next_node_layer = Vec::new(); + + for node in node_layer.iter() { + for child_node_id in node.children.iter() { + if let Some(child_node) = hash_map.get(child_node_id) { + next_node_layer.push(child_node); + } + } + } + + if next_node_layer.is_empty() { + break; + } + + let pos = nodes.len(); + nodes.extend(next_node_layer); + + node_layer = &nodes[pos..]; + } + + BftIter { nodes } + } +} + +impl<'a> Iterator for BftIter<'a> { + type Item = &'a DeviceNode; + + fn next(&mut self) -> Option { + if self.nodes.is_empty() { + None + } else { + Some(self.nodes.remove(0)) + } + } +} + +impl<'a> DoubleEndedIterator for BftIter<'a> { + fn next_back(&mut self) -> Option { + self.nodes.pop() + } +} diff --git a/vmm/src/lib.rs b/vmm/src/lib.rs index 3c3b4aa34..dad6cc406 100644 --- a/vmm/src/lib.rs +++ b/vmm/src/lib.rs @@ -39,6 +39,7 @@ pub mod api; pub mod config; pub mod cpu; pub mod device_manager; +pub mod device_tree; pub mod interrupt; pub mod memory_manager; pub mod migration;