def _find_peer_address(base: 'Router', peer: str, v6=False) \
         -> Tuple[Optional[str], Optional['Router']]:
     """Return the IP address that base should try to contact to establish
     a peering"""
     visited = set()  # type: Set[IPIntf]
     to_visit = {i.name: i for i in realIntfList(base)}
     prio_queue = [(0, i) for i in to_visit.keys()]
     #heapq.heapify(prio_queue)
     # Explore all interfaces in base ASN recursively, until we find one
     # connected to the peer
     iterations = 0
     while to_visit:
         path_cost, i = prio_queue.pop(0)
         if i in visited:
             continue
         i = to_visit.pop(i)
         visited.add(i)
         for n in i.broadcast_domain.routers:
             if n.node.name == peer:
                 if not v6:
                     return n.ip, n.node
                 if n.ip6 and not ip_address(n.ip6).is_link_local:
                     return n.ip6, n.node
                 return None, None
             if n.node.asn == base.asn or not n.node.asn:
                 for i in realIntfList(n.node):
                     to_visit[i.name] = i
                     prio_queue += [
                         (path_cost + i.igp_metric, i.name),
                     ]
         iterations += 1
     return None, None
Пример #2
0
    def compute_routerid(self):
        """Computes the default router id for all daemons.
        If a router ids were explicitly set for some of its daemons,
        the router id set to the daemon with the highest priority is chosen as the global router id.
        Otherwise if it has IPv4 addresses, it returns the most-visible one among its router interfaces.
        If both conditions are wrong, it generates a unique router id."""

        for d in self.daemons:
            if d.options.routerid:
                return d.options.routerid

        ip_list = sorted((ip for itf in realIntfList(self._node)
                          for ip in itf.ips()),
                         cmp=address_comparator)
        if len(ip_list) == 0:

            to_visit = realIntfList(self._node)
            # Explore all routers to check that none has the same router id
            while to_visit:
                self.incr_last_routerid()
                visited = set()
                while to_visit:
                    i = to_visit.pop()
                    if i in visited:
                        continue
                    visited.add(i)
                    for n in i.broadcast_domain.routers:
                        if self._equal_routerid(n.node):
                            break  # We need to change the router id
                        to_visit.extend(realIntfList(n.node))
                to_visit = realIntfList(self._node) if to_visit else []
            return last_routerid.compressed
        else:
            id = ip_list.pop().ip.compressed
            return id
Пример #3
0
    def compute_routerid(self):
        """Computes the default router id for all daemons.
        If a router ids were explicitly set for some of its daemons,
        the router id set to the daemon with the highest priority is chosen as the global router id.
        Otherwise if it has IPv4 addresses, it returns the most-visible one among its router interfaces.
        If both conditions are wrong, it generates a unique router id."""

        for d in self.daemons:
            if d.options.routerid:
                return d.options.routerid

        ip_list = sorted(
            (ip for itf in realIntfList(self._node) for ip in itf.ips()),
            cmp=address_comparator)
        if len(ip_list) == 0:

            to_visit = realIntfList(self._node)
            # Explore all routers to check that none has the same router id
            while to_visit:
                self.incr_last_routerid()
                visited = set()
                while to_visit:
                    i = to_visit.pop()
                    if i in visited:
                        continue
                    visited.add(i)
                    for n in i.broadcast_domain.routers:
                        if self._equal_routerid(n.node):
                            break  # We need to change the router id
                        to_visit.extend(realIntfList(n.node))
                to_visit = realIntfList(self._node) if to_visit else []
            return last_routerid.compressed
        else:
            id = ip_list.pop().ip.compressed
            return id
Пример #4
0
 def _fill_rdnss_addresses(self):
     for itf in realIntfList(self._node):
         for rdnss in itf.rdnss_list:
             if rdnss.ips is None:
                 rdnss.ips = []
                 dns = find_node(self._node, rdnss.node).node
                 for dns_itf in realIntfList(dns):
                     for ip in dns_itf.ip6s(exclude_lls=True):
                         rdnss.ips.append(ip.ip.compressed)
