From 135c818fee7c999c09eabe796b1dcdbd99c06cfa Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Mon, 20 Jun 2022 09:49:32 +0100 Subject: [PATCH] Feature/report node hardware info (#1308) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Adding simple hardware info reporting to the mixnode HTTP API * Adding sgx availability as another example field * Added sysinfo crate for addtitional simple hardware reporting * Added reporting on number of cpu cores and available ram * Cleanup of unused struct * Fixing merge conflict * Checking for supported system before using sysinfo * Breaking commit containing additional types ...and a painfully wrong implementation of the SMT processor cores type. * Handling unavailable brand string * Fixed getting SMT logical processor count * Rebase with develop + cleaned up changelog * unused import Co-authored-by: Jędrzej Stuczyński --- CHANGELOG.md | 2 + Cargo.lock | 33 ++++++++++++ mixnode/Cargo.toml | 6 ++- mixnode/src/node/http/hardware.rs | 87 +++++++++++++++++++++++++++++++ mixnode/src/node/http/mod.rs | 1 + mixnode/src/node/mod.rs | 3 +- 6 files changed, 129 insertions(+), 3 deletions(-) create mode 100644 mixnode/src/node/http/hardware.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index b99c085bb4..9a403e38f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https:// - wallet: the wallet backend learned how to archive wallet files - wallet: add ENABLE_QA_MODE environment variable to enable QA mode on built wallet - network-statistics: a new mixnet service that aggregates and exposes anonymized data about mixnet services ([#1328]) +- mixnode: Added basic mixnode hardware reporting to the HTTP API ([#1308]). ### Fixed @@ -63,6 +64,7 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https:// [#1292]: https://github.com/nymtech/nym/pull/1292 [#1295]: https://github.com/nymtech/nym/pull/1295 [#1302]: https://github.com/nymtech/nym/pull/1302 +[#1308]: https://github.com/nymtech/nym/pull/1308 [#1318]: https://github.com/nymtech/nym/pull/1318 [#1322]: https://github.com/nymtech/nym/pull/1322 [#1324]: https://github.com/nymtech/nym/pull/1324 diff --git a/Cargo.lock b/Cargo.lock index 80bb5e4055..47c6dff2cf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1140,6 +1140,16 @@ dependencies = [ "cipher 0.4.3", ] +[[package]] +name = "cupid" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bad352a84b567cc38a5854e3aa8ee903cb8519a25d0b799b739bafffd1f91a1" +dependencies = [ + "gcc", + "rustc_version 0.2.3", +] + [[package]] name = "curve25519-dalek" version = "3.2.0" @@ -1966,6 +1976,12 @@ dependencies = [ "tungstenite", ] +[[package]] +name = "gcc" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" + [[package]] name = "generator" version = "0.7.0" @@ -3120,6 +3136,7 @@ dependencies = [ "colored", "config", "crypto", + "cupid", "dirs", "dotenv", "futures", @@ -3138,6 +3155,7 @@ dependencies = [ "rocket", "serde", "serial_test", + "sysinfo", "task", "tokio", "tokio-util 0.7.3", @@ -5459,6 +5477,21 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "sysinfo" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a8e71535da31837213ac114531d31def75d7aebd133264e420a3451fa7f703" +dependencies = [ + "cfg-if 1.0.0", + "core-foundation-sys", + "libc", + "ntapi", + "once_cell", + "rayon", + "winapi", +] + [[package]] name = "tap" version = "1.0.1" diff --git a/mixnode/Cargo.toml b/mixnode/Cargo.toml index 8043ee96f2..a0ca74020b 100644 --- a/mixnode/Cargo.toml +++ b/mixnode/Cargo.toml @@ -16,24 +16,26 @@ rust-version = "1.58.1" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +anyhow = "1.0.40" bs58 = "0.4.0" clap = { version = "3.0.10", features = ["cargo", "derive"] } colored = "2.0" +cupid = "0.6.1" dirs = "3.0" dotenv = "0.15.0" futures = "0.3.0" humantime-serde = "1.0" +lazy_static = "1.4.0" log = "0.4.0" pretty_env_logger = "0.4.0" rand = "0.7.3" rocket = { version = "0.5.0-rc.2", features = ["json"] } serde = { version="1.0", features = ["derive"] } +sysinfo = "0.24.1" tokio = { version="1.19.1", features = ["rt-multi-thread", "net", "signal"] } tokio-util = { version="0.7.3", features = ["codec"] } toml = "0.5.8" url = { version = "2.2", features = ["serde"] } -lazy_static = "1.4.0" -anyhow = "1.0.40" ## internal config = { path="../common/config" } diff --git a/mixnode/src/node/http/hardware.rs b/mixnode/src/node/http/hardware.rs new file mode 100644 index 0000000000..18543e9d37 --- /dev/null +++ b/mixnode/src/node/http/hardware.rs @@ -0,0 +1,87 @@ +use cupid::TopologyType; +use rocket::serde::{json::Json, Serialize}; +use sysinfo::{System, SystemExt}; + +#[derive(Serialize, Debug)] +#[serde(crate = "rocket::serde")] +pub(crate) struct Hardware { + ram: String, + num_cores: usize, + crypto_hardware: Option, +} + +#[derive(Serialize, Debug)] +#[serde(crate = "rocket::serde")] +pub(crate) struct CryptoHardware { + aesni: bool, + avx2: bool, + brand_string: String, + smt_logical_processor_count: Vec, + osxsave: bool, + sgx: bool, + xsave: bool, +} + +/// Provides hardware information which Nym can use to optimize mixnet speed over time (memory, crypto hardware, CPU, cores, etc). +#[get("/hardware")] +pub(crate) fn hardware() -> Json> { + Json(hardware_info()) +} + +/// Gives back a summary report of whatever system hardware info we can get for this platform. +fn hardware_info() -> Option { + let crypto_hardware = hardware_info_from_cupid(); + hardware_from_sysinfo(crypto_hardware) +} + +/// Sysinfo gives back basic stuff like number of CPU cores and available memory. If available, this includes the hardware encryption +/// extensions report +fn hardware_from_sysinfo(crypto_hardware: Option) -> Option { + if System::IS_SUPPORTED { + let mut system = System::new_all(); + system.refresh_all(); + let ram = format!("{}KB", system.total_memory()); + let cores = system.cpus(); + let num_cores = cores.len(); + Some(Hardware { + crypto_hardware, + ram, + num_cores, + }) + } else { + None + } +} + +/// The `cupid` crate gives back a report on available hardware encryption extensions which may be useful for future mixnet optimizations. +/// +/// Note: this information is generally only available on x86 platforms for Linux. +fn hardware_info_from_cupid() -> Option { + cupid::master().map(|info| -> CryptoHardware { + let smt_logical_processor_count = + if let Some(extended_topology) = info.extended_topology_enumeration() { + extended_topology + .clone() + .filter_map(|entry| { + if entry.level_type() == TopologyType::SMT { + Some(entry.logical_processor_count()) + } else { + None + } + }) + .collect() + } else { + Vec::new() + }; + + CryptoHardware { + aesni: info.aesni(), + avx2: info.avx2(), + brand_string: info.brand_string().map(String::from).unwrap_or_default(), + smt_logical_processor_count, + osxsave: info.osxsave(), + sgx: info.sgx(), + xsave: info.xsave(), + } + }) +} diff --git a/mixnode/src/node/http/mod.rs b/mixnode/src/node/http/mod.rs index fb64c002dd..f92212b9aa 100644 --- a/mixnode/src/node/http/mod.rs +++ b/mixnode/src/node/http/mod.rs @@ -1,4 +1,5 @@ pub(crate) mod description; +pub(crate) mod hardware; pub(crate) mod stats; pub(crate) mod verloc; diff --git a/mixnode/src/node/mod.rs b/mixnode/src/node/mod.rs index 75d4b47ec0..f9b1386f8f 100644 --- a/mixnode/src/node/mod.rs +++ b/mixnode/src/node/mod.rs @@ -6,6 +6,7 @@ use crate::config::persistence::pathfinder::MixNodePathfinder; use crate::config::Config; use crate::node::http::{ description::description, + hardware::hardware, not_found, stats::stats, verloc::{verloc as verlocRoute, VerlocState}, @@ -140,7 +141,7 @@ impl MixNode { tokio::spawn(async move { rocket::build() .configure(config) - .mount("/", routes![verlocRoute, description, stats]) + .mount("/", routes![verlocRoute, description, stats, hardware]) .register("/", catchers![not_found]) .manage(verloc_state) .manage(descriptor)