1 | #!/usr/bin/env python |
---|
2 | |
---|
3 | import sys |
---|
4 | from deter import topdl |
---|
5 | |
---|
6 | def annotate_degree(top): |
---|
7 | ''' |
---|
8 | Add an attribute (node_degree) to each Computer in the topology (top) that |
---|
9 | lists its degree |
---|
10 | ''' |
---|
11 | for e in top.elements: |
---|
12 | # Skip elements that are not computers |
---|
13 | if not isinstance(e, topdl.Computer): continue |
---|
14 | # degree is the number of interfaces |
---|
15 | deg = len(e.interface) |
---|
16 | # Save a string-valued attribute |
---|
17 | e.set_attribute('node_degree', '%s' % deg) |
---|
18 | return top |
---|
19 | |
---|
20 | def add_operating_system(top): |
---|
21 | ''' |
---|
22 | Add an OperatingSystem class to each computer in the topology (top). If |
---|
23 | the node is a leaf (degree 1) make it Ubuntu Linux, otherwise make it |
---|
24 | FreeBSD. annotate_degree() must have been called on the topology as this |
---|
25 | routine uses the node_degree attribute to make decisions. |
---|
26 | ''' |
---|
27 | |
---|
28 | for e in top.elements: |
---|
29 | # Skip non-Computers |
---|
30 | if not isinstance(e, topdl.Computer): continue |
---|
31 | a = e.get_attribute('node_degree') |
---|
32 | # if there is a node_degree attribute, assign an OS |
---|
33 | if a: |
---|
34 | # Covnert the string attribute into an integer |
---|
35 | try: |
---|
36 | deg = int(a) |
---|
37 | except ValueError, e: |
---|
38 | sys.exit('%s has a non-integer degree %s!?' % (e.name, a)) |
---|
39 | # Assign the os - includes a distribution for Linux |
---|
40 | if deg == 1: |
---|
41 | e.os.append(topdl.OperatingSystem(name='Linux', |
---|
42 | distribution='Ubuntu')) |
---|
43 | else: |
---|
44 | e.os.append(topdl.OperatingSystem(name='FreeBSD')) |
---|
45 | return top |
---|
46 | |
---|
47 | def add_links(top): |
---|
48 | ''' |
---|
49 | For each router - Computer with FreeBSD assigned as an OS - select one of |
---|
50 | its Linux children and make a connection to one of the other router's |
---|
51 | children. |
---|
52 | ''' |
---|
53 | |
---|
54 | def has_os(e, os_name): |
---|
55 | ''' |
---|
56 | Return true if any of e's os classes has the given os_name |
---|
57 | ''' |
---|
58 | if e.os is None: return False |
---|
59 | else: return any([ o.name == os_name for o in e.os ]) |
---|
60 | |
---|
61 | # At the end of this loop, leaves contains a list of leaves for each router |
---|
62 | # in the topology. |
---|
63 | leaves = [ ] |
---|
64 | for e in top.elements: |
---|
65 | if not isinstance(e, topdl.Computer): continue |
---|
66 | if not has_os(e, 'FreeBSD'): continue |
---|
67 | # This is a Computer running FreeBsd |
---|
68 | my_leaves = [] |
---|
69 | # walk the interfaces |
---|
70 | for inf in e.interface: |
---|
71 | # Walk the interface's substrates |
---|
72 | for s in inf.subs: |
---|
73 | # Walk the substrate's interfaces looking for the other |
---|
74 | # elements - not this router. |
---|
75 | for sinf in s.interfaces: |
---|
76 | ee = sinf.element |
---|
77 | # all the Linux computers get attached to the leaves dict |
---|
78 | if isinstance(ee, topdl.Computer) and ee != e: |
---|
79 | if has_os(ee, 'Linux'): |
---|
80 | my_leaves.append(ee) |
---|
81 | # One router has no leaves. Ignore it. |
---|
82 | if len(my_leaves) > 0: |
---|
83 | leaves.append(my_leaves) |
---|
84 | |
---|
85 | |
---|
86 | # This loop takes the first computer in one entry in leaves and connects it |
---|
87 | # to the last computer in the next entry in leaves (wrapping around at the |
---|
88 | # top). |
---|
89 | for i in range(0, len(leaves)): |
---|
90 | link_name = 'new-link%d' % i |
---|
91 | f = leaves[i][0] |
---|
92 | t = leaves[(i+1) % len(leaves)][-1] |
---|
93 | f.interface.append(topdl.Interface(substrate=[link_name])) |
---|
94 | t.interface.append(topdl.Interface(substrate=[link_name])) |
---|
95 | top.substrates.append(topdl.Substrate(name=link_name)) |
---|
96 | |
---|
97 | # Now incorporate the new links |
---|
98 | top.incorporate_elements() |
---|
99 | return top |
---|
100 | |
---|
101 | def output_ns(top, filename): |
---|
102 | ''' |
---|
103 | Output ns2 with the OperatingSystem specifications converted to local OSIDs |
---|
104 | when known. |
---|
105 | ''' |
---|
106 | def os_filter(e): |
---|
107 | ''' |
---|
108 | Convert OS id to local equivalents: |
---|
109 | FreeBSD -> FBSD8-STD |
---|
110 | Lunix/Ubuntu -> Ubuntu-64-STD |
---|
111 | ''' |
---|
112 | # Only work on Computers |
---|
113 | if not isinstance(e, topdl.Computer): return '' |
---|
114 | # Only handle exactly 1 specified OS |
---|
115 | if len(e.os) != 1 : return '' |
---|
116 | # String translation |
---|
117 | if e.os[0].name == 'FreeBSD': |
---|
118 | return 'tb-set-node-os ${%s} FBSD8-STD\n' % \ |
---|
119 | topdl.to_tcl_name(e.name) |
---|
120 | elif e.os[0].name == 'Linux' and e.os[0].distribution == 'Ubuntu': |
---|
121 | return 'tb-set-node-os ${%s} Ubuntu1204-64-STD\n' % \ |
---|
122 | topdl.to_tcl_name(e.name) |
---|
123 | else: |
---|
124 | return '' |
---|
125 | |
---|
126 | # Main line. Open the file and write the otcl to it. |
---|
127 | try: |
---|
128 | f = open(filename, 'w') |
---|
129 | # Include the os_filter |
---|
130 | f.write(topdl.topology_to_ns2(top, |
---|
131 | filters=[os_filter], routing='Static')) |
---|
132 | f.close() |
---|
133 | except EnvironmentError, e: |
---|
134 | sys.exit('Cannot write %s: %s' % (e.filename, e.strerror)) |
---|
135 | |
---|
136 | |
---|
137 | # Parse get the file to parse and output file |
---|
138 | if len(sys.argv) > 2: |
---|
139 | infile, outfile = (sys.argv[1], sys.argv[2]) |
---|
140 | else: |
---|
141 | sys.exit('Usage: %s infile outfile' % sys.argv[0]) |
---|
142 | |
---|
143 | top = topdl.topology_from_xml(filename=infile, top='experiment') |
---|
144 | top = annotate_degree(top) |
---|
145 | top = add_operating_system(top) |
---|
146 | top = add_links(top) |
---|
147 | output_ns(top, outfile) |
---|