daemon: refactoring for starting up and shutting down emane daemon per interface

This commit is contained in:
Blake Harnden 2021-05-26 09:54:32 -07:00
parent 820539191d
commit 795a5f5865
2 changed files with 60 additions and 76 deletions

View file

@ -5,9 +5,8 @@ Implements configuration and control of an EMANE emulation.
import logging
import os
import threading
from dataclasses import dataclass, field
from enum import Enum
from typing import TYPE_CHECKING, Dict, List, Optional, Set, Type, Union
from typing import TYPE_CHECKING, Dict, List, Optional, Set, Tuple, Type, Union
from core import utils
from core.emane.emanemodel import EmaneModel
@ -17,7 +16,7 @@ from core.emane.nodes import EmaneNet
from core.emulator.data import LinkData
from core.emulator.enumerations import LinkTypes, MessageFlags, RegisterTlvs
from core.errors import CoreCommandError, CoreError
from core.nodes.base import CoreNetworkBase, CoreNode, CoreNodeBase, NodeBase
from core.nodes.base import CoreNetworkBase, CoreNode, NodeBase
from core.nodes.interface import CoreInterface, TunTap
from core.xml import emanexml
@ -57,12 +56,6 @@ class EmaneState(Enum):
NOT_READY = 2
@dataclass
class StartData:
node: CoreNodeBase
ifaces: List[CoreInterface] = field(default_factory=list)
class EmaneEventService:
def __init__(
self, manager: "EmaneManager", device: str, group: str, port: int
@ -327,26 +320,24 @@ class EmaneManager:
def startup_nodes(self) -> None:
with self._emane_node_lock:
logger.info("emane building xmls...")
start_data = self.get_start_data()
for data in start_data:
node = data.node
for iface in data.ifaces:
nem_id = self.next_nem_id(iface)
logger.info(
"starting emane for node(%s) iface(%s) nem(%s)",
node.name,
iface.name,
nem_id,
)
self.setup_control_channels(nem_id, node, iface)
emanexml.build_platform_xml(self, nem_id, node, iface)
self.start_daemon(node, iface)
self.install_iface(iface)
for emane_net, iface in self.get_ifaces():
nem_id = self.next_nem_id(iface)
nem_port = self.get_nem_port(iface)
logger.info(
"starting emane for node(%s) iface(%s) nem(%s)",
iface.node.name,
iface.name,
nem_id,
)
config = self.get_iface_config(emane_net, iface)
self.setup_control_channels(nem_id, iface, config)
emanexml.build_platform_xml(nem_id, nem_port, emane_net, iface, config)
self.start_daemon(iface)
self.install_iface(emane_net, iface, config)
def get_start_data(self) -> List[StartData]:
node_map = {}
for node_id in sorted(self._emane_nets):
emane_net = self._emane_nets[node_id]
def get_ifaces(self) -> List[Tuple[EmaneNet, CoreInterface]]:
ifaces = []
for emane_net in self._emane_nets.values():
if not emane_net.model:
logger.error("emane net(%s) has no model", emane_net.name)
continue
@ -358,21 +349,13 @@ class EmaneManager:
iface.name,
)
continue
start_node = node_map.setdefault(iface.node, StartData(iface.node))
start_node.ifaces.append(iface)
start_nodes = sorted(node_map.values(), key=lambda x: x.node.id)
for start_node in start_nodes:
start_node.ifaces = sorted(start_node.ifaces, key=lambda x: x.node_id)
return start_nodes
ifaces.append((emane_net, iface))
return sorted(ifaces, key=lambda x: (x[1].node.id, x[1].node_id))
def setup_control_channels(
self, nem_id: int, node: CoreNodeBase, iface: CoreInterface
self, nem_id: int, iface: CoreInterface, config: Dict[str, str]
) -> None:
if not isinstance(iface.net, EmaneNet):
raise CoreError(
f"emane interface not connected to emane net: {iface.net.name}"
)
config = self.get_iface_config(iface.net, iface)
node = iface.node
# setup ota device
otagroup, _otaport = config["otamanagergroup"].split(":")
otadev = config["otamanagerdevice"]
@ -467,6 +450,8 @@ class EmaneManager:
self._emane_nets.clear()
self.nems_to_ifaces.clear()
self.ifaces_to_nems.clear()
self.nems_to_ifaces.clear()
self.services.clear()
def shutdown(self) -> None:
"""
@ -478,17 +463,19 @@ class EmaneManager:
logger.info("stopping EMANE daemons")
if self.links_enabled():
self.link_monitor.stop()
# shutdown interfaces and stop daemons
kill_emaned = "killall -q emane"
start_data = self.get_start_data()
for data in start_data:
node = data.node
# shutdown interfaces
nodes = set()
for _, iface in self.get_ifaces():
node = iface.node
if not node.up:
continue
for iface in data.ifaces:
if isinstance(node, CoreNode):
iface.shutdown()
iface.poshook = None
nodes.add(node)
if isinstance(node, CoreNode):
iface.shutdown()
iface.poshook = None
kill_emaned = "killall -q emane"
# stop all emane daemons on associated nodes
for node in nodes:
if isinstance(node, CoreNode):
node.cmd(kill_emaned, wait=False)
else:
@ -550,11 +537,14 @@ class EmaneManager:
color=color,
)
def start_daemon(self, node: CoreNodeBase, iface: CoreInterface) -> None:
def start_daemon(self, iface: CoreInterface) -> None:
"""
Start one EMANE daemon per node having a radio.
Add a control network even if the user has not configured one.
Start emane daemon for a given nem/interface.
:param iface: interface to start emane daemon for
:return: nothing
"""
node = iface.node
loglevel = str(DEFAULT_LOG_LEVEL)
cfgloglevel = self.session.options.get_config_int("emane_log_level")
realtime = self.session.options.get_config_bool("emane_realtime", default=True)
@ -576,13 +566,9 @@ class EmaneManager:
args = f"{emanecmd} -f {log_file} {platform_xml}"
node.host_cmd(args, cwd=self.session.directory)
def install_iface(self, iface: CoreInterface) -> None:
emane_net = iface.net
if not isinstance(emane_net, EmaneNet):
raise CoreError(
f"emane interface not connected to emane net: {emane_net.name}"
)
config = self.get_iface_config(emane_net, iface)
def install_iface(
self, emane_net: EmaneNet, iface: CoreInterface, config: Dict[str, str]
) -> None:
external = config.get("external", "0")
if isinstance(iface, TunTap) and external == "0":
iface.set_ips()

View file

@ -17,7 +17,6 @@ from core.xml import corexml
logger = logging.getLogger(__name__)
if TYPE_CHECKING:
from core.emane.emanemanager import EmaneManager
from core.emane.emanemodel import EmaneModel
_MAC_PREFIX = "02:02"
@ -145,33 +144,29 @@ def add_configurations(
def build_platform_xml(
emane_manager: "EmaneManager", nem_id: int, node: CoreNodeBase, iface: CoreInterface
nem_id: int,
nem_port: int,
emane_net: EmaneNet,
iface: CoreInterface,
config: Dict[str, str],
) -> None:
"""
Create platform xml for a specific node.
Create platform xml for a nem/interface.
:param emane_manager: emane manager with emane
configurations
:param nem_id: nem id for current node/interface
:param node: node to create a platform xml for
:param nem_port: control port to configure for emane
:param emane_net: emane network associate with node and interface
:param iface: node interface to create platform xml for
:return: the next nem id that can be used for creating platform xml files
:param config: emane configuration for interface
:return: nothing
"""
# create model based xml files
emane_net = iface.net
if not isinstance(emane_net, EmaneNet):
raise CoreError(f"emane interface not connected to emane net: {emane_net.name}")
config = emane_manager.get_iface_config(emane_net, iface)
emane_net.model.build_xml_files(config, iface)
# create top level platform element
platform_element = etree.Element("platform")
for configuration in emane_net.model.platform_config:
name = configuration.id
value = config[configuration.id]
if name == "controlportendpoint":
port = emane_manager.get_nem_port(iface)
value = f"0.0.0.0:{port}"
value = f"0.0.0.0:{nem_port}"
add_param(platform_element, name, value)
# build nem xml
@ -180,6 +175,9 @@ def build_platform_xml(
"nem", id=str(nem_id), name=iface.localname, definition=nem_definition
)
# create model based xml files
emane_net.model.build_xml_files(config, iface)
# check if this is an external transport
if is_external(config):
nem_element.set("transport", "external")
@ -205,7 +203,7 @@ def build_platform_xml(
doc_name = "platform"
file_name = platform_file_name(iface)
create_node_file(node, platform_element, doc_name, file_name)
create_node_file(iface.node, platform_element, doc_name, file_name)
def create_transport_xml(iface: CoreInterface, config: Dict[str, str]) -> None: