emane xml fully generated from lxml apis, removed xml functions embedded within emane nodes, emane manager, and emane models. Started consolidating emanexml logic into its own module, when it makes sense

This commit is contained in:
Blake J. Harnden 2018-07-03 18:49:36 -07:00
parent ae94c78fbb
commit f115b1a847
8 changed files with 249 additions and 424 deletions

View file

@ -1284,7 +1284,7 @@ class CoreHandler(SocketServer.BaseRequestHandler):
if values_str:
config = ConfigShim.str_to_dict(values_str)
self.session.emane.set_configs(config, node_id=node_id)
self.session.emane.set_configs(config)
# extra logic to start slave Emane object after nemid has been configured from the master
if message_type == ConfigFlags.UPDATE and self.session.master is False:

View file

@ -2,10 +2,13 @@
commeffect.py: EMANE CommEffect model for CORE
"""
from lxml import etree
from core import logger
from core.conf import ConfigGroup
from core.emane import emanemanifest
from core.emane import emanemodel
from core.xml import emanexml
try:
from emane.events.commeffectevent import CommEffectEvent
@ -36,6 +39,9 @@ class EmaneCommEffectModel(emanemodel.EmaneModel):
shim_defaults = {}
config_shim = emanemanifest.parse(shim_xml, shim_defaults)
# comm effect does not need the default phy configuration
phy_config = ()
@classmethod
def configurations(cls):
return cls.config_shim
@ -46,39 +52,36 @@ class EmaneCommEffectModel(emanemodel.EmaneModel):
ConfigGroup("CommEffect SHIM Parameters", 1, len(cls.configurations()))
]
def build_xml_files(self, emane_manager, interface):
def build_xml_files(self, config, interface=None):
"""
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.
:param core.emane.emanemanager.EmaneManager emane_manager: core emane manager
:param dict config: emane model configuration for the node and interface
:param interface: interface for the emane node
:return: nothing
"""
config = emane_manager.getifcconfig(self.object_id, interface, self.name)
if not config:
return
# retrieve xml names
nem_name = self.nem_name(interface)
shim_name = self.shim_name(interface)
nem_document = emane_manager.xmldoc("nem")
nem_element = nem_document.getElementsByTagName("nem").pop()
nem_element.setAttribute("name", "%s NEM" % self.name)
nem_element.setAttribute("type", "unstructured")
emane_manager.appendtransporttonem(nem_document, nem_element, self.object_id, interface)
# create and write nem document
nem_element = etree.Element("nem", name="%s NEM" % self.name, type="unstructured")
transport_type = "virtual"
if interface and interface.transport_type == "raw":
transport_type = "raw"
transport_name = "n%strans%s.xml" % (self.object_id, transport_type)
etree.SubElement(nem_element, "transport", definition=transport_name)
shim_xml = emane_manager.xmlshimdefinition(nem_document, shim_name)
nem_element.appendChild(shim_xml)
emane_manager.xmlwrite(nem_document, nem_name)
# set shim configuration
etree.SubElement(nem_element, "shim", definition=shim_name)
shim_document = emane_manager.xmldoc("shim")
shim_element = shim_document.getElementsByTagName("shim").pop()
shim_element.setAttribute("name", "%s SHIM" % self.name)
shim_element.setAttribute("library", self.shim_library)
self.create_file(nem_element, nem_name, "nem")
# create and write shim document
shim_element = etree.Element("shim", name="%s SHIM" % self.name, library=self.shim_library)
# append all shim options (except filterfile) to shimdoc
for configuration in self.config_shim:
@ -86,14 +89,14 @@ class EmaneCommEffectModel(emanemodel.EmaneModel):
if name == "filterfile":
continue
value = config[name]
param = emane_manager.xmlparam(shim_document, name, value)
shim_element.appendChild(param)
emanexml.add_param(shim_element, name, value)
# empty filterfile is not allowed
ff = config["filterfile"]
if ff.strip() != "":
shim_element.appendChild(emane_manager.xmlparam(shim_document, "filterfile", ff))
emane_manager.xmlwrite(shim_document, shim_name)
emanexml.add_param(shim_element, "filterfile", ff)
self.create_file(shim_element, shim_name, "shim")
def linkconfig(self, netif, bw=None, delay=None, loss=None, duplicate=None, jitter=None, netif2=None):
"""

