# 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
#
# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
-import ipaddr
+import ipaddress
import networkx
+import math
import random
class TopologyType:
: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).
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):
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)
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
return self.topology.node[nid].get(name)
def node_annotations(self, nid):
- return self.topology.node[nid].keys()
+ return list(self.topology.node[nid].keys())
def del_node_annotation(self, nid, name):
del self.topology.node[nid][name]
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
return self.topology.edge[nid1][nid2].get("net", dict())
def edge_annotation(self, nid1, nid2, name):
- return self.topoplogy.edge[nid1][nid2].get(name)
+ return self.topology.edge[nid1][nid2].get(name)
def edge_annotations(self, nid1, nid2):
- return self.topology.edge[nid1][nid2].keys()
+ return list(self.topology.edge[nid1][nid2].keys())
def del_edge_annotation(self, nid1, nid2, name):
del self.topology.edge[nid1][nid2][name]
# Assign IP addresses to host
netblock = "%s/%d" % (network, prefix)
if version == 4:
- net = ipaddr.IPv4Network(netblock)
- new_prefix = 31
+ net = ipaddress.ip_network(netblock)
+ new_prefix = 30
elif version == 6:
- net = ipaddr.IPv6Network(netblock)
- new_prefix = 31
+ net = 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():
#### 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
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)