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
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
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
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
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
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)
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, ))
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) ))
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)
def fqdn(self, node): """Shortcut to fqdn""" return ank.fqdn(self, node)
def configure_dynagen(self): """Generates dynagen specific configuration files.""" LOG.info("Configuring Dynagen") # Location of IOS binary # Set up routers lab_template = lookup.get_template("dynagen/topology.mako") # Counter starting at 2000, eg 2000, 2001, 2002, etc console_ports = itertools.count(2000) #NOTE this must be a full path! server_config_dir = os.path.join(config.settings['Dynagen']['working dir'], lab_dir()) working_dir ="/tmp" #TODO: need nice way to map ANK graph into feasible hardware graph #TODO: see what chassis is used for chassis = config.settings['Dynagen']['model'] model = config.settings['Dynagen']['model'] slots = config.settings['Dynagen']['Slots'] options = config.settings['Dynagen']['Options'] # ugly alias #TODO: remove this graph = self.network.graph all_router_info = {} #TODO: make this use dynagen tagged nodes for router in sorted(self.network.routers()): router_info = {} data = graph.node[router] router_info['hostname'] = router.fqdn rtr_console_port = console_ports.next() router_info['console'] = rtr_console_port self.network.graph.node[router]['dynagen_console_port'] = rtr_console_port #TODO: tidy this up - want relative reference to config dir rtr_conf_file = os.path.join("configs", "%s.conf" % router.folder_name) #router_info['cnfg'] = rtr_conf_file # Absolute configs for remote dynagen deployment #TODO: make this dependent on remote host - if localhost then don't use # and if do use, then rtr_conf_file_with_path = os.path.join(server_config_dir, rtr_conf_file) #router_info['cnfg'] = os.path.abspath(rtr_conf_file_with_path) router_info['cnfg'] = rtr_conf_file_with_path # Max of 3 connections out # todo: check symmetric router_links = [] router_info['slot1'] = "NM-4E" for src, dst, data in sorted(graph.edges(router, data=True)): if dst.is_router: # Src is node, dst is router connected to. Link data in data local_id = data['id'] remote_id = graph.edge[dst][src]['id'] local_cisco_id = self.dynagen_interface_name(self.int_id(local_id)) remote_cisco_id = self.dynagen_interface_name(self.int_id(remote_id)) remote_hostname = ank.fqdn(self.network, dst) router_links.append( (local_cisco_id, remote_cisco_id, remote_hostname)) # Store links router_info['links'] = router_links # and store info all_router_info[router] = router_info #pprint.pprint(all_router_info) lab_file = os.path.join(lab_dir(), "lab.net") with open( lab_file, 'wb') as f_lab: f_lab.write( lab_template.render( image = self.image, hypervisor_port = self.hypervisor_port, hypervisor_server = self.hypervisor_server, all_router_info = all_router_info, working_dir = working_dir, chassis = chassis, model = model, slots = slots, options = options, )) return
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 IOS bgp peerings # route maps 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, } return (bgp_groups, policy_options)
def jsplot(network): """ Plot the network """ plot_dir = config.plot_dir if not os.path.isdir(plot_dir): os.mkdir(plot_dir) jsplot_dir = os.path.join(plot_dir, "jsplot") if not os.path.isdir(jsplot_dir): os.mkdir(jsplot_dir) js_template = lookup.get_template("arborjs/main_js.mako") css_template = lookup.get_template("arborjs/style_css.mako") html_template = lookup.get_template("arborjs/index_html.mako") ank_css_template = lookup.get_template("autonetkit/style_css.mako") #TODO: tidy these up with the embedded network in node name node_list = ( (node.fqdn, {'label': network.fqdn(node)}) for node in network.graph.nodes()) edge_list = list( (src.fqdn, dst.fqdn, {}) for (src, dst, data) in network.graph.edges(data=True)) js_files = [] timestamp = time.strftime("%Y/%m/%d %H:%M:%S", time.localtime()) js_filename = os.path.join(jsplot_dir, "main.js") js_files.append("main.js") with open( js_filename, 'w') as f_js: f_js.write( js_template.render( node_list = node_list, edge_list = edge_list, physical_graph = True, )) js_filename = os.path.join(jsplot_dir, "ip.js") js_files.append("ip.js") node_list = [] for node in network.graph.nodes(): # Set label to be FQDN, so don't have multiple "Router A" nodes etc data = { 'label': "%s %s" % (ank.fqdn(network, node), network.lo_ip(node).ip)} node_list.append( (node.fqdn, data)) edge_list = list( (src.fqdn, dst.fqdn, data['sn']) for (src, dst, data) in network.graph.edges(data=True)) with open( js_filename, 'w') as f_js: f_js.write( js_template.render( node_list = node_list, edge_list = edge_list, physical_graph = True, )) js_filename = os.path.join(jsplot_dir, "igp.js") js_files.append("igp.js") node_list = [] for node in network.graph.nodes(): if not node.igp_link_count: # no IGP links, don't add to plot continue # Set label to be FQDN, so don't have multiple "Router A" nodes etc data = { 'label': "%s" % node.fqdn} node_list.append( (node.fqdn, data)) edge_list = list( (src.fqdn, dst.fqdn, data.get('weight')) for (src, dst, data) in network.graph.edges(data=True) if src.asn == dst.asn) with open( js_filename, 'w') as f_js: f_js.write( js_template.render( node_list = node_list, edge_list = edge_list, physical_graph = True, )) #TODO: work out how to do multiple on one page ebgp_graph = ank.get_ebgp_graph(network) labels = dict( (n, network.label(n)) for n in ebgp_graph) nx.relabel_nodes(ebgp_graph, labels, copy=False) ebgp_filename = os.path.join(jsplot_dir, "ebgp.js") js_files.append("ebgp.js") with open( ebgp_filename, 'w') as f_js: f_js.write( js_template.render( node_list = ebgp_graph.nodes(data=True), edge_list = ebgp_graph.edges(data=True), overlay_graph = True, )) ibgp_graph = ank.get_ibgp_graph(network) node_list = [] for node in ibgp_graph.nodes(): # Set label to be FQDN, so don't have multiple "Router A" nodes etc data = { 'label': "%s (%s)" % (node.fqdn, network.graph.node[node].get("ibgp_level"))} node_list.append( (node.fqdn, data)) edge_list = ibgp_graph.edges(data=True) edge_list = list( (src.fqdn, dst.fqdn, data.get("rr_dir")) for (src, dst, data) in edge_list) ibgp_filename = os.path.join(jsplot_dir, "ibgp.js") js_files.append("ibgp.js") with open( ibgp_filename, 'w') as f_js: f_js.write( js_template.render( node_list = node_list, edge_list = edge_list, physical_graph = True, )) #TODO: clarify difference of physical_graph and overlay_graph #TODO: see if js_files ever used dns_graph = ank.get_dns_graph(network) node_list = [] for node in dns_graph.nodes(): # Set label to be FQDN, so don't have multiple "Router A" nodes etc data = { 'label': "%s (%s)" % (node.fqdn, dns_graph.node[node].get("level"))} node_list.append( (node.fqdn, data)) dns_filename = os.path.join(jsplot_dir, "dns.js") edge_list = dns_graph.edges(data=True) #edge_list = list( (src.fqdn, dst.fqdn, data.get('dns_dir')) for (src, dst, data) in edge_list) edge_list = list( (src.fqdn, dst.fqdn, '') for (src, dst, data) in edge_list) js_files.append("dns.js") with open( dns_filename, 'w') as f_js: f_js.write( js_template.render( node_list = node_list, edge_list = edge_list, physical_graph = True, )) dns_auth_graph = ank.get_dns_auth_graph(network) node_list = [] for node in dns_auth_graph.nodes(): # Set label to be FQDN, so don't have multiple "Router A" nodes etc data = { 'label': "%s" % node.label} node_list.append( (node.fqdn, data)) dns_filename = os.path.join(jsplot_dir, "dns_auth.js") edge_list = dns_auth_graph.edges(data=True) edge_list = list( (src.fqdn, dst.fqdn, data) for (src, dst, data) in edge_list) js_files.append("dns_auth.js") with open( dns_filename, 'w') as f_js: f_js.write( js_template.render( node_list = node_list, edge_list = edge_list, physical_graph = True, )) #TODO: add timestamps to plots # put html file in main plot directory #TODO: parameterised/variable the css location plot_width = config.settings['Plotting']['jsplot width'] plot_height = config.settings['Plotting']['jsplot height'] html_filename = os.path.join(plot_dir, "plot.html") with open( html_filename, 'w') as f_html: f_html.write( html_template.render( js_file = "main.js", timestamp=timestamp, plot_width = plot_width, plot_height = plot_height, title = "Physical Network", css_filename = "./ank_style.css",)) html_filename = os.path.join(plot_dir, "ip.html") with open( html_filename, 'w') as f_html: f_html.write( html_template.render( js_file = "ip.js", timestamp=timestamp, plot_width = plot_width, plot_height = plot_height, title = "IP", css_filename = "./ank_style.css",)) html_filename = os.path.join(plot_dir, "igp.html") with open( html_filename, 'w') as f_html: f_html.write( html_template.render( js_file = "igp.js", timestamp=timestamp, plot_width = plot_width, plot_height = plot_height, title = "IGP", css_filename = "./ank_style.css",)) html_filename = os.path.join(plot_dir, "ibgp.html") with open( html_filename, 'w') as f_html: f_html.write( html_template.render( js_file = "ibgp.js", timestamp=timestamp, plot_width = plot_width, plot_height = plot_height, title = "iBGP", css_filename = "./ank_style.css",)) html_filename = os.path.join(plot_dir, "ebgp.html") with open( html_filename, 'w') as f_html: f_html.write( html_template.render( js_file = "ebgp.js", timestamp=timestamp, plot_width = plot_width, plot_height = plot_height, title = "eBGP", css_filename = "./ank_style.css",)) html_filename = os.path.join(plot_dir, "dns.html") with open( html_filename, 'w') as f_html: f_html.write( html_template.render( js_file = "dns.js", timestamp=timestamp, plot_width = plot_width, plot_height = plot_height, title = "DNS Hierarchy", css_filename = "./ank_style.css",)) html_filename = os.path.join(plot_dir, "dns_auth.html") with open( html_filename, 'w') as f_html: f_html.write( html_template.render( js_file = "dns_auth.js", timestamp=timestamp, plot_width = plot_width, plot_height = plot_height, title = "DNS Authority", css_filename = "./ank_style.css",)) css_filename = os.path.join(jsplot_dir, "style.css") with open( css_filename, 'w') as f_css: f_css.write( css_template.render()) # and ank css_template css_filename = os.path.join(plot_dir, "ank_style.css") with open( css_filename, 'w') as f_css: f_css.write( ank_css_template.render()) arbor_js_src_filename = os.path.join(template_dir, "arborjs", "arbor.js") arbor_js_dst_filename = os.path.join(jsplot_dir, "arbor.js") shutil.copy(arbor_js_src_filename, arbor_js_dst_filename)
def summarydoc(network): """ Plot the network """ ank_main_dir = config.ank_main_dir html_template = lookup.get_template("autonetkit/summary_html.mako") ank_css_template = lookup.get_template("autonetkit/style_css.mako") ebgp_graph = ank.get_ebgp_graph(network) ibgp_graph = ank.get_ibgp_graph(network) # Network wide stats network_stats = {} network_stats['device_count'] = len(list(network.devices())) network_stats['router_count'] = len(list(network.routers())) network_stats['server_count'] = len(list(network.servers())) network_stats['edge_count'] = network.graph.number_of_edges() as_graphs = ank.get_as_graphs(network) network_stats['as_count'] = len(as_graphs) as_stats = {} for my_as in as_graphs: #print single_as.nodes(data=True) # Get ASN of first node asn = my_as.asn #print asn node_list = {} loopbacks = [] virtual_nodes = {} for router in network.routers(asn): node_label = network.fqdn(router) loopbacks.append( (node_label, network.lo_ip(router).ip)) node_list[node_label] = {} interface_list = [] ibgp_list = [] ebgp_list = [] for _, dst, data in network.graph.edges(router, data=True): interface_list.append( (ank.fqdn(network, dst), data['sn'])) node_list[node_label]['interface_list'] = interface_list for _, dst, data in ebgp_graph.edges(router, data=True): ebgp_list.append( (ank.fqdn(network, dst), network.lo_ip(dst).ip)) node_list[node_label]['ebgp_list'] = ebgp_list for _, dst, data in ibgp_graph.edges(router, data=True): ibgp_list.append( (ank.fqdn(network, dst), network.lo_ip(dst).ip)) node_list[node_label]['ibgp_list'] = ibgp_list for virtual_node in network.virtual_nodes(asn): links = [] for link in network.links(virtual_node): links.append( (link.local_ip, link.remote_ip, link.dst)) virtual_nodes[virtual_node] = { 'links': links, } as_stats[my_as.name] = { 'asn': asn, 'loopbacks': loopbacks, 'node_list': node_list, 'virtual_nodes': virtual_nodes, } plot_dir = config.plot_dir if not os.path.isdir(plot_dir): os.mkdir(plot_dir) timestamp = time.strftime("%Y/%m/%d %H:%M:%S", time.localtime()) css_filename = os.path.join(plot_dir, "ank_style.css") with open( css_filename, 'w') as f_css: f_css.write( ank_css_template.render()) # put html file in main plot directory html_filename = os.path.join(plot_dir, "summary.html") #print html_filename with open( html_filename, 'w') as f_html: f_html.write( html_template.render( network_stats = network_stats, as_stats = as_stats, timestamp=timestamp, css_filename = "./ank_style.css", ) )