daemon: further heavy cleanup to how emane generates and runs xml files

This commit is contained in:
Blake Harnden 2020-07-02 17:49:56 -07:00
parent bd48e14348
commit ce4b61d3b2
5 changed files with 103 additions and 179 deletions

View file

@ -12,7 +12,6 @@ from core.config import ConfigGroup, Configuration
from core.emane import emanemanifest, emanemodel
from core.emane.nodes import EmaneNet
from core.emulator.data import LinkOptions
from core.emulator.enumerations import TransportType
from core.nodes.interface import CoreInterface
from core.xml import emanexml
@ -73,26 +72,16 @@ class EmaneCommEffectModel(emanemodel.EmaneModel):
:param iface: interface for the emane node
:return: nothing
"""
# interface node
node = iface.node
# retrieve xml names
nem_name = emanexml.nem_file_name(iface)
shim_name = emanexml.shim_file_name(iface)
# create and write nem document
nem_element = etree.Element("nem", name=f"{self.name} NEM", type="unstructured")
transport_type = TransportType.VIRTUAL
if iface.transport_type == TransportType.RAW:
transport_type = TransportType.RAW
transport_file = emanexml.transport_file_name(iface, transport_type)
etree.SubElement(nem_element, "transport", definition=transport_file)
transport_name = emanexml.transport_file_name(iface)
etree.SubElement(nem_element, "transport", definition=transport_name)
# set shim configuration
nem_name = emanexml.nem_file_name(iface)
shim_name = emanexml.shim_file_name(iface)
etree.SubElement(nem_element, "shim", definition=shim_name)
nem_file = os.path.join(node.nodedir, nem_name)
emanexml.create_file(nem_element, "nem", nem_file)
emanexml.create_iface_file(iface, nem_element, "nem", nem_name)
# create and write shim document
shim_element = etree.Element(
@ -111,9 +100,10 @@ class EmaneCommEffectModel(emanemodel.EmaneModel):
ff = config["filterfile"]
if ff.strip() != "":
emanexml.add_param(shim_element, "filterfile", ff)
emanexml.create_iface_file(iface, shim_element, "shim", shim_name)
shim_file = os.path.join(node.nodedir, shim_name)
emanexml.create_file(shim_element, "shim", shim_file)
# create transport xml
emanexml.create_transport_xml(iface, config)
def linkconfig(
self, iface: CoreInterface, options: LinkOptions, iface2: CoreInterface = None

View file

@ -281,8 +281,6 @@ class EmaneManager(ModelManager):
instantiation
"""
logging.debug("emane setup")
# TODO: drive this from the session object
with self.session.nodes_lock:
for node_id in self.session.nodes:
node = self.session.nodes[node_id]
@ -291,7 +289,6 @@ class EmaneManager(ModelManager):
"adding emane node: id(%s) name(%s)", node.id, node.name
)
self.add_node(node)
if not self._emane_nets:
logging.debug("no emane nodes in session")
return EmaneState.NOT_NEEDED
@ -322,7 +319,7 @@ class EmaneManager(ModelManager):
logging.debug("emane event service device index: %s", netidx)
if netidx < 0:
logging.error(
"EMANE cannot start, check core config. invalid event service device: %s",
"emane cannot start due to invalid event service device: %s",
eventdev,
)
return EmaneState.NOT_READY
@ -330,7 +327,6 @@ class EmaneManager(ModelManager):
self.session.add_remove_control_net(
net_index=netidx, remove=False, conf_required=False
)
self.check_node_models()
return EmaneState.SUCCESS
@ -349,10 +345,6 @@ class EmaneManager(ModelManager):
self.starteventmonitor()
self.buildeventservicexml()
with self._emane_node_lock:
# on master, control network bridge added earlier in startup()
control_net = self.session.add_remove_control_net(
0, remove=False, conf_required=False
)
logging.info("emane building xmls...")
for node_id in sorted(self._emane_nets):
emane_net = self._emane_nets[node_id]
@ -360,25 +352,31 @@ class EmaneManager(ModelManager):
logging.error("emane net(%s) has no model", emane_net.name)
continue
for iface in emane_net.get_ifaces():
if not iface.node:
logging.error(
"emane net(%s) connected interface missing node",
emane_net.name,
)
continue
nem_id = self.next_nem_id()
self.nems[nem_id] = iface
self.write_nem(iface, nem_id)
emanexml.build_platform_xml(
self, control_net, emane_net, iface, nem_id
)
emanexml.build_model_xmls(self, emane_net, iface)
self.start_daemon(iface)
self.install_iface(emane_net, iface)
self.start_iface(emane_net, iface)
if self.links_enabled():
self.link_monitor.start()
return EmaneState.SUCCESS
def start_iface(self, emane_net: EmaneNet, iface: CoreInterface) -> None:
if not iface.node:
logging.error(
"emane net(%s) connected interface(%s) missing node",
emane_net.name,
iface.name,
)
return
control_net = self.session.add_remove_control_net(
0, remove=False, conf_required=False
)
nem_id = self.next_nem_id()
self.nems[nem_id] = iface
self.write_nem(iface, nem_id)
emanexml.build_platform_xml(self, control_net, emane_net, iface, nem_id)
config = self.get_iface_config(emane_net, iface)
emane_net.model.build_xml_files(config, iface)
self.start_daemon(iface)
self.install_iface(emane_net, iface)
def write_nem(self, iface: CoreInterface, nem_id: int) -> None:
path = os.path.join(self.session.session_dir, "emane_nems")
try:

