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.core_pb2 import ExecuteScriptRequest, GetConfigRequest
|
||||||
from core.api.grpc.emane_pb2 import (
|
from core.api.grpc.emane_pb2 import (
|
||||||
EmaneLinkRequest,
|
EmaneLinkRequest,
|
||||||
GetEmaneConfigRequest,
|
|
||||||
GetEmaneEventChannelRequest,
|
GetEmaneEventChannelRequest,
|
||||||
GetEmaneModelConfigRequest,
|
GetEmaneModelConfigRequest,
|
||||||
SetEmaneConfigRequest,
|
|
||||||
SetEmaneModelConfigRequest,
|
SetEmaneModelConfigRequest,
|
||||||
)
|
)
|
||||||
from core.api.grpc.mobility_pb2 import (
|
from core.api.grpc.mobility_pb2 import (
|
||||||
|
@ -253,7 +251,6 @@ class CoreGrpcClient:
|
||||||
if asymmetric_links:
|
if asymmetric_links:
|
||||||
asymmetric_links = [x.to_proto() for x in asymmetric_links]
|
asymmetric_links = [x.to_proto() for x in asymmetric_links]
|
||||||
hooks = [x.to_proto() for x in session.hooks.values()]
|
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 = []
|
emane_model_configs = []
|
||||||
mobility_configs = []
|
mobility_configs = []
|
||||||
wlan_configs = []
|
wlan_configs = []
|
||||||
|
@ -313,7 +310,6 @@ class CoreGrpcClient:
|
||||||
links=links,
|
links=links,
|
||||||
location=session.location.to_proto(),
|
location=session.location.to_proto(),
|
||||||
hooks=hooks,
|
hooks=hooks,
|
||||||
emane_config=emane_config,
|
|
||||||
emane_model_configs=emane_model_configs,
|
emane_model_configs=emane_model_configs,
|
||||||
wlan_configs=wlan_configs,
|
wlan_configs=wlan_configs,
|
||||||
mobility_configs=mobility_configs,
|
mobility_configs=mobility_configs,
|
||||||
|
@ -917,31 +913,6 @@ class CoreGrpcClient:
|
||||||
response = self.stub.SetWlanConfig(request)
|
response = self.stub.SetWlanConfig(request)
|
||||||
return response.result
|
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(
|
def get_emane_model_config(
|
||||||
self, session_id: int, node_id: int, model: str, iface_id: int = -1
|
self, session_id: int, node_id: int, model: str, iface_id: int = -1
|
||||||
) -> Dict[str, wrappers.ConfigOption]:
|
) -> Dict[str, wrappers.ConfigOption]:
|
||||||
|
|
|
@ -630,10 +630,6 @@ def get_node_config_service_configs(session: Session) -> List[ConfigServiceConfi
|
||||||
return configs
|
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(
|
def get_mobility_node(
|
||||||
session: Session, node_id: int, context: ServicerContext
|
session: Session, node_id: int, context: ServicerContext
|
||||||
) -> Union[WlanNode, EmaneNet]:
|
) -> 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
|
x=x, y=y, z=z, lat=lat, lon=lon, alt=alt, scale=session.location.refscale
|
||||||
)
|
)
|
||||||
hooks = get_hooks(session)
|
hooks = get_hooks(session)
|
||||||
emane_config = get_emane_config(session)
|
|
||||||
emane_model_configs = get_emane_model_configs(session)
|
emane_model_configs = get_emane_model_configs(session)
|
||||||
wlan_configs = get_wlan_configs(session)
|
wlan_configs = get_wlan_configs(session)
|
||||||
mobility_configs = get_mobility_configs(session)
|
mobility_configs = get_mobility_configs(session)
|
||||||
|
@ -685,7 +680,6 @@ def convert_session(session: Session) -> wrappers.Session:
|
||||||
default_services=default_services,
|
default_services=default_services,
|
||||||
location=location,
|
location=location,
|
||||||
hooks=hooks,
|
hooks=hooks,
|
||||||
emane_config=emane_config,
|
|
||||||
emane_model_configs=emane_model_configs,
|
emane_model_configs=emane_model_configs,
|
||||||
wlan_configs=wlan_configs,
|
wlan_configs=wlan_configs,
|
||||||
service_configs=service_configs,
|
service_configs=service_configs,
|
||||||
|
|
|
@ -33,14 +33,10 @@ from core.api.grpc.emane_pb2 import (
|
||||||
EmaneLinkResponse,
|
EmaneLinkResponse,
|
||||||
EmanePathlossesRequest,
|
EmanePathlossesRequest,
|
||||||
EmanePathlossesResponse,
|
EmanePathlossesResponse,
|
||||||
GetEmaneConfigRequest,
|
|
||||||
GetEmaneConfigResponse,
|
|
||||||
GetEmaneEventChannelRequest,
|
GetEmaneEventChannelRequest,
|
||||||
GetEmaneEventChannelResponse,
|
GetEmaneEventChannelResponse,
|
||||||
GetEmaneModelConfigRequest,
|
GetEmaneModelConfigRequest,
|
||||||
GetEmaneModelConfigResponse,
|
GetEmaneModelConfigResponse,
|
||||||
SetEmaneConfigRequest,
|
|
||||||
SetEmaneConfigResponse,
|
|
||||||
SetEmaneModelConfigRequest,
|
SetEmaneModelConfigRequest,
|
||||||
SetEmaneModelConfigResponse,
|
SetEmaneModelConfigResponse,
|
||||||
)
|
)
|
||||||
|
@ -266,7 +262,6 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
|
||||||
return core_pb2.StartSessionResponse(result=False, exceptions=exceptions)
|
return core_pb2.StartSessionResponse(result=False, exceptions=exceptions)
|
||||||
|
|
||||||
# emane configs
|
# emane configs
|
||||||
session.emane.config.update(request.emane_config)
|
|
||||||
for config in request.emane_model_configs:
|
for config in request.emane_model_configs:
|
||||||
_id = utils.iface_config_id(config.node_id, config.iface_id)
|
_id = utils.iface_config_id(config.node_id, config.iface_id)
|
||||||
session.emane.set_config(_id, config.model, config.config)
|
session.emane.set_config(_id, config.model, config.config)
|
||||||
|
@ -1045,36 +1040,6 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
|
||||||
node.updatemodel(config)
|
node.updatemodel(config)
|
||||||
return SetWlanConfigResponse(result=True)
|
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(
|
def GetEmaneModelConfig(
|
||||||
self, request: GetEmaneModelConfigRequest, context: ServicerContext
|
self, request: GetEmaneModelConfigRequest, context: ServicerContext
|
||||||
) -> GetEmaneModelConfigResponse:
|
) -> 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
|
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)
|
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)
|
metadata: Dict[str, str] = field(default_factory=dict)
|
||||||
file: Path = None
|
file: Path = None
|
||||||
options: Dict[str, ConfigOption] = field(default_factory=dict)
|
options: Dict[str, ConfigOption] = field(default_factory=dict)
|
||||||
|
@ -836,7 +835,6 @@ class Session:
|
||||||
default_services=default_services,
|
default_services=default_services,
|
||||||
location=SessionLocation.from_proto(proto.location),
|
location=SessionLocation.from_proto(proto.location),
|
||||||
hooks=hooks,
|
hooks=hooks,
|
||||||
emane_config=ConfigOption.from_dict(proto.emane_config),
|
|
||||||
metadata=dict(proto.metadata),
|
metadata=dict(proto.metadata),
|
||||||
file=file_path,
|
file=file_path,
|
||||||
options=options,
|
options=options,
|
||||||
|
@ -889,11 +887,6 @@ class Session:
|
||||||
self.links.append(link)
|
self.links.append(link)
|
||||||
return 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:
|
def set_options(self, config: Dict[str, str]) -> None:
|
||||||
for key, value in config.items():
|
for key, value in config.items():
|
||||||
option = ConfigOption(name=key, value=value)
|
option = ConfigOption(name=key, value=value)
|
||||||
|
|
|
@ -1046,8 +1046,6 @@ class CoreHandler(socketserver.BaseRequestHandler):
|
||||||
self.handle_config_mobility(message_type, config_data)
|
self.handle_config_mobility(message_type, config_data)
|
||||||
elif config_data.object in self.session.mobility.models:
|
elif config_data.object in self.session.mobility.models:
|
||||||
replies = self.handle_config_mobility_models(message_type, config_data)
|
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:
|
elif config_data.object in EmaneModelManager.models:
|
||||||
replies = self.handle_config_emane_models(message_type, config_data)
|
replies = self.handle_config_emane_models(message_type, config_data)
|
||||||
else:
|
else:
|
||||||
|
@ -1379,36 +1377,6 @@ class CoreHandler(socketserver.BaseRequestHandler):
|
||||||
|
|
||||||
return replies
|
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):
|
def handle_config_emane_models(self, message_type, config_data):
|
||||||
replies = []
|
replies = []
|
||||||
node_id = config_data.node
|
node_id = config_data.node
|
||||||
|
@ -1851,14 +1819,6 @@ class CoreHandler(socketserver.BaseRequestHandler):
|
||||||
)
|
)
|
||||||
self.session.broadcast_config(config_data)
|
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
|
# send emane model configs
|
||||||
for node_id, model_configs in self.session.emane.node_configs.items():
|
for node_id, model_configs in self.session.emane.node_configs.items():
|
||||||
for model_name, config in model_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 logging
|
||||||
import os
|
import os
|
||||||
import threading
|
import threading
|
||||||
from collections import OrderedDict
|
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from pathlib import Path
|
|
||||||
from typing import TYPE_CHECKING, Dict, List, Optional, Set, Tuple, Type
|
from typing import TYPE_CHECKING, Dict, List, Optional, Set, Tuple, Type
|
||||||
|
|
||||||
from core import utils
|
from core import utils
|
||||||
from core.config import ConfigGroup, Configuration
|
|
||||||
from core.emane import emanemanifest
|
|
||||||
from core.emane.emanemodel import EmaneModel
|
from core.emane.emanemodel import EmaneModel
|
||||||
from core.emane.linkmonitor import EmaneLinkMonitor
|
from core.emane.linkmonitor import EmaneLinkMonitor
|
||||||
from core.emane.modelmanager import EmaneModelManager
|
from core.emane.modelmanager import EmaneModelManager
|
||||||
from core.emane.nodes import EmaneNet
|
from core.emane.nodes import EmaneNet
|
||||||
from core.emulator.data import LinkData
|
from core.emulator.data import LinkData
|
||||||
from core.emulator.enumerations import (
|
from core.emulator.enumerations import LinkTypes, MessageFlags, RegisterTlvs
|
||||||
ConfigDataTypes,
|
|
||||||
LinkTypes,
|
|
||||||
MessageFlags,
|
|
||||||
RegisterTlvs,
|
|
||||||
)
|
|
||||||
from core.errors import CoreCommandError, CoreError
|
from core.errors import CoreCommandError, CoreError
|
||||||
from core.nodes.base import CoreNetworkBase, CoreNode, CoreNodeBase, NodeBase
|
from core.nodes.base import CoreNetworkBase, CoreNode, CoreNodeBase, NodeBase
|
||||||
from core.nodes.interface import CoreInterface, TunTap
|
from core.nodes.interface import CoreInterface, TunTap
|
||||||
|
@ -102,8 +93,6 @@ class EmaneManager:
|
||||||
self.eventmonthread: Optional[threading.Thread] = None
|
self.eventmonthread: Optional[threading.Thread] = None
|
||||||
|
|
||||||
# model for global EMANE configuration options
|
# 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_configs: Dict[int, Dict[str, Dict[str, str]]] = {}
|
||||||
self.node_models: Dict[int, str] = {}
|
self.node_models: Dict[int, str] = {}
|
||||||
|
|
||||||
|
@ -115,7 +104,7 @@ class EmaneManager:
|
||||||
self.event_device: Optional[str] = None
|
self.event_device: Optional[str] = None
|
||||||
|
|
||||||
def next_nem_id(self, iface: CoreInterface) -> int:
|
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:
|
while nem_id in self.nems_to_ifaces:
|
||||||
nem_id += 1
|
nem_id += 1
|
||||||
self.nems_to_ifaces[nem_id] = iface
|
self.nems_to_ifaces[nem_id] = iface
|
||||||
|
@ -206,7 +195,6 @@ class EmaneManager:
|
||||||
|
|
||||||
def config_reset(self, node_id: int = None) -> None:
|
def config_reset(self, node_id: int = None) -> None:
|
||||||
if node_id is None:
|
if node_id is None:
|
||||||
self.config = self.emane_config.default_values()
|
|
||||||
self.node_configs.clear()
|
self.node_configs.clear()
|
||||||
self.node_models.clear()
|
self.node_models.clear()
|
||||||
else:
|
else:
|
||||||
|
@ -224,25 +212,20 @@ class EmaneManager:
|
||||||
self.service = None
|
self.service = None
|
||||||
self.event_device = 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.
|
Re-initialize the EMANE Event service.
|
||||||
The multicast group and/or port may be configured.
|
The multicast group and/or port may be configured.
|
||||||
"""
|
"""
|
||||||
self.deleteeventservice()
|
|
||||||
if shutdown:
|
|
||||||
return
|
|
||||||
|
|
||||||
# Get the control network to be used for events
|
# Get the control network to be used for events
|
||||||
group, port = self.config["eventservicegroup"].split(":")
|
group, port = "224.1.2.8:45703".split(":")
|
||||||
self.event_device = self.config["eventservicedevice"]
|
self.event_device = DEFAULT_DEV
|
||||||
eventnetidx = self.session.get_control_net_index(self.event_device)
|
eventnetidx = self.session.get_control_net_index(self.event_device)
|
||||||
if eventnetidx < 0:
|
if eventnetidx < 0:
|
||||||
logger.error(
|
logger.error(
|
||||||
"invalid emane event service device provided: %s", self.event_device
|
"invalid emane event service device provided: %s", self.event_device
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
# make sure the event control network is in place
|
# make sure the event control network is in place
|
||||||
eventnet = self.session.add_remove_control_net(
|
eventnet = self.session.add_remove_control_net(
|
||||||
net_index=eventnetidx, remove=False, conf_required=False
|
net_index=eventnetidx, remove=False, conf_required=False
|
||||||
|
@ -251,14 +234,13 @@ class EmaneManager:
|
||||||
# direct EMANE events towards control net bridge
|
# direct EMANE events towards control net bridge
|
||||||
self.event_device = eventnet.brname
|
self.event_device = eventnet.brname
|
||||||
self.eventchannel = (group, int(port), self.event_device)
|
self.eventchannel = (group, int(port), self.event_device)
|
||||||
|
|
||||||
# disabled otachannel for event service
|
# disabled otachannel for event service
|
||||||
# only needed for e.g. antennaprofile events xmit by models
|
# 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:
|
try:
|
||||||
self.service = EventService(eventchannel=self.eventchannel, otachannel=None)
|
self.service = EventService(eventchannel=self.eventchannel, otachannel=None)
|
||||||
except EventServiceException:
|
except EventServiceException:
|
||||||
logger.exception("error instantiating emane EventService")
|
logger.exception("error starting emane event service")
|
||||||
|
|
||||||
def add_node(self, emane_net: EmaneNet) -> None:
|
def add_node(self, emane_net: EmaneNet) -> None:
|
||||||
"""
|
"""
|
||||||
|
@ -309,9 +291,8 @@ class EmaneManager:
|
||||||
if EventService is None:
|
if EventService is None:
|
||||||
raise CoreError("EMANE python bindings are not installed")
|
raise CoreError("EMANE python bindings are not installed")
|
||||||
|
|
||||||
# control network bridge required for EMANE 0.9.2
|
# control network bridge required for emane
|
||||||
# - needs to exist when eventservice binds to it (initeventservice)
|
otadev = DEFAULT_DEV
|
||||||
otadev = self.config["otamanagerdevice"]
|
|
||||||
netidx = self.session.get_control_net_index(otadev)
|
netidx = self.session.get_control_net_index(otadev)
|
||||||
logger.debug("emane ota manager device: index(%s) otadev(%s)", netidx, otadev)
|
logger.debug("emane ota manager device: index(%s) otadev(%s)", netidx, otadev)
|
||||||
if netidx < 0:
|
if netidx < 0:
|
||||||
|
@ -320,25 +301,9 @@ class EmaneManager:
|
||||||
otadev,
|
otadev,
|
||||||
)
|
)
|
||||||
return EmaneState.NOT_READY
|
return EmaneState.NOT_READY
|
||||||
|
|
||||||
self.session.add_remove_control_net(
|
self.session.add_remove_control_net(
|
||||||
net_index=netidx, remove=False, conf_required=False
|
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()
|
self.check_node_models()
|
||||||
return EmaneState.SUCCESS
|
return EmaneState.SUCCESS
|
||||||
|
|
||||||
|
@ -354,8 +319,9 @@ class EmaneManager:
|
||||||
status = self.setup()
|
status = self.setup()
|
||||||
if status != EmaneState.SUCCESS:
|
if status != EmaneState.SUCCESS:
|
||||||
return status
|
return status
|
||||||
self.starteventmonitor()
|
self.initeventservice()
|
||||||
self.buildeventservicexml()
|
if self.service and self.doeventmonitor():
|
||||||
|
self.starteventmonitor()
|
||||||
with self._emane_node_lock:
|
with self._emane_node_lock:
|
||||||
logger.info("emane building xmls...")
|
logger.info("emane building xmls...")
|
||||||
start_data = self.get_start_data()
|
start_data = self.get_start_data()
|
||||||
|
@ -392,40 +358,54 @@ class EmaneManager:
|
||||||
control_net = self.session.add_remove_control_net(
|
control_net = self.session.add_remove_control_net(
|
||||||
0, remove=False, conf_required=False
|
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
|
# builds xmls and start emane daemons
|
||||||
for iface in data.ifaces:
|
for iface in data.ifaces:
|
||||||
|
if isinstance(node, CoreNode):
|
||||||
|
self.setup_ota(node, iface)
|
||||||
emanexml.build_platform_xml(self, control_net, node, iface)
|
emanexml.build_platform_xml(self, control_net, node, iface)
|
||||||
self.start_daemon(node, iface)
|
self.start_daemon(node, iface)
|
||||||
self.install_iface(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]:
|
def get_iface(self, nem_id: int) -> Optional[CoreInterface]:
|
||||||
return self.nems_to_ifaces.get(nem_id)
|
return self.nems_to_ifaces.get(nem_id)
|
||||||
|
|
||||||
|
@ -445,7 +425,7 @@ class EmaneManager:
|
||||||
logger.exception("error writing to emane nem file")
|
logger.exception("error writing to emane nem file")
|
||||||
|
|
||||||
def links_enabled(self) -> bool:
|
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:
|
def poststartup(self) -> None:
|
||||||
"""
|
"""
|
||||||
|
@ -551,35 +531,6 @@ class EmaneManager:
|
||||||
color=color,
|
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:
|
def start_daemon(self, node: CoreNodeBase, iface: CoreInterface) -> None:
|
||||||
"""
|
"""
|
||||||
Start one EMANE daemon per node having a radio.
|
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.
|
Start monitoring EMANE location events if configured to do so.
|
||||||
"""
|
"""
|
||||||
logger.info("emane start event monitor")
|
logger.info("starting emane 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
|
|
||||||
self.doeventloop = True
|
self.doeventloop = True
|
||||||
self.eventmonthread = threading.Thread(
|
self.eventmonthread = threading.Thread(
|
||||||
target=self.eventmonitorloop, daemon=True
|
target=self.eventmonitorloop, daemon=True
|
||||||
|
@ -673,8 +614,7 @@ class EmaneManager:
|
||||||
if self.service is not None:
|
if self.service is not None:
|
||||||
self.service.breakloop()
|
self.service.breakloop()
|
||||||
# reset the service, otherwise nextEvent won"t work
|
# reset the service, otherwise nextEvent won"t work
|
||||||
self.initeventservice(shutdown=True)
|
self.deleteeventservice()
|
||||||
|
|
||||||
if self.eventmonthread is not None:
|
if self.eventmonthread is not None:
|
||||||
self.eventmonthread.join()
|
self.eventmonthread.join()
|
||||||
self.eventmonthread = None
|
self.eventmonthread = None
|
||||||
|
@ -685,26 +625,17 @@ class EmaneManager:
|
||||||
"""
|
"""
|
||||||
if self.service is None:
|
if self.service is None:
|
||||||
return
|
return
|
||||||
logger.info(
|
logger.info("subscribing to EMANE location events")
|
||||||
"subscribing to EMANE location events. (%s)",
|
while self.doeventloop:
|
||||||
threading.currentThread().getName(),
|
|
||||||
)
|
|
||||||
while self.doeventloop is True:
|
|
||||||
_uuid, _seq, events = self.service.nextEvent()
|
_uuid, _seq, events = self.service.nextEvent()
|
||||||
|
|
||||||
# this occurs with 0.9.1 event service
|
# this occurs with 0.9.1 event service
|
||||||
if not self.doeventloop:
|
if not self.doeventloop:
|
||||||
break
|
break
|
||||||
|
|
||||||
for event in events:
|
for event in events:
|
||||||
nem, eid, data = event
|
nem, eid, data = event
|
||||||
if eid == LocationEvent.IDENTIFIER:
|
if eid == LocationEvent.IDENTIFIER:
|
||||||
self.handlelocationevent(nem, eid, data)
|
self.handlelocationevent(nem, eid, data)
|
||||||
|
logger.info("unsubscribing from EMANE location events")
|
||||||
logger.info(
|
|
||||||
"unsubscribing from EMANE location events. (%s)",
|
|
||||||
threading.currentThread().getName(),
|
|
||||||
)
|
|
||||||
|
|
||||||
def handlelocationevent(self, rxnemid: int, eid: int, data: str) -> None:
|
def handlelocationevent(self, rxnemid: int, eid: int, data: str) -> None:
|
||||||
"""
|
"""
|
||||||
|
@ -818,85 +749,3 @@ class EmaneManager:
|
||||||
event.append(nem2, forward=rx2)
|
event.append(nem2, forward=rx2)
|
||||||
self.service.publish(nem1, event)
|
self.service.publish(nem1, event)
|
||||||
self.service.publish(nem2, 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
|
self.running: bool = False
|
||||||
|
|
||||||
def start(self) -> None:
|
def start(self) -> None:
|
||||||
self.loss_threshold = int(self.emane_manager.config["loss_threshold"])
|
options = self.emane_manager.session.options
|
||||||
self.link_interval = int(self.emane_manager.config["link_interval"])
|
self.loss_threshold = options.get_config_int("loss_threshold")
|
||||||
self.link_timeout = int(self.emane_manager.config["link_timeout"])
|
self.link_interval = options.get_config_int("link_interval")
|
||||||
|
self.link_timeout = options.get_config_int("link_timeout")
|
||||||
self.initialize()
|
self.initialize()
|
||||||
if not self.clients:
|
if not self.clients:
|
||||||
logger.info("no valid emane models to monitor links")
|
logger.info("no valid emane models to monitor links")
|
||||||
|
|
|
@ -38,7 +38,7 @@ class LinuxNetClient:
|
||||||
:param device: device to add route to
|
:param device: device to add route to
|
||||||
:return: nothing
|
: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:
|
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(
|
def create_emane_model_config(
|
||||||
node_id: int,
|
node_id: int,
|
||||||
model: "EmaneModelType",
|
model: "EmaneModelType",
|
||||||
|
@ -104,22 +90,22 @@ def create_emane_model_config(
|
||||||
add_attribute(emane_element, "node", node_id)
|
add_attribute(emane_element, "node", node_id)
|
||||||
add_attribute(emane_element, "iface", iface_id)
|
add_attribute(emane_element, "iface", iface_id)
|
||||||
add_attribute(emane_element, "model", model.name)
|
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")
|
mac_element = etree.SubElement(emane_element, "mac")
|
||||||
for mac_config in model.mac_config:
|
for mac_config in model.mac_config:
|
||||||
value = config[mac_config.id]
|
value = config[mac_config.id]
|
||||||
add_configuration(mac_element, mac_config.id, value)
|
add_configuration(mac_element, mac_config.id, value)
|
||||||
|
|
||||||
phy_element = etree.SubElement(emane_element, "phy")
|
phy_element = etree.SubElement(emane_element, "phy")
|
||||||
for phy_config in model.phy_config:
|
for phy_config in model.phy_config:
|
||||||
value = config[phy_config.id]
|
value = config[phy_config.id]
|
||||||
add_configuration(phy_element, phy_config.id, value)
|
add_configuration(phy_element, phy_config.id, value)
|
||||||
|
|
||||||
external_element = etree.SubElement(emane_element, "external")
|
external_element = etree.SubElement(emane_element, "external")
|
||||||
for external_config in model.external_config:
|
for external_config in model.external_config:
|
||||||
value = config[external_config.id]
|
value = config[external_config.id]
|
||||||
add_configuration(external_element, external_config.id, value)
|
add_configuration(external_element, external_config.id, value)
|
||||||
|
|
||||||
return emane_element
|
return emane_element
|
||||||
|
|
||||||
|
|
||||||
|
@ -376,8 +362,6 @@ class CoreXmlWriter:
|
||||||
self.scenario.append(metadata_elements)
|
self.scenario.append(metadata_elements)
|
||||||
|
|
||||||
def write_emane_configs(self) -> None:
|
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")
|
emane_configurations = etree.Element("emane_configurations")
|
||||||
for node_id, model_configs in self.session.emane.node_configs.items():
|
for node_id, model_configs in self.session.emane.node_configs.items():
|
||||||
node_id, iface_id = utils.parse_iface_config_id(node_id)
|
node_id, iface_id = utils.parse_iface_config_id(node_id)
|
||||||
|
@ -591,7 +575,6 @@ class CoreXmlReader:
|
||||||
self.read_session_origin()
|
self.read_session_origin()
|
||||||
self.read_service_configs()
|
self.read_service_configs()
|
||||||
self.read_mobility_configs()
|
self.read_mobility_configs()
|
||||||
self.read_emane_global_config()
|
|
||||||
self.read_nodes()
|
self.read_nodes()
|
||||||
self.read_links()
|
self.read_links()
|
||||||
self.read_emane_configs()
|
self.read_emane_configs()
|
||||||
|
@ -729,28 +712,10 @@ class CoreXmlReader:
|
||||||
files.add(name)
|
files.add(name)
|
||||||
service.configs = tuple(files)
|
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:
|
def read_emane_configs(self) -> None:
|
||||||
emane_configurations = self.scenario.find("emane_configurations")
|
emane_configurations = self.scenario.find("emane_configurations")
|
||||||
if emane_configurations is None:
|
if emane_configurations is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
for emane_configuration in emane_configurations.iterchildren():
|
for emane_configuration in emane_configurations.iterchildren():
|
||||||
node_id = get_int(emane_configuration, "node")
|
node_id = get_int(emane_configuration, "node")
|
||||||
iface_id = get_int(emane_configuration, "iface")
|
iface_id = get_int(emane_configuration, "iface")
|
||||||
|
@ -768,18 +733,21 @@ class CoreXmlReader:
|
||||||
)
|
)
|
||||||
|
|
||||||
# read and set emane model configuration
|
# 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")
|
mac_configuration = emane_configuration.find("mac")
|
||||||
for config in mac_configuration.iterchildren():
|
for config in mac_configuration.iterchildren():
|
||||||
name = config.get("name")
|
name = config.get("name")
|
||||||
value = config.get("value")
|
value = config.get("value")
|
||||||
configs[name] = value
|
configs[name] = value
|
||||||
|
|
||||||
phy_configuration = emane_configuration.find("phy")
|
phy_configuration = emane_configuration.find("phy")
|
||||||
for config in phy_configuration.iterchildren():
|
for config in phy_configuration.iterchildren():
|
||||||
name = config.get("name")
|
name = config.get("name")
|
||||||
value = config.get("value")
|
value = config.get("value")
|
||||||
configs[name] = value
|
configs[name] = value
|
||||||
|
|
||||||
external_configuration = emane_configuration.find("external")
|
external_configuration = emane_configuration.find("external")
|
||||||
for config in external_configuration.iterchildren():
|
for config in external_configuration.iterchildren():
|
||||||
name = config.get("name")
|
name = config.get("name")
|
||||||
|
|
|
@ -162,7 +162,7 @@ def build_platform_xml(
|
||||||
:param iface: node interface to create platform xml for
|
:param iface: node interface to create platform xml for
|
||||||
:return: the next nem id that can be used for creating platform xml files
|
: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
|
emane_net = iface.net
|
||||||
if not isinstance(emane_net, EmaneNet):
|
if not isinstance(emane_net, EmaneNet):
|
||||||
raise CoreError(f"emane interface not connected to emane net: {emane_net.name}")
|
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
|
# create top level platform element
|
||||||
transport_configs = {"otamanagerdevice", "eventservicedevice"}
|
transport_configs = {"otamanagerdevice", "eventservicedevice"}
|
||||||
platform_element = etree.Element("platform")
|
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
|
name = configuration.id
|
||||||
if not isinstance(node, CoreNode) and name in transport_configs:
|
if not isinstance(node, CoreNode) and name in transport_configs:
|
||||||
value = control_net.brname
|
value = control_net.brname
|
||||||
else:
|
else:
|
||||||
value = emane_manager.config[name]
|
value = config[configuration.id]
|
||||||
if name == "controlportendpoint":
|
if name == "controlportendpoint":
|
||||||
port = emane_manager.get_nem_port(iface)
|
port = emane_manager.get_nem_port(iface)
|
||||||
value = f"0.0.0.0:{port}"
|
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)
|
session.add_link(node1=node2, node2=emane, iface1=iface1)
|
||||||
|
|
||||||
# setup emane configurations using a dict mapping currently support values as strings
|
# setup emane configurations using a dict mapping currently support values as strings
|
||||||
session.set_emane({"eventservicettl": "2"})
|
emane.set_emane_model(
|
||||||
emane.set_emane_model(EmaneIeee80211abgModel.name, {"unicastrate": "3"})
|
EmaneIeee80211abgModel.name, {"eventservicettl": "2", "unicastrate": "3"}
|
||||||
|
)
|
||||||
|
|
||||||
# start session
|
# start session
|
||||||
core.start_session(session)
|
core.start_session(session)
|
||||||
|
|
|
@ -95,10 +95,6 @@ service CoreApi {
|
||||||
}
|
}
|
||||||
|
|
||||||
// emane rpc
|
// emane rpc
|
||||||
rpc GetEmaneConfig (emane.GetEmaneConfigRequest) returns (emane.GetEmaneConfigResponse) {
|
|
||||||
}
|
|
||||||
rpc SetEmaneConfig (emane.SetEmaneConfigRequest) returns (emane.SetEmaneConfigResponse) {
|
|
||||||
}
|
|
||||||
rpc GetEmaneModelConfig (emane.GetEmaneModelConfigRequest) returns (emane.GetEmaneModelConfigResponse) {
|
rpc GetEmaneModelConfig (emane.GetEmaneModelConfigRequest) returns (emane.GetEmaneModelConfigResponse) {
|
||||||
}
|
}
|
||||||
rpc SetEmaneModelConfig (emane.SetEmaneModelConfigRequest) returns (emane.SetEmaneModelConfigResponse) {
|
rpc SetEmaneModelConfig (emane.SetEmaneModelConfigRequest) returns (emane.SetEmaneModelConfigResponse) {
|
||||||
|
@ -144,19 +140,18 @@ message StartSessionRequest {
|
||||||
repeated Link links = 3;
|
repeated Link links = 3;
|
||||||
repeated Hook hooks = 4;
|
repeated Hook hooks = 4;
|
||||||
SessionLocation location = 5;
|
SessionLocation location = 5;
|
||||||
map<string, string> emane_config = 6;
|
repeated wlan.WlanConfig wlan_configs = 6;
|
||||||
repeated wlan.WlanConfig wlan_configs = 7;
|
repeated emane.EmaneModelConfig emane_model_configs = 7;
|
||||||
repeated emane.EmaneModelConfig emane_model_configs = 8;
|
repeated mobility.MobilityConfig mobility_configs = 8;
|
||||||
repeated mobility.MobilityConfig mobility_configs = 9;
|
repeated services.ServiceConfig service_configs = 9;
|
||||||
repeated services.ServiceConfig service_configs = 10;
|
repeated services.ServiceFileConfig service_file_configs = 10;
|
||||||
repeated services.ServiceFileConfig service_file_configs = 11;
|
repeated Link asymmetric_links = 11;
|
||||||
repeated Link asymmetric_links = 12;
|
repeated configservices.ConfigServiceConfig config_service_configs = 12;
|
||||||
repeated configservices.ConfigServiceConfig config_service_configs = 13;
|
map<string, string> options = 13;
|
||||||
map<string, string> options = 14;
|
string user = 14;
|
||||||
string user = 15;
|
bool definition = 15;
|
||||||
bool definition = 16;
|
map<string, string> metadata = 16;
|
||||||
map<string, string> metadata = 17;
|
repeated Server servers = 17;
|
||||||
repeated Server servers = 18;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message StartSessionResponse {
|
message StartSessionResponse {
|
||||||
|
|
|
@ -4,23 +4,6 @@ package emane;
|
||||||
|
|
||||||
import "core/api/grpc/common.proto";
|
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 {
|
message GetEmaneModelConfigRequest {
|
||||||
int32 session_id = 1;
|
int32 session_id = 1;
|
||||||
int32 node_id = 2;
|
int32 node_id = 2;
|
||||||
|
|
|
@ -61,6 +61,7 @@ eval "$ifcommand" | awk '
|
||||||
/tmp\./ {print "removing interface " $1; system("ip link del " $1);}
|
/tmp\./ {print "removing interface " $1; system("ip link del " $1);}
|
||||||
/gt\./ {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);}
|
/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 '
|
nft list ruleset | awk '
|
||||||
|
|
|
@ -83,11 +83,6 @@ class TestGrpc:
|
||||||
scale=location_scale,
|
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
|
# setup wlan config
|
||||||
wlan_config_key = "range"
|
wlan_config_key = "range"
|
||||||
wlan_config_value = "333"
|
wlan_config_value = "333"
|
||||||
|
@ -151,7 +146,6 @@ class TestGrpc:
|
||||||
location_alt,
|
location_alt,
|
||||||
)
|
)
|
||||||
assert real_session.location.refscale == location_scale
|
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(
|
set_wlan_config = real_session.mobility.get_model_config(
|
||||||
wlan_node.id, BasicRangeModel.name
|
wlan_node.id, BasicRangeModel.name
|
||||||
)
|
)
|
||||||
|
@ -518,35 +512,6 @@ class TestGrpc:
|
||||||
assert config[range_key] == range_value
|
assert config[range_key] == range_value
|
||||||
assert wlan.model.range == int(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):
|
def test_set_emane_model_config(self, grpc_server: CoreGrpcServer):
|
||||||
# given
|
# given
|
||||||
client = CoreGrpcClient()
|
client = CoreGrpcClient()
|
||||||
|
|
|
@ -941,35 +941,3 @@ class TestGui:
|
||||||
|
|
||||||
config = coretlv.session.emane.get_config(wlan.id, EmaneIeee80211abgModel.name)
|
config = coretlv.session.emane.get_config(wlan.id, EmaneIeee80211abgModel.name)
|
||||||
assert config[config_key] == config_value
|
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)
|
iface1 = iface_helper.create_iface(node2.id, 0)
|
||||||
session.add_link(node1=node2, node2=emane, iface1=iface1)
|
session.add_link(node1=node2, node2=emane, iface1=iface1)
|
||||||
|
|
||||||
# setting global emane configuration
|
|
||||||
session.set_emane({"eventservicettl": "2"})
|
|
||||||
# setting emane specific emane model configuration
|
# 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
|
# start session
|
||||||
core.start_session(session)
|
core.start_session(session)
|
||||||
|
|
Loading…
Reference in a new issue