Пример #5
0
    def _find_peer_address(base: 'Router', peer: str, v6=False) \
            -> Tuple[Optional[str], Optional['Router'], Optional[str]]:
        """
        Finds the IP address of the peer from the base router to
        typically configure the BGP session between the two routers.

        :param base: The router from which the peer's address must be found
        :param peer: the name of the node for which we are looking for the IP address
        :param v6: if set to True, the function seeks the IPv6 address.
                   Otherwise, if set to False, it looks for the IPv4 address
        :return: a 3-Tuple <peer IP, peer Router object, local base IP>
                 peer IP: the IP address set on the peer interface
                 peer Router object: the node object related to the peer
                 local base IP: the local IP address used on base router
                                to establish the connection with the peer
        """
        visited = set()  # type: Set[str]
        to_visit = {i.name: i for i in realIntfList(base)}
        prio_queue: List['Peer.PQNode'] = [
            Peer.PQNode((0, i), to_visit[i]) for i in to_visit.keys()
        ]
        heapq.heapify(prio_queue)
        # Explore all interfaces in base ASN recursively, until we find one
        # connected to the peer
        while to_visit:
            node = heapq.heappop(prio_queue)
            path_cost = node.key[0]
            i = node.key[1]
            my_interface = node.value
            if i in visited:
                continue
            visited.add(
                i)  # putting the string representation of the interface
            i = to_visit.pop(i)
            for n in i.broadcast_domain.routers:
                if n.node.name == peer:
                    if not v6:
                        return n.ip, n.node, my_interface.ip
                    if n.ip6 and not ip_address(n.ip6).is_link_local:
                        return n.ip6, n.node, my_interface.ip6
                    return None, None, None
                if n.node.asn == base.asn or not n.node.asn:
                    for i in realIntfList(n.node):
                        to_visit[i.name] = i
                        heapq.heappush(
                            prio_queue,
                            Peer.PQNode((path_cost + i.igp_metric, i.name),
                                        my_interface))
        return None, None, None
Пример #6
0
 def build(self):
     cfg = super(OSPF, self).build()
     cfg.redistribute = self.options.redistribute
     interfaces = [itf for itf in realIntfList(self._node)]
     cfg.interfaces = self._build_interfaces(interfaces)
     cfg.networks = self._build_networks(interfaces)
     return cfg
Пример #7
0
    def createDefaultRoutes(self):
        if 'defaultRoute' in self.params:
            return True

        # The first router we find will become the default gateway
        found = False
        for itf in realIntfList(self):
            for r in itf.broadcast_domain.routers:
                if self.use_v4 and self.use_v4 and len(r.addresses[4]) > 0:
                    self.setDefaultRoute("dev {} via {}".format(itf.name,
                                                                r.ip),
                                         v6=False)
                    found = True
                if self.use_v6 and self.use_v6 and len(r.addresses[6]) > 0 \
                        and len(r.ra_prefixes) == 0:
                    # We define a default route only if router
                    # advertisements are not activated. If we call the same
                    # function, the route created above might be deleted
                    self.setDefaultRoute("dev {} via {}".format(itf.name,
                                                                r.ip6),
                                         v6=True)
                    found = True
                break
            if found:
                return True
        return False
Пример #8
0
    def _equal_routerid(self, n):

        # Router id of 'n' already set
        if n.config.routerid:
            return str(n.config.routerid) != str(last_routerid)

        # Check that a router id explicitly set
        # in any other daemon is not in conflict
        # with the current router id
        for d in n.config.daemons:
            if d != self \
                    and d.options.routerid \
                    and str(d.options.routerid) == str(last_routerid):
                return True

        # Check that the most-visible IPv4 address is not in conflict
        # with the current router id
        ip_list = sorted((ip for itf in realIntfList(n)
                          for ip in itf.ips()),
                         cmp=address_comparator)
        if len(ip_list) != 0 \
                and str(ip_list.pop().ip) == str(last_routerid):
            return True

        return False
