mirror of
https://github.com/LibreQoE/LibreQoS.git
synced 2026-11-03 20:56:45 -06:00
Cleanup: cargo fmt run
This commit is contained in:
1 parent
60d8a3dfe6
commit
bebba9def0
11 files changed
+332
-177
No files matched your search
@@ -1,8 +1,8 @@
|
||||
//! Collects the blackboard functionality together
|
||||
|
||||
use lqos_bus::BlackboardSystem;
|
||||
use serde::Serialize;
|
||||
use tracing::info;
|
||||
use lqos_bus::BlackboardSystem;
|
||||
|
||||
pub async fn blackboard(subsystem: BlackboardSystem, key: &str, value: &str) {
|
||||
let Ok(config) = lqos_config::load_config() else {
|
||||
@@ -40,4 +40,4 @@ pub async fn blackboard_blob<T: Serialize>(key: &str, value: T) -> anyhow::Resul
|
||||
let _ = lqos_bus::bus_request(req).await;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -2,19 +2,19 @@
|
||||
//! be ported back to Python, with Rust support structures - but I'll iterate
|
||||
//! faster in Rust.
|
||||
|
||||
mod blackboard;
|
||||
#[warn(missing_docs)]
|
||||
mod errors;
|
||||
pub mod ip_ranges;
|
||||
mod strategies;
|
||||
pub mod uisp_types;
|
||||
mod blackboard;
|
||||
|
||||
use crate::errors::UispIntegrationError;
|
||||
use crate::ip_ranges::IpRanges;
|
||||
pub use blackboard::*;
|
||||
use lqos_config::Config;
|
||||
use tokio::time::Instant;
|
||||
use tracing::{error, info};
|
||||
pub use blackboard::*;
|
||||
|
||||
/// Start the tracing/logging system
|
||||
fn init_tracing() {
|
||||
@@ -35,7 +35,6 @@ fn check_enabled_status(config: &Config) -> Result<(), UispIntegrationError> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), UispIntegrationError> {
|
||||
let now = Instant::now();
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
use std::fs::write;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
use tracing::{error, info, warn};
|
||||
use lqos_config::Config;
|
||||
use crate::errors::UispIntegrationError;
|
||||
use crate::ip_ranges::IpRanges;
|
||||
use crate::strategies::common::UispData;
|
||||
use crate::strategies::full::shaped_devices_writer::ShapedDevice;
|
||||
use lqos_config::Config;
|
||||
use std::fs::write;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
use tracing::{error, info, warn};
|
||||
|
||||
/// Creates a network with only APs detected
|
||||
/// from clients.
|
||||
@@ -35,8 +35,14 @@ pub async fn build_ap_only_network(
|
||||
ap_object.insert("children".to_string(), serde_json::Map::new().into());
|
||||
|
||||
// Limits
|
||||
ap_object.insert("downloadBandwidthMbps".to_string(), serde_json::Value::Number(ap_device.download.into()));
|
||||
ap_object.insert("uploadBandwidthMbps".to_string(), serde_json::Value::Number(ap_device.upload.into()));
|
||||
ap_object.insert(
|
||||
"downloadBandwidthMbps".to_string(),
|
||||
serde_json::Value::Number(ap_device.download.into()),
|
||||
);
|
||||
ap_object.insert(
|
||||
"uploadBandwidthMbps".to_string(),
|
||||
serde_json::Value::Number(ap_device.upload.into()),
|
||||
);
|
||||
|
||||
// Metadata
|
||||
ap_object.insert("type".to_string(), "AP".to_string().into());
|
||||
@@ -60,7 +66,11 @@ pub async fn build_ap_only_network(
|
||||
for (parent, client_ids) in mappings.iter() {
|
||||
for client_id in client_ids {
|
||||
let site = uisp_data.sites.iter().find(|s| *client_id == s.id).unwrap();
|
||||
let devices = uisp_data.devices.iter().filter(|d| d.site_id == *client_id).collect::<Vec<_>>();
|
||||
let devices = uisp_data
|
||||
.devices
|
||||
.iter()
|
||||
.filter(|d| d.site_id == *client_id)
|
||||
.collect::<Vec<_>>();
|
||||
for device in devices.iter().filter(|d| d.has_address()) {
|
||||
let sd = ShapedDevice {
|
||||
circuit_id: site.id.clone(),
|
||||
@@ -105,4 +115,4 @@ pub async fn build_ap_only_network(
|
||||
info!("Wrote {} lines to ShapedDevices.csv", shaped_devices.len());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,14 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::fs::write;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
use tracing::{error, info, warn};
|
||||
use lqos_config::Config;
|
||||
use crate::blackboard_blob;
|
||||
use crate::errors::UispIntegrationError;
|
||||
use crate::ip_ranges::IpRanges;
|
||||
use crate::strategies::common::UispData;
|
||||
use crate::strategies::full::shaped_devices_writer::ShapedDevice;
|
||||
use lqos_config::Config;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::fs::write;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
use tracing::{error, info, warn};
|
||||
|
||||
#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Clone)]
|
||||
pub enum GraphMapping {
|
||||
@@ -29,12 +29,11 @@ pub async fn build_ap_site_network(
|
||||
let uisp_data = UispData::fetch_uisp_data(config.clone(), ip_ranges).await?;
|
||||
|
||||
// Find trouble-spots!
|
||||
let _trouble = find_troublesome_sites(&uisp_data).await
|
||||
.map_err(|e|{
|
||||
error!("Error finding troublesome sites");
|
||||
error!("{e:?}");
|
||||
UispIntegrationError::UnknownSiteType
|
||||
})?;
|
||||
let _trouble = find_troublesome_sites(&uisp_data).await.map_err(|e| {
|
||||
error!("Error finding troublesome sites");
|
||||
error!("{e:?}");
|
||||
UispIntegrationError::UnknownSiteType
|
||||
})?;
|
||||
|
||||
// Find the clients
|
||||
let ap_mappings = uisp_data.map_clients_to_aps();
|
||||
@@ -76,7 +75,10 @@ pub async fn build_ap_site_network(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn write_shaped_devices(config: &Arc<Config>, shaped_devices: &mut Vec<ShapedDevice>) -> Result<(), UispIntegrationError> {
|
||||
pub(crate) fn write_shaped_devices(
|
||||
config: &Arc<Config>,
|
||||
shaped_devices: &mut Vec<ShapedDevice>,
|
||||
) -> Result<(), UispIntegrationError> {
|
||||
let file_path = Path::new(&config.lqos_directory).join("ShapedDevices.csv");
|
||||
let mut writer = csv::WriterBuilder::new()
|
||||
.has_headers(true)
|
||||
@@ -95,18 +97,23 @@ pub(crate) fn write_shaped_devices(config: &Arc<Config>, shaped_devices: &mut Ve
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn map_sites_above_aps(uisp_data: &UispData, ap_mappings: HashMap<String, Vec<String>>, access_points: HashMap<String, Layer>) -> HashMap<String, Layer> {
|
||||
pub(crate) fn map_sites_above_aps(
|
||||
uisp_data: &UispData,
|
||||
ap_mappings: HashMap<String, Vec<String>>,
|
||||
access_points: HashMap<String, Layer>,
|
||||
) -> HashMap<String, Layer> {
|
||||
let mut sites = HashMap::new();
|
||||
for (ap_name, client_ids) in ap_mappings.iter() {
|
||||
if let Some(device) = uisp_data.find_device_by_name(ap_name) {
|
||||
if let Some(device_site_id) = device.get_site_id() {
|
||||
if let Some(device_site) = uisp_data.sites.iter().find(|s| s.id == device_site_id) {
|
||||
let site_entry = sites.entry(device_site.name.clone()).or_insert_with(|| {
|
||||
Layer {
|
||||
id: GraphMapping::SiteByName(device_site.name.clone()),
|
||||
children: Vec::new(),
|
||||
}
|
||||
});
|
||||
let site_entry =
|
||||
sites
|
||||
.entry(device_site.name.clone())
|
||||
.or_insert_with(|| Layer {
|
||||
id: GraphMapping::SiteByName(device_site.name.clone()),
|
||||
children: Vec::new(),
|
||||
});
|
||||
let ap_map = access_points.get(ap_name).unwrap().clone();
|
||||
site_entry.children.push(ap_map);
|
||||
}
|
||||
@@ -165,15 +172,21 @@ impl Layer {
|
||||
GraphMapping::SiteByName(name) | GraphMapping::AccessPointByName(name) => {
|
||||
name.to_owned()
|
||||
}
|
||||
_ => "".to_owned()
|
||||
_ => "".to_owned(),
|
||||
};
|
||||
for child in self.children.iter() {
|
||||
match &child.id {
|
||||
GraphMapping::SiteByName(name) | GraphMapping::AccessPointByName(name) => {
|
||||
children.insert(name.clone(), child.walk_children(Some(&parent_name), uisp_data, shaped_devices, config).into());
|
||||
children.insert(
|
||||
name.clone(),
|
||||
child
|
||||
.walk_children(Some(&parent_name), uisp_data, shaped_devices, config)
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
GraphMapping::ClientById(_client_id) => {
|
||||
let _ = child.walk_children(Some(&parent_name), uisp_data, shaped_devices, config);
|
||||
let _ =
|
||||
child.walk_children(Some(&parent_name), uisp_data, shaped_devices, config);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@@ -185,7 +198,10 @@ impl Layer {
|
||||
root.insert("type".to_string(), "Site".into());
|
||||
root.insert("name".to_string(), name.clone().into());
|
||||
if let Some(site) = uisp_data.sites.iter().find(|s| s.name == *name) {
|
||||
root.insert("downloadBandwidthMbps".to_owned(), site.max_down_mbps.into());
|
||||
root.insert(
|
||||
"downloadBandwidthMbps".to_owned(),
|
||||
site.max_down_mbps.into(),
|
||||
);
|
||||
root.insert("uploadBandwidthMbps".to_owned(), site.max_up_mbps.into());
|
||||
root.insert("uisp_site".to_string(), site.id.clone().into());
|
||||
root.insert("parent_site".to_string(), name.to_string().into());
|
||||
@@ -203,7 +219,11 @@ impl Layer {
|
||||
}
|
||||
GraphMapping::ClientById(client_id) => {
|
||||
if let Some(site) = uisp_data.sites.iter().find(|c| c.id == *client_id) {
|
||||
let devices = uisp_data.devices.iter().filter(|d| d.site_id == *client_id).collect::<Vec<_>>();
|
||||
let devices = uisp_data
|
||||
.devices
|
||||
.iter()
|
||||
.filter(|d| d.site_id == *client_id)
|
||||
.collect::<Vec<_>>();
|
||||
for device in devices.iter().filter(|d| d.has_address()) {
|
||||
let sd = ShapedDevice {
|
||||
circuit_id: site.id.clone(),
|
||||
@@ -238,7 +258,10 @@ impl Layer {
|
||||
}
|
||||
}
|
||||
if parent.is_some() {
|
||||
root.insert("children".to_string(), serde_json::to_value(children).unwrap());
|
||||
root.insert(
|
||||
"children".to_string(),
|
||||
serde_json::to_value(children).unwrap(),
|
||||
);
|
||||
} else {
|
||||
for child in children {
|
||||
root.insert(child.0, child.1);
|
||||
@@ -253,9 +276,7 @@ pub struct TroublesomeClients {
|
||||
pub client_of_clients: HashSet<String>,
|
||||
}
|
||||
|
||||
pub(crate) async fn find_troublesome_sites(
|
||||
data: &UispData,
|
||||
) -> anyhow::Result<TroublesomeClients> {
|
||||
pub(crate) async fn find_troublesome_sites(data: &UispData) -> anyhow::Result<TroublesomeClients> {
|
||||
let multi_entry_points = find_clients_with_multiple_entry_points(data)?;
|
||||
let client_of_clients = find_clients_linked_from_other_clients(data)?;
|
||||
|
||||
@@ -268,17 +289,19 @@ pub(crate) async fn find_troublesome_sites(
|
||||
})
|
||||
}
|
||||
|
||||
fn find_clients_with_multiple_entry_points(
|
||||
data: &UispData,
|
||||
) -> anyhow::Result<HashSet<String>> {
|
||||
fn find_clients_with_multiple_entry_points(data: &UispData) -> anyhow::Result<HashSet<String>> {
|
||||
let mut result = HashSet::new();
|
||||
for client in data.find_client_sites() {
|
||||
let mut links_to_client = HashSet::new();
|
||||
for link in data.data_links_raw.iter() {
|
||||
if let (Some(from_site), Some(to_site)) = (&link.from.site, &link.to.site) {
|
||||
if from_site.identification.id == client.id && to_site.identification.id != client.id {
|
||||
if from_site.identification.id == client.id
|
||||
&& to_site.identification.id != client.id
|
||||
{
|
||||
links_to_client.insert(to_site.identification.id.clone());
|
||||
} else if from_site.identification.id != client.id && to_site.identification.id == client.id {
|
||||
} else if from_site.identification.id != client.id
|
||||
&& to_site.identification.id == client.id
|
||||
{
|
||||
links_to_client.insert(from_site.identification.id.clone());
|
||||
}
|
||||
}
|
||||
@@ -295,24 +318,30 @@ fn find_clients_with_multiple_entry_points(
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn find_clients_linked_from_other_clients(
|
||||
data: &UispData
|
||||
) -> anyhow::Result<HashSet<String>> {
|
||||
fn find_clients_linked_from_other_clients(data: &UispData) -> anyhow::Result<HashSet<String>> {
|
||||
let all_clients = data.find_client_sites();
|
||||
let mut result = HashSet::new();
|
||||
for client in &all_clients {
|
||||
for link in data.data_links_raw.iter() {
|
||||
if let (Some(from_site), Some(to_site)) = (&link.from.site, &link.to.site) {
|
||||
if from_site.identification.id == client.id && to_site.identification.id != client.id
|
||||
&& all_clients.iter().any(|c| c.id == to_site.identification.id) {
|
||||
if from_site.identification.id == client.id
|
||||
&& to_site.identification.id != client.id
|
||||
&& all_clients
|
||||
.iter()
|
||||
.any(|c| c.id == to_site.identification.id)
|
||||
{
|
||||
warn!(
|
||||
"Client {} is linked from another client: {}",
|
||||
client.name, to_site.identification.id
|
||||
);
|
||||
result.insert(client.id.clone());
|
||||
}
|
||||
if from_site.identification.id != client.id && to_site.identification.id == client.id
|
||||
&& all_clients.iter().any(|c| c.id == from_site.identification.id) {
|
||||
if from_site.identification.id != client.id
|
||||
&& to_site.identification.id == client.id
|
||||
&& all_clients
|
||||
.iter()
|
||||
.any(|c| c.id == from_site.identification.id)
|
||||
{
|
||||
warn!(
|
||||
"Client {} is linked to another client: {}",
|
||||
client.name, from_site.identification.id
|
||||
@@ -323,4 +352,4 @@ fn find_clients_linked_from_other_clients(
|
||||
}
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,14 @@
|
||||
use crate::blackboard_blob;
|
||||
use crate::errors::UispIntegrationError;
|
||||
use crate::ip_ranges::IpRanges;
|
||||
use crate::strategies::full::parse::parse_uisp_datasets;
|
||||
use crate::strategies::full::uisp_fetch::load_uisp_data;
|
||||
use crate::uisp_types::{UispDataLink, UispDevice, UispSite, UispSiteType};
|
||||
use lqos_config::Config;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use tracing::warn;
|
||||
use lqos_config::Config;
|
||||
use uisp::{DataLink, Device, Site};
|
||||
use crate::blackboard_blob;
|
||||
use crate::ip_ranges::IpRanges;
|
||||
use crate::strategies::full::uisp_fetch::load_uisp_data;
|
||||
use crate::errors::UispIntegrationError;
|
||||
use crate::strategies::full::parse::parse_uisp_datasets;
|
||||
use crate::uisp_types::{UispDataLink, UispDevice, UispSite, UispSiteType};
|
||||
|
||||
pub(crate) struct UispData {
|
||||
pub sites_raw: Vec<Site>,
|
||||
@@ -63,19 +63,29 @@ impl UispData {
|
||||
}
|
||||
|
||||
pub fn find_client_sites(&self) -> Vec<&UispSite> {
|
||||
self.sites.iter().filter(|s| s.site_type == UispSiteType::Client).collect()
|
||||
self.sites
|
||||
.iter()
|
||||
.filter(|s| s.site_type == UispSiteType::Client)
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn find_devices_in_site(&self, site_id: &str) -> Vec<&Device> {
|
||||
self.devices_raw.iter().filter(|d| d.get_site_id().unwrap_or_default() == site_id).collect()
|
||||
self.devices_raw
|
||||
.iter()
|
||||
.filter(|d| d.get_site_id().unwrap_or_default() == site_id)
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn find_device_by_id(&self, device_id: &str) -> Option<&Device> {
|
||||
self.devices_raw.iter().find(|d| d.identification.id == device_id)
|
||||
self.devices_raw
|
||||
.iter()
|
||||
.find(|d| d.identification.id == device_id)
|
||||
}
|
||||
|
||||
pub fn find_device_by_name(&self, device_name: &str) -> Option<&Device> {
|
||||
self.devices_raw.iter().find(|d| d.get_name().unwrap_or_default() == device_name)
|
||||
self.devices_raw
|
||||
.iter()
|
||||
.find(|d| d.get_name().unwrap_or_default() == device_name)
|
||||
}
|
||||
|
||||
pub fn map_clients_to_aps(&self) -> HashMap<String, Vec<String>> {
|
||||
@@ -120,9 +130,12 @@ impl UispData {
|
||||
if let Some(from_device) = &link.from.device {
|
||||
if from_device.identification.id == device.identification.id {
|
||||
if let Some(to_device) = &link.to.device {
|
||||
if let Some(apdev) = self.find_device_by_id(&to_device.identification.id) {
|
||||
if let Some(apdev) =
|
||||
self.find_device_by_id(&to_device.identification.id)
|
||||
{
|
||||
if apdev.get_site_id().unwrap_or_default() != client.id {
|
||||
parent = Some(("AP", apdev.get_name().unwrap_or_default()));
|
||||
parent =
|
||||
Some(("AP", apdev.get_name().unwrap_or_default()));
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
@@ -133,9 +146,12 @@ impl UispData {
|
||||
if let Some(to_device) = &link.to.device {
|
||||
if to_device.identification.id == device.identification.id {
|
||||
if let Some(from_device) = &link.from.device {
|
||||
if let Some(apdev) = self.find_device_by_id(&from_device.identification.id) {
|
||||
if let Some(apdev) =
|
||||
self.find_device_by_id(&from_device.identification.id)
|
||||
{
|
||||
if apdev.get_site_id().unwrap_or_default() != client.id {
|
||||
parent = Some(("AP", apdev.get_name().unwrap_or_default()));
|
||||
parent =
|
||||
Some(("AP", apdev.get_name().unwrap_or_default()));
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
@@ -152,7 +168,9 @@ impl UispData {
|
||||
if let Some(from_site) = &link.from.site {
|
||||
if from_site.identification.id == client.id {
|
||||
if let Some(to_device) = &link.to.device {
|
||||
if let Some(apdev) = self.find_device_by_id(&to_device.identification.id) {
|
||||
if let Some(apdev) =
|
||||
self.find_device_by_id(&to_device.identification.id)
|
||||
{
|
||||
if apdev.get_site_id().unwrap_or_default() != client.id {
|
||||
parent = Some(("AP", apdev.get_name().unwrap_or_default()));
|
||||
found = true;
|
||||
@@ -164,7 +182,9 @@ impl UispData {
|
||||
if let Some(to_site) = &link.to.site {
|
||||
if to_site.identification.id == client.id {
|
||||
if let Some(from_device) = &link.from.device {
|
||||
if let Some(apdev) = self.find_device_by_id(&from_device.identification.id) {
|
||||
if let Some(apdev) =
|
||||
self.find_device_by_id(&from_device.identification.id)
|
||||
{
|
||||
if apdev.get_site_id().unwrap_or_default() != client.id {
|
||||
parent = Some(("AP", apdev.get_name().unwrap_or_default()));
|
||||
found = true;
|
||||
@@ -178,7 +198,9 @@ impl UispData {
|
||||
|
||||
if !found {
|
||||
//println!("Client {} has no obvious parent AP", client.name);
|
||||
let entry = mappings.entry("Orphans".to_string()).or_insert_with(Vec::new);
|
||||
let entry = mappings
|
||||
.entry("Orphans".to_string())
|
||||
.or_insert_with(Vec::new);
|
||||
entry.push(client.id.clone());
|
||||
} else {
|
||||
//info!("Client {} is connected to {:?}", client.name, parent);
|
||||
@@ -191,4 +213,3 @@ impl UispData {
|
||||
mappings
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
mod dot;
|
||||
mod graph_mapping;
|
||||
mod link_mapping;
|
||||
mod dot;
|
||||
mod net_json_parent;
|
||||
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::fs::write;
|
||||
use std::path::Path;
|
||||
use crate::blackboard_blob;
|
||||
use crate::errors::UispIntegrationError;
|
||||
use crate::ip_ranges::IpRanges;
|
||||
use crate::strategies::common::UispData;
|
||||
use crate::uisp_types::UispDevice;
|
||||
use lqos_config::Config;
|
||||
use std::sync::Arc;
|
||||
use petgraph::{Graph, Undirected};
|
||||
use petgraph::graph::NodeIndex;
|
||||
use tracing::{error, info, warn};
|
||||
use petgraph::visit::{EdgeRef, NodeRef};
|
||||
use crate::blackboard_blob;
|
||||
use crate::strategies::full::routes_override::RouteOverride;
|
||||
use crate::strategies::full::shaped_devices_writer::ShapedDevice;
|
||||
use crate::strategies::full2::dot::save_dot_file;
|
||||
use crate::strategies::full2::graph_mapping::GraphMapping;
|
||||
use crate::strategies::full2::link_mapping::LinkMapping;
|
||||
use crate::strategies::full2::net_json_parent::{walk_parents, NetJsonParent};
|
||||
use crate::strategies::full::routes_override::RouteOverride;
|
||||
use crate::strategies::full::shaped_devices_writer::ShapedDevice;
|
||||
use crate::strategies::full2::net_json_parent::{NetJsonParent, walk_parents};
|
||||
use crate::uisp_types::UispDevice;
|
||||
use lqos_config::Config;
|
||||
use petgraph::graph::NodeIndex;
|
||||
use petgraph::visit::{EdgeRef, NodeRef};
|
||||
use petgraph::{Graph, Undirected};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::fs::write;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
use tracing::{error, info, warn};
|
||||
|
||||
type GraphType = petgraph::Graph<GraphMapping, LinkMapping, Undirected>;
|
||||
|
||||
@@ -34,15 +34,17 @@ pub async fn build_full_network_v2(
|
||||
let uisp_data = UispData::fetch_uisp_data(config.clone(), ip_ranges).await?;
|
||||
|
||||
// Report on obvious UISP errors that should be fixed
|
||||
let _trouble = crate::strategies::ap_site::find_troublesome_sites(&uisp_data).await
|
||||
let _trouble = crate::strategies::ap_site::find_troublesome_sites(&uisp_data)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
error!("Error finding troublesome sites");
|
||||
error!("{e:?}");
|
||||
UispIntegrationError::UnknownSiteType
|
||||
})?;
|
||||
error!("Error finding troublesome sites");
|
||||
error!("{e:?}");
|
||||
UispIntegrationError::UnknownSiteType
|
||||
})?;
|
||||
|
||||
// Load overrides
|
||||
let bandwidth_overrides = crate::strategies::full::bandwidth_overrides::get_site_bandwidth_overrides(&config)?;
|
||||
let bandwidth_overrides =
|
||||
crate::strategies::full::bandwidth_overrides::get_site_bandwidth_overrides(&config)?;
|
||||
let routing_overrides = crate::strategies::full::routes_override::get_route_overrides(&config)?;
|
||||
|
||||
// Create a new graph
|
||||
@@ -54,7 +56,13 @@ pub async fn build_full_network_v2(
|
||||
// Add all sites to the graph
|
||||
let mut site_map = HashMap::new();
|
||||
let mut root_idx = None;
|
||||
add_all_sites_to_graph(&uisp_data, &mut graph, &root_site_name, &mut site_map, &mut root_idx);
|
||||
add_all_sites_to_graph(
|
||||
&uisp_data,
|
||||
&mut graph,
|
||||
&root_site_name,
|
||||
&mut site_map,
|
||||
&mut root_idx,
|
||||
);
|
||||
let root_idx = root_idx.expect("Root site not found");
|
||||
|
||||
// Iterate all UISP devices and if their parent site is in the graph, add them
|
||||
@@ -65,21 +73,16 @@ pub async fn build_full_network_v2(
|
||||
add_device_links_to_graph(&uisp_data, &mut graph, &mut device_map);
|
||||
|
||||
// Now we iterate only sites, looking for connectivity to the root
|
||||
let orphans = graph.add_node(GraphMapping::GeneratedSite{ name: "Orphans".to_string()});
|
||||
let orphans = graph.add_node(GraphMapping::GeneratedSite {
|
||||
name: "Orphans".to_string(),
|
||||
});
|
||||
graph.add_edge(root_idx, orphans, LinkMapping::Ethernet);
|
||||
for (_, site_ref) in site_map.iter() {
|
||||
if *site_ref == root_idx {
|
||||
continue;
|
||||
}
|
||||
let a_star_run = petgraph::algo::astar(
|
||||
&graph,
|
||||
*site_ref,
|
||||
|n| {
|
||||
n.id() == root_idx.id()
|
||||
},
|
||||
|_| 0,
|
||||
|_| 0,
|
||||
);
|
||||
let a_star_run =
|
||||
petgraph::algo::astar(&graph, *site_ref, |n| n.id() == root_idx.id(), |_| 0, |_| 0);
|
||||
|
||||
if a_star_run.is_none() {
|
||||
warn!(
|
||||
@@ -96,7 +99,11 @@ pub async fn build_full_network_v2(
|
||||
// Find the APs that have clients
|
||||
let mut aps_with_clients = HashSet::new();
|
||||
for (ap_name, _client_ids) in client_mappings.iter() {
|
||||
let Some(ap_device) = uisp_data.devices_raw.iter().find(|d| d.get_name().unwrap_or_default() == *ap_name) else {
|
||||
let Some(ap_device) = uisp_data
|
||||
.devices_raw
|
||||
.iter()
|
||||
.find(|d| d.get_name().unwrap_or_default() == *ap_name)
|
||||
else {
|
||||
// Orphaning is already handled
|
||||
continue;
|
||||
};
|
||||
@@ -106,11 +113,11 @@ pub async fn build_full_network_v2(
|
||||
// Count linkages to APs
|
||||
let mut ap_link_count = HashMap::<String, usize>::new();
|
||||
for edge_ref in graph.edge_references() {
|
||||
if let GraphMapping::AccessPoint{ref id, ..} = graph[edge_ref.source()] {
|
||||
if let GraphMapping::AccessPoint { ref id, .. } = graph[edge_ref.source()] {
|
||||
let entry = ap_link_count.entry(id.clone()).or_insert(0);
|
||||
*entry += 1;
|
||||
};
|
||||
if let GraphMapping::AccessPoint{ref id, ..} = graph[edge_ref.target()] {
|
||||
if let GraphMapping::AccessPoint { ref id, .. } = graph[edge_ref.target()] {
|
||||
let entry = ap_link_count.entry(id.clone()).or_insert(0);
|
||||
*entry += 1;
|
||||
};
|
||||
@@ -129,7 +136,10 @@ pub async fn build_full_network_v2(
|
||||
}
|
||||
to_remove.push(*ap_ref);
|
||||
}
|
||||
info!("Removing {} APs with no clients or only one link", to_remove.len());
|
||||
info!(
|
||||
"Removing {} APs with no clients or only one link",
|
||||
to_remove.len()
|
||||
);
|
||||
for ap_ref in to_remove.iter() {
|
||||
graph.remove_node(*ap_ref);
|
||||
}
|
||||
@@ -145,36 +155,52 @@ pub async fn build_full_network_v2(
|
||||
continue;
|
||||
}
|
||||
match &graph[node] {
|
||||
GraphMapping::GeneratedSite{name} | GraphMapping::Site{name, ..} |
|
||||
GraphMapping::AccessPoint{name, ..} => {
|
||||
GraphMapping::GeneratedSite { name }
|
||||
| GraphMapping::Site { name, .. }
|
||||
| GraphMapping::AccessPoint { name, .. } => {
|
||||
let route = petgraph::algo::astar(
|
||||
&graph,
|
||||
root_idx,
|
||||
|n| n == node,
|
||||
|e| (10_000u64).saturating_sub(link_capacity_mbps(&e.weight(), &uisp_data.devices, &routing_overrides)),
|
||||
|e| {
|
||||
(10_000u64).saturating_sub(link_capacity_mbps(
|
||||
&e.weight(),
|
||||
&uisp_data.devices,
|
||||
&routing_overrides,
|
||||
))
|
||||
},
|
||||
|_| 0,
|
||||
).unwrap_or((0, vec![]));
|
||||
)
|
||||
.unwrap_or((0, vec![]));
|
||||
|
||||
if route.1.is_empty() {
|
||||
//println!("No path detected from {:?} to {}", graph[node], root_site_name);
|
||||
parents.insert(name.to_owned(), NetJsonParent {
|
||||
parent_name: "Orphans".to_string(),
|
||||
mapping: &graph[node],
|
||||
download: config.queues.generated_pn_download_mbps,
|
||||
upload: config.queues.generated_pn_upload_mbps,
|
||||
});
|
||||
parents.insert(
|
||||
name.to_owned(),
|
||||
NetJsonParent {
|
||||
parent_name: "Orphans".to_string(),
|
||||
mapping: &graph[node],
|
||||
download: config.queues.generated_pn_download_mbps,
|
||||
upload: config.queues.generated_pn_upload_mbps,
|
||||
},
|
||||
);
|
||||
} else {
|
||||
let mut capacity = (config.queues.generated_pn_download_mbps,config.queues.generated_pn_upload_mbps);
|
||||
if !config.uisp_integration.ignore_calculated_capacity {
|
||||
match &graph[node] {
|
||||
GraphMapping::AccessPoint { id, .. } => {
|
||||
if let Some(device) = uisp_data.devices.iter().find(|d| d.id == *id) {
|
||||
capacity = (device.download, device.upload);
|
||||
if let Some(bw_override) = bandwidth_overrides.get(&device.name) {
|
||||
capacity = (bw_override.0 as u64, bw_override.1 as u64);
|
||||
}
|
||||
let mut capacity = (
|
||||
config.queues.generated_pn_download_mbps,
|
||||
config.queues.generated_pn_upload_mbps,
|
||||
);
|
||||
if !config.uisp_integration.ignore_calculated_capacity {
|
||||
match &graph[node] {
|
||||
GraphMapping::AccessPoint { id, .. } => {
|
||||
if let Some(device) = uisp_data.devices.iter().find(|d| d.id == *id)
|
||||
{
|
||||
capacity = (device.download, device.upload);
|
||||
if let Some(bw_override) = bandwidth_overrides.get(&device.name)
|
||||
{
|
||||
capacity = (bw_override.0 as u64, bw_override.1 as u64);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@@ -183,12 +209,15 @@ pub async fn build_full_network_v2(
|
||||
// We need the weight from node to parent_node in the graph edges
|
||||
if let Some(_edge) = graph.find_edge(parent_node, node) {
|
||||
let parent = graph[route.1[route.1.len() - 2]].name();
|
||||
parents.insert(name.to_owned(), NetJsonParent {
|
||||
parent_name: parent,
|
||||
mapping: &graph[node],
|
||||
download: capacity.0,
|
||||
upload: capacity.1,
|
||||
});
|
||||
parents.insert(
|
||||
name.to_owned(),
|
||||
NetJsonParent {
|
||||
parent_name: parent,
|
||||
mapping: &graph[node],
|
||||
download: capacity.0,
|
||||
upload: capacity.1,
|
||||
},
|
||||
);
|
||||
} else {
|
||||
panic!("DID NOT FIND THE EDGE");
|
||||
}
|
||||
@@ -200,14 +229,14 @@ pub async fn build_full_network_v2(
|
||||
|
||||
// Write the network.json file
|
||||
let mut network_json = serde_json::Map::new();
|
||||
for (name, node_info) in parents.iter().filter(|(_name, parent)| parent.parent_name == root_site_name) {
|
||||
network_json.insert(name.into(), walk_parents(
|
||||
&parents,
|
||||
name,
|
||||
&node_info,
|
||||
&config,
|
||||
&graph,
|
||||
).into());
|
||||
for (name, node_info) in parents
|
||||
.iter()
|
||||
.filter(|(_name, parent)| parent.parent_name == root_site_name)
|
||||
{
|
||||
network_json.insert(
|
||||
name.into(),
|
||||
walk_parents(&parents, name, &node_info, &config, &graph).into(),
|
||||
);
|
||||
}
|
||||
let network_path = Path::new(&config.lqos_directory).join("network.json");
|
||||
if network_path.exists() && !config.integration_common.always_overwrite_network_json {
|
||||
@@ -240,10 +269,14 @@ pub async fn build_full_network_v2(
|
||||
continue;
|
||||
}
|
||||
|
||||
let download = (site.max_down_mbps as f32) * config.uisp_integration.bandwidth_overhead_factor;
|
||||
let upload = (site.max_up_mbps as f32) * config.uisp_integration.bandwidth_overhead_factor;
|
||||
let download_min = (download * config.uisp_integration.commit_bandwidth_multiplier) as u64;
|
||||
let upload_min = (upload * config.uisp_integration.commit_bandwidth_multiplier) as u64;
|
||||
let download =
|
||||
(site.max_down_mbps as f32) * config.uisp_integration.bandwidth_overhead_factor;
|
||||
let upload =
|
||||
(site.max_up_mbps as f32) * config.uisp_integration.bandwidth_overhead_factor;
|
||||
let download_min =
|
||||
(download * config.uisp_integration.commit_bandwidth_multiplier) as u64;
|
||||
let upload_min =
|
||||
(upload * config.uisp_integration.commit_bandwidth_multiplier) as u64;
|
||||
let download_max = download as u64;
|
||||
let upload_max = upload as u64;
|
||||
|
||||
@@ -285,7 +318,11 @@ pub async fn build_full_network_v2(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn add_device_links_to_graph(uisp_data: &UispData, graph: &mut Graph<GraphMapping, LinkMapping, Undirected>, device_map: &mut HashMap<String, NodeIndex>) {
|
||||
fn add_device_links_to_graph(
|
||||
uisp_data: &UispData,
|
||||
graph: &mut Graph<GraphMapping, LinkMapping, Undirected>,
|
||||
device_map: &mut HashMap<String, NodeIndex>,
|
||||
) {
|
||||
for link in uisp_data.data_links_raw.iter() {
|
||||
let Some(from_device) = &link.from.device else {
|
||||
continue;
|
||||
@@ -303,9 +340,19 @@ fn add_device_links_to_graph(uisp_data: &UispData, graph: &mut Graph<GraphMappin
|
||||
// If the devices are the same, we don't need to add an edge
|
||||
continue;
|
||||
}
|
||||
if let Some(dev_a) = uisp_data.devices_raw.iter().find(|d| d.get_id() == from_device.identification.id) {
|
||||
if let Some(dev_b) = uisp_data.devices_raw.iter().find(|d| d.get_id() == to_device.identification.id) {
|
||||
if dev_a.get_site_id().unwrap_or_default() == dev_b.get_site_id().unwrap_or_default() {
|
||||
if let Some(dev_a) = uisp_data
|
||||
.devices_raw
|
||||
.iter()
|
||||
.find(|d| d.get_id() == from_device.identification.id)
|
||||
{
|
||||
if let Some(dev_b) = uisp_data
|
||||
.devices_raw
|
||||
.iter()
|
||||
.find(|d| d.get_id() == to_device.identification.id)
|
||||
{
|
||||
if dev_a.get_site_id().unwrap_or_default()
|
||||
== dev_b.get_site_id().unwrap_or_default()
|
||||
{
|
||||
// If the devices are in the same site, we don't need to add an edge
|
||||
continue;
|
||||
}
|
||||
@@ -315,11 +362,23 @@ fn add_device_links_to_graph(uisp_data: &UispData, graph: &mut Graph<GraphMappin
|
||||
// If the edge already exists, we don't need to add it
|
||||
continue;
|
||||
}
|
||||
graph.add_edge(*a_ref, *b_ref, LinkMapping::DevicePair(from_device.identification.id.clone(), to_device.identification.id.clone()));
|
||||
graph.add_edge(
|
||||
*a_ref,
|
||||
*b_ref,
|
||||
LinkMapping::DevicePair(
|
||||
from_device.identification.id.clone(),
|
||||
to_device.identification.id.clone(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn add_devices_to_graph(uisp_data: &UispData, graph: &mut Graph<GraphMapping, LinkMapping, Undirected>, site_map: &mut HashMap<String, NodeIndex>, device_map: &mut HashMap<String, NodeIndex>) {
|
||||
fn add_devices_to_graph(
|
||||
uisp_data: &UispData,
|
||||
graph: &mut Graph<GraphMapping, LinkMapping, Undirected>,
|
||||
site_map: &mut HashMap<String, NodeIndex>,
|
||||
device_map: &mut HashMap<String, NodeIndex>,
|
||||
) {
|
||||
for device in uisp_data.devices_raw.iter() {
|
||||
let Some(site_id) = &device.identification.site else {
|
||||
continue;
|
||||
@@ -339,7 +398,13 @@ fn add_devices_to_graph(uisp_data: &UispData, graph: &mut Graph<GraphMapping, Li
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_all_sites_to_graph(uisp_data: &UispData, graph: &mut Graph<GraphMapping, LinkMapping, Undirected>, root_site_name: &String, site_map: &mut HashMap<String, NodeIndex>, root_idx: &mut Option<NodeIndex>) {
|
||||
pub fn add_all_sites_to_graph(
|
||||
uisp_data: &UispData,
|
||||
graph: &mut Graph<GraphMapping, LinkMapping, Undirected>,
|
||||
root_site_name: &String,
|
||||
site_map: &mut HashMap<String, NodeIndex>,
|
||||
root_idx: &mut Option<NodeIndex>,
|
||||
) {
|
||||
for site in uisp_data.sites_raw.iter().filter(|s| !s.is_client_site()) {
|
||||
let site_name = site.name_or_blank();
|
||||
let id = site.id.clone();
|
||||
@@ -363,20 +428,30 @@ pub fn add_all_sites_to_graph(uisp_data: &UispData, graph: &mut Graph<GraphMappi
|
||||
}
|
||||
}
|
||||
|
||||
fn link_capacity_mbps(link_mapping: &LinkMapping, devices: &[UispDevice], route_overrides: &[RouteOverride]) -> u64 {
|
||||
fn link_capacity_mbps(
|
||||
link_mapping: &LinkMapping,
|
||||
devices: &[UispDevice],
|
||||
route_overrides: &[RouteOverride],
|
||||
) -> u64 {
|
||||
match link_mapping {
|
||||
LinkMapping::Ethernet => 10_000,
|
||||
LinkMapping::DevicePair(device_a, device_b) => {
|
||||
let capacity ;
|
||||
let capacity;
|
||||
|
||||
if let Some(device_a) = devices.iter().find(|d| d.id == *device_a) {
|
||||
if let Some(override_a) = route_overrides.iter().find(|o| o.from_site == device_a.name || o.to_site == device_a.name) {
|
||||
if let Some(override_a) = route_overrides
|
||||
.iter()
|
||||
.find(|o| o.from_site == device_a.name || o.to_site == device_a.name)
|
||||
{
|
||||
capacity = override_a.cost as u64;
|
||||
} else {
|
||||
capacity = device_a.download;
|
||||
}
|
||||
} else if let Some(device_b) = devices.iter().find(|d| d.id == *device_b) {
|
||||
if let Some(override_b) = route_overrides.iter().find(|o| o.from_site == device_b.name || o.to_site == device_b.name) {
|
||||
if let Some(override_b) = route_overrides
|
||||
.iter()
|
||||
.find(|o| o.from_site == device_b.name || o.to_site == device_b.name)
|
||||
{
|
||||
capacity = override_b.cost as u64;
|
||||
} else {
|
||||
capacity = device_b.download;
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
use std::fs::write;
|
||||
use crate::errors::UispIntegrationError;
|
||||
use crate::strategies::full2::GraphType;
|
||||
use std::fs::write;
|
||||
|
||||
pub fn save_dot_file(graph: &GraphType) -> Result<(), UispIntegrationError> {
|
||||
// Save the dot file
|
||||
let dot_data = format!("{:?}", petgraph::dot::Dot::with_config(graph, &[petgraph::dot::Config::EdgeNoLabel]));
|
||||
let dot_data = format!(
|
||||
"{:?}",
|
||||
petgraph::dot::Dot::with_config(graph, &[petgraph::dot::Config::EdgeNoLabel])
|
||||
);
|
||||
let _ = write("graph.dot", dot_data.as_bytes());
|
||||
let _ = std::process::Command::new("dot")
|
||||
.arg("-Tpng")
|
||||
@@ -13,4 +16,4 @@ pub fn save_dot_file(graph: &GraphType) -> Result<(), UispIntegrationError> {
|
||||
.arg("graph.png")
|
||||
.output();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -2,10 +2,22 @@ use serde::Serialize;
|
||||
|
||||
#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Clone, Serialize)]
|
||||
pub enum GraphMapping {
|
||||
Root { name: String, id: String },
|
||||
Site { name: String, id: String },
|
||||
GeneratedSite { name: String },
|
||||
AccessPoint { name: String, id: String, site_name: String },
|
||||
Root {
|
||||
name: String,
|
||||
id: String,
|
||||
},
|
||||
Site {
|
||||
name: String,
|
||||
id: String,
|
||||
},
|
||||
GeneratedSite {
|
||||
name: String,
|
||||
},
|
||||
AccessPoint {
|
||||
name: String,
|
||||
id: String,
|
||||
site_name: String,
|
||||
},
|
||||
}
|
||||
|
||||
impl GraphMapping {
|
||||
@@ -17,4 +29,4 @@ impl GraphMapping {
|
||||
GraphMapping::AccessPoint { name, .. } => name.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,4 +4,4 @@ use serde::Serialize;
|
||||
pub enum LinkMapping {
|
||||
Ethernet,
|
||||
DevicePair(String, String),
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
use crate::strategies::full2::GraphType;
|
||||
use crate::strategies::full2::graph_mapping::GraphMapping;
|
||||
use lqos_config::Config;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use lqos_config::Config;
|
||||
use crate::strategies::full2::graph_mapping::GraphMapping;
|
||||
use crate::strategies::full2::GraphType;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct NetJsonParent<'a> {
|
||||
@@ -33,7 +33,11 @@ pub fn walk_parents(
|
||||
GraphMapping::GeneratedSite { .. } => {
|
||||
map.insert("type".into(), "Site".into());
|
||||
}
|
||||
GraphMapping::AccessPoint { name: _, id, site_name } => {
|
||||
GraphMapping::AccessPoint {
|
||||
name: _,
|
||||
id,
|
||||
site_name,
|
||||
} => {
|
||||
map.insert("type".into(), "AP".into());
|
||||
map.insert("parent_site".into(), site_name.clone().into());
|
||||
map.insert("uisp_device".into(), id.clone().into());
|
||||
@@ -41,8 +45,10 @@ pub fn walk_parents(
|
||||
}
|
||||
|
||||
let mut children = serde_json::Map::new();
|
||||
for (name, node_info) in parents.iter().filter(|(_, node_info)|
|
||||
node_info.parent_name == *name) {
|
||||
for (name, node_info) in parents
|
||||
.iter()
|
||||
.filter(|(_, node_info)| node_info.parent_name == *name)
|
||||
{
|
||||
let child = walk_parents(parents, name, &node_info, config, graph);
|
||||
children.insert(name.into(), child.into());
|
||||
}
|
||||
@@ -50,4 +56,4 @@ pub fn walk_parents(
|
||||
map.insert("children".into(), children.into());
|
||||
|
||||
map
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
mod flat;
|
||||
mod full;
|
||||
mod ap_only;
|
||||
mod ap_site;
|
||||
mod common;
|
||||
mod flat;
|
||||
mod full;
|
||||
mod full2;
|
||||
|
||||
use crate::blackboard;
|
||||
|
||||
Reference in new issue
Block a user