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:
Blake Harnden 2021-05-19 20:44:00 -07:00
parent 071023b1d9
commit 5bc3345d37
17 changed files with 98 additions and 483 deletions

View file

@ -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]:

View file

@ -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,

View file

@ -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:

View file

@ -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)

View file

@ -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():

View file

@ -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,22 +301,6 @@ 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
)
@ -354,8 +319,9 @@ class EmaneManager:
status = self.setup()
if status != EmaneState.SUCCESS:
return status
self.initeventservice()
if self.service and self.doeventmonitor():
self.starteventmonitor()
self.buildeventservicexml()
with self._emane_node_lock:
logger.info("emane building xmls...")
start_data = self.get_start_data()
@ -392,13 +358,26 @@ class EmaneManager:
control_net = self.session.add_remove_control_net(
0, remove=False, conf_required=False
)
# 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 = self.config["otamanagergroup"].split(":")
otadev = self.config["otamanagerdevice"]
otagroup, _otaport = config["otamanagergroup"].split(":")
otadev = config["otamanagerdevice"]
otanetidx = self.session.get_control_net_index(otadev)
eventgroup, _eventport = self.config["eventservicegroup"].split(":")
eventdev = self.config["eventservicedevice"]
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(
@ -415,16 +394,17 @@ class EmaneManager:
node, eventservicenetidx, remove=False, conf_required=False
)
# multicast route is needed for OTA data
logger.info("OTA GROUP(%s) OTA DEV(%s)", otagroup, otadev)
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)
# builds xmls and start emane daemons
for iface in data.ifaces:
emanexml.build_platform_xml(self, control_net, node, iface)
self.start_daemon(node, iface)
self.install_iface(iface)
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()]
)

View file

@ -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")

View file

@ -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:
"""

View file

@ -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")

View file

@ -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}"

View file

@ -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)

View file

@ -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 {

View file

@ -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;

View file

@ -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 '

View file

@ -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()

View file

@ -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

View file

@ -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)