from sfa.util.rspec import Rspec
from sfa.server.registry import Registries
from sfa.plc.nodes import *
-from sfa.rspecs.aggregates.vini_utils import *
+from sfa.rspecs.aggregates.vini.utils import *
+from sfa.rspecs.aggregates.vini.rspec import *
import sys
-SFA_VINI_DEFAULT_RSPEC = '/etc/sfa/vini.rspec'
SFA_VINI_WHITELIST = '/etc/sfa/vini.whitelist'
"""
return 1
def get_rspec(api, hrn):
- # Get default rspec
- default = Rspec()
- default.parseFile(SFA_VINI_DEFAULT_RSPEC)
+ rspec = ViniRspec()
+ (sites, nodes, tags) = get_topology(api)
+
+ rspec.updateCapacity(sites, nodes)
if (hrn):
slicename = hrn_to_pl_slicename(hrn)
- defaultrspec = default.toDict()
- nodedict = get_nodedict(defaultrspec)
-
- # call the default sfa.plc.nodes.get_rspec() method
- nodes = Nodes(api)
- rspec = nodes.get_rspec(hrn)
-
- # Grab all the PLC info we'll need at once
slice = get_slice(api, slicename)
if slice:
- nodes = get_nodes(api)
- tags = get_slice_tags(api)
-
- # Add the node tags from the Capacity statement to Node objects
- for (k, v) in nodedict.iteritems():
- for id in nodes:
- if v == nodes[id].hostname:
- nodes[id].tag = k
-
- endpoints = []
- for node in slice.get_nodes(nodes):
- linktag = slice.get_tag('topo_rspec', tags, node)
- if linktag:
- l = eval(linktag.value)
- for (id, realip, bw, lvip, rvip, vnet) in l:
- endpoints.append((node.id, id, bw))
-
- if endpoints:
- linkspecs = []
- for (l, r, bw) in endpoints:
- if (r, l, bw) in endpoints:
- if l < r:
- edict = {}
- edict['endpoint'] = [nodes[l].tag, nodes[r].tag]
- edict['bw'] = [bw]
- linkspecs.append(edict)
-
- d = default.toDict()
- d['Rspec']['Request'][0]['NetSpec'][0]['LinkSpec'] = linkspecs
- d['Rspec']['Request'][0]['NetSpec'][0]['name'] = hrn
- new = Rspec()
- new.parseDict(d)
- rspec = new.toxml()
- else:
- # Return canned response for now...
- rspec = default.toxml()
+ slice.hrn = hrn
+ rspec.updateRequest(slice, nodes, tags)
+ else:
+ # call the default sfa.plc.nodes.get_rspec() method
+ return Nodes(api).get_rspec(hrn)
- return rspec
+ return rspec.toxml()
+
+
+"""
+Check the requested topology against the available topology and capacity
+"""
+def check_request(hrn, rspec, nodes, sites, sitelinks, maxbw):
+ linkspecs = rspec['Rspec']['Request'][0]['NetSpec'][0]['LinkSpec']
+ if linkspecs:
+ for l in linkspecs:
+ n1 = Node.lookup(l['endpoint'][0])
+ n2 = Node.lookup(l['endpoint'][1])
+ bw = l['bw'][0]
+ reqbps = get_tc_rate(bw)
+ maxbps = get_tc_rate(maxbw)
+ if reqbps <= 0:
+ raise GeniInvalidArgument(bw, "BW")
+ if reqbps > maxbps:
+ raise PermissionError(" %s requested %s but max BW is %s" %
+ (hrn, bw, maxbw))
+
+ if adjacent_nodes(n1, n2, sites, sitelinks):
+ availbps = get_avail_bps(n1, n2, sites, sitelinks)
+ if availbps < reqbps:
+ raise PermissionError("%s: capacity exceeded" % hrn)
+ else:
+ raise PermissionError("%s: nodes %s and %s not adjacent"
+ % (hrn, n1.tag, n2.tag))
+"""
+Hook called via 'sfi.py create'
+"""
def create_slice(api, hrn, xml):
r = Rspec(xml)
rspec = r.toDict()
whitelist[slice] = maxbw
if hrn in whitelist:
- maxbps = get_tc_rate(whitelist[hrn])
+ maxbw = whitelist[hrn]
else:
raise PermissionError("%s not in VINI whitelist" % hrn)
- ### Check to make sure that the slice isn't requesting more
- ### than its maximum bandwidth.
- linkspecs = rspec['Rspec']['Request'][0]['NetSpec'][0]['LinkSpec']
- if linkspecs:
- for l in linkspecs:
- bw = l['bw'][0]
- bps = get_tc_rate(bw)
- if bps <= 0:
- raise GeniInvalidArgument(bw, "BW")
- if bps > maxbps:
- raise PermissionError(" %s requested %s but max BW is %s" % (hrn, bw, whitelist[hrn]))
+ # Construct picture of global topology
+ (sites, nodes, tags) = get_topology(api)
# Check request against current allocations
- # Request OK
+ #check_request(hrn, rspec, nodes, sites, sitelinks, maxbw)
nodes = rspec_to_nodeset(rspec)
create_slice_vini_aggregate(api, hrn, nodes)
linkspecs = rspec['Rspec']['Request'][0]['NetSpec'][0]['LinkSpec']
if linkspecs:
slicename = hrn_to_pl_slicename(hrn)
-
- # Grab all the PLC info we'll need at once
slice = get_slice(api, slicename)
if slice:
- nodes = get_nodes(api)
- tags = get_slice_tags(api)
-
slice.update_tag('vini_topo', 'manual', tags)
slice.assign_egre_key(tags)
slice.turn_on_netns(tags)
--- /dev/null
+from sfa.util.rspec import Rspec
+from sfa.rspecs.aggregates.vini.utils import *
+import sys
+
+SFA_VINI_DEFAULT_RSPEC = '/etc/sfa/vini.rspec'
+
+class ViniRspec(Rspec):
+ def __init__(self):
+ Rspec.__init__(self)
+ self.parseFile(SFA_VINI_DEFAULT_RSPEC)
+
+ def updateCapacity(self, sites, nodes):
+ d = self.toDict()
+ sitespecs = []
+ sitelinkspecs = []
+ for s in sites:
+ site = sites[s]
+ if not site.public:
+ continue
+ sdict = {}
+ nodespecs = []
+ for node in site.get_sitenodes(nodes):
+ if not node.tag:
+ continue
+ ndict = {}
+ ndict['hostname'] = [node.hostname]
+ ndict['name'] = node.tag
+ ndict['bw'] = ['999Mbit']
+ nodespecs.append(ndict)
+ sdict['NodeSpec'] = nodespecs
+ sdict['name'] = site.name
+ sitespecs.append(sdict)
+
+ for sl in site.sitelinks:
+ if sl.site1 == site:
+ sldict = {}
+ sldict['endpoint'] = [sl.site1.name, sl.site2.name]
+ sldict['bw'] = [str(sl.availMbps) + "Mbit"]
+ sitelinkspecs.append(sldict)
+
+ d['Rspec']['Capacity'][0]['NetSpec'][0]['SiteSpec'] = sitespecs
+ d['Rspec']['Capacity'][0]['NetSpec'][0]['SiteLinkSpec'] = sitelinkspecs
+ self.parseDict(d)
+
+
+ def updateRequest(self, slice, nodes, tags):
+ endpoints = []
+ for node in slice.get_nodes(nodes):
+ linktag = slice.get_tag('topo_rspec', tags, node)
+ if linktag:
+ l = eval(linktag.value)
+ for (id, realip, bw, lvip, rvip, vnet) in l:
+ endpoints.append((node.id, id, bw))
+
+ if endpoints:
+ linkspecs = []
+ for (l, r, bw) in endpoints:
+ if (r, l, bw) in endpoints:
+ if l < r:
+ edict = {}
+ edict['endpoint'] = [nodes[l].tag, nodes[r].tag]
+ edict['bw'] = [bw]
+ linkspecs.append(edict)
+
+ d = self.toDict()
+ d['Rspec']['Request'][0]['NetSpec'][0]['LinkSpec'] = linkspecs
+ d['Rspec']['Request'][0]['NetSpec'][0]['name'] = slice.hrn
+ self.parseDict(d)
\ No newline at end of file
--- /dev/null
+#!/usr/bin/python
+
+# $Id: topology.py 14181 2009-07-01 19:46:07Z acb $
+# $URL: https://svn.planet-lab.org/svn/NodeManager-topo/trunk/topology.py $
+
+#
+# Links in the physical topology, gleaned from looking at the Internet2
+# and NLR topology maps. Link (a, b) connects sites with IDs a and b.
+#
+PhysicalLinks = [(2, 12), # I2 Princeton - New York
+ (4, 5), # NLR Chicago - Houston
+ (4, 6), # NLR Chicago - Atlanta
+ (4, 7), # NLR Chicago - Seattle
+ (4, 9), # NLR Chicago - New York
+ (4, 10), # NLR Chicago - Wash DC
+ (5, 6), # NLR Houston - Atlanta
+ (5, 8), # NLR Houston - Los Angeles
+ (6, 10), # NLR Atlanta - Wash DC
+ (6, 14), # NLR Atlanta - Ga Tech
+ (7, 8), # NLR Seattle - Los Angeles
+ (9, 10), # NLR New York - Wash DC
+ (11, 13), # I2 Chicago - Wash DC
+ (11, 15), # I2 Chicago - Atlanta
+ (11, 16), # I2 Chicago - CESNET
+ (11, 17), # I2 Chicago - Kansas City
+ (12, 13), # I2 New York - Wash DC
+ (13, 15), # I2 Wash DC - Atlanta
+ (14, 15), # Ga Tech - I2 Atlanta
+ (15, 19), # I2 Atlanta - Houston
+ (17, 19), # I2 Kansas City - Houston
+ (17, 22), # I2 Kansas City - Salt Lake City
+ (17, 24), # I2 Kansas City - UMKC
+ (19, 20), # I2 Houston - Los Angeles
+ (20, 21), # I2 Los Angeles - Seattle
+ (20, 22), # I2 Los Angeles - Salt Lake City
+ (21, 22)] # I2 Seattle - Salt Lake City
+
+
import re
import socket
+from sfa.rspecs.aggregates.vini.topology import *
# Taken from bwlimit.py
#
def get_site(self, sites):
return sites[self.site_id]
-
- def adjacent_nodes(self, sites, nodes, node_ids):
- mysite = self.get_site(sites)
- adj_ids = mysite.adj_node_ids.intersection(node_ids)
- adj_nodes = []
- for id in adj_ids:
- adj_nodes.append(nodes[id])
- return adj_nodes
def init_links(self):
self.links = []
net = self.get_virt_net(remote)
link = remote.id, remote.ipaddr, bw, my_ip, remote_ip, net
self.links.append(link)
+
+ def add_tag(self, sites):
+ s = self.get_site(sites)
+ words = self.hostname.split(".")
+ index = words[0].replace("node", "")
+ if index.isdigit():
+ self.tag = s.tag + index
+ else:
+ self.tag = None
+
+class SiteLink:
+ def __init__(self, site1, site2, mbps = 1000):
+ self.site1 = site1
+ self.site2 = site2
+ self.totalMbps = mbps
+ self.availMbps = mbps
+
+ site1.add_sitelink(self)
+ site2.add_sitelink(self)
+
class Site:
def __init__(self, site):
self.id = site['site_id']
self.node_ids = site['node_ids']
- self.adj_site_ids = set()
- self.adj_node_ids = set()
+ self.name = site['abbreviated_name']
+ self.tag = site['login_base']
+ self.public = site['is_public']
+ self.sitelinks = []
def get_sitenodes(self, nodes):
n = []
n.append(nodes[i])
return n
- def add_adjacency(self, site):
- self.adj_site_ids.add(site.id)
- for n in site.node_ids:
- self.adj_node_ids.add(n)
-
+ def add_sitelink(self, link):
+ self.sitelinks.append(link)
+
class Slice:
def __init__(self, slice):
"""
Create a dictionary of site objects keyed by site ID
"""
-def get_sites():
+def get_sites(api):
tmp = []
- for site in GetSites():
+ for site in api.plshell.GetSites(api.plauth):
t = site['site_id'], Site(site)
tmp.append(t)
return dict(tmp)
return "%s" % key
+"""
+Return the network topology.
+The topology consists of:
+* a dictionary mapping site IDs to Site objects
+* a dictionary mapping node IDs to Node objects
+* the Site objects are connected via SiteLink objects representing
+ the physical topology and available bandwidth
+"""
+def get_topology(api):
+ sites = get_sites(api)
+ nodes = get_nodes(api)
+ tags = get_slice_tags(api)
+
+ for (s1, s2) in PhysicalLinks:
+ SiteLink(sites[s1], sites[s2])
+ for id in nodes:
+ nodes[id].add_tag(sites)
+
+ return (sites, nodes, tags)