Example #1
0
    def __init__(self, network, services, igp="ospf", target=None, olive_qemu_patched=False):
        self.network = network
        self.services = services
        self.igp = igp
        self.target = target
        self.olive_qemu_patched = olive_qemu_patched
        self.interface_limit = 0

#TODO: tidy up platform: Olive/Junosphere between the vmm and the device configs

        self.junosphere = False
        self.junosphere_olive = False
        if target in ['junosphere', 'junosphere_olive']:
            self.junosphere = True
            self.int_id_em = ank.naming.junos_int_id_em
            self.junosphere_platform = config.settings['Junosphere']['platform']
            if self.junosphere_platform == "Olive":
                self.junosphere_olive = True
                self.target = "junosphere_olive"
                self.olive_qemu_patched = config.settings['Junosphere']['olive_qemu_patched']
                self.int_id_em = ank.interface_id(self.target, olive_qemu_patched=olive_qemu_patched)
            else:
                self.interface_limit = 256 # TODO: check upper bound for VJX

        self.int_id = ank.interface_id(self.target, olive_qemu_patched=olive_qemu_patched)

        self.olive = False
        if self.target in ['olive', 'junosphere_olive']:
            self.olive = True

        if self.olive:
            self.interface_limit = 7
        if self.olive_qemu_patched:
            self.interface_limit = 8 # Patch allows 8 interfaces
Example #2
0
    def configure_interfaces(self, device):
        LOG.debug("Configuring interfaces for %s" % self.network.fqdn(device))
        """Interface configuration"""
        lo_ip = self.network.lo_ip(device)
        interfaces = []

        interfaces.append({
            'id':          'lo0',
            'ip':           str(lo_ip.ip),
            'netmask':      str(lo_ip.netmask),
            'prefixlen':    str(lo_ip.prefixlen),
            'net_ent_title': ank.ip_to_net_ent_title(lo_ip.ip),
            'description': 'Loopback',
        })

        for src, dst, data in self.network.graph.edges(device, data=True):
            subnet = data['sn']
            int_id = self.int_id(data['id'])
            description = 'Interface %s -> %s' % (
                    ank.fqdn(self.network, src), 
                    ank.fqdn(self.network, dst))

# Interface information for router config
            interfaces.append({
                'id':          int_id,
                'ip':           str(data['ip']),
                'prefixlen':    str(subnet.prefixlen),
                'broadcast':    str(subnet.broadcast),
                'description':  description,
            })

        return interfaces
Example #3
0
    def load(self, filename):   
        """Loads the network description from a graph file.
        Note this is done automatically if a filename is given to
        the Internet constructor.

        Args:
           filename:    The file to load from

        Returns:
           None

        Example usage:

        >>> inet = ank.internet.Internet()
        >>> inet.load("simple")
        >>> sorted(inet.network.graph.nodes())
        [RouterB.AS1, RouterA.AS1, RouterD.AS2, RouterC.AS1, RouterA.AS2, RouterA.AS3, RouterB.AS2, RouterC.AS2]

        >>> inet = ank.internet.Internet()
        >>> inet.load("singleas")
        >>> sorted(inet.network.graph.nodes())
        [1a.AS1, 1b.AS1, 1d.AS1, 1c.AS1]

        >>> inet = ank.internet.Internet()
        >>> inet.load("multias")
        >>> sorted(inet.network.graph.nodes())
        [1b.AS1, 1a.AS1, 2d.AS2, 1c.AS1, 2a.AS2, 3a.AS3, 2b.AS2, 2c.AS2]

        """
        LOG.info("Loading")
        ext = os.path.splitext(filename)[1]
        if ext == "":
            #TODO: use try/except block here
            self.network.graph = ank.load_example(filename)

#TODO: allow url to be entered, eg from zoo, if so then download the file and proceed on as normal

        elif ext == ".gml":
            # GML file from Topology Zoo
            ank.load_zoo(self.network, filename)
        elif ext == ".graphml":
            self.network.graph = ank.load_graphml(filename)
        elif ext == ".pickle":
            LOG.warn("AutoNetkit no longer supports pickle file format, please use GraphML")
        elif ext == ".yaml":
            # Legacy ANK file format
            LOG.warn("AutoNetkit no longer supports YAML file format, please use GraphML")
        else:
            LOG.warn("AutoNetkit does not support file format %s" % ext)

        #TODO: check that loaded network has at least one node, if not throw exception
        self.network.instantiate_nodes()
Example #4
0
    def dump(self):
        """Dumps overlay graphs to file 

        .. note::
            
            Doesn't currently support saving graphs - NetworkX cannot save nodes/edges with dictionary attributes

        """
        with open( os.path.join(config.log_dir, "physical.txt"), 'w') as f_pol_dump:
            f_pol_dump.write(ank.debug_nodes(self.network.graph))
            f_pol_dump.write(ank.debug_edges(self.network.graph))
        #nx.write_graphml(self.network.graph, os.path.join(config.log_dir, "physical.graphml"))

        with open( os.path.join(config.log_dir, "bgp.txt"), 'w') as f_pol_dump:
            f_pol_dump.write(ank.debug_nodes(self.network.g_session))
            f_pol_dump.write(ank.debug_edges(self.network.g_session))
        #nx.write_graphml(self.network.g_session, os.path.join(config.log_dir, "bgp.graphml"))

        with open( os.path.join(config.log_dir, "dns.txt"), 'w') as f_pol_dump:
            f_pol_dump.write(ank.debug_nodes(self.network.g_dns))
            f_pol_dump.write(ank.debug_edges(self.network.g_session))
        #nx.write_graphml(self.network.g_session, os.path.join(config.log_dir, "dns.graphml"))

        with open( os.path.join(config.log_dir, "dns_auth.txt"), 'w') as f_pol_dump:
            f_pol_dump.write(ank.debug_nodes(self.network.g_dns_auth))
            f_pol_dump.write(ank.debug_edges(self.network.g_dns_auth))
Example #5
0
    def configure_junos(self):
        """ Configures Junos"""
        LOG.info("Configuring Junos: %s" % self.target)
        junos_template = lookup.get_template("junos/junos.mako")
        ank_version = pkg_resources.get_distribution("AutoNetkit").version
        date = time.strftime("%Y-%m-%d %H:%M", time.localtime())

        physical_graph = self.network.graph
        igp_graph = ank.igp_graph(self.network)
        ibgp_graph = ank.get_ibgp_graph(self.network)
        ebgp_graph = ank.get_ebgp_graph(self.network)

        #TODO: correct this router type selector
        for router in self.network.routers():
            #check interfaces feasible
            if self.network.graph.in_degree(router) > self.interface_limit:
                LOG.warn("%s exceeds interface count: %s (max %s)" % (self.network.label(router),
                    self.network.graph.in_degree(router), self.interface_limit))
            asn = self.network.asn(router)
            network_list = []
            lo_ip = self.network.lo_ip(router)

            interfaces,static_routes = self.configure_interfaces(router)
            igp_interfaces = self.configure_igp(router, igp_graph,ebgp_graph)
            (bgp_groups, policy_options) = self.configure_bgp(router, physical_graph, ibgp_graph, ebgp_graph)

            # advertise AS subnet
            adv_subnet = self.network.ip_as_allocs[asn]
            if not adv_subnet in network_list:
                network_list.append(adv_subnet)

            juniper_filename = router_conf_path(self.network, router)
            with open( juniper_filename, 'wb') as f_jun:
                f_jun.write( junos_template.render(
                    hostname = router.rtr_folder_name,
                    username = '******',
                    interfaces=interfaces,
		    static_routes=static_routes,
                    igp_interfaces=igp_interfaces,
                    igp_protocol = self.igp,
                    asn = asn,
                    lo_ip=lo_ip,
                    router_id = lo_ip.ip,
                    network_list = network_list,
                    bgp_groups = bgp_groups,
                    policy_options = policy_options,
                    ank_version = ank_version,
                    date = date,
                    ))
Example #6
0
    def configure_igp(self, router, igp_graph, ebgp_graph):
        """igp configuration"""
        LOG.debug("Configuring IGP for %s" % self.network.label(router))
#TODO: get area from router
        default_area = 0
        igp_interfaces = []
        if igp_graph.degree(router) > 0:
            # Only start IGP process if IGP links
#TODO: make loopback a network mask so don't have to do "0.0.0.0"
            igp_interfaces.append({ 'id': 'lo0', 'wildcard': router.lo_ip.hostmask,
                'passive': False,
                'network': router.lo_ip.network,
                'area': default_area, 'weight': self.default_weight,
                })
            for src, dst, data in igp_graph.edges(router, data=True):
                int_id = self.int_id(data['id'])
                subnet = self.network.graph[src][dst]['sn']
                description = 'Interface %s -> %s' % (
                        ank.fqdn(self.network, src), 
                        ank.fqdn(self.network, dst))
                igp_interfaces.append({
                    'id':       int_id,
                    'weight':   data.get('weight', self.default_weight),
                    'area':   data.get('area', default_area),
                    'network': str(subnet.network),
                    'description': description,
                    'wildcard':      str(subnet.hostmask),
                    })

# Need to add eBGP edges as passive interfaces
            for src, dst in ebgp_graph.edges(router):