View file

@ -9,7 +9,7 @@ from core.config import ConfigGroup, Configuration
from core.emane import emanemanifest
from core.emane.nodes import EmaneNet
from core.emulator.data import LinkOptions
from core.emulator.enumerations import ConfigDataTypes, TransportType
from core.emulator.enumerations import ConfigDataTypes
from core.errors import CoreError
from core.location.mobility import WirelessModel
from core.nodes.base import CoreNode
@ -102,34 +102,14 @@ class EmaneModel(WirelessModel):
both mac.xml and phy.xml definitions.
:param config: emane model configuration for the node and interface
:param iface: interface for the emane node
:param iface: interface to run emane for
:return: nothing
"""
nem_name = emanexml.nem_file_name(iface)
mac_name = emanexml.mac_file_name(iface)
phy_name = emanexml.phy_file_name(iface)
# check if this is external
transport_type = TransportType.VIRTUAL
if iface.transport_type == TransportType.RAW:
transport_type = TransportType.RAW
transport_name = emanexml.transport_file_name(iface, transport_type)
node = iface.node
server = node.server
# create nem xml file
nem_file = os.path.join(node.nodedir, nem_name)
emanexml.create_nem_xml(
self, config, nem_file, transport_name, mac_name, phy_name, server
)
# create mac xml file
mac_file = os.path.join(node.nodedir, mac_name)
emanexml.create_mac_xml(self, config, mac_file, server)
# create phy xml file
phy_file = os.path.join(node.nodedir, phy_name)
emanexml.create_phy_xml(self, config, phy_file, server)
# create nem, mac, and phy xml files
emanexml.create_nem_xml(self, iface, config)
emanexml.create_mac_xml(self, iface, config)
emanexml.create_phy_xml(self, iface, config)
emanexml.create_transport_xml(iface, config)
def post_startup(self) -> None:
"""

View file

@ -96,7 +96,6 @@ class EmaneNet(CoreNetworkBase):
"""
set the EmaneModel associated with this node
"""
logging.info("adding model: %s", model.name)
if model.config_type == RegisterTlvs.WIRELESS:
# EmaneModel really uses values from ConfigurableManager
# when buildnemxml() is called, not during init()

View file