View file

@ -4,8 +4,8 @@ emane.py: definition of an Emane class for implementing configuration control of
import os
import threading
from lxml import etree
from xml.dom.minidom import parseString
from core import CoreCommandError
from core import constants
@ -33,7 +33,7 @@ from core.enumerations import RegisterTlvs
from core.misc import nodeutils
from core.misc import utils
from core.misc.ipaddress import MacAddress
from core.xml import xmlutils
from core.xml import emanexml
try:
from emane.events import EventService
@ -56,10 +56,9 @@ EMANE_MODELS = [
]
def build_node_platform_xml(node):
platform_element = etree.Element("platform")
def build_node_platform_xml(emane_manager, control_net, node, nem_id):
nem_entries = {}
platform_xmls = {}
if node.model is None:
logger.info("warning: EmaneNode %s has no associated model", node.name)
@ -67,26 +66,147 @@ def build_node_platform_xml(node):
for netif in node.netifs():
# build nem xml
# nementry = node.model.build_nem_xml(doc, node, netif)
nem_name = node.model.nem_name(netif)
nem_element = etree.Element("nem", name=netif.localname, definition=nem_name)
nem_element = etree.Element("nem", id=str(nem_id), name=netif.localname, definition=nem_name)
# build transport xml
# trans = node.model.build_transport_xml(doc, node, netif)
transport_type = netif.transport_type
if not transport_type:
logger.info("warning: %s interface type unsupported!", netif.name)
transport_type = "raw"
transport_name = node.transportxmlname(transport_type)
transport_name = "n%strans%s.xml" % (node.objid, transport_type.lower())
transport_element = etree.SubElement(nem_element, "transport", definition=transport_name)
# add transport parameter
etree.SubElement(transport_element, "param", name="device", value=netif.name)
emanexml.add_param(transport_element, "device", netif.name)
# add nem entry
nem_entries[netif] = nem_element
return nem_entries
# merging code
key = netif.node.objid
if netif.transport_type == "raw":
key = "host"
otadev = control_net.brname
eventdev = control_net.brname
else:
otadev = None
eventdev = None
platform_element = platform_xmls.get(key)
if not platform_element:
platform_element = etree.Element("platform")
if otadev:
emane_manager.set_config("otamanagerdevice", otadev)
if eventdev:
emane_manager.set_config("eventservicedevice", eventdev)
# append all platform options (except starting id) to doc
for configuration in emane_manager.emane_config.emulator_config:
name = configuration.id
if name == "platform_id_start":
continue
value = emane_manager.get_config(name)
emanexml.add_param(platform_element, name, value)
# add platform xml
platform_xmls[key] = platform_element
platform_element.append(nem_element)
node.setnemid(netif, nem_id)
macstr = emane_manager._hwaddr_prefix + ":00:00:"
macstr += "%02X:%02X" % ((nem_id >> 8) & 0xFF, nem_id & 0xFF)
netif.sethwaddr(MacAddress.from_string(macstr))
# increment nem id
nem_id += 1
for key in sorted(platform_xmls.keys()):
if key == "host":
file_name = "platform.xml"
else:
file_name = "platform%d.xml" % key
platform_element = platform_xmls[key]
doc_name = "platform"
file_path = os.path.join(emane_manager.session.session_dir, file_name)
emanexml.create_file(platform_element, doc_name, file_path)
return nem_id
def build_transport_xml(emane_manager, node, transport_type):
transport_element = etree.Element(
"transport",
name="%s Transport" % transport_type.capitalize(),
library="trans%s" % transport_type.lower()
)
# add bitrate
emanexml.add_param(transport_element, "bitrate", "0")
# get emane model cnfiguration
config = emane_manager.get_configs(node_id=node.objid, config_type=node.model.name)
flowcontrol = config.get("flowcontrolenable", "0") == "1"
if "virtual" in transport_type.lower():
device_path = "/dev/net/tun_flowctl"
if not os.path.exists(device_path):
device_path = "/dev/net/tun"
emanexml.add_param(transport_element, "devicepath", device_path)
if flowcontrol:
emanexml.add_param(transport_element, "flowcontrolenable", "on")
doc_name = "transport"
file_name = "n%strans%s.xml" % (node.objid, transport_type.lower())
file_path = os.path.join(emane_manager.session.session_dir, file_name)
emanexml.create_file(transport_element, doc_name, file_path)
def build_xml_files(emane_manager, node):
if node.model is None:
return
# get model configurations
config = emane_manager.getifcconfig(node.model.object_id, None, node.model.name)
if not config:
return
# build XML for overall network (EmaneNode) configs
node.model.build_xml_files(config)
# build XML for specific interface (NEM) configs
need_virtual = False
need_raw = False
vtype = "virtual"
rtype = "raw"
for netif in node.netifs():
# check for interface specific emane configuration and write xml files, if needed
config = emane_manager.getifcconfig(node.model.object_id, netif, node.model.name)
if config:
node.model.build_xml_files(config, netif)
# check transport type needed for interface
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:
build_transport_xml(emane_manager, node, vtype)
if need_raw:
build_transport_xml(emane_manager, node, rtype)
class EmaneManager(ModelManager):
@ -541,46 +661,6 @@ class EmaneManager(ModelManager):
msg = coreapi.CoreConfMessage(flags=0, hdr=msghdr, data=rawmsg[coreapi.CoreMessage.header_len:])
self.session.broker.handle_message(msg)
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.
"""
pathname = os.path.join(self.session.session_dir, filename)
with open(pathname, "w") as xml_file:
doc.writexml(writer=xml_file, indent="", addindent=" ", newl="\n", encoding="UTF-8")
def check_node_models(self):
"""
Associate EmaneModel classes with EmaneNode nodes. The model
@ -633,74 +713,16 @@ class EmaneManager(ModelManager):
count += len(emane_node.netifs())
return count
def newplatformxmldoc(self, otadev=None, eventdev=None):
"""
Start a new platform XML file. Use global EMANE config values
as keys. Override OTA manager and event service devices if
specified (in order to support Raw Transport).
"""
doc = self.xmldoc("platform")
plat = doc.getElementsByTagName("platform").pop()
if otadev:
self.set_config("otamanagerdevice", otadev)
if eventdev:
self.set_config("eventservicedevice", eventdev)
# append all platform options (except starting id) to doc
for configuration in self.emane_config.emulator_config:
name = configuration.id
if name == "platform_id_start":
continue
value = self.get_config(name)
param = self.xmlparam(doc, name, value)
plat.appendChild(param)
return doc
def buildplatformxml(self, ctrlnet):
"""
Build a platform.xml file now that all nodes are configured.
"""
nemid = int(self.get_config("nem_id_start"))
platformxmls = {}
# assume self._objslock is already held here
for key in sorted(self._emane_nodes.keys()):
emane_node = self._emane_nodes[key]
nems = emane_node.buildplatformxmlentry(self.xmldoc("platform"))
for netif in sorted(nems, key=lambda x: x.node.objid):
nementry = nems[netif]
nementry.setAttribute("id", "%d" % nemid)
key = netif.node.objid
if netif.transport_type == "raw":
key = "host"
otadev = ctrlnet.brname
eventdev = ctrlnet.brname
else:
otadev = None
eventdev = None
if key not in platformxmls:
platformxmls[key] = self.newplatformxmldoc(otadev, eventdev)
doc = platformxmls[key]
plat = doc.getElementsByTagName("platform").pop()
plat.appendChild(nementry)
emane_node.setnemid(netif, nemid)
macstr = self._hwaddr_prefix + ":00:00:"
macstr += "%02X:%02X" % ((nemid >> 8) & 0xFF, nemid & 0xFF)
netif.sethwaddr(MacAddress.from_string(macstr))
nemid += 1
for key in sorted(platformxmls.keys()):
if key == "host":
self.xmlwrite(platformxmls["host"], "platform.xml")
continue
self.xmlwrite(platformxmls[key], "platform%d.xml" % key)
nemid = build_node_platform_xml(self, ctrlnet, emane_node, nemid)
def buildnemxml(self):
"""
@ -709,23 +731,7 @@ class EmaneManager(ModelManager):
"""
for key in sorted(self._emane_nodes.keys()):
emane_node = self._emane_nodes[key]
emane_node.build_xml_files(self)
def appendtransporttonem(self, doc, nem, nodenum, ifc=None):
"""
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.
"""
emane_node = self._emane_nodes[nodenum]
transtag = doc.createElement("transport")
transtypestr = "virtual"
if ifc and ifc.transport_type == "raw":
transtypestr = "raw"
transtag.setAttribute("definition", emane_node.transportxmlname(transtypestr))
nem.appendChild(transtag)
build_xml_files(self, emane_node)
def buildtransportxml(self):
"""
@ -758,14 +764,14 @@ class EmaneManager(ModelManager):
return
dev = self.get_config("eventservicedevice")
doc = self.xmldoc("emaneeventmsgsvc")
es = doc.getElementsByTagName("emaneeventmsgsvc").pop()
kvs = (("group", group), ("port", port), ("device", dev), ("mcloop", "1"), ("ttl", "32"))
xmlutils.add_text_elements_from_tuples(doc, es, kvs)
filename = "libemaneeventservice.xml"
self.xmlwrite(doc, filename)
pathname = os.path.join(self.session.session_dir, filename)
self.initeventservice(filename=pathname)
event_element = etree.Element("emaneeventmsgsvc")
for name, value in (("group", group), ("port", port), ("device", dev), ("mcloop", "1"), ("ttl", "32")):
sub_element = etree.SubElement(event_element, name)
sub_element.text = value
file_name = "libemaneeventservice.xml"
file_path = os.path.join(self.session.session_dir, file_name)
emanexml.create_file(event_element, "emaneeventmsgsvc", file_path)
def startdaemons(self):
"""
@ -1062,8 +1068,5 @@ class EmaneGlobalModel(EmaneModel):
def __init__(self, session, object_id=None):
super(EmaneGlobalModel, self).__init__(session, object_id)
def build_xml_files(self, emane_manager, interface):
"""
Build the necessary nem, mac, and phy XMLs in the given path.
"""
def build_xml_files(self, config, interface=None):
raise NotImplementedError

