fb-tutorial.py
ipaccess-openepc-genilib.py
—
Python Source,
11 KB (11975 bytes)
File contents
#!/usr/bin/env python import geni.portal as portal import geni.rspec.pg as RSpec import geni.rspec.igext as IG from lxml import etree as ET # # Globals # class GLOBALS(object): NODETYPE = RSpec.NodeType.RAW VALID_ROLES = ["epc-client","epc-enablers","pgw","sgw-mme-sgsn","enodeb", "angw", "epdg", "nodeb"] OEPC_STARTSCRIPT = "/usr/bin/sudo /opt/OpenEPC/bin/start_epc.sh" SYSTEM_URN_PREFIX = "urn:publicid:IDN+emulab.net+image+emulab-ops:" OEPCIMG_URN_PREFIX = "urn:publicid:IDN+emulab.net+image+PhantomNet:" BINOEPC_OS = "UBUNTU12-64-OEPCR5" ENODEB_HWTYPE = "enodeb" UE_HWTYPE = "nexus5" ENODEB_OS = "GENERICDEV-NOVLANS" UE_OS = "ANDROID444-STD" # # Static set of EPC roles # class EPCROLES(object): ENABLERS = "epc-enablers" PGW = "pgw" SGW_MME_SGSN = "sgw-mme-sgsn" CLIENT = "epc-client" ENODEB = "enodeb" # # Static set of EPC lans (recognized by PhantomNet setup code) # class EPCLANS(object): MGMT = "mgmt" NET_A = "net-a" NET_B = "net-b" NET_C = "net-c" NET_D = "net-d" AN_LTE = "an-lte" # # Create our in-memory model of the RSpec -- the resources we're going # to request in our experiment, and their configuration. # rspec = RSpec.Request() # # This geni-lib script is designed to run in the PhantomNet Portal. # pc = portal.Context() # # Describe profile. Will be rendered in Markdown on Portal. # tourDescription = \ """ ###*<center>Use this profile to instantiate real OTS hardware paired with OpenEPC.</center>* --- Attributes/features: * One real OTS UE handset (Google Nexus5) * One real OTS eNodeB (ip.access e40) * Emulated RF link between OTS devices (set to 0dB attenuation) * Essential EPC compenents (OpenEPC): HSS, MME, SGW, PGW * Configurable number of emulated edge components: UEs and eNodeBs. """ tourInstructions = \ """ This profile makes use of user-supplied parameters. You can use these parameters to tune the number of clients (emulated UEs), request additional emulated eNodeBs, and to choose the hardware used. An advanced parameter allows you to set the default LAN bandwidth. This is a parameterized profile implemented via a [geni-lib](http://geni-lib.readthedocs.org "geni-lib documentation") script. You may make a copy of the script to use in your own profile where you can modify the script to suit your needs. """ # # Setup the Tour info with the above description and instructions. # tour = IG.Tour() tour.Description(IG.Tour.MARKDOWN,tourDescription) tour.Instructions(IG.Tour.MARKDOWN,tourInstructions) rspec.addTour(tour) # # Define some parameters for OpenEPC experiments. # pc.defineParameter("NUMCLI", "Number of clients (UEs)", portal.ParameterType.INTEGER, 1, longDescription="Specify the number of emulated client (User Equipment) resources to allocate. This number must be between 1 and 32 currently.") pc.defineParameter("NUMENB", "Number of eNodeB nodes.", portal.ParameterType.INTEGER, 1, [1,2,3], longDescription="Number of emulated eNodeB (LTE base station) nodes to allocate. May be from 1 to 3 (inclusive).") pc.defineParameter("HWTYPE","Node Hardware Type", portal.ParameterType.STRING, "pc", [("pc","Any available (compatible) physical machine type"), ("pc3000","Emulab pc3000 nodes"), ("d710","Emulab d710 nodes"), ("pcvm","Any available (compatible) virtual machine type"), ("pc3000vm","Virtual machines on top of pc3000 nodes."), ("d710vm","Virtual machines on top of d710 nodes.")], longDescription="Specify which node resource type to use for OpenEPC nodes. Note that only those types that are compatible with the OpenEPC image(s) are listed.") pc.defineParameter("LINKBW","Default Link Bandwidth (Mbps)", portal.ParameterType.INTEGER, 1000, longDescription="Specify the default LAN bandwidth in Mbps for all EPC LANs. Leave at \"0\" to indicate \"best effort\". Values that do not line up with common physical interface speeds (e.g. 10, 100, or 1000) WILL cause the insertion of link shaping elements.", advanced=True) pc.defineParameter("FIXEDUE", "Bind to a specific UE", portal.ParameterType.STRING, "", longDescription="Input the name of a PhantomNet UE node to allocate (e.g., \'ue1\'). Leave blank to let the mapping algorithm choose.", advanced=True) pc.defineParameter("FIXEDENB", "Bind to a specific eNodeB", portal.ParameterType.STRING, "", longDescription="Input the name of a PhantomNet eNodeB device to allocate (e.g., \'enodeb01\'). Leave blank to let the mapping algorithm choose. If you bind both UE and eNodeB devices, mapping will fail unless there is path between them via the attenuator matrix.", advanced=True) # # Get any input parameter values that will override our defaults. # params = pc.bindParameters() # # Verify parameters and throw errors. # if params.NUMCLI > 32 or params.NUMCLI < 1: perr = portal.ParameterError("You cannot ask for fewer than one or more than 32 client nodes!", ['NUMCLI']) pc.reportError(perr) pass if params.NUMENB < 1 or params.NUMENB > 3: perr = portal.ParameterError("You cannot ask for fewer than one or more than three eNodeB nodes!", ['NUMENB']) pc.reportError(perr) pass if int(params.LINKBW) not in [0, 10, 100, 1000]: pwarn = portal.ParameterWarning("You are asking for a default link bandwidth that is NOT a standard physical link speed. Link shaping resources WILL be inserted!", ['LINKBW']) pc.reportWarning(pwarn) pass # XXX: put in check for fixed eNB and UE device names. # # Give the library a chance to return nice JSON-formatted exception(s) and/or # warnings; this might sys.exit(). # pc.verifyParameters() # # Switch up some settings if VMs were requested. # if params.HWTYPE.find("vm") >= 0: GLOBALS.NODETYPE = RSpec.NodeType.VM params.HWTYPE = params.HWTYPE.replace("vm","") rspec.setCollocateFactor(10) rspec.setPackingStrategy("pack") # # Temporary RFLink class # class RFLink(RSpec.Link): def __init__(self, name): super(RFLink, self).__init__(name) self.bandwidth = 500 def _write(self, root): lnk = super(RFLink, self)._write(root) lnk.attrib["protocol"] = "P2PLTE" return lnk # # EPC lan class # class epclan(RSpec.LAN): def __init__(self, name): super(epclan, self).__init__(name) if params.LINKBW == 0: self.best_effort = 1 self.trivial_ok = 1 else: self.bandwidth = params.LINKBW * 1000 if GLOBALS.NODETYPE == RSpec.NodeType.VM: self.vlan_tagging = 1 #self.link_multiplexing = 1 def isMember(self, node): for intf in self.interfaces: if intf.node == node: return 1 return 0 # XXX: not doing anything with latency right now! def addMember(self, node, bandwidth = 0, latency = 0): ifname = self.client_id intf = node.addInterface(ifname) if bandwidth: intf.bandwidth = bandwidth * 1000 self.addInterface(intf) # # Add node to an epc lan # LANS = {} def addtolan(lan, node, bw = 0, lat = 0): global LANS if not lan in LANS: LANS[lan] = epclan(lan) # Don't ever shape the management LAN. if lan == EPCLANS.MGMT: LANS[lan].bandwidth = -1 LANS[lan].best_effort = 1 LANS[lan].trivial_ok = 1 bw = 0 lat = 0 rspec.addResource(LANS[lan]) if not LANS[lan].isMember(node): LANS[lan].addMember(node, bandwidth = bw, latency = lat) # # Build up an epc node based on role and sliver type (VM or raw) # class InvalidRole(Exception): def __init__(self, role): self.role = role def __str__(self): return "Warning: Invalid EPC role: %s\n" % role def epcnode(name, role, hname = None, component_id = None): node = None if role not in GLOBALS.VALID_ROLES: raise InvalidRole(role) if GLOBALS.NODETYPE == RSpec.NodeType.VM: node = IG.XenVM(name, component_id = component_id, exclusive = True) node.ram = 1024 node.disk = 0 else: node = RSpec.RawPC(name, component_id = component_id) # Don't set the hwtype if a generic type was requested. if params.HWTYPE != "pc": node.hardware_type = params.HWTYPE node.disk_image = GLOBALS.OEPCIMG_URN_PREFIX + GLOBALS.BINOEPC_OS addtolan(EPCLANS.MGMT, node) startcmd = "%s -r %s" % (GLOBALS.OEPC_STARTSCRIPT, role) if hname: startcmd += " -h %s" % hname node.addService(RSpec.Execute(shell="csh", command=startcmd)) rspec.addResource(node) return node # # Add the core EPC nodes # # epc-enablers node epcen = epcnode("epc", EPCROLES.ENABLERS) addtolan(EPCLANS.NET_A, epcen) # pgw node pgw = epcnode("pgw", EPCROLES.PGW) addtolan(EPCLANS.NET_A, pgw) addtolan(EPCLANS.NET_B, pgw) # sgw-mme-sgsn node sgw = epcnode("sgw", EPCROLES.SGW_MME_SGSN) addtolan(EPCLANS.NET_B, sgw) addtolan(EPCLANS.NET_D, sgw) # Add a real eNodeB renb1 = RSpec.RawPC("renb1") rspec.addResource(renb1) if params.FIXEDENB: renb1.component_id = params.FIXEDENB renb1.hardware_type = GLOBALS.ENODEB_HWTYPE renb1.disk_image = GLOBALS.SYSTEM_URN_PREFIX + GLOBALS.ENODEB_OS addtolan(EPCLANS.NET_D, renb1) renb1_rflink1 = renb1.addInterface("renb1_rflink1") renb1_rflink2 = renb1.addInterface("renb1_rflink2") # Add the first real UE rue1 = RSpec.RawPC("rue1") rspec.addResource(rue1) if params.FIXEDUE: rue1.component_id = params.FIXEDUE rue1.hardware_type = GLOBALS.UE_HWTYPE rue1.disk_image = GLOBALS.OEPCIMG_URN_PREFIX + GLOBALS.UE_OS rue1_rflink1 = rue1.addInterface("rue1_rflink1") # Create the RF link between the real UE and eNodeB rflink1 = RFLink("rflink1") rspec.addResource(rflink1) rflink1.addInterface(rue1_rflink1) rflink1.addInterface(renb1_rflink1) # Add the second real UE rue2 = RSpec.RawPC("rue2") rspec.addResource(rue2) if params.FIXEDUE: rue2.component_id = params.FIXEDUE rue2.hardware_type = GLOBALS.UE_HWTYPE rue2.disk_image = GLOBALS.OEPCIMG_URN_PREFIX + GLOBALS.UE_OS rue2_rflink1 = rue2.addInterface("rue2_rflink1") # Create the RF link between the real UE and eNodeB rflink2 = RFLink("rflink2") rspec.addResource(rflink2) rflink2.addInterface(rue2_rflink1) rflink2.addInterface(renb1_rflink2) # # Create the requested number of emulated eNodeB nodes # for i in range(1, params.NUMENB + 1): ename = "enb%d" % i enb = epcnode(ename, EPCROLES.ENODEB, hname = ename) addtolan(EPCLANS.NET_D, enb) addtolan(EPCLANS.AN_LTE, enb) # # Now pop in the requested number of emulated clients (UEs). # for i in range(1, params.NUMCLI + 1): cname = "client%d" % i client = epcnode(cname, EPCROLES.CLIENT, hname = cname) addtolan(EPCLANS.AN_LTE, client) # # Add parameters to the request so we can get their values on the nodes. # The nodes download the manifest(s), and the setup scripts read the parameter # values when they run. # class Parameters(RSpec.Resource): def _write(self, root): ns = "{http://www.protogeni.net/resources/rspec/ext/phantomnet/1}" paramXML = "%sparameter" % ns el = ET.SubElement(root,"%sprofile_parameters" % ns) param = ET.SubElement(el,paramXML) param.text = 'NUMCLIENTS="%d"' % params.NUMCLI param = ET.SubElement(el,paramXML) param.text = 'NUMENODEB="%d"' % params.NUMENB return el pass parameters = Parameters() rspec.addResource(parameters) # # Print and go! # pc.printRequestRSpec(rspec)