From bfbee35a5314b5842292fb839bbe9d2936e4c206 Mon Sep 17 00:00:00 2001 From: "Blake J. Harnden" Date: Wed, 11 Jul 2018 09:19:06 -0700 Subject: [PATCH] updates to support external transport configuration and an emane transport service to generate and run emanetransport for a configured external transport model --- daemon/core/conf.py | 2 +- daemon/core/emane/commeffect.py | 3 +- daemon/core/emane/emanemanager.py | 7 +++-- daemon/core/emane/emanemodel.py | 18 ++++++++++-- daemon/core/emane/nodes.py | 2 +- daemon/core/netns/vif.py | 2 ++ daemon/core/services/emaneservices.py | 40 +++++++++++++++++++++++++++ daemon/core/xml/corexml.py | 11 ++++++++ daemon/core/xml/emanexml.py | 37 ++++++++++++++++++++----- daemon/data/logging.conf | 2 +- 10 files changed, 108 insertions(+), 16 deletions(-) create mode 100644 daemon/core/services/emaneservices.py diff --git a/daemon/core/conf.py b/daemon/core/conf.py index b232b101..f9e6e29d 100644 --- a/daemon/core/conf.py +++ b/daemon/core/conf.py @@ -105,7 +105,7 @@ class Configuration(object): Represents a configuration options. """ - def __init__(self, _id, _type, label, default="", options=None): + def __init__(self, _id, _type, label=None, default="", options=None): """ Creates a Configuration object. diff --git a/daemon/core/emane/commeffect.py b/daemon/core/emane/commeffect.py index efb279c7..bf0eee79 100644 --- a/daemon/core/emane/commeffect.py +++ b/daemon/core/emane/commeffect.py @@ -41,8 +41,9 @@ class EmaneCommEffectModel(emanemodel.EmaneModel): shim_defaults = {} config_shim = emanemanifest.parse(shim_xml, shim_defaults) - # comm effect does not need the default phy configuration + # comm effect does not need the default phy and external configurations phy_config = () + external_config = () @classmethod def configurations(cls): diff --git a/daemon/core/emane/emanemanager.py b/daemon/core/emane/emanemanager.py index d3fec411..e7b831e8 100644 --- a/daemon/core/emane/emanemanager.py +++ b/daemon/core/emane/emanemanager.py @@ -128,7 +128,9 @@ class EmaneManager(ModelManager): if not config and self.has_configs(interface.node.objid): config = self.get_configs(node_id=interface.node.objid, config_type=model_name) - if not config and interface.transport_type == "raw": + # get non interface config, when none found + # if not config and interface.transport_type == "raw": + if not config and self.has_configs(node_id): # with EMANE 0.9.2+, we need an extra NEM XML from # model.buildnemxmlfiles(), so defaults are returned here config = self.get_configs(node_id=node_id, config_type=model_name) @@ -561,11 +563,12 @@ class EmaneManager(ModelManager): Build a platform.xml file now that all nodes are configured. """ nemid = int(self.get_config("nem_id_start")) + platform_xmls = {} # assume self._objslock is already held here for key in sorted(self._emane_nodes.keys()): emane_node = self._emane_nodes[key] - nemid = emanexml.build_node_platform_xml(self, ctrlnet, emane_node, nemid) + nemid = emanexml.build_node_platform_xml(self, ctrlnet, emane_node, nemid, platform_xmls) def buildnemxml(self): """ diff --git a/daemon/core/emane/emanemodel.py b/daemon/core/emane/emanemodel.py index 55092741..d1e5df22 100644 --- a/daemon/core/emane/emanemodel.py +++ b/daemon/core/emane/emanemodel.py @@ -5,7 +5,9 @@ import os from core import logger from core.conf import ConfigGroup +from core.conf import Configuration from core.emane import emanemanifest +from core.enumerations import ConfigDataTypes from core.mobility import WirelessModel from core.xml import emanexml @@ -32,19 +34,28 @@ class EmaneModel(WirelessModel): } phy_config = emanemanifest.parse(phy_xml, phy_defaults) + # support for external configurations + external_config = [ + Configuration("external", ConfigDataTypes.BOOL, default="0"), + Configuration("platformendpoint", ConfigDataTypes.STRING, default="127.0.0.1:40001"), + Configuration("transportendpoint", ConfigDataTypes.STRING, default="127.0.0.1:50002") + ] + config_ignore = set() @classmethod def configurations(cls): - return cls.mac_config + cls.phy_config + return cls.mac_config + cls.phy_config + cls.external_config @classmethod def config_groups(cls): mac_len = len(cls.mac_config) + phy_len = len(cls.phy_config) + mac_len config_len = len(cls.configurations()) return [ ConfigGroup("MAC Parameters", 1, mac_len), - ConfigGroup("PHY Parameters", mac_len + 1, config_len) + ConfigGroup("PHY Parameters", mac_len + 1, phy_len), + ConfigGroup("External Parameters", phy_len + 1, config_len) ] def build_xml_files(self, config, interface=None): @@ -60,6 +71,7 @@ class EmaneModel(WirelessModel): mac_name = emanexml.mac_file_name(self, interface) phy_name = emanexml.phy_file_name(self, interface) + # check if this is external transport_type = "virtual" if interface and interface.transport_type == "raw": transport_type = "raw" @@ -67,7 +79,7 @@ class EmaneModel(WirelessModel): # create nem xml file nem_file = os.path.join(self.session.session_dir, nem_name) - emanexml.create_nem_xml(self, nem_file, transport_name, mac_name, phy_name) + emanexml.create_nem_xml(self, config, nem_file, transport_name, mac_name, phy_name) # create mac xml file mac_file = os.path.join(self.session.session_dir, mac_name) diff --git a/daemon/core/emane/nodes.py b/daemon/core/emane/nodes.py index dd154b8b..6eb788d3 100644 --- a/daemon/core/emane/nodes.py +++ b/daemon/core/emane/nodes.py @@ -131,7 +131,7 @@ class EmaneNode(EmaneNet): for netif in self.netifs(): if do_netns and "virtual" in netif.transport_type.lower(): netif.install() - netif.setaddrs() + # netif.setaddrs() if not self.session.emane.genlocationevents(): netif.poshook = None continue diff --git a/daemon/core/netns/vif.py b/daemon/core/netns/vif.py index b7d77d23..2e5b66fc 100644 --- a/daemon/core/netns/vif.py +++ b/daemon/core/netns/vif.py @@ -169,6 +169,7 @@ class TunTap(PyCoreNetIf): :return: wait for device local response :rtype: int """ + logger.debug("waiting for device local: %s", self.localname) def localdevexists(): args = [constants.IP_BIN, "link", "show", self.localname] @@ -182,6 +183,7 @@ class TunTap(PyCoreNetIf): :return: nothing """ + logger.debug("waiting for device node: %s", self.name) def nodedevexists(): args = [constants.IP_BIN, "link", "show", self.name] diff --git a/daemon/core/services/emaneservices.py b/daemon/core/services/emaneservices.py new file mode 100644 index 00000000..26c59282 --- /dev/null +++ b/daemon/core/services/emaneservices.py @@ -0,0 +1,40 @@ +from core.enumerations import NodeTypes +from core.misc import nodeutils +from core.service import CoreService +from core.xml import emanexml + + +class EmaneTransportService(CoreService): + name = "transportd" + executables = ("emanetransportd", "emanegentransportxml") + group = "EMANE" + dependencies = () + dirs = () + configs = ("emanetransport.sh",) + startup = ("sh %s" % configs[0],) + validate = ("pidof %s" % executables[0],) + validation_timer = 0.5 + shutdown = ("killall %s" % executables[0],) + + @classmethod + def generate_config(cls, node, filename): + if filename == cls.configs[0]: + transport_commands = [] + for interface in node.netifs(sort=True): + network_node = node.session.get_object(interface.net.objid) + if nodeutils.is_node(network_node, NodeTypes.EMANE): + if not node.session.emane.has_configs(network_node.objid): + continue + all_configs = node.session.emane.get_all_configs(network_node.objid) + config = all_configs.get(network_node.model.name) + if emanexml.is_external(config): + nem_id = network_node.getnemid(interface) + command = "emanetransportd -r -l 0 -d ../transportdaemon%s.xml" % nem_id + transport_commands.append(command) + transport_commands = "\n".join(transport_commands) + return """ +emanegentransportxml -o ../ ../platform%s.xml +%s +""" % (node.objid, transport_commands) + else: + raise ValueError diff --git a/daemon/core/xml/corexml.py b/daemon/core/xml/corexml.py index 9d022625..df01a178 100644 --- a/daemon/core/xml/corexml.py +++ b/daemon/core/xml/corexml.py @@ -84,6 +84,11 @@ def create_emane_model_config(node_id, model, config): value = config[phy_config.id] add_configuration(phy_element, phy_config.id, value) + external_element = etree.SubElement(emane_element, "external") + for external_config in model.external_config: + value = config[external_config.id] + add_configuration(external_element, external_config.id, value) + return emane_element @@ -774,6 +779,12 @@ class CoreXmlReader(object): value = config.get("value") configs[name] = value + external_configuration = emane_configuration.find("external") + for config in external_configuration.iterchildren(): + name = config.get("name") + value = config.get("value") + configs[name] = value + logger.info("reading emane configuration node(%s) model(%s)", node_id, model_name) self.session.emane.set_model_config(node_id, model_name, configs) diff --git a/daemon/core/xml/emanexml.py b/daemon/core/xml/emanexml.py index db811f76..b235872c 100644 --- a/daemon/core/xml/emanexml.py +++ b/daemon/core/xml/emanexml.py @@ -10,6 +10,17 @@ from core.xml import corexml _hwaddr_prefix = "02:02" +def is_external(config): + """ + Checks if the configuration is for an external transport. + + :param dict config: configuration to check + :return: True if external, False otherwise + :rtype: bool + """ + return config.get("external") == "1" + + def _value_to_params(value): """ Helper to convert a parameter to a parameter tuple. @@ -85,7 +96,7 @@ def add_configurations(xml_element, configurations, config, config_ignore): add_param(xml_element, name, value) -def build_node_platform_xml(emane_manager, control_net, node, nem_id): +def build_node_platform_xml(emane_manager, control_net, node, nem_id, platform_xmls): """ Create platform xml for a specific node. @@ -93,15 +104,15 @@ def build_node_platform_xml(emane_manager, control_net, node, nem_id): :param core.netns.nodes.CtrlNet control_net: control net node for this emane network :param core.emane.nodes.EmaneNode node: node to write platform xml for :param int nem_id: nem id to use for interfaces for this node + :param dict platform_xmls: stores platform xml elements to append nem entries to :return: the next nem id that can be used for creating platform xml files :rtype: int """ logger.debug("building emane platform xml for node(%s): %s", node, node.name) nem_entries = {} - platform_xmls = {} if node.model is None: - logger.info("warning: EmaneNode %s has no associated model", node.name) + logger.warn("warning: EmaneNode %s has no associated model", node.name) return nem_entries for netif in node.netifs(): @@ -109,6 +120,16 @@ def build_node_platform_xml(emane_manager, control_net, node, nem_id): nem_definition = nem_file_name(node.model, netif) nem_element = etree.Element("nem", id=str(nem_id), name=netif.localname, definition=nem_definition) + # check if this is an external transport, get default config if an interface specific one does not exist + config = emane_manager.getifcconfig(node.model.object_id, netif, node.model.name) + + if is_external(config): + nem_element.set("transport", "external") + platform_endpoint = "platformendpoint" + add_param(nem_element, platform_endpoint, config[platform_endpoint]) + transport_endpoint = "transportendpoint" + add_param(nem_element, transport_endpoint, config[transport_endpoint]) + # build transport xml transport_type = netif.transport_type if not transport_type: @@ -220,7 +241,6 @@ def build_xml_files(emane_manager, node): 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) @@ -270,7 +290,7 @@ def create_phy_xml(emane_model, config, file_path): Create the phy xml document. :param core.emane.emanemodel.EmaneModel emane_model: emane model to create phy xml for - :param dict config: all current configuration values, mac + phy + :param dict config: all current configuration values :param str file_path: path to write file to :return: nothing """ @@ -287,7 +307,7 @@ def create_mac_xml(emane_model, config, file_path): Create the mac xml document. :param core.emane.emanemodel.EmaneModel emane_model: emane model to create phy xml for - :param dict config: all current configuration values, mac + phy + :param dict config: all current configuration values :param str file_path: path to write file to :return: nothing """ @@ -299,11 +319,12 @@ def create_mac_xml(emane_model, config, file_path): create_file(mac_element, "mac", file_path) -def create_nem_xml(emane_model, nem_file, transport_definition, mac_definition, phy_definition): +def create_nem_xml(emane_model, config, nem_file, transport_definition, mac_definition, phy_definition): """ Create the nem xml document. :param core.emane.emanemodel.EmaneModel emane_model: emane model to create phy xml for + :param dict config: all current configuration values :param str nem_file: nem file path to write :param str transport_definition: transport file definition path :param str mac_definition: mac file definition path @@ -311,6 +332,8 @@ def create_nem_xml(emane_model, nem_file, transport_definition, mac_definition, :return: nothing """ nem_element = etree.Element("nem", name="%s NEM" % emane_model.name) + if is_external(config): + nem_element.set("type", "unstructured") etree.SubElement(nem_element, "transport", definition=transport_definition) etree.SubElement(nem_element, "mac", definition=mac_definition) etree.SubElement(nem_element, "phy", definition=phy_definition) diff --git a/daemon/data/logging.conf b/daemon/data/logging.conf index 7f3d496f..46de6e92 100644 --- a/daemon/data/logging.conf +++ b/daemon/data/logging.conf @@ -14,7 +14,7 @@ } }, "root": { - "level": "INFO", + "level": "DEBUG", "handlers": ["console"] } }