View file

@ -8,95 +8,8 @@ from lxml import etree
from core import logger
from core.conf import ConfigGroup
from core.emane import emanemanifest
from core.misc import utils
from core.mobility import WirelessModel
from core.xml import corexml
def emane_xml_doctype(name):
"""
Create emane xml doctype for xml files.
:param str name: name for xml doctype
:return: emane xml doctype
:rtype: str
"""
return '<!DOCTYPE %s SYSTEM "file:///usr/share/emane/dtd/%s.dtd">' % (name, name)
def add_emane_configurations(xml_element, configurations, config, config_ignore):
"""
:param lxml.etree.Element xml_element: xml element to add emane configurations to
:param list[core.config.Configuration] configurations: configurations to add to xml
:param dict config: configuration values
:param set config_ignore: configuration options to ignore
:return:
"""
for configuration in configurations:
# ignore custom configurations
name = configuration.id
if name in config_ignore:
continue
# check if value is a multi param
value = str(config[name])
params = lxml_value_to_params(value)
if params:
params_element = etree.SubElement(xml_element, "paramlist", name=name)
for param in params:
etree.SubElement(params_element, "item", value=param)
else:
etree.SubElement(xml_element, "param", name=name, value=value)
def lxml_value_to_params(value):
"""
Helper to convert a parameter to a parameter tuple.
:param str value: value string to convert to tuple
:return: parameter tuple, None otherwise
"""
try:
values = utils.make_tuple_fromstr(value, str)
if not hasattr(values, "__iter__"):
return None
if len(values) < 2:
return None
return values
except SyntaxError:
logger.exception("error in value string to param list")
return None
# def value_to_params(doc, name, value):
# """
# Helper to convert a parameter to a paramlist. Returns an XML paramlist, or None if the value does not expand to
# multiple values.
#
# :param xml.dom.minidom.Document doc: xml document
# :param name: name of element for params
# :param str value: value string to convert to tuple
# :return: xml document with added params or None, when an invalid value has been provided
# """
# try:
# values = utils.make_tuple_fromstr(value, str)
# except SyntaxError:
# logger.exception("error in value string to param list")
# return None
#
# if not hasattr(values, "__iter__"):
# return None
#
# if len(values) < 2:
# return None
#
# return xmlutils.add_param_list_to_parent(doc, parent=None, name=name, values=values)
from core.xml import emanexml
class EmaneModel(WirelessModel):
@ -122,8 +35,6 @@ class EmaneModel(WirelessModel):
phy_config = emanemanifest.parse(phy_xml, phy_defaults)
config_ignore = set()
config_groups_override = None
configurations_override = None
@classmethod
def configurations(cls):
@ -138,29 +49,25 @@ class EmaneModel(WirelessModel):
ConfigGroup("PHY Parameters", mac_len + 1, config_len)
]
def build_xml_files(self, emane_manager, interface):
def build_xml_files(self, config, interface=None):
"""
Builds xml files for emane. Includes a nem.xml file that points to both mac.xml and phy.xml definitions.
Builds xml files for this emane model. Creates a nem.xml file that points to both mac.xml and phy.xml
definitions.
:param core.emane.emanemanager.EmaneManager emane_manager: core emane manager
:param dict config: emane model configuration for the node and interface
:param interface: interface for the emane node
:return: nothing
"""
# retrieve configuration values
config = emane_manager.getifcconfig(self.object_id, interface, self.name)
if not config:
return
# create document and write to disk
self.create_nem_doc(interface)
self.create_nem_xml(interface)
# create mac document and write to disk
self.create_mac_doc(interface, config)
self.create_mac_xml(interface, config)
# create phy document and write to disk
self.create_phy_doc(interface, config)
self.create_phy_xml(interface, config)
def create_nem_doc(self, interface):
def create_nem_xml(self, interface):
"""
Create the nem xml document.
@ -188,7 +95,7 @@ class EmaneModel(WirelessModel):
nem_name = self.nem_name(interface)
self.create_file(nem_element, nem_name, "nem")
def create_mac_doc(self, interface, config):
def create_mac_xml(self, interface, config):
"""
Create the mac xml document.
@ -200,13 +107,13 @@ class EmaneModel(WirelessModel):
raise ValueError("must define emane model library")
mac_element = etree.Element("mac", name="%s MAC" % self.name, library=self.mac_library)
add_emane_configurations(mac_element, self.mac_config, config, self.config_ignore)
emanexml.add_configurations(mac_element, self.mac_config, config, self.config_ignore)
# write out xml
mac_name = self.mac_name(interface)
self.create_file(mac_element, mac_name, "mac")
def create_phy_doc(self, interface, config):
def create_phy_xml(self, interface, config):
"""
Create the phy xml document.
@ -218,7 +125,7 @@ class EmaneModel(WirelessModel):
if self.phy_library:
phy_element.set("library", self.phy_library)
add_emane_configurations(phy_element, self.phy_config, config, self.config_ignore)
emanexml.add_configurations(phy_element, self.phy_config, config, self.config_ignore)
# write out xml
phy_name = self.phy_name(interface)
@ -226,8 +133,7 @@ class EmaneModel(WirelessModel):
def create_file(self, xml_element, file_name, doc_name):
file_path = os.path.join(self.session.session_dir, file_name)
doctype = emane_xml_doctype(doc_name)
corexml.write_xml_file(xml_element, file_path, doctype=doctype)
emanexml.create_file(xml_element, doc_name, file_path)
def post_startup(self):
"""
@ -237,64 +143,6 @@ class EmaneModel(WirelessModel):
"""
logger.info("emane model(%s) has no post setup tasks", self.name)
def build_nem_xml(self, doc, emane_node, interface):
"""
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 name="NODE-001" definition="rfpipenem.xml">
:param xml.dom.minidom.Document doc: xml document
:param core.emane.nodes.EmaneNode emane_node: emane node to get information from
:param interface: interface for the emane node
:return: created platform xml
"""
# if this netif contains a non-standard (per-interface) config,
# then we need to use a more specific xml file here
nem_name = self.nem_name(interface)
nem = doc.createElement("nem")
nem.setAttribute("name", interface.localname)
nem.setAttribute("definition", nem_name)
return nem
def build_transport_xml(self, doc, emane_node, interface):
"""
Build the transport definition that goes into the platform.xml file.
This returns an XML element that will be added to the nem definition.
This default method supports raw and virtual transport types, but may be
overridden by a model to support the e.g. pluggable virtual transport.
<transport definition="transvirtual.xml" group="1">
<param name="device" value="n1.0.158" />
</transport>
:param xml.dom.minidom.Document doc: xml document
:param core.emane.nodes.EmaneNode emane_node: emane node to get information from
:param interface: interface for the emane node
:return: created transport xml
"""
transport_type = interface.transport_type
if not transport_type:
logger.info("warning: %s interface type unsupported!", interface.name)
transport_type = "raw"
transport_name = emane_node.transportxmlname(transport_type)
transport = doc.createElement("transport")
transport.setAttribute("definition", transport_name)
param = doc.createElement("param")
param.setAttribute("name", "device")
param.setAttribute("value", interface.name)
transport.appendChild(param)
return transport
def _basename(self, interface=None):
"""
Create name that is leveraged for configuration file creation.

