updates to support external transport configuration and an emane transport service to generate and run emanetransport for a configured external transport model

This commit is contained in:
Blake J. Harnden 2018-07-11 09:19:06 -07:00
parent bf222cd5b4
commit bfbee35a53
10 changed files with 108 additions and 16 deletions

View file

@ -105,7 +105,7 @@ class Configuration(object):
Represents a configuration options. 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. Creates a Configuration object.

View file

@ -41,8 +41,9 @@ class EmaneCommEffectModel(emanemodel.EmaneModel):
shim_defaults = {} shim_defaults = {}
config_shim = emanemanifest.parse(shim_xml, 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 = () phy_config = ()
external_config = ()
@classmethod @classmethod
def configurations(cls): def configurations(cls):

View file

@ -128,7 +128,9 @@ class EmaneManager(ModelManager):
if not config and self.has_configs(interface.node.objid): if not config and self.has_configs(interface.node.objid):
config = self.get_configs(node_id=interface.node.objid, config_type=model_name) 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 # with EMANE 0.9.2+, we need an extra NEM XML from
# model.buildnemxmlfiles(), so defaults are returned here # model.buildnemxmlfiles(), so defaults are returned here
config = self.get_configs(node_id=node_id, config_type=model_name) 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. Build a platform.xml file now that all nodes are configured.
""" """
nemid = int(self.get_config("nem_id_start")) nemid = int(self.get_config("nem_id_start"))
platform_xmls = {}
# assume self._objslock is already held here # assume self._objslock is already held here
for key in sorted(self._emane_nodes.keys()): for key in sorted(self._emane_nodes.keys()):
emane_node = self._emane_nodes[key] 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): def buildnemxml(self):
""" """

View file

@ -5,7 +5,9 @@ import os
from core import logger from core import logger
from core.conf import ConfigGroup from core.conf import ConfigGroup
from core.conf import Configuration
from core.emane import emanemanifest from core.emane import emanemanifest
from core.enumerations import ConfigDataTypes
from core.mobility import WirelessModel from core.mobility import WirelessModel
from core.xml import emanexml from core.xml import emanexml
@ -32,19 +34,28 @@ class EmaneModel(WirelessModel):
} }
phy_config = emanemanifest.parse(phy_xml, phy_defaults) 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() config_ignore = set()
@classmethod @classmethod
def configurations(cls): def configurations(cls):
return cls.mac_config + cls.phy_config return cls.mac_config + cls.phy_config + cls.external_config
@classmethod @classmethod
def config_groups(cls): def config_groups(cls):
mac_len = len(cls.mac_config) mac_len = len(cls.mac_config)
phy_len = len(cls.phy_config) + mac_len
config_len = len(cls.configurations()) config_len = len(cls.configurations())
return [ return [
ConfigGroup("MAC Parameters", 1, mac_len), 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): def build_xml_files(self, config, interface=None):
@ -60,6 +71,7 @@ class EmaneModel(WirelessModel):
mac_name = emanexml.mac_file_name(self, interface) mac_name = emanexml.mac_file_name(self, interface)
phy_name = emanexml.phy_file_name(self, interface) phy_name = emanexml.phy_file_name(self, interface)
# check if this is external
transport_type = "virtual" transport_type = "virtual"
if interface and interface.transport_type == "raw": if interface and interface.transport_type == "raw":
transport_type = "raw" transport_type = "raw"
@ -67,7 +79,7 @@ class EmaneModel(WirelessModel):
# create nem xml file # create nem xml file
nem_file = os.path.join(self.session.session_dir, nem_name) 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 # create mac xml file
mac_file = os.path.join(self.session.session_dir, mac_name) mac_file = os.path.join(self.session.session_dir, mac_name)

View file

@ -131,7 +131,7 @@ class EmaneNode(EmaneNet):
for netif in self.netifs(): for netif in self.netifs():
if do_netns and "virtual" in netif.transport_type.lower(): if do_netns and "virtual" in netif.transport_type.lower():
netif.install() netif.install()
netif.setaddrs() # netif.setaddrs()
if not self.session.emane.genlocationevents(): if not self.session.emane.genlocationevents():
netif.poshook = None netif.poshook = None
continue continue

View file

@ -169,6 +169,7 @@ class TunTap(PyCoreNetIf):
:return: wait for device local response :return: wait for device local response
:rtype: int :rtype: int
""" """
logger.debug("waiting for device local: %s", self.localname)
def localdevexists(): def localdevexists():
args = [constants.IP_BIN, "link", "show", self.localname] args = [constants.IP_BIN, "link", "show", self.localname]
@ -182,6 +183,7 @@ class TunTap(PyCoreNetIf):
:return: nothing :return: nothing
""" """
logger.debug("waiting for device node: %s", self.name)
def nodedevexists(): def nodedevexists():
args = [constants.IP_BIN, "link", "show", self.name] args = [constants.IP_BIN, "link", "show", self.name]

View file

@ -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

View file

@ -84,6 +84,11 @@ def create_emane_model_config(node_id, model, config):
value = config[phy_config.id] value = config[phy_config.id]
add_configuration(phy_element, phy_config.id, value) 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 return emane_element
@ -774,6 +779,12 @@ class CoreXmlReader(object):
value = config.get("value") value = config.get("value")
configs[name] = 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) logger.info("reading emane configuration node(%s) model(%s)", node_id, model_name)
self.session.emane.set_model_config(node_id, model_name, configs) self.session.emane.set_model_config(node_id, model_name, configs)