# Get relevant edges from ebgp_graph, and edge data from physical graph
                data = self.network.graph[src][dst]
                int_id = self.int_id(data['id'])
                subnet = self.network.graph[src][dst]['sn']
                description = 'Interface %s -> %s' % (
                    ank.fqdn(self.network, src), 
                    ank.fqdn(self.network, dst))
                igp_interfaces.append({
                    'id':       int_id,
                    'weight':   data.get('weight', self.default_weight),
                    'area':   data.get('area', default_area),
                    'description': description,
                    'passive': True,
                    'network': str(subnet.network),
                    'wildcard':      str(subnet.hostmask),
                    })

        return igp_interfaces
Example #7
0
    def configure_ios(self):
        """ Configures IOS"""
        LOG.info("Configuring IOS")
        ios_template = lookup.get_template("cisco/ios.mako")
        ank_version = pkg_resources.get_distribution("AutoNetkit").version
        date = time.strftime("%Y-%m-%d %H:%M", time.localtime())

        physical_graph = self.network.graph
        igp_graph = ank.igp_graph(self.network)
        ibgp_graph = ank.get_ibgp_graph(self.network)
        ebgp_graph = ank.get_ebgp_graph(self.network)

        for router in self.network.routers():
            #check interfaces feasible
#TODO: make in_degree a property eg link_count
            asn = self.network.asn(router)
            network_list = []
            lo_ip = self.network.lo_ip(router)

            interfaces = self.configure_interfaces(router)
            igp_interfaces = self.configure_igp(router, igp_graph,ebgp_graph)
            (bgp_groups, policy_options) = self.configure_bgp(router, physical_graph, ibgp_graph, ebgp_graph)

            # advertise AS subnet
            adv_subnet = self.network.ip_as_allocs[asn]
            if not adv_subnet in network_list:
                network_list.append(adv_subnet)

            juniper_filename = router_conf_path(self.network, router)
            with open( juniper_filename, 'wb') as f_jun:
                f_jun.write( ios_template.render(
                    hostname = router.rtr_folder_name,
                    username = '******',
                    interfaces=interfaces,
                    igp_interfaces=igp_interfaces,
                    igp_protocol = self.igp,
# explicit protocol
                    use_isis = self.igp == 'isis',
                    asn = asn,
                    lo_ip=lo_ip,
                    #TODO: make router have property "identifier" which maps to lo_ip
                    router_id = lo_ip.ip,
                    network_list = network_list,
                    bgp_groups = bgp_groups,
                    policy_options = policy_options,
                    ank_version = ank_version,
                    date = date,
                    ))
Example #8
0
 def __init__(self, network, services, zebra_password="******"):
     self.network = network
     self.services = services
     self.zebra_password = zebra_password
     self.interface_id = ank.interface_id('netkit')
     self.tap_interface_id = ank.tap_interface_id
     self.lo_interface = lo_interface
     self.default_weight = 1
Example #9
0
def dump_identifiers(network, filename):
    with open( filename, 'w') as f_dump:
# writes out lo_ip for routers, and identifying IP for servers
        for my_as in ank.get_as_graphs(network):
            for router in sorted(network.routers(my_as.asn), key = lambda x: x.fqdn):
                f_dump.write( "%s\t%s\n" % (router, router.lo_ip.ip))
            for server in sorted(network.servers(my_as.asn), key = lambda x: x.fqdn):
                    f_dump.write( "%s\t%s\n" % (server, server_ip(server)))
            f_dump.write("\n")
Example #10
0
    def configure_interfaces(self, device):
        LOG.debug("Configuring interfaces for %s" % self.network.fqdn(device))
        """Interface configuration"""
        lo_ip = self.network.lo_ip(device)
        interfaces = []
	static_routes = []
        interfaces.append({
            'id':          'lo0',
            'ip':           str(lo_ip.ip),
            'netmask':      str(lo_ip.netmask),
            'prefixlen':    str(lo_ip.prefixlen),
            'net_ent_title': ank.ip_to_net_ent_title(lo_ip.ip),
            'description': 'Loopback',
        })

        for src, dst, data in self.network.graph.edges(device, data=True):
	    neighbor = ank.fqdn(self.network, dst)
            subnet = data['sn']
            int_id = self.int_id(data['id'])
            description = 'Interface %s -> %s' % (
                    ank.fqdn(self.network, src), 
                    ank.fqdn(self.network, dst))

# Interface information for router config
            interfaces.append({
                'id':          int_id,
                'ip':           str(data['ip']),
                'prefixlen':    str(subnet.prefixlen),
		'netmask':	str(subnet.netmask),
                'broadcast':    str(subnet.broadcast),
                'description':  description,
            })
#static routes for the dummy nodes
	    for virtual in sorted(self.network.virtual_nodes(), key = lambda x: x.fqdn):
		virtual_hostname = virtual.hostname
		if neighbor == virtual_hostname:
		    subnet = data['sn']
		    static_routes.append({
		        'network':	str(subnet.network),
			'prefixlen':	str(subnet.prefixlen),
			'ip':		str(data['ip']),
		    })

        return interfaces,static_routes
Example #11
0
    def configure_igp(self, router, igp_graph, ebgp_graph):
        """igp configuration"""
        LOG.debug("Configuring IGP for %s" % self.network.label(router))
        default_weight = 1
        igp_interfaces = []
        if igp_graph.degree(router) > 0:
            # Only start IGP process if IGP links
            igp_interfaces.append({ 'id': 'lo0', 'passive': True})
            for src, dst, data in igp_graph.edges(router, data=True):
                int_id = ank.junos_logical_int_id(self.int_id(data['id']))
                description = 'Interface %s -> %s' % (
                    ank.fqdn(self.network, src), 
                    ank.fqdn(self.network, dst))
                igp_interfaces.append({
                    'id':       int_id,
                    'weight':   data.get('weight', default_weight),
                    'description': description,
                    })

# Need to add eBGP edges as passive interfaces
            for src, dst in ebgp_graph.edges(router):
# Get relevant edges from ebgp_graph, and edge data from physical graph
                data = self.network.graph[src][dst]
                int_id = ank.junos_logical_int_id(self.int_id(data['id']))
                description = 'Interface %s -> %s' % (
                    ank.fqdn(self.network, src), 
                    ank.fqdn(self.network, dst))
                igp_interfaces.append({
                    'id':       int_id,
                    'weight':   data.get('weight', default_weight),
                    'description': description,
                    'passive': True,
                    })

        return igp_interfaces
Example #12
0
    def configure_interfaces(self, device):
        LOG.debug("Configuring interfaces for %s" % self.network.fqdn(device))
        """Interface configuration"""
        lo_ip = self.network.lo_ip(device)
        interfaces = []

        interfaces.append({
            'id':          'lo0',
            'ip':           lo_ip.ip,
            'netmask':      lo_ip.netmask,
            'wildcard':      lo_ip.hostmask,
            'prefixlen':    lo_ip.prefixlen,
            'network':       lo_ip.network,
            'description': 'Loopback',
        })

        for src, dst, data in self.network.graph.edges(device, data=True):
            subnet = data['sn']
            int_id = self.interface_id(data['id'])
            description = 'Interface %s -> %s' % (
                    ank.fqdn(self.network, src), 
                    ank.fqdn(self.network, dst))

# Interface information for router config
            interfaces.append({
                'id':          int_id,
                'ip':           data['ip'],
                'network':       subnet.network,
                'prefixlen':    subnet.prefixlen,
                'netmask':    subnet.netmask,
                'wildcard':      subnet.hostmask,
                'broadcast':    subnet.broadcast,
                'description':  description,
                'weight':   data.get('weight', self.default_weight),
            })

        return interfaces
Example #13
0
def plot(network, show=False, save=True):
    """ Plot the network """
    try:
        import matplotlib.pyplot as plt
    except ImportError:
        LOG.warn("Matplotlib not found, not plotting using Matplotlib")
        return
    try:
        import numpy
    except ImportError:
        LOG.warn("Matplotlib plotting requires numpy for graph layout")
        return

    plot_dir = config.plot_dir
    if not os.path.isdir(plot_dir):
        os.mkdir(plot_dir)

    graph = network.graph
    pos=nx.spring_layout(graph)

# Different node color for each AS. Use heatmap based on ASN

    plot_graph(graph, title="Network", pos=pos, show=show, save=save,
            node_color=cmap_index(network, graph))

    graph = ank.get_ebgp_graph(network)
    labels = dict( (n, network.label(n)) for n in graph)
    plot_graph(graph, title="eBGP", pos=pos, labels=labels, show=show, save=save)

    graph = ank.get_ibgp_graph(network)
    labels = dict( (n, network.label(n)) for n in graph)
    plot_graph(graph, title="iBGP", pos=pos, labels=labels, show=show, save=save)

    graph = ank.get_dns_graph(network)
    labels = dict( (n, network.label(n)) for n in graph)
    plot_graph(graph, title="DNS", pos=pos, labels=labels, show=show, save=save)
Example #14
0
def inv_cap_weights(network):
    """Updates link weights based on inverse of link speed."""
    #TODO: rewrite this to be cleaner iteration and setting
    for graph in ank.get_as_graphs(network):
        for (src, dst, data) in graph.edges_iter(data=True):    
            # only update if non default weight       
            if 'speed' in data and 'weight' in data and data['weight'] == 1: 
                # assume largest link is 10gb 
                #TODO: use Cisco guidelines for this
                scale_speed = 100000      
                speed = float(data['speed'])
                weight = int((1/speed)*scale_speed)    
                weight = max(weight, 1)
                if weight is 0:
                    weight = 1
                    graph[src][dst]['weight'] = weight
                    network.set_edge_property(src, dst, 'weight', weight)
    return
