adjustments to remove global emane configuration, platform configurations can now be configured per nem, retrieve emane specific core settings from session options
This commit is contained in:
		
							parent
							
								
									071023b1d9
								
							
						
					
					
						commit
						5bc3345d37
					
				
					 17 changed files with 98 additions and 483 deletions
				
			
		|  | @ -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]: | ||||
|  |  | |||
|  | @ -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, | ||||
|  |  | |||
|  | @ -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: | ||||
|  |  | |||
|  | @ -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) | ||||
|  |  | |||
|  | @ -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(): | ||||
|  |  | |||
|  | @ -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()] | ||||
|         ) | ||||
|  |  | |||
|  | @ -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") | ||||
|  |  | |||
|  | @ -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: | ||||
|         """ | ||||
|  |  | |||
|  | @ -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") | ||||
|  |  | |||
|  | @ -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}" | ||||
|  |  | |||
|  | @ -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) | ||||
|  |  | |||
|  | @ -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<string, string> 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<string, string> options = 14; | ||||
|     string user = 15; | ||||
|     bool definition = 16; | ||||
|     map<string, string> 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<string, string> options = 13; | ||||
|     string user = 14; | ||||
|     bool definition = 15; | ||||
|     map<string, string> metadata = 16; | ||||
|     repeated Server servers = 17; | ||||
| } | ||||
| 
 | ||||
| message StartSessionResponse { | ||||
|  |  | |||
|  | @ -4,23 +4,6 @@ package emane; | |||
| 
 | ||||
| import "core/api/grpc/common.proto"; | ||||
| 
 | ||||
| message GetEmaneConfigRequest { | ||||
|     int32 session_id = 1; | ||||
| } | ||||
| 
 | ||||
| message GetEmaneConfigResponse { | ||||
|     map<string, common.ConfigOption> config = 1; | ||||
| } | ||||
| 
 | ||||
| message SetEmaneConfigRequest { | ||||
|     int32 session_id = 1; | ||||
|     map<string, string> config = 2; | ||||
| } | ||||
| 
 | ||||
| message SetEmaneConfigResponse { | ||||
|     bool result = 1; | ||||
| } | ||||
| 
 | ||||
| message GetEmaneModelConfigRequest { | ||||
|     int32 session_id = 1; | ||||
|     int32 node_id = 2; | ||||
|  |  | |||
|  | @ -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 ' | ||||
|  |  | |||
|  | @ -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() | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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) | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue