support for EMANE 0.9.2 by running emane process in each container

use control network for data and events
use internal transport instead of emanetransportd for 0.9.2
(Boeing r1881)
This commit is contained in:
ahrenholz 2014-09-23 16:26:22 +00:00
parent 24263d77bd
commit e825b94e13
8 changed files with 296 additions and 122 deletions

View file

@ -42,6 +42,7 @@ class EmaneBypassModel(EmaneModel):
nemdoc = e.xmldoc("nem") nemdoc = e.xmldoc("nem")
nem = nemdoc.getElementsByTagName("nem").pop() nem = nemdoc.getElementsByTagName("nem").pop()
nem.setAttribute("name", "BYPASS NEM") nem.setAttribute("name", "BYPASS NEM")
e.appendtransporttonem(nemdoc, nem, self.objid)
mactag = nemdoc.createElement("mac") mactag = nemdoc.createElement("mac")
mactag.setAttribute("definition", self.macxmlname(ifc)) mactag.setAttribute("definition", self.macxmlname(ifc))
nem.appendChild(mactag) nem.appendChild(mactag)

View file

@ -95,6 +95,7 @@ class EmaneCommEffectModel(EmaneModel):
nem = nemdoc.getElementsByTagName("nem").pop() nem = nemdoc.getElementsByTagName("nem").pop()
nem.setAttribute("name", "commeffect NEM") nem.setAttribute("name", "commeffect NEM")
nem.setAttribute("type", "unstructured") nem.setAttribute("type", "unstructured")
e.appendtransporttonem(nemdoc, nem, self.objid)
nem.appendChild(e.xmlshimdefinition(nemdoc, self.shimxmlname(ifc))) nem.appendChild(e.xmlshimdefinition(nemdoc, self.shimxmlname(ifc)))
e.xmlwrite(nemdoc, self.nemxmlname(ifc)) e.xmlwrite(nemdoc, self.nemxmlname(ifc))

View file