def load_example(filename):
    """
    Load example network
    """
    # No extension, see if filename is an included example Topology
    topology_dir = resource_filename("AutoNetkit", os.path.join("lib", "examples", "topologies"))
    test_filename = os.path.join(topology_dir, "%s.graphml" % filename)
    if os.path.isfile(test_filename):
        LOG.info("Loading example topology %s " % filename)
        return ank.load_graphml(test_filename)
    else:
        example_files = glob.glob(topology_dir + os.sep + "*.graphml")
        # Remove path
        example_files = (os.path.split(filename)[1] for filename in example_files)
        # Remove extension
        example_files = (os.path.splitext(filename)[0] for filename in example_files)
        LOG.warn("Unable to find example topology %s" % filename)
        LOG.info("Valid example topologies are: " + ", ".join(example_files))
Example #16
0
def router_conf_file(network, router):
    """Returns filename for config file for router"""
    return "%s.conf" % ank.rtr_folder_name(network, router)
Example #17
0
 def dns_host_portion_only(self):
     return ank.dns_host_portion_only(self)
Example #18
0
    def configure_bgp(self, router, physical_graph, ibgp_graph, ebgp_graph):
        LOG.debug("Configuring BGP for %s" % self.network.fqdn(router))
        """ BGP configuration"""
#TODO: Don't configure iBGP or eBGP if no eBGP edges
# need to pass correct blank dicts to templates then...

#TODO: put comments in for junos bgp peerings
        # route maps
        bgp_groups = {}
        route_maps = []
        if router in ibgp_graph:
            internal_peers = []
            for peer in ibgp_graph.neighbors(router):
                if not peer.is_router:
#no iBGP peering to non-routers
                    continue
                route_maps_in = [route_map for route_map in 
                        self.network.g_session[peer][router]['ingress']]
                route_maps_out = [route_map for route_map in 
                        self.network.g_session[router][peer]['egress']]
                route_maps += route_maps_in
                route_maps += route_maps_out   
                internal_peers.append({
                    'id': self.network.lo_ip(peer).ip,
                    'route_maps_in': [r.name for r in route_maps_in],
                    'route_maps_out': [r.name for r in route_maps_out],
                    })
            bgp_groups['internal_peers'] = {
                    'type': 'internal',
                    'neighbors': internal_peers
                    }

        ibgp_neighbor_list = []
        ibgp_rr_client_list = []
        if router in ibgp_graph:
            for src, neigh, data in ibgp_graph.edges(router, data=True):
                route_maps_in = [route_map for route_map in 
                        self.network.g_session[neigh][router]['ingress']]
                route_maps_out = [route_map for route_map in 
                        self.network.g_session[router][neigh]['egress']]
                route_maps += route_maps_in
                route_maps += route_maps_out     
                description = data.get("rr_dir") + " to " + ank.fqdn(self.network, neigh)
                if data.get('rr_dir') == 'down':
                    ibgp_rr_client_list.append(
                            {
                                'id':  self.network.lo_ip(neigh).ip,
                                'description':      description,
                                'route_maps_in': [r.name for r in route_maps_in],
                                'route_maps_out': [r.name for r in route_maps_out],
                                })
                elif (data.get('rr_dir') in set(['up', 'over', 'peer'])
                        or data.get('rr_dir') is None):
                    ibgp_neighbor_list.append(
                            {
                                'id':  self.network.lo_ip(neigh).ip,
                                'description':      description,
                                'route_maps_in': [r.name for r in route_maps_in],
                                'route_maps_out': [r.name for r in route_maps_out],
                                })

        bgp_groups['internal_peers'] = {
            'type': 'internal',
            'neighbors': ibgp_neighbor_list
            }
        if len(ibgp_rr_client_list):
            bgp_groups['internal_rr'] = {
                    'type': 'internal',
                    'neighbors': ibgp_rr_client_list,
                    'cluster': self.network.lo_ip(router).ip,
                    }

        if router in ebgp_graph:
            external_peers = []
            for peer in ebgp_graph.neighbors(router):
                if not peer.is_router:
#no eBGP peering to non-routers
                    continue
                route_maps_in = [route_map for route_map in 
                        self.network.g_session[peer][router]['ingress']]
                route_maps_out = [route_map for route_map in 
                        self.network.g_session[router][peer]['egress']]
                route_maps += route_maps_in
                route_maps += route_maps_out   
                peer_ip = physical_graph[peer][router]['ip']
                external_peers.append({
                    'id': peer_ip, 
                    'route_maps_in': [r.name for r in route_maps_in],
                    'route_maps_out': [r.name for r in route_maps_out],
                    'peer_as': self.network.asn(peer)})
            bgp_groups['external_peers'] = {
                    'type': 'external', 
                    'neighbors': external_peers}

# Ensure only one copy of each route map, can't use set due to list inside tuples (which won't hash)
# Use dict indexed by name, and then extract the dict items, dict hashing ensures only one route map per name
        route_maps = dict( (route_map.name, route_map) for route_map in route_maps).values()

        community_lists = {}
        prefix_lists = {}
        node_bgp_data = self.network.g_session.node.get(router)
        if node_bgp_data:
            community_lists = node_bgp_data.get('tags')
            prefix_lists = node_bgp_data.get('prefixes')
        policy_options = {
                'community_lists': community_lists,
                'prefix_lists': prefix_lists,
                'route_maps': route_maps,
                }

        return (bgp_groups, policy_options)
Example #19
0
    def collect_data(self, commands):
        shell = self.server.get_shell()
        shell.setecho(False)

        collected_data_dir = config.collected_data_dir
        netkit_data_dir = os.path.join(collected_data_dir, "netkit")
        if not os.path.isdir(netkit_data_dir):
                os.mkdir(netkit_data_dir)
        host_data_dir = os.path.join(netkit_data_dir, self.host_alias)
        if not os.path.isdir(host_data_dir):
                os.mkdir(host_data_dir)
        collect_timestamp_dir = os.path.join(host_data_dir, time.strftime("%Y%m%d_%H%M%S", time.localtime()))
        if not os.path.isdir(collect_timestamp_dir):
            os.mkdir(collect_timestamp_dir)

        servers = set(self.network.servers())

        #TODO: need to have way to allow privexec.... or just disable enable password?
#TODO: Put term len 0 into configs

        for node in self.network.devices():
            routername = ank.fqdn(self.network, node)
            full_routername = ank.rtr_folder_name(self.network, node)
            user_exec_prompt = "%s>" % node.dns_hostname
            priv_exec_prompt = "%s#" % node.dns_hostname
            for port_command in commands:
                LOG.info("%s: running %s" % (routername, port_command))
                telnet_port, command = port_command.split(":")
                if telnet_port == 'ssh':
                    self.server.connect_vm(node.tap_ip, shell)
                    shell.sendline(command)
                    shell.expect(self.server.NETKIT_PROMPT)
                    command_output = shell.before
                    self.server.disconnect_vm(shell)
                    shell.prompt()
# need to ssh into this machine
                else:
                    if node in servers:
# don't try telnet into as zebra not running
                        continue
