3 from sfa.rspecs.aggregates.vini.topology import *
5 # Taken from bwlimit.py
7 # See tc_util.c and http://physics.nist.gov/cuu/Units/binary.html. Be
8 # warned that older versions of tc interpret "kbps", "mbps", "mbit",
9 # and "kbit" to mean (in this system) "kibps", "mibps", "mibit", and
10 # "kibit" and that if an older version is installed, all rates will
11 # be off by a small fraction.
19 "gibit": 1024*1024*1024,
21 "tibit": 1024*1024*1024*1024,
22 "tbit": 1000000000000,
28 "gibps": 8*1024*1024*1024,
30 "tibps": 8*1024*1024*1024*1024,
37 Parses an integer or a tc rate string (e.g., 1.5mbit) into bits/second
42 m = re.match(r"([0-9.]+)(\D*)", s)
45 suffix = m.group(2).lower()
46 if suffixes.has_key(suffix):
47 return int(float(m.group(1)) * suffixes[suffix])
53 def __init__(self, node):
54 self.id = node['node_id']
55 self.hostname = node['hostname']
56 self.shortname = self.hostname.replace('.vini-veritas.net', '')
57 self.site_id = node['site_id']
58 self.ipaddr = socket.gethostbyname(self.hostname)
61 def get_link_id(self, remote):
62 if self.id < remote.id:
63 link = (self.id<<7) + remote.id
65 link = (remote.id<<7) + self.id
68 def get_iface_id(self, remote):
69 if self.id < remote.id:
75 def get_virt_ip(self, remote):
76 link = self.get_link_id(remote)
77 iface = self.get_iface_id(remote)
79 second = ((link & 0x3f)<<2) + iface
80 return "192.168.%d.%d" % (first, second)
82 def get_virt_net(self, remote):
83 link = self.get_link_id(remote)
85 second = (link & 0x3f)<<2
86 return "192.168.%d.%d/30" % (first, second)
88 def get_site(self, sites):
89 return sites[self.site_id]
94 def add_link(self, remote, bw):
95 my_ip = self.get_virt_ip(remote)
96 remote_ip = remote.get_virt_ip(self)
97 net = self.get_virt_net(remote)
98 link = remote.id, remote.ipaddr, bw, my_ip, remote_ip, net
99 self.links.append(link)
101 def add_tag(self, sites):
102 s = self.get_site(sites)
103 words = self.hostname.split(".")
104 index = words[0].replace("node", "")
106 self.tag = s.tag + index
112 def __init__(self, site1, site2, mbps = 1000):
115 self.totalMbps = mbps
116 self.availMbps = mbps
118 site1.add_sitelink(self)
119 site2.add_sitelink(self)
123 def __init__(self, site):
124 self.id = site['site_id']
125 self.node_ids = site['node_ids']
126 self.name = site['abbreviated_name']
127 self.tag = site['login_base']
128 self.public = site['is_public']
131 def get_sitenodes(self, nodes):
133 for i in self.node_ids:
137 def add_sitelink(self, link):
138 self.sitelinks.append(link)
142 def __init__(self, slice):
143 self.id = slice['slice_id']
144 self.name = slice['name']
145 self.node_ids = set(slice['node_ids'])
146 self.slice_tag_ids = slice['slice_tag_ids']
148 def get_tag(self, tagname, slicetags, node = None):
149 for i in self.slice_tag_ids:
151 if tag.tagname == tagname:
152 if (not node) or (node.id == tag.node_id):
157 def get_nodes(self, nodes):
159 for id in self.node_ids:
164 # Add a new slice tag
165 def add_tag(self, tagname, value, slicetags, node = None):
166 record = {'slice_tag_id':None, 'slice_id':self.id, 'tagname':tagname, 'value':value}
168 record['node_id'] = node.id
170 record['node_id'] = None
171 tag = Slicetag(record)
172 slicetags[tag.id] = tag
173 self.slice_tag_ids.append(tag.id)
178 # Update a slice tag if it exists, else add it
179 def update_tag(self, tagname, value, slicetags, node = None):
180 tag = self.get_tag(tagname, slicetags, node)
181 if tag and tag.value == value:
187 tag = self.add_tag(tagname, value, slicetags, node)
190 def assign_egre_key(self, slicetags):
191 if not self.get_tag('egre_key', slicetags):
193 key = free_egre_key(slicetags)
194 self.update_tag('egre_key', key, slicetags)
196 # Should handle this case...
200 def turn_on_netns(self, slicetags):
201 tag = self.get_tag('netns', slicetags)
202 if (not tag) or (tag.value != '1'):
203 self.update_tag('netns', '1', slicetags)
206 def turn_off_netns(self, slicetags):
207 tag = self.get_tag('netns', slicetags)
208 if tag and (tag.value != '0'):
212 def add_cap_net_admin(self, slicetags):
213 tag = self.get_tag('capabilities', slicetags)
215 caps = tag.value.split(',')
217 if cap == "CAP_NET_ADMIN":
220 newcaps = "CAP_NET_ADMIN," + tag.value
221 self.update_tag('capabilities', newcaps, slicetags)
223 self.add_tag('capabilities', 'CAP_NET_ADMIN', slicetags)
226 def remove_cap_net_admin(self, slicetags):
227 tag = self.get_tag('capabilities', slicetags)
229 caps = tag.value.split(',')
232 if cap != "CAP_NET_ADMIN":
235 value = ','.join(newcaps)
236 self.update_tag('capabilities', value, slicetags)
241 # Update the vsys/setup-link and vsys/setup-nat slice tags.
242 def add_vsys_tags(self, slicetags):
244 for i in self.slice_tag_ids:
246 if tag.tagname == 'vsys':
247 if tag.value == 'setup-link':
249 elif tag.value == 'setup-nat':
252 self.add_tag('vsys', 'setup-link', slicetags)
254 self.add_tag('vsys', 'setup-nat', slicetags)
260 def __init__(self, tag):
261 self.id = tag['slice_tag_id']
263 # Make one up for the time being...
264 self.id = Slicetag.newid
266 self.slice_id = tag['slice_id']
267 self.tagname = tag['tagname']
268 self.value = tag['value']
269 self.node_id = tag['node_id']
274 # Mark a tag as deleted
279 def write(self, api):
282 api.plshell.UpdateSliceTag(api.plauth, self.id, self.value)
284 api.plshell.AddSliceTag(api.plauth, self.slice_id,
285 self.tagname, self.value, self.node_id)
286 elif self.deleted and int(self.id) > 0:
287 api.plshell.DeleteSliceTag(api.plauth, self.id)
291 Create a dictionary of site objects keyed by site ID
295 for site in api.plshell.GetSites(api.plauth):
296 t = site['site_id'], Site(site)
302 Create a dictionary of node objects keyed by node ID
306 for node in api.plshell.GetNodes(api.plauth):
307 t = node['node_id'], Node(node)
312 Create a dictionary of slice objects keyed by slice ID
314 def get_slice(api, slicename):
315 slice = api.plshell.GetSlices(api.plauth, [slicename])
317 return Slice(slice[0])
322 Create a dictionary of slicetag objects keyed by slice tag ID
324 def get_slice_tags(api):
326 for tag in api.plshell.GetSliceTags(api.plauth):
327 t = tag['slice_tag_id'], Slicetag(tag)
334 def free_egre_key(slicetags):
338 if tag.tagname == 'egre_key':
339 used.add(int(tag.value))
341 for i in range(1, 256):
346 raise KeyError("No more EGRE keys available")
351 Return the network topology.
352 The topology consists of:
353 * a dictionary mapping site IDs to Site objects
354 * a dictionary mapping node IDs to Node objects
355 * the Site objects are connected via SiteLink objects representing
356 the physical topology and available bandwidth
358 def get_topology(api):
359 sites = get_sites(api)
360 nodes = get_nodes(api)
361 tags = get_slice_tags(api)
363 for (s1, s2) in PhysicalLinks:
364 SiteLink(sites[s1], sites[s2])
367 nodes[id].add_tag(sites)
369 return (sites, nodes, tags)