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:
parent
ae94c78fbb
commit
f115b1a847
8 changed files with 249 additions and 424 deletions
|
@ -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:
|
||||
|
|
|
@ -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):
|
||||
"""
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
64
daemon/core/xml/emanexml.py
Normal file
64
daemon/core/xml/emanexml.py
Normal 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)
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue