]> xenbits.xensource.com Git - xen-guest-agent.git/commitdiff
net: prepare interface cache for name changing
authorYann Dirson <yann.dirson@vates.fr>
Fri, 24 Nov 2023 11:00:52 +0000 (12:00 +0100)
committerYann Dirson <yann.dirson@vates.fr>
Fri, 8 Dec 2023 09:59:46 +0000 (10:59 +0100)
While name changes do not necessarily have external impact (eg.
xenstore_schema_std does not expose those names), they are necessary
on Linux to know whether an iface is a VIF.  This requires
NetInterface objects in the cache to be mutable.

Signed-off-by: Yann Dirson <yann.dirson@vates.fr>
src/collector_net_netlink.rs
src/collector_net_pnet.rs
src/datastructs.rs
src/main.rs
src/publisher.rs
src/xenstore_schema_rfc.rs
src/xenstore_schema_std.rs

index bea3a45bec6ad010a1db41f00ad639d21a3b3b5a..f9ad97cfb974bda38727786cf0a36fcaab89ba32 100644 (file)
@@ -23,6 +23,7 @@ use rtnetlink::constants::{
     RTMGRP_IPV6_IFADDR,
     RTMGRP_LINK,
     };
+use std::cell::RefCell;
 use std::collections::hash_map;
 use std::convert::TryInto;
 use std::error::Error;
@@ -141,8 +142,11 @@ impl NetworkSource {
         Ok(events)
     }
 
