Configuring daemons

We can add daemons to the routers 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(MyTopology, self).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 three helper functions:

  • bgp_fullmesh(topo, routers): Establish a full-mesh set of BGP peerings between routers
  • bgp_peering(topo, r1, r2): Register a BGP peering between two routers
  • ebgp_session(topo, r1, r2): Register an eBGP peering between two routers, and disable IGP adjacencies between them

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

class MyTopology(IPTopo):

    def build(self, *args, **kwargs):

        # AS1 routers
        as1r1 = self.addRouter("as1r1", config=RouterConfig)
        as1r1.addDaemon(BGP)
        as1r2 = self.addRouter("as1r2", config=RouterConfig)
        as1r2.addDaemon(BGP)
        as1r3 = self.addRouter("as1r3", config=RouterConfig)
        as1r3.addDaemon(BGP)

        self.addLink(as1r1, as1r2)
        self.addLink(as1r1, as1r3)
        self.addLink(as1r2, as1r3)

        # AS2 routers
        as2r1 = self.addRouter("as2r1", config=RouterConfig)
        as2r1.addDaemon(BGP)
        as2r2 = self.addRouter("as2r2", config=RouterConfig)
        as2r2.addDaemon(BGP)
        as2r3 = self.addRouter("as2r3", config=RouterConfig)
        as2r3.addDaemon(BGP)

        self.addLink(as2r1, as2r2)
        self.addLink(as2r1, as2r3)
        self.addLink(as2r2, as2r3)

        # AS3 routers
        as3r1 = self.addRouter("as3r1", config=RouterConfig)
        as3r1.addDaemon(BGP)
        as3r2 = self.addRouter("as3r2", config=RouterConfig)
        as3r2.addDaemon(BGP)
        as3r3 = self.addRouter("as3r3", config=RouterConfig)
        as3r3.addDaemon(BGP)

        self.addLink(as3r1, as3r2)
        self.addLink(as3r1, as3r3)
        self.addLink(as3r2, as3r3)

        # Inter-AS links
        self.addLink(as1r1, as2r1)
        self.addLink(as2r3, as3r1)

        # 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(MyTopology, self).build(*args, **kwargs)

IPTables

This is currently mainly a proxy class to generate a list of static rules to pass to iptables. As such, see man iptables and man iptables-extensions to see the various table names, commands, pre-existing chains, …

It takes one parameter:

IPTables.set_defaults(defaults)
Parameters:rules – The (ordered) list of iptables rules that should be executed. If a rule is an iterable of strings, these will be joined using a space.

IP6Tables

This class is the IPv6 equivalent to IPTables.

It also takes one parameter:

IP6Tables.set_defaults(defaults)
Parameters:rules – The (ordered) list of iptables rules that should be executed. 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 – Experinmental 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. Cruical 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 = self.addRouter("router1")
        router2 = self.addRouter("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(MyTopology, self).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 = self.addRouter("r1")
        r2 = self.addRouter("r2")
        r3 = self.addRouter("r3")

        # Add links
        self.addLink(r1, r2)
        self.addLink(r1, r3)
        self.addLink(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(MyTopology, self).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 = self.addRouter("router1")
        router2 = self.addRouter("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(MyTopology, self).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

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(MyTopology, self).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(MyTopology, self).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