diff --git a/daemon/core/api/grpc/client.py b/daemon/core/api/grpc/client.py index b07d2c04..5ebed44e 100644 --- a/daemon/core/api/grpc/client.py +++ b/daemon/core/api/grpc/client.py @@ -28,10 +28,8 @@ from core.api.grpc.configservices_pb2 import ( from core.api.grpc.core_pb2 import ExecuteScriptRequest, GetConfigRequest from core.api.grpc.emane_pb2 import ( EmaneLinkRequest, - GetEmaneConfigRequest, GetEmaneEventChannelRequest, GetEmaneModelConfigRequest, - SetEmaneConfigRequest, SetEmaneModelConfigRequest, ) from core.api.grpc.mobility_pb2 import ( @@ -253,7 +251,6 @@ class CoreGrpcClient: if asymmetric_links: asymmetric_links = [x.to_proto() for x in asymmetric_links] hooks = [x.to_proto() for x in session.hooks.values()] - emane_config = {k: v.value for k, v in session.emane_config.items()} emane_model_configs = [] mobility_configs = [] wlan_configs = [] @@ -313,7 +310,6 @@ class CoreGrpcClient: links=links, location=session.location.to_proto(), hooks=hooks, - emane_config=emane_config, emane_model_configs=emane_model_configs, wlan_configs=wlan_configs, mobility_configs=mobility_configs, @@ -917,31 +913,6 @@ class CoreGrpcClient: response = self.stub.SetWlanConfig(request) return response.result - def get_emane_config(self, session_id: int) -> Dict[str, wrappers.ConfigOption]: - """ - Get session emane configuration. - - :param session_id: session id - :return: response with a list of configuration groups - :raises grpc.RpcError: when session doesn't exist - """ - request = GetEmaneConfigRequest(session_id=session_id) - response = self.stub.GetEmaneConfig(request) - return wrappers.ConfigOption.from_dict(response.config) - - def set_emane_config(self, session_id: int, config: Dict[str, str]) -> bool: - """ - Set session emane configuration. - - :param session_id: session id - :param config: emane configuration - :return: True for success, False otherwise - :raises grpc.RpcError: when session doesn't exist - """ - request = SetEmaneConfigRequest(session_id=session_id, config=config) - response = self.stub.SetEmaneConfig(request) - return response.result - def get_emane_model_config( self, session_id: int, node_id: int, model: str, iface_id: int = -1 ) -> Dict[str, wrappers.ConfigOption]: diff --git a/daemon/core/api/grpc/grpcutils.py b/daemon/core/api/grpc/grpcutils.py index 67e11c5e..169819ba 100644 --- a/daemon/core/api/grpc/grpcutils.py +++ b/daemon/core/api/grpc/grpcutils.py @@ -630,10 +630,6 @@ def get_node_config_service_configs(session: Session) -> List[ConfigServiceConfi return configs -def get_emane_config(session: Session) -> Dict[str, common_pb2.ConfigOption]: - return get_config_options(session.emane.config, session.emane.emane_config) - - def get_mobility_node( session: Session, node_id: int, context: ServicerContext ) -> Union[WlanNode, EmaneNet]: @@ -663,7 +659,6 @@ def convert_session(session: Session) -> wrappers.Session: x=x, y=y, z=z, lat=lat, lon=lon, alt=alt, scale=session.location.refscale ) hooks = get_hooks(session) - emane_config = get_emane_config(session) emane_model_configs = get_emane_model_configs(session) wlan_configs = get_wlan_configs(session) mobility_configs = get_mobility_configs(session) @@ -685,7 +680,6 @@ def convert_session(session: Session) -> wrappers.Session: default_services=default_services, location=location, hooks=hooks, - emane_config=emane_config, emane_model_configs=emane_model_configs, wlan_configs=wlan_configs, service_configs=service_configs, diff --git a/daemon/core/api/grpc/server.py b/daemon/core/api/grpc/server.py index 8b5c5c1f..e2851964 100644 --- a/daemon/core/api/grpc/server.py +++ b/daemon/core/api/grpc/server.py @@ -33,14 +33,10 @@ from core.api.grpc.emane_pb2 import ( EmaneLinkResponse, EmanePathlossesRequest, EmanePathlossesResponse, - GetEmaneConfigRequest, - GetEmaneConfigResponse, GetEmaneEventChannelRequest, GetEmaneEventChannelResponse, GetEmaneModelConfigRequest, GetEmaneModelConfigResponse, - SetEmaneConfigRequest, - SetEmaneConfigResponse, SetEmaneModelConfigRequest, SetEmaneModelConfigResponse, ) @@ -266,7 +262,6 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer): return core_pb2.StartSessionResponse(result=False, exceptions=exceptions) # emane configs - session.emane.config.update(request.emane_config) for config in request.emane_model_configs: _id = utils.iface_config_id(config.node_id, config.iface_id) session.emane.set_config(_id, config.model, config.config) @@ -1045,36 +1040,6 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer): node.updatemodel(config) return SetWlanConfigResponse(result=True) - def GetEmaneConfig( - self, request: GetEmaneConfigRequest, context: ServicerContext - ) -> GetEmaneConfigResponse: - """ - Retrieve EMANE configuration of a session - - :param request: get-EMANE-configuration request - :param context: context object - :return: get-EMANE-configuration response - """ - logger.debug("get emane config: %s", request) - session = self.get_session(request.session_id, context) - config = grpcutils.get_emane_config(session) - return GetEmaneConfigResponse(config=config) - - def SetEmaneConfig( - self, request: SetEmaneConfigRequest, context: ServicerContext - ) -> SetEmaneConfigResponse: - """ - Set EMANE configuration of a session - - :param request: set-EMANE-configuration request - :param context: context object - :return: set-EMANE-configuration response - """ - logger.debug("set emane config: %s", request) - session = self.get_session(request.session_id, context) - session.emane.config.update(request.config) - return SetEmaneConfigResponse(result=True) - def GetEmaneModelConfig( self, request: GetEmaneModelConfigRequest, context: ServicerContext ) -> GetEmaneModelConfigResponse: diff --git a/daemon/core/api/grpc/wrappers.py b/daemon/core/api/grpc/wrappers.py index a0277edd..802af3c3 100644 --- a/daemon/core/api/grpc/wrappers.py +++ b/daemon/core/api/grpc/wrappers.py @@ -783,7 +783,6 @@ class Session: x=0.0, y=0.0, z=0.0, lat=47.57917, lon=-122.13232, alt=2.0, scale=150.0 ) hooks: Dict[str, Hook] = field(default_factory=dict) - emane_config: Dict[str, ConfigOption] = field(default_factory=dict) metadata: Dict[str, str] = field(default_factory=dict) file: Path = None options: Dict[str, ConfigOption] = field(default_factory=dict) @@ -836,7 +835,6 @@ class Session: default_services=default_services, location=SessionLocation.from_proto(proto.location), hooks=hooks, - emane_config=ConfigOption.from_dict(proto.emane_config), metadata=dict(proto.metadata), file=file_path, options=options, @@ -889,11 +887,6 @@ class Session: self.links.append(link) return link - def set_emane(self, config: Dict[str, str]) -> None: - for key, value in config.items(): - option = ConfigOption(name=key, value=value) - self.emane_config[key] = option - def set_options(self, config: Dict[str, str]) -> None: for key, value in config.items(): option = ConfigOption(name=key, value=value) diff --git a/daemon/core/api/tlv/corehandlers.py b/daemon/core/api/tlv/corehandlers.py index 527924c1..a1c1d34a 100644 --- a/daemon/core/api/tlv/corehandlers.py +++ b/daemon/core/api/tlv/corehandlers.py @@ -1046,8 +1046,6 @@ class CoreHandler(socketserver.BaseRequestHandler): self.handle_config_mobility(message_type, config_data) elif config_data.object in self.session.mobility.models: replies = self.handle_config_mobility_models(message_type, config_data) - elif config_data.object == self.session.emane.name: - replies = self.handle_config_emane(message_type, config_data) elif config_data.object in EmaneModelManager.models: replies = self.handle_config_emane_models(message_type, config_data) else: @@ -1379,36 +1377,6 @@ class CoreHandler(socketserver.BaseRequestHandler): return replies - def handle_config_emane(self, message_type, config_data): - replies = [] - node_id = config_data.node - object_name = config_data.object - iface_id = config_data.iface_id - values_str = config_data.data_values - - node_id = utils.iface_config_id(node_id, iface_id) - logger.debug( - "received configure message for %s nodenum: %s", object_name, node_id - ) - if message_type == ConfigFlags.REQUEST: - logger.info("replying to configure request for %s model", object_name) - typeflags = ConfigFlags.NONE.value - config = self.session.emane.config - config_response = ConfigShim.config_data( - 0, node_id, typeflags, self.session.emane.emane_config, config - ) - replies.append(config_response) - elif message_type != ConfigFlags.RESET: - if not object_name: - logger.info("no configuration object for node %s", node_id) - return [] - - if values_str: - config = ConfigShim.str_to_dict(values_str) - self.session.emane.config = config - - return replies - def handle_config_emane_models(self, message_type, config_data): replies = [] node_id = config_data.node @@ -1851,14 +1819,6 @@ class CoreHandler(socketserver.BaseRequestHandler): ) self.session.broadcast_config(config_data) - # send global emane config - config = self.session.emane.config - logger.debug("global emane config: values(%s)", config) - config_data = ConfigShim.config_data( - 0, None, ConfigFlags.UPDATE.value, self.session.emane.emane_config, config - ) - self.session.broadcast_config(config_data) - # send emane model configs for node_id, model_configs in self.session.emane.node_configs.items(): for model_name, config in model_configs.items(): diff --git a/daemon/core/emane/emanemanager.py b/daemon/core/emane/emanemanager.py index 337cd0de..b952d942 100644 --- a/daemon/core/emane/emanemanager.py +++ b/daemon/core/emane/emanemanager.py @@ -1,30 +1,21 @@ """ -emane.py: definition of an Emane class for implementing configuration control of an EMANE emulation. +Implements configuration and control of an EMANE emulation. """ import logging import os import threading -from collections import OrderedDict from dataclasses import dataclass, field from enum import Enum -from pathlib import Path from typing import TYPE_CHECKING, Dict, List, Optional, Set, Tuple, Type from core import utils -from core.config import ConfigGroup, Configuration -from core.emane import emanemanifest from core.emane.emanemodel import EmaneModel from core.emane.linkmonitor import EmaneLinkMonitor from core.emane.modelmanager import EmaneModelManager from core.emane.nodes import EmaneNet from core.emulator.data import LinkData -from core.emulator.enumerations import ( - ConfigDataTypes, - LinkTypes, - MessageFlags, - RegisterTlvs, -) +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.interface import CoreInterface, TunTap @@ -102,8 +93,6 @@ class EmaneManager: self.eventmonthread: Optional[threading.Thread] = None # model for global EMANE configuration options - self.emane_config: EmaneGlobalModel = EmaneGlobalModel(session) - self.config: Dict[str, str] = self.emane_config.default_values() self.node_configs: Dict[int, Dict[str, Dict[str, str]]] = {} self.node_models: Dict[int, str] = {} @@ -115,7 +104,7 @@ class EmaneManager: self.event_device: Optional[str] = None def next_nem_id(self, iface: CoreInterface) -> int: - nem_id = int(self.config["nem_id_start"]) + nem_id = self.session.options.get_config_int("nem_id_start") while nem_id in self.nems_to_ifaces: nem_id += 1 self.nems_to_ifaces[nem_id] = iface @@ -206,7 +195,6 @@ class EmaneManager: def config_reset(self, node_id: int = None) -> None: if node_id is None: - self.config = self.emane_config.default_values() self.node_configs.clear() self.node_models.clear() else: @@ -224,25 +212,20 @@ class EmaneManager: self.service = None self.event_device = None - def initeventservice(self, filename: str = None, shutdown: bool = False) -> None: + def initeventservice(self) -> None: """ Re-initialize the EMANE Event service. The multicast group and/or port may be configured. """ - self.deleteeventservice() - if shutdown: - return - # Get the control network to be used for events - group, port = self.config["eventservicegroup"].split(":") - self.event_device = self.config["eventservicedevice"] + group, port = "224.1.2.8:45703".split(":") + self.event_device = DEFAULT_DEV eventnetidx = self.session.get_control_net_index(self.event_device) if eventnetidx < 0: logger.error( "invalid emane event service device provided: %s", self.event_device ) return - # make sure the event control network is in place eventnet = self.session.add_remove_control_net( net_index=eventnetidx, remove=False, conf_required=False @@ -251,14 +234,13 @@ class EmaneManager: # direct EMANE events towards control net bridge self.event_device = eventnet.brname self.eventchannel = (group, int(port), self.event_device) - # disabled otachannel for event service # only needed for e.g. antennaprofile events xmit by models - logger.info("using %s for event service traffic", self.event_device) + logger.info("using %s for emane event service", self.event_device) try: self.service = EventService(eventchannel=self.eventchannel, otachannel=None) except EventServiceException: - logger.exception("error instantiating emane EventService") + logger.exception("error starting emane event service") def add_node(self, emane_net: EmaneNet) -> None: """ @@ -309,9 +291,8 @@ class EmaneManager: if EventService is None: raise CoreError("EMANE python bindings are not installed") - # control network bridge required for EMANE 0.9.2 - # - needs to exist when eventservice binds to it (initeventservice) - otadev = self.config["otamanagerdevice"] + # control network bridge required for emane + otadev = DEFAULT_DEV netidx = self.session.get_control_net_index(otadev) logger.debug("emane ota manager device: index(%s) otadev(%s)", netidx, otadev) if netidx < 0: @@ -320,25 +301,9 @@ class EmaneManager: otadev, ) return EmaneState.NOT_READY - self.session.add_remove_control_net( net_index=netidx, remove=False, conf_required=False ) - eventdev = self.config["eventservicedevice"] - logger.debug("emane event service device: eventdev(%s)", eventdev) - if eventdev != otadev: - netidx = self.session.get_control_net_index(eventdev) - logger.debug("emane event service device index: %s", netidx) - if netidx < 0: - logger.error( - "emane cannot start due to invalid event service device: %s", - eventdev, - ) - return EmaneState.NOT_READY - - self.session.add_remove_control_net( - net_index=netidx, remove=False, conf_required=False - ) self.check_node_models() return EmaneState.SUCCESS @@ -354,8 +319,9 @@ class EmaneManager: status = self.setup() if status != EmaneState.SUCCESS: return status - self.starteventmonitor() - self.buildeventservicexml() + self.initeventservice() + if self.service and self.doeventmonitor(): + self.starteventmonitor() with self._emane_node_lock: logger.info("emane building xmls...") start_data = self.get_start_data() @@ -392,40 +358,54 @@ class EmaneManager: control_net = self.session.add_remove_control_net( 0, remove=False, conf_required=False ) - if isinstance(node, CoreNode): - # setup ota device - otagroup, _otaport = self.config["otamanagergroup"].split(":") - otadev = self.config["otamanagerdevice"] - otanetidx = self.session.get_control_net_index(otadev) - eventgroup, _eventport = self.config["eventservicegroup"].split(":") - eventdev = self.config["eventservicedevice"] - eventservicenetidx = self.session.get_control_net_index(eventdev) - # control network not yet started here - self.session.add_remove_control_iface( - node, 0, remove=False, conf_required=False - ) - if otanetidx > 0: - logger.info("adding ota device ctrl%d", otanetidx) - self.session.add_remove_control_iface( - node, otanetidx, remove=False, conf_required=False - ) - if eventservicenetidx >= 0: - logger.info("adding event service device ctrl%d", eventservicenetidx) - self.session.add_remove_control_iface( - node, eventservicenetidx, remove=False, conf_required=False - ) - # multicast route is needed for OTA data - logger.info("OTA GROUP(%s) OTA DEV(%s)", otagroup, otadev) - node.node_net_client.create_route(otagroup, otadev) - # multicast route is also needed for event data if on control network - if eventservicenetidx >= 0 and eventgroup != otagroup: - node.node_net_client.create_route(eventgroup, eventdev) # builds xmls and start emane daemons for iface in data.ifaces: + if isinstance(node, CoreNode): + self.setup_ota(node, iface) emanexml.build_platform_xml(self, control_net, node, iface) self.start_daemon(node, iface) self.install_iface(iface) + def setup_ota(self, node: CoreNode, iface: CoreInterface) -> 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) + # setup ota device + otagroup, _otaport = config["otamanagergroup"].split(":") + otadev = config["otamanagerdevice"] + otanetidx = self.session.get_control_net_index(otadev) + eventgroup, _eventport = config["eventservicegroup"].split(":") + eventdev = config["eventservicedevice"] + eventservicenetidx = self.session.get_control_net_index(eventdev) + # control network not yet started here + self.session.add_remove_control_iface( + node, 0, remove=False, conf_required=False + ) + if otanetidx > 0: + logger.info("adding ota device ctrl%d", otanetidx) + self.session.add_remove_control_iface( + node, otanetidx, remove=False, conf_required=False + ) + if eventservicenetidx >= 0: + logger.info("adding event service device ctrl%d", eventservicenetidx) + self.session.add_remove_control_iface( + node, eventservicenetidx, remove=False, conf_required=False + ) + # multicast route is needed for OTA data + logger.info( + "node(%s) interface(%s) ota group(%s) dev(%s)", + node.name, + iface.name, + otagroup, + otadev, + ) + node.node_net_client.create_route(otagroup, otadev) + # multicast route is also needed for event data if on control network + if eventservicenetidx >= 0 and eventgroup != otagroup: + node.node_net_client.create_route(eventgroup, eventdev) + def get_iface(self, nem_id: int) -> Optional[CoreInterface]: return self.nems_to_ifaces.get(nem_id) @@ -445,7 +425,7 @@ class EmaneManager: logger.exception("error writing to emane nem file") def links_enabled(self) -> bool: - return self.config["link_enabled"] == "1" + return self.session.options.get_config_int("link_enabled") == 1 def poststartup(self) -> None: """ @@ -551,35 +531,6 @@ class EmaneManager: color=color, ) - def buildeventservicexml(self) -> None: - """ - Build the libemaneeventservice.xml file if event service options - were changed in the global config. - """ - need_xml = False - default_values = self.emane_config.default_values() - for name in ["eventservicegroup", "eventservicedevice"]: - a = default_values[name] - b = self.config[name] - if a != b: - need_xml = True - if not need_xml: - # reset to using default config - self.initeventservice() - return - try: - group, port = self.config["eventservicegroup"].split(":") - except ValueError: - logger.exception("invalid eventservicegroup in EMANE config") - return - dev = self.config["eventservicedevice"] - emanexml.create_event_service_xml(group, port, dev, self.session.directory) - self.session.distributed.execute( - lambda x: emanexml.create_event_service_xml( - group, port, dev, self.session.directory, x - ) - ) - def start_daemon(self, node: CoreNodeBase, iface: CoreInterface) -> None: """ Start one EMANE daemon per node having a radio. @@ -648,17 +599,7 @@ class EmaneManager: """ Start monitoring EMANE location events if configured to do so. """ - logger.info("emane start event monitor") - if not self.doeventmonitor(): - return - if self.service is None: - logger.error( - "Warning: EMANE events will not be generated " - "because the emaneeventservice\n binding was " - "unable to load " - "(install the python-emaneeventservice bindings)" - ) - return + logger.info("starting emane event monitor") self.doeventloop = True self.eventmonthread = threading.Thread( target=self.eventmonitorloop, daemon=True @@ -673,8 +614,7 @@ class EmaneManager: if self.service is not None: self.service.breakloop() # reset the service, otherwise nextEvent won"t work - self.initeventservice(shutdown=True) - + self.deleteeventservice() if self.eventmonthread is not None: self.eventmonthread.join() self.eventmonthread = None @@ -685,26 +625,17 @@ class EmaneManager: """ if self.service is None: return - logger.info( - "subscribing to EMANE location events. (%s)", - threading.currentThread().getName(), - ) - while self.doeventloop is True: + logger.info("subscribing to EMANE location events") + while self.doeventloop: _uuid, _seq, events = self.service.nextEvent() - # this occurs with 0.9.1 event service if not self.doeventloop: break - for event in events: nem, eid, data = event if eid == LocationEvent.IDENTIFIER: self.handlelocationevent(nem, eid, data) - - logger.info( - "unsubscribing from EMANE location events. (%s)", - threading.currentThread().getName(), - ) + logger.info("unsubscribing from EMANE location events") def handlelocationevent(self, rxnemid: int, eid: int, data: str) -> None: """ @@ -818,85 +749,3 @@ class EmaneManager: event.append(nem2, forward=rx2) self.service.publish(nem1, event) self.service.publish(nem2, event) - - -class EmaneGlobalModel: - """ - Global EMANE configuration options. - """ - - name: str = "emane" - bitmap: Optional[str] = None - - def __init__(self, session: "Session") -> None: - self.session: "Session" = session - self.core_config: List[Configuration] = [ - Configuration( - id="platform_id_start", - type=ConfigDataTypes.INT32, - default="1", - label="Starting Platform ID", - ), - Configuration( - id="nem_id_start", - type=ConfigDataTypes.INT32, - default="1", - label="Starting NEM ID", - ), - Configuration( - id="link_enabled", - type=ConfigDataTypes.BOOL, - default="1", - label="Enable Links?", - ), - Configuration( - id="loss_threshold", - type=ConfigDataTypes.INT32, - default="30", - label="Link Loss Threshold (%)", - ), - Configuration( - id="link_interval", - type=ConfigDataTypes.INT32, - default="1", - label="Link Check Interval (sec)", - ), - Configuration( - id="link_timeout", - type=ConfigDataTypes.INT32, - default="4", - label="Link Timeout (sec)", - ), - ] - self.emulator_config = None - self.parse_config() - - def parse_config(self) -> None: - emane_prefix = self.session.options.get_config( - "emane_prefix", default=DEFAULT_EMANE_PREFIX - ) - emane_prefix = Path(emane_prefix) - emulator_xml = emane_prefix / "share/emane/manifest/nemmanager.xml" - emulator_defaults = { - "eventservicedevice": DEFAULT_DEV, - "eventservicegroup": "224.1.2.8:45703", - "otamanagerdevice": DEFAULT_DEV, - "otamanagergroup": "224.1.2.8:45702", - } - self.emulator_config = emanemanifest.parse(emulator_xml, emulator_defaults) - - def configurations(self) -> List[Configuration]: - return self.emulator_config + self.core_config - - def config_groups(self) -> List[ConfigGroup]: - emulator_len = len(self.emulator_config) - config_len = len(self.configurations()) - return [ - ConfigGroup("Platform Attributes", 1, emulator_len), - ConfigGroup("CORE Configuration", emulator_len + 1, config_len), - ] - - def default_values(self) -> Dict[str, str]: - return OrderedDict( - [(config.id, config.default) for config in self.configurations()] - ) diff --git a/daemon/core/emane/linkmonitor.py b/daemon/core/emane/linkmonitor.py index fd27c51d..9b18bae2 100644 --- a/daemon/core/emane/linkmonitor.py +++ b/daemon/core/emane/linkmonitor.py @@ -189,9 +189,10 @@ class EmaneLinkMonitor: self.running: bool = False def start(self) -> None: - self.loss_threshold = int(self.emane_manager.config["loss_threshold"]) - self.link_interval = int(self.emane_manager.config["link_interval"]) - self.link_timeout = int(self.emane_manager.config["link_timeout"]) + options = self.emane_manager.session.options + self.loss_threshold = options.get_config_int("loss_threshold") + self.link_interval = options.get_config_int("link_interval") + self.link_timeout = options.get_config_int("link_timeout") self.initialize() if not self.clients: logger.info("no valid emane models to monitor links") diff --git a/daemon/core/nodes/netclient.py b/daemon/core/nodes/netclient.py index 729550b6..c066910b 100644 --- a/daemon/core/nodes/netclient.py +++ b/daemon/core/nodes/netclient.py @@ -38,7 +38,7 @@ class LinuxNetClient: :param device: device to add route to :return: nothing """ - self.run(f"{IP} route add {route} dev {device}") + self.run(f"{IP} route replace {route} dev {device}") def device_up(self, device: str) -> None: """ diff --git a/daemon/core/xml/corexml.py b/daemon/core/xml/corexml.py index 629750bf..647300fc 100644 --- a/daemon/core/xml/corexml.py +++ b/daemon/core/xml/corexml.py @@ -80,20 +80,6 @@ def create_iface_data(iface_element: etree.Element) -> InterfaceData: ) -def create_emane_config(session: "Session") -> etree.Element: - emane_configuration = etree.Element("emane_global_configuration") - config = session.emane.config - emulator_element = etree.SubElement(emane_configuration, "emulator") - for emulator_config in session.emane.emane_config.emulator_config: - value = config[emulator_config.id] - add_configuration(emulator_element, emulator_config.id, value) - core_element = etree.SubElement(emane_configuration, "core") - for core_config in session.emane.emane_config.core_config: - value = config[core_config.id] - add_configuration(core_element, core_config.id, value) - return emane_configuration - - def create_emane_model_config( node_id: int, model: "EmaneModelType", @@ -104,22 +90,22 @@ def create_emane_model_config( add_attribute(emane_element, "node", node_id) add_attribute(emane_element, "iface", iface_id) add_attribute(emane_element, "model", model.name) - + platform_element = etree.SubElement(emane_element, "platform") + for platform_config in model.platform_config: + value = config[platform_config.id] + add_configuration(platform_element, platform_config.id, value) mac_element = etree.SubElement(emane_element, "mac") for mac_config in model.mac_config: value = config[mac_config.id] add_configuration(mac_element, mac_config.id, value) - phy_element = etree.SubElement(emane_element, "phy") for phy_config in model.phy_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 @@ -376,8 +362,6 @@ class CoreXmlWriter: self.scenario.append(metadata_elements) def write_emane_configs(self) -> None: - emane_global_configuration = create_emane_config(self.session) - self.scenario.append(emane_global_configuration) emane_configurations = etree.Element("emane_configurations") for node_id, model_configs in self.session.emane.node_configs.items(): node_id, iface_id = utils.parse_iface_config_id(node_id) @@ -591,7 +575,6 @@ class CoreXmlReader: self.read_session_origin() self.read_service_configs() self.read_mobility_configs() - self.read_emane_global_config() self.read_nodes() self.read_links() self.read_emane_configs() @@ -729,28 +712,10 @@ class CoreXmlReader: files.add(name) service.configs = tuple(files) - def read_emane_global_config(self) -> None: - emane_global_configuration = self.scenario.find("emane_global_configuration") - if emane_global_configuration is None: - return - emulator_configuration = emane_global_configuration.find("emulator") - configs = {} - for config in emulator_configuration.iterchildren(): - name = config.get("name") - value = config.get("value") - configs[name] = value - core_configuration = emane_global_configuration.find("core") - for config in core_configuration.iterchildren(): - name = config.get("name") - value = config.get("value") - configs[name] = value - self.session.emane.config = configs - def read_emane_configs(self) -> None: emane_configurations = self.scenario.find("emane_configurations") if emane_configurations is None: return - for emane_configuration in emane_configurations.iterchildren(): node_id = get_int(emane_configuration, "node") iface_id = get_int(emane_configuration, "iface") @@ -768,18 +733,21 @@ class CoreXmlReader: ) # read and set emane model configuration + platform_configuration = emane_configuration.find("platform") + for config in platform_configuration.iterchildren(): + name = config.get("name") + value = config.get("value") + configs[name] = value mac_configuration = emane_configuration.find("mac") for config in mac_configuration.iterchildren(): name = config.get("name") value = config.get("value") configs[name] = value - phy_configuration = emane_configuration.find("phy") for config in phy_configuration.iterchildren(): name = config.get("name") value = config.get("value") configs[name] = value - external_configuration = emane_configuration.find("external") for config in external_configuration.iterchildren(): name = config.get("name") diff --git a/daemon/core/xml/emanexml.py b/daemon/core/xml/emanexml.py index 88c5aa38..97646699 100644 --- a/daemon/core/xml/emanexml.py +++ b/daemon/core/xml/emanexml.py @@ -162,7 +162,7 @@ def build_platform_xml( :param iface: node interface to create platform xml for :return: the next nem id that can be used for creating platform xml files """ - # create nem xml entries for all interfaces + # 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}") @@ -173,12 +173,12 @@ def build_platform_xml( # create top level platform element transport_configs = {"otamanagerdevice", "eventservicedevice"} platform_element = etree.Element("platform") - for configuration in emane_manager.emane_config.emulator_config: + for configuration in emane_net.model.platform_config: name = configuration.id if not isinstance(node, CoreNode) and name in transport_configs: value = control_net.brname else: - value = emane_manager.config[name] + value = config[configuration.id] if name == "controlportendpoint": port = emane_manager.get_nem_port(iface) value = f"0.0.0.0:{port}" diff --git a/daemon/examples/grpc/emane80211.py b/daemon/examples/grpc/emane80211.py index fbafbe07..00c5458f 100644 --- a/daemon/examples/grpc/emane80211.py +++ b/daemon/examples/grpc/emane80211.py @@ -30,8 +30,9 @@ iface1 = iface_helper.create_iface(node2.id, 0) session.add_link(node1=node2, node2=emane, iface1=iface1) # setup emane configurations using a dict mapping currently support values as strings -session.set_emane({"eventservicettl": "2"}) -emane.set_emane_model(EmaneIeee80211abgModel.name, {"unicastrate": "3"}) +emane.set_emane_model( + EmaneIeee80211abgModel.name, {"eventservicettl": "2", "unicastrate": "3"} +) # start session core.start_session(session) diff --git a/daemon/proto/core/api/grpc/core.proto b/daemon/proto/core/api/grpc/core.proto index ce66b038..3c703866 100644 --- a/daemon/proto/core/api/grpc/core.proto +++ b/daemon/proto/core/api/grpc/core.proto @@ -95,10 +95,6 @@ service CoreApi { } // emane rpc - rpc GetEmaneConfig (emane.GetEmaneConfigRequest) returns (emane.GetEmaneConfigResponse) { - } - rpc SetEmaneConfig (emane.SetEmaneConfigRequest) returns (emane.SetEmaneConfigResponse) { - } rpc GetEmaneModelConfig (emane.GetEmaneModelConfigRequest) returns (emane.GetEmaneModelConfigResponse) { } rpc SetEmaneModelConfig (emane.SetEmaneModelConfigRequest) returns (emane.SetEmaneModelConfigResponse) { @@ -144,19 +140,18 @@ message StartSessionRequest { repeated Link links = 3; repeated Hook hooks = 4; SessionLocation location = 5; - map emane_config = 6; - repeated wlan.WlanConfig wlan_configs = 7; - repeated emane.EmaneModelConfig emane_model_configs = 8; - repeated mobility.MobilityConfig mobility_configs = 9; - repeated services.ServiceConfig service_configs = 10; - repeated services.ServiceFileConfig service_file_configs = 11; - repeated Link asymmetric_links = 12; - repeated configservices.ConfigServiceConfig config_service_configs = 13; - map options = 14; - string user = 15; - bool definition = 16; - map metadata = 17; - repeated Server servers = 18; + repeated wlan.WlanConfig wlan_configs = 6; + repeated emane.EmaneModelConfig emane_model_configs = 7; + repeated mobility.MobilityConfig mobility_configs = 8; + repeated services.ServiceConfig service_configs = 9; + repeated services.ServiceFileConfig service_file_configs = 10; + repeated Link asymmetric_links = 11; + repeated configservices.ConfigServiceConfig config_service_configs = 12; + map options = 13; + string user = 14; + bool definition = 15; + map metadata = 16; + repeated Server servers = 17; } message StartSessionResponse { diff --git a/daemon/proto/core/api/grpc/emane.proto b/daemon/proto/core/api/grpc/emane.proto index de739891..1e56a0aa 100644 --- a/daemon/proto/core/api/grpc/emane.proto +++ b/daemon/proto/core/api/grpc/emane.proto @@ -4,23 +4,6 @@ package emane; import "core/api/grpc/common.proto"; -message GetEmaneConfigRequest { - int32 session_id = 1; -} - -message GetEmaneConfigResponse { - map config = 1; -} - -message SetEmaneConfigRequest { - int32 session_id = 1; - map config = 2; -} - -message SetEmaneConfigResponse { - bool result = 1; -} - message GetEmaneModelConfigRequest { int32 session_id = 1; int32 node_id = 2; diff --git a/daemon/scripts/core-cleanup b/daemon/scripts/core-cleanup index c97d6843..ced76634 100755 --- a/daemon/scripts/core-cleanup +++ b/daemon/scripts/core-cleanup @@ -61,6 +61,7 @@ eval "$ifcommand" | awk ' /tmp\./ {print "removing interface " $1; system("ip link del " $1);} /gt\./ {print "removing interface " $1; system("ip link del " $1);} /b\./ {print "removing bridge " $1; system("ip link set " $1 " down; ip link del " $1);} + /ctrl[0-9]+\./ {print "removing bridge " $1; system("ip link set " $1 " down; ip link del " $1);} ' nft list ruleset | awk ' diff --git a/daemon/tests/test_grpc.py b/daemon/tests/test_grpc.py index e836251e..ebfe29eb 100644 --- a/daemon/tests/test_grpc.py +++ b/daemon/tests/test_grpc.py @@ -83,11 +83,6 @@ class TestGrpc: scale=location_scale, ) - # setup global emane config - emane_config_key = "platform_id_start" - emane_config_value = "2" - session.set_emane({emane_config_key: emane_config_value}) - # setup wlan config wlan_config_key = "range" wlan_config_value = "333" @@ -151,7 +146,6 @@ class TestGrpc: location_alt, ) assert real_session.location.refscale == location_scale - assert real_session.emane.config[emane_config_key] == emane_config_value set_wlan_config = real_session.mobility.get_model_config( wlan_node.id, BasicRangeModel.name ) @@ -518,35 +512,6 @@ class TestGrpc: assert config[range_key] == range_value assert wlan.model.range == int(range_value) - def test_get_emane_config(self, grpc_server: CoreGrpcServer): - # given - client = CoreGrpcClient() - session = grpc_server.coreemu.create_session() - - # then - with client.context_connect(): - config = client.get_emane_config(session.id) - - # then - assert len(config) > 0 - - def test_set_emane_config(self, grpc_server: CoreGrpcServer): - # given - client = CoreGrpcClient() - session = grpc_server.coreemu.create_session() - config_key = "platform_id_start" - config_value = "2" - - # then - with client.context_connect(): - result = client.set_emane_config(session.id, {config_key: config_value}) - - # then - assert result is True - config = session.emane.config - assert len(config) > 1 - assert config[config_key] == config_value - def test_set_emane_model_config(self, grpc_server: CoreGrpcServer): # given client = CoreGrpcClient() diff --git a/daemon/tests/test_gui.py b/daemon/tests/test_gui.py index 7b8a987d..5f4ab487 100644 --- a/daemon/tests/test_gui.py +++ b/daemon/tests/test_gui.py @@ -941,35 +941,3 @@ class TestGui: config = coretlv.session.emane.get_config(wlan.id, EmaneIeee80211abgModel.name) assert config[config_key] == config_value - - def test_config_emane_request(self, coretlv: CoreHandler): - message = coreapi.CoreConfMessage.create( - 0, - [ - (ConfigTlvs.OBJECT, "emane"), - (ConfigTlvs.TYPE, ConfigFlags.REQUEST.value), - ], - ) - coretlv.handle_broadcast_config = mock.MagicMock() - - coretlv.handle_message(message) - - coretlv.handle_broadcast_config.assert_called_once() - - def test_config_emane_update(self, coretlv: CoreHandler): - config_key = "eventservicedevice" - config_value = "eth4" - values = {config_key: config_value} - message = coreapi.CoreConfMessage.create( - 0, - [ - (ConfigTlvs.OBJECT, "emane"), - (ConfigTlvs.TYPE, ConfigFlags.UPDATE.value), - (ConfigTlvs.VALUES, dict_to_str(values)), - ], - ) - - coretlv.handle_message(message) - - config = coretlv.session.emane.config - assert config[config_key] == config_value diff --git a/docs/grpc.md b/docs/grpc.md index 5cc0e7ae..aef79308 100644 --- a/docs/grpc.md +++ b/docs/grpc.md @@ -328,10 +328,11 @@ session.add_link(node1=node1, node2=emane, iface1=iface1) iface1 = iface_helper.create_iface(node2.id, 0) session.add_link(node1=node2, node2=emane, iface1=iface1) -# setting global emane configuration -session.set_emane({"eventservicettl": "2"}) # setting emane specific emane model configuration -emane.set_emane_model(EmaneIeee80211abgModel.name, {"unicastrate": "3"}) +emane.set_emane_model(EmaneIeee80211abgModel.name, { + "eventservicettl": "2", + "unicastrate": "3", +}) # start session core.start_session(session)