initial import (Boeing r1752, NRL r878)

This commit is contained in:
ahrenholz 2013-08-29 14:21:13 +00:00
commit f8f46d28be
394 changed files with 99738 additions and 0 deletions

View file

View file

@ -0,0 +1,65 @@
#
# CORE
# Copyright (c)2011-2012 the Boeing Company.
# See the LICENSE file included in this distribution.
#
# author: Jeff Ahrenholz <jeffrey.m.ahrenholz@boeing.com>
#
'''
bypass.py: EMANE Bypass model for CORE
'''
import sys
import string
from core.api import coreapi
from core.constants import *
from emane import EmaneModel
class EmaneBypassModel(EmaneModel):
def __init__(self, session, objid = None, verbose = False):
EmaneModel.__init__(self, session, objid, verbose)
_name = "emane_bypass"
_confmatrix = [
("none",coreapi.CONF_DATA_TYPE_BOOL, '0',
'True,False','There are no parameters for the bypass model.'),
]
# value groupings
_confgroups = "Bypass Parameters:1-1"
def buildnemxmlfiles(self, e, ifc):
''' Build the necessary nem, mac, and phy XMLs in the given path.
If an individual NEM has a nonstandard config, we need to build
that file also. Otherwise the WLAN-wide nXXemane_bypassnem.xml,
nXXemane_bypassmac.xml, nXXemane_bypassphy.xml are used.
'''
values = e.getifcconfig(self.objid, self._name,
self.getdefaultvalues(), ifc)
if values is None:
return
nemdoc = e.xmldoc("nem")
nem = nemdoc.getElementsByTagName("nem").pop()
nem.setAttribute("name", "BYPASS NEM")
mactag = nemdoc.createElement("mac")
mactag.setAttribute("definition", self.macxmlname(ifc))
nem.appendChild(mactag)
phytag = nemdoc.createElement("phy")
phytag.setAttribute("definition", self.phyxmlname(ifc))
nem.appendChild(phytag)
e.xmlwrite(nemdoc, self.nemxmlname(ifc))
macdoc = e.xmldoc("mac")
mac = macdoc.getElementsByTagName("mac").pop()
mac.setAttribute("name", "BYPASS MAC")
mac.setAttribute("library", "bypassmaclayer")
e.xmlwrite(macdoc, self.macxmlname(ifc))
phydoc = e.xmldoc("phy")
phy = phydoc.getElementsByTagName("phy").pop()
phy.setAttribute("name", "BYPASS PHY")
phy.setAttribute("library", "bypassphylayer")
e.xmlwrite(phydoc, self.phyxmlname(ifc))

124
daemon/core/emane/commeffect.py Executable file
View file

@ -0,0 +1,124 @@
#
# CORE
# Copyright (c)2010-2013 the Boeing Company.
# See the LICENSE file included in this distribution.
#
# authors: Jeff Ahrenholz <jeffrey.m.ahrenholz@boeing.com>
# Randy Charland <rcharland@ll.mit.edu>
#
'''
commeffect.py: EMANE CommEffect model for CORE
'''
import sys
import string
from core.api import coreapi
from core.constants import *
from emane import EmaneModel
try:
import emaneeventservice
import emaneeventcommeffect
except Exception, e:
pass
def z(x):
''' Helper to use 0 for None values. '''
if x is None:
return 0
else:
return x
class EmaneCommEffectModel(EmaneModel):
def __init__(self, session, objid = None, verbose = False):
EmaneModel.__init__(self, session, objid, verbose)
# model name
_name = "emane_commeffect"
# CommEffect parameters
_confmatrix_shim = [
("defaultconnectivity", coreapi.CONF_DATA_TYPE_BOOL, '0',
'On,Off', 'defaultconnectivity'),
("filterfile", coreapi.CONF_DATA_TYPE_STRING, '',
'', 'filter file'),
("groupid", coreapi.CONF_DATA_TYPE_UINT32, '0',
'', 'NEM Group ID'),
("enablepromiscuousmode", coreapi.CONF_DATA_TYPE_BOOL, '0',
'On,Off', 'enable promiscuous mode'),
("enabletighttimingmode", coreapi.CONF_DATA_TYPE_BOOL, '0',
'On,Off', 'enable tight timing mode'),
("receivebufferperiod", coreapi.CONF_DATA_TYPE_FLOAT, '1.0',
'', 'receivebufferperiod'),
]
_confmatrix = _confmatrix_shim
# value groupings
_confgroups = "CommEffect SHIM Parameters:1-%d" \
% len(_confmatrix_shim)
def buildnemxmlfiles(self, e, ifc):
''' Build the necessary nem and commeffect XMLs in the given path.
If an individual NEM has a nonstandard config, we need to build
that file also. Otherwise the WLAN-wide
nXXemane_commeffectnem.xml, nXXemane_commeffectshim.xml are used.
'''
values = e.getifcconfig(self.objid, self._name,
self.getdefaultvalues(), ifc)
if values is None:
return
shimdoc = e.xmldoc("shim")
shim = shimdoc.getElementsByTagName("shim").pop()
shim.setAttribute("name", "commeffect SHIM")
shim.setAttribute("library", "commeffectshim")
names = self.getnames()
shimnames = list(names[:len(self._confmatrix_shim)])
shimnames.remove("filterfile")
# append all shim options (except filterfile) to shimdoc
map( lambda n: shim.appendChild(e.xmlparam(shimdoc, n, \
self.valueof(n, values))), shimnames)
# empty filterfile is not allowed
ff = self.valueof("filterfile", values)
if ff.strip() != '':
shim.appendChild(e.xmlparam(shimdoc, "filterfile", ff))
e.xmlwrite(shimdoc, self.shimxmlname(ifc))
nemdoc = e.xmldoc("nem")
nem = nemdoc.getElementsByTagName("nem").pop()
nem.setAttribute("name", "commeffect NEM")
nem.setAttribute("type", "unstructured")
nem.appendChild(e.xmlshimdefinition(nemdoc, self.shimxmlname(ifc)))
e.xmlwrite(nemdoc, self.nemxmlname(ifc))
def linkconfig(self, netif, bw = None, delay = None,
loss = None, duplicate = None, jitter = None, netif2 = None):
''' Generate CommEffect events when a Link Message is received having
link parameters.
'''
service = self.session.emane.service
if service is None:
self.session.warn("%s: EMANE event service unavailable" % \
self._name)
return
if netif is None or netif2 is None:
self.session.warn("%s: missing NEM information" % self._name)
return
# TODO: batch these into multiple events per transmission
event = emaneeventcommeffect.EventCommEffect(1)
index = 0
e = self.session.obj(self.objid)
nemid = e.getnemid(netif)
nemid2 = e.getnemid(netif2)
mbw = bw
event.set(index, nemid, 0, z(delay), 0, z(jitter), z(loss),
z(duplicate), long(z(bw)), long(z(mbw)))
service.publish(emaneeventcommeffect.EVENT_ID,
emaneeventservice.PLATFORMID_ANY,
nemid2, emaneeventservice.COMPONENTID_ANY,
event.export())

844
daemon/core/emane/emane.py Normal file
View file

