#[generic_tests::define]
mod t {
use std::collections::{BTreeMap, BTreeSet};
use crate::{
bgp::BgpRoute,
builder::*,
config::{ConfigExpr::IgpLinkWeight, NetworkConfig},
event::BasicEventQueue,
network::{Network, DEFAULT_INTERNAL_ASN},
ospf::{global::GlobalOspf, local::LocalOspf, OspfImpl, OspfProcess},
route_map::{
RouteMap, RouteMapDirection::*, RouteMapFlow::*, RouteMapSet as Set, RouteMapState::*,
},
router::StaticRoute::*,
types::{
Ipv4Prefix, NetworkError, Prefix, PrefixMap, RouterId, SimplePrefix, SinglePrefix, ASN,
},
};
use lazy_static::lazy_static;
use maplit::{btreemap, btreeset};
use pretty_assertions::assert_eq;
type Net<P, Ospf> = Network<P, BasicEventQueue<P>, Ospf>;
lazy_static! {
static ref E1: RouterId = 0.into();
static ref R1: RouterId = 1.into();
static ref R2: RouterId = 2.into();
static ref R3: RouterId = 3.into();
static ref R4: RouterId = 4.into();
static ref E4: RouterId = 5.into();
static ref E5: RouterId = 6.into();
}
fn test_net<P: Prefix, Ospf: OspfImpl>() -> Net<P, Ospf> {
let mut net: Net<P, Ospf> = Net::default();
assert_eq!(*E1, net.add_router("E1", ASN(65101)));
assert_eq!(*R1, net.add_router("R1", 65500));
assert_eq!(*R2, net.add_router("R2", 65500));
assert_eq!(*R3, net.add_router("R3", 65500));
assert_eq!(*R4, net.add_router("R4", 65500));
assert_eq!(*E4, net.add_router("E4", ASN(65104)));
net.add_link(*R1, *E1).unwrap();
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(*R4, *E4).unwrap();
net
}
fn get_test_net_igp<P: Prefix, Ospf: OspfImpl>(net_fn: fn() -> Net<P, Ospf>) -> Net<P, Ospf> {
let mut net = net_fn();
net.set_link_weight(*R1, *R2, 5.0).unwrap();
net.set_link_weight(*R1, *R3, 1.0).unwrap();
net.set_link_weight(*R2, *R3, 1.0).unwrap();
net.set_link_weight(*R2, *R4, 1.0).unwrap();
net.set_link_weight(*R3, *R4, 3.0).unwrap();
net.set_link_weight(*R2, *R1, 5.0).unwrap();
net.set_link_weight(*R3, *R1, 1.0).unwrap();
net.set_link_weight(*R3, *R2, 1.0).unwrap();
net.set_link_weight(*R4, *R2, 1.0).unwrap();
net.set_link_weight(*R4, *R3, 3.0).unwrap();
net.set_bgp_session(*R1, *R2, Some(false)).unwrap();
net.set_bgp_session(*R1, *R3, Some(false)).unwrap();
net.set_bgp_session(*R1, *R4, Some(false)).unwrap();
net.set_bgp_session(*R2, *R3, Some(false)).unwrap();
net.set_bgp_session(*R2, *R4, Some(false)).unwrap();
net.set_bgp_session(*R3, *R4, Some(false)).unwrap();
net.set_bgp_session(*R1, *E1, Some(false)).unwrap();
net.set_bgp_session(*R4, *E4, Some(false)).unwrap();
net
}
fn get_test_net_bgp<P: Prefix, Ospf: OspfImpl>(net_fn: fn() -> Net<P, Ospf>) -> Net<P, Ospf> {
let mut net = get_test_net_igp::<P, Ospf>(net_fn);
net.set_bgp_session(*R1, *R2, Some(false)).unwrap();
net.set_bgp_session(*R1, *R3, Some(false)).unwrap();
net.set_bgp_session(*R1, *R4, Some(false)).unwrap();
net.set_bgp_session(*R2, *R3, Some(false)).unwrap();
net.set_bgp_session(*R2, *R4, Some(false)).unwrap();
net.set_bgp_session(*R3, *R4, Some(false)).unwrap();
net.set_bgp_session(*R1, *E1, Some(false)).unwrap();
net.set_bgp_session(*R4, *E4, Some(false)).unwrap();
net
}
#[test]
fn test_single_router<P: Prefix, Ospf: OspfImpl>() {
let mut net: Net<P, Ospf> = Network::default();
let p = P::from(0);
let r = net.add_router("r", 65500);
let e = net.add_router("e", 1);
net.add_link(r, e).unwrap();
assert!(&net.get_router(r).unwrap().ospf.is_reachable(e));
net.set_bgp_session(r, e, Some(false)).unwrap();
net.advertise_route(e, p, [1], None, None).unwrap();
test_route!(net, r, p, [r, e]);
}
#[test]
fn test_remove_router<P: Prefix, Ospf: OspfImpl>() {
let mut net = get_test_net_bgp::<P, Ospf>(test_net);
let p = P::from(0);
net.advertise_route(*E1, p, vec![ASN(65101), ASN(65201)], None, None)
.unwrap();
test_route!(net, *R1, p, [*R1, *E1]);
test_route!(net, *R2, p, [*R2, *R3, *R1, *E1]);
test_route!(net, *R3, p, [*R3, *R1, *E1]);
test_route!(net, *R4, p, [*R4, *R2, *R3, *R1, *E1]);
net.advertise_route(*E4, p, vec![ASN(65104), ASN(65201)], None, None)
.unwrap();
test_route!(net, *R1, p, [*R1, *E1]);
test_route!(net, *R2, p, [*R2, *R4, *E4]);
test_route!(net, *R3, p, [*R3, *R1, *E1]);
test_route!(net, *R4, p, [*R4, *E4]);
let net_clone = net.clone();
let r5 = net.add_router("R5", 65500);
net.add_link(*R3, r5).unwrap();
net.add_link(*R4, r5).unwrap();
net.set_link_weight(*R3, r5, 1.0).unwrap();
net.set_link_weight(*R4, r5, 1.0).unwrap();
net.set_link_weight(r5, *R3, 1.0).unwrap();
net.set_link_weight(r5, *R4, 1.0).unwrap();
net.set_bgp_session(*R1, r5, Some(false)).unwrap();
net.set_bgp_session(*R4, r5, Some(false)).unwrap();
test_route!(net, *R1, p, [*R1, *E1]);
test_route!(net, *R2, p, [*R2, *R4, *E4]);
test_route!(net, *R3, p, [*R3, *R1, *E1]);
test_route!(net, *R4, p, [*R4, *E4]);
test_route!(net, r5, p, [r5, *R4, *E4]);
net.remove_router(r5).unwrap();
assert!(net_clone.weak_eq(&net));
net.remove_router(*E1).unwrap();
test_route!(net, *R1, p, [*R1, *R3, *R2, *R4, *E4]);
test_route!(net, *R2, p, [*R2, *R4, *E4]);
test_route!(net, *R3, p, [*R3, *R2, *R4, *E4]);
test_route!(net, *R4, p, [*R4, *E4]);
net.remove_router(*R2).unwrap();
test_route!(net, *R1, p, [*R1, *R3, *R4, *E4]);
test_route!(net, *R3, p, [*R3, *R4, *E4]);
test_route!(net, *R4, p, [*R4, *E4]);
}
#[test]
fn test_get_router<P: Prefix, Ospf: OspfImpl>() {
let net = test_net::<P, Ospf>();
assert_eq!(net.get_router_id("R1"), Ok(*R1));
assert_eq!(net.get_router_id("R2"), Ok(*R2));
assert_eq!(net.get_router_id("R3"), Ok(*R3));
assert_eq!(net.get_router_id("R4"), Ok(*R4));
assert_eq!(net.get_router_id("E1"), Ok(*E1));
assert_eq!(net.get_router_id("E4"), Ok(*E4));
assert_eq!(net.get_router(*R1).map(|r| r.name()), Ok("R1"));
assert_eq!(net.get_router(*R2).map(|r| r.name()), Ok("R2"));
assert_eq!(net.get_router(*R3).map(|r| r.name()), Ok("R3"));
assert_eq!(net.get_router(*R4).map(|r| r.name()), Ok("R4"));
assert_eq!(net.get_router(*E1).map(|r| r.name()), Ok("E1"));
assert_eq!(net.get_router(*E4).map(|r| r.name()), Ok("E4"));
net.get_router_id("e0").unwrap_err();
net.get_router(10.into()).unwrap_err();
let mut routers = net.indices().collect::<Vec<_>>();
routers.sort();
assert_eq!(routers, vec![*E1, *R1, *R2, *R3, *R4, *E4]);
}
#[test]
fn test_bgp_connectivity<P: Prefix, Ospf: OspfImpl>() {
let mut net = get_test_net_bgp::<P, Ospf>(test_net);
let p = P::from(0);
for router in net.indices() {
assert_eq!(
net.get_forwarding_state().get_paths(router, p),
Err(NetworkError::ForwardingBlackHole(vec![router]))
);
}
net.advertise_route(*E1, p, vec![ASN(65101), ASN(65201)], None, None)
.unwrap();
test_route!(net, *R1, p, [*R1, *E1]);
test_route!(net, *R2, p, [*R2, *R3, *R1, *E1]);
test_route!(net, *R3, p, [*R3, *R1, *E1]);
test_route!(net, *R4, p, [*R4, *R2, *R3, *R1, *E1]);
net.advertise_route(*E4, p, vec![ASN(65104), ASN(65201)], None, None)
.unwrap();
test_route!(net, *R1, p, [*R1, *E1]);
test_route!(net, *R2, p, [*R2, *R4, *E4]);
test_route!(net, *R3, p, [*R3, *R1, *E1]);
test_route!(net, *R4, p, [*R4, *E4]);
}
#[test]
fn test_bgp_rib_entries<P: Prefix, Ospf: OspfImpl>() {
use ordered_float::NotNan;
let mut net = get_test_net_bgp::<P, Ospf>(test_net);
let p = P::from(0);
net.advertise_route(*E1, p, vec![ASN(65101), ASN(65201)], None, None)
.unwrap();
test_route!(net, *R1, p, [*R1, *E1]);
test_route!(net, *R2, p, [*R2, *R3, *R1, *E1]);
test_route!(net, *R3, p, [*R3, *R1, *E1]);
test_route!(net, *R4, p, [*R4, *R2, *R3, *R1, *E1]);
let r1_rib = net.get_router(*R1).unwrap().bgp.get_rib().get(&p).unwrap();
let r2_rib = net.get_router(*R2).unwrap().bgp.get_rib().get(&p).unwrap();
let r3_rib = net.get_router(*R3).unwrap().bgp.get_rib().get(&p).unwrap();
let r4_rib = net.get_router(*R4).unwrap().bgp.get_rib().get(&p).unwrap();
assert_eq!(r1_rib.route.next_hop, *E1);
assert_eq!(r2_rib.route.next_hop, *R1);
assert_eq!(r3_rib.route.next_hop, *R1);
assert_eq!(r4_rib.route.next_hop, *R1);
assert_eq!(r1_rib.igp_cost.unwrap(), NotNan::new(0.0).unwrap());
assert_eq!(r2_rib.igp_cost.unwrap(), NotNan::new(2.0).unwrap());
assert_eq!(r3_rib.igp_cost.unwrap(), NotNan::new(1.0).unwrap());
assert_eq!(r4_rib.igp_cost.unwrap(), NotNan::new(3.0).unwrap());
net.advertise_route(*E4, p, vec![ASN(65104), ASN(65201)], None, None)
.unwrap();
test_route!(net, *R1, p, [*R1, *E1]);
test_route!(net, *R2, p, [*R2, *R4, *E4]);
test_route!(net, *R3, p, [*R3, *R1, *E1]);
test_route!(net, *R4, p, [*R4, *E4]);
let r1_rib = net.get_router(*R1).unwrap().bgp.get_rib().get(&p).unwrap();
let r2_rib = net.get_router(*R2).unwrap().bgp.get_rib().get(&p).unwrap();
let r3_rib = net.get_router(*R3).unwrap().bgp.get_rib().get(&p).unwrap();
let r4_rib = net.get_router(*R4).unwrap().bgp.get_rib().get(&p).unwrap();
assert_eq!(r1_rib.route.next_hop, *E1);
assert_eq!(r2_rib.route.next_hop, *R4);
assert_eq!(r3_rib.route.next_hop, *R1);
assert_eq!(r4_rib.route.next_hop, *E4);
assert_eq!(r1_rib.igp_cost.unwrap(), NotNan::new(0.0).unwrap());
assert_eq!(r2_rib.igp_cost.unwrap(), NotNan::new(1.0).unwrap());
assert_eq!(r3_rib.igp_cost.unwrap(), NotNan::new(1.0).unwrap());
assert_eq!(r4_rib.igp_cost.unwrap(), NotNan::new(0.0).unwrap());
}
#[test]
fn test_static_route<P: Prefix, Ospf: OspfImpl>() {
let mut net = get_test_net_bgp::<P, Ospf>(test_net);
let p = P::from(0);
for router in net.indices() {
assert_eq!(
net.get_forwarding_state().get_paths(router, p),
Err(NetworkError::ForwardingBlackHole(vec![router]))
);
}
net.advertise_route(*E1, p, vec![ASN(65101), ASN(65201)], None, None)
.unwrap();
net.advertise_route(*E4, p, vec![ASN(65104), ASN(65201)], None, None)
.unwrap();
test_route!(net, *R1, p, [*R1, *E1]);
test_route!(net, *R2, p, [*R2, *R4, *E4]);
test_route!(net, *R3, p, [*R3, *R1, *E1]);
test_route!(net, *R4, p, [*R4, *E4]);
net.set_static_route(*R3, p, Some(Direct(*R4))).unwrap();
test_route!(net, *R1, p, [*R1, *E1]);
test_route!(net, *R2, p, [*R2, *R4, *E4]);
test_route!(net, *R3, p, [*R3, *R4, *E4]);
test_route!(net, *R4, p, [*R4, *E4]);
net.set_static_route(*R2, p, Some(Direct(*R3))).unwrap();
test_route!(net, *R1, p, [*R1, *E1]);
test_route!(net, *R2, p, [*R2, *R3, *R4, *E4]);
test_route!(net, *R3, p, [*R3, *R4, *E4]);
test_route!(net, *R4, p, [*R4, *E4]);
net.set_static_route(*R1, p, Some(Direct(*R4))).unwrap();
assert_eq!(
net.get_forwarding_state().get_paths(*R1, p),
Err(NetworkError::ForwardingBlackHole(vec![*R1]))
);
net.set_static_route(*R1, p, Some(Indirect(*R4))).unwrap();
test_route!(net, *R1, p, [*R1, *R3, *R4, *E4]);
}
#[test]
fn test_bgp_decision<P: Prefix, Ospf: OspfImpl>() {
let mut net = get_test_net_bgp::<P, Ospf>(test_net);
let p = P::from(0);
net.advertise_route(*E1, p, vec![ASN(65101), ASN(65201)], None, None)
.unwrap();
net.advertise_route(*E4, p, vec![ASN(65104), ASN(65201)], None, None)
.unwrap();
test_route!(net, *R1, p, [*R1, *E1]);
test_route!(net, *R2, p, [*R2, *R4, *E4]);
test_route!(net, *R3, p, [*R3, *R1, *E1]);
test_route!(net, *R4, p, [*R4, *E4]);
net.advertise_route(*E4, p, vec![ASN(65104), ASN(65500), ASN(65201)], None, None)
.unwrap();
test_route!(net, *R1, p, [*R1, *E1]);
test_route!(net, *R2, p, [*R2, *R3, *R1, *E1]);
test_route!(net, *R3, p, [*R3, *R1, *E1]);
test_route!(net, *R4, p, [*R4, *R2, *R3, *R1, *E1]);
net.advertise_route(*E4, p, vec![ASN(65104), ASN(65201)], None, None)
.unwrap();
test_route!(net, *R1, p, [*R1, *E1]);
test_route!(net, *R2, p, [*R2, *R4, *E4]);
test_route!(net, *R3, p, [*R3, *R1, *E1]);
test_route!(net, *R4, p, [*R4, *E4]);
net.advertise_route(*E4, p, vec![ASN(65104), ASN(65201)], Some(20), None)
.unwrap();
test_route!(net, *R1, p, [*R1, *E1]);
test_route!(net, *R2, p, [*R2, *R4, *E4]);
test_route!(net, *R3, p, [*R3, *R1, *E1]);
test_route!(net, *R4, p, [*R4, *E4]);
net.advertise_route(*E4, p, vec![ASN(65104), ASN(65201)], None, None)
.unwrap();
test_route!(net, *R1, p, [*R1, *E1]);
test_route!(net, *R2, p, [*R2, *R4, *E4]);
test_route!(net, *R3, p, [*R3, *R1, *E1]);
test_route!(net, *R4, p, [*R4, *E4]);
}
#[test]
fn test_bgp_decision_with_med<P: Prefix, Ospf: OspfImpl>() {
let mut net = get_test_net_bgp::<P, Ospf>(test_net);
assert_eq!(net.add_router("E5", 65101), *E5);
net.add_link(*R4, *E5).unwrap();
net.set_bgp_session(*R4, *E5, Some(false)).unwrap();
let p = P::from(0);
net.advertise_route(*E1, p, vec![ASN(65201)], None, None)
.unwrap();
net.advertise_route(*E5, p, vec![ASN(65201)], None, None)
.unwrap();
test_route!(net, *R1, p, [*R1, *E1]);
test_route!(net, *R2, p, [*R2, *R4, *E5]);
test_route!(net, *R3, p, [*R3, *R1, *E1]);
test_route!(net, *R4, p, [*R4, *E5]);
net.advertise_route(*E5, p, vec![ASN(65201)], Some(20), None)
.unwrap();
println!(
"{:#?}",
net.get_router(*R4)
.unwrap()
.bgp
.get_known_routes(p)
.unwrap()
);
test_route!(net, *R1, p, [*R1, *E1]);
test_route!(net, *R2, p, [*R2, *R3, *R1, *E1]);
test_route!(net, *R3, p, [*R3, *R1, *E1]);
test_route!(net, *R4, p, [*R4, *R2, *R3, *R1, *E1]);
net.advertise_route(*E5, p, vec![ASN(65201)], None, None)
.unwrap();
test_route!(net, *R1, p, [*R1, *E1]);
test_route!(net, *R2, p, [*R2, *R4, *E5]);
test_route!(net, *R3, p, [*R3, *R1, *E1]);
test_route!(net, *R4, p, [*R4, *E5]);
}
#[test]
fn test_route_maps<P: Prefix, Ospf: OspfImpl>() {
let mut original_net = get_test_net_bgp::<P, Ospf>(test_net);
let p = P::from(0);
original_net
.advertise_route(*E1, p, vec![ASN(65101), ASN(65201)], None, None)
.unwrap();
original_net
.advertise_route(*E4, p, vec![ASN(65104), ASN(65201)], None, None)
.unwrap();
test_route!(original_net, *R1, p, [*R1, *E1]);
assert_eq!(
original_net.get_forwarding_state().get_paths(*R2, p),
Ok(vec![vec![*R2, *R4, *E4]]),
);
assert_eq!(
original_net.get_forwarding_state().get_paths(*R3, p),
Ok(vec![vec![*R3, *R1, *E1]])
);
test_route!(original_net, *R4, p, [*R4, *E4]);
let mut net = original_net.clone();
net.set_bgp_route_map(
*R1,
*E1,
Incoming,
RouteMap::new(10, Deny, vec![], vec![], Continue),
)
.unwrap();
test_route!(net, *R1, p, [*R1, *R3, *R2, *R4, *E4]);
test_route!(net, *R2, p, [*R2, *R4, *E4]);
test_route!(net, *R3, p, [*R3, *R2, *R4, *E4]);
test_route!(net, *R4, p, [*R4, *E4]);
let mut net = original_net.clone();
net.set_bgp_route_map(
*R1,
*R2,
Outgoing,
RouteMap::new(20, Deny, vec![], vec![], Continue),
)
.unwrap();
net.set_bgp_route_map(
*R1,
*R3,
Outgoing,
RouteMap::new(20, Deny, vec![], vec![], Continue),
)
.unwrap();
net.set_bgp_route_map(
*R1,
*R4,
Outgoing,
RouteMap::new(20, Deny, vec![], vec![], Continue),
)
.unwrap();
test_route!(net, *R1, p, [*R1, *E1]);
test_route!(net, *R2, p, [*R2, *R4, *E4]);
test_route!(net, *R3, p, [*R3, *R2, *R4, *E4]);
test_route!(net, *R4, p, [*R4, *E4]);
let mut net = original_net.clone();
net.set_bgp_route_map(
*R1,
*E1,
Incoming,
RouteMap::new(10, Allow, vec![], vec![Set::LocalPref(Some(50))], Continue),
)
.unwrap();
test_route!(net, *R1, p, [*R1, *R3, *R2, *R4, *E4]);
test_route!(net, *R2, p, [*R2, *R4, *E4]);
test_route!(net, *R3, p, [*R3, *R2, *R4, *E4]);
test_route!(net, *R4, p, [*R4, *E4]);
let mut net = original_net.clone();
net.set_bgp_route_map(
*R1,
*R2,
Outgoing,
RouteMap::new(10, Allow, vec![], vec![Set::LocalPref(Some(50))], Continue),
)
.unwrap();
net.set_bgp_route_map(
*R1,
*R3,
Outgoing,
RouteMap::new(10, Allow, vec![], vec![Set::LocalPref(Some(50))], Continue),
)
.unwrap();
net.set_bgp_route_map(
*R1,
*R4,
Outgoing,
RouteMap::new(10, Allow, vec![], vec![Set::LocalPref(Some(50))], Continue),
)
.unwrap();
test_route!(net, *R1, p, [*R1, *E1]);
test_route!(net, *R2, p, [*R2, *R4, *E4]);
test_route!(net, *R3, p, [*R3, *R2, *R4, *E4]);
test_route!(net, *R4, p, [*R4, *E4]);
let mut net = original_net;
net.set_bgp_route_map(
*R1,
*R2,
Outgoing,
RouteMap::new(10, Allow, vec![], vec![Set::LocalPref(Some(200))], Exit),
)
.unwrap();
test_route!(net, *R1, p, [*R1, *E1]);
test_route!(net, *R2, p, [*R2, *R3, *R1, *E1]);
test_route!(net, *R3, p, [*R3, *R1, *E1]);
test_route!(net, *R4, p, [*R4, *E4]);
net.set_bgp_route_map(
*R1,
*R2,
Outgoing,
RouteMap::new(20, Allow, vec![], vec![Set::LocalPref(Some(50))], Continue),
)
.unwrap();
net.set_bgp_route_map(
*R1,
*R3,
Outgoing,
RouteMap::new(20, Allow, vec![], vec![Set::LocalPref(Some(50))], Continue),
)
.unwrap();
net.set_bgp_route_map(
*R1,
*R4,
Outgoing,
RouteMap::new(20, Allow, vec![], vec![Set::LocalPref(Some(50))], Continue),
)
.unwrap();
test_route!(net, *R1, p, [*R1, *E1]);
test_bad_route!(fw_loop, &net, *R2, p, [], [*R2, *R3]);
test_bad_route!(fw_loop, &net, *R3, p, [], [*R3, *R2]);
test_route!(net, *R4, p, [*R4, *E4]);
net.set_link_weight(*R3, *R4, 1.0).unwrap();
net.set_link_weight(*R4, *R3, 1.0).unwrap();
test_route!(net, *R1, p, [*R1, *E1]);
test_route!(net, *R2, p, [*R2, *R3, *R4, *E4]);
test_route!(net, *R3, p, [*R3, *R4, *E4]);
test_route!(net, *R4, p, [*R4, *E4]);
}
#[test]
fn test_link_failure<P: Prefix, Ospf: OspfImpl>() {
let mut original_net = get_test_net_bgp::<P, Ospf>(test_net);
let p = P::from(0);
original_net
.advertise_route(*E1, p, vec![ASN(65101), ASN(65103), ASN(65201)], None, None)
.unwrap();
original_net
.advertise_route(
*E4,
p,
vec![ASN(65104), ASN(65101), ASN(65103), ASN(65201)],
None,
None,
)
.unwrap();
test_route!(original_net, *R1, p, [*R1, *E1]);
test_route!(original_net, *R2, p, [*R2, *R3, *R1, *E1]);
test_route!(original_net, *R3, p, [*R3, *R1, *E1]);
test_route!(original_net, *R4, p, [*R4, *R2, *R3, *R1, *E1]);
let mut net = original_net.clone();
net.remove_link(*R2, *R4).unwrap();
test_route!(net, *R1, p, [*R1, *E1]);
test_route!(net, *R2, p, [*R2, *R3, *R1, *E1]);
test_route!(net, *R3, p, [*R3, *R1, *E1]);
test_route!(net, *R4, p, [*R4, *R3, *R1, *E1]);
let mut net = original_net.clone();
net.remove_link(*R1, *R4).unwrap_err();
let mut net = original_net.clone();
net.remove_link(*R1, *E1).unwrap();
test_route!(net, *R1, p, [*R1, *R3, *R2, *R4, *E4]);
test_route!(net, *R2, p, [*R2, *R4, *E4]);
test_route!(net, *R3, p, [*R3, *R2, *R4, *E4]);
test_route!(net, *R4, p, [*R4, *E4]);
let mut net = original_net.clone();
net.remove_link(*E1, *R1).unwrap();
test_route!(net, *R1, p, [*R1, *R3, *R2, *R4, *E4]);
test_route!(net, *R2, p, [*R2, *R4, *E4]);
test_route!(net, *R3, p, [*R3, *R2, *R4, *E4]);
test_route!(net, *R4, p, [*R4, *E4]);
let mut net = original_net.clone();
net.remove_link(*R2, *R3).unwrap();
test_route!(net, *R1, p, [*R1, *E1]);
test_route!(net, *R2, p, [*R2, *R1, *E1]);
test_route!(net, *R3, p, [*R3, *R1, *E1]);
test_route!(net, *R4, p, [*R4, *R3, *R1, *E1]);
let mut net = original_net;
net.withdraw_route(*E4, p).unwrap();
test_route!(net, *R1, p, [*R1, *E1]);
test_route!(net, *R2, p, [*R2, *R3, *R1, *E1]);
test_route!(net, *R3, p, [*R3, *R1, *E1]);
test_route!(net, *R4, p, [*R4, *R2, *R3, *R1, *E1]);
}
#[test]
fn test_config_extractor<P: Prefix, Ospf: OspfImpl>() {
let mut net = get_test_net_bgp::<P, Ospf>(test_net);
let mut original_cfg = net.get_config().unwrap();
let extracted_cfg = net.get_config().unwrap();
assert_eq!(original_cfg, extracted_cfg);
let modifier = crate::config::ConfigModifier::Update {
from: IgpLinkWeight {
source: *R2,
target: *R4,
weight: 1.0,
},
to: IgpLinkWeight {
source: *R2,
target: *R4,
weight: 2.0,
},
};
net.apply_modifier(&modifier).unwrap();
let extracted_cfg = net.get_config().unwrap();
assert_ne!(original_cfg, extracted_cfg);
original_cfg.apply_modifier(&modifier).unwrap();
assert_eq!(original_cfg, extracted_cfg);
}
fn get_test_net_bgp_load_balancing<P: Prefix, Ospf: OspfImpl>(
) -> Network<P, BasicEventQueue<P>, Ospf> {
let mut net = test_net::<P, Ospf>();
net.set_link_weight(*R1, *R2, 2.0).unwrap();
net.set_link_weight(*R1, *R3, 1.0).unwrap();
net.set_link_weight(*R2, *R3, 1.0).unwrap();
net.set_link_weight(*R2, *R4, 1.0).unwrap();
net.set_link_weight(*R3, *R4, 2.0).unwrap();
net.set_link_weight(*R2, *R1, 2.0).unwrap();
net.set_link_weight(*R3, *R1, 1.0).unwrap();
net.set_link_weight(*R3, *R2, 1.0).unwrap();
net.set_link_weight(*R4, *R2, 1.0).unwrap();
net.set_link_weight(*R4, *R3, 2.0).unwrap();
net.set_bgp_session(*R1, *R2, Some(false)).unwrap();
net.set_bgp_session(*R1, *R3, Some(false)).unwrap();
net.set_bgp_session(*R1, *R4, Some(false)).unwrap();
net.set_bgp_session(*R2, *R3, Some(false)).unwrap();
net.set_bgp_session(*R2, *R4, Some(false)).unwrap();
net.set_bgp_session(*R3, *R4, Some(false)).unwrap();
net.set_bgp_session(*R1, *E1, Some(false)).unwrap();
net.set_bgp_session(*R4, *E4, Some(false)).unwrap();
net
}
#[test]
fn test_load_balancing<P: Prefix, Ospf: OspfImpl>() {
let mut net = get_test_net_bgp_load_balancing::<P, Ospf>();
let p = P::from(0);
net.advertise_route(*E1, p, vec![ASN(65101)], None, None)
.unwrap();
test_route!(net, *R1, p, [*R1, *E1]);
test_route!(net, *R2, p, [*R2, *R1, *E1]);
test_route!(net, *R3, p, [*R3, *R1, *E1]);
test_route!(net, *R4, p, [*R4, *R2, *R1, *E1]);
net.set_load_balancing(*R1, true).unwrap();
net.set_load_balancing(*R2, true).unwrap();
net.set_load_balancing(*R3, true).unwrap();
net.set_load_balancing(*R4, true).unwrap();
test_route!(net, *R1, p, [*R1, *E1]);
test_route!(net, *R2, p, [*R2, *R1, *E1], [*R2, *R3, *R1, *E1]);
test_route!(net, *R3, p, [*R3, *R1, *E1]);
test_route!(
&net,
*R4,
p,
[*R4, *R2, *R1, *E1],
[*R4, *R2, *R3, *R1, *E1],
[*R4, *R3, *R1, *E1]
);
}
#[test]
fn test_static_route_load_balancing<P: Prefix, Ospf: OspfImpl>() {
let mut net = get_test_net_bgp_load_balancing::<P, Ospf>();
let p = P::from(0);
net.advertise_route(*E1, p, vec![ASN(1), ASN(2), ASN(3)], None, None)
.unwrap();
net.advertise_route(*E4, p, vec![ASN(5)], None, None)
.unwrap();
test_route!(net, *R1, p, [*R1, *R2, *R4, *E4]);
test_route!(net, *R2, p, [*R2, *R4, *E4]);
test_route!(net, *R3, p, [*R3, *R2, *R4, *E4]);
test_route!(net, *R4, p, [*R4, *E4]);
net.set_load_balancing(*R1, true).unwrap();
net.set_load_balancing(*R2, true).unwrap();
net.set_load_balancing(*R3, true).unwrap();
net.set_load_balancing(*R4, true).unwrap();
test_route!(
&net,
*R1,
p,
[*R1, *R2, *R4, *E4],
[*R1, *R3, *R2, *R4, *E4],
[*R1, *R3, *R4, *E4]
);
test_route!(net, *R2, p, [*R2, *R4, *E4]);
test_route!(net, *R3, p, [*R3, *R2, *R4, *E4], [*R3, *R4, *E4]);
test_route!(net, *R4, p, [*R4, *E4]);
net.set_static_route(*R1, p, Some(Direct(*E1))).unwrap();
net.set_static_route(*R2, p, Some(Indirect(*R1))).unwrap();
net.set_static_route(*R3, p, Some(Indirect(*R1))).unwrap();
net.set_static_route(*R4, p, Some(Indirect(*R1))).unwrap();
test_route!(net, *R1, p, [*R1, *E1]);
test_route!(net, *R2, p, [*R2, *R1, *E1], [*R2, *R3, *R1, *E1]);
test_route!(net, *R3, p, [*R3, *R1, *E1]);
test_route!(
&net,
*R4,
p,
[*R4, *R2, *R1, *E1],
[*R4, *R2, *R3, *R1, *E1],
[*R4, *R3, *R1, *E1]
);
}
#[test]
fn bgp_propagation_client_peers<P: Prefix, Ospf: OspfImpl>() {
let mut net = Network::<_, _, Ospf>::default();
let r1 = net.add_router("r1", 65500);
let r2 = net.add_router("r2", 65500);
let r3 = net.add_router("r3", 65500);
let e3 = net.add_router("e3", ASN(3));
let p = P::from(1);
net.add_link(r1, r2).unwrap();
net.add_link(r1, r3).unwrap();
net.add_link(r3, e3).unwrap();
net.build_link_weights(1.0).unwrap();
net.build_ebgp_sessions().unwrap();
net.set_bgp_session(r1, r2, Some(false)).unwrap();
net.set_bgp_session(r1, r3, Some(true)).unwrap();
net.advertise_route(e3, p, [3, 3, 30], None, None).unwrap();
let mut fw_state = net.get_forwarding_state();
assert_eq!(fw_state.get_paths(r3, p), Ok(vec![vec![r3, e3]]));
assert_eq!(fw_state.get_paths(r1, p), Ok(vec![vec![r1, r3, e3]]));
assert_eq!(fw_state.get_paths(r2, p), Ok(vec![vec![r2, r1, r3, e3]]));
}
#[test]
fn bgp_state_incoming<P: Prefix, Ospf: OspfImpl>() {
let mut net = get_test_net_igp::<P, Ospf>(test_net);
let p = P::from(1);
net.build_ibgp_route_reflection(vec![*R2]).unwrap();
net.build_ebgp_sessions().unwrap();
net.build_advertisements(p, EqualPreference::new().internal_asn(ASN(65500)), ASN(100))
.unwrap();
let state = net.get_bgp_state(p);
let route_e1 = BgpRoute {
prefix: p,
as_path: vec![ASN(65101), ASN(100)],
next_hop: *E1,
local_pref: None,
med: None,
community: Default::default(),
originator_id: None,
cluster_list: Vec::new(),
};
let route_r1 = BgpRoute {
prefix: p,
as_path: vec![ASN(65101), ASN(100)],
next_hop: *R1,
local_pref: Some(100),
med: Some(0),
community: Default::default(),
originator_id: None,
cluster_list: Vec::new(),
};
let route_e4 = BgpRoute {
prefix: p,
as_path: vec![ASN(65104), ASN(100)],
next_hop: *E4,
local_pref: None,
med: None,
community: Default::default(),
originator_id: None,
cluster_list: Vec::new(),
};
let route_r4 = BgpRoute {
prefix: p,
as_path: vec![ASN(65104), ASN(100)],
next_hop: *R4,
local_pref: Some(100),
med: Some(0),
community: Default::default(),
originator_id: None,
cluster_list: Vec::new(),
};
let route_r42 = BgpRoute {
originator_id: Some(*R4),
cluster_list: vec![*R2],
..route_r4.clone()
};
assert_eq!(BTreeMap::from_iter(state.incoming(*E1)), btreemap! {});
assert_eq!(
BTreeMap::from_iter(state.incoming(*R1)),
btreemap! {*E1 => &route_e1, *R2 => &route_r42}
);
assert_eq!(
BTreeMap::from_iter(state.incoming(*R2)),
btreemap! {*R1 => &route_r1, *R4 => &route_r4}
);
assert_eq!(
BTreeMap::from_iter(state.incoming(*R3)),
btreemap! {*R2 => &route_r42}
);
assert_eq!(
BTreeMap::from_iter(state.incoming(*R4)),
btreemap! {*E4 => &route_e4}
);
assert_eq!(BTreeMap::from_iter(state.incoming(*E4)), btreemap! {});
}
#[test]
fn bgp_state_incoming_2<P: Prefix, Ospf: OspfImpl>() {
let mut net = get_test_net_igp::<P, Ospf>(test_net);
let p = P::from(1);
net.build_ibgp_route_reflection(vec![*R2]).unwrap();
net.build_ebgp_sessions().unwrap();
net.advertise_route(*E4, p, vec![ASN(100)], None, None)
.unwrap();
let state = net.get_bgp_state(p);
let route_e4 = BgpRoute {
prefix: p,
as_path: vec![ASN(65104), ASN(100)],
next_hop: *E4,
local_pref: None,
med: None,
community: Default::default(),
originator_id: None,
cluster_list: Vec::new(),
};
let route_r4 = BgpRoute {
prefix: p,
as_path: vec![ASN(65104), ASN(100)],
next_hop: *R4,
local_pref: Some(100),
med: Some(0),
community: Default::default(),
originator_id: None,
cluster_list: Vec::new(),
};
let route_r42 = BgpRoute {
originator_id: Some(*R4),
cluster_list: vec![*R2],
..route_r4.clone()
};
let route_r421 = BgpRoute {
prefix: p,
as_path: vec![DEFAULT_INTERNAL_ASN, ASN(65104), ASN(100)],
next_hop: *R1,
local_pref: None,
med: None,
community: Default::default(),
originator_id: None,
cluster_list: Vec::new(),
};
assert_eq!(
BTreeMap::from_iter(state.incoming(*E1)),
btreemap! {*R1 => &route_r421}
);
assert_eq!(
BTreeMap::from_iter(state.incoming(*R1)),
btreemap! {*R2 => &route_r42}
);
assert_eq!(
BTreeMap::from_iter(state.incoming(*R2)),
btreemap! {*R4 => &route_r4}
);
assert_eq!(
BTreeMap::from_iter(state.incoming(*R3)),
btreemap! {*R2 => &route_r42}
);
assert_eq!(
BTreeMap::from_iter(state.incoming(*R4)),
btreemap! {*E4 => &route_e4}
);
assert_eq!(BTreeMap::from_iter(state.incoming(*E4)), btreemap! {});
}
#[test]
fn bgp_state_peers_incoming<P: Prefix, Ospf: OspfImpl>() {
let mut net = get_test_net_igp::<P, Ospf>(test_net);
let p = P::from(1);
net.build_ibgp_route_reflection(vec![*R2]).unwrap();
net.build_ebgp_sessions().unwrap();
net.build_advertisements(p, EqualPreference::new().internal_asn(ASN(65500)), ASN(0))
.unwrap();
let state = net.get_bgp_state(p);
assert_eq!(BTreeSet::from_iter(state.peers_incoming(*E1)), btreeset! {});
assert_eq!(
BTreeSet::from_iter(state.peers_incoming(*R1)),
btreeset! {*E1, *R2}
);
assert_eq!(
BTreeSet::from_iter(state.peers_incoming(*R2)),
btreeset! {*R1, *R4}
);
assert_eq!(
BTreeSet::from_iter(state.peers_incoming(*R3)),
btreeset! {*R2}
);
assert_eq!(
BTreeSet::from_iter(state.peers_incoming(*R4)),
btreeset! {*E4}
);
assert_eq!(BTreeSet::from_iter(state.peers_incoming(*E4)), btreeset! {});
}
#[test]
fn bgp_state_outgoing<P: Prefix, Ospf: OspfImpl>() {
let mut net = get_test_net_igp::<P, Ospf>(test_net);
let p = P::from(1);
net.build_ibgp_route_reflection(vec![*R2]).unwrap();
net.build_ebgp_sessions().unwrap();
net.build_advertisements(p, EqualPreference::new().internal_asn(ASN(65500)), ASN(0))
.unwrap();
let state = net.get_bgp_state(p);
let route_e1 = BgpRoute {
prefix: p,
as_path: vec![ASN(65101), ASN(0)],
next_hop: *E1,
local_pref: None,
med: None,
community: Default::default(),
originator_id: None,
cluster_list: Vec::new(),
};
let route_r1 = BgpRoute {
prefix: p,
as_path: vec![ASN(65101), ASN(0)],
next_hop: *R1,
local_pref: Some(100),
med: Some(0),
community: Default::default(),
originator_id: None,
cluster_list: Vec::new(),
};
let route_e4 = BgpRoute {
prefix: p,
as_path: vec![ASN(65104), ASN(0)],
next_hop: *E4,
local_pref: None,
med: None,
community: Default::default(),
originator_id: None,
cluster_list: Vec::new(),
};
let route_r4 = BgpRoute {
prefix: p,
as_path: vec![ASN(65104), ASN(0)],
next_hop: *R4,
local_pref: Some(100),
med: Some(0),
community: Default::default(),
originator_id: None,
cluster_list: Vec::new(),
};
let route_r42 = BgpRoute {
originator_id: Some(*R4),
cluster_list: vec![*R2],
..route_r4.clone()
};
assert_eq!(
BTreeMap::from_iter(state.outgoing(*E1)),
btreemap! {*R1 => &route_e1}
);
assert_eq!(
BTreeMap::from_iter(state.outgoing(*R1)),
btreemap! {*R2 => &route_r1}
);
assert_eq!(
BTreeMap::from_iter(state.outgoing(*R2)),
btreemap! {*R1 => &route_r42, *R3 => &route_r42}
);
assert_eq!(BTreeMap::from_iter(state.outgoing(*R3)), btreemap! {});
assert_eq!(
BTreeMap::from_iter(state.outgoing(*R4)),
btreemap! {*R2 => &route_r4}
);
assert_eq!(
BTreeMap::from_iter(state.outgoing(*E4)),
btreemap! {*R4 => &route_e4}
);
}
#[test]
fn bgp_state_outgoing_2<P: Prefix, Ospf: OspfImpl>() {
let mut net = get_test_net_igp::<P, Ospf>(test_net);
let p = P::from(1);
net.build_ibgp_route_reflection(vec![*R2]).unwrap();
net.build_ebgp_sessions().unwrap();
net.advertise_route(*E4, p, vec![ASN(100)], None, None)
.unwrap();
let state = net.get_bgp_state(p);
let route_e4 = BgpRoute {
prefix: p,
as_path: vec![ASN(65104), ASN(100)],
next_hop: *E4,
local_pref: None,
med: None,
community: Default::default(),
originator_id: None,
cluster_list: Vec::new(),
};
let route_r4 = BgpRoute {
prefix: p,
as_path: vec![ASN(65104), ASN(100)],
next_hop: *R4,
local_pref: Some(100),
med: Some(0),
community: Default::default(),
originator_id: None,
cluster_list: Vec::new(),
};
let route_r42 = BgpRoute {
originator_id: Some(*R4),
cluster_list: vec![*R2],
..route_r4.clone()
};
let route_r421 = BgpRoute {
prefix: p,
as_path: vec![ASN(65500), ASN(65104), ASN(100)],
next_hop: *R1,
local_pref: None,
med: None,
community: Default::default(),
originator_id: None,
cluster_list: Vec::new(),
};
assert_eq!(BTreeMap::from_iter(state.outgoing(*E1)), btreemap! {});
assert_eq!(
BTreeMap::from_iter(state.outgoing(*R1)),
btreemap! {*E1 => &route_r421}
);
assert_eq!(
BTreeMap::from_iter(state.outgoing(*R2)),
btreemap! {*R1 => &route_r42, *R3 => &route_r42}
);
assert_eq!(BTreeMap::from_iter(state.outgoing(*R3)), btreemap! {});
assert_eq!(
BTreeMap::from_iter(state.outgoing(*R4)),
btreemap! {*R2 => &route_r4}
);
assert_eq!(
BTreeMap::from_iter(state.outgoing(*E4)),
btreemap! {*R4 => &route_e4}
);
}
#[test]
fn bgp_state_peers_outgoing<P: Prefix, Ospf: OspfImpl>() {
let mut net = get_test_net_igp::<P, Ospf>(test_net);
let p = P::from(1);
net.build_ibgp_route_reflection(vec![*R2]).unwrap();
net.build_ebgp_sessions().unwrap();
net.build_advertisements(p, EqualPreference::new().internal_asn(ASN(65500)), ASN(0))
.unwrap();
let state = net.get_bgp_state(p);
assert_eq!(
BTreeSet::from_iter(state.peers_outgoing(*E1)),
btreeset! {*R1}
);
assert_eq!(
BTreeSet::from_iter(state.peers_outgoing(*R1)),
btreeset! {*R2}
);
assert_eq!(
BTreeSet::from_iter(state.peers_outgoing(*R2)),
btreeset! {*R1, *R3}
);
assert_eq!(BTreeSet::from_iter(state.peers_outgoing(*R3)), btreeset! {});
assert_eq!(
BTreeSet::from_iter(state.peers_outgoing(*R4)),
btreeset! {*R2}
);
assert_eq!(
BTreeSet::from_iter(state.peers_outgoing(*E4)),
btreeset! {*R4}
);
}
#[test]
fn bgp_state_reach<P: Prefix, Ospf: OspfImpl>() {
let mut net = get_test_net_igp::<P, Ospf>(test_net);
let p = P::from(1);
net.build_ibgp_route_reflection(vec![*R2]).unwrap();
net.build_ebgp_sessions().unwrap();
net.build_advertisements(p, EqualPreference::new().internal_asn(ASN(65500)), ASN(0))
.unwrap();
let state = net.get_bgp_state(p);
assert_eq!(BTreeSet::from_iter(state.reach(*E1)), btreeset! {*E1, *R1});
assert_eq!(BTreeSet::from_iter(state.reach(*R1)), btreeset! {*R1});
assert_eq!(BTreeSet::from_iter(state.reach(*R2)), btreeset! {*R2, *R3});
assert_eq!(BTreeSet::from_iter(state.reach(*R3)), btreeset! {*R3});
assert_eq!(
BTreeSet::from_iter(state.reach(*R4)),
btreeset! {*R2, *R3, *R4}
);
assert_eq!(
BTreeSet::from_iter(state.reach(*E4)),
btreeset! {*R2, *R3, *R4, *E4}
);
}
#[test]
fn bgp_state_propagation_path<P: Prefix, Ospf: OspfImpl>() {
let mut net = get_test_net_igp::<P, Ospf>(test_net);
let p = P::from(1);
net.build_ibgp_route_reflection(vec![*R2]).unwrap();
net.build_ebgp_sessions().unwrap();
net.build_advertisements(p, EqualPreference::new().internal_asn(ASN(65500)), ASN(0))
.unwrap();
let state = net.get_bgp_state(p);
assert_eq!(state.propagation_path(*E1), vec![*E1]);
assert_eq!(state.propagation_path(*R1), vec![*E1, *R1]);
assert_eq!(state.propagation_path(*R2), vec![*E4, *R4, *R2]);
assert_eq!(state.propagation_path(*R3), vec![*E4, *R4, *R2, *R3]);
assert_eq!(state.propagation_path(*R4), vec![*E4, *R4]);
assert_eq!(state.propagation_path(*E4), vec![*E4]);
}
#[test]
fn bgp_state_transform<P: Prefix, Ospf: OspfImpl>() {
let mut net = get_test_net_igp::<P, Ospf>(test_net);
let p = P::from(1);
net.build_ibgp_route_reflection(vec![*R2]).unwrap();
net.build_ebgp_sessions().unwrap();
net.build_advertisements(p, EqualPreference::new().internal_asn(ASN(65500)), ASN(0))
.unwrap();
assert_eq!(net.get_bgp_state(p).as_owned(), net.get_bgp_state_owned(p));
assert_eq!(
net.get_bgp_state(p).into_owned(),
net.get_bgp_state_owned(p)
);
}
#[instantiate_tests(<SinglePrefix, GlobalOspf>)]
mod single_global_ospf {}
#[instantiate_tests(<SimplePrefix, GlobalOspf>)]
mod simple_global_ospf {}
#[instantiate_tests(<Ipv4Prefix, GlobalOspf>)]
mod ipv4_global_ospf {}
#[instantiate_tests(<SinglePrefix, LocalOspf>)]
mod single_local_ospf {}
#[instantiate_tests(<SimplePrefix, LocalOspf>)]
mod simple_local_ospf {}
#[instantiate_tests(<Ipv4Prefix, LocalOspf>)]
mod ipv4_local_ospf {}
}