From 1ffd95187a61582e858dd37c0ab434d3159a0f52 Mon Sep 17 00:00:00 2001 From: Wei Gao Date: Mon, 9 Aug 2021 14:26:35 +0800 Subject: [PATCH 2/6] agent: add support of new sandbox hypervisor kind StratoVirt. 1. add new grpc interface `UpdateInterfaceHwAddrByName`. 2. comment out rescan_pci temporarily. Signed-off-by: Wei Gao --- src/agent/protocols/protos/agent.proto | 5 +++ src/agent/src/netlink.rs | 31 ++++++++++++++++ src/agent/src/rpc.rs | 51 +++++++++++++++++++++++++- 3 files changed, 85 insertions(+), 2 deletions(-) diff --git a/src/agent/protocols/protos/agent.proto b/src/agent/protocols/protos/agent.proto index 6cbf5a28..e00f5c63 100644 --- a/src/agent/protocols/protos/agent.proto +++ b/src/agent/protocols/protos/agent.proto @@ -46,6 +46,7 @@ service AgentService { // networking rpc UpdateInterface(UpdateInterfaceRequest) returns (types.Interface); + rpc UpdateInterfaceHwAddrByName(UpdateInterfaceHwAddrByNameRequest) returns (types.Interface); rpc UpdateRoutes(UpdateRoutesRequest) returns (Routes); rpc ListInterfaces(ListInterfacesRequest) returns(Interfaces); rpc ListRoutes(ListRoutesRequest) returns (Routes); @@ -308,6 +309,10 @@ message UpdateInterfaceRequest { types.Interface interface = 1; } +message UpdateInterfaceHwAddrByNameRequest { + types.Interface interface = 1; +} + message UpdateRoutesRequest { Routes routes = 1; } diff --git a/src/agent/src/netlink.rs b/src/agent/src/netlink.rs index 3ab6dbaa..82632d1b 100644 --- a/src/agent/src/netlink.rs +++ b/src/agent/src/netlink.rs @@ -104,6 +104,29 @@ impl Handle { Ok(()) } + pub async fn update_interface_hw_addr_by_name(&mut self, iface: &Interface) -> Result<()> { + let link = self.find_link(LinkFilter::Name(&iface.name)).await?; + + // Delete all addresses associated with the link + let addresses = self + .list_addresses(AddressFilter::LinkIndex(link.index())) + .await?; + self.delete_addresses(addresses).await?; + + if iface.IPAddresses.len() == 0 { + self.enable_link(link.index(), false).await?; + } + + // Update hardware mac address + let mac_addr = parse_mac_address(iface.get_hwAddr()) + .with_context(|| format!("Failed to parse MAC address: {}", iface.get_hwAddr()))?; + self.link_set_hw_addr(link.index(), mac_addr) + .await + .with_context(|| format!("Could not set {:?} to {}", mac_addr, link.name()))?; + + Ok(()) + } + pub async fn handle_localhost(&self) -> Result<()> { let link = self.find_link(LinkFilter::Name("lo")).await?; self.enable_link(link.index(), true).await?; @@ -216,6 +239,14 @@ impl Handle { Ok(()) } + async fn link_set_hw_addr(&self, link_index: u32, hw_addr: [u8; 6]) -> Result<()> { + let link_req = self.handle.link().set(link_index); + let set_req = link_req.address(hw_addr.to_vec()); + set_req.execute().await?; + + Ok(()) + } + async fn query_routes( &self, ip_version: Option, diff --git a/src/agent/src/rpc.rs b/src/agent/src/rpc.rs index 92025af3..2cc1c983 100644 --- a/src/agent/src/rpc.rs +++ b/src/agent/src/rpc.rs @@ -40,7 +40,7 @@ use nix::sys::stat; use nix::unistd::{self, Pid}; use rustjail::process::ProcessOperations; -use crate::device::{add_devices, rescan_pci_bus, update_device_cgroup}; +use crate::device::{add_devices, update_device_cgroup}; use crate::linux_abi::*; use crate::metrics::get_metrics; use crate::mount::{add_storages, remove_mounts, BareMount, STORAGE_HANDLER_LIST}; @@ -123,7 +123,9 @@ impl AgentService { // re-scan PCI bus // looking for hidden devices - rescan_pci_bus().context("Could not rescan PCI bus")?; + // FIXME: Comment out this code temporarily, because once the PCIBus is scanned, + // the device hot-plug event is lost + // rescan_pci_bus().context("Could not rescan PCI bus")?; // Some devices need some extra processing (the ones invoked with // --device for instance), and that's what this call is doing. It @@ -797,6 +799,34 @@ impl protocols::agent_ttrpc::AgentService for AgentService { Ok(interface) } + async fn update_interface_hw_addr_by_name( + &self, + _ctx: &TtrpcContext, + req: protocols::agent::UpdateInterfaceHwAddrByNameRequest, + ) -> ttrpc::Result { + let interface = req.interface.into_option().ok_or_else(|| { + ttrpc_error( + ttrpc::Code::INVALID_ARGUMENT, + "empty update interface request".to_string(), + ) + })?; + + self.sandbox + .lock() + .await + .rtnl + .update_interface_hw_addr_by_name(&interface) + .await + .map_err(|e| { + ttrpc_error( + ttrpc::Code::INTERNAL, + format!("update interface hw addr: {:?}", e), + ) + })?; + + Ok(interface) + } + async fn update_routes( &self, _ctx: &TtrpcContext, @@ -1670,6 +1700,23 @@ mod tests { assert!(result.is_err(), "expected update interface to fail"); } + #[tokio::test] + async fn test_update_interface_hw_addr_by_name() { + let logger = slog::Logger::root(slog::Discard, o!()); + let sandbox = Sandbox::new(&logger).unwrap(); + + let agent_service = Box::new(AgentService { + sandbox: Arc::new(Mutex::new(sandbox)), + }); + + let req = protocols::agent::UpdateInterfaceHwAddrByNameRequest::default(); + let ctx = mk_ttrpc_context(); + + let result = agent_service.update_interface_hw_addr_by_name(&ctx, req).await; + + assert!(result.is_err(), "expected update interface to fail"); + } + #[tokio::test] async fn test_update_routes() { let logger = slog::Logger::root(slog::Discard, o!()); -- 2.21.1 (Apple Git-122.3)