@ -0,0 +1,844 @@
#
# CORE
# Copyright (c)2010-2013 the Boeing Company.
# See the LICENSE file included in this distribution.
#
# author: Jeff Ahrenholz <jeffrey.m.ahrenholz@boeing.com>
#
'''
emane.py: definition of an Emane class for implementing configuration
control of an EMANE emulation.
'''
import sys, os, threading, subprocess, time, string
from xml.dom.minidom import parseString, Document
from core.constants import *
from core.api import coreapi
from core.misc.ipaddr import MacAddr
from core.conf import ConfigurableManager, Configurable
from core.mobility import WirelessModel
from core.emane.nodes import EmaneNode
try:
import emaneeventservice
import emaneeventlocation
except Exception, e:
pass
class Emane(ConfigurableManager):
''' EMANE controller object. Lives in a Session instance and is used for
building EMANE config files from all of the EmaneNode objects in this
emulation, and for controlling the EMANE daemons.
'''
_name = "emane"
_type = coreapi.CORE_TLV_REG_EMULSRV
_hwaddr_prefix = "02:02"
def __init__(self, session):
ConfigurableManager.__init__(self, session)
self.verbose = self.session.getcfgitembool('verbose', False)
self._objs = {}
self._objslock = threading.Lock()
self._ifccounts = {}
self._ifccountslock = threading.Lock()
self._modelclsmap = {}
# Port numbers are allocated from these counters
self.platformport = self.session.getcfgitemint('emane_platform_port',
8100)
self.transformport = self.session.getcfgitemint('emane_transform_port',
8200)
# model for global EMANE configuration options
self.emane_config = EmaneGlobalModel(session, None, self.verbose)
session.broker.handlers += (self.handledistributed, )
self.loadmodels()
# this allows the event service Python bindings to be absent
try:
self.service = emaneeventservice.EventService()
except:
self.service = None
self.doeventloop = False
self.eventmonthread = None
# EMANE 0.7.4 support -- to be removed when 0.7.4 support is deprecated
self.emane074 = False
try:
tmp = emaneeventlocation.EventLocation(1)
# check if yaw parameter is supported by Location Events
# if so, we have EMANE 0.8.1+; if not, we have EMANE 0.7.4/earlier
tmp.set(0, 1, 2, 2, 2, 3)
except TypeError:
self.emane074 = True
except Exception:
pass
def loadmodels(self):
''' dynamically load EMANE models that were specified in the config file
'''
self._modelclsmap.clear()
self._modelclsmap[self.emane_config._name] = self.emane_config
emane_models = self.session.getcfgitem('emane_models')
if emane_models is None:
return
emane_models = emane_models.split(',')
for model in emane_models:
model = model.strip()
try:
modelfile = "%s" % model.lower()
clsname = "Emane%sModel" % model
importcmd = "from %s import %s" % (modelfile, clsname)
exec(importcmd)
except Exception, e:
warntxt = "unable to load the EMANE model '%s'" % modelfile
warntxt += " specified in the config file (%s)" % e
self.session.exception(coreapi.CORE_EXCP_LEVEL_WARNING, "emane",
None, warntxt)
self.warn(warntxt)
continue
# record the model name to class name mapping
# this should match clsname._name
confname = "emane_%s" % model.lower()
self._modelclsmap[confname] = eval(clsname)
# each EmaneModel must have ModelName.configure() defined
confmethod = eval("%s.configure_emane" % clsname)
self.session.addconfobj(confname, coreapi.CORE_TLV_REG_WIRELESS,
confmethod)
def addobj(self, obj):
''' add a new EmaneNode object to this Emane controller object
'''
self._objslock.acquire()
if obj.objid in self._objs:
self._objslock.release()
raise KeyError, "non-unique EMANE object id %s for %s" % \
(obj.objid, obj)
self._objs[obj.objid] = obj
self._objslock.release()
def getmodels(self, n):
''' Used with XML export; see ConfigurableManager.getmodels()
'''
r = ConfigurableManager.getmodels(self, n)
# EMANE global params are stored with first EMANE node (if non-default
# values are configured)
sorted_ids = sorted(self.configs.keys())
if None in self.configs and len(sorted_ids) > 1 and \
n.objid == sorted_ids[1]:
v = self.configs[None]
for model in v:
cls = self._modelclsmap[model[0]]
vals = model[1]
r.append((cls, vals))
return r
def getifcconfig(self, nodenum, conftype, defaultvalues, ifc):
# use the network-wide config values or interface(NEM)-specific values?
if ifc is None:
return self.getconfig(nodenum, conftype, defaultvalues)[1]
else:
# don't use default values when interface config is the same as net
# note here that using ifc.node.objid as key allows for only one type
# of each model per node; TODO: use both node and interface as key
return self.getconfig(ifc.node.objid, conftype, None)[1]
def setup(self):
''' Populate self._objs with EmaneNodes; perform distributed setup;
associate models with EmaneNodes from self.config.
'''
with self.session._objslock:
for obj in self.session.objs():
if isinstance(obj, EmaneNode):
self.addobj(obj)
if len(self._objs) == 0:
return False
if self.checkdistributed():
# we are slave, but haven't received a platformid yet
cfgval = self.getconfig(None, self.emane_config._name,
self.emane_config.getdefaultvalues())[1]
i = self.emane_config.getnames().index('platform_id_start')
if cfgval[i] == self.emane_config.getdefaultvalues()[i]:
return False
self.setnodemodels()
return True
def startup(self):
''' after all the EmaneNode objects have been added, build XML files
and start the daemons
'''
self.reset()
if not self.setup():
return
with self._objslock:
self.buildxml()
self.starteventmonitor()
if self.numnems() > 0:
self.startdaemons()
self.installnetifs()
def poststartup(self):
''' Retransmit location events now that all NEMs are active.
'''
if self.doeventmonitor():
return
with self._objslock:
for n in sorted(self._objs.keys()):
e = self._objs[n]
for netif in e.netifs():
(x, y, z) = netif.node.position.get()
e.setnemposition(netif, x, y, z)
def reset(self):
''' remove all EmaneNode objects from the dictionary,
reset port numbers and nem id counters
'''
with self._objslock:
self._objs.clear()
# don't clear self._ifccounts here; NEM counts are needed for buildxml
self.platformport = self.session.getcfgitemint('emane_platform_port',
8100)
self.transformport = self.session.getcfgitemint('emane_transform_port',
8200)
def shutdown(self):
''' stop all EMANE daemons
'''
self._ifccountslock.acquire()
self._ifccounts.clear()
self._ifccountslock.release()
self._objslock.acquire()
if len(self._objs) == 0:
self._objslock.release()
return
self.info("Stopping EMANE daemons.")
self.deinstallnetifs()
self.stopdaemons()
self.stopeventmonitor()
self._objslock.release()
def handledistributed(self, msg):
''' Broker handler for processing CORE API messages as they are
received. This is used to snoop the Link add messages to get NEM
counts of NEMs that exist on other servers.
'''
if msg.msgtype == coreapi.CORE_API_LINK_MSG and \
msg.flags & coreapi.CORE_API_ADD_FLAG:
nn = msg.nodenumbers()
# first node is always link layer node in Link add message
if nn[0] in self.session.broker.nets:
serverlist = self.session.broker.getserversbynode(nn[1])
for server in serverlist:
self._ifccountslock.acquire()
if server not in self._ifccounts:
self._ifccounts[server] = 1
else:
self._ifccounts[server] += 1
self._ifccountslock.release()
def checkdistributed(self):
''' Check for EMANE nodes that exist on multiple emulation servers and
coordinate the NEM id and port number space.
If we are the master EMANE node, return False so initialization will
proceed as normal; otherwise slaves return True here and
initialization is deferred.
'''
# check with the session if we are the "master" Emane object?
master = False
self._objslock.acquire()
if len(self._objs) > 0:
master = self.session.master
self.info("Setup EMANE with master=%s." % master)
self._objslock.release()
# we are not the master Emane object, wait for nem id and ports
if not master:
return True
cfgval = self.getconfig(None, self.emane_config._name,
self.emane_config.getdefaultvalues())[1]
values = list(cfgval)
nemcount = 0
self._objslock.acquire()
for n in self._objs:
emanenode = self._objs[n]
nemcount += emanenode.numnetif()
nemid = int(self.emane_config.valueof("nem_id_start", values))
nemid += nemcount
platformid = int(self.emane_config.valueof("platform_id_start", values))
names = list(self.emane_config.getnames())
# build an ordered list of servers so platform ID is deterministic
servers = []
for n in sorted(self._objs):
for s in self.session.broker.getserversbynode(n):
if s not in servers:
servers.append(s)
self._objslock.release()
for server in servers:
if server == "localhost":
continue
(host, port, sock) = self.session.broker.getserver(server)
if sock is None:
continue
platformid += 1
typeflags = coreapi.CONF_TYPE_FLAGS_UPDATE
values[names.index("platform_id_start")] = str(platformid)
values[names.index("nem_id_start")] = str(nemid)
msg = EmaneGlobalModel.toconfmsg(flags=0, nodenum=None,
typeflags=typeflags, values=values)
sock.send(msg)
# increment nemid for next server by number of interfaces
self._ifccountslock.acquire()
if server in self._ifccounts:
nemid += self._ifccounts[server]
self._ifccountslock.release()
return False
def buildxml(self):
''' Build all of the XML files required to run EMANE.
'''
# assume self._objslock is already held here
if self.verbose:
self.info("Emane.buildxml()")
self.buildplatformxml()
self.buildnemxml()
self.buildtransportxml()
def xmldoc(self, doctype):
''' Returns an XML xml.minidom.Document with a DOCTYPE tag set to the
provided doctype string, and an initial element having the same
name.
'''
# we hack in the DOCTYPE using the parser
docstr = """<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE %s SYSTEM "file:///usr/share/emane/dtd/%s.dtd">
<%s/>""" % (doctype, doctype, doctype)
# normally this would be: doc = Document()
return parseString(docstr)
def xmlparam(self, doc, name, value):
''' Convenience function for building a parameter tag of the format:
<param name="name" value="value" />
'''
p = doc.createElement("param")
p.setAttribute("name", name)
p.setAttribute("value", value)
return p
def xmlshimdefinition(self, doc, name):
''' Convenience function for building a definition tag of the format:
<shim definition="name" />
'''
p = doc.createElement("shim")
p.setAttribute("definition", name)
return p
def xmlwrite(self, doc, filename):
''' Write the given XML document to the specified filename.
'''
#self.info("%s" % doc.toprettyxml(indent=" "))
pathname = os.path.join(self.session.sessiondir, filename)
f = open(pathname, "w")
doc.writexml(writer=f, indent="", addindent=" ", newl="\n", \
encoding="UTF-8")
f.close()
def setnodemodels(self):
''' Associate EmaneModel classes with EmaneNode nodes. The model
configurations are stored in self.configs.
'''
for n in self._objs:
self.setnodemodel(n)
def setnodemodel(self, n):
emanenode = self._objs[n]
for (t, v) in self.configs[n]:
if t is None:
continue
if t == self.emane_config._name:
continue
# only use the first valid EmaneModel
# convert model name to class (e.g. emane_rfpipe -> EmaneRfPipe)
cls = self._modelclsmap[t]
emanenode.setmodel(cls, v)
return True
# no model has been configured for this EmaneNode
return False
def nemlookup(self, nemid):
''' Look for the given numerical NEM ID and return the first matching
EmaneNode and NEM interface.
'''
emanenode = None
netif = None
for n in self._objs:
emanenode = self._objs[n]
netif = emanenode.getnemnetif(nemid)
if netif is not None:
break
else:
emanenode = None
return (emanenode, netif)
def numnems(self):
''' Return the number of NEMs emulated locally.
'''
count = 0
for o in self._objs.values():
count += len(o.netifs())
return count
def buildplatformxml(self):
''' Build a platform.xml file now that all nodes are configured.
'''
values = self.getconfig(None, "emane",
self.emane_config.getdefaultvalues())[1]
doc = self.xmldoc("platform")
plat = doc.getElementsByTagName("platform").pop()
platformid = self.emane_config.valueof("platform_id_start", values)
plat.setAttribute("name", "Platform %s" % platformid)
plat.setAttribute("id", platformid)
names = list(self.emane_config.getnames())
platform_names = names[:len(self.emane_config._confmatrix_platform)]
platform_names.remove('platform_id_start')
# append all platform options (except starting id) to doc
map( lambda n: plat.appendChild(self.xmlparam(doc, n, \
self.emane_config.valueof(n, values))), platform_names)
nemid = int(self.emane_config.valueof("nem_id_start", values))
# assume self._objslock is already held here
for n in sorted(self._objs.keys()):
emanenode = self._objs[n]
nems = emanenode.buildplatformxmlentry(doc)
for netif in sorted(nems, key=lambda n: n.node.objid):
# set ID, endpoints here
nementry = nems[netif]
nementry.setAttribute("id", "%d" % nemid)
# insert nem options (except nem id) to doc
trans_addr = self.emane_config.valueof("transportendpoint", \
values)
nementry.insertBefore(self.xmlparam(doc, "transportendpoint", \
"%s:%d" % (trans_addr, self.transformport)),
nementry.firstChild)
platform_addr = self.emane_config.valueof("platformendpoint", \
values)
nementry.insertBefore(self.xmlparam(doc, "platformendpoint", \
"%s:%d" % (platform_addr, self.platformport)),
nementry.firstChild)
plat.appendChild(nementry)
emanenode.setnemid(netif, nemid)
# NOTE: MAC address set before here is incorrect, including the one
# sent from the GUI via link message
# MAC address determined by NEM ID: 02:02:00:00:nn:nn"
macstr = self._hwaddr_prefix + ":00:00:"
macstr += "%02X:%02X" % ((nemid >> 8) & 0xFF, nemid & 0xFF)
netif.sethwaddr(MacAddr.fromstring(macstr))
# increment counters used to manage IDs, endpoint port numbers
nemid += 1
self.platformport += 1
self.transformport += 1
self.xmlwrite(doc, "platform.xml")
def buildnemxml(self):
''' Builds the xxxnem.xml, xxxmac.xml, and xxxphy.xml files which
are defined on a per-EmaneNode basis.
'''
for n in sorted(self._objs.keys()):
emanenode = self._objs[n]
nems = emanenode.buildnemxmlfiles(self)
def buildtransportxml(self):
''' Calls emanegentransportxml using a platform.xml file to build
the transportdaemon*.xml.
'''
try:
subprocess.check_call(["emanegentransportxml", "platform.xml"], \
cwd=self.session.sessiondir)
except Exception, e:
self.info("error running emanegentransportxml: %s" % e)
def startdaemons(self):
''' Start the appropriate EMANE daemons. The transport daemon will
bind to the TAP interfaces.
'''
if self.verbose:
self.info("Emane.startdaemons()")
path = self.session.sessiondir
loglevel = "2"
cfgloglevel = self.session.getcfgitemint("emane_log_level")
realtime = self.session.getcfgitembool("emane_realtime", True)
if cfgloglevel:
self.info("setting user-defined EMANE log level: %d" % cfgloglevel)
loglevel = str(cfgloglevel)
emanecmd = ["emane", "-d", "--logl", loglevel, "-f", \
os.path.join(path, "emane.log")]
if realtime:
emanecmd += "-r",
try:
cmd = emanecmd + [os.path.join(path, "platform.xml")]
if self.verbose:
self.info("Emane.startdaemons() running %s" % str(cmd))
subprocess.check_call(cmd, cwd=path)
except Exception, e:
errmsg = "error starting emane: %s" % e
self.session.exception(coreapi.CORE_EXCP_LEVEL_FATAL, "emane",
None, errmsg)
self.info(errmsg)
# start one transport daemon per transportdaemon*.xml file
transcmd = ["emanetransportd", "-d", "--logl", loglevel, "-f", \
os.path.join(path, "emanetransportd.log")]
if realtime:
transcmd += "-r",
files = os.listdir(path)
for file in files:
if file[-3:] == "xml" and file[:15] == "transportdaemon":
cmd = transcmd + [os.path.join(path, file)]
try:
if self.verbose:
self.info("Emane.startdaemons() running %s" % str(cmd))
subprocess.check_call(cmd, cwd=path)
except Exception, e:
errmsg = "error starting emanetransportd: %s" % e
self.session.exception(coreapi.CORE_EXCP_LEVEL_FATAL, "emane",
None, errmsg)
self.info(errmsg)
def stopdaemons(self):
''' Kill the appropriate EMANE daemons.
'''
# TODO: we may want to improve this if we had the PIDs from the
# specific EMANE daemons that we've started
subprocess.call(["killall", "-q", "emane"])
subprocess.call(["killall", "-q", "emanetransportd"])
def installnetifs(self):
''' Install TUN/TAP virtual interfaces into their proper namespaces
now that the EMANE daemons are running.
'''
for n in sorted(self._objs.keys()):
emanenode = self._objs[n]
if self.verbose:
self.info("Emane.installnetifs() for node %d" % n)
emanenode.installnetifs()
def deinstallnetifs(self):
''' Uninstall TUN/TAP virtual interfaces.
'''
for n in sorted(self._objs.keys()):
emanenode = self._objs[n]
emanenode.deinstallnetifs()
def configure(self, session, msg):
''' Handle configuration messages for global EMANE config.
'''
r = self.emane_config.configure_emane(session, msg)
# extra logic to start slave Emane object after nemid has been
# configured from the master
conftype = msg.gettlv(coreapi.CORE_TLV_CONF_TYPE)
if conftype == coreapi.CONF_TYPE_FLAGS_UPDATE and \
self.session.master == False:
self.startup()
return r
def doeventmonitor(self):
''' Returns boolean whether or not EMANE events will be monitored.
'''
# this support must be explicitly turned on; by default, CORE will
# generate the EMANE events when nodes are moved
return self.session.getcfgitembool('emane_event_monitor', False)
def starteventmonitor(self):
''' Start monitoring EMANE location events if configured to do so.
'''
if self.verbose:
self.info("Emane.starteventmonitor()")
if not self.doeventmonitor():
return
if self.service is None:
errmsg = "Warning: EMANE events will not be generated " \
"because the emaneeventservice\n binding was " \
"unable to load " \
"(install the python-emaneeventservice bindings)"
self.session.exception(coreapi.CORE_EXCP_LEVEL_WARNING, "emane",
None, errmsg)
self.warn(errmsg)
return
self.doeventloop = True
self.eventmonthread = threading.Thread(target = self.eventmonitorloop)
self.eventmonthread.daemon = True
self.eventmonthread.start()
def stopeventmonitor(self):
''' Stop monitoring EMANE location events.
'''
self.doeventloop = False
if self.service is not None:
self.service.breakloop()
# reset the service, otherwise nextEvent won't work
del self.service
self.service = emaneeventservice.EventService()
if self.eventmonthread is not None:
self.eventmonthread.join()
self.eventmonthread = None
def eventmonitorloop(self):
''' Thread target that monitors EMANE location events.
'''
if self.service is None:
return
self.info("subscribing to EMANE location events")
#self.service.subscribe(emaneeventlocation.EVENT_ID,
# self.handlelocationevent)
#self.service.loop()
#self.service.subscribe(emaneeventlocation.EVENT_ID, None)
while self.doeventloop is True:
(event, platform, nem, component, data) = self.service.nextEvent()
if event == emaneeventlocation.EVENT_ID:
self.handlelocationevent(event, platform, nem, component, data)
self.info("unsubscribing from EMANE location events")
#self.service.unsubscribe(emaneeventlocation.EVENT_ID)
def handlelocationevent(self, event, platform, nem, component, data):
''' Handle an EMANE location event.
'''
event = emaneeventlocation.EventLocation(data)
entries = event.entries()
for e in entries.values():
# yaw,pitch,roll,azimuth,elevation,velocity are unhandled
(nemid, lat, long, alt) = e[:4]
# convert nemid to node number
(emanenode, netif) = self.nemlookup(nemid)
if netif is None:
if self.verbose:
self.info("location event for unknown NEM %s" % nemid)
continue
n = netif.node.objid
# convert from lat/long/alt to x,y,z coordinates
(x, y, z) = self.session.location.getxyz(lat, long, alt)
x = int(x)
y = int(y)
z = int(z)
if self.verbose:
self.info("location event NEM %s (%s, %s, %s) -> (%s, %s, %s)" \
% (nemid, lat, long, alt, x, y, z))
try:
if (x.bit_length() > 16) or (y.bit_length() > 16) or \
(z.bit_length() > 16) or (x < 0) or (y < 0) or (z < 0):
warntxt = "Unable to build node location message since " \
"received lat/long/alt exceeds coordinate " \
"space: NEM %s (%d, %d, %d)" % (nemid, x, y, z)
self.info(warntxt)
self.session.exception(coreapi.CORE_EXCP_LEVEL_ERROR,
"emane", None, warntxt)
continue
except AttributeError:
# int.bit_length() not present on Python 2.6
pass
# generate a node message for this location update
try:
node = self.session.obj(n)
except KeyError:
self.warn("location event NEM %s has no corresponding node %s" \
% (nemid, n))
continue
# don't use node.setposition(x,y,z) which generates an event
node.position.set(x,y,z)
msg = node.tonodemsg(flags=0)
self.session.broadcastraw(None, msg)
self.session.sdt.updatenodegeo(node, lat, long, alt)
class EmaneModel(WirelessModel):
''' EMANE models inherit from this parent class, which takes care of
handling configuration messages based on the _confmatrix list of
configurable parameters. Helper functions also live here.
'''
_prefix = {'y': 1e-24, # yocto
'z': 1e-21, # zepto
'a': 1e-18, # atto
'f': 1e-15, # femto
'p': 1e-12, # pico
'n': 1e-9, # nano
'u': 1e-6, # micro
'm': 1e-3, # mili
'c': 1e-2, # centi
'd': 1e-1, # deci
'k': 1e3, # kilo
'M': 1e6, # mega
'G': 1e9, # giga
'T': 1e12, # tera
'P': 1e15, # peta
'E': 1e18, # exa
'Z': 1e21, # zetta
'Y': 1e24, # yotta
}
@classmethod
def configure_emane(cls, session, msg):
''' Handle configuration messages for setting up a model.
Pass the Emane object as the manager object.
'''
return cls.configure(session.emane, msg)
@classmethod
def emane074_fixup(cls, value, div=1.0):
''' Helper for converting 0.8.1 and newer values to EMANE 0.7.4
compatible values.
NOTE: This should be removed when support for 0.7.4 has been
deprecated.
'''
if div == 0:
return "0"
if type(value) is not str:
return str(value / div)
if value.endswith(tuple(cls._prefix.keys())):
suffix = value[-1]
value = float(value[:-1]) * cls._prefix[suffix]
return str(int(value / div))
def buildnemxmlfiles(self, e, ifc):
''' Build the necessary nem, mac, and phy XMLs in the given path.
'''
raise NotImplementedError
def buildplatformxmlnementry(self, doc, n, ifc):
''' Build the NEM definition that goes into the platform.xml file.
This returns an XML element that will be added to the <platform/> element.
This default method supports per-interface config
(e.g. <nem definition="n2_0_63emane_rfpipe.xml" id="1"> or per-EmaneNode
config (e.g. <nem definition="n1emane_rfpipe.xml" id="1">.
This can be overriden by a model for NEM flexibility; n is the EmaneNode.
'''
nem = doc.createElement("nem")
nem.setAttribute("name", ifc.localname)
# if this netif contains a non-standard (per-interface) config,
# then we need to use a more specific xml file here
nem.setAttribute("definition", self.nemxmlname(ifc))
return nem
def buildplatformxmltransportentry(self, doc, n, ifc):
''' Build the transport definition that goes into the platform.xml file.
This returns an XML element that will added to the nem definition.
This default method supports raw and virtual transport types, but may be
overriden by a model to support the e.g. pluggable virtual transport.
n is the EmaneNode.
'''
type = ifc.transport_type
if not type:
e.info("warning: %s interface type unsupported!" % ifc.name)
type = "raw"
trans = doc.createElement("transport")
trans.setAttribute("definition", n.transportxmlname(type))
trans.setAttribute("group", "1")
param = doc.createElement("param")
param.setAttribute("name", "device")
if type == "raw":
# raw RJ45 name e.g. 'eth0'
param.setAttribute("value", ifc.name)
else:
# virtual TAP name e.g. 'n3.0.17'
param.setAttribute("value", ifc.localname)
trans.appendChild(param)
return trans
def basename(self, ifc = None):
''' Return the string that other names are based on.
If a specific config is stored for a node's interface, a unique
filename is needed; otherwise the name of the EmaneNode is used.
'''
emane = self.session.emane
name = "n%s" % self.objid
if ifc is not None:
nodenum = ifc.node.objid
if emane.getconfig(nodenum, self._name, None)[1] is not None:
name = ifc.localname.replace('.','_')
return "%s%s" % (name, self._name)
def nemxmlname(self, ifc = None):
''' Return the string name for the NEM XML file, e.g. 'n3rfpipenem.xml'
'''
return "%snem.xml" % self.basename(ifc)
def shimxmlname(self, ifc = None):
''' Return the string name for the SHIM XML file, e.g. 'commeffectshim.xml'
'''
return "%sshim.xml" % self.basename(ifc)
def macxmlname(self, ifc = None):
''' Return the string name for the MAC XML file, e.g. 'n3rfpipemac.xml'
'''
return "%smac.xml" % self.basename(ifc)
def phyxmlname(self, ifc = None):
''' Return the string name for the PHY XML file, e.g. 'n3rfpipephy.xml'
'''
return "%sphy.xml" % self.basename(ifc)
def update(self, moved, moved_netifs):
''' invoked from MobilityModel when nodes are moved; this causes
EMANE location events to be generated for the nodes in the moved
list, making EmaneModels compatible with Ns2ScriptedMobility
'''
try:
wlan = self.session.obj(self.objid)
except KeyError:
return
wlan.setnempositions(moved_netifs)
def linkconfig(self, netif, bw = None, delay = None,
loss = None, duplicate = None, jitter = None, netif2 = None):
''' Invoked when a Link Message is received. Default is unimplemented.
'''
warntxt = "EMANE model %s does not support link " % self._name
warntxt += "configuration, dropping Link Message"
self.session.warn(warntxt)
class EmaneGlobalModel(EmaneModel):
''' Global EMANE configuration options.
'''
def __init__(self, session, objid = None, verbose = False):
EmaneModel.__init__(self, session, objid, verbose)
_name = "emane"
_confmatrix_platform = [
("otamanagerchannelenable", coreapi.CONF_DATA_TYPE_BOOL, '0',
'on,off', 'enable OTA Manager channel'),
("otamanagergroup", coreapi.CONF_DATA_TYPE_STRING, '224.1.2.8:45702',
'', 'OTA Manager group'),
("otamanagerdevice", coreapi.CONF_DATA_TYPE_STRING, 'lo',
'', 'OTA Manager device'),
("eventservicegroup", coreapi.CONF_DATA_TYPE_STRING, '224.1.2.8:45703',
'', 'Event Service group'),
("eventservicedevice", coreapi.CONF_DATA_TYPE_STRING, 'lo',
'', 'Event Service device'),
("platform_id_start", coreapi.CONF_DATA_TYPE_INT32, '1',
'', 'starting Platform ID'),
("debugportenable", coreapi.CONF_DATA_TYPE_BOOL, '0',
'on,off', 'enable debug port'),
("debugport", coreapi.CONF_DATA_TYPE_UINT16, '47000',
'', 'debug port number'),
]
_confmatrix_nem = [
("transportendpoint", coreapi.CONF_DATA_TYPE_STRING, 'localhost',
'', 'Transport endpoint address (port is automatic)'),
("platformendpoint", coreapi.CONF_DATA_TYPE_STRING, 'localhost',
'', 'Platform endpoint address (port is automatic)'),
("nem_id_start", coreapi.CONF_DATA_TYPE_INT32, '1',
'', 'starting NEM ID'),
]
_confmatrix = _confmatrix_platform + _confmatrix_nem
_confgroups = "Platform Attributes:1-%d|NEM Parameters:%d-%d" % \
(len(_confmatrix_platform), len(_confmatrix_platform) + 1,
len(_confmatrix))

