diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e7498fa --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +__pycache__ +*.bak +*.ntfl +*.topo.sh +example/*.py \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..ff0f1e8 --- /dev/null +++ b/README.md @@ -0,0 +1,35 @@ +# Nanonet + +This repository implements the Nanonet tool, as described [here](https://segment-routing.org/index.php/Testing/Nanonet). + +As Python 2 is now deprecated, it was updated in September 2024 to support Python 3 runtime. + +## Running the example + +- Check the contents of the NTFL example file +``` +nanonet $ cat example/example.ntfl +A B 1 0.2 100000 +A C 1 0.2 100000 +B C 1 0.2 100000 +``` + +- Generate a topology out of this file: +``` +nanonet $ ./tools/ntfl2topo.sh example/example.ntfl Test > example/example.py +``` + +- Create a deployment script out of the topology: +``` +nanonet $ ./build example/example.py Test +# Building topology... +# Assigning prefixes... +# Running dijkstra... (3 nodes) +# Running dijkstra for node B (1/3) +# Running dijkstra for node C (2/3) +# Running dijkstra for node A (3/3) +nanonet $ +``` + +You obtain a file named Test.topo.sh that contains all the commands to execute to deploy the topology on linux. + diff --git a/addr.py b/addr.py index 1f4f5c6..de08c26 100644 --- a/addr.py +++ b/addr.py @@ -16,7 +16,7 @@ def __init__(self, net, mask, submask): self.idx_low = self.submask/8 - 1 def next_net(self): - i = self.idx_low + i = int(self.idx_low) while i >= self.idx_high: if self.curnet[i] == 0xff: diff --git a/build b/build index a9f1831..f926728 100755 --- a/build +++ b/build @@ -8,7 +8,7 @@ from net import * # custom exec inspired by mininet def usage(): - print 'Usage: %s topofile.py toponame [outdir]' % (sys.argv[0]) + print('Usage: %s topofile.py toponame [outdir]' % (sys.argv[0])) sys.exit(-1) if len(sys.argv) < 3 or len(sys.argv) > 4: @@ -23,8 +23,8 @@ topos = {} sys.path.append('.') customs = {} -execfile(sys.argv[1], customs, customs) -for name, val in customs.iteritems(): +exec(compile(open(sys.argv[1], "rb").read(), sys.argv[1], 'exec'), customs, customs) +for name, val in customs.items(): if name == 'topos': globals()['topos'].update(val) else: diff --git a/example/.gitkeep b/example/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/example/example.ntfl b/example/example.ntfl new file mode 100644 index 0000000..e84fe9d --- /dev/null +++ b/example/example.ntfl @@ -0,0 +1,3 @@ +A B 1 0.2 100000 +A C 1 0.2 100000 +B C 1 0.2 100000 diff --git a/net.py b/net.py index 0a5b905..6e30962 100644 --- a/net.py +++ b/net.py @@ -40,22 +40,22 @@ def assign(self): # print e.port2 # print 'For port1 %d and port2 %d' % (e.port1, e.port2) - e.node1.intfs_addr[e.port1] = socket.inet_ntop(socket.AF_INET6, str(a1))+'/'+str(self.linknet.submask) - e.node2.intfs_addr[e.port2] = socket.inet_ntop(socket.AF_INET6, str(a2))+'/'+str(self.linknet.submask) + e.node1.intfs_addr[e.port1] = socket.inet_ntop(socket.AF_INET6, a1)+'/'+str(self.linknet.submask) + e.node2.intfs_addr[e.port2] = socket.inet_ntop(socket.AF_INET6, a2)+'/'+str(self.linknet.submask) for n in self.topo.nodes: enet = self.loopnet.next_net() enet[-1] = 1 - n.addr = socket.inet_ntop(socket.AF_INET6, str(enet))+'/'+str(self.loopnet.submask) + n.addr = socket.inet_ntop(socket.AF_INET6, enet)+'/'+str(self.loopnet.submask) def start(self, netname=None): - print '# Building topology...' + print('# Building topology...') self.topo.build() - print '# Assigning prefixes...' + print('# Assigning prefixes...') self.assign() - print '# Running dijkstra... (%d nodes)' % len(self.topo.nodes) + print('# Running dijkstra... (%d nodes)' % len(self.topo.nodes)) self.topo.compute() if netname is not None: @@ -105,7 +105,7 @@ def dump_commands(self, wr=(lambda x: self.call(x)), noroute=False): if not noroute: for n in self.topo.nodes: - for dst in n.routes.keys(): + for dst in list(n.routes.keys()): rts = n.routes[dst] laddr = n.addr.split('/')[0] if len(rts) == 1: @@ -120,7 +120,7 @@ def dump_commands(self, wr=(lambda x: self.call(x)), noroute=False): for c in host_cmd: wr('%s' % c) - for n in node_cmd.keys(): + for n in list(node_cmd.keys()): wr('ip netns exec %s bash -c \'%s\'' % (n.name, "; ".join(node_cmd[n]))) def igp_prepare_link_down(self, name1, name2): diff --git a/node.py b/node.py index 84f0f7e..02f21a5 100644 --- a/node.py +++ b/node.py @@ -19,7 +19,7 @@ def __init__(self, name): self.routes = {} def add_route(self, r): - if r.dst not in self.routes.keys(): + if r.dst not in list(self.routes.keys()): self.routes[r.dst] = [r] else: self.routes[r.dst].append(r) @@ -255,7 +255,7 @@ def get_nh_from_paths(self, paths): def compute_node(self, n): n.routes = {} dist, path = self.dijkstra(n) - for t in dist.keys(): + for t in list(dist.keys()): if len(path[t]) == 0: continue nh = self.get_nh_from_paths(path[t]) @@ -268,6 +268,6 @@ def compute_node(self, n): def compute(self): cnt = 0 for n in self.nodes: - print '# Running dijkstra for node %s (%d/%d)' % (n.name, cnt+1, len(self.nodes)) + print('# Running dijkstra for node %s (%d/%d)' % (n.name, cnt+1, len(self.nodes))) self.compute_node(n) cnt += 1