@ -13,6 +13,7 @@ from core.emulator.enumerations import TransportType
from core.errors import CoreError
from core.nodes.interface import CoreInterface
from core.nodes.network import CtrlNet
from core.nodes.physical import Rj45Node
from core.xml import corexml
if TYPE_CHECKING:
@ -63,16 +64,15 @@ def create_file(
:param xml_element: root element to write to file
:param doc_name: name to use in the emane doctype
:param file_path: file path to write xml file to
:param server: remote server node
will run on, default is None for localhost
:param server: remote server to create file on
:return: nothing
"""
doctype = (
f'<!DOCTYPE {doc_name} SYSTEM "file:///usr/share/emane/dtd/{doc_name}.dtd">'
)
if server is not None:
if server:
temp = NamedTemporaryFile(delete=False)
create_file(xml_element, doc_name, temp.name)
corexml.write_xml_file(xml_element, temp.name, doctype=doctype)
temp.close()
server.remote_put(temp.name, file_path)
os.unlink(temp.name)
@ -80,6 +80,26 @@ def create_file(
corexml.write_xml_file(xml_element, file_path, doctype=doctype)
def create_iface_file(
iface: CoreInterface, xml_element: etree.Element, doc_name: str, file_name: str
) -> None:
"""
Create emane xml for an interface.
:param iface: interface running emane
:param xml_element: root element to write to file
:param doc_name: name to use in the emane doctype
:param file_name: name of xml file
:return:
"""
node = iface.node
if isinstance(node, Rj45Node):
file_path = os.path.join(node.session.session_dir, file_name)
else:
file_path = os.path.join(node.nodedir, file_name)
create_file(xml_element, doc_name, file_path, node.server)
def add_param(xml_element: etree.Element, name: str, value: str) -> None:
"""
Add emane configuration parameter to xml element.
@ -159,21 +179,14 @@ def build_platform_xml(
transport_endpoint = "transportendpoint"
add_param(nem_element, transport_endpoint, config[transport_endpoint])
else:
# build transport xml
transport_type = iface.transport_type
if not transport_type:
logging.info("warning: %s interface type unsupported!", iface.name)
transport_type = TransportType.RAW
transport_file = transport_file_name(iface, transport_type)
transport_name = transport_file_name(iface)
transport_element = etree.SubElement(
nem_element, "transport", definition=transport_file
nem_element, "transport", definition=transport_name
)
add_param(transport_element, "device", iface.name)
# determine platform element to add xml to
key = iface.node.id
if iface.transport_type == TransportType.RAW:
key = "host"
otadev = control_net.brname
eventdev = control_net.brname
else:
@ -195,67 +208,19 @@ def build_platform_xml(
iface.set_mac(mac)
doc_name = "platform"
server = None
if key == "host":
file_name = "platform.xml"
file_path = os.path.join(emane_manager.session.session_dir, file_name)
else:
node = iface.node
file_name = f"{iface.name}-platform.xml"
file_path = os.path.join(node.nodedir, file_name)
server = node.server
create_file(platform_element, doc_name, file_path, server)
file_name = f"{iface.name}-platform.xml"
create_iface_file(iface, platform_element, doc_name, file_name)
def build_model_xmls(
manager: "EmaneManager", emane_net: EmaneNet, iface: CoreInterface
) -> None:
"""
Generate emane xml files required for node.
:param manager: emane manager with emane
configurations
:param emane_net: emane network associated with interface
:param iface: interface to create emane xml for
:return: nothing
"""
# build XML for specific interface (NEM) configs
# check for interface specific emane configuration and write xml files
config = manager.get_iface_config(emane_net, iface)
emane_net.model.build_xml_files(config, iface)
# check transport type needed for interface
need_virtual = False
need_raw = False
vtype = TransportType.VIRTUAL
rtype = TransportType.RAW
if iface.transport_type == TransportType.VIRTUAL:
need_virtual = True
vtype = iface.transport_type
else:
need_raw = True
rtype = iface.transport_type
if need_virtual:
build_transport_xml(manager, emane_net, iface, vtype)
if need_raw:
build_transport_xml(manager, emane_net, iface, rtype)
def build_transport_xml(
manager: "EmaneManager",
emane_net: EmaneNet,
iface: CoreInterface,
transport_type: TransportType,
) -> None:
def create_transport_xml(iface: CoreInterface, config: Dict[str, str]) -> None:
"""
Build transport xml file for node and transport type.
:param manager: emane manager with emane configurations
:param emane_net: emane network associated with interface
:param iface: interface to build transport xml for
:param transport_type: transport type to build xml for
:param config: all current configuration values
:return: nothing
"""
transport_type = get_transport_type(iface)
transport_element = etree.Element(
"transport",
name=f"{transport_type.value.capitalize()} Transport",
@ -264,7 +229,6 @@ def build_transport_xml(
add_param(transport_element, "bitrate", "0")
# get emane model cnfiguration
config = manager.get_iface_config(emane_net, iface)
flowcontrol = config.get("flowcontrolenable", "0") == "1"
if transport_type == TransportType.VIRTUAL:
device_path = "/dev/net/tun_flowctl"
@ -274,29 +238,19 @@ def build_transport_xml(
if flowcontrol:
add_param(transport_element, "flowcontrolenable", "on")
doc_name = "transport"
node = iface.node
file_name = transport_file_name(iface, transport_type)
file_path = os.path.join(node.nodedir, file_name)
create_file(transport_element, doc_name, file_path)
manager.session.distributed.execute(
lambda x: create_file(transport_element, doc_name, file_path, x)
)
transport_name = transport_file_name(iface)
create_iface_file(iface, transport_element, doc_name, transport_name)
def create_phy_xml(
emane_model: "EmaneModel",
config: Dict[str, str],
file_path: str,
server: Optional[DistributedServer],
emane_model: "EmaneModel", iface: CoreInterface, config: Dict[str, str]
) -> None:
"""
Create the phy xml document.
:param emane_model: emane model to create xml
:param iface: interface to create xml for
:param config: all current configuration values
:param file_path: path to write file to
:param server: remote server node
will run on, default is None for localhost
:return: nothing
"""
phy_element = etree.Element("phy", name=f"{emane_model.name} PHY")
@ -305,23 +259,19 @@ def create_phy_xml(
add_configurations(
phy_element, emane_model.phy_config, config, emane_model.config_ignore
)
create_file(phy_element, "phy", file_path, server)
file_name = phy_file_name(iface)
create_iface_file(iface, phy_element, "phy", file_name)
def create_mac_xml(
emane_model: "EmaneModel",
config: Dict[str, str],
file_path: str,
server: Optional[DistributedServer],
emane_model: "EmaneModel", iface: CoreInterface, config: Dict[str, str]
) -> None:
"""
Create the mac xml document.
:param emane_model: emane model to create xml
:param iface: interface to create xml for
:param config: all current configuration values
:param file_path: path to write file to
:param server: remote server node
will run on, default is None for localhost
:return: nothing
"""
if not emane_model.mac_library:
@ -332,39 +282,33 @@ def create_mac_xml(
add_configurations(
mac_element, emane_model.mac_config, config, emane_model.config_ignore
)
create_file(mac_element, "mac", file_path, server)
file_name = mac_file_name(iface)
create_iface_file(iface, mac_element, "mac", file_name)
def create_nem_xml(
emane_model: "EmaneModel",
config: Dict[str, str],
nem_file: str,
transport_definition: str,
mac_definition: str,
phy_definition: str,
server: Optional[DistributedServer],
emane_model: "EmaneModel", iface: CoreInterface, config: Dict[str, str]
) -> None:
"""
Create the nem xml document.
:param emane_model: emane model to create xml
:param iface: interface to create xml for
:param config: all current configuration values
:param nem_file: nem file path to write
:param transport_definition: transport file definition path
:param mac_definition: mac file definition path
:param phy_definition: phy file definition path
:param server: remote server node
will run on, default is None for localhost
:return: nothing
"""
nem_element = etree.Element("nem", name=f"{emane_model.name} NEM")
if is_external(config):
nem_element.set("type", "unstructured")
else:
etree.SubElement(nem_element, "transport", definition=transport_definition)
etree.SubElement(nem_element, "mac", definition=mac_definition)
etree.SubElement(nem_element, "phy", definition=phy_definition)
create_file(nem_element, "nem", nem_file, server)
transport_name = transport_file_name(iface)
etree.SubElement(nem_element, "transport", definition=transport_name)
mac_name = mac_file_name(iface)
etree.SubElement(nem_element, "mac", definition=mac_name)
phy_name = phy_file_name(iface)
etree.SubElement(nem_element, "phy", definition=phy_name)
nem_name = nem_file_name(iface)
create_iface_file(iface, nem_element, "nem", nem_name)
def create_event_service_xml(
@ -400,14 +344,27 @@ def create_event_service_xml(
create_file(event_element, "emaneeventmsgsvc", file_path, server)
def transport_file_name(iface: CoreInterface, transport_type: TransportType) -> str:
def get_transport_type(iface: CoreInterface) -> TransportType:
"""
Get transport type for a given interface.
:param iface: interface to get transport type for
:return: transport type
"""
transport_type = TransportType.VIRTUAL
if iface.transport_type == TransportType.RAW:
transport_type = TransportType.RAW
return transport_type
def transport_file_name(iface: CoreInterface) -> str:
"""
Create name for a transport xml file.
:param iface: interface running emane
:param transport_type: transport type to generate transport file
:return: transport xml file name
"""
transport_type = get_transport_type(iface)
return f"{iface.name}-trans-{transport_type.value}.xml"