def eigrp(self, node): super(IosXrCompiler, self).eigrp(node) node.eigrp.name = 1 # TODO: check if this should be ASN g_eigrp = self.anm['eigrp'] ipv4_interfaces = [] ipv6_interfaces = [] for interface in node.physical_interfaces: if interface.exclude_igp: continue # don't configure IGP for this interface eigrp_int = g_eigrp.interface(interface) if eigrp_int and eigrp_int.is_bound: #TODO: for here and below use stanza directly data = {'id': interface.id, 'passive': False} stanza = config_stanza(**data) if node.eigrp.use_ipv4: ipv4_interfaces.append(stanza) if node.eigrp.use_ipv6: ipv6_interfaces.append(stanza) loopback_zero = node.loopback_zero data = {'id': node.loopback_zero.id, 'passive': True} stanza = config_stanza(**data) if node.eigrp.use_ipv4: ipv4_interfaces.append(stanza) if node.eigrp.use_ipv6: ipv6_interfaces.append(stanza) node.eigrp.ipv4_interfaces = ipv4_interfaces node.eigrp.ipv6_interfaces = ipv6_interfaces
def lab_topology(self): # TODO: replace name/label and use attribute from subgraph lab_topology = self.nidb.topology[self.host] lab_topology.render_template = os.path.join("templates", "netkit_lab_conf.mako") lab_topology.render_dst_folder = os.path.join("rendered", self.host, "netkit") lab_topology.render_dst_file = "lab.conf" lab_topology.description = "AutoNetkit Lab" lab_topology.author = "AutoNetkit" lab_topology.web = "www.autonetkit.org" host_nodes = list( self.nidb.nodes(host=self.host, platform="netkit")) if not len(host_nodes): log.debug("No Netkit hosts for %s" % self.host) # also need collision domains for this host cd_nodes = self.nidb.nodes("broadcast_domain", host=self.host) host_nodes += cd_nodes subgraph = self.nidb.subgraph(host_nodes, self.host) lab_topology.machines = " ".join(alpha_sort(naming.network_hostname(phy_node) for phy_node in subgraph.l3devices())) lab_topology.config_items = [] for node in sorted(subgraph.l3devices()): for interface in node.physical_interfaces: broadcast_domain = str(interface.ipv4_subnet).replace("/", ".") #netkit lab.conf uses 1 instead of eth1 numeric_id = interface.numeric_id stanza = config_stanza( device=naming.network_hostname(node), key=numeric_id, value=broadcast_domain, ) lab_topology.config_items.append(stanza) lab_topology.tap_ips = [] for node in subgraph: if node.tap: stanza = config_stanza( device=naming.network_hostname(node), id=node.tap.id.replace("eth", ""), # strip ethx -> x ip=node.tap.ip, ) lab_topology.tap_ips.append(stanza) lab_topology.tap_ips = sorted(lab_topology.tap_ips, key = lambda x: x.ip) lab_topology.config_items = sorted(lab_topology.config_items, key = lambda x: x.device)
def isis(self, node): super(IosXrCompiler, self).isis(node) node.isis.isis_links = [] for interface in node.physical_interfaces: if interface.exclude_igp: continue # don't configure IGP for this interface # print interface.isis.dump() # copy across attributes from the IosBaseCompiler setting step isis_int = self.anm['isis'].interface(interface) if isis_int and isis_int.is_bound: data = { 'id': interface.id, 'metric': isis_int.metric, 'multipoint': isis_int.multipoint } if interface.isis.hello_padding_disable is not None: data['hello_padding_disable'] = \ interface.isis.hello_padding_disable if interface.isis.mtu is not None: data['mtu'] = interface.isis.hello_padding_disable #TODO: make stanza stanza = config_stanza(**data) node.isis.isis_links.append(stanza)
def vrf(self, node): g_vrf = self.anm['vrf'] vrf_node = self.anm['vrf'].node(node) node.add_stanza("vrf") node.add_stanza("mpls") node.vrf.vrfs = [] if vrf_node and vrf_node.vrf_role is 'PE': # TODO: check if mpls ldp already set elsewhere for vrf in vrf_node.node_vrf_names: route_target = g_vrf.data.route_targets[node.asn][vrf] rd_index = vrf_node.rd_indices[vrf] rd = '%s:%s' % (node.asn, rd_index) stanza = config_stanza(vrf=vrf, rd=rd, route_target=route_target) node.vrf.vrfs.append(stanza) for interface in node.interfaces: vrf_int = self.anm['vrf'].interface(interface) if vrf_int.vrf_name: interface.vrf = vrf_int.vrf_name # mark interface as being part of vrf if interface.physical: interface.description += ' vrf %s' \ % vrf_int.vrf_name if vrf_node and vrf_node.vrf_role in ('P', 'PE'): # Add PE -> P, PE -> PE interfaces to MPLS LDP node.mpls.ldp_interfaces = [] for interface in node.physical_interfaces: mpls_ldp_int = self.anm['mpls_ldp'].interface(interface) if mpls_ldp_int.is_bound: node.mpls.ldp_interfaces.append(interface.id) interface.use_mpls = True if vrf_node and vrf_node.vrf_role is 'P': node.mpls.ldp_interfaces = [] for interface in node.physical_interfaces: node.mpls.ldp_interfaces.append(interface.id) vrf_node = self.anm['vrf'].node(node) node.vrf.use_ipv4 = node.ip.use_ipv4 node.vrf.use_ipv6 = node.ip.use_ipv6 node.vrf.vrfs = sorted(node.vrf.vrfs, key=lambda x: x.vrf) if self.anm.has_overlay('mpls_ldp') and node \ in self.anm['mpls_ldp']: node.mpls.enabled = True node.mpls.router_id = node.loopback_zero.id
def ospf(self, node): """Quagga ospf compiler""" super(QuaggaCompiler, self).ospf(node) # add eBGP link subnets node.ospf.passive_interfaces = [] for interface in node.physical_interfaces: if interface.exclude_igp: continue # don't configure IGP for this interface bgp_int = self.anm['ebgp_v4'].interface(interface) if bgp_int.is_bound: # ebgp interface node.ospf.passive_interfaces.append(config_stanza(id=interface.id)) subnet = bgp_int['ipv4'].subnet default_ebgp_area = 0 node.ospf.ospf_links.append( config_stanza(network=subnet, area=default_ebgp_area))
def vrf(self, node): g_vrf = self.anm['vrf'] vrf_node = self.anm['vrf'].node(node) node.add_stanza("vrf") node.add_stanza("mpls") node.vrf.vrfs = [] if vrf_node and vrf_node.vrf_role is 'PE': # TODO: check if mpls ldp already set elsewhere for vrf in vrf_node.node_vrf_names: route_target = g_vrf.data.route_targets[node.asn][vrf] rd_index = vrf_node.rd_indices[vrf] rd = '%s:%s' % (node.asn, rd_index) stanza = config_stanza(vrf = vrf, rd = rd, route_target = route_target) node.vrf.vrfs.append(stanza) for interface in node.interfaces: vrf_int = self.anm['vrf'].interface(interface) if vrf_int.vrf_name: interface.vrf = vrf_int.vrf_name # mark interface as being part of vrf if interface.physical: interface.description += ' vrf %s' \ % vrf_int.vrf_name if vrf_node and vrf_node.vrf_role in ('P', 'PE'): # Add PE -> P, PE -> PE interfaces to MPLS LDP node.mpls.ldp_interfaces = [] for interface in node.physical_interfaces: mpls_ldp_int = self.anm['mpls_ldp'].interface(interface) if mpls_ldp_int.is_bound: node.mpls.ldp_interfaces.append(interface.id) interface.use_mpls = True if vrf_node and vrf_node.vrf_role is 'P': node.mpls.ldp_interfaces = [] for interface in node.physical_interfaces: node.mpls.ldp_interfaces.append(interface.id) vrf_node = self.anm['vrf'].node(node) node.vrf.use_ipv4 = node.ip.use_ipv4 node.vrf.use_ipv6 = node.ip.use_ipv6 node.vrf.vrfs = sorted(node.vrf.vrfs, key = lambda x: x.vrf) if self.anm.has_overlay('mpls_ldp') and node \ in self.anm['mpls_ldp']: node.mpls.enabled = True node.mpls.router_id = node.loopback_zero.id
def mpls_te(self, node): super(IosXrCompiler, self).mpls_te(node) g_mpls_te = self.anm['mpls_te'] if node not in g_mpls_te: return # no mpls te configured rsvp_interfaces = [] mpls_te_interfaces = [] mpls_te_node = g_mpls_te.node(node) for interface in mpls_te_node.physical_interfaces: nidb_interface = self.nidb.interface(interface) stanza = config_stanza(id=nidb_interface.id, bandwidth_percent=100) rsvp_interfaces.append(stanza) mpls_te_interfaces.append(nidb_interface.id) node.add_stanza("rsvp") node.rsvp.interfaces = rsvp_interfaces node.mpls.te_interfaces = mpls_te_interfaces
def mpls_te(self, node): super(IosXrCompiler, self).mpls_te(node) g_mpls_te = self.anm['mpls_te'] if node not in g_mpls_te: return # no mpls te configured rsvp_interfaces = [] mpls_te_interfaces = [] mpls_te_node = g_mpls_te.node(node) for interface in mpls_te_node.physical_interfaces: nidb_interface = self.nidb.interface(interface) stanza = config_stanza(id = nidb_interface.id, bandwidth_percent = 100) rsvp_interfaces.append(stanza) mpls_te_interfaces.append(nidb_interface.id) node.add_stanza("rsvp") node.rsvp.interfaces = rsvp_interfaces node.mpls.te_interfaces = mpls_te_interfaces
def isis(self, node): super(IosXrCompiler, self).isis(node) node.isis.isis_links = [] for interface in node.physical_interfaces: if interface.exclude_igp: continue # don't configure IGP for this interface # print interface.isis.dump() # copy across attributes from the IosBaseCompiler setting step isis_int = self.anm['isis'].interface(interface) if isis_int and isis_int.is_bound: data = {'id': interface.id, 'metric': isis_int.metric, 'multipoint': isis_int.multipoint} if interface.isis.hello_padding_disable is not None: data['hello_padding_disable'] = \ interface.isis.hello_padding_disable if interface.isis.mtu is not None: data['mtu'] = interface.isis.hello_padding_disable #TODO: make stanza stanza = config_stanza(**data) node.isis.isis_links.append(stanza)
def static_routes(self, node): node.static_routes_v4 = [ ] # initialise for case of no routes -> simplifies template logic node.host_routes_v4 = [ ] # initialise for case of no routes -> simplifies template logic node.static_routes_v6 = [ ] # initialise for case of no routes -> simplifies template logic node.host_routes_v6 = [ ] # initialise for case of no routes -> simplifies template logic if not self.anm['phy'].data.enable_routing: log.info( 'Routing disabled, not configuring static routes for Ubuntu server %s' % node) return if self.anm['phy'].node(node).dont_configure_static_routing: log.info('Static routing disabled for server %s' % node) return l3_conn_node = self.anm['l3_conn'].node(node) phy_node = self.anm['phy'].node(node) gateway_list = [n for n in l3_conn_node.neighbors() if n.is_router()] if not len(gateway_list): log.warning('Server %s is not directly connected to any routers' % node) return else: gateway = gateway_list[0] # choose first (and only gateway) if len(gateway_list) > 1: log.info('Server %s is multi-homed, using gateway %s' % (node, gateway)) # TODO: warn if server has no neighbors in same ASN (either in design or verification steps) # TODO: need to check that servers don't have any direct ebgp connections gateway_edge_l3 = self.anm['l3_conn'].edge(node, gateway) server_interface = gateway_edge_l3.src_int server_interface_id = self.nidb.interface(server_interface).id gateway_interface = gateway_edge_l3.dst_int gateway_ipv4 = gateway_ipv6 = None node.add_stanza("ip") if node.ip.use_ipv4: gateway_ipv4 = gateway_interface['ipv4'].ip_address if node.ip.use_ipv6: gateway_ipv6 = gateway_interface['ipv6'].ip_address # TODO: look at aggregation # TODO: catch case of ip addressing being disabled # TODO: handle both ipv4 and ipv6 # IGP advertised infrastructure pool from same AS static_routes_v4 = [] host_routes_v4 = [] for (asn, asn_routes) in self.anm['ipv4'].data['infra_blocks'].items(): # host_routes_v4 for infra_route in asn_routes: route_entry = { 'network': infra_route, 'prefix': infra_route.network, 'gw': gateway_ipv4, 'interface': server_interface_id, 'description': 'Route to infra subnet in AS %s via %s' \ % (asn, gateway), } route_entry = config_stanza(**route_entry) if infra_route.prefixlen == 32: host_routes_v4.append(route_entry) else: static_routes_v4.append(route_entry) # eBGP advertised loopbacks in all (same + other) ASes for (asn, asn_routes) in self.anm['ipv4'].data['loopback_blocks'].items(): for asn_route in asn_routes: route_entry = { 'network': asn_route, 'prefix': asn_route.network, 'gw': gateway_ipv4, 'interface': server_interface_id, 'description': 'Route to loopback subnet in AS %s via %s' \ % (asn, gateway), } route_entry = config_stanza(**route_entry) if asn_route.prefixlen == 32: host_routes_v4.append(route_entry) else: static_routes_v4.append(route_entry) # TODO: combine the above logic into single step rather than creating dict then formatting with it cloud_init_static_routes = [] for entry in static_routes_v4: formatted = 'route add -net %s gw %s dev %s' \ % (entry.network, entry.gw, entry.interface) cloud_init_static_routes.append(formatted) for entry in host_routes_v4: formatted = 'route add -host %s gw %s dev %s' \ % (entry.prefix, entry.gw, entry.interface) cloud_init_static_routes.append(formatted) node.add_stanza("cloud_init") node.cloud_init.static_routes = cloud_init_static_routes
def compile_devices(self): g_phy = self.anm['phy'] to_memory, use_mgmt_interfaces, dst_folder = self._parameters() if use_mgmt_interfaces: log.info("Allocating VIRL management interfaces") else: log.info("Not allocating VIRL management interfaces") #TODO: need to copy across the interface name from edge to the interface # TODO: merge common router code, so end up with three loops: routers, ios # routers, ios_xr routers #TODO: Split out each device compiler into own function #TODO: look for unused code paths here - especially for interface allocation # store autonetkit_cisco version log.info("Generating device configurations") from pkg_resources import get_distribution ank_cisco_version = get_distribution("autonetkit_cisco").version for phy_node in g_phy.l3devices(host=self.host): loopback_ids = self.loopback_interface_ids() # allocate loopbacks to routes (same for all ios variants) nidb_node = self.nidb.node(phy_node) nidb_node.add_stanza("render") nidb_node.ank_cisco_version = ank_cisco_version nidb_node.indices = phy_node.indices for interface in nidb_node.loopback_interfaces: if interface != nidb_node.loopback_zero: interface.id = loopback_ids.next() # numeric ids numeric_int_ids = self.numeric_interface_ids() for interface in nidb_node.physical_interfaces: phy_numeric_id = phy_node.interface(interface).numeric_id if phy_numeric_id is None: #TODO: remove numeric ID code interface.numeric_id = numeric_int_ids.next() else: interface.numeric_id = int(phy_numeric_id) phy_specified_id = phy_node.interface(interface).specified_id if phy_specified_id is not None: interface.id = phy_specified_id #from autonetkit.compilers.device.ubuntu import UbuntuCompiler from autonetkit_cisco.compilers.device.ubuntu import UbuntuCompiler ubuntu_compiler = UbuntuCompiler(self.nidb, self.anm) for phy_node in g_phy.servers(host=self.host): nidb_node = self.nidb.node(phy_node) nidb_node.add_stanza("render") nidb_node.add_stanza("ip") #TODO: look at server syntax also, same as for routers for interface in nidb_node.physical_interfaces: phy_specified_id = phy_node.interface(interface).specified_id if phy_specified_id is not None: interface.id = phy_specified_id #interface.id = self.numeric_to_interface_label_linux(interface.numeric_id) #print "numeric", interface.numeric_id, interface.id nidb_node.ip.use_ipv4 = phy_node.use_ipv4 nidb_node.ip.use_ipv6 = phy_node.use_ipv6 #TODO: clean up interface handling numeric_int_ids = self.numeric_interface_ids() for interface in nidb_node.physical_interfaces: phy_int = phy_node.interface(interface) phy_numeric_id = phy_node.interface(interface).numeric_id if phy_numeric_id is None: #TODO: remove numeric ID code interface.numeric_id = numeric_int_ids.next() else: interface.numeric_id = int(phy_numeric_id) phy_specified_id = phy_node.interface(interface).specified_id if phy_specified_id is not None: interface.id = phy_specified_id #TODO: make this part of the base device compiler, which server/router inherits if use_mgmt_interfaces: # not these are physical interfaces; configure after previous config steps mgmt_int = nidb_node.add_interface(management=True, description="eth0") mgmt_int_id = "eth0" mgmt_int.id = mgmt_int_id # render route config nidb_node = self.nidb.node(phy_node) ubuntu_compiler.compile(nidb_node) if not phy_node.dont_configure_static_routing: nidb_node.render.template = os.path.join( "templates", "linux", "static_route.mako") if to_memory: nidb_node.render.to_memory = True else: nidb_node.render.dst_folder = dst_folder nidb_node.render.dst_file = "%s.conf" % naming.network_hostname( phy_node) #TODO: refactor out common logic ios_compiler = IosClassicCompiler(self.nidb, self.anm) host_routers = g_phy.routers(host=self.host) ios_nodes = (n for n in host_routers if n.syntax in ("ios", "ios_xe")) for phy_node in ios_nodes: nidb_node = self.nidb.node(phy_node) nidb_node.add_stanza("render") nidb_node.render.template = os.path.join("templates", "ios.mako") if to_memory: nidb_node.render.to_memory = True else: nidb_node.render.dst_folder = dst_folder nidb_node.render.dst_file = "%s.conf" % naming.network_hostname( phy_node) #TODO: write function that assigns interface number excluding those already taken # Assign interfaces if phy_node.device_subtype == "IOSv": int_ids = self.interface_ids_ios() numeric_to_interface_label = self.numeric_to_interface_label_ios elif phy_node.device_subtype == "CSR1000v": int_ids = self.interface_ids_csr1000v() numeric_to_interface_label = self.numeric_to_interface_label_ra else: # default if no subtype specified #TODO: need to set default in the load module log.warning("Unexpected subtype %s for %s" % (phy_node.device_subtype, phy_node)) int_ids = self.interface_ids_ios() numeric_to_interface_label = self.numeric_to_interface_label_ios if use_mgmt_interfaces: if phy_node.device_subtype == "IOSv": #TODO: make these configured in the internal config file # for platform/device_subtype keying mgmt_int_id = "GigabitEthernet0/0" if phy_node.device_subtype == "CSR1000v": mgmt_int_id = "GigabitEthernet1" for interface in nidb_node.physical_interfaces: #TODO: use this code block once for all routers if not interface.id: interface.id = numeric_to_interface_label( interface.numeric_id) ios_compiler.compile(nidb_node) if use_mgmt_interfaces: mgmt_int = nidb_node.add_interface(management=True) mgmt_int.id = mgmt_int_id try: from autonetkit_cisco.compilers.device.cisco import IosXrCompiler ios_xr_compiler = IosXrCompiler(self.nidb, self.anm) except ImportError: ios_xr_compiler = IosXrCompiler(self.nidb, self.anm) for phy_node in g_phy.routers(host=self.host, syntax='ios_xr'): nidb_node = self.nidb.node(phy_node) nidb_node.add_stanza("render") nidb_node.render.template = os.path.join("templates", "ios_xr", "router.conf.mako") if to_memory: nidb_node.render.to_memory = True else: nidb_node.render.dst_folder = dst_folder nidb_node.render.dst_file = "%s.conf" % naming.network_hostname( phy_node) # Assign interfaces int_ids = self.interface_ids_ios_xr() for interface in nidb_node.physical_interfaces: if not interface.id: interface.id = self.numeric_to_interface_label_ios_xr( interface.numeric_id) ios_xr_compiler.compile(nidb_node) if use_mgmt_interfaces: mgmt_int_id = "mgmteth0/0/CPU0/0" mgmt_int = nidb_node.add_interface(management=True) mgmt_int.id = mgmt_int_id nxos_compiler = NxOsCompiler(self.nidb, self.anm) for phy_node in g_phy.routers(host=self.host, syntax='nx_os'): nidb_node = self.nidb.node(phy_node) nidb_node.add_stanza("render") nidb_node.render.template = os.path.join("templates", "nx_os.mako") if to_memory: nidb_node.render.to_memory = True else: nidb_node.render.dst_folder = dst_folder nidb_node.render.dst_file = "%s.conf" % naming.network_hostname( phy_node) # Assign interfaces int_ids = self.interface_ids_nxos() for interface in nidb_node.physical_interfaces: if not interface.id: interface.id = self.numeric_to_interface_label_nxos( interface.numeric_id) nidb_node.supported_features = config_stanza(mpls_te=False, mpls_oam=False, vrf=False) nxos_compiler.compile(nidb_node) #TODO: make this work other way around if use_mgmt_interfaces: mgmt_int_id = "mgmt0" mgmt_int = nidb_node.add_interface(management=True) mgmt_int.id = mgmt_int_id staros_compiler = StarOsCompiler(self.nidb, self.anm) for phy_node in g_phy.routers(host=self.host, syntax='StarOS'): nidb_node = self.nidb.node(phy_node) nidb_node.add_stanza("render") nidb_node.render.template = os.path.join("templates", "staros.mako") if to_memory: nidb_node.render.to_memory = True else: nidb_node.render.dst_folder = dst_folder nidb_node.render.dst_file = "%s.conf" % naming.network_hostname( phy_node) # Assign interfaces int_ids = self.interface_ids_nxos() for interface in nidb_node.physical_interfaces: if not interface.id: interface.id = self.numeric_to_interface_label_star_os( interface.numeric_id) staros_compiler.compile(nidb_node) #TODO: make this work other way around if use_mgmt_interfaces: mgmt_int_id = "ethernet 1/1" mgmt_int = nidb_node.add_interface(management=True) mgmt_int.id = mgmt_int_id
def bgp(self, node): phy_node = self.anm['phy'].node(node) g_ipv4 = self.anm['ipv4'] if node.ip.use_ipv6: g_ipv6 = self.anm['ipv6'] asn = phy_node.asn node.asn = asn node.add_stanza("bgp") node.bgp.ipv4_advertise_subnets = [] if node.ip.use_ipv4: node.bgp.ipv4_advertise_subnets = \ g_ipv4.data.infra_blocks.get(asn) or [] # could be none (if one-node AS) default empty list node.bgp.ipv6_advertise_subnets = [] if node.ip.use_ipv6: g_ipv6 = self.anm['ipv6'] node.bgp.ipv6_advertise_subnets = \ g_ipv6.data.infra_blocks.get(asn) or [] ibgp_neighbors = [] ibgp_rr_clients = [] ibgp_rr_parents = [] g_ibgp_v4 = self.anm['ibgp_v4'] for session in sort_sessions(g_ibgp_v4.edges(phy_node)): if session.exclude: log.debug('Skipping excluded ibgp session %s' % session) continue # exclude from regular ibgp config (eg VRF, VPLS, etc) data = self.ibgp_session_data(session, ip_version=4) bgp_stanza = config_stanza(**data) direction = session.direction if direction == 'down': ibgp_rr_clients.append(bgp_stanza) elif direction == 'up': ibgp_rr_parents.append(bgp_stanza) else: ibgp_neighbors.append(bgp_stanza) # TODO: check v6 hierarchy only created if node set to being v4 or v6 if node.ip.use_ipv6: g_ibgp_v6 = self.anm['ibgp_v6'] for session in sort_sessions(g_ibgp_v6.edges(phy_node)): if session.exclude: log.debug('Skipping excluded ibgp session %s' % session) continue # exclude from regular ibgp config (eg VRF, VPLS, etc) data = self.ibgp_session_data(session, ip_version=6) bgp_stanza = config_stanza(**data) direction = session.direction if direction == 'down': ibgp_rr_clients.append(bgp_stanza) elif direction == 'up': ibgp_rr_parents.append(bgp_stanza) else: ibgp_neighbors.append(bgp_stanza) # TODO: update this to use ibgp_v4 and ibgp_v6 overlays node.bgp.ibgp_neighbors = ibgp_neighbors node.bgp.ibgp_rr_clients = ibgp_rr_clients node.bgp.ibgp_rr_parents = ibgp_rr_parents # ebgp ebgp_neighbors = [] g_ebgp_v4 = self.anm['ebgp_v4'] for session in sort_sessions(g_ebgp_v4.edges(phy_node)): if session.exclude: log.debug('Skipping excluded ebgp session %s' % session) continue # exclude from regular ibgp config (eg VRF, VPLS, etc) data = self.ebgp_session_data(session, ip_version=4) bgp_stanza = config_stanza(**data) ebgp_neighbors.append(bgp_stanza) if node.ip.use_ipv6: g_ebgp_v6 = self.anm['ebgp_v6'] for session in sort_sessions(g_ebgp_v6.edges(phy_node)): if session.exclude: print "Exclude" log.debug('Skipping excluded ebgp session %s' % session) continue # exclude from regular ibgp config (eg VRF, VPLS, etc) data = self.ebgp_session_data(session, ip_version=6) bgp_stanza = config_stanza(**data) ebgp_neighbors.append(bgp_stanza) ebgp_neighbors = sorted(ebgp_neighbors, key = lambda x: x.asn) node.bgp.ebgp_neighbors = ebgp_neighbors return
def compile_devices(self): g_phy = self.anm['phy'] to_memory, use_mgmt_interfaces, dst_folder = self._parameters() if use_mgmt_interfaces: log.info("Allocating VIRL management interfaces") else: log.info("Not allocating VIRL management interfaces") #TODO: need to copy across the interface name from edge to the interface # TODO: merge common router code, so end up with three loops: routers, ios # routers, ios_xr routers #TODO: Split out each device compiler into own function #TODO: look for unused code paths here - especially for interface allocation # store autonetkit_cisco version log.info("Generating device configurations") from pkg_resources import get_distribution ank_cisco_version = get_distribution("autonetkit_cisco").version for phy_node in g_phy.l3devices(host=self.host): loopback_ids = self.loopback_interface_ids() # allocate loopbacks to routes (same for all ios variants) nidb_node = self.nidb.node(phy_node) nidb_node.add_stanza("render") nidb_node.ank_cisco_version = ank_cisco_version nidb_node.indices = phy_node.indices for interface in nidb_node.loopback_interfaces: if interface != nidb_node.loopback_zero: interface.id = loopback_ids.next() # numeric ids numeric_int_ids = self.numeric_interface_ids() for interface in nidb_node.physical_interfaces: phy_numeric_id = phy_node.interface(interface).numeric_id if phy_numeric_id is None: #TODO: remove numeric ID code interface.numeric_id = numeric_int_ids.next() else: interface.numeric_id = int(phy_numeric_id) phy_specified_id = phy_node.interface(interface).specified_id if phy_specified_id is not None: interface.id = phy_specified_id #from autonetkit.compilers.device.ubuntu import UbuntuCompiler from autonetkit_cisco.compilers.device.ubuntu import UbuntuCompiler ubuntu_compiler = UbuntuCompiler(self.nidb, self.anm) for phy_node in g_phy.servers(host=self.host): nidb_node = self.nidb.node(phy_node) nidb_node.add_stanza("render") nidb_node.add_stanza("ip") #TODO: look at server syntax also, same as for routers for interface in nidb_node.physical_interfaces: phy_specified_id = phy_node.interface(interface).specified_id if phy_specified_id is not None: interface.id = phy_specified_id #interface.id = self.numeric_to_interface_label_linux(interface.numeric_id) #print "numeric", interface.numeric_id, interface.id nidb_node.ip.use_ipv4 = phy_node.use_ipv4 nidb_node.ip.use_ipv6 = phy_node.use_ipv6 #TODO: clean up interface handling numeric_int_ids = self.numeric_interface_ids() for interface in nidb_node.physical_interfaces: phy_int = phy_node.interface(interface) phy_numeric_id = phy_node.interface(interface).numeric_id if phy_numeric_id is None: #TODO: remove numeric ID code interface.numeric_id = numeric_int_ids.next() else: interface.numeric_id = int(phy_numeric_id) phy_specified_id = phy_node.interface(interface).specified_id if phy_specified_id is not None: interface.id = phy_specified_id #TODO: make this part of the base device compiler, which server/router inherits if use_mgmt_interfaces: # not these are physical interfaces; configure after previous config steps mgmt_int = nidb_node.add_interface(management = True, description = "eth0") mgmt_int_id = "eth0" mgmt_int.id = mgmt_int_id # render route config nidb_node = self.nidb.node(phy_node) ubuntu_compiler.compile(nidb_node) if not phy_node.dont_configure_static_routing: nidb_node.render.template = os.path.join("templates", "linux", "static_route.mako") if to_memory: nidb_node.render.to_memory = True else: nidb_node.render.dst_folder = dst_folder nidb_node.render.dst_file = "%s.conf" % naming.network_hostname( phy_node) #TODO: refactor out common logic ios_compiler = IosClassicCompiler(self.nidb, self.anm) host_routers = g_phy.routers(host=self.host) ios_nodes = (n for n in host_routers if n.syntax in ("ios", "ios_xe")) for phy_node in ios_nodes: nidb_node = self.nidb.node(phy_node) nidb_node.add_stanza("render") nidb_node.render.template = os.path.join("templates","ios.mako") if to_memory: nidb_node.render.to_memory = True else: nidb_node.render.dst_folder = dst_folder nidb_node.render.dst_file = "%s.conf" % naming.network_hostname( phy_node) #TODO: write function that assigns interface number excluding those already taken # Assign interfaces if phy_node.device_subtype == "IOSv": int_ids = self.interface_ids_ios() numeric_to_interface_label = self.numeric_to_interface_label_ios elif phy_node.device_subtype == "CSR1000v": int_ids = self.interface_ids_csr1000v() numeric_to_interface_label = self.numeric_to_interface_label_ra else: # default if no subtype specified #TODO: need to set default in the load module log.warning("Unexpected subtype %s for %s" % (phy_node.device_subtype, phy_node)) int_ids = self.interface_ids_ios() numeric_to_interface_label = self.numeric_to_interface_label_ios if use_mgmt_interfaces: if phy_node.device_subtype == "IOSv": #TODO: make these configured in the internal config file # for platform/device_subtype keying mgmt_int_id = "GigabitEthernet0/0" if phy_node.device_subtype == "CSR1000v": mgmt_int_id = "GigabitEthernet1" for interface in nidb_node.physical_interfaces: #TODO: use this code block once for all routers if not interface.id: interface.id = numeric_to_interface_label(interface.numeric_id) ios_compiler.compile(nidb_node) if use_mgmt_interfaces: mgmt_int = nidb_node.add_interface(management = True) mgmt_int.id = mgmt_int_id try: from autonetkit_cisco.compilers.device.cisco import IosXrCompiler ios_xr_compiler = IosXrCompiler(self.nidb, self.anm) except ImportError: ios_xr_compiler = IosXrCompiler(self.nidb, self.anm) for phy_node in g_phy.routers(host=self.host, syntax='ios_xr'): nidb_node = self.nidb.node(phy_node) nidb_node.add_stanza("render") nidb_node.render.template = os.path.join("templates","ios_xr","router.conf.mako") if to_memory: nidb_node.render.to_memory = True else: nidb_node.render.dst_folder = dst_folder nidb_node.render.dst_file = "%s.conf" % naming.network_hostname( phy_node) # Assign interfaces int_ids = self.interface_ids_ios_xr() for interface in nidb_node.physical_interfaces: if not interface.id: interface.id = self.numeric_to_interface_label_ios_xr(interface.numeric_id) ios_xr_compiler.compile(nidb_node) if use_mgmt_interfaces: mgmt_int_id = "mgmteth0/0/CPU0/0" mgmt_int = nidb_node.add_interface(management = True) mgmt_int.id = mgmt_int_id nxos_compiler = NxOsCompiler(self.nidb, self.anm) for phy_node in g_phy.routers(host=self.host, syntax='nx_os'): nidb_node = self.nidb.node(phy_node) nidb_node.add_stanza("render") nidb_node.render.template = os.path.join("templates","nx_os.mako") if to_memory: nidb_node.render.to_memory = True else: nidb_node.render.dst_folder = dst_folder nidb_node.render.dst_file = "%s.conf" % naming.network_hostname( phy_node) # Assign interfaces int_ids = self.interface_ids_nxos() for interface in nidb_node.physical_interfaces: if not interface.id: interface.id = self.numeric_to_interface_label_nxos(interface.numeric_id) nidb_node.supported_features = config_stanza(mpls_te = False, mpls_oam = False, vrf = False) nxos_compiler.compile(nidb_node) #TODO: make this work other way around if use_mgmt_interfaces: mgmt_int_id = "mgmt0" mgmt_int = nidb_node.add_interface(management = True) mgmt_int.id = mgmt_int_id staros_compiler = StarOsCompiler(self.nidb, self.anm) for phy_node in g_phy.routers(host=self.host, syntax='StarOS'): nidb_node = self.nidb.node(phy_node) nidb_node.add_stanza("render") nidb_node.render.template = os.path.join("templates","staros.mako") if to_memory: nidb_node.render.to_memory = True else: nidb_node.render.dst_folder = dst_folder nidb_node.render.dst_file = "%s.conf" % naming.network_hostname( phy_node) # Assign interfaces int_ids = self.interface_ids_nxos() for interface in nidb_node.physical_interfaces: if not interface.id: interface.id = self.numeric_to_interface_label_star_os(interface.numeric_id) staros_compiler.compile(nidb_node) #TODO: make this work other way around if use_mgmt_interfaces: mgmt_int_id = "ethernet 1/1" mgmt_int = nidb_node.add_interface(management = True) mgmt_int.id = mgmt_int_id
def bgp(self, node): super(IosClassicCompiler, self).bgp(node) node.bgp.use_ipv4 = node.ip.use_ipv4 node.bgp.use_ipv6 = node.ip.use_ipv6 # Seperate by address family ipv4_peers = [] ipv6_peers = [] # Note cast to dict - #TODO revisit this requirement # TODO: revisit and tidy up the logic here: split iBGP and eBGP # TODO: sort the peer list by peer IP for peer in node.bgp.ibgp_neighbors: peer = config_stanza(peer) peer.remote_ip = peer.loopback if peer.use_ipv4: if node.is_ebgp_v4: peer.next_hop_self = True ipv4_peers.append(peer) if peer.use_ipv6: if node.is_ebgp_v6: peer.next_hop_self = True ipv6_peers.append(peer) for peer in node.bgp.ibgp_rr_parents: peer = config_stanza(peer) peer.remote_ip = peer.loopback if peer.use_ipv4: if node.is_ebgp_v4: peer.next_hop_self = True ipv4_peers.append(peer) if peer.use_ipv6: if node.is_ebgp_v6: peer.next_hop_self = True ipv6_peers.append(peer) for peer in node.bgp.ibgp_rr_clients: peer = config_stanza(peer) peer.rr_client = True peer.remote_ip = peer.loopback if peer.use_ipv4: if node.is_ebgp_v4: peer.next_hop_self = True ipv4_peers.append(peer) if peer.use_ipv6: if node.is_ebgp_v6: peer.next_hop_self = True ipv6_peers.append(peer) for peer in node.bgp.ebgp_neighbors: peer = config_stanza(peer) peer.is_ebgp = True peer.remote_ip = peer.dst_int_ip if peer.use_ipv4: peer.next_hop_self = True ipv4_peers.append(peer) if peer.use_ipv6: peer.next_hop_self = True ipv6_peers.append(peer) node.bgp.ipv4_peers = ipv4_peers node.bgp.ipv6_peers = ipv6_peers vpnv4_neighbors = [] if node.bgp.vpnv4: for neigh in node.bgp.ibgp_neighbors: if not neigh.use_ipv4: continue neigh_data = config_stanza(neigh) vpnv4_neighbors.append(neigh_data) for neigh in node.bgp.ibgp_rr_clients: if not neigh.use_ipv4: continue neigh_data = config_stanza(neigh) neigh_data.rr_client = True vpnv4_neighbors.append(neigh_data) for neigh in node.bgp.ibgp_rr_parents: if not neigh.use_ipv4: continue neigh_data = config_stanza(neigh) vpnv4_neighbors.append(neigh_data) vpnv4_neighbors = sorted(vpnv4_neighbors, key=lambda x: \ x['loopback']) node.bgp.vpnv4_neighbors = vpnv4_neighbors
def bgp(self, node): node.add_stanza("bgp") node.bgp.lo_interface = self.lo_interface super(IosBaseCompiler, self).bgp(node) phy_node = self.anm['phy'].node(node) asn = phy_node.asn g_ebgp_v4 = self.anm['ebgp_v4'] g_ebgp_v6 = self.anm['ebgp_v6'] if node in g_ebgp_v4 \ and len(list(g_ebgp_v4.node(node).edges())) > 0: node.is_ebgp_v4 = True else: node.is_ebgp_v4 = False if node in g_ebgp_v6 \ and len(list(g_ebgp_v6.node(node).edges())) > 0: node.is_ebgp_v6 = True else: node.is_ebgp_v6 = False node.bgp.ipv4_advertise_subnets = [] node.bgp.ipv6_advertise_subnets = [] # Advertise loopbacks into BGP if node.ip.use_ipv4: node.bgp.ipv4_advertise_subnets = \ [node.loopback_zero.ipv4_cidr] if node.ip.use_ipv6: node.bgp.ipv6_advertise_subnets = \ [node.loopback_zero.ipv6_address] # Advertise infrastructure into eBGP if node.ip.use_ipv4 and node.is_ebgp_v4: infra_blocks = self.anm['ipv4'].data['infra_blocks' ].get(asn) or [] for infra_route in infra_blocks: node.bgp.ipv4_advertise_subnets.append(infra_route) if node.ip.use_ipv6 and node.is_ebgp_v6: infra_blocks = self.anm['ipv6'].data['infra_blocks' ].get(asn) or [] for infra_route in infra_blocks: node.bgp.ipv6_advertise_subnets.append(infra_route) self.nailed_up_routes(node) # vrf # TODO: this should be inside vrf section? node.bgp.vrfs = [] vrf_node = self.anm['vrf'].node(node) if vrf_node and vrf_node.vrf_role is 'PE': # iBGP sessions for this VRF vrf_ibgp_neighbors = defaultdict(list) g_ibgp_v4 = self.anm['ibgp_v4'] for session in sort_sessions(g_ibgp_v4.edges(vrf_node)): if session.exclude and session.vrf: data = self.ibgp_session_data(session, ip_version=4) stanza = config_stanza(data) vrf_ibgp_neighbors[session.vrf].append(stanza) g_ibgp_v6 = self.anm['ibgp_v6'] for session in sort_sessions(g_ibgp_v6.edges(vrf_node)): if session.exclude and session.vrf: data = self.ibgp_session_data(session, ip_version=6) stanza = config_stanza(data) vrf_ibgp_neighbors[session.vrf].append(stanza) # eBGP sessions for this VRF vrf_ebgp_neighbors = defaultdict(list) for session in sort_sessions(g_ebgp_v4.edges(vrf_node)): if session.exclude and session.vrf: data = self.ebgp_session_data(session, ip_version=4) stanza = config_stanza(data) vrf_ebgp_neighbors[session.vrf].append(stanza) for session in sort_sessions(g_ebgp_v6.edges(vrf_node)): if session.exclude and session.vrf: data = self.ebgp_session_data(session, ip_version=6) stanza = config_stanza(data) vrf_ebgp_neighbors[session.vrf].append(stanza) for vrf in vrf_node.node_vrf_names: rd_index = vrf_node.rd_indices[vrf] rd = '%s:%s' % (node.asn, rd_index) stanza = config_stanza( vrf=vrf, rd=rd, use_ipv4=node.ip.use_ipv4, use_ipv6=node.ip.use_ipv6, vrf_ebgp_neighbors=vrf_ebgp_neighbors[vrf], vrf_ibgp_neighbors=vrf_ibgp_neighbors[vrf], ) node.bgp.vrfs.append(stanza) # Retain route_target if in ibgp_vpn_v4 and RR or HRR (set in design) vpnv4_node = self.anm['ibgp_vpn_v4'].node(node) if vpnv4_node: retain = False if vpnv4_node.retain_route_target: retain = True node.bgp.vpnv4 = config_stanza(retain_route_target = retain)
def static_routes(self, node): node.static_routes_v4 = [] # initialise for case of no routes -> simplifies template logic node.host_routes_v4 = [] # initialise for case of no routes -> simplifies template logic node.static_routes_v6 = [] # initialise for case of no routes -> simplifies template logic node.host_routes_v6 = [] # initialise for case of no routes -> simplifies template logic if not self.anm['phy'].data.enable_routing: log.info('Routing disabled, not configuring static routes for Ubuntu server %s' % node) return if self.anm['phy'].node(node).dont_configure_static_routing: log.info('Static routing disabled for server %s' % node) return l3_conn_node = self.anm['l3_conn'].node(node) phy_node = self.anm['phy'].node(node) gateway_list = [n for n in l3_conn_node.neighbors() if n.is_router()] if not len(gateway_list): log.warning('Server %s is not directly connected to any routers' % node) return else: gateway = gateway_list[0] # choose first (and only gateway) if len(gateway_list) > 1: log.info('Server %s is multi-homed, using gateway %s' % (node, gateway)) # TODO: warn if server has no neighbors in same ASN (either in design or verification steps) # TODO: need to check that servers don't have any direct ebgp connections gateway_edge_l3 = self.anm['l3_conn'].edge(node, gateway) server_interface = gateway_edge_l3.src_int server_interface_id = self.nidb.interface(server_interface).id gateway_interface = gateway_edge_l3.dst_int gateway_ipv4 = gateway_ipv6 = None node.add_stanza("ip") if node.ip.use_ipv4: gateway_ipv4 = gateway_interface['ipv4'].ip_address if node.ip.use_ipv6: gateway_ipv6 = gateway_interface['ipv6'].ip_address # TODO: look at aggregation # TODO: catch case of ip addressing being disabled # TODO: handle both ipv4 and ipv6 # IGP advertised infrastructure pool from same AS static_routes_v4 = [] host_routes_v4 = [] for (asn, asn_routes) in self.anm['ipv4'].data['infra_blocks'].items(): # host_routes_v4 for infra_route in asn_routes: route_entry = { 'network': infra_route, 'prefix': infra_route.network, 'gw': gateway_ipv4, 'interface': server_interface_id, 'description': 'Route to infra subnet in AS %s via %s' \ % (asn, gateway), } route_entry = config_stanza(**route_entry) if infra_route.prefixlen == 32: host_routes_v4.append(route_entry) else: static_routes_v4.append(route_entry) # eBGP advertised loopbacks in all (same + other) ASes for (asn, asn_routes) in self.anm['ipv4'].data['loopback_blocks' ].items(): for asn_route in asn_routes: route_entry = { 'network': asn_route, 'prefix': asn_route.network, 'gw': gateway_ipv4, 'interface': server_interface_id, 'description': 'Route to loopback subnet in AS %s via %s' \ % (asn, gateway), } route_entry = config_stanza(**route_entry) if asn_route.prefixlen == 32: host_routes_v4.append(route_entry) else: static_routes_v4.append(route_entry) # TODO: combine the above logic into single step rather than creating dict then formatting with it cloud_init_static_routes = [] for entry in static_routes_v4: formatted = 'route add -net %s gw %s dev %s' \ % (entry.network, entry.gw, entry.interface) cloud_init_static_routes.append(formatted) for entry in host_routes_v4: formatted = 'route add -host %s gw %s dev %s' \ % (entry.prefix, entry.gw, entry.interface) cloud_init_static_routes.append(formatted) node.add_stanza("cloud_init") node.cloud_init.static_routes = cloud_init_static_routes
def bgp(self, node): node.add_stanza("bgp") node.bgp.lo_interface = self.lo_interface super(IosBaseCompiler, self).bgp(node) phy_node = self.anm['phy'].node(node) asn = phy_node.asn g_ebgp_v4 = self.anm['ebgp_v4'] g_ebgp_v6 = self.anm['ebgp_v6'] if node in g_ebgp_v4 \ and len(list(g_ebgp_v4.node(node).edges())) > 0: node.is_ebgp_v4 = True else: node.is_ebgp_v4 = False if node in g_ebgp_v6 \ and len(list(g_ebgp_v6.node(node).edges())) > 0: node.is_ebgp_v6 = True else: node.is_ebgp_v6 = False node.bgp.ipv4_advertise_subnets = [] node.bgp.ipv6_advertise_subnets = [] # Advertise loopbacks into BGP if node.ip.use_ipv4: node.bgp.ipv4_advertise_subnets = \ [node.loopback_zero.ipv4_cidr] if node.ip.use_ipv6: node.bgp.ipv6_advertise_subnets = \ [node.loopback_zero.ipv6_address] # Advertise infrastructure into eBGP if node.ip.use_ipv4 and node.is_ebgp_v4: infra_blocks = self.anm['ipv4'].data['infra_blocks'].get(asn) or [] for infra_route in infra_blocks: node.bgp.ipv4_advertise_subnets.append(infra_route) if node.ip.use_ipv6 and node.is_ebgp_v6: infra_blocks = self.anm['ipv6'].data['infra_blocks'].get(asn) or [] for infra_route in infra_blocks: node.bgp.ipv6_advertise_subnets.append(infra_route) self.nailed_up_routes(node) # vrf # TODO: this should be inside vrf section? node.bgp.vrfs = [] vrf_node = self.anm['vrf'].node(node) if vrf_node and vrf_node.vrf_role is 'PE': # iBGP sessions for this VRF vrf_ibgp_neighbors = defaultdict(list) g_ibgp_v4 = self.anm['ibgp_v4'] for session in sort_sessions(g_ibgp_v4.edges(vrf_node)): if session.exclude and session.vrf: data = self.ibgp_session_data(session, ip_version=4) stanza = config_stanza(data) vrf_ibgp_neighbors[session.vrf].append(stanza) g_ibgp_v6 = self.anm['ibgp_v6'] for session in sort_sessions(g_ibgp_v6.edges(vrf_node)): if session.exclude and session.vrf: data = self.ibgp_session_data(session, ip_version=6) stanza = config_stanza(data) vrf_ibgp_neighbors[session.vrf].append(stanza) # eBGP sessions for this VRF vrf_ebgp_neighbors = defaultdict(list) for session in sort_sessions(g_ebgp_v4.edges(vrf_node)): if session.exclude and session.vrf: data = self.ebgp_session_data(session, ip_version=4) stanza = config_stanza(data) vrf_ebgp_neighbors[session.vrf].append(stanza) for session in sort_sessions(g_ebgp_v6.edges(vrf_node)): if session.exclude and session.vrf: data = self.ebgp_session_data(session, ip_version=6) stanza = config_stanza(data) vrf_ebgp_neighbors[session.vrf].append(stanza) for vrf in vrf_node.node_vrf_names: rd_index = vrf_node.rd_indices[vrf] rd = '%s:%s' % (node.asn, rd_index) stanza = config_stanza( vrf=vrf, rd=rd, use_ipv4=node.ip.use_ipv4, use_ipv6=node.ip.use_ipv6, vrf_ebgp_neighbors=vrf_ebgp_neighbors[vrf], vrf_ibgp_neighbors=vrf_ibgp_neighbors[vrf], ) node.bgp.vrfs.append(stanza) # Retain route_target if in ibgp_vpn_v4 and RR or HRR (set in design) vpnv4_node = self.anm['ibgp_vpn_v4'].node(node) if vpnv4_node: retain = False if vpnv4_node.retain_route_target: retain = True node.bgp.vpnv4 = config_stanza(retain_route_target=retain)
def ospf(self, node): """Returns OSPF links, also sets process_id """ g_ospf = self.anm['ospf'] g_ipv4 = self.anm['ipv4'] ospf_stanza = node.add_stanza("ospf") node.ospf.ipv4_mpls_te = False # default, inherited enable if necessary node.ospf.loopback_area = g_ospf.node(node).area or 0 node.ospf.process_id = 1 # TODO: set this in build_network module node.ospf.lo_interface = self.lo_interface node.ospf.ospf_links = [] # aggregate by area from collections import defaultdict interfaces_by_area = defaultdict(list) for interface in node.physical_interfaces: if interface.exclude_igp: continue # don't configure IGP for this interface ospf_int = g_ospf.interface(interface) if ospf_int and ospf_int.is_bound: area = ospf_int.area #TODO: can we remove the next line? area = str(area) # can't serialize IPAddress object to JSON #TODO: put in interface rather than interface.id for consistency stanza = config_stanza(id = interface.id, cost = int(ospf_int.cost), passive = False) if node.ip.use_ipv4: stanza.ipv4_address = ospf_int['ipv4'].ip_address stanza.ipv4_subnet = ospf_int['ipv4'].subnet if node.ip.use_ipv6: stanza.ipv6_address = ospf_int['ipv6'].ip_address stanza.ipv6_subnet = ospf_int['ipv6'].subnet interfaces_by_area[area].append(stanza) loopback_zero = node.loopback_zero ospf_loopback_zero = g_ospf.interface(loopback_zero) router_area = ospf_loopback_zero.area # area assigned to router router_area = str(router_area) # can't serialize IPAddress object to JSON stanza = config_stanza(id = node.loopback_zero.id, cost = 0, passive = True) interfaces_by_area[router_area].append(stanza) node.ospf.interfaces_by_area = config_stanza(**interfaces_by_area) added_networks = set() for interface in node.physical_interfaces: if interface.exclude_igp: continue # don't configure IGP for this interface ipv4_int = g_ipv4.interface(interface) ospf_int = g_ospf.interface(interface) if not ospf_int.is_bound: continue # not an OSPF interface try: ospf_cost = int(ospf_int.cost) except TypeError: try: ospf_cost = netaddr.IPAddress(ospf_int.cost) except (TypeError, netaddr.AddrFormatError): log.debug('Using default OSPF cost of 1 for %s on %s' % (ospf_int, node)) ospf_cost = 1 # default interface.ospf_cost = ospf_cost network = ipv4_int.subnet if ospf_int and ospf_int.is_bound and network \ not in added_networks: # don't add more than once added_networks.add(network) link_stanza = config_stanza(network = network, interface = interface, area = ospf_int.area) node.ospf.ospf_links.append(link_stanza)