@ -32,6 +32,14 @@ try:
from emanesh.events import LocationEvent from emanesh.events import LocationEvent
except Exception, e: except Exception, e:
pass pass
# EMANE 0.9.2
try:
from emanesh import remotecontrolportapi_pb2
HAVE092 = ('TYPE_COMPONENT_TRANSPORT' in
dir(remotecontrolportapi_pb2.Response.Query.Manifest.NEM.Component))
del remotecontrolportapi_pb2
except Exception, e:
HAVE092 = False
class Emane(ConfigurableManager): class Emane(ConfigurableManager):
@ -67,7 +75,7 @@ class Emane(ConfigurableManager):
self.emane_config = EmaneGlobalModel(session, None, self.verbose) self.emane_config = EmaneGlobalModel(session, None, self.verbose)
session.broker.handlers += (self.handledistributed, ) session.broker.handlers += (self.handledistributed, )
self.loadmodels() self.loadmodels()
self.initeventservice() self.service = None
def detectversion(self): def detectversion(self):
''' Detects the installed EMANE version and sets self.version. ''' Detects the installed EMANE version and sets self.version.
@ -81,6 +89,7 @@ class Emane(ConfigurableManager):
''' '''
# for further study: different EMANE versions on distributed machines # for further study: different EMANE versions on distributed machines
try: try:
# TODO: fix BUG here -- killall may kill this process too
status, result = cmdresult(['emane', '--version']) status, result = cmdresult(['emane', '--version'])
except OSError: except OSError:
status = -1 status = -1
@ -111,17 +120,16 @@ class Emane(ConfigurableManager):
self.emane_config.getdefaultvalues())[1] self.emane_config.getdefaultvalues())[1]
group, port = self.emane_config.valueof('eventservicegroup', group, port = self.emane_config.valueof('eventservicegroup',
values).split(':') values).split(':')
if self.version > self.EMANE091 and \
'ctrlnet' in self.session._objs:
# direct EMANE events towards control net bridge
dev = self.session.obj('ctrlnet').brname
else:
dev = self.emane_config.valueof('eventservicedevice', values) dev = self.emane_config.valueof('eventservicedevice', values)
otachannel = None # disabled otachannel for event service
ota_enable = self.emane_config.valueof('otamanagerchannelenable', # only needed for e.g. antennaprofile events xmit by models
values)
if self.emane_config.offontobool(ota_enable):
ogroup, oport = self.emane_config.valueof('otamanagergroup',
values).split(':')
odev = self.emane_config.valueof('otamanagerdevice', values)
otachannel = (ogroup, int(oport), odev)
self.service = EventService(eventchannel=(group, int(port), dev), self.service = EventService(eventchannel=(group, int(port), dev),
otachannel=otachannel) otachannel=None)
return True return True
if filename is not None: if filename is not None:
tmp = os.getenv(self.EVENTCFGVAR) tmp = os.getenv(self.EVENTCFGVAR)
@ -181,6 +189,17 @@ class Emane(ConfigurableManager):
self._objs[obj.objid] = obj self._objs[obj.objid] = obj
self._objslock.release() self._objslock.release()
def getnodes(self):
''' Return a set of CoreNodes that are linked to an EmaneNode,
e.g. containers having one or more radio interfaces.
'''
# assumes self._objslock already held
r = set()
for e in self._objs.values():
for netif in e.netifs():
r.add(netif.node)
return r
def getmodels(self, n): def getmodels(self, n):
''' Used with XML export; see ConfigurableManager.getmodels() ''' Used with XML export; see ConfigurableManager.getmodels()
''' '''
@ -238,13 +257,24 @@ class Emane(ConfigurableManager):
r = self.setup() r = self.setup()
if r != Emane.SUCCESS: if r != Emane.SUCCESS:
return r # NOT_NEEDED or NOT_READY return r # NOT_NEEDED or NOT_READY
if self.versionstr == "":
raise ValueError, "EMANE version not properly detected"
with self._objslock: with self._objslock:
if self.version < self.EMANE092:
self.buildxml() self.buildxml()
self.initeventservice()
self.starteventmonitor() self.starteventmonitor()
if self.numnems() > 0: if self.numnems() > 0:
# TODO: check and return failure for these methods # TODO: check and return failure for these methods
self.startdaemons() self.startdaemons()
self.installnetifs() self.installnetifs()
else:
self.buildxml2()
self.initeventservice()
self.starteventmonitor()
if self.numnems() > 0:
self.startdaemons2()
self.installnetifs(do_netns=False)
return Emane.SUCCESS return Emane.SUCCESS
def poststartup(self): def poststartup(self):
@ -369,7 +399,9 @@ class Emane(ConfigurableManager):
return False return False
def buildxml(self): def buildxml(self):
''' Build all of the XML files required to run EMANE. ''' Build all of the XML files required to run EMANE on the host.
NEMs run in a single host emane process, with TAP devices pushed
into namespaces.
''' '''
# assume self._objslock is already held here # assume self._objslock is already held here
if self.verbose: if self.verbose:
@ -379,6 +411,20 @@ class Emane(ConfigurableManager):
self.buildtransportxml() self.buildtransportxml()
self.buildeventservicexml() self.buildeventservicexml()
def buildxml2(self):
''' Build XML files required to run EMANE on each node.
NEMs run inside containers using the control network for passing
events and data.
'''
# control network bridge needs to exist when eventservice binds to it
self.session.addremovectrlif(node=None, remove=False, conf_reqd=False)
# assume self._objslock is already held here
if self.verbose:
self.info("Emane.buildxml2()")
self.buildplatformxml2()
self.buildnemxml()
self.buildeventservicexml()
def xmldoc(self, doctype): def xmldoc(self, doctype):
''' Returns an XML xml.minidom.Document with a DOCTYPE tag set to the ''' Returns an XML xml.minidom.Document with a DOCTYPE tag set to the
provided doctype string, and an initial element having the same provided doctype string, and an initial element having the same
@ -473,8 +519,8 @@ class Emane(ConfigurableManager):
self.emane_config.getdefaultvalues())[1] self.emane_config.getdefaultvalues())[1]
doc = self.xmldoc("platform") doc = self.xmldoc("platform")
plat = doc.getElementsByTagName("platform").pop() plat = doc.getElementsByTagName("platform").pop()
platformid = self.emane_config.valueof("platform_id_start", values)
if self.version < self.EMANE091: if self.version < self.EMANE091:
platformid = self.emane_config.valueof("platform_id_start", values)
plat.setAttribute("name", "Platform %s" % platformid) plat.setAttribute("name", "Platform %s" % platformid)
plat.setAttribute("id", platformid) plat.setAttribute("id", platformid)
@ -521,6 +567,47 @@ class Emane(ConfigurableManager):
self.transformport += 1 self.transformport += 1
self.xmlwrite(doc, "platform.xml") self.xmlwrite(doc, "platform.xml")
def newplatformxmldoc(self, values):
doc = self.xmldoc("platform")
plat = doc.getElementsByTagName("platform").pop()
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)
return doc
def buildplatformxml2(self):
''' Build a platform.xml file now that all nodes are configured.
'''
values = self.getconfig(None, "emane",
self.emane_config.getdefaultvalues())[1]
nemid = int(self.emane_config.valueof("nem_id_start", values))
platformxmls = {}
# assume self._objslock is already held here
for n in sorted(self._objs.keys()):
emanenode = self._objs[n]
nems = emanenode.buildplatformxmlentry(self.xmldoc("platform"))
for netif in sorted(nems, key=lambda n: n.node.objid):
# set ID, endpoints here
nementry = nems[netif]
nementry.setAttribute("id", "%d" % nemid)
nodenum = netif.node.objid
if nodenum not in platformxmls:
platformxmls[nodenum] = self.newplatformxmldoc(values)
doc = platformxmls[nodenum]
plat = doc.getElementsByTagName("platform").pop()
plat.appendChild(nementry)
emanenode.setnemid(netif, nemid)
macstr = self._hwaddr_prefix + ":00:00:"
macstr += "%02X:%02X" % ((nemid >> 8) & 0xFF, nemid & 0xFF)
netif.sethwaddr(MacAddr.fromstring(macstr))
nemid += 1
for nodenum in sorted(platformxmls.keys()):
self.xmlwrite(platformxmls[nodenum], "platform%d.xml" % nodenum)
def buildnemxml(self): def buildnemxml(self):
''' Builds the xxxnem.xml, xxxmac.xml, and xxxphy.xml files which ''' Builds the xxxnem.xml, xxxmac.xml, and xxxphy.xml files which
are defined on a per-EmaneNode basis. are defined on a per-EmaneNode basis.
@ -529,6 +616,19 @@ class Emane(ConfigurableManager):
emanenode = self._objs[n] emanenode = self._objs[n]
nems = emanenode.buildnemxmlfiles(self) nems = emanenode.buildnemxmlfiles(self)
def appendtransporttonem(self, doc, nem, nodenum):
''' Given a nem XML node and EMANE WLAN node number, append
a <transport/> tag to the NEM definition, required for using
EMANE's internal transport.
'''
if self.version < self.EMANE092:
return
emanenode = self._objs[nodenum]
transtag = doc.createElement("transport")
transtag.setAttribute("definition",
emanenode.transportxmlname("virtual"))
nem.appendChild(transtag)
def buildtransportxml(self): def buildtransportxml(self):
''' Calls emanegentransportxml using a platform.xml file to build ''' Calls emanegentransportxml using a platform.xml file to build
the transportdaemon*.xml. the transportdaemon*.xml.
@ -624,15 +724,70 @@ class Emane(ConfigurableManager):
None, errmsg) None, errmsg)
self.info(errmsg) self.info(errmsg)
def startdaemons2(self):
''' Start one EMANE daemon per node having a radio.
Add a control network even if the user has not configured one.
'''
if self.verbose:
self.info("Emane.startdaemons()")
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]
if realtime:
emanecmd += "-r",
values = self.getconfig(None, "emane",
self.emane_config.getdefaultvalues())[1]
otagroup, otaport = self.emane_config.valueof('otamanagergroup',
values).split(':')
otadev = self.emane_config.valueof('otamanagerdevice', values)
for node in self.getnodes():
path = self.session.sessiondir
n = node.objid
# control network not yet started here
self.session.addremovectrlif(node, remove=False, conf_reqd=False)
# multicast route is needed for OTA data on ctrl0
cmd = [IP_BIN, "route", "add", otagroup, "dev", otadev]
#rc = node.cmd(cmd, wait=True)
node.cmd(cmd, wait=True)
try:
cmd = emanecmd + ["-f", os.path.join(path, "emane%d.log" % n),
os.path.join(path, "platform%d.xml" % n)]
if self.verbose:
self.info("Emane.startdaemons() running %s" % str(cmd))
#node.cmd(cmd, cwd=path, wait=True)
#status, result = node.cmdresult(cmd, cwd=path, wait=True)
status = node.cmd(cmd, wait=True)
if self.verbose:
self.info("Emane.startdaemons2() return code %d" % status)
except Exception, e:
errmsg = "error starting emane: %s" % e
self.session.exception(coreapi.CORE_EXCP_LEVEL_FATAL, "emane",
n, errmsg)
self.info(errmsg)
def stopdaemons(self): def stopdaemons(self):
''' Kill the appropriate EMANE daemons. ''' Kill the appropriate EMANE daemons.
''' '''
# TODO: we may want to improve this if we had the PIDs from the # TODO: we may want to improve this if we had the PIDs from the
# specific EMANE daemons that we've started # specific EMANE daemons that we've started
subprocess.call(["killall", "-q", "emane"]) cmd = ["killall", "-q", "emane"]
if self.version > self.EMANE091:
for node in self.getnodes():
if node.up:
node.cmd(cmd, wait=False)
# TODO: RJ45 node
else:
subprocess.call(cmd)
subprocess.call(["killall", "-q", "emanetransportd"]) subprocess.call(["killall", "-q", "emanetransportd"])
def installnetifs(self): def installnetifs(self, do_netns=True):
''' Install TUN/TAP virtual interfaces into their proper namespaces ''' Install TUN/TAP virtual interfaces into their proper namespaces
now that the EMANE daemons are running. now that the EMANE daemons are running.
''' '''
@ -640,7 +795,7 @@ class Emane(ConfigurableManager):
emanenode = self._objs[n] emanenode = self._objs[n]
if self.verbose: if self.verbose:
self.info("Emane.installnetifs() for node %d" % n) self.info("Emane.installnetifs() for node %d" % n)
emanenode.installnetifs() emanenode.installnetifs(do_netns)
def deinstallnetifs(self): def deinstallnetifs(self):
''' Uninstall TUN/TAP virtual interfaces. ''' Uninstall TUN/TAP virtual interfaces.
@ -893,6 +1048,7 @@ class EmaneModel(WirelessModel):
type = "raw" type = "raw"
trans = doc.createElement("transport") trans = doc.createElement("transport")
trans.setAttribute("definition", n.transportxmlname(type)) trans.setAttribute("definition", n.transportxmlname(type))
if self.session.emane.version < self.session.emane.EMANE092:
trans.setAttribute("group", "1") trans.setAttribute("group", "1")
param = doc.createElement("param") param = doc.createElement("param")
param.setAttribute("name", "device") param.setAttribute("name", "device")
@ -902,6 +1058,9 @@ class EmaneModel(WirelessModel):
else: else:
# virtual TAP name e.g. 'n3.0.17' # virtual TAP name e.g. 'n3.0.17'
param.setAttribute("value", ifc.localname) param.setAttribute("value", ifc.localname)
if self.session.emane.version > self.session.emane.EMANE091:
param.setAttribute("value", ifc.name)
trans.appendChild(param) trans.appendChild(param)
return trans return trans
@ -967,6 +1126,8 @@ class EmaneModel(WirelessModel):
values = maketuplefromstr(value, str) values = maketuplefromstr(value, str)
except SyntaxError: except SyntaxError:
return None return None
if not hasattr(values, '__iter__'):
return None
if len(values) < 2: if len(values) < 2:
return None return None
return addparamlisttoparent(dom, parent=None, name=name, values=values) return addparamlisttoparent(dom, parent=None, name=name, values=values)
@ -978,17 +1139,24 @@ class EmaneGlobalModel(EmaneModel):
def __init__(self, session, objid = None, verbose = False): def __init__(self, session, objid = None, verbose = False):
EmaneModel.__init__(self, session, objid, verbose) EmaneModel.__init__(self, session, objid, verbose)
# Over-The-Air channel required for EMANE 0.9.2
_DEFAULT_OTA = '0'
_DEFAULT_DEV = 'lo'
if HAVE092:
_DEFAULT_OTA = '1'
_DEFAULT_DEV = 'ctrl0'
_name = "emane" _name = "emane"
_confmatrix_platform_base = [ _confmatrix_platform_base = [
("otamanagerchannelenable", coreapi.CONF_DATA_TYPE_BOOL, '0', ("otamanagerchannelenable", coreapi.CONF_DATA_TYPE_BOOL, _DEFAULT_OTA,
'on,off', 'enable OTA Manager channel'), 'on,off', 'enable OTA Manager channel'),
("otamanagergroup", coreapi.CONF_DATA_TYPE_STRING, '224.1.2.8:45702', ("otamanagergroup", coreapi.CONF_DATA_TYPE_STRING, '224.1.2.8:45702',
'', 'OTA Manager group'), '', 'OTA Manager group'),
("otamanagerdevice", coreapi.CONF_DATA_TYPE_STRING, 'lo', ("otamanagerdevice", coreapi.CONF_DATA_TYPE_STRING, _DEFAULT_DEV,
'', 'OTA Manager device'), '', 'OTA Manager device'),
("eventservicegroup", coreapi.CONF_DATA_TYPE_STRING, '224.1.2.8:45703', ("eventservicegroup", coreapi.CONF_DATA_TYPE_STRING, '224.1.2.8:45703',
'', 'Event Service group'), '', 'Event Service group'),
("eventservicedevice", coreapi.CONF_DATA_TYPE_STRING, 'lo', ("eventservicedevice", coreapi.CONF_DATA_TYPE_STRING, _DEFAULT_DEV,
'', 'Event Service device'), '', 'Event Service device'),
("platform_id_start", coreapi.CONF_DATA_TYPE_INT32, '1', ("platform_id_start", coreapi.CONF_DATA_TYPE_INT32, '1',
'', 'starting Platform ID'), '', 'starting Platform ID'),
@ -1013,9 +1181,16 @@ class EmaneGlobalModel(EmaneModel):
("nem_id_start", coreapi.CONF_DATA_TYPE_INT32, '1', ("nem_id_start", coreapi.CONF_DATA_TYPE_INT32, '1',
'', 'starting NEM ID'), '', 'starting NEM ID'),
] ]
_confmatrix_nem_092 = [
("nem_id_start", coreapi.CONF_DATA_TYPE_INT32, '1',
'', 'starting NEM ID'),
]
if 'EventService' in globals(): if 'EventService' in globals():
_confmatrix_platform = _confmatrix_platform_base + \ _confmatrix_platform = _confmatrix_platform_base + \
_confmatrix_platform_091 _confmatrix_platform_091
if HAVE092:
_confmatrix_nem = _confmatrix_nem_092
else: else:
_confmatrix_platform = _confmatrix_platform_base + \ _confmatrix_platform = _confmatrix_platform_base + \
_confmatrix_platform_081 _confmatrix_platform_081
@ -1023,4 +1198,3 @@ class EmaneGlobalModel(EmaneModel):
_confgroups = "Platform Attributes:1-%d|NEM Parameters:%d-%d" % \ _confgroups = "Platform Attributes:1-%d|NEM Parameters:%d-%d" % \
(len(_confmatrix_platform), len(_confmatrix_platform) + 1, (len(_confmatrix_platform), len(_confmatrix_platform) + 1,
len(_confmatrix)) len(_confmatrix))