-    fn nl_linkmessage_decode(&mut self, msg: &LinkMessage)
-                             -> io::Result<(Rc<NetInterface>, Option<String>)> {
+    fn nl_linkmessage_decode(
+        &mut self, msg: &LinkMessage
+    ) -> io::Result<(Rc<RefCell<NetInterface>>, // ref to the (possibly new) impacted interface
+                     Option<String>,           // MAC address
+    )> {
         let LinkMessage{header, nlas, ..} = msg;
 
         // extract fields of interest
@@ -163,12 +167,15 @@ impl NetworkSource {
 
         let iface = self.iface_cache
             .entry(header.index)
-            .or_insert_with_key(|index| NetInterface::new(*index, iface_name).into());
+            .or_insert_with_key(|index|
+                                RefCell::new(NetInterface::new(*index, iface_name.clone()))
+                                .into());
 
         Ok((iface.clone(), mac_address))
     }
 
-    fn nl_addressmessage_decode(&mut self, msg: &AddressMessage) -> io::Result<(Rc<NetInterface>, IpAddr)> {
+    fn nl_addressmessage_decode(&mut self, msg: &AddressMessage)
+                                -> io::Result<(Rc<RefCell<NetInterface>>, IpAddr)> {
         let AddressMessage{header, nlas, ..} = msg;
 
         // extract fields of interest
index 0be42830d3550d64ce2547ad35ddb3a6a337a731..5bc826b55a894e719a81e7b5e83ff08295f2afce 100644 (file)
@@ -3,6 +3,7 @@ use crate::datastructs::{NetEvent, NetEventOp, NetInterface, NetInterfaceCache};
 use futures::stream::Stream;
 use ipnetwork::IpNetwork;
 use pnet_base::MacAddr;
+use std::cell::RefCell;
 use std::collections::{HashMap, HashSet, hash_map};
 use std::error::Error;
 use std::io;
@@ -100,7 +101,7 @@ impl NetworkSource {
                 Some(iface_info) => {
                     let iface_adresses = &iface_info.addresses;
                     for disappearing in cached_info.addresses.difference(iface_adresses) {
-                        log::trace!("disappearing {}: {:?}", iface.name, disappearing);
+                        log::trace!("disappearing {}: {:?}", iface.borrow().name, disappearing);
                         events.push(NetEvent{
                             iface: iface.clone(),
                             op: match disappearing {
@@ -120,7 +121,8 @@ impl NetworkSource {
             let iface = self.iface_cache
                 .entry(*iface_index)
                 .or_insert_with_key(|index| {
-                    let iface = Rc::new(NetInterface::new(*index, Some(iface_info.name.clone())));
+                    let iface = Rc::new(RefCell::new(
+                        NetInterface::new(*index, Some(iface_info.name.clone()))));
                     events.push(NetEvent{iface: iface.clone(), op: NetEventOp::AddIface});
                     iface
                 })
@@ -132,7 +134,7 @@ impl NetworkSource {
                     &empty_address_set
                 };
             for appearing in iface_info.addresses.difference(cache_adresses) {
-                log::trace!("appearing {}: {:?}", iface.name, appearing);
+                log::trace!("appearing {}: {:?}", iface.borrow().name, appearing);
                 events.push(NetEvent{iface: iface.clone(),
                                      op: match appearing {
                                          Address::IP(ip) => NetEventOp::AddIp(ip.ip()),
index a1ba27b36625a72a5794906100f49c704ba0bf0b..2b8a96d6f4e2f2a989b898798802adb117de32da 100644 (file)
@@ -1,3 +1,4 @@
+use std::cell::RefCell;
 use std::collections::HashMap;
 use std::net::IpAddr;
 use std::rc::Rc;
@@ -54,7 +55,8 @@ impl NetInterface {
 // remove interfaces from here once unplugged.  And Rust won't let us
 // use `&'static NetInterface` because we can do the latter, which is
 // good in the end.
-pub type NetInterfaceCache = HashMap<u32, Rc<NetInterface>>;
+// The interface may change name after creation (hence `RefCell`).
+pub type NetInterfaceCache = HashMap<u32, Rc<RefCell<NetInterface>>>;
 
 #[derive(Debug)]
 pub enum NetEventOp {
@@ -68,6 +70,6 @@ pub enum NetEventOp {
 
 #[derive(Debug)]
 pub struct NetEvent {
-    pub iface: Rc<NetInterface>,
+    pub iface: Rc<RefCell<NetInterface>>,
     pub op: NetEventOp,
 }
index 58ec8668a4020b748ebb81d6a0ba2c4211c61ce9..2b80850db18e1b7abc1ff630ac39b01dc71c3be9 100644 (file)
@@ -65,7 +65,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
     let network_cache = Box::leak(Box::new(NetInterfaceCache::new()));
     let mut collector_net = NetworkSource::new(network_cache)?;
     for event in collector_net.collect_current().await? {
-        if REPORT_INTERNAL_NICS || ! event.iface.toolstack_iface.is_none() {
+        if REPORT_INTERNAL_NICS || ! event.iface.borrow().toolstack_iface.is_none() {
             publisher.publish_netevent(&event)?;
         }
     }
@@ -78,7 +78,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
             event = netevent_stream.try_next().fuse() => {
                 match event? {
                     Some(event) => {
-                        if REPORT_INTERNAL_NICS || ! event.iface.toolstack_iface.is_none() {
+                        if REPORT_INTERNAL_NICS || ! event.iface.borrow().toolstack_iface.is_none() {
                             publisher.publish_netevent(&event)?;
                         } else {
                             log::debug!("no toolstack iface in {event:?}");
index fcaa26bfc387dbae6d09fe6aafec2577f2e5e7de..8258e36e9cbbfec2bc96f16052eb13e559fbd1ca 100644 (file)
@@ -29,7 +29,7 @@ impl Publisher {
         Ok(())
     }
     pub fn publish_netevent(&self, event: &NetEvent) -> io::Result<()> {
-        let iface_id = &event.iface.name;
+        let iface_id = &event.iface.borrow().name;
         match &event.op {
             NetEventOp::AddIface => println!("{iface_id} +IFACE"),
             NetEventOp::RmIface => println!("{iface_id} -IFACE"),
index e1f1a1eb00d84d1ba65914621cf1e47f19677539..74f32a936d303ac4df77a40476475c84cb26b34f 100644 (file)
@@ -41,11 +41,11 @@ impl XenstoreSchema for Schema {
 
     #[allow(clippy::useless_format)]
     fn publish_netevent(&mut self, event: &NetEvent) -> io::Result<()> {
-        let iface_id = &event.iface.index;
+        let iface_id = &event.iface.borrow().index;
         let xs_iface_prefix = format!("data/net/{iface_id}");
         match &event.op {
             NetEventOp::AddIface => {
-                xs_publish(&self.xs, &format!("{xs_iface_prefix}"), &event.iface.name)?;
+                xs_publish(&self.xs, &format!("{xs_iface_prefix}"), &event.iface.borrow().name)?;
             },
             NetEventOp::RmIface => {
                 xs_unpublish(&self.xs, &format!("{xs_iface_prefix}"))?;
index 0186deceb7c520c0a2217e1b637ac7206b5299e0..98177959c320344f90421d00534517012e0ba55e 100644 (file)
@@ -103,7 +103,7 @@ impl XenstoreSchema for Schema {
 
     // see https://xenbits.xen.org/docs/unstable/misc/xenstore-paths.html#domain-controlled-paths
     fn publish_netevent(&mut self, event: &NetEvent) -> io::Result<()> {
-        let iface_id = match event.iface.toolstack_iface {
+        let iface_id = match event.iface.borrow().toolstack_iface {
             ToolstackNetInterface::Vif(id) => id,
             ToolstackNetInterface::None => {
                 panic!("publish_netevent called with no toolstack iface for {:?}", event);
@@ -118,12 +118,12 @@ impl XenstoreSchema for Schema {
                 xs_unpublish(&self.xs, &format!("{xs_iface_prefix}"))?;
             },
             NetEventOp::AddIp(address) => {
-                let key_suffix = self.munged_address(address, &event.iface)?;
+                let key_suffix = self.munged_address(address, &event.iface.borrow())?;
                 xs_publish(&self.xs, &format!("{xs_iface_prefix}/{key_suffix}"),
                            &address.to_string())?;
             },
             NetEventOp::RmIp(address) => {
-                let key_suffix = self.munged_address(address, &event.iface)?;
+                let key_suffix = self.munged_address(address, &event.iface.borrow())?;
                 xs_unpublish(&self.xs, &format!("{xs_iface_prefix}/{key_suffix}"))?;
             },