View file

@ -0,0 +1,119 @@
#
# CORE
# Copyright (c)2010-2013 the Boeing Company.
# See the LICENSE file included in this distribution.
#
# author: Jeff Ahrenholz <jeffrey.m.ahrenholz@boeing.com>
#
'''
ieee80211abg.py: EMANE IEEE 802.11abg model for CORE
'''
import sys
import string
from core.api import coreapi
from core.constants import *
from emane import EmaneModel
from universal import EmaneUniversalModel
class EmaneIeee80211abgModel(EmaneModel):
def __init__(self, session, objid = None, verbose = False):
EmaneModel.__init__(self, session, objid, verbose)
# model name
_name = "emane_ieee80211abg"
_80211rates = '1 1 Mbps,2 2 Mbps,3 5.5 Mbps,4 11 Mbps,5 6 Mbps,' + \
'6 9 Mbps,7 12 Mbps,8 18 Mbps,9 24 Mbps,10 36 Mbps,11 48 Mbps,' + \
'12 54 Mbps'
# MAC parameters
_confmatrix_mac = [
("mode", coreapi.CONF_DATA_TYPE_UINT8, '0',
'0 802.11b (DSSS only),1 802.11b (DSSS only),' + \
'2 802.11a or g (OFDM),3 802.11b/g (DSSS and OFDM)', 'mode'),
("enablepromiscuousmode", coreapi.CONF_DATA_TYPE_BOOL, '0',
'On,Off', 'enable promiscuous mode'),
("distance", coreapi.CONF_DATA_TYPE_UINT32, '1000',
'', 'max distance (m)'),
("unicastrate", coreapi.CONF_DATA_TYPE_UINT8, '4', _80211rates,
'unicast rate (Mbps)'),
("multicastrate", coreapi.CONF_DATA_TYPE_UINT8, '1', _80211rates,
'multicast rate (Mbps)'),
("rtsthreshold", coreapi.CONF_DATA_TYPE_UINT16, '0',
'', 'RTS threshold (bytes)'),
("wmmenable", coreapi.CONF_DATA_TYPE_BOOL, '0',
'On,Off', 'WiFi Multimedia (WMM)'),
("pcrcurveuri", coreapi.CONF_DATA_TYPE_STRING,
'/usr/share/emane/models/ieee80211abg/xml/ieee80211pcr.xml',
'', 'SINR/PCR curve file'),
("flowcontrolenable", coreapi.CONF_DATA_TYPE_BOOL, '0',
'On,Off', 'enable traffic flow control'),
("flowcontroltokens", coreapi.CONF_DATA_TYPE_UINT16, '10',
'', 'number of flow control tokens'),
("queuesize", coreapi.CONF_DATA_TYPE_STRING, '0:255 1:255 2:255 3:255',
'', 'queue size (0-4:size)'),
("cwmin", coreapi.CONF_DATA_TYPE_STRING, '0:32 1:32 2:16 3:8',
'', 'min contention window (0-4:minw)'),
("cwmax", coreapi.CONF_DATA_TYPE_STRING, '0:1024 1:1024 2:64 3:16',
'', 'max contention window (0-4:maxw)'),
("aifs", coreapi.CONF_DATA_TYPE_STRING, '0:2 1:2 2:2 3:1',
'', 'arbitration inter frame space (0-4:aifs)'),
("txop", coreapi.CONF_DATA_TYPE_STRING, '0:0 1:0 2:0 3:0',
'', 'txop (0-4:usec)'),
("retrylimit", coreapi.CONF_DATA_TYPE_STRING, '0:3 1:3 2:3 3:3',
'', 'retry limit (0-4:numretries)'),
]
# PHY parameters from Universal PHY
_confmatrix_phy = EmaneUniversalModel._confmatrix
_confmatrix = _confmatrix_mac + _confmatrix_phy
# value groupings
_confgroups = "802.11 MAC Parameters:1-%d|Universal PHY Parameters:%d-%d" \
% (len(_confmatrix_mac), len(_confmatrix_mac) + 1, len(_confmatrix))
def buildnemxmlfiles(self, e, ifc):
''' Build the necessary nem, mac, and phy XMLs in the given path.
If an individual NEM has a nonstandard config, we need to build
that file also. Otherwise the WLAN-wide
nXXemane_ieee80211abgnem.xml, nXXemane_ieee80211abgemac.xml,
nXXemane_ieee80211abgphy.xml are used.
'''
# use the network-wide config values or interface(NEM)-specific values?
if ifc is None:
values = e.getconfig(self.objid, self._name,
self.getdefaultvalues())[1]
else:
nodenum = ifc.node.objid
values = e.getconfig(nodenum, self._name, None)[1]
if values is None:
# do not build specific files for this NEM when config is same
# as the network
return
nemdoc = e.xmldoc("nem")
nem = nemdoc.getElementsByTagName("nem").pop()
nem.setAttribute("name", "ieee80211abg NEM")
mactag = nemdoc.createElement("mac")
mactag.setAttribute("definition", self.macxmlname(ifc))
nem.appendChild(mactag)
phytag = nemdoc.createElement("phy")
phytag.setAttribute("definition", self.phyxmlname(ifc))
nem.appendChild(phytag)
e.xmlwrite(nemdoc, self.nemxmlname(ifc))
macdoc = e.xmldoc("mac")
mac = macdoc.getElementsByTagName("mac").pop()
mac.setAttribute("name", "ieee80211abg MAC")
mac.setAttribute("library", "ieee80211abgmaclayer")
names = self.getnames()
macnames = names[:len(self._confmatrix_mac)]
phynames = names[len(self._confmatrix_mac):]
# append all MAC options to macdoc
map( lambda n: mac.appendChild(e.xmlparam(macdoc, n, \
self.valueof(n, values))), macnames)
e.xmlwrite(macdoc, self.macxmlname(ifc))
phydoc = EmaneUniversalModel.getphydoc(e, self, values, phynames)
e.xmlwrite(phydoc, self.phyxmlname(ifc))

