use crate::{
config::{Config, ConfigExpr, ConfigModifier::*, ConfigPatch, NetworkConfig, RouteMapEdit},
event::{BasicEventQueue, EventQueue},
interactive::InteractiveNetwork,
network::Network,
route_map::{RouteMapBuilder, RouteMapDirection::*},
types::{NetworkError, Prefix, RouterId, SimplePrefix, ASN},
};
#[cfg(feature = "rand_queue")]
use crate::event::{ModelParams, SimpleTimingModel};
macro_rules! link_weight {
($source:expr,$target:expr,$weight:expr) => {
ConfigExpr::IgpLinkWeight {
source: $source,
target: $target,
weight: $weight,
}
};
}
macro_rules! bgp_session {
($source:expr,$target:expr,$client:expr) => {
ConfigExpr::BgpSession {
source: $source,
target: $target,
target_is_client: $client,
}
};
}
#[generic_tests::define]
mod t {
use super::*;
use crate::types::{Ipv4Prefix, SinglePrefix};
fn setup_simple<P, Q>(
net: &mut Network<P, Q>,
) -> (RouterId, RouterId, RouterId, RouterId, RouterId, RouterId)
where
P: Prefix,
Q: EventQueue<P>,
{
let e0 = net.add_router("E0", ASN(1));
let b0 = net.add_router("B0", 65500);
let r0 = net.add_router("R0", 65500);
let r1 = net.add_router("R1", 65500);
let b1 = net.add_router("B1", 65500);
let e1 = net.add_router("E1", ASN(1));
net.add_link(e0, b0).unwrap();
net.add_link(b0, r0).unwrap();
net.add_link(r0, r1).unwrap();
net.add_link(r1, b1).unwrap();
net.add_link(b1, e1).unwrap();
let mut c = Config::new();
c.add(link_weight!(b0, r0, 1.0)).unwrap();
c.add(link_weight!(r0, b0, 1.0)).unwrap();
c.add(link_weight!(r0, r1, 1.0)).unwrap();
c.add(link_weight!(r1, r0, 1.0)).unwrap();
c.add(link_weight!(r1, b1, 1.0)).unwrap();
c.add(link_weight!(b1, r1, 1.0)).unwrap();
c.add(bgp_session!(e0, b0, false)).unwrap();
c.add(bgp_session!(r0, b0, true)).unwrap();
c.add(bgp_session!(r0, r1, false)).unwrap();
c.add(bgp_session!(r1, b1, true)).unwrap();
c.add(bgp_session!(e1, b1, false)).unwrap();
net.set_config(&c).unwrap();
(e0, b0, r0, r1, b1, e1)
}
#[test]
fn test_simple<P: Prefix>() {
let mut net: Network<P, _> = Network::default();
let prefix = P::from(0);
let (e0, b0, r0, r1, b1, e1) = setup_simple(&mut net);
net.advertise_route(e0, prefix, vec![ASN(1), ASN(2), ASN(3)], None, None)
.unwrap();
net.advertise_route(e1, prefix, vec![ASN(1), ASN(2), ASN(3)], None, None)
.unwrap();
test_route!(net, b0, prefix, [b0, e0]);
test_route!(net, r0, prefix, [r0, b0, e0]);
test_route!(net, r1, prefix, [r1, b1, e1]);
test_route!(net, b1, prefix, [b1, e1]);
}
#[test]
#[cfg(feature = "rand_queue")]
fn test_simple_model<P: Prefix>() {
let mut net: Network<P, _> = Network::new(SimpleTimingModel::new(ModelParams::new(
0.1, 1.0, 2.0, 5.0, 0.1,
)));
let prefix = P::from(0);
let (e0, b0, r0, r1, b1, e1) = setup_simple(&mut net);
net.advertise_route(e0, prefix, vec![ASN(1), ASN(2), ASN(3)], None, None)
.unwrap();
net.advertise_route(e1, prefix, vec![ASN(1), ASN(2), ASN(3)], None, None)
.unwrap();
test_route!(net, b0, prefix, [b0, e0]);
test_route!(net, r0, prefix, [r0, b0, e0]);
test_route!(net, r1, prefix, [r1, b1, e1]);
test_route!(net, b1, prefix, [b1, e1]);
}
fn setup_external<P, Q>(
net: &mut Network<P, Q>,
) -> (RouterId, RouterId, RouterId, RouterId, RouterId, RouterId)
where
P: Prefix,
Q: EventQueue<P>,
{
let r1 = net.add_router("r1", 65500);
let r2 = net.add_router("r2", 65500);
let r3 = net.add_router("r3", 65500);
let r4 = net.add_router("r4", 65500);
let e1 = net.add_router("e1", ASN(65101));
let e4 = net.add_router("e4", ASN(65104));
net.add_link(r1, r2).unwrap();
net.add_link(r1, r3).unwrap();
net.add_link(r2, r3).unwrap();
net.add_link(r2, r4).unwrap();
net.add_link(r3, r4).unwrap();
net.add_link(r1, e1).unwrap();
net.add_link(r4, e4).unwrap();
let mut c = Config::new();
c.add(link_weight!(r1, r2, 1.0)).unwrap();
c.add(link_weight!(r1, r3, 1.0)).unwrap();
c.add(link_weight!(r2, r3, 1.0)).unwrap();
c.add(link_weight!(r2, r4, 1.0)).unwrap();
c.add(link_weight!(r3, r4, 3.0)).unwrap();
c.add(link_weight!(r2, r1, 1.0)).unwrap();
c.add(link_weight!(r3, r1, 1.0)).unwrap();
c.add(link_weight!(r3, r2, 1.0)).unwrap();
c.add(link_weight!(r4, r2, 1.0)).unwrap();
c.add(link_weight!(r4, r3, 3.0)).unwrap();
c.add(bgp_session!(r1, e1, false)).unwrap();
c.add(bgp_session!(r1, r2, false)).unwrap();
c.add(bgp_session!(r1, r3, false)).unwrap();
c.add(bgp_session!(r1, r4, false)).unwrap();
net.set_config(&c).unwrap();
(e1, r1, r2, r3, r4, e4)
}
#[test]
fn test_external_router<P: Prefix>() {
let mut net: Network<P, _> = Network::default();
let prefix = P::from(0);
let (e1, r1, r2, r3, r4, e4) = setup_external(&mut net);
net.advertise_route(e1, prefix, vec![ASN(65101), ASN(65200)], None, None)
.unwrap();
net.advertise_route(e4, prefix, vec![ASN(65104), ASN(65200)], None, None)
.unwrap();
test_route!(net, r1, prefix, [r1, e1]);
test_route!(net, r2, prefix, [r2, r1, e1]);
test_route!(net, r3, prefix, [r3, r1, e1]);
test_route!(net, r4, prefix, [r4, r2, r1, e1]);
eprintln!("{:#?}", net.get_router(r2));
net.apply_modifier(&Insert(bgp_session!(r2, r4, false)))
.unwrap();
net.apply_modifier(&Insert(bgp_session!(r3, r4, false)))
.unwrap();
net.apply_modifier(&Insert(bgp_session!(r4, e4, false)))
.unwrap();
eprintln!("{:#?}", net.get_router(r2));
net.apply_modifier(&Remove(bgp_session!(r1, r2, false)))
.unwrap();
net.apply_modifier(&Remove(bgp_session!(r1, r3, false)))
.unwrap();
net.apply_modifier(&Remove(bgp_session!(r1, e1, false)))
.unwrap();
eprintln!("{:#?}", net.get_router(r2));
test_route!(net, r1, prefix, [r1, r2, r4, e4]);
test_route!(net, r2, prefix, [r2, r4, e4]);
test_route!(net, r3, prefix, [r3, r2, r4, e4]);
test_route!(net, r4, prefix, [r4, e4]);
}
#[test]
#[cfg(feature = "rand_queue")]
fn test_external_router_model<P: Prefix>() {
let mut net: Network<P, _> = Network::new(SimpleTimingModel::new(ModelParams::new(
0.1, 1.0, 2.0, 5.0, 0.1,
)));
let prefix = P::from(0);
let (e1, r1, r2, r3, r4, e4) = setup_external(&mut net);
net.advertise_route(e1, prefix, vec![ASN(65101), ASN(65200)], None, None)
.unwrap();
net.advertise_route(e4, prefix, vec![ASN(65104), ASN(65200)], None, None)
.unwrap();
test_route!(net, r1, prefix, [r1, e1]);
test_route!(net, r2, prefix, [r2, r1, e1]);
test_route!(net, r3, prefix, [r3, r1, e1]);
test_route!(net, r4, prefix, [r4, r2, r1, e1]);
eprintln!("{:#?}", net.get_router(r2));
net.apply_modifier(&Insert(bgp_session!(r2, r4, false)))
.unwrap();
net.apply_modifier(&Insert(bgp_session!(r3, r4, false)))
.unwrap();
net.apply_modifier(&Insert(bgp_session!(r4, e4, false)))
.unwrap();
eprintln!("{:#?}", net.get_router(r2));
net.apply_modifier(&Remove(bgp_session!(r1, r2, false)))
.unwrap();
net.apply_modifier(&Remove(bgp_session!(r1, r3, false)))
.unwrap();
net.apply_modifier(&Remove(bgp_session!(r1, e1, false)))
.unwrap();
eprintln!("{:#?}", net.get_router(r2));
test_route!(net, r1, prefix, [r1, r2, r4, e4]);
test_route!(net, r2, prefix, [r2, r4, e4]);
test_route!(net, r3, prefix, [r3, r2, r4, e4]);
test_route!(net, r4, prefix, [r4, e4]);
}
#[test]
fn test_route_order1<P: Prefix>() {
let mut net: Network<P, _> = Network::default();
let prefix = P::from(0);
let e0 = net.add_router("E0", ASN(1));
let b0 = net.add_router("B0", 65500);
let r0 = net.add_router("R0", 65500);
let r1 = net.add_router("R1", 65500);
let b1 = net.add_router("B1", 65500);
let e1 = net.add_router("E1", ASN(1));
net.add_link(e0, b0).unwrap();
net.add_link(b0, r1).unwrap();
net.add_link(r0, r1).unwrap();
net.add_link(r0, b1).unwrap();
net.add_link(b1, e1).unwrap();
let mut c = Config::new();
c.add(link_weight!(b0, r1, 1.0)).unwrap();
c.add(link_weight!(r1, b0, 1.0)).unwrap();
c.add(link_weight!(r0, r1, 1.0)).unwrap();
c.add(link_weight!(r1, r0, 1.0)).unwrap();
c.add(link_weight!(r0, b1, 1.0)).unwrap();
c.add(link_weight!(b1, r0, 1.0)).unwrap();
c.add(bgp_session!(e0, b0, false)).unwrap();
c.add(bgp_session!(r0, b0, true)).unwrap();
c.add(bgp_session!(r0, r1, false)).unwrap();
c.add(bgp_session!(r1, b1, true)).unwrap();
c.add(bgp_session!(e1, b1, false)).unwrap();
net.set_config(&c).unwrap();
net.advertise_route(e0, prefix, vec![ASN(1), ASN(2), ASN(3)], None, None)
.unwrap();
net.advertise_route(e1, prefix, vec![ASN(1), ASN(2), ASN(3)], None, None)
.unwrap();
test_route!(net, b0, prefix, [b0, e0]);
test_route!(net, r0, prefix, [r0, r1, b0, e0]);
test_route!(net, r1, prefix, [r1, b0, e0]);
test_route!(net, b1, prefix, [b1, e1]);
}
#[test]
fn test_route_order2<P: Prefix>() {
let mut net: Network<P, _> = Network::default();
let prefix = P::from(0);
let e0 = net.add_router("E0", ASN(1));
let b0 = net.add_router("B0", 65500);
let r0 = net.add_router("R0", 65500);
let r1 = net.add_router("R1", 65500);
let b1 = net.add_router("B1", 65500);
let e1 = net.add_router("E1", ASN(1));
net.add_link(e0, b0).unwrap();
net.add_link(b0, r1).unwrap();
net.add_link(r0, r1).unwrap();
net.add_link(r0, b1).unwrap();
net.add_link(b1, e1).unwrap();
let mut c = Config::new();
c.add(link_weight!(b0, r1, 1.0)).unwrap();
c.add(link_weight!(r1, b0, 1.0)).unwrap();
c.add(link_weight!(r0, r1, 1.0)).unwrap();
c.add(link_weight!(r1, r0, 1.0)).unwrap();
c.add(link_weight!(r0, b1, 1.0)).unwrap();
c.add(link_weight!(b1, r0, 1.0)).unwrap();
c.add(bgp_session!(e0, b0, false)).unwrap();
c.add(bgp_session!(r0, b0, true)).unwrap();
c.add(bgp_session!(r0, r1, false)).unwrap();
c.add(bgp_session!(r1, b1, true)).unwrap();
c.add(bgp_session!(e1, b1, false)).unwrap();
net.set_config(&c).unwrap();
net.advertise_route(e1, prefix, vec![ASN(1), ASN(2), ASN(3)], None, None)
.unwrap();
net.advertise_route(e0, prefix, vec![ASN(1), ASN(2), ASN(3)], None, None)
.unwrap();
test_route!(net, b0, prefix, [b0, e0]);
test_route!(net, r0, prefix, [r0, b1, e1]);
test_route!(net, r1, prefix, [r1, r0, b1, e1]);
test_route!(net, b1, prefix, [b1, e1]);
}
#[test]
fn test_bad_gadget<P: Prefix>() {
let mut net: Network<P, _> = Network::default();
let prefix = P::from(0);
let e0 = net.add_router("E0", ASN(65100));
let e1 = net.add_router("E1", ASN(65101));
let e2 = net.add_router("E2", ASN(65102));
let b0 = net.add_router("B0", 65500);
let b1 = net.add_router("B1", 65500);
let b2 = net.add_router("B2", 65500);
let r0 = net.add_router("R0", 65500);
let r1 = net.add_router("R1", 65500);
let r2 = net.add_router("R2", 65500);
net.add_link(e0, b0).unwrap();
net.add_link(e1, b1).unwrap();
net.add_link(e2, b2).unwrap();
net.add_link(b0, r0).unwrap();
net.add_link(b1, r1).unwrap();
net.add_link(b2, r2).unwrap();
net.add_link(r0, b1).unwrap();
net.add_link(r1, b2).unwrap();
net.add_link(r2, b0).unwrap();
let mut c = Config::new();
c.add(link_weight!(b0, r0, 5.0)).unwrap();
c.add(link_weight!(r0, b0, 5.0)).unwrap();
c.add(link_weight!(b1, r1, 5.0)).unwrap();
c.add(link_weight!(r1, b1, 5.0)).unwrap();
c.add(link_weight!(b2, r2, 5.0)).unwrap();
c.add(link_weight!(r2, b2, 5.0)).unwrap();
c.add(link_weight!(r0, b1, 1.0)).unwrap();
c.add(link_weight!(b1, r0, 1.0)).unwrap();
c.add(link_weight!(r1, b2, 1.0)).unwrap();
c.add(link_weight!(b2, r1, 1.0)).unwrap();
c.add(link_weight!(r2, b0, 1.0)).unwrap();
c.add(link_weight!(b0, r2, 1.0)).unwrap();
c.add(bgp_session!(r0, b0, true)).unwrap();
c.add(bgp_session!(r1, b1, true)).unwrap();
c.add(bgp_session!(r2, b2, true)).unwrap();
c.add(bgp_session!(r0, r1, false)).unwrap();
c.add(bgp_session!(r0, r2, false)).unwrap();
c.add(bgp_session!(r1, r2, false)).unwrap();
c.add(bgp_session!(b0, e0, false)).unwrap();
c.add(bgp_session!(b1, e1, false)).unwrap();
c.add(bgp_session!(b2, e2, false)).unwrap();
net.set_config(&c).unwrap();
net.set_msg_limit(Some(1000));
assert_eq!(
net.advertise_route(e2, prefix, vec![ASN(0), ASN(1)], None, None),
Ok(())
);
assert_eq!(
net.advertise_route(e1, prefix, vec![ASN(0), ASN(1)], None, None),
Ok(())
);
let last_advertisement = net.advertise_route(e0, prefix, vec![ASN(0), ASN(1)], None, None);
assert!(last_advertisement == Err(NetworkError::NoConvergence));
}
#[test]
fn change_ibgp_topology_1<P: Prefix>() {
let mut net: Network<P, _> = Network::default();
let prefix = P::from(0);
let rr = net.add_router("rr", 65500);
let r1 = net.add_router("r1", 65500);
let r2 = net.add_router("r2", 65500);
let r3 = net.add_router("r3", 65500);
let e1 = net.add_router("e1", 65500);
let e2 = net.add_router("e2", 65500);
let e3 = net.add_router("e3", 65500);
let p1 = net.add_router("p1", ASN(65101));
let p2 = net.add_router("p2", ASN(65102));
let p3 = net.add_router("p3", ASN(65103));
net.add_link(r1, e1).unwrap();
net.add_link(r2, e2).unwrap();
net.add_link(r3, e3).unwrap();
net.add_link(e1, p1).unwrap();
net.add_link(e2, p2).unwrap();
net.add_link(e3, p3).unwrap();
net.add_link(e1, r2).unwrap();
net.add_link(e2, r3).unwrap();
net.add_link(e3, r1).unwrap();
net.add_link(rr, e1).unwrap();
net.add_link(rr, e2).unwrap();
net.add_link(rr, e3).unwrap();
let mut c = Config::new();
c.add(link_weight!(r1, e1, 10.0)).unwrap();
c.add(link_weight!(e1, r1, 10.0)).unwrap();
c.add(link_weight!(r2, e2, 10.0)).unwrap();
c.add(link_weight!(e2, r2, 10.0)).unwrap();
c.add(link_weight!(r3, e3, 10.0)).unwrap();
c.add(link_weight!(e3, r3, 10.0)).unwrap();
c.add(link_weight!(e1, r2, 1.0)).unwrap();
c.add(link_weight!(r2, e1, 1.0)).unwrap();
c.add(link_weight!(e2, r3, 1.0)).unwrap();
c.add(link_weight!(r3, e2, 1.0)).unwrap();
c.add(link_weight!(e3, r1, 1.0)).unwrap();
c.add(link_weight!(r1, e3, 1.0)).unwrap();
c.add(link_weight!(rr, e1, 1.0)).unwrap();
c.add(link_weight!(e1, rr, 100.0)).unwrap();
c.add(link_weight!(rr, e2, 2.0)).unwrap();
c.add(link_weight!(e2, rr, 100.0)).unwrap();
c.add(link_weight!(rr, e3, 3.0)).unwrap();
c.add(link_weight!(e3, rr, 100.0)).unwrap();
c.add(bgp_session!(rr, r1, false)).unwrap();
c.add(bgp_session!(rr, r2, false)).unwrap();
c.add(bgp_session!(rr, r3, false)).unwrap();
c.add(bgp_session!(r1, r2, false)).unwrap();
c.add(bgp_session!(r1, r3, false)).unwrap();
c.add(bgp_session!(r2, r3, false)).unwrap();
c.add(bgp_session!(r1, e1, true)).unwrap();
c.add(bgp_session!(r2, e2, true)).unwrap();
c.add(bgp_session!(r3, e2, true)).unwrap();
c.add(bgp_session!(r3, e3, true)).unwrap();
c.add(bgp_session!(p1, e1, false)).unwrap();
c.add(bgp_session!(p2, e2, false)).unwrap();
c.add(bgp_session!(p3, e3, false)).unwrap();
net.set_config(&c).unwrap();
net.advertise_route(p1, prefix, vec![ASN(1)], None, None)
.unwrap();
net.advertise_route(p2, prefix, vec![ASN(1)], None, None)
.unwrap();
net.advertise_route(p3, prefix, vec![ASN(1)], None, None)
.unwrap();
test_route!(net, r1, prefix, [r1, e1, p1]);
test_route!(net, r2, prefix, [r2, e1, p1]);
test_route!(net, r3, prefix, [r3, e2, p2]);
test_route!(net, rr, prefix, [rr, e1, p1]);
net.set_msg_limit(Some(5_000));
let mut patch = ConfigPatch::new();
patch.add(Remove(bgp_session!(r3, e2, true)));
let patch_result = net.apply_patch(&patch);
println!("{patch_result:#?}");
assert!(patch_result == Err(NetworkError::NoConvergence));
}
#[test]
fn change_ibgp_topology_2<P: Prefix>() {
let mut net: Network<P, _> = Network::default();
let prefix = P::from(0);
let rr = net.add_router("rr", 65500);
let r1 = net.add_router("r1", 65500);
let r2 = net.add_router("r2", 65500);
let r3 = net.add_router("r3", 65500);
let e1 = net.add_router("e1", 65500);
let e2 = net.add_router("e2", 65500);
let e3 = net.add_router("e3", 65500);
let p1 = net.add_router("p1", ASN(65101));
let p2 = net.add_router("p2", ASN(65102));
let p3 = net.add_router("p3", ASN(65103));
net.add_link(r1, e1).unwrap();
net.add_link(r2, e2).unwrap();
net.add_link(r3, e3).unwrap();
net.add_link(e1, p1).unwrap();
net.add_link(e2, p2).unwrap();
net.add_link(e3, p3).unwrap();
net.add_link(e1, r2).unwrap();
net.add_link(e2, r3).unwrap();
net.add_link(e3, r1).unwrap();
net.add_link(rr, e1).unwrap();
net.add_link(rr, e2).unwrap();
net.add_link(rr, e3).unwrap();
let mut c = Config::new();
c.add(link_weight!(r1, e1, 10.0)).unwrap();
c.add(link_weight!(e1, r1, 10.0)).unwrap();
c.add(link_weight!(r2, e2, 10.0)).unwrap();
c.add(link_weight!(e2, r2, 10.0)).unwrap();
c.add(link_weight!(r3, e3, 10.0)).unwrap();
c.add(link_weight!(e3, r3, 10.0)).unwrap();
c.add(link_weight!(e1, r2, 1.0)).unwrap();
c.add(link_weight!(r2, e1, 1.0)).unwrap();
c.add(link_weight!(e2, r3, 1.0)).unwrap();
c.add(link_weight!(r3, e2, 1.0)).unwrap();
c.add(link_weight!(e3, r1, 1.0)).unwrap();
c.add(link_weight!(r1, e3, 1.0)).unwrap();
c.add(link_weight!(rr, e1, 1.0)).unwrap();
c.add(link_weight!(e1, rr, 100.0)).unwrap();
c.add(link_weight!(rr, e2, 2.0)).unwrap();
c.add(link_weight!(e2, rr, 100.0)).unwrap();
c.add(link_weight!(rr, e3, 3.0)).unwrap();
c.add(link_weight!(e3, rr, 100.0)).unwrap();
c.add(bgp_session!(rr, r1, false)).unwrap();
c.add(bgp_session!(rr, r2, false)).unwrap();
c.add(bgp_session!(rr, r3, false)).unwrap();
c.add(bgp_session!(r1, r2, false)).unwrap();
c.add(bgp_session!(r1, r3, false)).unwrap();
c.add(bgp_session!(r2, r3, false)).unwrap();
c.add(bgp_session!(r1, e1, true)).unwrap();
c.add(bgp_session!(r2, e2, true)).unwrap();
c.add(bgp_session!(r3, e2, true)).unwrap();
c.add(bgp_session!(r3, e3, true)).unwrap();
c.add(bgp_session!(p1, e1, false)).unwrap();
c.add(bgp_session!(p2, e2, false)).unwrap();
c.add(bgp_session!(p3, e3, false)).unwrap();
net.set_config(&c).unwrap();
assert_eq!(
net.advertise_route(p1, prefix, vec![ASN(1)], None, None),
Ok(())
);
assert_eq!(
net.advertise_route(p2, prefix, vec![ASN(1)], None, None),
Ok(())
);
assert_eq!(
net.advertise_route(p3, prefix, vec![ASN(1)], None, None),
Ok(())
);
test_route!(net, r1, prefix, [r1, e1, p1]);
test_route!(net, r2, prefix, [r2, e1, p1]);
test_route!(net, r3, prefix, [r3, e2, p2]);
test_route!(net, rr, prefix, [rr, e1, p1]);
assert_eq!(
net.apply_modifier(&Remove(bgp_session!(r1, r2, false))),
Ok(())
);
assert_eq!(
net.apply_modifier(&Remove(bgp_session!(r1, r3, false))),
Ok(())
);
assert_eq!(
net.apply_modifier(&Update {
from: bgp_session!(rr, r1, false),
to: bgp_session!(rr, r1, true),
}),
Ok(())
);
test_route!(net, r1, prefix, [r1, e1, p1]);
test_route!(net, r2, prefix, [r2, e2, p2]);
test_route!(net, r3, prefix, [r3, e2, p2]);
test_route!(net, rr, prefix, [rr, e1, p1]);
assert_eq!(
net.apply_modifier(&Remove(bgp_session!(r2, r3, false))),
Ok(())
);
assert_eq!(
net.apply_modifier(&Remove(bgp_session!(rr, r2, false))),
Ok(())
);
assert_eq!(
net.apply_modifier(&Insert(bgp_session!(rr, r2, true))),
Ok(())
);
test_route!(net, r1, prefix, [r1, e1, p1]);
test_route!(net, r2, prefix, [r2, e1, p1]);
test_route!(net, r3, prefix, [r3, e2, p2]);
test_route!(net, rr, prefix, [rr, e1, p1]);
assert_eq!(
net.apply_modifier(&Remove(bgp_session!(rr, r3, false))),
Ok(())
);
assert_eq!(
net.apply_modifier(&Insert(bgp_session!(rr, r3, true))),
Ok(())
);
test_route!(net, r1, prefix, [r1, e1, p1]);
test_route!(net, r2, prefix, [r2, e1, p1]);
test_route!(net, r3, prefix, [r3, e2, p2]);
test_route!(net, rr, prefix, [rr, e1, p1]);
assert_eq!(
net.apply_modifier(&Remove(bgp_session!(r3, e2, true))),
Ok(())
);
test_route!(net, r1, prefix, [r1, e1, p1]);
test_route!(net, r2, prefix, [r2, e1, p1]);
test_route!(net, r3, prefix, [r3, e3, p3]);
test_route!(net, rr, prefix, [rr, e1, p1]);
}
#[test]
fn test_pylon_gadget<P: Prefix>() {
let mut net: Network<P, _> = Network::default();
let prefix = P::from(0);
let s = net.add_router("s", 65500);
let rr1 = net.add_router("rr1", 65500);
let rr2 = net.add_router("rr2", 65500);
let r1 = net.add_router("r1", 65500);
let r2 = net.add_router("r2", 65500);
let e0 = net.add_router("e0", 65500);
let e1 = net.add_router("e1", 65500);
let p0 = net.add_router("p0", ASN(65100));
let p1 = net.add_router("p1", ASN(65101));
let ps = net.add_router("ps", ASN(65102));
net.add_link(s, r1).unwrap();
net.add_link(s, r2).unwrap();
net.add_link(s, rr1).unwrap();
net.add_link(s, rr2).unwrap();
net.add_link(rr1, rr2).unwrap();
net.add_link(rr1, e0).unwrap();
net.add_link(rr2, e1).unwrap();
net.add_link(r1, r2).unwrap();
net.add_link(r1, e1).unwrap();
net.add_link(r2, e0).unwrap();
net.add_link(e0, p0).unwrap();
net.add_link(e1, p1).unwrap();
net.add_link(s, ps).unwrap();
let mut c = Config::new();
c.add(link_weight!(s, r1, 100.0)).unwrap();
c.add(link_weight!(s, r2, 100.0)).unwrap();
c.add(link_weight!(s, rr1, 100.0)).unwrap();
c.add(link_weight!(s, rr2, 100.0)).unwrap();
c.add(link_weight!(rr1, rr2, 1.0)).unwrap();
c.add(link_weight!(rr1, e0, 1.0)).unwrap();
c.add(link_weight!(rr2, e1, 1.0)).unwrap();
c.add(link_weight!(r1, r2, 1.0)).unwrap();
c.add(link_weight!(r1, e1, 1.0)).unwrap();
c.add(link_weight!(r2, e0, 1.0)).unwrap();
c.add(link_weight!(r1, s, 100.0)).unwrap();
c.add(link_weight!(r2, s, 100.0)).unwrap();
c.add(link_weight!(rr1, s, 100.0)).unwrap();
c.add(link_weight!(rr2, s, 100.0)).unwrap();
c.add(link_weight!(rr2, rr1, 1.0)).unwrap();
c.add(link_weight!(e0, rr1, 1.0)).unwrap();
c.add(link_weight!(e1, rr2, 1.0)).unwrap();
c.add(link_weight!(r2, r1, 1.0)).unwrap();
c.add(link_weight!(e1, r1, 1.0)).unwrap();
c.add(link_weight!(e0, r2, 1.0)).unwrap();
c.add(bgp_session!(s, rr1, true)).unwrap();
c.add(bgp_session!(s, rr2, true)).unwrap();
c.add(bgp_session!(rr1, r1, true)).unwrap();
c.add(bgp_session!(rr2, r2, true)).unwrap();
c.add(bgp_session!(r1, e0, true)).unwrap();
c.add(bgp_session!(r2, e0, true)).unwrap();
c.add(bgp_session!(r2, e1, true)).unwrap();
c.add(bgp_session!(s, ps, false)).unwrap();
c.add(bgp_session!(e0, p0, false)).unwrap();
c.add(bgp_session!(e1, p1, false)).unwrap();
net.set_config(&c).unwrap();
net.advertise_route(ps, prefix, vec![ASN(1)], None, None)
.unwrap();
net.advertise_route(p0, prefix, vec![ASN(1)], None, None)
.unwrap();
net.advertise_route(p1, prefix, vec![ASN(1)], None, None)
.unwrap();
test_route!(net, s, prefix, [s, ps]);
test_route!(net, rr1, prefix, [rr1, e0, p0]);
test_route!(net, rr2, prefix, [rr2, rr1, e0, p0]);
test_route!(net, r1, prefix, [r1, r2, e0, p0]);
test_route!(net, r2, prefix, [r2, e0, p0]);
net.apply_modifier(&Remove(bgp_session!(r2, e0, true)))
.unwrap();
test_route!(net, s, prefix, [s, ps]);
test_route!(net, rr1, prefix, [rr1, e0, p0]);
test_route!(net, rr2, prefix, [rr2, e1, p1]);
test_bad_route!(fw_loop, net, r1, prefix, [], [r1, r2]);
test_bad_route!(fw_loop, net, r2, prefix, [], [r2, r1]);
net.apply_modifier(&Insert(bgp_session!(r1, e1, true)))
.unwrap();
test_route!(net, s, prefix, [s, ps]);
test_route!(net, rr1, prefix, [rr1, rr2, e1, p1]);
test_route!(net, rr2, prefix, [rr2, e1, p1]);
test_route!(net, r1, prefix, [r1, e1, p1]);
test_route!(net, r2, prefix, [r2, r1, e1, p1]);
}
#[test]
fn batch_route_map_update<P: Prefix>() {
let mut net: Network<P, BasicEventQueue<P>> = Network::default();
let p = P::from(1);
let r1 = net.add_router("r1", 65500);
let r2 = net.add_router("r2", 65500);
let ex = net.add_router("ex", ASN(100));
net.add_link(r1, r2).unwrap();
net.add_link(r1, ex).unwrap();
net.set_link_weight(r1, r2, 1.0).unwrap();
net.set_link_weight(r2, r1, 1.0).unwrap();
net.set_bgp_session(r1, r2, Some(false)).unwrap();
net.set_bgp_session(r1, ex, Some(false)).unwrap();
net.set_bgp_route_map(
r1,
r2,
Outgoing,
RouteMapBuilder::new().order(100).deny().build(),
)
.unwrap();
net.advertise_route(ex, p, [100, 100, 1], None, [(65500, 10).into()])
.unwrap();
net.manual_simulation();
assert_eq!(net.get_router(r2).unwrap().get_next_hop(p), vec![]);
let mut net2 = net.clone();
net2.apply_modifier(&BatchRouteMapEdit {
router: r1,
updates: vec![
RouteMapEdit {
neighbor: r2,
direction: Outgoing,
old: Some(RouteMapBuilder::new().order(100).deny().build()),
new: Some(RouteMapBuilder::new().order(100).allow().build()),
},
RouteMapEdit {
neighbor: r2,
direction: Outgoing,
old: None,
new: Some(
RouteMapBuilder::new()
.order(50)
.deny()
.match_community((65500, 10))
.build(),
),
},
],
})
.unwrap();
assert!(net2.queue().is_empty());
net.apply_modifier(&Update {
from: ConfigExpr::BgpRouteMap {
router: r1,
neighbor: r2,
direction: Outgoing,
map: RouteMapBuilder::new().order(100).deny().build(),
},
to: ConfigExpr::BgpRouteMap {
router: r1,
neighbor: r2,
direction: Outgoing,
map: RouteMapBuilder::new().order(100).allow().build(),
},
})
.unwrap();
net.apply_modifier(&Insert(ConfigExpr::BgpRouteMap {
router: r1,
neighbor: r2,
direction: Outgoing,
map: RouteMapBuilder::new()
.order(50)
.deny()
.match_community((65500, 10))
.build(),
}))
.unwrap();
assert_eq!(net.queue().len(), 2);
net.simulate().unwrap();
pretty_assertions::assert_eq!(net.get_config().unwrap(), net2.get_config().unwrap());
assert!(net.weak_eq(&net2));
}
#[instantiate_tests(<SinglePrefix>)]
mod single {}
#[instantiate_tests(<SimplePrefix>)]
mod simple {}
#[instantiate_tests(<Ipv4Prefix>)]
mod ipv4 {}
}
#[test]
fn carousel_gadget() {
use crate::route_map::*;
let mut net: Network<SimplePrefix, _> = Network::default();
let prefix1 = SimplePrefix::from(1);
let prefix2 = SimplePrefix::from(2);
let rr = net.add_router("rr", 65500);
let r1 = net.add_router("r1", 65500);
let r2 = net.add_router("r2", 65500);
let r3 = net.add_router("r3", 65500);
let r4 = net.add_router("r4", 65500);
let e1 = net.add_router("e1", 65500);
let e2 = net.add_router("e2", 65500);
let e3 = net.add_router("e3", 65500);
let e4 = net.add_router("e4", 65500);
let pr = net.add_router("pr", ASN(65100));
let p1 = net.add_router("p1", ASN(65101));
let p2 = net.add_router("p2", ASN(65102));
let p3 = net.add_router("p3", ASN(65103));
let p4 = net.add_router("p4", ASN(65104));
net.add_link(rr, r1).unwrap();
net.add_link(rr, r2).unwrap();
net.add_link(rr, r3).unwrap();
net.add_link(rr, r4).unwrap();
net.add_link(r1, r2).unwrap();
net.add_link(r1, e2).unwrap();
net.add_link(r1, e3).unwrap();
net.add_link(r2, e1).unwrap();
net.add_link(r3, r4).unwrap();
net.add_link(r3, e4).unwrap();
net.add_link(r4, e2).unwrap();
net.add_link(r4, e3).unwrap();
net.add_link(rr, pr).unwrap();
net.add_link(e1, p1).unwrap();
net.add_link(e2, p2).unwrap();
net.add_link(e3, p3).unwrap();
net.add_link(e4, p4).unwrap();
let mut c = Config::new();
c.add(link_weight!(rr, r1, 100.0)).unwrap();
c.add(link_weight!(rr, r2, 100.0)).unwrap();
c.add(link_weight!(rr, r3, 100.0)).unwrap();
c.add(link_weight!(rr, r4, 100.0)).unwrap();
c.add(link_weight!(r1, r2, 1.0)).unwrap();
c.add(link_weight!(r1, e2, 5.0)).unwrap();
c.add(link_weight!(r1, e3, 1.0)).unwrap();
c.add(link_weight!(r2, e1, 9.0)).unwrap();
c.add(link_weight!(r3, r4, 1.0)).unwrap();
c.add(link_weight!(r3, e4, 9.0)).unwrap();
c.add(link_weight!(r4, e2, 1.0)).unwrap();
c.add(link_weight!(r4, e3, 4.0)).unwrap();
c.add(link_weight!(r1, rr, 100.0)).unwrap();
c.add(link_weight!(r2, rr, 100.0)).unwrap();
c.add(link_weight!(r3, rr, 100.0)).unwrap();
c.add(link_weight!(r4, rr, 100.0)).unwrap();
c.add(link_weight!(r2, r1, 1.0)).unwrap();
c.add(link_weight!(e2, r1, 5.0)).unwrap();
c.add(link_weight!(e3, r1, 1.0)).unwrap();
c.add(link_weight!(e1, r2, 9.0)).unwrap();
c.add(link_weight!(r4, r3, 1.0)).unwrap();
c.add(link_weight!(e4, r3, 9.0)).unwrap();
c.add(link_weight!(e2, r4, 1.0)).unwrap();
c.add(link_weight!(e3, r4, 4.0)).unwrap();
c.add(bgp_session!(rr, r1, true)).unwrap();
c.add(bgp_session!(rr, r2, true)).unwrap();
c.add(bgp_session!(rr, r3, true)).unwrap();
c.add(bgp_session!(rr, r4, true)).unwrap();
c.add(bgp_session!(r1, e1, true)).unwrap();
c.add(bgp_session!(r1, e3, true)).unwrap();
c.add(bgp_session!(r2, e1, true)).unwrap();
c.add(bgp_session!(r2, e2, true)).unwrap();
c.add(bgp_session!(r2, e3, true)).unwrap();
c.add(bgp_session!(r3, e2, true)).unwrap();
c.add(bgp_session!(r3, e3, true)).unwrap();
c.add(bgp_session!(r3, e4, true)).unwrap();
c.add(bgp_session!(r4, e2, true)).unwrap();
c.add(bgp_session!(r4, e4, true)).unwrap();
c.add(bgp_session!(e1, p1, false)).unwrap();
c.add(bgp_session!(e2, p2, false)).unwrap();
c.add(bgp_session!(e3, p3, false)).unwrap();
c.add(bgp_session!(e4, p4, false)).unwrap();
c.add(bgp_session!(rr, pr, false)).unwrap();
c.add(ConfigExpr::BgpRouteMap {
router: e2,
neighbor: p2,
direction: RouteMapDirection::Incoming,
map: RouteMap::new(
10,
RouteMapState::Allow,
vec![],
vec![RouteMapSet::LocalPref(Some(50))],
RouteMapFlow::Continue,
),
})
.unwrap();
c.add(ConfigExpr::BgpRouteMap {
router: e3,
neighbor: p3,
direction: RouteMapDirection::Incoming,
map: RouteMap::new(
10,
RouteMapState::Allow,
vec![],
vec![RouteMapSet::LocalPref(Some(50))],
RouteMapFlow::Continue,
),
})
.unwrap();
net.set_config(&c).unwrap();
net.advertise_route(pr, prefix1, vec![ASN(1)], None, None)
.unwrap();
net.advertise_route(pr, prefix2, vec![ASN(1)], None, None)
.unwrap();
net.advertise_route(p1, prefix1, vec![ASN(1)], None, None)
.unwrap();
net.advertise_route(p2, prefix1, vec![ASN(1)], None, None)
.unwrap();
net.advertise_route(p2, prefix2, vec![ASN(1)], None, None)
.unwrap();
net.advertise_route(p3, prefix1, vec![ASN(1)], None, None)
.unwrap();
net.advertise_route(p3, prefix2, vec![ASN(1)], None, None)
.unwrap();
net.advertise_route(p4, prefix2, vec![ASN(1)], None, None)
.unwrap();
test_route!(net, rr, prefix1, [rr, pr]);
test_route!(net, rr, prefix2, [rr, pr]);
test_route!(net, r1, prefix1, [r1, r2, e1, p1]);
test_route!(net, r1, prefix2, [r1, rr, pr]);
test_route!(net, r2, prefix1, [r2, e1, p1]);
test_route!(net, r2, prefix2, [r2, rr, pr]);
test_route!(net, r3, prefix1, [r3, rr, pr]);
test_route!(net, r3, prefix2, [r3, e4, p4]);
test_route!(net, r4, prefix1, [r4, rr, pr]);
test_route!(net, r4, prefix2, [r4, r3, e4, p4]);
test_route!(net, e1, prefix1, [e1, p1]);
test_route!(net, e1, prefix2, [e1, r2, rr, pr]);
test_route!(net, e2, prefix1, [e2, r1, r2, e1, p1]);
test_route!(net, e2, prefix2, [e2, r4, r3, e4, p4]);
test_route!(net, e3, prefix1, [e3, r1, r2, e1, p1]);
test_route!(net, e3, prefix2, [e3, r4, r3, e4, p4]);
test_route!(net, e4, prefix1, [e4, r3, rr, pr]);
test_route!(net, e4, prefix2, [e4, p4]);
net.apply_modifier(&Remove(ConfigExpr::BgpRouteMap {
router: e2,
neighbor: p2,
direction: RouteMapDirection::Incoming,
map: RouteMap::new(
10,
RouteMapState::Allow,
vec![],
vec![RouteMapSet::LocalPref(Some(50))],
RouteMapFlow::Continue,
),
}))
.unwrap();
test_route!(net, rr, prefix1, [rr, pr]);
test_route!(net, rr, prefix2, [rr, pr]);
test_bad_route!(fw_loop, net, r1, prefix1, [], [r1, r2]);
test_route!(net, r1, prefix2, [r1, rr, pr]);
test_bad_route!(fw_loop, net, r2, prefix1, [], [r2, r1]);
test_route!(net, r2, prefix2, [r2, r1, rr, pr]);
test_route!(net, r3, prefix1, [r3, r4, e2, p2]);
test_route!(net, r3, prefix2, [r3, r4, e2, p2]);
test_route!(net, r4, prefix1, [r4, e2, p2]);
test_route!(net, r4, prefix2, [r4, e2, p2]);
test_route!(net, e1, prefix1, [e1, p1]);
test_route!(net, e1, prefix2, [e1, r2, r1, rr, pr]);
test_route!(net, e2, prefix1, [e2, p2]);
test_route!(net, e2, prefix2, [e2, p2]);
test_route!(net, e3, prefix1, [e3, r4, e2, p2]);
test_route!(net, e3, prefix2, [e3, r4, e2, p2]);
test_route!(net, e4, prefix1, [e4, r3, r4, e2, p2]);
test_route!(net, e4, prefix2, [e4, p4]);
net.apply_modifier(&Remove(ConfigExpr::BgpRouteMap {
router: e3,
neighbor: p3,
direction: RouteMapDirection::Incoming,
map: RouteMap::new(
10,
RouteMapState::Allow,
vec![],
vec![RouteMapSet::LocalPref(Some(50))],
RouteMapFlow::Continue,
),
}))
.unwrap();
test_route!(net, rr, prefix1, [rr, pr]);
test_route!(net, rr, prefix2, [rr, pr]);
test_route!(net, r1, prefix1, [r1, e3, p3]);
test_route!(net, r1, prefix2, [r1, e3, p3]);
test_route!(net, r2, prefix1, [r2, r1, e3, p3]);
test_route!(net, r2, prefix2, [r2, r1, e3, p3]);
test_route!(net, r3, prefix1, [r3, r4, e2, p2]);
test_route!(net, r3, prefix2, [r3, r4, e2, p2]);
test_route!(net, r4, prefix1, [r4, e2, p2]);
test_route!(net, r4, prefix2, [r4, e2, p2]);
test_route!(net, e1, prefix1, [e1, p1]);
test_route!(net, e1, prefix2, [e1, r2, r1, e3, p3]);
test_route!(net, e2, prefix1, [e2, p2]);
test_route!(net, e2, prefix2, [e2, p2]);
test_route!(net, e3, prefix1, [e3, p3]);
test_route!(net, e3, prefix2, [e3, p3]);
test_route!(net, e4, prefix1, [e4, r3, r4, e2, p2]);
test_route!(net, e4, prefix2, [e4, p4]);
}
#[test]
fn test_twicebad_gadget() {
let mut net: Network<SimplePrefix, _> = Network::default();
let prefix1 = SimplePrefix::from(1);
let prefix2 = SimplePrefix::from(2);
let r1 = net.add_router("r1", 65500);
let r2 = net.add_router("r2", 65500);
let r3 = net.add_router("r3", 65500);
let r4 = net.add_router("r4", 65500);
let e1 = net.add_router("e1", 65500);
let ex = net.add_router("ex", 65500);
let e2 = net.add_router("e2", 65500);
let e3 = net.add_router("e3", 65500);
let e4 = net.add_router("e4", 65500);
let pr = net.add_router("pr", ASN(65100));
let p1 = net.add_router("p1", ASN(65101));
let px = net.add_router("px", ASN(65105));
let p2 = net.add_router("p2", ASN(65102));
let p3 = net.add_router("p3", ASN(65103));
let p4 = net.add_router("p4", ASN(65104));
net.add_link(r1, pr).unwrap();
net.add_link(e1, p1).unwrap();
net.add_link(ex, px).unwrap();
net.add_link(e2, p2).unwrap();
net.add_link(e3, p3).unwrap();
net.add_link(e4, p4).unwrap();
net.add_link(r1, e1).unwrap();
net.add_link(r1, e2).unwrap();
net.add_link(r2, ex).unwrap();
net.add_link(r2, e2).unwrap();
net.add_link(r2, e3).unwrap();
net.add_link(r2, e4).unwrap();
net.add_link(r3, e1).unwrap();
net.add_link(r3, ex).unwrap();
net.add_link(r3, e3).unwrap();
net.add_link(r4, e1).unwrap();
net.add_link(r4, e4).unwrap();
let mut c = Config::new();
c.add(link_weight!(r1, e1, 2.0)).unwrap();
c.add(link_weight!(r1, e2, 1.0)).unwrap();
c.add(link_weight!(r2, ex, 4.0)).unwrap();
c.add(link_weight!(r2, e2, 6.0)).unwrap();
c.add(link_weight!(r2, e3, 5.0)).unwrap();
c.add(link_weight!(r2, e4, 3.0)).unwrap();
c.add(link_weight!(r3, e1, 8.0)).unwrap();
c.add(link_weight!(r3, ex, 7.0)).unwrap();
c.add(link_weight!(r3, e3, 9.0)).unwrap();
c.add(link_weight!(r4, e1, 8.0)).unwrap();
c.add(link_weight!(r4, e4, 9.0)).unwrap();
c.add(link_weight!(e1, r1, 2.0)).unwrap();
c.add(link_weight!(e2, r1, 1.0)).unwrap();
c.add(link_weight!(ex, r2, 4.0)).unwrap();
c.add(link_weight!(e2, r2, 6.0)).unwrap();
c.add(link_weight!(e3, r2, 5.0)).unwrap();
c.add(link_weight!(e4, r2, 3.0)).unwrap();
c.add(link_weight!(e1, r3, 8.0)).unwrap();
c.add(link_weight!(ex, r3, 7.0)).unwrap();
c.add(link_weight!(e3, r3, 9.0)).unwrap();
c.add(link_weight!(e1, r4, 8.0)).unwrap();
c.add(link_weight!(e4, r4, 9.0)).unwrap();
c.add(bgp_session!(r1, e1, true)).unwrap();
c.add(bgp_session!(r1, ex, true)).unwrap();
c.add(bgp_session!(r2, ex, true)).unwrap();
c.add(bgp_session!(r2, e2, true)).unwrap();
c.add(bgp_session!(r3, e3, true)).unwrap();
c.add(bgp_session!(r4, e4, true)).unwrap();
c.add(bgp_session!(r1, r2, false)).unwrap();
c.add(bgp_session!(r1, r3, false)).unwrap();
c.add(bgp_session!(r1, r4, false)).unwrap();
c.add(bgp_session!(r2, r3, false)).unwrap();
c.add(bgp_session!(r2, r4, false)).unwrap();
c.add(bgp_session!(r3, r4, false)).unwrap();
c.add(bgp_session!(r1, pr, false)).unwrap();
c.add(bgp_session!(e1, p1, false)).unwrap();
c.add(bgp_session!(ex, px, false)).unwrap();
c.add(bgp_session!(e2, p2, false)).unwrap();
c.add(bgp_session!(e3, p3, false)).unwrap();
c.add(bgp_session!(e4, p4, false)).unwrap();
net.set_config(&c).unwrap();
assert_eq!(
net.advertise_route(p1, prefix1, vec![ASN(1)], None, None),
Ok(())
);
assert_eq!(
net.advertise_route(p1, prefix2, vec![ASN(2)], None, None),
Ok(())
);
assert_eq!(
net.advertise_route(px, prefix1, vec![ASN(1)], None, None),
Ok(())
);
assert_eq!(
net.advertise_route(px, prefix2, vec![ASN(2)], None, None),
Ok(())
);
assert_eq!(
net.advertise_route(p2, prefix1, vec![ASN(1)], None, None),
Ok(())
);
assert_eq!(
net.advertise_route(p3, prefix1, vec![ASN(1)], None, None),
Ok(())
);
assert_eq!(
net.advertise_route(p4, prefix2, vec![ASN(2)], None, None),
Ok(())
);
assert_eq!(
net.advertise_route(pr, prefix2, vec![ASN(2)], None, None),
Ok(())
);
let m1 = Insert(bgp_session!(r3, e1, true));
net.set_msg_limit(Some(5_000));
assert!(net.apply_modifier(&m1) == Err(NetworkError::NoConvergence));
}