daemon: refactoring for starting up and shutting down emane daemon per interface
This commit is contained in:
parent
820539191d
commit
795a5f5865
2 changed files with 60 additions and 76 deletions
|
@ -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()
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in a new issue