Пример #9
0
    def _equal_routerid(self, n):

        # Router id of 'n' already set
        if n.config.routerid:
            return str(n.config.routerid) != str(last_routerid)

        # Check that a router id explicitly set
        # in any other daemon is not in conflict
        # with the current router id
        for d in n.config.daemons:
            if d != self \
                    and d.options.routerid \
                    and str(d.options.routerid) == str(last_routerid):
                return True

        # Check that the most-visible IPv4 address is not in conflict
        # with the current router id
        ip_list = sorted((ip for itf in realIntfList(n)
                          for ip in itf.ips()),
                         key=OrderedAddress)
        if len(ip_list) != 0 \
                and str(ip_list.pop().ip) == str(last_routerid):
            return True

        return False
Пример #10
0
    def build_zone(self, zone: 'DNSZone') -> ConfigDict:
        master_ips = []
        for s_name in zone.servers + [zone.dns_master] + zone.dns_slaves:
            server_itf = find_node(self._node, s_name)
            if server_itf is None:
                lg.error("Cannot find the server node {name} of DNS zone"
                         " {zone}. Are you sure that they are connected to "
                         "the current node {current}?".format(
                             name=s_name,
                             zone=zone.name,
                             current=self._node.name))
                continue
            server = server_itf.node
            for itf in realIntfList(server):
                for ip in itf.ips():
                    if ".arpa" not in zone.name:  # Not a Reverse zone
                        zone.soa_record.add_record(
                            ARecord(s_name, ip.ip.compressed))
                    if s_name == zone.dns_master:
                        master_ips.append(ip.ip.compressed)

                for ip6 in itf.ip6s(exclude_lls=True):
                    if ".arpa" not in zone.name:  # Not a Reverse zone
                        zone.soa_record.add_record(
                            AAAARecord(s_name, ip6.ip.compressed))
                    if s_name == zone.dns_master:
                        master_ips.append(ip6.ip.compressed)

        return ConfigDict(name=zone.soa_record.domain_name,
                          soa_record=zone.soa_record,
                          records=zone.soa_record.records,
                          master=self._node.name == zone.dns_master,
                          master_ips=master_ips)
Пример #11
0
 def build(self):
     cfg = super(Zebra, self).build()
     # Update with preset defaults
     cfg.update(self.options)
     # Track interfaces
     cfg.interfaces = (ConfigDict(name=itf.name, description=itf.describe)
                       for itf in realIntfList(self._node))
     return cfg
Пример #12
0
 def build(self):
     cfg = super(PIMD, self).build()
     cfg.update(self.options)
     cfg.interfaces = [ConfigDict(
         name=itf.name,
         ssm=itf.get('multicast_ssm', self.options.multicast_ssm),
         igmp=itf.get('multicast_igmp', self.options.multicast_igmp))
         for itf in realIntfList(self._node) if itf.enable_multicast]
     return cfg
Пример #13
0
 def build(self):
     cfg = super().build()
     cfg.update(self.options)
     cfg.node_name = self._node.name
     interfaces = realIntfList(self._node)
     cfg.interfaces = self._build_interfaces(interfaces)
     cfg.networks = self._build_networks(interfaces)
     cfg.prefixes = self._build_prefixes(interfaces)
     return cfg
Пример #14
0
 def build(self):
     cfg = super(Zebra, self).build()
     # Update with preset defaults
     cfg.update(self.options)
     # Track interfaces
     cfg.interfaces = (ConfigDict(name=itf.name,
                                  description=itf.describe)
                       for itf in realIntfList(self._node))
     return cfg
Пример #15
0
 def build(self):
     cfg = super(Openr, self).build()
     cfg.update(self.options)
     cfg.node_name = self._node.name
     interfaces = [itf
                   for itf in realIntfList(self._node)]
     cfg.interfaces = self._build_interfaces(interfaces)
     cfg.networks = self._build_networks(interfaces)
     cfg.prefixes = self._build_prefixes(interfaces)
     return cfg
Пример #16
0
 def build(self):
     cfg = super().build()
     self.options.redistribute_ifaces = \
         ','.join([intf.name for intf in self._node.intfList()])
     cfg.update(self.options)
     interfaces = realIntfList(self._node)
     cfg.interfaces = self._build_interfaces(interfaces)
     cfg.networks = self._build_networks(interfaces)
     cfg.prefixes = self._build_prefixes(interfaces)
     return cfg
