Support routing overrides

This commit is contained in:
Herbert Wolverson 2024-04-22 11:14:20 -05:00
parent 6cd3993a34
commit d7181a663d
4 changed files with 78 additions and 24 deletions

View File

@ -3,15 +3,16 @@ use std::path::Path;
use csv::ReaderBuilder;
use tracing::{error, info};
use serde::{Deserialize, Serialize};
use lqos_config::Config;
use crate::errors::UispIntegrationError;
pub type BandwidthOverrides = HashMap<String, (f32, f32)>;
/// Attempts to load integrationUISPbandwidths.csv to use for
/// bandwidth overrides. Returns an empty set if not found.
pub fn get_site_bandwidth_overrides() -> Result<BandwidthOverrides, UispIntegrationError> {
pub fn get_site_bandwidth_overrides(config: &Config) -> Result<BandwidthOverrides, UispIntegrationError> {
info!("Looking for integrationUISPbandwidths.csv");
let file_path = Path::new("integrationUISPbandwidths.csv");
let file_path = Path::new(&config.lqos_directory).join("integrationUISPbandwidths.csv");
if file_path.exists() {
let reader = ReaderBuilder::new()
.comment(Some(b'#'))

View File

@ -7,6 +7,7 @@ mod tree_walk;
mod uisp_fetch;
mod utils;
mod bandwidth_overrides;
mod routes_override;
use crate::errors::UispIntegrationError;
use crate::strategies::full::ap_promotion::promote_access_points;
@ -21,11 +22,15 @@ use crate::uisp_types::UispSite;
use lqos_config::Config;
use crate::strategies::full::bandwidth_overrides::get_site_bandwidth_overrides;
pub use bandwidth_overrides::BandwidthOverrides;
use crate::strategies::full::routes_override::get_route_overrides;
/// Attempt to construct a full hierarchy topology for the UISP network.
pub async fn build_full_network(config: Config) -> Result<(), UispIntegrationError> {
// Load any bandwidth overrides
let bandwidth_overrides = get_site_bandwidth_overrides()?;
let bandwidth_overrides = get_site_bandwidth_overrides(&config)?;
// Load any routing overrrides
let routing_overrides = get_route_overrides(&config)?;
// Obtain the UISP data and transform it into easier to work with types
let (sites_raw, devices_raw, data_links_raw) = load_uisp_data(config.clone()).await?;
@ -55,7 +60,7 @@ pub async fn build_full_network(config: Config) -> Result<(), UispIntegrationErr
squash_single_aps(&mut sites)?;
// Build Path Weights
walk_tree_for_routing(&mut sites, &root_site)?;
walk_tree_for_routing(&mut sites, &root_site, &routing_overrides)?;
// Issue No Parent Warnings
warn_of_no_parents(&sites, &devices_raw);
@ -67,21 +72,3 @@ pub async fn build_full_network(config: Config) -> Result<(), UispIntegrationErr
Ok(())
}
fn walk_node(
idx: usize,
weight: u32,
sites: &mut Vec<UispSite>,
visited: &mut std::collections::HashSet<usize>,
) {
if visited.contains(&idx) {
return;
}
visited.insert(idx);
for i in 0..sites.len() {
if sites[i].parent_indices.contains(&idx) {
sites[i].route_weights.push((idx, weight));
walk_node(i, weight + 10, sites, visited);
}
}
}

View File

@ -0,0 +1,40 @@
use std::path::Path;
use csv::ReaderBuilder;
use serde::Deserialize;
use tracing::{error, info};
use lqos_config::Config;
use crate::errors::UispIntegrationError;
#[derive(Deserialize, Debug)]
pub struct RouteOverride {
pub from_site: String,
pub to_site: String,
pub cost: u32,
}
pub fn get_route_overrides(config: &Config) -> Result<Vec<RouteOverride>, UispIntegrationError> {
let file_path = Path::new(&config.lqos_directory).join("integrationUISProutes.csv");
if file_path.exists() {
let reader = ReaderBuilder::new()
.comment(Some(b'#'))
.trim(csv::Trim::All)
.from_path(file_path);
if reader.is_err() {
error!("Unable to read integrationUISProutes.csv");
error!("{:?}", reader);
return Err(UispIntegrationError::CsvError);
}
let mut reader = reader.unwrap();
let mut overrides = Vec::new();
for result in reader.deserialize::<RouteOverride>() {
if let Ok(result) = result {
overrides.push(result);
}
}
info!("Loaded {} route overrides", overrides.len());
Ok(overrides)
} else {
info!("No integrationUISProutes.csv found - no route overrides loaded.");
Ok(Vec::new())
}
}

View File

@ -1,15 +1,16 @@
use crate::errors::UispIntegrationError;
use crate::strategies::full::walk_node;
use crate::strategies::full::routes_override::RouteOverride;
use crate::uisp_types::{UispSite, UispSiteType};
pub fn walk_tree_for_routing(
sites: &mut Vec<UispSite>,
root_site: &str,
overrides: &Vec<RouteOverride>,
) -> Result<(), UispIntegrationError> {
if let Some(root_idx) = sites.iter().position(|s| s.name == root_site) {
let mut visited = std::collections::HashSet::new();
let mut current_node = root_idx;
walk_node(current_node, 10, sites, &mut visited);
walk_node(current_node, 10, sites, &mut visited, overrides);
} else {
tracing::error!("Unable to build a path-weights graph because I can't find the root node");
return Err(UispIntegrationError::NoRootSite);
@ -26,3 +27,28 @@ pub fn walk_tree_for_routing(
Ok(())
}
fn walk_node(
idx: usize,
weight: u32,
sites: &mut Vec<UispSite>,
visited: &mut std::collections::HashSet<usize>,
overrides: &Vec<RouteOverride>,
) {
if visited.contains(&idx) {
return;
}
visited.insert(idx);
for i in 0..sites.len() {
if sites[i].parent_indices.contains(&idx) {
let from = sites[i].name.clone();
let to = sites[idx].name.clone();
if let Some(route_override) = overrides.iter().find(|o| o.from_site == from && o.to_site == to) {
sites[i].route_weights.push((idx, route_override.cost));
} else {
sites[i].route_weights.push((idx, weight));
}
walk_node(i, weight + 10, sites, visited, overrides);
}
}
}