281
daemon/core/emane/nodes.py Normal file
View file

@ -0,0 +1,281 @@
#
# CORE
# Copyright (c)2010-2013 the Boeing Company.
# See the LICENSE file included in this distribution.
#
# author: Jeff Ahrenholz <jeffrey.m.ahrenholz@boeing.com>
#
'''
nodes.py: definition of an EmaneNode class for implementing configuration
control of an EMANE emulation. An EmaneNode has several attached NEMs that
share the same MAC+PHY model.
'''
import sys
from core.api import coreapi
from core.coreobj import PyCoreNet
try:
import emaneeventservice
import emaneeventlocation
except Exception, e:
''' Don't require all CORE users to have EMANE libeventservice and its
Python bindings installed.
'''
pass
class EmaneNet(PyCoreNet):
''' EMANE network base class.
'''
apitype = coreapi.CORE_NODE_EMANE
linktype = coreapi.CORE_LINK_WIRELESS
type = "wlan" # icon used
class EmaneNode(EmaneNet):
''' EMANE node contains NEM configuration and causes connected nodes
to have TAP interfaces (instead of VEth). These are managed by the
Emane controller object that exists in a session.
'''
def __init__(self, session, objid = None, name = None, verbose = False,
start = True):
PyCoreNet.__init__(self, session, objid, name, verbose, start)
self.verbose = verbose
self.conf = ""
self.up = False
self.nemidmap = {}
self.model = None
self.mobility = None
def linkconfig(self, netif, bw = None, delay = None,
loss = None, duplicate = None, jitter = None, netif2 = None):
''' The CommEffect model supports link configuration.
'''
if not self.model:
return
return self.model.linkconfig(netif=netif, bw=bw, delay=delay, loss=loss,
duplicate=duplicate, jitter=jitter, netif2=netif2)
def config(self, conf):
#print "emane", self.name, "got config:", conf
self.conf = conf
def shutdown(self):
pass
def link(self, netif1, netif2):
pass
def unlink(self, netif1, netif2):
pass
def setmodel(self, model, config):
''' set the EmaneModel associated with this node
'''
if (self.verbose):
self.info("adding model %s" % model._name)
if model._type == coreapi.CORE_TLV_REG_WIRELESS:
# EmaneModel really uses values from ConfigurableManager
# when buildnemxml() is called, not during init()
self.model = model(session=self.session, objid=self.objid,
verbose=self.verbose)
elif model._type == coreapi.CORE_TLV_REG_MOBILITY:
self.mobility = model(session=self.session, objid=self.objid,
verbose=self.verbose, values=config)
def setnemid(self, netif, nemid):
''' Record an interface to numerical ID mapping. The Emane controller
object manages and assigns these IDs for all NEMs.
'''
self.nemidmap[netif] = nemid
def getnemid(self, netif):
''' Given an interface, return its numerical ID.
'''
if netif not in self.nemidmap:
return None
else:
return self.nemidmap[netif]
def getnemnetif(self, nemid):
''' Given a numerical NEM ID, return its interface. This returns the
first interface that matches the given NEM ID.
'''
for netif in self.nemidmap:
if self.nemidmap[netif] == nemid:
return netif
return None
def netifs(self, sort=True):
''' Retrieve list of linked interfaces sorted by node number.
'''
return sorted(self._netif.values(), key=lambda ifc: ifc.node.objid)
def buildplatformxmlentry(self, doc):
''' Return a dictionary of XML elements describing the NEMs
connected to this EmaneNode for inclusion in the platform.xml file.
'''
ret = {}
if self.model is None:
self.info("warning: EmaneNode %s has no associated model" % \
self.name)
return ret
for netif in self.netifs():
# <nem name="NODE-001" definition="rfpipenem.xml">
nementry = self.model.buildplatformxmlnementry(doc, self, netif)
# <transport definition="transvirtual.xml" group="1">
# <param name="device" value="n1.0.158" />
# </transport>
trans = self.model.buildplatformxmltransportentry(doc, self, netif)
nementry.appendChild(trans)
ret[netif] = nementry
return ret
def buildnemxmlfiles(self, emane):
''' Let the configured model build the necessary nem, mac, and phy
XMLs.
'''
if self.model is None:
return
# build XML for overall network (EmaneNode) configs
self.model.buildnemxmlfiles(emane, ifc=None)
# build XML for specific interface (NEM) configs
need_virtual = False
need_raw = False
vtype = "virtual"
rtype = "raw"
for netif in self.netifs():
self.model.buildnemxmlfiles(emane, netif)
if "virtual" in netif.transport_type:
need_virtual = True
vtype = netif.transport_type
else:
need_raw = True
rtype = netif.transport_type
# build transport XML files depending on type of interfaces involved
if need_virtual:
self.buildtransportxml(emane, vtype)
if need_raw:
self.buildtransportxml(emane, rtype)
def buildtransportxml(self, emane, type):
''' Write a transport XML file for the Virtual or Raw Transport.
'''
transdoc = emane.xmldoc("transport")
trans = transdoc.getElementsByTagName("transport").pop()
trans.setAttribute("name", "%s Transport" % type.capitalize())
trans.setAttribute("library", "trans%s" % type.lower())
trans.appendChild(emane.xmlparam(transdoc, "bitrate", "0"))
if "virtual" in type.lower():
trans.appendChild(emane.xmlparam(transdoc, "devicepath",
"/dev/net/tun"))
emane.xmlwrite(transdoc, self.transportxmlname(type.lower()))
def transportxmlname(self, type):
''' Return the string name for the Transport XML file,
e.g. 'n3transvirtual.xml'
'''
return "n%strans%s.xml" % (self.objid, type)
def installnetifs(self):
''' Install TAP devices into their namespaces. This is done after
EMANE daemons have been started, because that is their only chance
to bind to the TAPs.
'''
if not self.session.emane.doeventmonitor() and \
self.session.emane.service is None:
warntxt = "unable to publish EMANE events because the eventservice "
warntxt += "Python bindings failed to load"
self.session.exception(coreapi.CORE_EXCP_LEVEL_ERROR, self.name,
self.objid, warntxt)
for netif in self.netifs():
if "virtual" in netif.transport_type.lower():
netif.install()
# if we are listening for EMANE events, don't generate them
if self.session.emane.doeventmonitor():
netif.poshook = None
continue
# at this point we register location handlers for generating
# EMANE location events
netif.poshook = self.setnemposition
(x,y,z) = netif.node.position.get()
self.setnemposition(netif, x, y, z)
def deinstallnetifs(self):
''' Uninstall TAP devices. This invokes their shutdown method for
any required cleanup; the device may be actually removed when
emanetransportd terminates.
'''
for netif in self.netifs():
if "virtual" in netif.transport_type.lower():
netif.shutdown()
netif.poshook = None
def setnemposition(self, netif, x, y, z):
''' Publish a NEM location change event using the EMANE event service.
'''
if self.session.emane.service is None:
if self.verbose:
self.info("position service not available")
return
nemid = self.getnemid(netif)
ifname = netif.localname
if nemid is None:
self.info("nemid for %s is unknown" % ifname)
return
(lat, long, alt) = self.session.location.getgeo(x, y, z)
if self.verbose:
self.info("setnemposition %s (%s) x,y,z=(%d,%d,%s)"
"(%.6f,%.6f,%.6f)" % \
(ifname, nemid, x, y, z, lat, long, alt))
event = emaneeventlocation.EventLocation(1)
# altitude must be an integer or warning is printed
# unused: yaw, pitch, roll, azimuth, elevation, velocity
alt = int(round(alt))
event.set(0, nemid, lat, long, alt)
self.session.emane.service.publish(emaneeventlocation.EVENT_ID,
emaneeventservice.PLATFORMID_ANY,
emaneeventservice.NEMID_ANY,
emaneeventservice.COMPONENTID_ANY,
event.export())
def setnempositions(self, moved_netifs):
''' Several NEMs have moved, from e.g. a WaypointMobilityModel
calculation. Generate an EMANE Location Event having several
entries for each netif that has moved.
'''
if len(moved_netifs) == 0:
return
if self.session.emane.service is None:
if self.verbose:
self.info("position service not available")
return
event = emaneeventlocation.EventLocation(len(moved_netifs))
i = 0
for netif in moved_netifs:
nemid = self.getnemid(netif)
ifname = netif.localname
if nemid is None:
self.info("nemid for %s is unknown" % ifname)
continue
(x, y, z) = netif.node.getposition()
(lat, long, alt) = self.session.location.getgeo(x, y, z)
if self.verbose:
self.info("setnempositions %d %s (%s) x,y,z=(%d,%d,%s)"
"(%.6f,%.6f,%.6f)" % \
(i, ifname, nemid, x, y, z, lat, long, alt))
# altitude must be an integer or warning is printed
alt = int(round(alt))
event.set(i, nemid, lat, long, alt)
i += 1
self.session.emane.service.publish(emaneeventlocation.EVENT_ID,
emaneeventservice.PLATFORMID_ANY,
emaneeventservice.NEMID_ANY,
emaneeventservice.COMPONENTID_ANY,
event.export())

106
daemon/core/emane/rfpipe.py Normal file
View file

@ -0,0 +1,106 @@
#
# CORE
# Copyright (c)2010-2013 the Boeing Company.
# See the LICENSE file included in this distribution.
#
# author: Jeff Ahrenholz <jeffrey.m.ahrenholz@boeing.com>
# author: Harry Bullen <hbullen@i-a-i.com>
#
'''
rfpipe.py: EMANE RF-PIPE model for CORE
'''
import sys
import string
from core.api import coreapi
from core.constants import *
from emane import EmaneModel
from universal import EmaneUniversalModel
class EmaneRfPipeModel(EmaneModel):
def __init__(self, session, objid = None, verbose = False):
EmaneModel.__init__(self, session, objid, verbose)
# model name
_name = "emane_rfpipe"
# configuration parameters are
# ( 'name', 'type', 'default', 'possible-value-list', 'caption')
# MAC parameters
_confmatrix_mac = [
("enablepromiscuousmode", coreapi.CONF_DATA_TYPE_BOOL, '0',
'True,False', 'enable promiscuous mode'),
("datarate", coreapi.CONF_DATA_TYPE_UINT32, '1M',
'', 'data rate (bps)'),
("jitter", coreapi.CONF_DATA_TYPE_FLOAT, '0.0',
'', 'transmission jitter (usec)'),
("delay", coreapi.CONF_DATA_TYPE_FLOAT, '0.0',
'', 'transmission delay (usec)'),
("flowcontrolenable", coreapi.CONF_DATA_TYPE_BOOL, '0',
'On,Off', 'enable traffic flow control'),
("flowcontroltokens", coreapi.CONF_DATA_TYPE_UINT16, '10',
'', 'number of flow control tokens'),
("enabletighttiming", coreapi.CONF_DATA_TYPE_BOOL, '0',
'On,Off', 'enable tight timing for pkt delay'),
("pcrcurveuri", coreapi.CONF_DATA_TYPE_STRING,
'/usr/share/emane/models/rfpipe/xml/rfpipepcr.xml',
'', 'SINR/PCR curve file'),
("transmissioncontrolmap", coreapi.CONF_DATA_TYPE_STRING, '',
'', 'tx control map (nem:rate:freq:tx_dBm)'),
]
# PHY parameters from Universal PHY
_confmatrix_phy = EmaneUniversalModel._confmatrix
_confmatrix = _confmatrix_mac + _confmatrix_phy
# value groupings
_confgroups = "RF-PIPE MAC Parameters:1-%d|Universal PHY Parameters:%d-%d" \
% ( len(_confmatrix_mac), len(_confmatrix_mac) + 1, len(_confmatrix))
def buildnemxmlfiles(self, e, ifc):
''' Build the necessary nem, mac, and phy XMLs in the given path.
If an individual NEM has a nonstandard config, we need to build
that file also. Otherwise the WLAN-wide nXXemane_rfpipenem.xml,
nXXemane_rfpipemac.xml, nXXemane_rfpipephy.xml are used.
'''
values = e.getifcconfig(self.objid, self._name,
self.getdefaultvalues(), ifc)
if values is None:
return
nemdoc = e.xmldoc("nem")
nem = nemdoc.getElementsByTagName("nem").pop()
nem.setAttribute("name", "RF-PIPE NEM")
mactag = nemdoc.createElement("mac")
mactag.setAttribute("definition", self.macxmlname(ifc))
nem.appendChild(mactag)
phytag = nemdoc.createElement("phy")
phytag.setAttribute("definition", self.phyxmlname(ifc))
nem.appendChild(phytag)
e.xmlwrite(nemdoc, self.nemxmlname(ifc))
names = list(self.getnames())
macnames = names[:len(self._confmatrix_mac)]
phynames = names[len(self._confmatrix_mac):]
macdoc = e.xmldoc("mac")
mac = macdoc.getElementsByTagName("mac").pop()
mac.setAttribute("name", "RF-PIPE MAC")
mac.setAttribute("library", "rfpipemaclayer")
if self.valueof("transmissioncontrolmap", values) is "":
macnames.remove("transmissioncontrolmap")
# EMANE 0.7.4 support
if e.emane074:
# convert datarate from bps to kbps
i = names.index('datarate')
values = list(values)
values[i] = self.emane074_fixup(values[i], 1000)
# append MAC options to macdoc
map( lambda n: mac.appendChild(e.xmlparam(macdoc, n, \
self.valueof(n, values))), macnames)
e.xmlwrite(macdoc, self.macxmlname(ifc))
phydoc = EmaneUniversalModel.getphydoc(e, self, values, phynames)
e.xmlwrite(phydoc, self.phyxmlname(ifc))