Пример #17
0
 def build(self):
     cfg = super(RADVD, self).build()
     # Update with preset defaults
     cfg.update(self.options)
     # Track interfaces
     cfg.interfaces = (ConfigDict(name=itf.name, description=itf.describe,
                                  ra_prefixes=itf.ra_prefixes,
                                  rdnss_list=itf.rdnss_list)
                       for itf in realIntfList(self._node)
                       if itf.ra_prefixes)
     return cfg
Пример #18
0
 def _find_peer_address(base, peer):
     """Return the IP address that base should try to contact to establish
     a peering"""
     visited = set()
     to_visit = realIntfList(base)
     # Explore all interfaces in base ASN recursively, until we find one
     # connected to the peer
     while to_visit:
         i = to_visit.pop()
         if i in visited:
             continue
         visited.add(i)
         for n in i.broadcast_domain.routers:
             if n.node.name == peer:
                 ip = n.ip
                 return (ip, n.node) if ip else (
                     n.ip6, n.node)
             elif n.node.asn == base.asn or not n.node.asn:
                 to_visit.extend(realIntfList(n.node))
     return None, None
Пример #19
0
 def _find_peer_address(base, peer):
     """Return the IP address that base should try to contact to establish
     a peering"""
     visited = set()
     to_visit = realIntfList(base)
     # Explore all interfaces in base ASN recursively, until we find one
     # connected to the peer
     while to_visit:
         i = to_visit.pop()
         if i in visited:
             continue
         visited.add(i)
         for n in i.broadcast_domain.routers:
             if n.node.name == peer:
                 ip = n.ip
                 return (ip, n.node) if ip else (
                     n.ip6, n.node)
             elif n.node.asn == base.asn or not n.node.asn:
                 to_visit.extend(realIntfList(n.node))
     return None, None
Пример #20
0
 def build(self):
     cfg = super(RADVD, self).build()
     # Update with preset defaults
     cfg.update(self.options)
     # Track interfaces
     cfg.interfaces = (ConfigDict(name=itf.name,
                                  description=itf.describe,
                                  ra_prefixes=itf.ra_prefixes,
                                  rdnss_list=itf.rdnss_list)
                       for itf in realIntfList(self._node)
                       if itf.ra_prefixes)
     return cfg
Пример #21
0
 def build(self):
     cfg = super(RIPng, self).build()
     cfg.redistribute = self.options.redistribute
     cfg.split_horizon = self.options.split_horizon
     cfg.split_horizon_with_poison = self.options.split_horizon_with_poison
     cfg.timers = self._build_timers(self.options.update_timer,
                                     self.options.timeout_timer,
                                     self.options.garbage_timer)
     interfaces = [itf for itf in realIntfList(self._node)]
     cfg.interfaces = self._build_interfaces(interfaces)
     cfg.networks = self._build_networks(interfaces)
     return cfg
Пример #22
0
 def build(self):
     cfg = super(RADVD, self).build()
     # Update with preset defaults
     cfg.update(self.options)
     # Track interfaces
     cfg.interfaces = (ConfigDict(name=itf.name, description=itf.describe,
                                  ra_prefixes=itf.ra_prefixes,
                                  rdnss_list=itf.rdnss_list)
                       for itf in realIntfList(self._node)
                       if itf.ra_prefixes)
     # Fill AdvConnectedPrefix prefixes
     self._fill_connected_prefixes()
     # Fill AdvRDNSS IP addresses
     self._fill_rdnss_addresses()
     return cfg
Пример #23
0
    def post_build(self, net):
        # Run the failure plan and then, restore the links
        failure_plan = [("r1", "r2"), ("r3", "r4")]
        interfaces_down = net.runFailurePlan(failure_plan)
        net.restoreIntfs(interfaces_down)

        # Run a random failure with 2 link to be downed and then, restore them
        interfaces_down = net.randomFailure(2)
        net.restoreIntfs(interfaces_down)

        # Run a 1 link Failure Random based on a given list of link
        # and then, restore the link
        links = list(map(lambda x: x.link, realIntfList(net["r1"])))
        interfaces_down = net.randomFailure(1, weak_links=links)
        net.restoreIntfs(interfaces_down)
        super().post_build(net)