View file

@ -10,6 +10,17 @@ from core.xml import corexml
_hwaddr_prefix = "02:02" _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): def _value_to_params(value):
""" """
Helper to convert a parameter to a parameter tuple. 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) 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. 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.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 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 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 :return: the next nem id that can be used for creating platform xml files
:rtype: int :rtype: int
""" """
logger.debug("building emane platform xml for node(%s): %s", node, node.name) logger.debug("building emane platform xml for node(%s): %s", node, node.name)
nem_entries = {} nem_entries = {}
platform_xmls = {}
if node.model is None: 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 return nem_entries
for netif in node.netifs(): 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_definition = nem_file_name(node.model, netif)
nem_element = etree.Element("nem", id=str(nem_id), name=netif.localname, definition=nem_definition) 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 # build transport xml
transport_type = netif.transport_type transport_type = netif.transport_type
if not transport_type: if not transport_type:
@ -220,7 +241,6 @@ def build_xml_files(emane_manager, node):
need_raw = True need_raw = True
rtype = netif.transport_type rtype = netif.transport_type
# build transport XML files depending on type of interfaces involved
if need_virtual: if need_virtual:
build_transport_xml(emane_manager, node, vtype) 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. Create the phy xml document.
:param core.emane.emanemodel.EmaneModel emane_model: emane model to create phy xml for :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 :param str file_path: path to write file to
:return: nothing :return: nothing
""" """
@ -287,7 +307,7 @@ def create_mac_xml(emane_model, config, file_path):
Create the mac xml document. Create the mac xml document.
:param core.emane.emanemodel.EmaneModel emane_model: emane model to create phy xml for :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 :param str file_path: path to write file to
:return: nothing :return: nothing
""" """
@ -299,11 +319,12 @@ def create_mac_xml(emane_model, config, file_path):
create_file(mac_element, "mac", 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. Create the nem xml document.
:param core.emane.emanemodel.EmaneModel emane_model: emane model to create phy xml for :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 nem_file: nem file path to write
:param str transport_definition: transport file definition path :param str transport_definition: transport file definition path
:param str mac_definition: mac 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 :return: nothing
""" """
nem_element = etree.Element("nem", name="%s NEM" % emane_model.name) 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, "transport", definition=transport_definition)
etree.SubElement(nem_element, "mac", definition=mac_definition) etree.SubElement(nem_element, "mac", definition=mac_definition)
etree.SubElement(nem_element, "phy", definition=phy_definition) etree.SubElement(nem_element, "phy", definition=phy_definition)

View file

@ -14,7 +14,7 @@
} }
}, },
"root": { "root": {
"level": "INFO", "level": "DEBUG",
"handlers": ["console"] "handlers": ["console"]
} }
} }