From 1ffd95187a61582e858dd37c0ab434d3159a0f52 Mon Sep 17 00:00:00 2001
From: Wei Gao <gaowei66@huawei.com>
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 <gaowei66@huawei.com>
---
 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<IpVersion>,
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<Interface> {
+        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)