Пример #24
0
    def network_ips(self) -> Dict[str, List[str]]:
        """Return all the addresses of the nodes connected directly or not
        to this node"""
        ips = {}  # type: Dict[str, List[str]]
        visited = set()  # type: Set[str]
        to_visit = [self]
        while to_visit:
            node = to_visit.pop()
            if node.name in visited:
                continue
            visited.add(node.name)
            if isinstance(node, (Host, IPNode)):
                for i in node.intfList():
                    for ip in list(i.ips()) \
                              + list(i.ip6s(exclude_lls=True)):
                        ips.setdefault(node.name, []).append(ip.ip.compressed)

            for i in realIntfList(node):
                adj_i = otherIntf(i)
                if adj_i is not None:
                    to_visit.append(adj_i.node)
        return ips
Пример #25
0
def test_topologydb(topology: Type[IPTopo]):
    net = IPNet(topo=topology())
    try:
        db = TopologyDB(net=net)

        db_path = "/tmp/.test_topologydb.json"
        if os.path.exists(db_path):
            os.unlink(db_path)
        db.save(db_path)

        assert os.path.exists(db_path), \
            "TopologyDB did not write the JSON database"

        db = TopologyDB(db=db_path)

        for node in net.routers + net.hosts + net.switches:
            assert node.name in db._network, \
                "The node {} in the network is not in the DB file".format(node)

        for node, node_info in db._network.items():
            assert node in net, \
                "The node {} in the DB file is not in the network".format(node)

            # Check type

            assert "type" in node_info, \
                "No info on the type of node {}".format(node)
            node_type = node_info["type"]
            if node_type == "host":
                assert type(net[node]) == IPHost, "The node {} is not an " \
                                                  "host".format(node)
            elif node_type == "router":
                assert type(net[node]) == Router, "The node {} is not a " \
                                                  "router".format(node)
            elif node_type == "switch":
                assert type(net[node]) == IPSwitch, "The node {} is not a " \
                                                    "switch".format(node)
            else:
                pytest.fail("The node type {} of node {} is invalid".format(
                    node_type, node))

            # Check interfaces

            assert "interfaces" in node_info, \
                "No information about interfaces of node {}".format(node)
            real_intfs = {itf.name for itf in realIntfList(net[node])}
            assert real_intfs == set(node_info["interfaces"]), \
                "The interface list is not the same on node {}".format(node)

            for info_key, info_value in node_info.items():
                if info_key == "type" or info_key == "interfaces":
                    continue

                try:
                    intf = net[node].intf(info_key)
                    # info_key is a interface name
                except KeyError:
                    # info_key is a node name
                    assert info_key in net, \
                        "{} is neither a node nor an interface nor a special " \
                        "key of node {}".format(info_key, node)
                    intf = net[node].intf(info_value["name"])

                    # Checks that the node is a neighbor
                    assert otherIntf(intf).node.name == info_key, \
                        "The node {} has no neighbor node {}".format(node,
                                                                     info_key)

                # Checks the IP address
                assert info_value["ip"] == '%s/%s' % (intf.ip, intf.prefixLen), \
                    "The IP address of the record {} of node {} does not " \
                    "match".format(info_key, node)

                # Checks the IP prefixes
                prefixes = {
                    ip.with_prefixlen
                    for ip in itertools.chain(intf.ips(), intf.ip6s())
                }
                assert set(info_value["ips"]) == prefixes, \
                    "The IP prefixes of the record {} of node {} do not " \
                    "match".format(info_key, node)

    finally:
        net.stop()
Пример #26
0
 def _fill_connected_prefixes(self):
     for itf in realIntfList(self._node):
         for ra_prefix in itf.ra_prefixes:
             if isinstance(ra_prefix, AdvConnectedPrefix):
                 for ip in itf.ip6s(exclude_lls=True):
                     ra_prefix.prefixes.append(ip.network.with_prefixlen)