core-extra/daemon/core/emane/commeffect.py

155 lines
5 KiB
Python
Raw Normal View History

"""
commeffect.py: EMANE CommEffect model for CORE
"""
import logging
import os
from typing import Dict, List
2019-09-10 22:20:51 +01:00
from lxml import etree
from core.config import ConfigGroup, Configuration
2019-09-10 22:20:51 +01:00
from core.emane import emanemanifest, emanemodel
from core.nodes.interface import CoreInterface
from core.xml import emanexml
try:
2018-03-29 22:04:15 +01:00
from emane.events.commeffectevent import CommEffectEvent
except ImportError:
try:
from emanesh.events.commeffectevent import CommEffectEvent
except ImportError:
logging.debug("compatible emane python bindings not installed")
def convert_none(x: float) -> int:
"""
Helper to use 0 for None values.
"""
if isinstance(x, str):
x = float(x)
if x is None:
return 0
else:
return int(x)
class EmaneCommEffectModel(emanemodel.EmaneModel):
name = "emane_commeffect"
shim_library = "commeffectshim"
shim_xml = "commeffectshim.xml"
shim_defaults = {}
config_shim = []
# comm effect does not need the default phy and external configurations
phy_config = []
external_config = []
@classmethod
def load(cls, emane_prefix: str) -> None:
shim_xml_path = os.path.join(emane_prefix, "share/emane/manifest", cls.shim_xml)
cls.config_shim = emanemanifest.parse(shim_xml_path, cls.shim_defaults)
@classmethod
def configurations(cls) -> List[Configuration]:
return cls.config_shim
@classmethod
def config_groups(cls) -> List[ConfigGroup]:
return [ConfigGroup("CommEffect SHIM Parameters", 1, len(cls.configurations()))]
def build_xml_files(
self, config: Dict[str, str], interface: CoreInterface = None
) -> None:
"""
Build the necessary nem and commeffect XMLs in the given path.
If an individual NEM has a nonstandard config, we need to build
that file also. Otherwise the WLAN-wide
nXXemane_commeffectnem.xml, nXXemane_commeffectshim.xml are used.
:param config: emane model configuration for the node and interface
:param interface: interface for the emane node
:return: nothing
"""
# retrieve xml names
nem_name = emanexml.nem_file_name(self, interface)
shim_name = emanexml.shim_file_name(self, interface)
# create and write nem document
2019-10-18 18:33:31 +01:00
nem_element = etree.Element("nem", name=f"{self.name} NEM", type="unstructured")
transport_type = "virtual"
if interface and interface.transport_type == "raw":
transport_type = "raw"
transport_file = emanexml.transport_file_name(self.id, transport_type)
etree.SubElement(nem_element, "transport", definition=transport_file)
# set shim configuration
etree.SubElement(nem_element, "shim", definition=shim_name)
nem_file = os.path.join(self.session.session_dir, nem_name)
emanexml.create_file(nem_element, "nem", nem_file)
# create and write shim document
shim_element = etree.Element(
2019-10-18 18:33:31 +01:00
"shim", name=f"{self.name} SHIM", library=self.shim_library
)
# append all shim options (except filterfile) to shimdoc
for configuration in self.config_shim:
name = configuration.id
if name == "filterfile":
continue
value = config[name]
emanexml.add_param(shim_element, name, value)
# empty filterfile is not allowed
ff = config["filterfile"]
if ff.strip() != "":
emanexml.add_param(shim_element, "filterfile", ff)
shim_file = os.path.join(self.session.session_dir, shim_name)
emanexml.create_file(shim_element, "shim", shim_file)
def linkconfig(
self,
netif: CoreInterface,
bw: float = None,
delay: float = None,
loss: float = None,
duplicate: float = None,
jitter: float = None,
netif2: CoreInterface = None,
) -> None:
"""
Generate CommEffect events when a Link Message is received having
link parameters.
"""
service = self.session.emane.service
if service is None:
logging.warning("%s: EMANE event service unavailable", self.name)
return
if netif is None or netif2 is None:
logging.warning("%s: missing NEM information", self.name)
return
# TODO: batch these into multiple events per transmission
# TODO: may want to split out seconds portion of delay and jitter
event = CommEffectEvent()
emane_node = self.session.get_node(self.id)
nemid = emane_node.getnemid(netif)
nemid2 = emane_node.getnemid(netif2)
mbw = bw
logging.info("sending comm effect event")
event.append(
nemid,
latency=convert_none(delay),
jitter=convert_none(jitter),
loss=convert_none(loss),
duplicate=convert_none(duplicate),
2019-09-11 05:01:51 +01:00
unicast=int(convert_none(bw)),
broadcast=int(convert_none(mbw)),
)
service.publish(nemid2, event)