Esempio n. 1
0
def make_connected(network):
    neighbors = convert_to_neighbors(network)
    clusters = _get_clusters_sets(neighbors)

    def get_unique_id(neighbors, i=0):
        if f'interconnect-{i}' not in neighbors:
            return f'interconnect-{i}'
        else:
            return get_unique_id(neighbors, i + 1)

    def get_center_node(neighbors, cluster):
        max_neighbors = 0
        center_node = None
        for sid, neighs in neighbors.items():
            if sid in cluster and len(neighs) >= max_neighbors:
                max_neighbors = len(neighs)
                center_node = sid
        return center_node

    if len(clusters) > 1:
        central = get_unique_id(neighbors)

        # connect all clusters via central node
        for cluster in clusters:
            center = get_center_node(neighbors, cluster)
            network['links'].append({
                'source': central,
                'target': center,
                'type': 'vpn'
            })
Esempio n. 2
0
def get_paths_to_gateways(network, gateways):
    nodes = list(convert_to_neighbors(network).keys())

    dijkstra = Dijkstra(network)

    paths = []

    # remove gateways from nodes list
    for gateway in gateways:
        nodes.remove(gateway)

    for node in nodes:
        distance_min = math.inf
        gateway_min = None
        for gateway in gateways:
            d = dijkstra.find_shortest_distance(gateway, node)
            if distance_min == math.inf or d <= distance_min:
                distance_min = d
                gateway_min = gateway

        if gateway_min is not None:
            paths.append((node, gateway))

    return paths
Esempio n. 3
0
def _get_remote_mapping(cur_state, new_state, remotes, cur_state_rmap):
    def partition_into_subgraph_nodes(neighbor_map, nodes, rmap, remotes):
        random.shuffle(nodes)
        # remote_id => [<node_ids>]
        partitions = {}

        # keep running nodes on the same partition
        for node_id, remote in rmap.items():
            remote_id = remotes.index(remote)
            partitions.setdefault(remote_id, []).append(node_id)
            if node_id not in nodes:
                eprint(f'Node {node_id} not in previous state!')
                stop_all_terminals()
                exit(1)
            nodes.remove(node_id)

        for remote_id in range(len(remotes)):
            if len(nodes) == 0:
                break
            if remote_id not in partitions:
                partitions[remote_id] = [nodes.pop()]

        # find neighbor node of cluster
        def grow_cluster(cluster, nodes):
            for node in nodes:
                for cluster_node in cluster:
                    if node in neighbor_map[cluster_node]:
                        cluster.append(node)
                        nodes.remove(node)
                        return
            # cannot extend cluster via neighbor => use left over node
            cluster.append(nodes.pop())

        while len(nodes) > 0:
            # get smallest cluster (remote) key
            key = min(partitions.keys(), key=lambda k: len(partitions[k]))
            grow_cluster(partitions[key], nodes)

        return partitions

    # get node distribution balance
    def get_variance(partition):
        median = 0
        for remote_id, cluster in partition.items():
            median += len(cluster)
        median /= len(partition)

        q = 0
        for remote_id, cluster in partition.items():
            q = (len(cluster) - median)**2

        return math.sqrt(q / len(partition))

    def partition_to_map(partition, remotes):
        node_to_remote_map = {}
        for remote_id, node_ids in partition.items():
            for node_id in node_ids:
                node_to_remote_map[node_id] = remotes[remote_id]
        return node_to_remote_map

    '''
    # debug output
    def debug_partition(partition, remotes):
        print('partitioning:')

        for remote_id, cluster in partition.items():
            print('  {}: {} nodes'.format(remotes[remote_id].get('address', 'local'), len(cluster)))

        interconnects = 0
        node_to_remote_map = partition_to_map(partition, remotes)
        for link in new_state.get('links', []):
            if node_to_remote_map[str(link['source'])] is not node_to_remote_map[str(link['target'])]:
                interconnects += 1
        print(f'  l2tp links: {interconnects}')
    '''

    # try multiple random (connected) partitions and select the best
    neighbor_map = convert_to_neighbors(cur_state, new_state)
    tries = 20
    lowest_variance = math.inf
    best_partition = []

    # shortcut: if no mapping on multiple remotes is needed
    if len(remotes) == 1 and len(cur_state_rmap) == 0:
        return partition_to_map({0: neighbor_map.keys()}, remotes)

    for _ in range(tries):
        partition = partition_into_subgraph_nodes(neighbor_map,
                                                  list(neighbor_map.keys()),
                                                  cur_state_rmap, remotes)
        if partition:
            variance = get_variance(partition)
            if variance < lowest_variance:
                lowest_variance = variance
                best_partition = partition

    if len(best_partition) == 0:
        eprint('No network partition found.')
        stop_all_terminals()
        exit(1)

    #if verbosity in ['verbose', 'normal']:
    #    debug_partition(best_partition, remotes)

    # node_id => remote
    return partition_to_map(best_partition, remotes)
Esempio n. 4
0
 def __init__(self, network):
     self.dists_cache = {}
     self.prevs_cache = {}
     self.nodes = convert_to_neighbors(network)
Esempio n. 5
0
def get_random_nodes(network, count):
    nodes = list(convert_to_neighbors(network).keys())
    return random.sample(nodes, count)
Esempio n. 6
0
def get_random_paths(network=None, count=10, seed=None):
    nodes = list(convert_to_neighbors(network).keys())
    return _get_random_paths(nodes=nodes, count=count, seed=seed)