Source code for tests.router_tree_plugin

import netaddr
from base_objects import Switch
from generic_vm_objects import GenericRouter
from linux.base_objects import LinuxHost

from firewheel.control.experiment_graph import Vertex, AbstractPlugin


[docs] class RouterTree(AbstractPlugin): """This creates a router high-degree tree running OSPF and BGP. Following is an example of a 3 degree tree:: <host> -- <OSPF> -- <BGP> ------------------------- | | | <BGP 0> <BGP 1> <BGP 2> | | | <OSPF 0> <OSPF 1> <OSPF 2> | | | <host 0> <host 1> <host 2> """
[docs] def run(self, size): """ Create the router tree topology. Args: size (str): The degree of the router tree. This must be castable to an :obj:`int`. """ # Convert the size to an int. # Note that all parameters to Plugins will be strings as they are passed # in via the command line. They have to be converted to the requested type. size = int(size) # Create two networks where the control nets can be used for communication # between routers and the host_nets are used to communicate amongst hosts. control_nets = netaddr.IPNetwork("192.168.0.0/16").subnet(30) host_nets = netaddr.IPNetwork("10.0.0.0/8").subnet(24) # Create an iterator with AS numbers which can be used with the BGP routers. # Start with AS number 1000 because there were topologies connected with # router_tree that used the same AS numbers. start_as_number = 1000 as_nums = iter(range(start_as_number, start_as_number + size + 1)) # First, make the root pair. root = self._make_router_pair("root.net", control_nets, host_nets, as_nums) # The root BGP router needs lots of memory if the topology is large try: root.vm["mem"] = 4096 except AttributeError: root.vm = {"mem": 4096} # Next, create all of the leaves and link them to the root. for i in range(size): # Create the leaf nodes and return the BGP router leaf = self._make_router_pair( f"leaf-{i}.net", control_nets, host_nets, as_nums ) # Create a switch to connect the leaf to the root router switch = Vertex(self.g, f"root-leaf{i}.switch") switch.decorate(Switch) # Get the next subnet bgp_net = next(control_nets) bgp_ips = bgp_net.iter_hosts() # Connect both the root BGP router and the leaf BGP router leaf.connect(switch, next(bgp_ips), bgp_net.netmask) root.connect(switch, next(bgp_ips), bgp_net.netmask) # Make sure that the routers peer with each other via BGP root.link_bgp(leaf, switch, switch) # Sanity check that everything was created correctly # i.e. make sure interfaces were created. assert len(root.interfaces.interfaces) != 0 assert len(leaf.interfaces.interfaces) != 0
[docs] def _make_router_pair(self, name, control_nets, host_nets, as_nums): """Internal function to create the host, OSPF, BGP sequence. Args: name (str): The name of the router/host sequence (e.g. 'leaf-1.net'). control_nets (netaddr.IPNetwork): The network to use between routers. host_nets (netaddr.IPNetwork): The network to use between hosts. as_nums (range_iterator): An iterator for the AS numbering of the BGP routers. Returns: generic_vm_objects.GenericRouter: The BGP router for the pairing. """ # Get the next subnet in the `host_nets` IP block # Then get an iter of IPs for that subnet host_net = next(host_nets) host_ips = host_net.iter_hosts() # Create a host host = Vertex(self.g, f"host.{name}") host.decorate(LinuxHost) # Create an OSFF Router ospf = Vertex(self.g, f"ospf.{name}") ospf.decorate(GenericRouter) # Create a switch to connect the Host and OSPF router switch_host_to_ospf = Vertex(self.g, f"switch-host-ospf.{name}") switch_host_to_ospf.decorate(Switch) # Connect the OSPF router and Host to the Switch. # Use the `host_nets` IP network as the IP address for the VMs ospf.connect(switch_host_to_ospf, next(host_ips), host_net.netmask) host.connect(switch_host_to_ospf, next(host_ips), host_net.netmask) # Get the next subnet in the `control_nets` IP block # Then get an iter of IPs for that subnet ospf_net = next(control_nets) ospf_ips = ospf_net.iter_hosts() # Create a BGP Router bgp = Vertex(self.g, f"bgp.{name}") bgp.decorate(GenericRouter) # Set the AS number of the BGP router as_num = next(as_nums) bgp.set_bgp_as(as_num) # Create a switch to connect the OSPF router and the BGP router switch_ospf_to_bgp = Vertex(self.g, f"switch-ospf-bgp.{name}") switch_ospf_to_bgp.decorate(Switch) # Connect the OSPF and BGP routers to the Switch. # We use the ospf_connect method which enables us to define the connection # as an OSPF connection. # Use the `control_nets` IP network as the IP address for the VMs ospf.ospf_connect(switch_ospf_to_bgp, next(ospf_ips), ospf_net.netmask) bgp.ospf_connect(switch_ospf_to_bgp, next(ospf_ips), ospf_net.netmask) # Redistribute routes for directly connected subnets to OSPF peers. ospf.redistribute_ospf_connected() # Enable redistributing routes from BGP peers to OSPF peers. bgp.redistribute_bgp_into_ospf() # Enable redistributing routes from OSPF peers to BGP peers. bgp.redistribute_ospf_into_bgp() # Return the BGP router return bgp