net!() { /* proc-macro */ }
Expand description
Create a Network
using a domain specific language. This proc-macro will check at compile time
that all invariants are satisfied.
§Syntax
The content can contain the following parts:
-
links
: An enumeration of links in the network. Each link is written asSRC -> DST: WEIGHT
, where bothSRC
andDST
are identifiers of a node, andWEIGHT
is a number defining the weight. By default, this notation will automatically create the link, and set the link weight in both directions. However, you can also set the link weight in the opposite direction by writingDST -> SRC: WEIGHT
. -
sessions
: An enumeration of all BGP sessions in the network. Each session is written asSRC -> DST[: TYPE]
, where bothSRC
andDST
are identifiers of a node. TheTYPE
is optiona, and can be omitted. If the type is omitted, then it will be aBgpSessionType::IBgpPeer
for internal sessions, andBgpSessionType::EBgp
for external sessions. TheTYPE
can be one of the following identifiers:ebgp
, which maps toBgpSessionType::EBgp
,peer
, which maps toBgpSessionType::IBgpPeer
,client
, which maps toBgpSessionType::IBgpClient
.
This macro will automatically add links between nodes for external sessions if they are not already defined in
links
. -
routes
: An enumeration of all BGP announcements from external routers. Each announcement is written asSRC -> PREFIX as {path: P, [med: M], [communities: C]}
. The symbols mean the following:SRC
is the external router that announces the prefix.PREFIX
is the prefix that should be announced. The prefix can either be a number, a string containing an IP prefix (seeprefix!
), or an identifier of a local variable that was already defined earlier.P
is the AS path and is required. It can be either a single number (which will be turned into a path of length 1), an array of numbers representing the path, or any other arbitrary expression that evaluates toimpl Iterator<Item = I> where I: Into<AsId>
.M
is the MED value but is optional. If omitted, then the MED value will not be set in the announcement.M
must be either a number, or an expression that evaluates toOption<u32>
.C
is the set of communities present in the route, and is optional. Similar toP
, it can also either take a single number, an array of numbers, or any other arbitrary expression that evaluates toimpl Iterator<Item = I> where I: Into<u32>
.
-
Prefix
: The type of the prefix. Choose eitherSinglePrefix
,SimplePrefix
, orIpv4Prefix
here (optional). -
Queue
: The type of the queue (optional). -
queue
: The expression to create the empty queue. If no queue is provided, then the expanded macro will useDefault::default()
. -
return
: A nested tuple of identifiers that referr to previously defined nodes.
§Defining external routers
Every node identifier can also be written like a macro invocation by appending a !(AS_ID)
,
where AS_ID
is a literal number. In that case, this node will be trned into an external router
that uses the given AS number. You only need to annotate an external router once!
§Example
use bgpsim::prelude::*;
let (net, ((b0, b1), (e0, e1))) = net! {
Prefix = Ipv4Prefix;
links = {
b0 -> r0: 1;
r0 -> r1: 1;
r1 -> b1: 1;
};
sessions = {
b1 -> e1!(1);
b0 -> e0!(2);
r0 -> r1: peer;
r0 -> b0: client;
r1 -> b1: client;
};
routes = {
e0 -> "10.0.0.0/8" as {path: [1, 3, 4], med: 100, community: 20};
e1 -> "10.0.0.0/8" as {path: [2, 4]};
};
return ((b0, b1), (e0, e1))
};
This example will be expanded into the following code. This code was cleaned-up, so the different parts can be seen better.
use bgpsim::prelude::*;
// these imports are added for compactness
use ipnet::Ipv4Net;
use std::net::Ipv4Addr;
let (_net, ((b0, b1), (e0, e1))) = {
let mut _net: Network<Ipv4Prefix, _> = Network::new(BasicEventQueue::default());
let b0 = _net.add_router("b0");
let b1 = _net.add_router("b1");
let r0 = _net.add_router("r0");
let r1 = _net.add_router("r1");
let e0 = _net.add_external_router("e0", 2u32);
let e1 = _net.add_external_router("e1", 1u32);
_net.add_link(b0, r0);
_net.add_link(r1, b1);
_net.add_link(r0, r1);
_net.add_link(b1, e1);
_net.add_link(b0, e0);
_net.set_link_weight(b0, r0, 1f64).unwrap();
_net.set_link_weight(r0, b0, 1f64).unwrap();
_net.set_link_weight(r1, b1, 1f64).unwrap();
_net.set_link_weight(b1, r1, 1f64).unwrap();
_net.set_link_weight(r0, r1, 1f64).unwrap();
_net.set_link_weight(r1, r0, 1f64).unwrap();
_net.set_bgp_session(b0, e0, Some(BgpSessionType::EBgp)).unwrap();
_net.set_bgp_session(r1, b1, Some(BgpSessionType::IBgpClient)).unwrap();
_net.set_bgp_session(r0, r1, Some(BgpSessionType::IBgpPeer)).unwrap();
_net.set_bgp_session(b1, e1, Some(BgpSessionType::EBgp)).unwrap();
_net.set_bgp_session(r0, b0, Some(BgpSessionType::IBgpClient)).unwrap();
_net.advertise_external_route(
e0,
Ipv4Net::new(Ipv4Addr::new(10, 0, 0, 0),8).unwrap(),
[1, 3, 4],
Some(100),
[20],
).unwrap();
_net.advertise_external_route(
e1,
Ipv4Net::new(Ipv4Addr::new(10, 0, 0, 0),8).unwrap(),
[2, 4],
None,
[],
).unwrap();
(_net, ((b0, b1), (e0, e1)))
};
§Order or assigned Router-IDs
The router-IDs are assigned in order of their first occurrence. The first named router will be
assigned id 0, the second 1, and so on. The first occurrence must not necessarily be in the
routers
block, but it also includes the mentioning of a router in a link or BGP session. Here
is an example:
use bgpsim::prelude::*;
let (net, ((b0, b1), (r0, r1), (e0, e1))) = net! {
Prefix = Ipv4Prefix;
links = {
b0 -> r0: 1;
r0 -> r1: 1;
r1 -> b1: 1;
};
sessions = {
b1 -> e1!(1);
b0 -> e0!(2);
r0 -> r1: peer;
r0 -> b0: client;
r1 -> b1: client;
};
routes = {
e0 -> "10.0.0.0/8" as {path: [1, 3, 4], med: 100, community: 20};
e1 -> "10.0.0.0/8" as {path: [2, 4]};
};
return ((b0, b1), (r0, r1), (e0, e1))
};
assert_eq!(b0.index(), 0);
assert_eq!(r0.index(), 1);
assert_eq!(r1.index(), 2);
assert_eq!(b1.index(), 3);
assert_eq!(e1.index(), 4);
assert_eq!(e0.index(), 5);