# use telnet
                    shell.sendline("telnet %s %s" % (node.tap_ip, telnet_port))
                    shell.expect("Password:"******"1234")
                    shell.expect(user_exec_prompt)
                    shell.sendline("en")
                    i = shell.expect(["Password:"******"1234")
                    else:
# all good, in priv exec
                        pass
# just to be sure
                    set_term_length = "term len 0"
                    shell.sendline(set_term_length)
                    shell.expect(priv_exec_prompt)
                    shell.sendline(command)
                    shell.expect(priv_exec_prompt)
# Can be an issue with the telnet x zebra command (not for bgpd it seems)
                    command_output = shell.before
# If no command output, captured the previous command, try again
                    if command_output.strip() == set_term_length:
                        shell.expect(priv_exec_prompt)
                        command_output = shell.before
                    shell.sendline("exit")
                    shell.prompt() 
# from http://stackoverflow.com/q/295135/
                command_filename_format = (re.sub('[^\w\s-]', '', command).strip().lower())
                filename = "%s_%s_%s.txt" % (full_routername,
                        command_filename_format,
                        time.strftime("%Y%m%d_%H%M%S", time.localtime()))
                filename = os.path.join(collect_timestamp_dir, filename)
                
                with open( filename, 'w') as f_out:
                    f_out.write(command_output)
Example #20
0
    def configure_junosphere(self):
        """Configure Junosphere topology structure"""
        LOG.debug("Configuring Junosphere") 
        vmm_template = lookup.get_template("junos/topology_vmm.mako")
        topology_data = {}
        # Generator for private0, private1, etc
        collision_to_bridge_mapping = {}
        private_bridges = []
        junosphere_predefined_bridge_count = 124 # have to explicitly create bridges past 124

        image_tuple = namedtuple('image', "alias, basedisk")

        if self.junosphere_olive:
            image = image_tuple("MY_DISK", config.settings['Junosphere']['basedisk'])
        else:
            image = image_tuple("VJX1000_LATEST", None)


        bridge_id_generator = (i for i in itertools.count(0))
        def next_bridge_id():
            bridge_id = bridge_id_generator.next()
            retval = "private%s" % bridge_id
            if bridge_id > junosphere_predefined_bridge_count:
                private_bridges.append(retval)
            return retval

        for device in sorted(self.network.devices(), key = lambda x: x.fqdn):
            hostname = device.hostname
            topology_data[hostname] = {
                    'image': image.alias,
                    'config': router_conf_file(self.network, device),
                    'interfaces': [],
                    }
            for src, dst, data in sorted(self.network.graph.edges(device, data=True), key = lambda (s,t,d): t.fqdn):
                subnet = data['sn']
                description = 'Interface %s -> %s' % (
                        ank.fqdn(self.network, src), 
                        ank.fqdn(self.network, dst))
# Bridge information for topology config
                if subnet in collision_to_bridge_mapping:
# Use bridge allocated for this subnet
                    bridge_id = collision_to_bridge_mapping[subnet]
                else:
# Allocate a bridge for this subnet
                    bridge_id = next_bridge_id()
                    collision_to_bridge_mapping[subnet] = bridge_id

                if not self.junosphere_olive:
                    description += "(%s)" % self.int_id(data['id']) 

                topology_data[hostname]['interfaces'].append({
                    'description': description,
                    'id': self.int_id_em(data['id']),
                    'id_ge':  self.int_id(data['id']),
                    'bridge_id': bridge_id,
                    })

            if self.junosphere_olive:
# em2 is dead on Olive Junosphere platform
                topology_data[hostname]['interfaces'].append({
                    'description': "dead interface",
                    'id': "em2",
                    'bridge_id': "dead",
                    })
            
        vmm_file = os.path.join(lab_dir(), "topology.vmm")
        with open( vmm_file, 'wb') as f_vmm:
            f_vmm.write( vmm_template.render(
                topology_data = topology_data,
                private_bridges = private_bridges,
                image = image,
                olive_based = self.junosphere_olive,
                ))
Example #21
0
    def configure(self):
        """Configure C-BGP"""
        LOG.info("Configuring C-BGP")
        self.initialise()
        default_weight = 1
        template = lookup.get_template("cbgp/cbgp.mako")
        physical_graph = self.network.graph
        igp_graph = ank.igp_graph(self.network)
        ibgp_graph = ank.get_ibgp_graph(self.network)
        ebgp_graph = ank.get_ebgp_graph(self.network)
        as_graphs = ank.get_as_graphs(self.network)
        ip_as_allocs = ank.get_ip_as_allocs(self.network) # Allocs for ebgp announcements

        physical_topology = defaultdict(dict)
        ibgp_topology = {} 
        igp_topology = {} 
        ebgp_topology = {}
        ebgp_prefixes = {}
        bgp_routers = {}

# Fast lookup of loopbacks - the unique router ID for cBGP
        loopback = dict( (n, self.network.lo_ip(n).ip) for n in physical_graph)

# Physical topology
        for as_graph in as_graphs:
            asn = as_graph.name
            physical_topology[asn]['nodes'] = [loopback[n] for n in as_graph]
            physical_topology[asn]['links'] = [ (loopback[s], loopback[t]) 
                    for (s,t) in unidirectional(as_graph.edges())]

# Interdomain links
        interdomain_links =  [ (loopback[s], loopback[t])
                for (s,t) in unidirectional(ebgp_graph.edges())]

#IGP configuration
        for as_graph in as_graphs:
            asn = as_graph.name
            igp_topology[asn] = {}
# Subgraph of IGP graph for this AS
            as_igp_graph = igp_graph.subgraph(as_graph.nodes())
            igp_topology[asn]['nodes'] = [loopback[n] for n in as_igp_graph]
            igp_topology[asn]['links'] = [ (loopback[s], loopback[t], data.get('weight', default_weight)) 
                    for (s,t,data) in (as_graph.edges(data=True))]

# iBGP configuration
#TODO: if ibgp graph is a clique then use "bgp domain 1 full-mesh" where 1 is asn
# use nx.graph_clique_number(G) and compare to size of G, if same then is a clique
# otherwise create ibgp session by session

#TODO: add support for non full-mesh (need to find documentation on this)
        for as_graph in as_graphs:
            asn = as_graph.name
            for router in as_graph:
                if not router.is_router:
                    continue
                if router not in ibgp_graph:
# likely single node AS
                    continue
                ibgp_topology[router] = []
                for peer in ibgp_graph.neighbors(router):
                    ibgp_topology[router].append(peer)
            bgp_routers[asn] = [n.lo_ip.ip for n in ank.bgp_routers(self.network)
                    if n.asn == asn]

# eBGP configuration
        for node in ebgp_graph.nodes():
            node_id = loopback[node]
            peers = []
            for peer in ebgp_graph.neighbors(node):
                peers.append( (self.network.asn(peer), loopback[peer]))
            ebgp_topology[node_id] = peers
# Prefixes to originate
            adv_subnet = ip_as_allocs[self.network.asn(node)]
            ebgp_prefixes[node_id] = adv_subnet

            #TODO: see if can just do for node in ebgp_graph ie without the .nodes() on end

        # bgp policy
        bgp_policy = {}
        for router in self.network.routers():
            for peer in self.network.g_session.neighbors(router):
                pol_egress = self.network.g_session[router][peer]['egress']
                pol_ingress = self.network.g_session[peer][router]['ingress']
                if len(pol_ingress) or len(pol_egress):
                    try:
                        bgp_policy[router][peer] = {
                                'ingress': pol_ingress,
                                'egress': pol_egress,
                                }
                    except KeyError:
                        bgp_policy[router] = {}
                        bgp_policy[router][peer] = {
                                'ingress': pol_ingress,
                                'egress': pol_egress,
                                }


        # tags dict for mapping from tag to community value, and for prefixes
        tags = self.network.g_session.graph['tags']
        prefixes = self.network.g_session.graph['prefixes']

        with open( cbgp_file(), 'w') as f_cbgp:
                f_cbgp.write( template.render(
                   physical_topology = physical_topology,
                   interdomain_links = interdomain_links,
                   igp_topology = igp_topology,
                   ibgp_topology = ibgp_topology,
                   ebgp_topology = ebgp_topology,
                   ebgp_prefixes = ebgp_prefixes,
                   bgp_routers = bgp_routers,
                   bgp_policy = bgp_policy,
                   tags = tags,
                   prefixes = prefixes,
                   ))
Example #22
0
    def configure_dns(self):
        """Generates BIND configuration files for DNS

        Can check configs eg:

        Forward::

            bash-3.2$ named-checkzone -d AS3 ank_lab/netkit_lab/AS3_l3_3_dns_1/etc/bind/db.AS3
            loading "AS3" from "ank_lab/netkit_lab/AS3_l3_3_dns_1/etc/bind/db.AS3" class "IN"
            zone AS3/IN: loaded serial 2008080101
            OK


        Reverse::

            bash-3.2$ named-checkzone -d 0.10.in-addr.arpa ank_lab/netkit_lab/AS3_l3_3_dns_1/etc/bind/db.0.10.in-addr.arpa. 
            loading "0.10.in-addr.arpa" from "ank_lab/netkit_lab/AS3_l3_3_dns_1/etc/bind/db.0.10.in-addr.arpa." class "IN"
            zone 0.10.in-addr.arpa/IN: loaded serial 2008080101
            OK


        named::

            bash-3.2$ named-checkconf ank_lab/netkit_lab/AS3_l3_3_dns_1/etc/bind/named.conf 
        
        """
        import netaddr
        ip_localhost = netaddr.IPAddress("127.0.0.1")
        linux_bind_dir = "/etc/bind"
        resolve_template = lookup.get_template("linux/resolv.mako")
        forward_template = lookup.get_template("bind/forward.mako")

        named_template = lookup.get_template("bind/named.mako")
        reverse_template = lookup.get_template("bind/reverse.mako")
        root_template = lookup.get_template("bind/root.mako")

        root_dns_template = lookup.get_template("bind/root_dns.mako")
        root_dns_named_template = lookup.get_template("bind/root_dns_named.mako")

        ip_as_allocs = ank.get_ip_as_allocs(self.network)

        dns_servers = ank.dns_servers(self.network)
        root_servers = list(ank.root_dns_servers(self.network))
        auth_servers = ank.dns.dns_auth_servers(self.network)
        caching_servers = ank.dns.dns_cache_servers(self.network)
        clients = ank.dns.dns_clients(self.network)
        routers = set(self.network.routers())

#TODO: use with for opening files

        for server in root_servers:
            children = ank.dns.dns_hiearchy_children(server)
            child_servers = []
            for child in children:
                advertise_block = ip_as_allocs[child.asn]
                reverse_identifier = ank.rev_dns_identifier(advertise_block)
                child_servers.append( (child.domain, reverse_identifier, ank.server_ip(child)))
            f_root_db = open(os.path.join(bind_dir(self.network, server), "db.root"), 'wb') 
            f_root_db.write( root_dns_template.render(
                dns_servers = child_servers,
                server = server,
            ))

            f_named = open( os.path.join(bind_dir(self.network, server), "named.conf"), 'wb')
            f_named.write(root_dns_named_template.render(
                logging = False,
            ))

        for server in caching_servers:
            #root_db_hint = ( ("ns.AS%s" % n.asn, ank.server_ip(n)) for n in ank.dns_hiearchy_parents(server))
            root_db_hint = ( ("ROOT-SERVER", ank.server_ip(n)) for n in root_servers)
            root_db_hint = list(root_db_hint)
#TODO: make caching use parent rather than global root
            f_root = open( os.path.join(bind_dir(self.network, server), "db.root"), 'wb')
            f_root.write( root_template.render( root_servers = root_db_hint))
            f_named = open( os.path.join(bind_dir(self.network, server), "named.conf"), 'wb')
            f_named.write(named_template.render(
                entry_list = [],
                bind_dir = linux_bind_dir,
                logging = False,
            ))
            f_named.close()

        for server in auth_servers:
            named_list = []
            advertise_links = list(ank.advertise_links(server))
            advertise_hosts = list(ank.dns_auth_children(server))
            LOG.debug("DNS server %s advertises %s" % (server, advertise_links))
#TODO: make reverse dns handle domains other than /8 /16 /24
            advertise_block = ip_as_allocs[server.asn]
# remove trailing fullstop
            reverse_identifier = ank.rev_dns_identifier(advertise_block).rstrip(".")
#TODO: look at using advertise_block.network.reverse_dns - check what Bind needs
            named_list.append(reverse_identifier)

            f_named = open( os.path.join(bind_dir(self.network, server), "named.conf"), 'wb')
            f_named.write(named_template.render(
                domain = server.domain,
                entry_list = named_list,
                bind_dir = linux_bind_dir,
                logging = False,
            ))
            f_named.close()

            for_entry_list = list( (self.interface_id(link.id), link.local_host.dns_host_portion_only, link.ip) 
                    for link in advertise_links)
# Add loopbacks for routers
            for_entry_list += ( (self.lo_interface(0), host.dns_host_portion_only, host.lo_ip.ip)
                    #TODO: make thise check l3 group rather than asn (generalise)
                    for host in advertise_hosts if host.is_router and host.asn == server.asn)
            
            rev_entry_list = list( 
                    (ank.reverse_subnet(link.ip, advertise_block.prefixlen), self.interface_id(link.id), link.local_host.dns_hostname) 
                    for link in advertise_links)
            # Add loopbacks for routers
            rev_entry_list += ( (ank.reverse_subnet(host.lo_ip.ip, advertise_block.prefixlen), self.lo_interface(0), host.dns_host_portion_only)
                    #TODO: make thise check l3 group rather than asn (generalise)
                    for host in advertise_hosts if host.is_router and host.asn == server.asn)

            #TODO: provide better way to get eg eth0.host than string concat inside the template

            host_cname_list = []
            for host in advertise_hosts:
                if host.asn != server.asn:
# host is from another asn, skip.
#TODO: extend this to make sure matches same asn, l3group and l2group
                    continue

                if host.is_router:
# has lo_ip
                    cname = "%s.%s" % (self.lo_interface(), host.dns_host_portion_only)
                else:
# choose an interface - arbitrary choice, choose first host link
                    interface = self.interface_id(ank.server_interface_id(host))
                    cname = "%s.%s" % (interface, host.dns_host_portion_only)
            
                host_cname_list.append( (host.dns_host_portion_only, cname))

            #Sort to make format nicer
            host_cname_list = sorted(host_cname_list, key = lambda x: x[1])
            for_entry_list = sorted(for_entry_list)
            for_entry_list = sorted(for_entry_list, key = lambda x: x[1])
            
            f_forward = open ( os.path.join(bind_dir(self.network, server), "db.%s" % server.domain), 'wb')
            f_forward.write(forward_template.render(
                        domain = server.domain,
                        entry_list = for_entry_list,
                        host_cname_list =  host_cname_list,
                        dns_server = server.dns_hostname,
                        dns_server_ip = ank.server_ip(server),
                ))

            f_reverse = open(os.path.join(bind_dir(self.network, server), "db.%s" % reverse_identifier), 'wb')

            f_reverse.write(reverse_template.render(
                domain = server.domain,
                identifier = reverse_identifier,
                entry_list = rev_entry_list,
                dns_server= server.dns_hostname,
                ))

            #TODO: make l2 use l3 for caching
#TODO: ROOT-SERVER can't be part of a domain...  - need to correctly handle case of multiple root servers
# and also need to handle this for case of single root server (ie no hiearchy) probably ok as /etc/resolv.conf points to server itself, not through dns hints
            root_db_hint = ( ("ROOT-SERVER", ank.server_ip(n)) for n in ank.dns_hiearchy_parents(server))
            f_root = open( os.path.join(bind_dir(self.network, server), "db.root"), 'wb')
            f_root.write( root_template.render( root_servers = root_db_hint))

        for server in dns_servers:
            f_resolv = open( os.path.join(etc_dir(self.network, server), "resolv.conf"), 'wb')
            f_resolv.write ( resolve_template.render(
                nameservers = [ank.server_ip(server)],
                domain = server.domain))

# Configure clients
        for client in clients:
            server_ips = (ank.server_ip(server) for server in ank.dns_hiearchy_parents(client))
            server_ips = list(server_ips)
            f_resolv = open( os.path.join(etc_dir(self.network, client), "resolv.conf"), 'wb')
            f_resolv.write ( resolve_template.render(
                nameservers = server_ips,
                domain = client.domain))

        return
Example #23
0
    def compile(self):        
        """Compile into device configuration files.

          Args:
             None

          Returns:
             None

          Example usage:

          >>> inet = ank.internet.Internet()
          >>> inet.compile()

          >>> inet = ank.internet.Internet()
          >>> inet.compile()

          """

        #TODO: fix import order problem with doctests:
        #No handlers could be found for logger "ANK"
        LOG.info("Compiling")

        # Sanity check
        if self.network.graph.number_of_nodes() == 0:
            LOG.warn("Cannot compile empty network")
            return

        # Clean up old archives
        ank.tidy_archives()
      
        #TODO: 
        #config.get_plugin("Inv Cap").run(self.network)   
        #ank.inv_cap_weights(self.network)
        #config.get_plugin("Test").run()
        ank.initialise_bgp(self.network)
        
        # Ensure nodes have a type set
        self.network.update_node_type(default_type="netkit_router")
        ank.allocate_dns_servers(self.network)

        # Allocations  
        ank.allocate_subnets(self.network, IPNetwork("10.0.0.0/8")) 
        ank.alloc_interfaces(self.network)

        ank.alloc_tap_hosts(self.network, self.tapsn)

        if self.policy_file:
            LOG.info("Applying BGP policy from %s" % self.policy_file)
            pol_parser = ank.BgpPolicyParser(self.network)
            pol_parser.apply_policy_file(self.policy_file)
	
	if self.rpki_file:
	    LOG.info("Applying RPKI structure from %s" % self.rpki_file)
	    rpki_parser = ank.RpkiSetsParser(self.network)
	    rpki_parser.apply_rpki_file(self.rpki_file)
            
        if self.will_deploy and not self.compile_targets['netkit']:
            auto_compile = any( data.get("active") 
                    for data in config.settings['Netkit Hosts'].values())
            if auto_compile:
                LOG.info("Active Netkit deployment target, automatically compiling")
                self.compile_targets['netkit'] = True
        if self.compile_targets['netkit']:
            nk_comp = ank.NetkitCompiler(self.network, self.services)
            nk_comp.initialise()     
            nk_comp.configure()

        auto_compile = any( data.get("active") 
                for data in config.settings['Dynagen Hosts'].values())
        if auto_compile:
                LOG.info("Active Dynagen deployment target, automatically compiling")
                self.compile_targets['dynagen'] = True
        if self.compile_targets['dynagen']:
            dynagen_comp = ank.dynagenCompiler(self.network, services = self.services, 
                    igp = self.igp,
                    image = config.settings['Dynagen']['image'],
                    hypervisor_server = config.settings['Dynagen']['Hypervisor']['server'],
                    hypervisor_port = config.settings['Dynagen']['Hypervisor']['port'],
                    )
            dynagen_comp.initialise()     
            dynagen_comp.configure()

        if self.compile_targets['junosphere']:
            junos_comp = ank.JunosCompiler(self.network, self.services, self.igp, target="junosphere")
            junos_comp.initialise()
            junos_comp.configure()

        if self.compile_targets['junosphere_olive']:
            LOG.warn("Junosphere Olive not currently supported")
            #junos_comp = ank.JunosCompiler(self.network, self.services, self.igp, target="junosphere_olive")
            #junos_comp.initialise()
            #junos_comp.configure()

        if self.will_deploy and not self.compile_targets['olive']:
            auto_compile = any( data.get("active") 
                    for data in config.settings['Olive Hosts'].values())
            if auto_compile:
                self.compile_targets['olive'] = True
                LOG.info("Active Olive deployment target, automatically compiling")
        if self.compile_targets['olive']:
            olive_qemu_patched = self.compile_targets['olive_qemu_patched']
            junos_comp = ank.JunosCompiler(self.network, self.services, self.igp, target="olive",
                    olive_qemu_patched = olive_qemu_patched)
            junos_comp.initialise()
            junos_comp.configure()

        if self.will_deploy and not self.compile_targets['cbgp']:
            auto_compile = any( data.get("active") 
                    for data in config.settings['cBGP Hosts'].values())
            if auto_compile:
                self.compile_targets['cbgp'] = True
                LOG.info("Active cBGP deployment target, automatically compiling")
        if self.compile_targets['cbgp']:
            cbgp_comp = ank.CbgpCompiler(self.network, self.services)
            cbgp_comp.configure()
Example #24
0
    def configure_netkit(self):
        """Generates Netkit and Zebra/Quagga specific configuration files."""

        # Sets up netkit related files
        tap_host = ank.get_tap_host(self.network)

        ank_version = pkg_resources.get_distribution("AutoNetkit").version
        date = time.strftime("%Y-%m-%d %H:%M", time.localtime())

        lab_template = lookup.get_template("netkit/lab.mako")
        startup_template = lookup.get_template("netkit/startup.mako")
        zebra_daemons_template = lookup.get_template(
            "quagga/zebra_daemons.mako")
        zebra_template = lookup.get_template("quagga/zebra.mako")
        sshd_template = lookup.get_template("linux/sshd.mako")
        motd_template = lookup.get_template("quagga/motd.mako")

        # Shared (common) configuration
        startup_daemon_list = []
        #Setup ssh
        shutil.copy(resource_filename("AutoNetkit","lib/shadow"), shared_etc_dir())
        startup_daemon_list.append("ssh")
        # Need to chown root dir for ssh keys
# refer http://list.dia.uniroma3.it/pipermail/netkit.users/2010-February/000552.html
        use_ssh_key = False
        if config.settings['Netkit']['ssh key']:
            #chown root:root /root
            use_ssh_key = True

        f_startup = open( os.path.join(lab_dir(), "shared.startup"), 'wb')
        f_startup.write(startup_template.render(
            interfaces=[],
            add_localhost=True,
            #don't send out the tap interface
            del_default_route=True,
            daemons=startup_daemon_list,
            use_ssh_key = use_ssh_key,
            ))
        f_startup.close()


# Files for indvidual node configuration

        #TODO: this needs to be created for each netkit host machine
        f_lab = open(os.path.join(lab_dir(), "lab.conf"), 'wb')

        lab_conf = {}
        tap_list_strings = {}

        ibgp_routers = ank.ibgp_routers(self.network)
        ebgp_routers = ank.ebgp_routers(self.network)
        igp_graph = ank.igp_graph(self.network)

        dns_servers = set(self.network.dns_servers())
        routers = set(self.network.routers())

        for node in self.network.devices():
            #TODO: see if rtr label is still needed, if so replace with
            # appropriate naming module function
            rtr_folder_name = ank.rtr_folder_name(self.network, node)

            # sshd options
            f_sshd = open( os.path.join(sshd_dir(self.network, node), "sshd_config"), 'wb')
            f_sshd.write(sshd_template.render())
            f_sshd.close()

            lab_conf[rtr_folder_name] = []
            startup_daemon_list = ["zebra"]
            startup_int_list = []

            # convert tap list from ips into strings
            # tap_int_id cannot conflict with already allocated interfaces
            # assume edges number sequentially, so next free int id is number of
            # edges
            node_tap_id = self.tap_interface_id(self.network, node)
            tap_list_strings[rtr_folder_name] = (node_tap_id,
                                                 self.network[node].get('tap_ip'))

            if node in dns_servers:
                startup_daemon_list.append("bind")
                dns_memory = 64 # Allocate more memory to DNS server 
                #TODO: remove key, val and make it just key: val
                lab_conf[rtr_folder_name].append( ('mem', dns_memory))

            if config.settings['Netkit']['ssh key']:
                f_auth_keys = open(os.path.join(dot_ssh_dir(self.network, node), "authorized_keys"), "wb")
                f_auth_keys.write(config.settings['Netkit']['ssh key'])
                f_auth_keys.close()

            # Zebra Daemons
            zebra_daemon_list = []
            f_zdaemons = open( os.path.join(zebra_dir(self.network, node),
                                            "daemons"), 'wb')
# Always start Zebra
            zebra_daemon_list.append("zebra")

            if igp_graph.degree(node) > 0:
                zebra_daemon_list.append("ospfd") # Only start IGP process if IGP links
            if (node in ibgp_routers) or (node in ebgp_routers):
                zebra_daemon_list.append("bgpd")

            f_zdaemons.write(zebra_daemons_template.render(
                entryList = zebra_daemon_list,
            ))
            f_zdaemons.close()
# MOTD
            f_zmotd = open( os.path.join(zebra_dir(self.network, node),
                                            "motd.txt"), 'wb')

            f_zmotd.write(motd_template.render(
                date = date,
                version = ank_version,
                password = self.zebra_password,
            ))

            # Main Zebra config
            f_z = open( os.path.join(zebra_dir(self.network, node),
                                     "zebra.conf"), 'wb')
            f_z.write( zebra_template.render(
                hostname = node.device_hostname,
                password = self.zebra_password,
                enable_password = self.zebra_password,
                use_snmp = True,
                use_debug = True,
                ))
            f_z.close()

            # Loopback interface
            lo_ip = self.network.lo_ip(node)
            startup_int_list.append({
                'int':          'lo:1',
                'ip':           str(lo_ip.ip),
                'netmask':      str(lo_ip.netmask),
            })

            # Ethernet interfaces
            for link in self.network.links(node):
                int_id = self.interface_id(link.id)
                subnet = link.subnet

                # replace the / from subnet label
                collision_domain = "%s.%s" % (subnet.ip, subnet.prefixlen)
    
                # lab.conf has id in form host[0]=... for eth0 of host
                lab_conf[rtr_folder_name].append((link.id, collision_domain))
                startup_int_list.append({
                    'int':          int_id,
                    'ip':           str(link.ip),
                    'netmask':      str(subnet.netmask),
                    'broadcast':    str(subnet.broadcast),
                })

            default_route = None
            if node.is_server:
                default_route = ank.default_route(node)
# add default_route for server to router

            chown_bind = False
            if node in ank.dns_servers(self.network):
                chown_bind = True

            #Write startup file for this router
            f_startup = open( os.path.join(netkit_dir(self.network, node),
                "{0}.startup".format(rtr_folder_name)), 'wb')

            f_startup.write(startup_template.render(
                interfaces=startup_int_list,
                add_localhost=True,
                #don't send out the tap interface
                del_default_route=True,
                default_route = default_route,
                daemons=startup_daemon_list,
                chown_bind = chown_bind,
                ))
            f_startup.close()

        # Write lab file for whole lab
        f_lab.write(lab_template.render(
            conf = lab_conf,
            tapHost = tap_host,
            tapList = tap_list_strings,
            lab_description = "AutoNetkit generated lab",
            lab_version = date,
            #TODO: get this from config file
            lab_email = "*****@*****.**",
            lab_author = "AutoNetkit %s" % ank_version,
            #TODO: get this from config file
            lab_web =  "www.autonetkit.org",
        ))
Example #25
0
    def plot(self, matplotlib=False): 
        """Plot the network topology

        Args:
           None

        Returns:
           None

        Example usage:

        >>> inet = ank.internet.Internet()
        >>> inet.plot()

        """              
        LOG.info("Plotting")      
        matplotlib = matplotlib or config.settings['Plotting']['matplotlib']
        if matplotlib:
            ank.plot(self.network)        
        ank.jsplot(self.network)        
        ank.summarydoc(self.network)
        ank.dump_graph(self.network.graph, os.path.join(config.log_dir, "physical"))
        physical_single_edge = nx.Graph(self.network.graph)
        ank.dump_graph(physical_single_edge, os.path.join(config.log_dir, "physical_single_edge"))
        ibgp_graph = ank.get_ibgp_graph(self.network)
        ebgp_graph = ank.get_ebgp_graph(self.network)
        ank.dump_graph(ibgp_graph, os.path.join(config.log_dir, "ibgp"))
        ank.dump_graph(ebgp_graph, os.path.join(config.log_dir, "ebgp"))
        g_dns = nx.Graph(self.network.g_dns)
        ank.dump_graph(g_dns, os.path.join(config.log_dir, "dns"))
        ank.dump_graph(self.network.g_dns_auth, os.path.join(config.log_dir, "dns_auth"))
        ank.dump_identifiers(self.network, os.path.join(config.log_dir, "identifiers.txt"))
Example #26
0
File: ip.py Project: iainwp/ank_le
def allocate_subnets(network, address_block=IPNetwork("10.0.0.0/8")):

    """Allocates subnets and IP addresses to links in the network.

    Args:
        address_block (IPNetwork):  The address block to use.

    Returns:
        ip_as_allocs

    Example usage:

    >>> network = ank.example_multi_as()
    >>> allocate_subnets(network)
    >>> print ank.debug_nodes(network.graph, "lo_ip")
    {'1a.AS1': IPNetwork('10.0.0.32/32'),
     '1b.AS1': IPNetwork('10.0.0.33/32'),
     '1c.AS1': IPNetwork('10.0.0.34/32'),
     '2a.AS2': IPNetwork('10.1.0.64/32'),
     '2b.AS2': IPNetwork('10.1.0.65/32'),
     '2c.AS2': IPNetwork('10.1.0.66/32'),
     '2d.AS2': IPNetwork('10.1.0.67/32'),
     '3a.AS3': IPNetwork('10.2.0.0/32')}
    
    >>> print ank.debug_edges(network.graph, "ip")
    {('1a.AS1', '1b.AS1'): IPAddress('10.0.0.10'),
     ('1a.AS1', '1c.AS1'): IPAddress('10.0.0.22'),
     ('1b.AS1', '1a.AS1'): IPAddress('10.0.0.9'),
     ('1b.AS1', '1c.AS1'): IPAddress('10.0.0.26'),
     ('1b.AS1', '3a.AS3'): IPAddress('10.0.0.17'),
     ('1c.AS1', '1a.AS1'): IPAddress('10.0.0.21'),
     ('1c.AS1', '1b.AS1'): IPAddress('10.0.0.25'),
     ('1c.AS1', '2a.AS2'): IPAddress('10.0.0.29'),
     ('2a.AS2', '1c.AS1'): IPAddress('10.0.0.30'),
     ('2a.AS2', '2b.AS2'): IPAddress('10.1.0.10'),
     ('2a.AS2', '2d.AS2'): IPAddress('10.1.0.26'),
     ('2b.AS2', '2a.AS2'): IPAddress('10.1.0.9'),
     ('2b.AS2', '2c.AS2'): IPAddress('10.1.0.18'),
     ('2c.AS2', '2b.AS2'): IPAddress('10.1.0.17'),
     ('2c.AS2', '2d.AS2'): IPAddress('10.1.0.30'),
     ('2d.AS2', '2a.AS2'): IPAddress('10.1.0.25'),
     ('2d.AS2', '2c.AS2'): IPAddress('10.1.0.29'),
     ('2d.AS2', '3a.AS3'): IPAddress('10.1.0.33'),
     ('3a.AS3', '1b.AS1'): IPAddress('10.0.0.18'),
     ('3a.AS3', '2d.AS2'): IPAddress('10.1.0.34')}

    
    >>> print ank.debug_edges(network.graph, "sn")
    {('1a.AS1', '1b.AS1'): IPNetwork('10.0.0.8/30'),
     ('1a.AS1', '1c.AS1'): IPNetwork('10.0.0.20/30'),
     ('1b.AS1', '1a.AS1'): IPNetwork('10.0.0.8/30'),
     ('1b.AS1', '1c.AS1'): IPNetwork('10.0.0.24/30'),
     ('1b.AS1', '3a.AS3'): IPNetwork('10.0.0.16/30'),
     ('1c.AS1', '1a.AS1'): IPNetwork('10.0.0.20/30'),
     ('1c.AS1', '1b.AS1'): IPNetwork('10.0.0.24/30'),
     ('1c.AS1', '2a.AS2'): IPNetwork('10.0.0.28/30'),
     ('2a.AS2', '1c.AS1'): IPNetwork('10.0.0.28/30'),
     ('2a.AS2', '2b.AS2'): IPNetwork('10.1.0.8/30'),
     ('2a.AS2', '2d.AS2'): IPNetwork('10.1.0.24/30'),
     ('2b.AS2', '2a.AS2'): IPNetwork('10.1.0.8/30'),
     ('2b.AS2', '2c.AS2'): IPNetwork('10.1.0.16/30'),
     ('2c.AS2', '2b.AS2'): IPNetwork('10.1.0.16/30'),
     ('2c.AS2', '2d.AS2'): IPNetwork('10.1.0.28/30'),
     ('2d.AS2', '2a.AS2'): IPNetwork('10.1.0.24/30'),
     ('2d.AS2', '2c.AS2'): IPNetwork('10.1.0.28/30'),
     ('2d.AS2', '3a.AS3'): IPNetwork('10.1.0.32/30'),
     ('3a.AS3', '1b.AS1'): IPNetwork('10.0.0.16/30'),
     ('3a.AS3', '2d.AS2'): IPNetwork('10.1.0.32/30')}
    
    """
    LOG.debug("Allocating subnets")
    # Initialise IP list to be graph edge format
    ip_as_allocs = {}

    # allocates subnets to the edges and loopback in network graph
    # Put into dictionary, indexed by ASN (the name attribute of each as graph)
    # for easy appending of eBGP links
    asgraphs = dict((my_as.asn, my_as) for my_as in ank.get_as_graphs(network))

    # Simple method: break address_block into a /16 for each network
    #TODO: check this is feasible - ie against required host count
    subnet_list = address_block.subnet(16)

    ebgp_edges = ank.ebgp_edges(network)
    visited_ebgp_edges = set()
    for src, dst in sorted(ebgp_edges):
      # Add the dst (external peer) to AS of src node so they are allocated
        # a subnet. (The AS choice is arbitrary)
        if (dst, src) in visited_ebgp_edges:
            continue
        src_as = asgraphs[src.asn]
        src_as.add_edge(src, dst)
# record for DNS purposes
        ank.dns_advertise_link(src, dst)
        visited_ebgp_edges.add( (src, dst))

    for my_as in sorted(asgraphs.values(), key = lambda x: x.asn):
        asn = my_as.asn
        as_subnet =  subnet_list.next()

        as_internal_nodes = [n for n in sorted(my_as.nodes()) if network.asn(n) == asn]

        host_count = my_as.number_of_nodes()

        # record this subnet
        ip_as_allocs[my_as.asn] = as_subnet

        # split into subnets for loopback and ptp
        ptp_count = my_as.number_of_edges()

        # Now subnet network into subnets of the larger of these two
        # TODO tidy up this comment
        # Note ptp subnets required a /30 ie 4 ips
        req_sn_count = max(host_count, 4*ptp_count)

        if req_sn_count == 0:
            # Nothing to allocate for this AS
            continue

        req_pref_len = int(32 - math.ceil(math.log(req_sn_count, 2)) )
        # Subnet as subnet into subnets of this size
        sn_iter = as_subnet.subnet(req_pref_len)
        # And allocate a subnet for each ptp and loopback

        if ptp_count > 0:
            # Don't allocate a ptp subnet if there are no ptp links
            ptp_subnet = sn_iter.next()
        loopback_subnet = sn_iter.next()

        if ptp_count > 0:
            link_subnet = ptp_subnet.subnet(30)

            # Now iterate over edges in this as and apply
            for src, dst in sorted(my_as.edges()):
                # Note we apply this back to the main graph
                # not to the as graph!

                subnet = link_subnet.next()

                #TODO: fix the technique for accessing edges
                # as it breaks with multigraphs, as it creates a new edge
                if network.asn(dst) != asn:
# eBGP link where dst has IP allocated from subnet of this AS
                    network.graph[dst][src]['remote_as_sn_block'] = True

                network.graph[src][dst]['sn'] = subnet
                network.graph[dst][src]['sn'] = subnet
                # allocate an ip to each end
                network.graph[src][dst]['ip'] = subnet[1]
                network.graph[dst][src]['ip'] = subnet[2]

        # Allocate an loopback interface to each router
        #TODO: check if next step is necessary
        loopback_ips = loopback_subnet.subnet(32)
    
        for rtr in sorted(as_internal_nodes):
            lo_ip = loopback_ips.next()
            network.graph.node[rtr]['lo_ip'] = lo_ip

    network.ip_as_allocs = ip_as_allocs
Example #27
0
File: ip.py Project: iainwp/ank_le
def alloc_tap_hosts(network, address_block=IPNetwork("172.16.0.0/16")):
    """Allocates TAP IPs for connecting using Netkit

    >>> network = ank.example_multi_as()
    >>> alloc_tap_hosts(network)
    >>> print ank.debug_nodes(network.graph, "tap_ip")
    {'1a.AS1': IPAddress('172.16.1.1'),
     '1b.AS1': IPAddress('172.16.1.2'),
     '1c.AS1': IPAddress('172.16.1.3'),
     '2a.AS2': IPAddress('172.16.2.1'),
     '2b.AS2': IPAddress('172.16.2.2'),
     '2c.AS2': IPAddress('172.16.2.3'),
     '2d.AS2': IPAddress('172.16.2.4'),
     '3a.AS3': IPAddress('172.16.3.1')}
    """
    LOG.debug("Allocating TAP hosts")
    network.tap_sn = address_block

    as_graph = ank.get_as_graphs(network)
    # Try allocating /24 to each subnet as cleaner
    # then check if this is feasible 
    prefix_len = 24
    # Check this will fit into provided network
    #TODO: check what these 2 lines of code are doing
    if prefix_len <= address_block.prefixlen:
        # Try with smaller prefix len
        prefix_len += 1
   
    # Number of bits required for AS subnet (network bits)
    # need to add one on for tap host subnet, eg 172.16.0.0 and 172.16.0.1 hosts
    req_network_bits = int( math.ceil(math.log(len(as_graph) + 1, 2)) )
    upper_bound = prefix_len 
    # Find the subnet with the most hosts in it

    max_req_hosts = max(len(my_as) for my_as in as_graph)
    req_host_bits = int(math.ceil(math.log(max_req_hosts, 2)))
#TODO: there is an off by one error here mking the tap subnets /9 rather than /8
# so end up with 172.16.64.1 and 172.16.128.1 not .1 .2 etc

    # Check subnetting is feasible
    lower_bound = address_block.prefixlen + req_network_bits
    upper_bound = lower_bound + req_host_bits
    if upper_bound > 32:
        #TODO: throw error
        print "Unfeasible tap subnet allocation"
        return
    else:
        prefix_len = lower_bound

    # Neatness: use a Class C, B, A (in order of preference) if feasible
    for x in [24, 16, 8]:
        if lower_bound < x < upper_bound:
            prefix_len = x
        elif lower_bound < upper_bound < x:
# eg both fit inside a class A, B or C
            prefix_len = x

    def set_tap_ips(network, nodes, host_ips):
        # Allocate in order of node name
        for node in sorted(nodes, key=network.label):
            network.graph.node[node]['tap_ip'] = host_ips.next()
        return

    # assign /required subnet size to each as then append pops to list
    if len(as_graph) == 1:
        # Single AS, don't need to subnet the address block
        host_ips = address_block.iter_hosts()
        network.tap_host = host_ips.next()
        _ = host_ips.next() # IP of tap VM
        my_as = as_graph.pop()
        # Allocate directly from address block
        set_tap_ips(network, my_as.nodes(), host_ips)
    else:
        sn_iter = address_block.subnet(prefix_len)
        tap_host_subnet = sn_iter.next()
        #TODO: make consistent with previous section [1] vs .next()
        network.tap_host = tap_host_subnet[1]
        for my_as in as_graph:
            LOG.debug("Setting tap IPs for %s" % my_as.asn)
            host_ips = sn_iter.next().iter_hosts()
            set_tap_ips(network, my_as.nodes(), host_ips)
        
    #TODO: make this a generic function which allocates items from an
    # generator to each node in the specified network
    # rather than IP addresses specifically
    return
Example #28
0
    def configure_igp(self):
        """Generates IGP specific configuration files (eg ospfd)"""
        LOG.debug("Configuring IGP")
        template = lookup.get_template("quagga/ospf.mako")
        default_weight = 1

        # configures IGP for each AS
        as_graphs = ank.get_as_graphs(self.network)
        for my_as in as_graphs:
            asn = my_as.asn
            LOG.debug("Configuring IGP for AS %s " % asn)
            if my_as.number_of_edges() == 0:
                # No edges, nothing to configure
                LOG.debug("Skipping IGP for AS%s as no internal links" % asn)
                continue

            for router in self.network.routers(asn):
                #TODO: can probably through most of these straight into the template and use properties there!

                interface_list = []
                network_list = []

                # Add loopback info
                lo_ip = router.lo_ip 
                interface_list.append ( {'id':  "lo", 'weight':  1,
                                        'remote_router': "NA (loopback)",
                                        'remote_int': "Loopback"})
                network_list.append ( { 'cidr': lo_ip.cidr, 'ip': lo_ip.ip,
                                    'netmask': lo_ip.netmask,
                                    'area': 0, 'remote_ip': "Loopback" })

                for link in self.network.links(router, my_as):

                    int_id = self.interface_id(link.id)
                    weight = link.weight or default_weight
                    interface_list.append ({ 'id':  int_id,
                                            'weight': weight,
                                            'remote_router': link.remote_host, } )

                    # fetch and format the ip details
                    subnet = link.subnet
                    local_ip = link.local_ip
                    remote_ip = link.remote_ip
                    network_list.append ( { 'cidr': subnet.cidr, 'ip': local_ip,
                                        'netmask': subnet.netmask,
                                        'remote_ip': remote_ip, 'area': 0, } )

                #TODO: see if need to use router-id for ospfd in quagga
                f_handle = open( os.path.join(zebra_dir(self.network, router),
                        "ospfd.conf"), 'wb')

                f_handle.write(template.render
                               (
                                   hostname = router.device_hostname,
                                   password = self.zebra_password,
                                   enable_password = self.zebra_password,
                                   interface_list = interface_list,
                                   network_list = network_list,
                                   routerID = router,
                                   use_igp = True,
                                   logfile = "/var/log/zebra/ospfd.log",
                                   use_debug = False,
                               ))
Example #29
0
def router_dir(network, rtr):
    """Returns path for router rtr"""
    foldername = ank.rtr_folder_name(network, rtr)
    return os.path.join(netkit_dir(network, rtr), foldername)
Example #30
0
    def configure_bgp(self):
        """Generates BGP specific configuration files"""

        ip_as_allocs = ank.get_ip_as_allocs(self.network)

        LOG.debug("Configuring BGP")
        template = lookup.get_template("quagga/bgp.mako")

        route_maps = {}

        ibgp_graph = ank.get_ibgp_graph(self.network)
        ebgp_graph = ank.get_ebgp_graph(self.network)
        physical_graph = self.network.graph

        for my_as in ank.get_as_graphs(self.network):
            asn = my_as.asn
            LOG.debug("Configuring IGP for AS %s " % asn)
            # get nodes ie intersection
            #H = nx.intersection(my_as, ibgp_graph)
            # get ibgp graph that contains only nodes from this AS

            for router in self.network.routers(asn):
                bgp_groups = {}
                route_maps = []
                ibgp_neighbor_list = []
                ibgp_rr_client_list = []
                route_map_groups = {}

                if router in ibgp_graph:
                        for src, neigh, data in ibgp_graph.edges(router, data=True):
                            route_maps_in = self.network.g_session[neigh][router]['ingress']
                            rm_group_name_in = None
                            if len(route_maps_in):
                                rm_group_name_in = "rm_%s_in" % neigh.folder_name
                                route_map_groups[rm_group_name_in] = [match_tuple 
                                        for route_map in route_maps_in
                                        for match_tuple in route_map.match_tuples]

                            route_maps_out = self.network.g_session[router][neigh]['egress']
                            rm_group_name_out = None
                            if len(route_maps_out):
                                rm_group_name_in = "rm_%s_out" % neigh.folder_name
                                route_map_groups[rm_group_name_out] = [match_tuple 
                                        for route_map in route_maps_out
                                        for match_tuple in route_map.match_tuples]

                            description = data.get("rr_dir") + " to " + ank.fqdn(self.network, neigh)
                            if data.get('rr_dir') == 'down':
                                ibgp_rr_client_list.append(
                                        {
                                            'id':  self.network.lo_ip(neigh).ip,
                                            'description':      description,
                                            'route_maps_in': rm_group_name_in,
                                            'route_maps_out': rm_group_name_out,
                                            })
                            elif (data.get('rr_dir') in set(['up', 'over', 'peer'])
                                    or data.get('rr_dir') is None):
                                ibgp_neighbor_list.append(
                                        {
                                            'id':  self.network.lo_ip(neigh).ip,
                                            'description':      description,
                                            'route_maps_in': rm_group_name_in,
                                            'route_maps_out': rm_group_name_out,
                                            })

                        bgp_groups['internal_peers'] = {
                            'type': 'internal',
                            'neighbors': ibgp_neighbor_list
                            }
                        if len(ibgp_rr_client_list):
                            bgp_groups['internal_rr'] = {
                                    'type': 'internal',
                                    'neighbors': ibgp_rr_client_list,
                                    'cluster': self.network.lo_ip(router).ip,
                                    }

                if router in ebgp_graph:
                    external_peers = []
                    for peer in ebgp_graph.neighbors(router):
                        route_maps_in = self.network.g_session[peer][router]['ingress']
                        rm_group_name_in = None
                        if len(route_maps_in):
                            rm_group_name_in = "rm_%s_in" % peer.folder_name
                            route_map_groups[rm_group_name_in] = [match_tuple 
                                    for route_map in route_maps_in
                                    for match_tuple in route_map.match_tuples]

# Now need to update the sequence numbers for the flattened route maps

                        route_maps_out = self.network.g_session[router][peer]['egress']
                        rm_group_name_out = None
                        if len(route_maps_out):
                            rm_group_name_out = "rm_%s_out" % peer.folder_name
                            route_map_groups[rm_group_name_out] = [match_tuple 
                                    for route_map in route_maps_out
                                    for match_tuple in route_map.match_tuples]

                        peer_ip = physical_graph[peer][router]['ip'] 

                        external_peers.append({
                            'id': peer_ip, 
                            'route_maps_in': rm_group_name_in,
                            'route_maps_out': rm_group_name_out,
                            'peer_as': self.network.asn(peer)})
                    bgp_groups['external_peers'] = {
                            'type': 'external', 
                            'neighbors': external_peers}

# Ensure only one copy of each route map, can't use set due to list inside tuples (which won't hash)
# Use dict indexed by name, and then extract the dict items, dict hashing ensures only one route map per name
                community_lists = {}
                prefix_lists = {}
                node_bgp_data = self.network.g_session.node.get(router)
                if node_bgp_data:
                    community_lists = node_bgp_data.get('tags')
                    prefix_lists = node_bgp_data.get('prefixes')
                policy_options = {
                'community_lists': community_lists,
                'prefix_lists': prefix_lists,
                'route_maps': route_map_groups,
                }
            
                f_handle = open(os.path.join(zebra_dir(self.network, router),
                                                "bgpd.conf"),'wb')

                #TODO: remove community_lists and prefix_lists as they are put into policy_options
                f_handle.write(template.render(
                        hostname = router.device_hostname,
                        asn = self.network.asn(router),
                        password = self.zebra_password,
                        enable_password = self.zebra_password,
                        router_id = self.network.lo_ip(router).ip,
                        community_lists = community_lists,
                        policy_options = policy_options,
                        prefix_lists = prefix_lists,
                        #TODO: see how this differs to router_id
                        identifying_loopback = self.network.lo_ip(router),
                        bgp_groups = bgp_groups,
                        ibgp_neighbor_list = ibgp_neighbor_list,
                        ibgp_rr_client_list = ibgp_rr_client_list,
                        route_maps = route_maps,
                        logfile = "/var/log/zebra/bgpd.log",
                        debug=True,
                        use_debug=True,
                        dump=False,
                        snmp=False,
                        interfaces = self.configure_interfaces(router)
                ))