View file

@ -93,20 +93,14 @@ class EmaneIeee80211abgModel(EmaneModel):
nXXemane_ieee80211abgnem.xml, nXXemane_ieee80211abgemac.xml, nXXemane_ieee80211abgnem.xml, nXXemane_ieee80211abgemac.xml,
nXXemane_ieee80211abgphy.xml are used. nXXemane_ieee80211abgphy.xml are used.
''' '''
# use the network-wide config values or interface(NEM)-specific values? values = e.getifcconfig(self.objid, self._name,
if ifc is None: self.getdefaultvalues(), ifc)
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: if values is None:
# do not build specific files for this NEM when config is same
# as the network
return return
nemdoc = e.xmldoc("nem") nemdoc = e.xmldoc("nem")
nem = nemdoc.getElementsByTagName("nem").pop() nem = nemdoc.getElementsByTagName("nem").pop()
nem.setAttribute("name", "ieee80211abg NEM") nem.setAttribute("name", "ieee80211abg NEM")
e.appendtransporttonem(nemdoc, nem, self.objid)
mactag = nemdoc.createElement("mac") mactag = nemdoc.createElement("mac")
mactag.setAttribute("definition", self.macxmlname(ifc)) mactag.setAttribute("definition", self.macxmlname(ifc))
nem.appendChild(mactag) nem.appendChild(mactag)

