X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=src%2Fnepi%2Futil%2Fnetgraph.py;h=96fb384d81acd24991f7c869a068f9d14dad513a;hb=3fe2e6f7812888dc1366915545dd2243ff6fb1bb;hp=6d68622651b298251b769466ba333f67e7e3c775;hpb=ec3460fce064ea44366cb417dea0f9e148d3d804;p=nepi.git diff --git a/src/nepi/util/netgraph.py b/src/nepi/util/netgraph.py index 6d686226..96fb384d 100644 --- a/src/nepi/util/netgraph.py +++ b/src/nepi/util/netgraph.py @@ -3,9 +3,8 @@ # Copyright (C) 2013 INRIA # # This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation; # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -17,10 +16,17 @@ # # Author: Alina Quereilhac -import ipaddr import networkx +import math import random +from six import next, PY2, PY3 +if PY2: + import ipaddr +else: + import ipaddress + + class TopologyType: LINEAR = "linear" LADDER = "ladder" @@ -69,10 +75,18 @@ class NetGraph(object): :param version: IP version for IP address assignment. :type version: int - :param assign_st: Select source and target nodes on the graph. :type assign_st: bool + :param sources_targets: dictionary with the list of sources (key = + "sources") and list of targets (key = "targets") if defined, ignore + assign_st + :type sources_targets: dictionary of lists + + :param leaf_source: if True, random sources will be selected only + from leaf nodes. + :type leaf_source: bool + NOTE: Only point-to-point like network topologies are supported for now. (Wireless and Ethernet networks were several nodes share the same edge (hyperedge) can not be modeled for the moment). @@ -99,9 +113,13 @@ class NetGraph(object): self.assign_p2p_ips(network = network, prefix = prefix, version = version) - if kwargs.get("assign_st"): + sources_targets = kwargs.get("sources_targets") + if sources_targets: + [self.set_source(n) for n in sources_targets["sources"]] + [self.set_target(n) for n in sources_targets["targets"]] + elif kwargs.get("assign_st"): self.select_target_zero() - self.select_random_leaf_source() + self.select_random_source(is_leaf = kwargs.get("leaf_source")) @property def topology(self): @@ -143,32 +161,21 @@ class NetGraph(object): nodesinbranch = (node_count - 1)/ BRANCHES c = 1 - for i in xrange(BRANCHES): + for i in range(BRANCHES): prev = 0 - for n in xrange(1, nodesinbranch + 1): + for n in range(1, nodesinbranch + 1): graph.add_node(c) graph.add_edge(prev, c) prev = c c += 1 - # node ids are int, make them str - g = networkx.Graph() - g.add_nodes_from(map(lambda nid: str(nid), graph.nodes())) - g.add_edges_from(map(lambda t: (str(t[0]), str(t[1])), - graph.edges())) - - return g + return graph def add_node(self, nid): - nid = str(nid) - if nid not in self.topology: self.topology.add_node(nid) def add_edge(self, nid1, nid2): - nid1 = str(nid1) - nid2 = str(nid2) - self.add_node(nid1) self.add_node( nid2) @@ -187,7 +194,7 @@ class NetGraph(object): def annotate_node(self, nid, name, value): if not isinstance(value, str) and not isinstance(value, int) and \ not isinstance(value, float) and not isinstance(value, bool): - raise RuntimeError, "Non-serializable annotation" + raise RuntimeError("Non-serializable annotation") self.topology.node[nid][name] = value @@ -195,7 +202,9 @@ class NetGraph(object): return self.topology.node[nid].get(name) def node_annotations(self, nid): - return self.topology.node[nid].keys() + retcod = self.topology.node[nid].keys() + if PY3: retcod = list(retcod) + return retcod def del_node_annotation(self, nid, name): del self.topology.node[nid][name] @@ -203,7 +212,7 @@ class NetGraph(object): def annotate_edge(self, nid1, nid2, name, value): if not isinstance(value, str) and not isinstance(value, int) and \ not isinstance(value, float) and not isinstance(value, bool): - raise RuntimeError, "Non-serializable annotation" + raise RuntimeError("Non-serializable annotation") self.topology.edge[nid1][nid2][name] = value @@ -223,7 +232,9 @@ class NetGraph(object): return self.topology.edge[nid1][nid2].get(name) def edge_annotations(self, nid1, nid2): - return self.topology.edge[nid1][nid2].keys() + retcod = self.topology.edge[nid1][nid2].keys() + if PY3: retcod = list(retcod) + return retcod def del_edge_annotation(self, nid1, nid2, name): del self.topology.edge[nid1][nid2][name] @@ -249,13 +260,13 @@ class NetGraph(object): # Assign IP addresses to host netblock = "%s/%d" % (network, prefix) if version == 4: - net = ipaddr.IPv4Network(netblock) + net = ipaddr.IPv4Network(netblock) if PY2 else ipaddress.ip_network(netblock) new_prefix = 30 elif version == 6: - net = ipaddr.IPv6Network(netblock) + net = ipaddr.IPv6Network(netblock) if PY2 else ipaddress.ip_network(netblock) new_prefix = 30 else: - raise RuntimeError, "Invalid IP version %d" % version + raise RuntimeError("Invalid IP version %d" % version) ## Clear all previusly assigned IPs for nid in self.topology.nodes(): @@ -268,15 +279,15 @@ class NetGraph(object): #### Compute subnets for each link # get a subnet of base_add with prefix /30 - subnet = sub_itr.next() + subnet = next(sub_itr) mask = subnet.netmask.exploded network = subnet.network.exploded prefixlen = subnet.prefixlen # get host addresses in that subnet i = subnet.iterhosts() - addr1 = i.next() - addr2 = i.next() + addr1 = next(i) + addr2 = next(i) ip1 = addr1.exploded ip2 = addr2.exploded @@ -314,27 +325,28 @@ class NetGraph(object): if self.topology.node[nid].get("source")] def select_target_zero(self): - """ Marks the node 0 as target + """ Mark the node 0 as target """ - self.set_target("0") + nid = 0 if 0 in self.topology.nodes() else "0" + self.set_target(nid) - def select_random_leaf_source(self): - """ Marks a random leaf node as source. + def select_random_source(self, **kwargs): + """ Mark a random node as source. """ # The ladder is a special case because is not symmetric. if self.topo_type == TopologyType.LADDER: total_nodes = self.order/2 - leaf1 = str(total_nodes - 1) - leaf2 = str(nodes - 1) + leaf1 = total_nodes + leaf2 = total_nodes - 1 leaves = [leaf1, leaf2] source = leaves.pop(random.randint(0, len(leaves) - 1)) else: # options must not be already sources or targets - options = [ k for k,v in self.topology.degree().iteritems() \ - if v == 1 and not self.topology.node[k].get("source") \ + options = [ k for k,v in self.topology.degree().items() \ + if (not kwargs.get("is_leaf") or v == 1) \ + and not self.topology.node[k].get("source") \ and not self.topology.node[k].get("target")] - source = options.pop(random.randint(0, len(options) - 1)) self.set_source(source)