use snowcap::hard_policies::*;
use snowcap::netsim::{config::Config, printer, Network, NetworkError};
use snowcap::optimizers::*;
use snowcap::permutators::*;
use snowcap::soft_policies::*;
use snowcap::strategies::*;
use snowcap::topology_zoo::{self, ZooTopology};
use snowcap::{optimize, synthesize, Stopper};
use snowcap_bencher::*;
use snowcap_runtime::perform_migration;
use clap::Clap;
use log::*;
use rand::prelude::*;
use std::error::Error;
use std::fmt;
mod example_topologies;
use example_topologies::*;
mod transient_violation;
use transient_violation::*;
fn main() -> Result<(), Box<dyn Error>> {
let args = CommandLineArguments::parse();
match args.cmd {
MainCommand::TransientViolation {
gml_file,
seed,
n_seeds,
n_iter,
reverse,
num_threads,
} => {
transient_violation_topologyzoo(gml_file, seed, n_seeds, n_iter, num_threads, reverse)?
}
MainCommand::CustomOperation { n_iter, variant } => transient_violation(n_iter, variant)?,
MainCommand::Optimize { network, use_tree } => {
pretty_env_logger::init();
let (net, final_config, hard_policy) = get_topo(network)?;
check_config(&net, &final_config)?;
let initial_config = net.current_config().clone();
info!(
"Problem has {} modifiers",
initial_config.get_diff(&final_config).modifiers.len()
);
let mut fw_state = net.get_forwarding_state();
let soft_policy = MinimizeTrafficShift::new(&mut fw_state, &net);
info!("Generating the update sequence");
let (sequence, cost) = if use_tree {
TreeOptimizer::<_>::synthesize(
net.clone(),
final_config,
hard_policy,
soft_policy,
None,
Stopper::new(),
)?
} else {
optimize::<MinimizeTrafficShift>(
net.clone(),
initial_config,
final_config,
hard_policy,
None,
)?
};
info!(
"Update sequence with cost: {}:\n {}",
cost,
sequence
.iter()
.map(|m| printer::config_modifier(&net, m).unwrap())
.collect::<Vec<_>>()
.join("\n "),
);
}
MainCommand::Synthesize { network, use_tree } => {
pretty_env_logger::init();
let (net, final_config, hard_policy) = get_topo(network)?;
check_config(&net, &final_config)?;
let initial_config = net.current_config().clone();
info!(
"Problem has {} modifiers",
initial_config.get_diff(&final_config).modifiers.len()
);
info!("Generating the update sequence");
let sequence = if use_tree {
PermutationStrategy::<RandomTreePermutator>::synthesize(
net.clone(),
final_config,
hard_policy,
None,
Stopper::new(),
)?
} else {
synthesize(
net.clone(),
initial_config,
final_config,
hard_policy,
Some(std::time::Duration::from_secs(3600)),
)?
};
info!(
"Update sequence:\n {}",
sequence
.iter()
.map(|m| printer::config_modifier(&net, m).unwrap())
.collect::<Vec<_>>()
.join("\n "),
);
}
MainCommand::Runtime {
network,
persistent_gns_project,
random_sequence,
at_once,
seed,
json_filename,
} => {
pretty_env_logger::init();
let (net, final_config, hard_policy) = get_topo(network)?;
check_config(&net, &final_config)?;
let initial_config = net.current_config().clone();
let sequence = if random_sequence {
info!("Generating a random update sequence");
let mut s = initial_config.get_diff(&final_config).modifiers;
if let Some(seed) = seed {
let mut rng = StdRng::seed_from_u64(seed);
s.shuffle(&mut rng);
} else {
s.shuffle(&mut thread_rng());
}
s
} else {
info!("Generating the update sequence");
synthesize(
net.clone(),
initial_config,
final_config,
hard_policy,
Some(std::time::Duration::from_secs(3600)),
)?
};
info!(
"Update sequence:\n {}",
sequence
.iter()
.map(|m| printer::config_modifier(&net, m).unwrap())
.collect::<Vec<_>>()
.join("\n "),
);
perform_migration(
&net,
&sequence,
persistent_gns_project,
json_filename,
at_once,
)?;
}
MainCommand::Bencher { network, args } => {
let scenario = network.repr();
let (net, final_config, hard_policy) = get_topo(network)?;
bench(net, final_config, hard_policy, scenario, args)?;
}
}
Ok(())
}
fn get_topo(args: NetworkSelection) -> Result<(Network, Config, HardPolicy), Box<dyn Error>> {
match args {
NetworkSelection::CustomNetwork => custom_scenario(),
NetworkSelection::TopologyZoo {
gml_file,
seed,
many_prefixes,
random_root,
scenario,
} => topology_zoo_scenario(gml_file, seed, many_prefixes, random_root, scenario),
NetworkSelection::ExampleNetwork {
topology,
initial_variant,
final_variant,
repetitions,
} => example_networks_scenario(topology, initial_variant, final_variant, repetitions),
}
}
fn custom_scenario() -> Result<(Network, Config, HardPolicy), Box<dyn Error>> {
todo!()
}
fn topology_zoo_scenario(
gml_file: String,
seed: u64,
many_prefixes: bool,
random_root: bool,
scenario: Scenario,
) -> Result<(Network, Config, HardPolicy), Box<dyn Error>> {
Ok(ZooTopology::new(&gml_file, seed)?.apply_scenario(
scenario.into(),
random_root,
100,
if many_prefixes { 5 } else { 1 },
if many_prefixes { 0.5 } else { 1.0 },
)?)
}
fn check_config(net: &Network, final_config: &Config) -> Result<(), Box<dyn Error>> {
match net.clone().set_config(final_config) {
Ok(()) => Ok(()),
Err(NetworkError::ConvergenceLoop(_, _)) => Ok(()),
Err(NetworkError::NoConvergence) => Ok(()),
Err(e) => Err(e.into()),
}
}
#[derive(Clap, Debug)]
#[clap(name = "Runtime (Binary)", author = "Tibor Schneider")]
struct CommandLineArguments {
#[clap(subcommand)]
cmd: MainCommand,
}
#[derive(Clap, Debug)]
enum MainCommand {
#[clap(name = "synthesize")]
Synthesize {
#[clap(short = 't', long)]
use_tree: bool,
#[clap(subcommand)]
network: NetworkSelection,
},
#[clap(name = "optimize")]
Optimize {
#[clap(short = 't', long)]
use_tree: bool,
#[clap(subcommand)]
network: NetworkSelection,
},
#[clap(name = "run")]
Runtime {
#[clap(subcommand)]
network: NetworkSelection,
#[clap(short = 'p', long)]
persistent_gns_project: bool,
#[clap(short = 'r', long)]
random_sequence: bool,
#[clap(short = 'a', long)]
at_once: bool,
#[clap(short = 's', long)]
seed: Option<u64>,
#[clap(long = "json")]
json_filename: Option<String>,
},
#[clap(name = "bench")]
Bencher {
#[clap(subcommand)]
network: NetworkSelection,
#[clap(flatten)]
args: BencherArguments,
},
#[clap(name = "transient")]
TransientViolation {
gml_file: String,
#[clap(short = 's', long, default_value = "42")]
seed: u64,
#[clap(short = 'n', long, default_value = "10000")]
n_iter: usize,
#[clap(short = 'i', long, default_value = "100")]
n_seeds: usize,
#[clap(short = 'r', long)]
reverse: bool,
#[clap(long)]
num_threads: Option<usize>,
},
#[clap(name = "custom")]
CustomOperation {
#[clap(short = 'n', long, default_value = "10000")]
n_iter: usize,
#[clap(short = 'v', long, default_value = "1")]
variant: usize,
},
}
#[derive(Clap, Debug)]
enum NetworkSelection {
#[clap(name = "custom")]
CustomNetwork,
#[clap(name = "topology-zoo")]
TopologyZoo {
gml_file: String,
#[clap(short = 's', long, default_value = "42")]
seed: u64,
#[clap(short = 'm', long)]
many_prefixes: bool,
#[clap(short = 'r', long)]
random_root: bool,
#[clap(arg_enum)]
scenario: Scenario,
},
#[clap(name = "example")]
ExampleNetwork {
#[clap(short = 'i', long, default_value = "0")]
initial_variant: usize,
#[clap(short = 'f', long)]
final_variant: Option<usize>,
#[clap(arg_enum, short = 'r', long)]
repetitions: Option<Reps>,
#[clap(arg_enum)]
topology: Topology,
},
}
impl NetworkSelection {
pub fn repr(&self) -> String {
match self {
NetworkSelection::CustomNetwork => "Custom Network".to_string(),
NetworkSelection::TopologyZoo {
gml_file,
many_prefixes,
random_root,
scenario,
seed,
} => {
format!(
"{}, s={}, {}{}{}",
gml_file.split('/').collect::<Vec<_>>().last().unwrap(),
seed,
scenario,
if !many_prefixes {
", single-prefix"
} else {
""
},
if *random_root { ", random-root" } else { "" },
)
}
NetworkSelection::ExampleNetwork {
initial_variant,
final_variant,
repetitions,
topology,
} => format!(
"{}{}{}{}",
topology,
if *initial_variant != 0 {
format!(", initial_variant={}", initial_variant)
} else {
"".to_string()
},
if let Some(f) = final_variant {
format!(", final_variant={}", f)
} else {
"".to_string()
},
if let Some(r) = repetitions {
format!(", rep={}", r)
} else {
"".to_string()
}
),
}
}
}
#[derive(Clap, Debug, Clone)]
pub enum Scenario {
#[clap(name = "FM2RR")]
FullMesh2RouteReflector,
#[clap(name = "RR2FM")]
RouteReflector2FullMesh,
#[clap(name = "IGPx2")]
DoubleIgpWeight,
#[clap(name = "IGPdiv2")]
HalveIgpWeight,
#[clap(name = "LPx2")]
DoubleLocalPref,
#[clap(name = "LPdiv2")]
HalveLocalPref,
#[clap(name = "add2ndRR")]
IntroduceSecondRouteReflector,
#[clap(name = "del2ndRR")]
RemoveSecondRouteReflector,
#[clap(name = "NetAcq")]
NetworkAcquisition,
#[clap(name = "NetSplit")]
NetworkSplit,
#[clap(name = "DiscR")]
DisconnectRouter,
#[clap(name = "ConnR")]
ConnectRouter,
#[clap(name = "Transient")]
VerifyTransientCondition,
#[clap(name = "TransientRev")]
VerifyTransientConditionReverse,
}
impl fmt::Display for Scenario {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Scenario::FullMesh2RouteReflector => {
write!(f, "FullMesh2RouteReflector")
}
Scenario::RouteReflector2FullMesh => {
write!(f, "RouteReflector2FullMesh")
}
Scenario::DoubleIgpWeight => {
write!(f, "DoubleIgpWeight")
}
Scenario::HalveIgpWeight => {
write!(f, "HalveIgpWeight")
}
Scenario::DoubleLocalPref => {
write!(f, "DoubleLocalPref")
}
Scenario::HalveLocalPref => {
write!(f, "HalveLocalPref")
}
Scenario::IntroduceSecondRouteReflector => {
write!(f, "IntroduceSecondRouteReflector")
}
Scenario::RemoveSecondRouteReflector => {
write!(f, "RemoveSecondRouteReflector")
}
Scenario::NetworkAcquisition => {
write!(f, "NetworkAcquisition")
}
Scenario::NetworkSplit => {
write!(f, "NetworkSplit")
}
Scenario::DisconnectRouter => {
write!(f, "DisconnectRouter")
}
Scenario::ConnectRouter => {
write!(f, "ConnectRouter")
}
Scenario::VerifyTransientCondition => {
write!(f, "VerifyTransientCondition")
}
Scenario::VerifyTransientConditionReverse => {
write!(f, "VerifyTransientConditionReverse")
}
}
}
}
#[allow(clippy::from_over_into)]
impl Into<topology_zoo::Scenario> for Scenario {
fn into(self) -> topology_zoo::Scenario {
match self {
Scenario::FullMesh2RouteReflector => topology_zoo::Scenario::FullMesh2RouteReflector,
Scenario::RouteReflector2FullMesh => topology_zoo::Scenario::RouteReflector2FullMesh,
Scenario::DoubleIgpWeight => topology_zoo::Scenario::DoubleIgpWeight,
Scenario::HalveIgpWeight => topology_zoo::Scenario::HalveIgpWeight,
Scenario::DoubleLocalPref => topology_zoo::Scenario::DoubleLocalPref,
Scenario::HalveLocalPref => topology_zoo::Scenario::HalveLocalPref,
Scenario::IntroduceSecondRouteReflector => {
topology_zoo::Scenario::IntroduceSecondRouteReflector
}
Scenario::RemoveSecondRouteReflector => {
topology_zoo::Scenario::RemoveSecondRouteReflector
}
Scenario::NetworkAcquisition => topology_zoo::Scenario::NetworkAcquisition,
Scenario::NetworkSplit => topology_zoo::Scenario::NetworkSplit,
Scenario::DisconnectRouter => topology_zoo::Scenario::DisconnectRouter,
Scenario::ConnectRouter => topology_zoo::Scenario::ConnectRouter,
Scenario::VerifyTransientCondition => topology_zoo::Scenario::VerifyTransientCondition,
Scenario::VerifyTransientConditionReverse => {
topology_zoo::Scenario::VerifyTransientConditionReverse
}
}
}
}