View file

@ -197,7 +197,7 @@ class EmaneNode(EmaneNet):
return "n%strans%s.xml" % (self.objid, type) return "n%strans%s.xml" % (self.objid, type)
def installnetifs(self): def installnetifs(self, do_netns=True):
''' Install TAP devices into their namespaces. This is done after ''' Install TAP devices into their namespaces. This is done after
EMANE daemons have been started, because that is their only chance EMANE daemons have been started, because that is their only chance
to bind to the TAPs. to bind to the TAPs.
@ -210,7 +210,7 @@ class EmaneNode(EmaneNet):
self.objid, warntxt) self.objid, warntxt)
for netif in self.netifs(): for netif in self.netifs():
if "virtual" in netif.transport_type.lower(): if do_netns and "virtual" in netif.transport_type.lower():
netif.install() netif.install()
# if we are listening for EMANE events, don't generate them # if we are listening for EMANE events, don't generate them
if self.session.emane.doeventmonitor(): if self.session.emane.doeventmonitor():

View file

@ -86,6 +86,7 @@ class EmaneRfPipeModel(EmaneModel):
nemdoc = e.xmldoc("nem") nemdoc = e.xmldoc("nem")
nem = nemdoc.getElementsByTagName("nem").pop() nem = nemdoc.getElementsByTagName("nem").pop()
nem.setAttribute("name", "RF-PIPE NEM") nem.setAttribute("name", "RF-PIPE NEM")
e.appendtransporttonem(nemdoc, nem, self.objid)
mactag = nemdoc.createElement("mac") mactag = nemdoc.createElement("mac")
mactag.setAttribute("definition", self.macxmlname(ifc)) mactag.setAttribute("definition", self.macxmlname(ifc))
nem.appendChild(mactag) nem.appendChild(mactag)

