Configuring daemons¶
We can add daemons to the routers or hosts and pass options to them. In the following code snippet, we add BGP daemon to r1.
from ipmininet.iptopo import IPTopo
from ipmininet.router.config import OSPF, OSPF6, RouterConfig
class MyTopology(IPTopo):
def build(self, *args, **kwargs):
r1 = self.addRouter("r1", config=RouterConfig)
r1.addDaemon(OSPF, hello_int=1)
r1.addDaemon(OSPF6, hello_int=1)
# [...]
super().build(*args, **kwargs)
This page presents how to configure each daemon.
BGP¶
When adding BGP to a router with router.addDaemon(BGP, **kargs)
, we change the following default parameters:
-
BGP.
set_defaults
(defaults) Parameters: - debug – the set of debug events that should be logged
- address_families – The set of AddressFamily to use
We can declare a set of routers in the same AS by using the overlay AS:
The overlay iBGPFullMesh extends the AS class and allows us to establish iBGP sessions in full mesh between BGP routers.
There are also some helper functions:
-
BGPConfig.
set_local_pref
(local_pref: int, from_peer: str, matching: Sequence[Union[ipmininet.router.config.zebra.AccessList, ipmininet.router.config.zebra.CommunityList]] = ()) → ipmininet.router.config.bgp.BGPConfig - Set local pref on a peering with ‘from_peer’ on routes
- matching all of the access and community lists in ‘matching’
Parameters: - local_pref – The local pref value to set
- from_peer – The peer on which the local pref is applied
- matching – A list of AccessList and/or CommunityList
Returns: self
-
BGPConfig.
set_med
(med: int, to_peer: str, matching: Sequence[Union[ipmininet.router.config.zebra.AccessList, ipmininet.router.config.zebra.CommunityList]] = ()) → ipmininet.router.config.bgp.BGPConfig - Set MED on a peering with ‘to_peer’ on routes
- matching all of the access and community lists in ‘matching’
Parameters: - med – The local pref value to set
- to_peer – The peer to which the med is applied
- matching – A list of AccessList and/or CommunityList
Returns: self
-
BGPConfig.
set_community
(community: Union[str, int], from_peer: Optional[str] = None, to_peer: Optional[str] = None, matching: Sequence[Union[ipmininet.router.config.zebra.AccessList, ipmininet.router.config.zebra.CommunityList]] = ()) → ipmininet.router.config.bgp.BGPConfig - Set community on a routes received from ‘from_peer’
- and routes sent to ‘to_peer’ on routes matching all of the access and community lists in ‘matching’
Parameters: - community – The community value to set
- from_peer – The peer on which received routes have to have the community
- to_peer – The peer on which sent routes have to have the community
- matching – A list of AccessList and/or CommunityList
Returns: self
-
BGPConfig.
deny
(name: Optional[str] = None, from_peer: Optional[str] = None, to_peer: Optional[str] = None, matching: Sequence[Union[ipmininet.router.config.zebra.AccessList, ipmininet.router.config.zebra.CommunityList]] = (), order=10) → ipmininet.router.config.bgp.BGPConfig - Deny all routes received from ‘from_peer’
- and routes sent to ‘to_peer’ matching all of the access and community lists in ‘matching’
Parameters: - name – The name of the route-map
- from_peer – The peer on which received routes have to have the community
- to_peer – The peer on which sent routes have to have the community
- matching – A list of AccessList and/or CommunityList
- order – The order in which route-maps are applied, i.e., lower order means applied before
Returns: self
-
BGPConfig.
permit
(name: Optional[str] = None, from_peer: Optional[str] = None, to_peer: Optional[str] = None, matching: Sequence[Union[ipmininet.router.config.zebra.AccessList, ipmininet.router.config.zebra.CommunityList]] = (), order=10) → ipmininet.router.config.bgp.BGPConfig - Accept all routes received from ‘from_peer’
- and routes sent to ‘to_peer’ matching all of the access and community lists in ‘matching’
Parameters: - name – The name of the route-map
- from_peer – The peer on which received routes have to have the community
- to_peer – The peer on which sent routes have to have the community
- matching – A list of AccessList and/or CommunityList
- order – The order in which route-maps are applied, i.e., lower order means applied before
Returns: self
-
bgp.
bgp_fullmesh
(routers: Sequence[str]) Establish a full-mesh set of BGP peerings between routers
Parameters: - topo – The current topology
- routers – The set of routers peering within each other
-
bgp.
bgp_peering
(a: str, b: str) Register a BGP peering between two nodes
-
bgp.
ebgp_session
(a: RouterDescription, b: RouterDescription, link_type: Optional[str] = None) Register an eBGP peering between two nodes, and disable IGP adjacencies between them.
Parameters: - topo – The current topology
- a – Local router
- b – Peer router
- link_type – Can be set to SHARE or CLIENT_PROVIDER. In this case ebgp_session will create import and export filter and set local pref based on the link type
-
bgp.
set_rr
(rr: str, peers: Sequence[str] = ()) Set rr as route reflector for all router r
Parameters: - topo – The current topology
- rr – The route reflector
- peers – Clients of the route reflector
The following code shows how to use all these abstractions:
from ipmininet.iptopo import IPTopo
from ipmininet.router.config import BGP, bgp_fullmesh, bgp_peering, \
ebgp_session, RouterConfig, AccessList, CommunityList
class MyTopology(IPTopo):
def build(self, *args, **kwargs):
# AS1 routers
as1r1, as1r2, as1r3 = self.addRouters("as1r1", "as1r2", "as1r3",
config=RouterConfig)
as1r1.addDaemon(BGP)
as1r2.addDaemon(BGP)
as1r3.addDaemon(BGP)
self.addLinks((as1r1, as1r2), (as1r1, as1r3), (as1r2, as1r3))
# AS2 routers
as2r1, as2r2, as2r3 = self.addRouters("as2r1", "as2r2", "as2r3",
config=RouterConfig)
as2r1.addDaemon(BGP)
as2r2.addDaemon(BGP)
as2r3.addDaemon(BGP)
self.addLinks((as2r1, as2r2), (as2r1, as2r3), (as2r2, as2r3))
# AS3 routers
as3r1, as3r2, as3r3 = self.addRouters("as3r1", "as3r2", "as3r3",
config=RouterConfig)
as3r1.addDaemon(BGP)
as3r2.addDaemon(BGP)
as3r3.addDaemon(BGP)
self.addLinks((as3r1, as3r2), (as3r1, as3r3), (as3r2, as3r3))
# Inter-AS links
self.addLinks((as1r1, as2r1), (as2r3, as3r1))
# Add an access list to 'any'
# This can be an IP prefix or address instead
all_al = AccessList('all', ('any',))
# Add a community list to as2r1
loc_pref = CommunityList('loc-pref', '2:80')
# as2r1 set the local pref of all the route coming from as1r1 and matching the community list community to 80
as2r1.get_config(BGP).set_local_pref(80, from_peer=as1r1, matching=(loc_pref,))
# as1r1 set the community of all the route sent to as2r1 and matching the access list all_al to 2:80
as1r1.get_config(BGP).set_community('2:80', to_peer=as2r1, matching=(all_al,))
# as3r1 set the med of all the route coming from as2r3 and matching the access list all_al to 50
as3r1.get_config(BGP).set_med(50, to_peer=as2r3, matching=(all_al,))
# AS1 is composed of 3 routers that have a full-mesh set of iBGP peering between them
self.addiBGPFullMesh(1, routers=[as1r1, as1r2, as1r3])
# AS2 only has one iBGP session between its routers
self.addAS(2, routers=[as2r1, as2r2, as2r3])
bgp_peering(self, as2r1, as2r3)
# AS3 is also composed of 3 routers that have a full-mesh set of iBGP peering between them
self.addAS(3, routers=[as3r1, as3r2, as3r3])
bgp_fullmesh(self, [as3r1, as3r2, as3r3])
# Establish eBGP sessions between ASes
ebgp_session(self, as1r1, as2r1)
ebgp_session(self, as2r3, as3r1)
super().build(*args, **kwargs)
IPTables¶
This is currently mainly a proxy class to generate a list of static rules to pass to iptables.
It takes one parameter:
-
IPTables.
set_defaults
(defaults) Parameters: rules – The (ordered) list of iptables Rules that should be executed or the list of Chain objects each containing rules. If a rule is an iterable of strings, these will be joined using a space.
These rules can be Rule objects with raw iptables command As such, see man iptables and man iptables-extensions to see the various table names, commands, pre-existing chains, …
-
class
ipmininet.router.config.iptables.
Rule
(*args, **kw) A Simple wrapper to represent an IPTable rule
Parameters: - args – the rule members, which will joined by a whitespace
- table – Specify the table in which the rule should be installed. Defaults to filter.
In this example, only ICMP traffic will be allowed between the routers over IPv4 as well as non-privileged TCP ports:
from ipmininet.iptopo import IPTopo
from ipmininet.router.config import IPTables, Rule
class MyTopology(IPTopo):
def build(self, *args, **kwargs):
r1 = self.addRouter('r1')
r2 = self.addRouter('r2')
self.addLink(r1, r2)
ip_rules = [Rule("-P INPUT DROP"),
Rule("-A INPUT -p tcp -m multiport --ports 80:1024 -j "
"DROP"),
Rule("-A INPUT -p tcp -m multiport ! --ports 1480 -j "
"ACCEPT"),
Rule("-A INPUT -p icmp -j ACCEPT")]
r1.addDaemon(IPTables, rules=ip_rules)
r2.addDaemon(IPTables, rules=ip_rules)
super().build(*args, **kwargs)
You can use other classes for better abstraction. You can use the Chain class or one of its subclasses:
-
class
ipmininet.router.config.iptables.
Chain
(table='filter', name='INPUT', default='DROP', rules=()) Chains are the hooks location for the respective tables. Tables support a limited subset of the available chains, see man iptables.
Build a chain description. For convenience, most parameters have more intuitive aliases than their one-letter CLI params.
Params table: The table on which the chain applies. Params name: The chain name Params default: The default verdict if nothing matches Params rules: The ordered list of ChainRule to apply
-
class
ipmininet.router.config.iptables.
Filter
(**kwargs) The filter table acts as inbound, outbound, and forwarding firewall.
-
class
ipmininet.router.config.iptables.
InputFilter
(**kwargs) The inbound firewall.
-
class
ipmininet.router.config.iptables.
OutputFilter
(**kwargs) The outbound firewall.
-
class
ipmininet.router.config.iptables.
TransitFilter
(**kwargs) The forward firewall.
Each rule in the Chain instance is a ChainRule that you can use directly or use one of its subclasses:
-
class
ipmininet.router.config.iptables.
ChainRule
(action='DROP', **kwargs) Describe one set of matching criteria and the corresponding action when embedded in a chain.
Params action: The action to perform on matching packets. Params oif: match in the output interface (optional) Params iif: match on the input interface (optional) Params src: match on the source address/network (optional) Params dst: match on the destination address/network (optional) Params proto: match on the protocol name/number (optional) Params match: additional matching clauses, per man iptables (optional) Params port: match on the source or destination port number/range (optional) Params sport: match on the source port number/range/name (optional) Params dport: match on the destination port number/range/name (optional)
-
class
ipmininet.router.config.iptables.
Allow
(**kwargs) Shorthand for ChainRule(action=’ACCEPT’, …). Expresses a whitelisting rule.
-
class
ipmininet.router.config.iptables.
Deny
(**kwargs) Shorthand for ChainRule(action=’DROP’, …). Expresses a blacklisting rule.
Each input value used for matching in ChainRule constructor can be negated with the NOT class:
-
class
ipmininet.router.config.iptables.
NOT
(clause) Negates the match clause :param clause: The value of the match clause to negate
This example implements the same properties as the previous one with the API.
from ipmininet.iptopo import IPTopo
from ipmininet.router.config import IPTables, InputFilter, NOT, \
Deny, Allow
class MyTopology(IPTopo):
def build(self, *args, **kwargs):
r1 = self.addRouter('r1')
r2 = self.addRouter('r2')
self.addLink(r1, r2)
ip_rules = [InputFilter(default="DROP", rules=[
Deny(proto='tcp', port='80:1024'),
Allow(proto='tcp', port=NOT(1480)),
Allow(proto='icmp'),
])]
r1.addDaemon(IPTables, rules=ip_rules)
r2.addDaemon(IPTables, rules=ip_rules)
super().build(*args, **kwargs)
IP6Tables¶
This class is the IPv6 equivalent to IPTables.
It also takes the same parameter (see previous section for details):
-
IP6Tables.
set_defaults
(defaults) Parameters: rules – The (ordered) list of iptables Rules that should be executed or the list of Chain objects each containing rules. If a rule is an iterable of strings, these will be joined using a space.
OpenR¶
The OpenR daemon can be tuned by adding keyword arguments to router.addDaemon(OpenR, **kargs)
.
Here is a list of the parameters:
-
OpenrDaemon.
_defaults
(**kwargs) Default parameters of the OpenR daemon. The template file openr.mako sets the default parameters listed here. See: https://github.com/facebook/openr/blob/master/openr/docs/Runbook.md.
Parameters: - alloc_prefix_len – Block size of allocated prefix in terms of it’s prefix length. In this case ‘/80’ prefix will be elected for a node. e.g. ‘face:b00c:0:0:1234::/80’. Default: 128.
- assume_drained – Default: False.
- config_store_filepath – Default: /tmp/aq_persistent_config_store.bin
- decision_debounce_max_ms – Knobs to control how often to run Decision. On receipt of first even debounce is created with MIN time which grows exponentially up to max if there are more events before debounce is executed. This helps us to react to single network failures quickly enough (with min duration) while avoid high CPU utilization under heavy network churn. Default: 250.
- decision_debounce_min_ms – Knobs to control how often to run Decision. On receipt of first even debounce is created with MIN time which grows exponentially up to max if there are more events before debounce is executed. This helps us to react to single network failures quickly enough (with min duration) while avoid high CPU utilization under heavy network churn. Default: 10.
- decision_rep_port – Default: 60004.
- domain – Name of domain this node is part of. OpenR will ‘only’ form adjacencies to OpenR instances within it’s own domain. This option becomes very useful if you want to run OpenR on two nodes adjacent to each other but belonging to different domains, e.g. Data Center and Wide Area Network. Usually it should depict the Network. Default: openr.
- dryrun – OpenR will not try to program routes in it’s default configuration. You should explicitly set this option to false to proceed with route programming. Default: False.
- enable_subnet_validation – OpenR supports subnet validation to avoid mis-cabling of v4 addresses on different subnets on each end of the link. Need to enable v4 and this flag at the same time to turn on validation. Default: True.
- enable_fib_sync – Default: False.
- enable_health_checker – OpenR can measure network health internally by pinging other nodes in the network and exports this information as counters or via breeze APIs. By default health checker is disabled. The expectation is that each node must have at least one v6 loopback addressed announced into the network for the reachability check. Default: False.
- enable_legacy_flooding – Default: True.
- enable_lfa – With this option, additional Loop-Free Alternate (LFA) routes can be computed, per RFC 5286, for fast failure recovery. Under the failure of all primary nexthops for a prefix, because of link failure, next best precomputed LFA will be used without need of an SPF run. Default: False.
- enable_netlink_fib_handler – Knob to enable/disable default implementation of ‘FibService’ that comes along with OpenR for Linux platform. If you want to run your own FIB service then disable this option. Default: True.
- enable_netlink_system_handler – Knob to enable/disable default implementation of ‘SystemService’ and ‘PlatformPublisher’ that comes along with OpenR for Linux platform. If you want to run your own SystemService then disable this option. Default: True.
- enable_perf_measurement – Experimental feature to measure convergence performance. Performance information can be viewed via breeze API ‘breeze perf fib’. Default: True.
- enable_prefix_alloc – Enable prefix allocator to elect and assign a unique prefix for the node. You will need to specify other configuration parameters below. Default: False.
- enable_rtt_metric – Default mechanism for cost of a link is ‘1’ and hence cost of path is hop count. With this option you can ask OpenR to compute and use RTT of a link as a metric value. You should only use this for networks where links have significant delay, on the order of a couple of milliseconds. Using this for point-to-point links will cause lot of churn in metric updates as measured RTT will fluctuate a lot because of packet processing overhead. RTT is measured at application level and hence the fluctuation for point-to-point links. Default: True.
- enable_secure_thrift_server – Flag to enable TLS for our thrift server. Disable this for plaintext thrift. Default: False.
- enable_segment_routing – Experimental and partially implemented segment routing feature. As of now it only elects node/adjacency labels. In future we will extend it to compute and program FIB routes. Default: False.
- enable_spark – Default: True.
- enable_v4 – OpenR supports v4 as well but it needs to be turned on explicitly. It is expected that each interface will have v4 address configured for link local transport and v4/v6 topologies are congruent. Default: False.
- enable_watchdog – Default: True.
- fib_handler_port – TCP port on which ‘FibService’ will be listening. Default: 60100.
- fib_rep_port – Default: 60009.
- health_checker_ping_interval_s – Configure ping interval of the health checker. The below option configures it to ping all other nodes every 3 seconds. Default: 3.
- health_checker_rep_port – Default: 60012.
- ifname_prefix – Interface prefixes to perform neighbor discovery on. All interfaces whose names start with these are used for neighbor discovery. Default: “”
- iface_regex_exclude – Default:”“.
- iface_regex_include – Default: “”.
- ip_tos – Set type of service (TOS) value with which every control plane packet from Open/R will be marked with. This marking can be used to prioritize control plane traffic (as compared to data plane) so that congestion in network doesn’t affect operations of Open/R. Default: 192
- key_prefix_filters – This comma separated string is used to set the key prefixes when key prefix filter is enabled (See SET_LEAF_NODE). It is also set when requesting KEY_DUMP from peer to request keys that match one of these prefixes. Default: “”.
- kvstore_flood_msg_per_sec – Default: 0.
- kvstore_flood_msg_burst_size – Default: 0.
- kvstore_flood_msg_per_sec – Default: 0.
- kvstore_ttl_decrement_ms – Default: 1.
- kvstore_zmq_hwm – Set buffering size for KvStore socket communication. Updates to neighbor node during flooding can be buffered upto this number. For larger networks where burst of updates can be high having high value makes sense. For smaller networks where burst of updates are low, having low value makes more sense. Default: 65536.
- link_flap_initial_backoff_ms – Default: 1000.
- link_flap_max_backoff_ms – Default: 60000.
- link_monitor_cmd_port – Default: 60006.
- loopback_iface – Indicates loopback address to which auto elected prefix will be assigned if enabled. Default: “lo”.
- memory_limit_mb – Enforce upper limit on amount of memory in mega-bytes that open/r process can use. Above this limit watchdog thread will trigger crash. Service can be auto-restarted via system or some kind of service manager. This is very useful to guarantee protocol doesn’t cause trouble to other services on device where it runs and takes care of slow memory leak kind of issues. Default: 300.
- minloglevel – Log messages at or above this level. Again, the numbers of severity levels INFO, WARNING, ERROR, and FATAL are 0, 1, 2, and 3, respectively. Default: 0.
- node_name – Name of the OpenR node. Crucial setting if you run multiple nodes. Default: “”.
- override_loopback_addr – Whenever new address is elected for a node, before assigning it to interface all previously allocated prefixes or other global prefixes will be overridden with the new one. Use it with care! Default: False.
- prefix_manager_cmd_port – Default: 60011.
- prefixes – Static list of comma separate prefixes to announce from the current node. Can’t be changed while running. Default: “”.
- redistribute_ifaces – Comma separated list of interface names whose ‘/32’ (for v4) and ‘/128’ (for v6) should be announced. OpenR will monitor address add/remove activity on this interface and announce it to rest of the network. Default: “lo1”.
- seed_prefix – In order to elect a prefix for the node a super prefix to elect from is required. This is only applicable when ‘ENABLE_PREFIX_ALLOC’ is set to true. Default: “”.
- set_leaf_node – Sometimes a node maybe a leaf node and have only one path in to network. This node does not require to keep track of the entire topology. In this case, it may be useful to optimize memory by reducing the amount of key/vals tracked by the node. Setting this flag enables key prefix filters defined by KEY_PREFIX_FILTERS. A node only tracks keys in kvstore that matches one of the prefixes in KEY_PREFIX_FILTERS. Default: False.
- set_loopback_address – If set to true along with ‘ENABLE_PREFIX_ALLOC’ then second valid IP address of the block will be assigned onto ‘LOOPBACK_IFACE’ interface. e.g. in this case ‘face:b00c:0:0:1234::1/80’ will be assigned on ‘lo’ interface. Default: False.
- spark_fastinit_keepalive_time_ms – When interface is detected UP, OpenR can perform fast initial neighbor discovery as opposed to slower keep alive packets. Default value is 100 which means neighbor will be discovered within 200ms on a link. Default: 100.
- spark_hold_time_s – Hold time indicating time in seconds from it’s last hello after which neighbor will be declared as down. Default: 30.
- spark_keepalive_time_s – How often to send spark hello messages to neighbors. Default: 3.
- static_prefix_alloc – Default: False.
- tls_acceptable_peers – A comma separated list of strings. Strings are x509 common names to accept SSL connections from. Default: “”
- tls_ecc_curve_name – If we are running an SSL thrift server, this option specifies the eccCurveName for the associated wangle::SSLContextConfig. Default: “prime256v1”.
- tls_ticket_seed_path – If we are running an SSL thrift server, this option specifies the TLS ticket seed file path to use for client session resumption. Default: “”.
- x509_ca_path – If we are running an SSL thrift server, this option specifies the certificate authority path for verifying peers. Default: “”.
- x509_cert_path – If we are running an SSL thrift server, this option specifies the certificate path for the associated wangle::SSLContextConfig. Default: “”.
- x509_key_path – If we are running an SSL thrift server, this option specifies the key path for the associated wangle::SSLContextConfig. Default: “”.
- logbufsecs – Default: 0
- log_dir – Directory to store log files at. The folder must exist. Default: /var/log.
- max_log_size – Default: 1.
- v – Show all verbose ‘VLOG(m)’ messages for m less or equal the value of this flag. Use higher value for more verbose logging. Default: 1.
OSPF¶
You can add keyword arguments to router.addDaemon(OSPF, **kargs)
to change the following parameters:
-
OSPF.
set_defaults
(defaults) Parameters: - debug – the set of debug events that should be logged
- dead_int – Dead interval timer
- hello_int – Hello interval timer
- priority – priority for the interface, used for DR election
- redistribute – set of OSPFRedistributedRoute sources
This daemon also uses the following interface parameters:
- igp_passive: Whether the interface is passive (default value: False)
- ospf_dead_int: Dead interval timer specific to this interface (default value:
dead_int
parameter) - ospf_hello_int: Hello interval timer specific to this interface (default value:
hello_int
parameter) - ospf_priority: Priority for this specific to this interface (default value:
priority
parameter)
OSPF uses two link parameters:
- igp_cost: The IGP cost of the link (default value: 1)
- igp_area: The OSPF area of the link (default value: ‘0.0.0.0’)
We can pass parameters to links and interfaces when calling addLink()
:
from ipmininet.iptopo import IPTopo
class MyTopology(IPTopo):
def build(self, *args, **kwargs):
# Add routers (OSPF daemon is added by default with the default config)
router1, router2 = self.addRouters("router1", "router2")
# Add link
l = self.addLink(router1, router2,
igp_cost=5, igp_area="0.0.0.1") # Link parameters
l[router1].addParams(ospf_dead_int=1) # Router1 interface parameters
l[router2].addParams(ospf_priority=1) # Router2 interface parameters
super().build(*args, **kwargs)
OSPF can use an overlay to declare with routers or links are completely in a given OSPF area. The following code adds all the interfaces of router r1 to ‘0.0.0.1’ while the link between r2 and r3 is in area ‘0.0.0.5’:
from ipmininet.iptopo import IPTopo
class MyTopology(IPTopo):
def build(self, *args, **kwargs):
# Add routers (OSPF daemon is added by default with the default config)
r1, r2, r3 = self.addRouters("r1", "r2", "r3")
# Add links
self.addLinks((r1, r2), (r1, r3), (r2, r3))
# Define OSPF areas
self.addOSPFArea('0.0.0.1', routers=[r1], links=[])
self.addOSPFArea('0.0.0.5', routers=[], links=[(r2, r3)])
super().build(*args, **kwargs)
OSPF6¶
OSPF6 supports the same parameters as OSPF. It supports the following parameter:
-
OSPF6.
set_defaults
(defaults) Parameters: - debug – the set of debug events that should be logged
- dead_int – Dead interval timer
- hello_int – Hello interval timer
- priority – priority for the interface, used for DR election
- redistribute – set of OSPFRedistributedRoute sources
- instance_id – the number of the attached OSPF instance
OSPF6 uses one link parameter:
- igp_cost: The IGP cost of the link (default value: 1)
It uses the following interface parameters:
- igp_passive: Whether the interface is passive (default value: False)
- instance_id: The number of the attached OSPF6 instance (default value: 0)
- ospf6_dead_int: Dead interval timer specific to this interface (default value:
ospf_dead_int
parameter) - ospf6_hello_int: Hello interval timer specific to this interface (default value:
ospf_hello_int
parameter) - ospf6_priority: Priority for this specific to this interface (default value:
ospf_priority
parameter)
from ipmininet.iptopo import IPTopo
class MyTopology(IPTopo):
def build(self, *args, **kwargs):
# Add routers (OSPF daemon is added by default with the default config)
router1, router2 = self.addRouters("router1", "router2")
# Add link
l = self.addLink(router1, router2,
igp_cost=5) # Link parameters
l[router1].addParams(ospf6_dead_int=1) # Router1 interface parameters
l[router2].addParams(ospf6_priority=1) # Router2 interface parameters
super().build(*args, **kwargs)
PIMD¶
When adding PIMD to a router with router.addDaemon(PIMD, **kargs)
, we can give the following parameters:
-
PIMD.
set_defaults
(defaults) Parameters: - debug – the set of debug events that should be logged
- multicast_ssm – Enable pim ssm mode by default or not
- multicast_igmp – Enable igmp by default or not
Named¶
When adding PIMD to a host with host.addDaemon(Named, **kargs)
, we can give the following parameters:
-
Named.
set_defaults
(defaults) Parameters: - log_severity – It controls the logging levels and may take the values defined. Logging will occur for any message equal to or higher than the level specified (=>) lower levels will not be logged. These levels are ‘critical’, ‘error’, ‘warning’, ‘notice’, ‘info’, ‘debug’ and ‘dynamic’.
- dns_server_port – The port number of the dns server
- hint_root_zone – Add hints to root dns servers if this is not the root server
Named uses an overlay to declare DNS zones:
-
DNSZone.
__init__
(name: str, dns_master: str, dns_slaves: Sequence[str] = (), records: Sequence[ipmininet.host.config.named.DNSRecord] = (), nodes: Sequence[str] = (), refresh_time=86400, retry_time=7200, expire_time=3600000, min_ttl=172800, ns_domain_name: Optional[str] = None, subdomain_delegation=True, delegated_zones: Sequence[DNSZone] = ()) Parameters: - name – The domain name of the zone
- dns_master – The name of the master DNS server
- dns_slaves – The list of names of DNS slaves
- records – The list of DNS Records to be included in the zone
- nodes – The list of nodes for which one A/AAAA record has to be created for each of their IPv4/IPv6 addresses
- refresh_time – The number of seconds before the zone should be refreshed
- retry_time – The number of seconds before a failed refresh should be retried
- expire_time – The upper limit in seconds before a zone is considered no longer authoritative
- min_ttl – The negative result TTL
- ns_domain_name – If it is defined, it is the suffix of the domain of the name servers, otherwise, parameter ‘name’ is used.
- subdomain_delegation – If set, additional records for subdomain name servers are added to guarantee correct delegation
- delegated_zones – Additional delegated zones
The following code will create a DNS server in dns_master and dns_slave with one DNS zone: ‘mydomain.org’. This will also create one reverse DNS zones for both IPv4 and IPv6.
from ipmininet.iptopo import IPTopo
from ipmininet.host.config import Named
class MyTopology(IPTopo):
def build(self, *args, **kwargs):
# Add router
r = self.addRouter("r")
# Add hosts
h1 = self.addHost("h1")
h2 = self.addHost("h2")
h3 = self.addHost("h3")
dns_master = self.addHost("dns_master")
dns_master.addDaemon(Named)
dns_slave = self.addHost("dns_slave")
dns_slave.addDaemon(Named)
# Add links
for h in self.hosts():
self.addLink(r, h)
# Define a DNS Zone
self.addDNSZone(name="mydomain.org",
dns_master=dns_master,
dns_slaves=[dns_slave],
nodes=self.hosts())
super().build(*args, **kwargs)
By default, the DNSZone will create all the NS, A and AAAA records. If you need to change the TTL of one of these record, you can define it explicitly.
from ipmininet.iptopo import IPTopo
from ipmininet.host.config import Named, NSRecord
class MyTopology(IPTopo):
def build(self, *args, **kwargs):
# Add router
r = self.addRouter("r")
# Add hosts
h1 = self.addHost("h1")
h2 = self.addHost("h2")
h3 = self.addHost("h3")
dns_master = self.addHost("dns_master")
dns_master.addDaemon(Named)
dns_slave = self.addHost("dns_slave")
dns_slave.addDaemon(Named)
# Add links
for h in self.hosts():
self.addLink(r, h)
# Define a DNS Zone
records = [NSRecord("mydomain.org", dns_master, ttl=120), NSRecord("mydomain.org", dns_slave, ttl=120)]
self.addDNSZone(name="mydomain.org",
dns_master=dns_master,
dns_slaves=[dns_slave],
records=records,
nodes=self.hosts())
super().build(*args, **kwargs)
By default, one reverse DNS zone are created for all A records and another for all AAAA records. However, you may want to split the PTR records more than two different zones. You may also want to change the default values of the zones or their PTR records. To change this, you can declare the reverse DNS zone yourself. No need to add the PTR records that you don’t want to modify, they will be created for you and placed in the zone that you declared if they fit in its domain name. Otherwise, another zone will be created.
from ipmininet.iptopo import IPTopo
from ipmininet.host.config import Named, PTRRecord
from ipaddress import ip_address
class MyTopology(IPTopo):
def build(self, *args, **kwargs):
# Add router
r = self.addRouter("r")
# Add hosts
h1 = self.addHost("h1")
h2 = self.addHost("h2")
h3 = self.addHost("h3")
dns_master = self.addHost("dns_master")
dns_master.addDaemon(Named)
dns_slave = self.addHost("dns_slave")
dns_slave.addDaemon(Named)
# Add links
for h in [h1, h2, dns_master, dns_slave]:
self.addLink(r, h)
lrh3 = self.addLink(r, h3)
self.addSubnet(links=[lrh3], subnets=["192.168.0.0/24", "fc00::/64"])
# Define a DNS Zone
self.addDNSZone(name="mydomain.org",
dns_master=dns_master,
dns_slaves=[dns_slave],
nodes=self.hosts())
# Change the TTL of one PTR record and the retry_time of its zone
ptr_record = PTRRecord("fc00::2", h3 + ".mydomain.org", ttl=120)
reverse_domain_name = ip_address("fc00::").reverse_pointer[-10:] # keeps "f.ip6.arpa"
self.addDNSZone(name=reverse_domain_name, dns_master=dns_master, dns_slaves=[dns_slave],
records=[ptr_record], ns_domain_name="mydomain.org", retry_time=8200)
super().build(*args, **kwargs)
By default, subdomains authority is delegated to the direct child zone name
servers by copying the NS records of the child zone to the parent zone. You can
remove this behavior, by zone, by setting the parameter subdomain_delegation
to False
. You can also delegate more zones by using the delegated_zones
parameter.
By default, all DNS servers that are not root DNS servers have hints to the
root DNS servers (if the root zone is added to the topology). This behavior
can be disabled by setting the parameter hint_root_zone
of Named
to
False
.
RADVD¶
When adding RADVD to a router with router.addDaemon(RADVD, **kargs)
, we can give the following parameters:
-
RADVD.
set_defaults
(defaults) Parameters: debuglevel – Turn on debugging information. Takes an integer between 0 and 5, where 0 completely turns off debugging, and 5 is extremely verbose. (see radvd(8) for more details)
This daemon also uses the following interface parameters:
- ra: A list of AdvPrefix objects that describes the prefixes to advertise
- rdnss: A list of AdvRDNSS objects that describes the DNS servers to advertise
from ipmininet.iptopo import IPTopo
from ipmininet.router.config import RADVD, AdvPrefix, AdvRDNSS
class MyTopology(IPTopo):
def build(self, *args, **kwargs):
r = self.addRouter('r')
r.addDaemon(RADVD, debug=0)
h = self.addHost('h')
dns = self.addHost('dns')
lrh = self.addLink(r, h)
lrh[r].addParams(ip=("2001:1341::1/64", "2001:2141::1/64"),
ra=[AdvPrefix("2001:1341::/64", valid_lifetime=86400, preferred_lifetime=14400),
AdvPrefix("2001:2141::/64")],
rdnss=[AdvRDNSS("2001:89ab::d", max_lifetime=25),
AdvRDNSS("2001:cdef::d", max_lifetime=25)])
lrdns = self.addLink(r, dns)
lrdns[r].addParams(ip=("2001:89ab::1/64", "2001:cdef::1/64")) # Static IP addresses
lrdns[dns].addParams(ip=("2001:89ab::d/64", "2001:cdef::d/64")) # Static IP addresses
super().build(*args, **kwargs)
Instead of giving all addresses explicitly, you can use AdvConnectedPrefix() to advertise all the prefixes of the interface. You can also give the name of the DNS server (instead of an IP address) in the AdvRDNSS constructor.
from ipmininet.iptopo import IPTopo
from ipmininet.router.config import RouterConfig, RADVD, AdvConnectedPrefix, AdvRDNSS
class MyTopology(IPTopo):
def build(self, *args, **kwargs):
r = self.addRouter('r')
r.addDaemon(RADVD, debug=0)
h = self.addHost('h')
dns = self.addHost('dns')
lrh = self.addLink(r, h)
lrh[r].addParams(ip=("2001:1341::1/64", "2001:2141::1/64"),
ra=[AdvConnectedPrefix(valid_lifetime=86400, preferred_lifetime=14400)],
rdnss=[AdvRDNSS(dns, max_lifetime=25)])
lrdns = self.addLink(r, dns)
lrdns[r].addParams(ip=("2001:89ab::1/64", "2001:cdef::1/64")) # Static IP addresses
lrdns[dns].addParams(ip=("2001:89ab::d/64", "2001:cdef::d/64")) # Static IP addresses
super().build(*args, **kwargs)
RIPng¶
When adding RIPng to a router with router.addDaemon(RIPng, **kargs)
, we can give the following parameters:
-
RIPng.
set_defaults
(defaults) Parameters: - debug – the set of debug events that should be logged (default: []).
- redistribute – set of RIPngRedistributedRoute sources (default: []).
- split_horizon – the daemon uses the split-horizon method (default: False).
- split_horizon_with_poison – the daemon uses the split-horizon. with reversed poison method. If both split_horizon_with_poison and split_horizon are set to True, RIPng will use the split-horizon with reversed poison method (default: True).
- update_timer – routing table timer value in second (default value:30).
- timeout_timer – routing information timeout timer (default value:180).
- garbage_timer – garbage collection timer (default value:120).
RIPng uses one link parameter:
- igp_metric: the metric of the link (default value: 1)
We can pass parameters to links when calling addLink():
from ipmininet.iptopo import IPTopo
from ipmininet.router.config import RIPng, RouterConfig
class MyTopology(IPTopo):
def build(self, *args, **kwargs):
# We use RouterConfig to prevent OSPF6 to be run
r1, r2 = self.addRouters("r1", "r2", config=RouterConfig)
h1 = self.addHost("h1")
h2 = self.addHost("h2")
self.addLink(r1, r2, igp_metric=10) # The IGP metric is set to 10
self.addLinks((r1, h1), (r2, h2))
r1.addDaemon(RIPng)
r2.addDaemon(RIPng)
super().build(*args, **kwargs)
SSHd¶
The SSHd daemon does not take any parameter. The SSH private and public keys are randomly generated but you can retrieve their paths with the following line:
from ipmininet.router.config.sshd import KEYFILE, PUBKEY
Zebra¶
FRRouting daemons (i.e., OSPF, OSPF6, BGP and PIMD) require this daemon and automatically trigger it.
So we only need to explicitly add it through router.addDaemon(Zebra, **kargs)
if we want to change one of its parameters:
-
Zebra.
set_defaults
(defaults) Parameters: - debug – the set of debug events that should be logged
- access_lists – The set of AccessList to create, independently from the ones already included by route_maps
- route_maps – The set of RouteMap to create