-use crate::datastructs::NetEvent;
+use crate::datastructs::{NetEvent, NetInterfaceCache};
use futures::stream::Stream;
use std::error::Error;
use std::io;
}
impl NetworkSource {
- pub fn new() -> io::Result<NetworkSource> {
+ pub fn new(_cache: &'static mut NetInterfaceCache) -> io::Result<NetworkSource> {
Ok(NetworkSource {})
}
use async_stream::try_stream;
-use crate::datastructs::{NetEvent, NetEventOp, NetInterface, ToolstackNetInterface};
-use crate::unix_helpers::interface_name;
+use crate::datastructs::{NetEvent, NetEventOp, NetInterface, NetInterfaceCache};
use futures::channel::mpsc::UnboundedReceiver;
use futures::stream::{Stream, StreamExt};
use netlink_packet_core::{
RTMGRP_IPV6_IFADDR,
RTMGRP_LINK,
};
+use std::collections::hash_map;
use std::convert::TryInto;
use std::error::Error;
use std::io;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
+use std::rc::Rc;
use std::vec::Vec;
pub struct NetworkSource {
handle: netlink_proto::ConnectionHandle<RtnlMessage>,
messages: UnboundedReceiver<(NetlinkMessage<RtnlMessage>, SocketAddr)>,
+ iface_cache: &'static mut NetInterfaceCache,
}
impl NetworkSource {
- pub fn new() -> io::Result<NetworkSource> {
+ pub fn new(iface_cache: &'static mut NetInterfaceCache) -> io::Result<NetworkSource> {
let (mut connection, handle, messages) = new_connection(NETLINK_ROUTE)?;
// What kinds of broadcast messages we want to listen for.
let nl_mgroup_flags = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR;
.bind(&nl_addr)
.expect("failed to bind");
tokio::spawn(connection);
- Ok(NetworkSource { handle, messages })
+ Ok(NetworkSource { handle, messages, iface_cache })
}
pub async fn collect_current(&mut self) -> Result<Vec<NetEvent>, Box<dyn Error>> {
Ok(event)
}
- fn nl_linkmessage_decode(&mut self, msg: &LinkMessage) -> io::Result<(NetInterface, String)> {
+ fn nl_linkmessage_decode(&mut self, msg: &LinkMessage) -> io::Result<(Rc<NetInterface>, String)> {
let LinkMessage{header, nlas, ..} = msg;
// extract fields of interest
.map(|b| format!("{b:02x}"))
.collect::<Vec<String>>().join(":"));
- let iface = NetInterface { index: header.index,
- name: iface_name.unwrap_or(String::from("")),
- toolstack_iface: ToolstackNetInterface::None,
- };
+ let iface = self.iface_cache
+ .entry(header.index)
+ .or_insert_with_key(|index| NetInterface::new(*index, iface_name).into());
match mac_address {
- Some(mac_address) => Ok((iface, mac_address)),
- None => Ok((iface, "".to_string())), // FIXME ad-hoc ugly, use Option<String> instead
+ Some(mac_address) => Ok((iface.clone(), mac_address)),
+ None => Ok((iface.clone(), "".to_string())), // FIXME ad-hoc ugly, use Option<String> instead
}
}
- fn nl_addressmessage_decode(&mut self, msg: &AddressMessage) -> io::Result<(NetInterface, IpAddr)> {
+ fn nl_addressmessage_decode(&mut self, msg: &AddressMessage) -> io::Result<(Rc<NetInterface>, IpAddr)> {
let AddressMessage{header, nlas, ..} = msg;
// extract fields of interest
_ => None,
};
- let iface = NetInterface { index: header.index,
- name: interface_name(header.index),
- toolstack_iface: ToolstackNetInterface::None,
+ let iface = match self.iface_cache.entry(header.index) {
+ hash_map::Entry::Occupied(entry) => { entry.get().clone() },
+ hash_map::Entry::Vacant(_) => {
+ return Err(io::Error::new(io::ErrorKind::InvalidData,
+ format!("unknown interface for index {}", header.index)));
+ },
};
match address {
- Some(address) => Ok((iface, address)),
+ Some(address) => Ok((iface.clone(), address)),
None => Err(io::Error::new(io::ErrorKind::InvalidData, "unknown address")),
}
}
-
}
+
use async_stream::try_stream;
-use crate::datastructs::{NetEvent, NetEventOp, NetInterface, ToolstackNetInterface};
+use crate::datastructs::{NetEvent, NetEventOp, NetInterface, NetInterfaceCache};
use futures::stream::Stream;
use ipnetwork::IpNetwork;
use pnet_base::MacAddr;
-use std::collections::{HashMap, HashSet};
+use std::collections::{HashMap, HashSet, hash_map};
use std::error::Error;
use std::io;
use std::time::Duration;
type AddressesState = HashMap<u32, InterfaceInfo>;
pub struct NetworkSource {
addresses_cache: AddressesState,
+ iface_cache: &'static mut NetInterfaceCache,
}
impl NetworkSource {
- pub fn new() -> io::Result<NetworkSource> {
- Ok(NetworkSource {addresses_cache: AddressesState::new()})
+ pub fn new(iface_cache: &'static mut NetInterfaceCache) -> io::Result<NetworkSource> {
+ Ok(NetworkSource {addresses_cache: AddressesState::new(), iface_cache})
}
pub async fn collect_current(&mut self) -> Result<Vec<NetEvent>, Box<dyn Error>> {
// disappearing addresses
for (cached_iface_index, cached_info) in self.addresses_cache.iter() {
- let iface = NetInterface { index: *cached_iface_index,
- name: cached_info.name.to_string(),
- toolstack_iface: ToolstackNetInterface::None,
+ // iface object from iface_cache
+ let iface = match self.iface_cache.entry(*cached_iface_index) {
+ hash_map::Entry::Occupied(entry) => { entry.get().clone() },
+ hash_map::Entry::Vacant(_) => {
+ return Err(io::Error::new(
+ io::ErrorKind::InvalidData,
+ format!("disappearing interface with index {} not in iface_cache",
+ cached_iface_index)));
+ },
};
let iface_adresses =
if let Some(iface_info) = current_addresses.get(cached_iface_index) {
}
// appearing addresses
for (iface_index, iface_info) in current_addresses.iter() {
- let iface = NetInterface { index: *iface_index,
- name: iface_info.name.to_string(),
- toolstack_iface: ToolstackNetInterface::None,
- };
+ let iface = self.iface_cache
+ .entry(*iface_index)
+ .or_insert_with_key(|index| {
+ NetInterface::new(*index, Some(iface_info.name.clone())).into()
+ })
+ .clone();
let cache_adresses =
if let Some(cache_info) = self.addresses_cache.get(iface_index) {
&cache_info.addresses
+use std::collections::HashMap;
use std::net::IpAddr;
+use std::rc::Rc;
pub struct KernelInfo {
pub release: String,
pub toolstack_iface: ToolstackNetInterface,
}
+impl NetInterface {
+ pub fn new(index: u32, name: Option<String>) -> NetInterface {
+ let name = match name {
+ Some(string) => { string },
+ None => {
+ log::error!("new interface with index {index} has no name");
+ String::from("") // this is not valid, but user will now be aware
+ },
+ };
+ NetInterface { index,
+ name: name.clone(),
+ toolstack_iface: crate::vif_detect::get_toolstack_interface(&name),
+ }
+ }
+}
+
+// The cache of currently-known network interfaces. We have to use
+// reference counting on the cached items, as we want on one hand to
+// use references to those items from NetEvent, and OTOH we want to
+// 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>>;
+
#[derive(Debug)]
pub enum NetEventOp {
AddMac(String),
#[derive(Debug)]
pub struct NetEvent {
- pub iface: NetInterface,
+ pub iface: Rc<NetInterface>,
pub op: NetEventOp,
}
use clap::Parser;
-use crate::datastructs::KernelInfo;
+use crate::datastructs::{KernelInfo, NetInterfaceCache};
use crate::publisher::Publisher;
use crate::collector_net::NetworkSource;
use crate::collector_memory::MemorySource;
let mut timer_stream = tokio::time::interval(Duration::from_secs(MEM_PERIOD_SECONDS));
// network events
- let mut collector_net = NetworkSource::new()?;
- for mut event in collector_net.collect_current().await? {
- vif_detect::add_vif_info(&mut event);
+ 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() {
publisher.publish_netevent(&event)?;
}
select! {
event = netevent_stream.try_next().fuse() => {
match event? {
- Some(mut event) => {
- vif_detect::add_vif_info(&mut event);
+ Some(event) => {
if REPORT_INTERNAL_NICS || ! event.iface.toolstack_iface.is_none() {
publisher.publish_netevent(&event)?;
} else {
pub fn get_toolstack_interface(iface_name: &str) -> ToolstackNetInterface {
return ToolstackNetInterface::None;
}
-
-pub fn add_vif_info(_event: &mut NetEvent) -> () {
-}
-use crate::datastructs::{NetEvent, ToolstackNetInterface};
+use crate::datastructs::ToolstackNetInterface;
// identifies a VIF as named "xn%ID"
},
}
}
-
-pub fn add_vif_info(event: &mut NetEvent) -> () {
- event.iface.toolstack_iface = get_toolstack_interface(&event.iface.name);
-}
-use crate::datastructs::{NetEvent, ToolstackNetInterface};
+use crate::datastructs::ToolstackNetInterface;
use std::fs;
// identifies a VIF from sysfs as devtype="vif", and take the VIF id
},
}
}
-
-pub fn add_vif_info(event: &mut NetEvent) {
- event.iface.toolstack_iface = get_toolstack_interface(&event.iface.name);
-}