View file

@ -20,6 +20,7 @@ from core.coreobj import PyCoreNode
class CtrlNet(LxBrNet): class CtrlNet(LxBrNet):
policy = "ACCEPT" policy = "ACCEPT"
CTRLIF_IDX_BASE = 99 # base control interface index CTRLIF_IDX_BASE = 99 # base control interface index
DEFAULT_PREFIX = "172.16.0.0/24"
def __init__(self, session, objid = "ctrlnet", name = None, def __init__(self, session, objid = "ctrlnet", name = None,
verbose = False, netid = 1, prefix = None, verbose = False, netid = 1, prefix = None,

View file

@ -736,21 +736,19 @@ class Session(object):
continue continue
n.validate() n.validate()
def addremovectrlnet(self, remove=False): def addremovectrlnet(self, remove=False, conf_reqd=True):
''' Create a control network bridge as necessary. ''' Create a control network bridge as necessary.
When the remove flag is True, remove the bridge that connects control When the remove flag is True, remove the bridge that connects control
interfaces. interfaces.
''' '''
prefix = None prefix = self.cfg.get('controlnet')
try:
if self.cfg['controlnet']:
prefix = self.cfg['controlnet']
except KeyError:
pass
if hasattr(self.options, 'controlnet'): if hasattr(self.options, 'controlnet'):
prefix = self.options.controlnet prefix = self.options.controlnet
if not prefix: if not prefix:
if conf_reqd:
return None # no controlnet needed return None # no controlnet needed
else:
prefix = nodes.CtrlNet.DEFAULT_PREFIX
# return any existing controlnet bridge # return any existing controlnet bridge
id = "ctrlnet" id = "ctrlnet"
@ -814,16 +812,20 @@ class Session(object):
self.broker.addnodemap(server, id) self.broker.addnodemap(server, id)
return ctrlnet return ctrlnet
def addremovectrlif(self, node, remove=False): def addremovectrlif(self, node, remove=False, conf_reqd=True):
''' Add a control interface to a node when a 'controlnet' prefix is ''' Add a control interface to a node when a 'controlnet' prefix is
listed in the config file or session options. Uses listed in the config file or session options. Uses
addremovectrlnet() to build or remove the control bridge. addremovectrlnet() to build or remove the control bridge.
If conf_reqd is False, the control network may be built even
when the user has not configured one (e.g. for EMANE.)
''' '''
ctrlnet = self.addremovectrlnet(remove) ctrlnet = self.addremovectrlnet(remove, conf_reqd)
if ctrlnet is None: if ctrlnet is None:
return return
if node is None: if node is None:
return return
if node.netif(ctrlnet.CTRLIF_IDX_BASE):
return # ctrl0 already exists
ctrlip = node.objid ctrlip = node.objid
try: try:
addrlist = ["%s/%s" % (ctrlnet.prefix.addr(ctrlip), addrlist = ["%s/%s" % (ctrlnet.prefix.addr(ctrlip),