View file

@ -4,8 +4,6 @@ control of an EMANE emulation. An EmaneNode has several attached NEMs that
share the same MAC+PHY model.
"""
import os
from core import logger
from core.coreobj import PyCoreNet
from core.enumerations import LinkTypes
@ -119,89 +117,6 @@ class EmaneNode(EmaneNet):
"""
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:
logger.info("warning: EmaneNode %s has no associated model", self.name)
return ret
for netif in self.netifs():
nementry = self.model.build_nem_xml(doc, self, netif)
trans = self.model.build_transport_xml(doc, self, netif)
nementry.appendChild(trans)
ret[netif] = nementry
return ret
def build_xml_files(self, emane_manager):
"""
Let the configured model build the necessary nem, mac, and phy XMLs.
:param core.emane.emanemanager.EmaneManager emane_manager: core emane manager
:return: nothing
"""
if self.model is None:
return
# build XML for overall network (EmaneNode) configs
self.model.build_xml_files(emane_manager, interface=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.build_xml_files(emane_manager, 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_manager, vtype)
if need_raw:
self.buildtransportxml(emane_manager, rtype)
def buildtransportxml(self, emane, transport_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" % transport_type.capitalize())
trans.setAttribute("library", "trans%s" % transport_type.lower())
trans.appendChild(emane.xmlparam(transdoc, "bitrate", "0"))
config = emane.get_configs(node_id=self.objid, config_type=self.model.name)
logger.debug("transport xml config: %s", config)
flowcontrol = config.get("flowcontrolenable", "0") == "1"
if "virtual" in transport_type.lower():
if os.path.exists("/dev/net/tun_flowctl"):
trans.appendChild(emane.xmlparam(transdoc, "devicepath", "/dev/net/tun_flowctl"))
else:
trans.appendChild(emane.xmlparam(transdoc, "devicepath", "/dev/net/tun"))
if flowcontrol:
trans.appendChild(emane.xmlparam(transdoc, "flowcontrolenable", "on"))
emane.xmlwrite(transdoc, self.transportxmlname(transport_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, do_netns=True):
"""
Install TAP devices into their namespaces. This is done after

View file

@ -59,7 +59,7 @@ def create_emane_config(node_id, emane_config, config):
emulator_element = etree.SubElement(emane_configuration, "emulator")
for emulator_config in emane_config.emulator_config:
value = config[emulator_config.id]
add_configuration(emulator_element, emane_config.id, value)
add_configuration(emulator_element, emulator_config.id, value)
nem_element = etree.SubElement(emane_configuration, "nem")
for nem_config in emane_config.nem_config:
@ -519,7 +519,7 @@ class CoreXmlWriter(object):
for model_name, config in all_configs.iteritems():
logger.info("writing emane config: %s", config)
if model_name == -1:
emane_configuration = create_emane_config(node_id, self.session.emane_config, config)
emane_configuration = create_emane_config(node_id, self.session.emane.emane_config, config)
else:
model = self.session.emane.models[model_name]
emane_configuration = create_emane_model_config(node_id, model, config)

View file

@ -0,0 +1,64 @@
from lxml import etree
from core import logger
from core.misc import utils
from core.xml import corexml
def _value_to_params(value):
"""
Helper to convert a parameter to a parameter tuple.
:param str value: value string to convert to tuple
:return: parameter tuple, None otherwise
"""
try:
values = utils.make_tuple_fromstr(value, str)
if not hasattr(values, "__iter__"):
return None
if len(values) < 2:
return None
return values
except SyntaxError:
logger.exception("error in value string to param list")
return None
def create_file(xml_element, doc_name, file_path):
doctype = '<!DOCTYPE %(doc_name)s SYSTEM "file:///usr/share/emane/dtd/%(doc_name)s.dtd">' % {"doc_name": doc_name}
corexml.write_xml_file(xml_element, file_path, doctype=doctype)
def add_param(xml_element, name, value):
etree.SubElement(xml_element, "param", name=name, value=value)
def add_configurations(xml_element, configurations, config, config_ignore):
"""
Add emane model configurations to xml element.
:param lxml.etree.Element xml_element: xml element to add emane configurations to
:param list[core.config.Configuration] configurations: configurations to add to xml
:param dict config: configuration values
:param set config_ignore: configuration options to ignore
:return:
"""
for configuration in configurations:
# ignore custom configurations
name = configuration.id
if name in config_ignore:
continue
# check if value is a multi param
value = str(config[name])
params = _value_to_params(value)
if params:
params_element = etree.SubElement(xml_element, "paramlist", name=name)
for param in params:
etree.SubElement(params_element, "item", value=param)
else:
add_param(xml_element, name, value)

View file

@ -1,8 +1,7 @@
from core.emane import emanemanifest
from core.emane import emanemodel
## Custom EMANE Model
class ExampleModel(emanemodel.EmaneModel):
### MAC Definition
@ -47,10 +46,3 @@ class ExampleModel(emanemodel.EmaneModel):
# Allows you to ignore options within phy/mac, used typically if you needed to add a custom option for display
# within the gui.
config_ignore = set()
# Allows you to override how options are displayed with the GUI, using the GUI format of
# "name:1-2|othername:3-4". This will be parsed into tabs, split by "|" and account for items based on the indexed
# numbers after ":" for including values in each tab.
config_groups_override = None
# Allows you to override the default config matrix list. This value by default is the mac_config + phy_config, in
# that order.
config_matrix_override = None