def add_link(self, node, voisin, config_node, config_voisin, link_type='share', **kwargs): """ Add a physical link between 2 devices (routers, hosts, anycast servers). Arguments : - node / voisin : name of devices to link. - config_node : config of node for the link. - config_voisin : config of voisin for the link. - link_type : used if as of node and voisin are not the same. Note : if AS of the 2 devices are not the same, add an eBGP connection. """ as_1, as_2 = self.get_as_of(node), self.get_as_of(voisin) node, voisin = self.get(node), self.get(voisin) config_node = config_node.copy() ip1, ip2 = config_node.pop('ip', None), config_voisin.pop('ip', None) if 'subnet' in config_voisin: subnet = config_voisin.pop('subnet') if isinstance(subnet, dict): subnet = format_address(subnet, self.__prefixes) ip1, ip2 = subnet elif self.infer_ip_link: generated_ips = self.generate_ip(node, 2, 1) if generated_ips: ip1, ip2 = generated_ips kwargs = {**config_node, **config_voisin} if ip1 is not None: kwargs.setdefault('params1', {}) kwargs['params1']['ip'] = ip1 if ip2 is not None: kwargs.setdefault('params2', {}) kwargs['params2']['ip'] = ip2 if self.debug: print("Adding link between {} and {} with config : {}".format( node, voisin, kwargs)) link = self.addLink(node, voisin, **kwargs) if as_1 != as_2: self.add_ebgp_session(node, voisin, as_1, as_2, link_type) return link
def _build_anycast_servers(self, as_name, anycast, as_routers): rr_levels = [] for r_name, r_config in as_routers.items(): rr_levels.append( r_config.get('niveau', 1) if 'clients' in r_config or 'peers' in r_config else 0) anycast_rr_level = max(rr_levels) + 1 for anycast_config in anycast: anycast_address = anycast_config['addresses'] anycast_address = tuple( format_address(anycast_address, self.__prefixes)) self.__anycast.setdefault(anycast_address, []) if self.debug: print("Adding anycast address : {}".format(anycast_address)) for node in anycast_config.get('nodes', []): server_name = 'server_{}'.format( len(self.__anycast_servers) + 1) self.__as[as_name]['anycast_servers'][ server_name] = anycast_address self.__anycast[anycast_address].append((node, server_name)) s_config = {'lo_addresses': anycast_address} if self.debug: print("Adding server {} to this anycast address".format( server_name)) server = self.addRouter(server_name, config=RouterConfig, **s_config) self.add_daemons(server, {'bgp': anycast_config.get('bgp_config', {})}, {}) self.__anycast_servers[server_name] = server self.add_new_link(server_name, node) # Add the node to the clients of the router if 'clients' not in as_routers[ node] and 'peers' not in as_routers[node]: as_routers[node].setdefault('niveau', anycast_rr_level) as_routers[node].setdefault('clients', []) as_routers[node]['clients'].append(server_name) subnet = self.get_subnet_of(node) if subnet is not None: self.__subnets[subnet]['nodes'].append(server_name)
def _build_routers(self, as_name, routers, **default_config): default_daemons = default_config.pop('daemons', []) for r_name, r_config in routers.items(): self.__as[as_name]['routers'].append(r_name) r_config = {**default_config, **r_config} if 'lo_addresses' in r_config: # option lo_addresses = [IPV6_ADDRESS, IPV4_ADDRESS] to set the loopback address of the router # see https://ipmininet.readthedocs.io/en/latest/addressing.html r_config['lo_addresses'] = format_address( r_config['lo_addresses'], self.__prefixes) elif self.infer_ip_lo: lo_addr = self.generate_ip(r_name, ipv4=True, ipv6=True) if lo_addr is not None: r_config['lo_addresses'] = lo_addr r_kwargs = { k: v for k, v in r_config.items() if k in ('lo_addresses', ) } if self.debug: print("Adding router {} to AS {} with config {}".format( r_name, as_name, r_kwargs)) router = self.addRouter(r_name, config=RouterConfig, **r_kwargs) self.add_daemons(router, r_config.get('daemons', []), default_daemons) self.__routers[r_name] = router if 'clients' in r_config or 'peers' in r_config: niv = r_config.get('niveau', 1) rr_config = {'niveau': niv} if 'clients' in r_config: rr_config['clients'] = r_config['clients'] if 'peers' in r_config: rr_config['peers'] = r_config['peers'] self.__as[as_name]['rr'].setdefault(niv, {}) self.__as[as_name]['rr'][niv][r_name] = rr_config if 'hosts' in r_config: self.add_host_to_router(r_name, r_config['hosts']) if self.add_hosts: self.add_fictif_host(as_name, r_name) self._build_rr(as_name)
def add_link(self, node, voisin, config_node, config_voisin, link_type='share', **kwargs): as_1, as_2 = self.get_as_of(node), self.get_as_of(voisin) node, voisin = self.get(node), self.get(voisin) config_node = config_node.copy() ip1, ip2 = config_node.pop('ip', None), config_voisin.pop('ip', None) if self.infer_ip_link and ip1 is None and 'subnet' not in config_voisin: ip1 = self.generate_ip(node) if self.infer_ip_link and ip2 is None and 'subnet' not in config_voisin: ip2 = self.generate_ip(voisin) if 'subnet' in config_voisin: subnet = config_voisin.pop('subnet') if isinstance(subnet, dict): subnet = format_address(subnet, self.__prefixes) ip1, ip2 = subnet kwargs = {**config_node, **config_voisin} if ip1 is not None: kwargs.setdefault('params1', {}) kwargs['params1']['ip'] = ip1 if ip2 is not None: kwargs.setdefault('params2', {}) kwargs['params2']['ip'] = ip2 if self.debug: print("Adding link between {} and {} with config : {}".format( node, voisin, kwargs)) link = self.addLink(node, voisin, **kwargs) if as_1 != as_2: self.add_ebgp_session(node, voisin, as_1, as_2, link_type) return link
def add_addr_to_subnet(net, first_addr, host_bits, is_ipv6): sep = '.' if not is_ipv6 else ':' new_mask = 32 - host_bits if not is_ipv6 else 128 - host_bits ip_subnet = format_address(net, self.__prefixes, is_ipv6=is_ipv6) last_bits = ip_subnet.split('/')[0].split(sep)[-1] if is_ipv6: last_bits = 0 if last_bits == '' else int(last_bits, 16) else: last_bits = int(last_bits) last_bits += first_addr new_ip = ip_subnet.split('/')[0].split(sep) new_ip[-1] = str(last_bits) new_ip = sep.join(new_ip) + '/' + str(new_mask) return new_ip
def _build_subnets(self): for subnet_name, subnet_config in self.__subnets.items(): if self.debug: print( "Creating subnet {} with prefix :\n- IPv4 : {}\n- IPv6 : {}" .format(subnet_name, subnet_config.get('ipv4', None), subnet_config.get('ipv6', None))) addresses = format_address(subnet_config, self.__prefixes) nodes = [ self.get(node_name) for node_name in subnet_config.get('nodes', []) ] if len(nodes) > 0: if self.debug: print("Adding nodes {} to subnet".format(nodes)) self.addSubnet(nodes, subnets=addresses) elif self.debug: print("No node attached to this subnet")
def add_daemons(self, router, daemons, default_daemons=[]): """ Add daemon to router. Arguments : - router : the router class to which add daemons. - daemons : daemons specific for this router. - default_daemons : daemons by default. daemons and default_daemons can be : - list : name of daemons (will be added without specific config). - dict : {daemon_name : dict (config)} """ if isinstance(default_daemons, list): default_daemons = {d: {} for d in default_daemons} if isinstance(daemons, list): daemons = {d: {} for d in daemons} daemons = deep_merge(default_daemons, daemons) for d, d_config in daemons.items(): if self.debug: print("Adding daemon {} with config {}".format(d, d_config)) if d == 'ospf': router.addDaemon(OSPF) elif d == 'ospf6': router.addDaemon(OSPF6) elif d == 'bgp': if 'networks' in d_config: d_config['networks'] = format_address( d_config['networks'], self.__prefixes) if 'communities' in d_config: self.__communities[router] = d_config["communities"] families = (AF_INET(redistribute=('connected', )), AF_INET6(redistribute=('connected', ))) router.addDaemon(BGP, address_families=families) else: raise NotImplementedError( "Daemon {} is not supported yet !".format(d)) return True
def add_daemons(self, router, daemons, default_daemons=[]): if isinstance(default_daemons, list): default_daemons = {d: {} for d in default_daemons} if isinstance(daemons, list): daemons = {d: {} for d in daemons} daemons = {**default_daemons, **daemons} for d, d_config in daemons.items(): if self.debug: print("Adding daemon {} with config {}".format(d, d_config)) if d == 'ospf': router.addDaemon(OSPF) elif d == 'ospf6': router.addDaemon(OSPF6) elif d == 'bgp': if 'networks' in d_config: d_config['networks'] = format_address( d_config['networks'], self.__prefixes) families = (AF_INET(redistribute=('connected', )), AF_INET6(redistribute=('connected', ))) router.addDaemon(BGP, address_families=families) return True