Skip to content

Commit 7b6bd0f

Browse files
authored
Merge pull request srl-labs#330 from vrnetlab/topomachine-keep-order
Add --keep-order to topomachine
2 parents 90d2da0 + 250b114 commit 7b6bd0f

File tree

2 files changed

+50
-19
lines changed

2 files changed

+50
-19
lines changed

topology-machine/README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,15 @@ topomachine does not currently use any information from the low level topology
3434
will very likely result in changes to the majority of links in the topology as
3535
they will be re-assigned to new interfaces.
3636

37+
The default behavior is to sort the routers and links and assign interfaces
38+
numbers to links in this sorted order. There is however an option called
39+
`--keep-order` that will take into account the order in which the *p2p* links
40+
and routers in *fullmeshes* are defined in the configuration file. This makes
41+
the interface assignment more stable when changing the topology. It also makes
42+
the assignment more natural, as we tend to list the important routers (like PE
43+
routers) in the topology first, followed by CPEs and the like. The interfaces on
44+
the devices listed first will be assigned lower numbers.
45+
3746
topology machine is able to run the machines for you, i.e. execute docker run
3847
for the routers defined in the configuration file and start vr-xcon with the
3948
relevant arguments to complete the topology:

topology-machine/topomachine

Lines changed: 41 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,15 @@ import jinja2
1010
class VrTopo:
1111
""" vrnetlab topo builder
1212
"""
13-
def __init__(self, config):
14-
self.routers = {}
13+
def __init__(self, config, keep_order):
14+
self.keep_order = keep_order
1515
self.links = []
1616
self.fullmeshes = {}
1717
self.hubs = {}
1818
if 'routers' in config:
1919
self.routers = config['routers']
20+
else:
21+
self.routers = {}
2022

2123
# sanity checking - use a YANG model and pyang to validate input?
2224
for r, val in self.routers.items():
@@ -25,21 +27,41 @@ class VrTopo:
2527
if val['type'] not in ('dummy', 'xcon', 'bgp', 'xrv', 'xrv9k', 'vmx', 'sros', 'csr', 'nxos', 'nxos9kv', 'vqfx', 'vrp', 'veos', 'openwrt'):
2628
raise ValueError("Unknown type %s for router %s" % (val['type'], r))
2729

28-
# expand p2p links
30+
# preserve order of entries if keep_order is set
31+
def maybe_sorted(d):
32+
if keep_order:
33+
return d
34+
else:
35+
return sorted(d)
36+
2937
links = []
30-
if 'p2p' in config:
31-
for router in sorted(config['p2p']):
32-
neighbors = config['p2p'][router]
33-
for neighbor in neighbors:
34-
links.append({ 'left': { 'router': router }, 'right': {
35-
'router': neighbor }})
38+
39+
# expand p2p links
40+
def p2p():
41+
nonlocal links
42+
if 'p2p' in config:
43+
for router in maybe_sorted(config['p2p']):
44+
neighbors = config['p2p'][router]
45+
for neighbor in neighbors:
46+
links.append({ 'left': { 'router': router }, 'right': {
47+
'router': neighbor }})
3648

3749
# expand fullmesh into links
38-
if 'fullmeshes' in config:
39-
for name in sorted(config['fullmeshes']):
40-
val = config['fullmeshes'][name]
41-
fmlinks = self.expand_fullmesh(val)
42-
links.extend(fmlinks)
50+
def fullmesh():
51+
nonlocal links
52+
if 'fullmeshes' in config:
53+
for name in maybe_sorted(config['fullmeshes']):
54+
val = config['fullmeshes'][name]
55+
fmlinks = self.expand_fullmesh(val)
56+
links.extend(fmlinks)
57+
58+
# expand fullmeshes before p2p if keep_order is set and fullmeshes is defined before p2p
59+
if keep_order and 'fullmeshes' in config and 'p2p' in config and tuple(config).index('fullmeshes') < tuple(config).index('p2p'):
60+
fullmesh()
61+
p2p()
62+
else:
63+
p2p()
64+
fullmesh()
4365

4466
self.links = self.assign_interfaces(links)
4567

@@ -73,9 +95,8 @@ class VrTopo:
7395
for num_id in val['interfaces']:
7496
val['interfaces'][num_id] = self.intf_num_to_name(router, num_id)
7597

76-
77-
78-
def expand_fullmesh(self, routers):
98+
@staticmethod
99+
def expand_fullmesh(routers):
79100
""" Flatten a full-mesh into a list of links
80101
81102
Links are considered bi-directional, so you will only see a link A->B
@@ -179,7 +200,7 @@ class VrTopo:
179200
}
180201

181202
if output_format == 'json':
182-
return json.dumps(output, sort_keys=True, indent=4)
203+
return json.dumps(output, sort_keys=(not self.keep_order), indent=4)
183204
else:
184205
raise ValueError("Invalid output format")
185206

@@ -299,6 +320,7 @@ if __name__ == '__main__':
299320
import argparse
300321
parser = argparse.ArgumentParser()
301322
parser.add_argument("--build", help="Build topology from config")
323+
parser.add_argument("--keep-order", action="store_true", help="Keep topology order (routers, links, fullmeshes). Applies to --build only")
302324
parser.add_argument("--run", help="Run topology")
303325
parser.add_argument("--dry-run", action="store_true", default=False, help="Only print what would be performed during --run")
304326
parser.add_argument("--prefix", default='', help="docker container name prefix")
@@ -321,7 +343,7 @@ if __name__ == '__main__':
321343
config = json.loads(input_file.read(), object_pairs_hook=OrderedDict)
322344
input_file.close()
323345
try:
324-
vt = VrTopo(config)
346+
vt = VrTopo(config, args.keep_order)
325347
except Exception as exc:
326348
print("ERROR:", exc)
327349
sys.exit(1)

0 commit comments

Comments
 (0)