View file

@ -0,0 +1,113 @@
#
# CORE
# Copyright (c)2010-2013 the Boeing Company.
# See the LICENSE file included in this distribution.
#
# author: Jeff Ahrenholz <jeffrey.m.ahrenholz@boeing.com>
#
'''
universal.py: EMANE Universal PHY model for CORE. Enumerates configuration items
used for the Universal PHY.
'''
import sys
import string
from core.api import coreapi
from core.constants import *
from emane import EmaneModel
class EmaneUniversalModel(EmaneModel):
''' This Univeral PHY model is meant to be imported by other models,
not instantiated.
'''
def __init__(self, session, objid = None, verbose = False):
raise SyntaxError
_name = "emane_universal"
_xmlname = "universalphy"
_xmllibrary = "universalphylayer"
# universal PHY parameters
_confmatrix = [
("antennagain", coreapi.CONF_DATA_TYPE_FLOAT, '0.0',
'','antenna gain (dBi)'),
("antennaazimuth", coreapi.CONF_DATA_TYPE_FLOAT, '0.0',
'','antenna azimuth (deg)'),
("antennaelevation", coreapi.CONF_DATA_TYPE_FLOAT, '0.0',
'','antenna elevation (deg)'),
("antennaprofileid", coreapi.CONF_DATA_TYPE_STRING, '1',
'','antenna profile ID'),
("antennaprofilemanifesturi", coreapi.CONF_DATA_TYPE_STRING, '',
'','antenna profile manifest URI'),
("antennaprofileenable", coreapi.CONF_DATA_TYPE_BOOL, '0',
'On,Off','antenna profile mode'),
("bandwidth", coreapi.CONF_DATA_TYPE_UINT64, '1M',
'', 'rf bandwidth (hz)'),
("defaultconnectivitymode", coreapi.CONF_DATA_TYPE_BOOL, '1',
'On,Off','default connectivity'),
("frequency", coreapi.CONF_DATA_TYPE_UINT64, '2.347G',
'','frequency (Hz)'),
("frequencyofinterest", coreapi.CONF_DATA_TYPE_UINT64, '2.347G',
'','frequency of interest (Hz)'),
("frequencyofinterestfilterenable", coreapi.CONF_DATA_TYPE_BOOL, '1',
'On,Off','frequency of interest filter enable'),
("noiseprocessingmode", coreapi.CONF_DATA_TYPE_BOOL, '0',
'On,Off','enable noise processing'),
("pathlossmode", coreapi.CONF_DATA_TYPE_STRING, '2ray',
'pathloss,2ray,freespace','path loss mode'),
("subid", coreapi.CONF_DATA_TYPE_UINT16, '1',
'','subid'),
("systemnoisefigure", coreapi.CONF_DATA_TYPE_FLOAT, '4.0',
'','system noise figure (dB)'),
("txpower", coreapi.CONF_DATA_TYPE_FLOAT, '0.0',
'','transmit power (dBm)'),
]
# old parameters
_confmatrix_ver074 = [
("antennaazimuthbeamwidth", coreapi.CONF_DATA_TYPE_FLOAT, '360.0',
'','azimith beam width (deg)'),
("antennaelevationbeamwidth", coreapi.CONF_DATA_TYPE_FLOAT, '180.0',
'','elevation beam width (deg)'),
("antennatype", coreapi.CONF_DATA_TYPE_STRING, 'omnidirectional',
'omnidirectional,unidirectional','antenna type'),
]
# parameters that require unit conversion for 0.7.4
_update_ver074 = ("bandwidth", "frequency", "frequencyofinterest")
# parameters that should be removed for 0.7.4
_remove_ver074 = ("antennaprofileenable", "antennaprofileid",
"antennaprofilemanifesturi",
"frequencyofinterestfilterenable")
@classmethod
def getphydoc(cls, e, mac, values, phynames):
phydoc = e.xmldoc("phy")
phy = phydoc.getElementsByTagName("phy").pop()
phy.setAttribute("name", cls._xmlname)
phy.setAttribute("library", cls._xmllibrary)
# EMANE 0.7.4 suppport - to be removed when 0.7.4 support is deprecated
if e.emane074:
names = mac.getnames()
values = list(values)
phynames = list(phynames)
# update units for some parameters
for p in cls._update_ver074:
i = names.index(p)
# these all happen to be KHz, so 1000 is used
values[i] = cls.emane074_fixup(values[i], 1000)
# remove new incompatible options
for p in cls._remove_ver074:
phynames.remove(p)
# insert old options with their default values
for old in cls._confmatrix_ver074:
phy.appendChild(e.xmlparam(phydoc, old[0], old[2]))
# append all PHY options to phydoc
map( lambda n: phy.appendChild(e.xmlparam(phydoc, n, \
mac.valueof(n, values))), phynames)
return phydoc