Basic data structures and collection for anonymous usage collection.

This commit is contained in:
Herbert Wolverson 2023-03-17 13:32:24 +00:00
parent 5805d9860e
commit 08e7788efb
6 changed files with 215 additions and 1 deletions

View File

@ -0,0 +1,2 @@
mod v1;
pub use v1::*;

View File

@ -0,0 +1,68 @@
#[derive(Default, Debug)]
/// Defines data to be submitted if anonymous usage submission is
/// enabled. This is protocol version 1.
pub struct AnonymousUsageV1 {
/// Total installed RAM (bytes)
pub total_memory: u64,
/// Total available RAM (bytes)
pub available_memory: u64,
/// Linux Kernel Version
pub kernel_version: String,
/// Number of "usable" CPU cores, as used by eBPF. This may not
/// be exactly equal to the number of actual cores.
pub usable_cores: u32,
/// CPU brand
pub cpu_brand: String,
/// CPU vendor
pub cpu_vendor: String,
/// CPU frequency
pub cpu_frequency: u64,
/// Installed network cards
pub nics: Vec<NicV1>,
/// SQM setting from the ispConfig.py file
pub sqm: String,
/// Is Monitor-ony mode enabled?
pub monitor_mode: bool,
/// Capacity as specified in ispConfig.py
pub total_capacity: (u32, u32),
/// Generated node capacity from ispConfig.py
pub generated_pdn_capacity: (u32, u32),
/// Number of shaped devices from ShapedDevices.csv
pub shaped_device_count: usize,
/// Number of nodes read from network.json
pub net_json_len: usize,
}
/// Description of installed NIC (version 1 data)
#[derive(Default, Debug)]
pub struct NicV1 {
/// Description, usually "Ethernet"
pub description: String,
/// Product name as specified by the driver
pub product: String,
/// Vendor as specified by the driver
pub vendor: String,
/// Clock speed, specified by the vendor (may not be accurate)
pub clock: String,
/// NIC possible capacity (as reported by the driver)
pub capacity: String,
}

View File

@ -20,3 +20,6 @@ pub use bus::{
UnixSocketServer, BUS_SOCKET_PATH,
};
pub use tc_handle::TcHandle;
/// Anonymous Usage Statistics Data Types
pub mod anonymous;

View File

@ -0,0 +1,70 @@
use std::process::Command;
use lqos_bus::anonymous::NicV1;
#[derive(Default)]
pub(crate) struct Nic {
pub(crate) description: String,
pub(crate) product: String,
pub(crate) vendor: String,
pub(crate) clock: String,
pub(crate) capacity: String,
}
#[allow(clippy::from_over_into)]
impl Into<NicV1> for Nic {
fn into(self) -> NicV1 {
NicV1 {
description: self.description,
product: self.product,
vendor: self.vendor,
clock: self.clock,
capacity: self.capacity,
}
}
}
pub(crate) fn get_nic_info() -> anyhow::Result<Vec<Nic>> {
let mut current_nic = None;
let mut result = Vec::new();
let output = Command::new("/bin/lshw")
.args(["-C", "network"])
.output()?;
let stdout = String::from_utf8(output.stdout)?;
let lines = stdout.split('\n');
for line in lines {
let trimmed = line.trim();
// Starting a new record
if trimmed.starts_with("*-network:") {
if let Some(nic) = current_nic {
result.push(nic);
}
current_nic = Some(Nic::default());
}
if let Some(mut nic) = current_nic.as_mut() {
if let Some(d) = trimmed.strip_prefix("description: ") {
nic.description = d.to_string();
}
if let Some(d) = trimmed.strip_prefix("product: ") {
nic.product = d.to_string();
}
if let Some(d) = trimmed.strip_prefix("vendor: ") {
nic.vendor = d.to_string();
}
if let Some(d) = trimmed.strip_prefix("clock: ") {
nic.clock = d.to_string();
}
if let Some(d) = trimmed.strip_prefix("capacity: ") {
nic.capacity = d.to_string();
}
}
}
if let Some(nic) = current_nic {
result.push(nic);
}
Ok(result)
}

View File

@ -0,0 +1,69 @@
mod lshw;
use std::time::Duration;
use lqos_bus::anonymous::AnonymousUsageV1;
use lqos_config::{EtcLqos, LibreQoSConfig};
use lqos_sys::num_possible_cpus;
use sysinfo::{System, SystemExt, CpuExt};
use crate::shaped_devices_tracker::{SHAPED_DEVICES, NETWORK_JSON};
const SLOW_START_SECS: u64 = 1;
const INTERVAL_SECS: u64 = 60 * 60 * 24;
pub async fn start_anonymous_usage() {
if let Ok(cfg) = EtcLqos::load() {
if let Some(usage) = cfg.usage_stats {
if usage.send_anonymous {
std::thread::spawn(|| {
std::thread::sleep(Duration::from_secs(SLOW_START_SECS));
loop {
let _ = anonymous_usage_dump();
std::thread::sleep(Duration::from_secs(INTERVAL_SECS));
}
});
}
}
}
}
fn anonymous_usage_dump() -> anyhow::Result<()> {
let mut data = AnonymousUsageV1::default();
let mut sys = System::new_all();
sys.refresh_all();
data.total_memory = sys.total_memory();
data.available_memory = sys.available_memory();
if let Some(kernel) = sys.kernel_version() {
data.kernel_version = kernel;
}
if let Ok(cores) = num_possible_cpus() {
data.usable_cores = cores;
}
let cpu = sys.cpus().first();
if let Some(cpu) = cpu {
data.cpu_brand = cpu.brand().to_string();
data.cpu_vendor = cpu.vendor_id().to_string();
data.cpu_frequency = cpu.frequency();
}
for nic in lshw::get_nic_info()? {
data.nics.push(nic.into());
}
if let Ok(cfg) = LibreQoSConfig::load() {
data.sqm = cfg.sqm;
data.monitor_mode = cfg.monitor_mode;
data.total_capacity = (
cfg.total_download_mbps,
cfg.total_upload_mbps,
);
data.generated_pdn_capacity = (
cfg.generated_download_mbps,
cfg.generated_upload_mbps,
);
}
data.shaped_device_count = SHAPED_DEVICES.read().unwrap().devices.len();
data.net_json_len = NETWORK_JSON.read().unwrap().nodes.len();
println!("{data:#?}");
Ok(())
}

View File

@ -5,6 +5,7 @@ mod lqos_daht_test;
mod program_control;
mod shaped_devices_tracker;
mod throughput_tracker;
mod anonymous_usage;
mod tuning;
mod validation;
use crate::{
@ -69,7 +70,8 @@ async fn main() -> Result<()> {
join!(
spawn_queue_structure_monitor(),
shaped_devices_tracker::shaped_devices_watcher(),
shaped_devices_tracker::network_json_watcher()
shaped_devices_tracker::network_json_watcher(),
anonymous_usage::start_anonymous_usage(),
);
throughput_tracker::spawn_throughput_monitor();
spawn_queue_monitor();