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, ))
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, ))
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, ))
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", ))
def configure_rpki(self): """ Configures RPKI servers""" LOG.info("Configuring RPKI servers: %s" % self.target) rpki_template = lookup.get_template("junos/rpki.mako") yaml_template = lookup.get_template("junos/yaml.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) as_prefixes = defaultdict(list) rpki_tree = defaultdict(dict) rpki_server_list = [] for router in self.network.graph.nodes(): # collect prefixes of the AS as_number = str(self.network.asn(router)) lo_ip = self.network.lo_ip(router) lo_ip_ip = str(lo_ip.ip) lo_ip_prefixlen = str(lo_ip.prefixlen) loopback_ip = str(lo_ip_ip+"/"+lo_ip_prefixlen) as_prefixes[as_number].append(loopback_ip) for src, dst, data in self.network.graph.edges(router, data=True): subnet = str(data['sn']) if not subnet in as_prefixes[as_number]: as_prefixes[as_number].append(subnet) rpki_root_lst = [n for n in self.network.g_rpki.nodes() if 'root' in self.network.rpki_root(n)] if len(rpki_root_lst) > 1: LOG.warn("%s rpki_root servers configured, only one is allowed" %len(rpki_root_lst)) rpki_root_str = ', '.join(rpki_root_lst) rpki_root_folder = ''.join([n if not "." in n else "_" for n in rpki_root_str]) for rpki_server in self.network.rpki_servers(): #check interfaces feasible rpki_children = {} asn = self.network.asn(rpki_server) rpki_aggregate = self.network.ip_as_allocs[asn] rpki_server_list.append(rpki_server) rpki_tree[rpki_server] = defaultdict(dict) rpki_tree[rpki_server]['fqdn'] = rpki_server for neighbor in self.network.g_rpki.neighbors(str(rpki_server)): nbr_list = [n for n in neighbor] # # check the relationships between rpki nodes relationship = self.network.g_rpki.get_edge_data(str(rpki_server), str(neighbor)) if 'children' in relationship['relation']: rpki_tree[rpki_server]['children'][neighbor] = defaultdict(dict) rpki_tree[rpki_server]['children'][neighbor]['asn'] = self.network.asn(neighbor) rpki_tree[rpki_server]['children'][neighbor]['rtr_folder'] = ''.join([n if not "." in n else "_" for n in nbr_list]) rpki_tree[rpki_server]['children'][neighbor]['fqdn'] = neighbor rpki_tree[rpki_server]['children'][neighbor]['aggregate'] = self.network.ip_as_allocs[self.network.asn(neighbor)] rpki_tree[rpki_server]['children'][neighbor]['prefixes'] = as_prefixes[str(self.network.asn(neighbor))] def find_children(parent): for node in rpki_tree: if str(parent) in str(node): tmp_dict = rpki_tree[node] for i in tmp_dict: if 'children' in i: return [j for j in tmp_dict[i]] # write yaml file for yamltest.py # TODO: write this in mako yaml_file = yaml_path() with open( yaml_file, 'wb' ) as f_yaml: yaml_string = "" yaml_string += ("name: %s\ncrl_interval: 5m\nregen_margin: 2m\nvalid_for: 2d\nkids:" %rpki_root_folder) tree_iter = rpki_tree.items() for node, data in tree_iter: if rpki_root_str in str(data['fqdn']): indent = " " count = 1 root_iter = data.items() for key, value in root_iter: if isinstance(value,dict): for i in value: yaml_string += "\n%s- name: %s" % (indent,value[i]['rtr_folder']) yaml_string += "\n%s asn: %s" % (indent, value[i]['asn']) yaml_string += "\n%s ipv4: %s" % (indent, value[i]['aggregate']) yaml_string += "\n%s roa_request:" % indent for prefix in value[i]['prefixes']: yaml_string += "\n%s- asn: %s" % (indent*3, value[i]['asn']) yaml_string += "\n%s ipv4: %s" % (indent*3, prefix) composer = ank.ChildComposer(value[i]['fqdn'], indent*3*count, rpki_tree) child_entries = composer.search() if len(child_entries): yaml_string += "\n%s kids:" %indent yaml_string += child_entries # print yaml_string f_yaml.write(yaml_string) # for rpki_server in self.network.rpki_servers(): #check interfaces feasible if self.network.graph.in_degree(rpki_server) > self.interface_limit: LOG.warn("%s exceeds interface count: %s (max %s)" % (self.network.label(rpki_server), self.network.graph.in_degree(rpki_server), self.interface_limit)) asn = self.network.asn(rpki_server) network_list = [] lo_ip = self.network.lo_ip(rpki_server) interfaces,static_routes = self.configure_interfaces(rpki_server) igp_interfaces = self.configure_igp(rpki_server, igp_graph, ebgp_graph) (bgp_groups, policy_options) = self.configure_bgp(rpki_server, 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) server_filename = router_conf_path(self.network, rpki_server) with open( server_filename, 'wb') as f_jun: f_jun.write( rpki_template.render( hostname = rpki_server.hostname, 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, ))