daemon: added class variable type hinting to core.emane

This commit is contained in:
Blake Harnden 2020-06-12 09:52:01 -07:00
parent ef3cf5697d
commit 6201875b78
11 changed files with 116 additions and 100 deletions

View file

@ -1,6 +1,7 @@
""" """
EMANE Bypass model for CORE EMANE Bypass model for CORE
""" """
from typing import List, Set
from core.config import Configuration from core.config import Configuration
from core.emane import emanemodel from core.emane import emanemodel
@ -8,14 +9,14 @@ from core.emulator.enumerations import ConfigDataTypes
class EmaneBypassModel(emanemodel.EmaneModel): class EmaneBypassModel(emanemodel.EmaneModel):
name = "emane_bypass" name: str = "emane_bypass"
# values to ignore, when writing xml files # values to ignore, when writing xml files
config_ignore = {"none"} config_ignore: Set[str] = {"none"}
# mac definitions # mac definitions
mac_library = "bypassmaclayer" mac_library: str = "bypassmaclayer"
mac_config = [ mac_config: List[Configuration] = [
Configuration( Configuration(
_id="none", _id="none",
_type=ConfigDataTypes.BOOL, _type=ConfigDataTypes.BOOL,
@ -25,8 +26,8 @@ class EmaneBypassModel(emanemodel.EmaneModel):
] ]
# phy definitions # phy definitions
phy_library = "bypassphylayer" phy_library: str = "bypassphylayer"
phy_config = [] phy_config: List[Configuration] = []
@classmethod @classmethod
def load(cls, emane_prefix: str) -> None: def load(cls, emane_prefix: str) -> None:

View file

@ -22,6 +22,7 @@ except ImportError:
try: try:
from emanesh.events.commeffectevent import CommEffectEvent from emanesh.events.commeffectevent import CommEffectEvent
except ImportError: except ImportError:
CommEffectEvent = None
logging.debug("compatible emane python bindings not installed") logging.debug("compatible emane python bindings not installed")
@ -38,16 +39,15 @@ def convert_none(x: float) -> int:
class EmaneCommEffectModel(emanemodel.EmaneModel): class EmaneCommEffectModel(emanemodel.EmaneModel):
name = "emane_commeffect" name: str = "emane_commeffect"
shim_library: str = "commeffectshim"
shim_library = "commeffectshim" shim_xml: str = "commeffectshim.xml"
shim_xml = "commeffectshim.xml" shim_defaults: Dict[str, str] = {}
shim_defaults = {} config_shim: List[Configuration] = []
config_shim = []
# comm effect does not need the default phy and external configurations # comm effect does not need the default phy and external configurations
phy_config = [] phy_config: List[Configuration] = []
external_config = [] external_config: List[Configuration] = []
@classmethod @classmethod
def load(cls, emane_prefix: str) -> None: def load(cls, emane_prefix: str) -> None:

View file

@ -70,11 +70,13 @@ class EmaneManager(ModelManager):
controlling the EMANE daemons. controlling the EMANE daemons.
""" """
name = "emane" name: str = "emane"
config_type = RegisterTlvs.EMULATION_SERVER config_type: RegisterTlvs = RegisterTlvs.EMULATION_SERVER
SUCCESS, NOT_NEEDED, NOT_READY = (0, 1, 2) SUCCESS: int = 0
EVENTCFGVAR = "LIBEMANEEVENTSERVICECONFIG" NOT_NEEDED: int = 1
DEFAULT_LOG_LEVEL = 3 NOT_READY: int = 2
EVENTCFGVAR: str = "LIBEMANEEVENTSERVICECONFIG"
DEFAULT_LOG_LEVEL: int = 3
def __init__(self, session: "Session") -> None: def __init__(self, session: "Session") -> None:
""" """
@ -84,29 +86,29 @@ class EmaneManager(ModelManager):
:return: nothing :return: nothing
""" """
super().__init__() super().__init__()
self.session = session self.session: "Session" = session
self._emane_nets = {} self._emane_nets: Dict[int, EmaneNet] = {}
self._emane_node_lock = threading.Lock() self._emane_node_lock: threading.Lock = threading.Lock()
# port numbers are allocated from these counters # port numbers are allocated from these counters
self.platformport = self.session.options.get_config_int( self.platformport: int = self.session.options.get_config_int(
"emane_platform_port", 8100 "emane_platform_port", 8100
) )
self.transformport = self.session.options.get_config_int( self.transformport: int = self.session.options.get_config_int(
"emane_transform_port", 8200 "emane_transform_port", 8200
) )
self.doeventloop = False self.doeventloop: bool = False
self.eventmonthread = None self.eventmonthread: Optional[threading.Thread] = None
# model for global EMANE configuration options # model for global EMANE configuration options
self.emane_config = EmaneGlobalModel(session) self.emane_config: EmaneGlobalModel = EmaneGlobalModel(session)
self.set_configs(self.emane_config.default_values()) self.set_configs(self.emane_config.default_values())
# link monitor # link monitor
self.link_monitor = EmaneLinkMonitor(self) self.link_monitor: EmaneLinkMonitor = EmaneLinkMonitor(self)
self.service = None self.service: Optional[EventService] = None
self.eventchannel = None self.eventchannel: Optional[Tuple[str, int, str]] = None
self.event_device = None self.event_device: Optional[str] = None
self.emane_check() self.emane_check()
def getifcconfig( def getifcconfig(
@ -890,12 +892,12 @@ class EmaneGlobalModel:
Global EMANE configuration options. Global EMANE configuration options.
""" """
name = "emane" name: str = "emane"
bitmap = None bitmap: Optional[str] = None
def __init__(self, session: "Session") -> None: def __init__(self, session: "Session") -> None:
self.session = session self.session: "Session" = session
self.core_config = [ self.core_config: List[Configuration] = [
Configuration( Configuration(
_id="platform_id_start", _id="platform_id_start",
_type=ConfigDataTypes.INT32, _type=ConfigDataTypes.INT32,

View file

@ -11,6 +11,7 @@ except ImportError:
try: try:
from emanesh import manifest from emanesh import manifest
except ImportError: except ImportError:
manifest = None
logging.debug("compatible emane python bindings not installed") logging.debug("compatible emane python bindings not installed")

View file

@ -3,7 +3,7 @@ Defines Emane Models used within CORE.
""" """
import logging import logging
import os import os
from typing import Dict, List from typing import Dict, List, Optional, Set
from core.config import ConfigGroup, Configuration from core.config import ConfigGroup, Configuration
from core.emane import emanemanifest from core.emane import emanemanifest
@ -25,19 +25,23 @@ class EmaneModel(WirelessModel):
""" """
# default mac configuration settings # default mac configuration settings
mac_library = None mac_library: Optional[str] = None
mac_xml = None mac_xml: Optional[str] = None
mac_defaults = {} mac_defaults: Dict[str, str] = {}
mac_config = [] mac_config: List[Configuration] = []
# default phy configuration settings, using the universal model # default phy configuration settings, using the universal model
phy_library = None phy_library: Optional[str] = None
phy_xml = "emanephy.xml" phy_xml: str = "emanephy.xml"
phy_defaults = {"subid": "1", "propagationmodel": "2ray", "noisemode": "none"} phy_defaults: Dict[str, str] = {
phy_config = [] "subid": "1",
"propagationmodel": "2ray",
"noisemode": "none",
}
phy_config: List[Configuration] = []
# support for external configurations # support for external configurations
external_config = [ external_config: List[Configuration] = [
Configuration("external", ConfigDataTypes.BOOL, default="0"), Configuration("external", ConfigDataTypes.BOOL, default="0"),
Configuration( Configuration(
"platformendpoint", ConfigDataTypes.STRING, default="127.0.0.1:40001" "platformendpoint", ConfigDataTypes.STRING, default="127.0.0.1:40001"
@ -47,7 +51,7 @@ class EmaneModel(WirelessModel):
), ),
] ]
config_ignore = set() config_ignore: Set[str] = set()
@classmethod @classmethod
def load(cls, emane_prefix: str) -> None: def load(cls, emane_prefix: str) -> None:

View file

@ -8,11 +8,11 @@ from core.emane import emanemodel
class EmaneIeee80211abgModel(emanemodel.EmaneModel): class EmaneIeee80211abgModel(emanemodel.EmaneModel):
# model name # model name
name = "emane_ieee80211abg" name: str = "emane_ieee80211abg"
# mac configuration # mac configuration
mac_library = "ieee80211abgmaclayer" mac_library: str = "ieee80211abgmaclayer"
mac_xml = "ieee80211abgmaclayer.xml" mac_xml: str = "ieee80211abgmaclayer.xml"
@classmethod @classmethod
def load(cls, emane_prefix: str) -> None: def load(cls, emane_prefix: str) -> None:

View file

@ -2,7 +2,7 @@ import logging
import sched import sched
import threading import threading
import time import time
from typing import TYPE_CHECKING, Dict, List, Tuple from typing import TYPE_CHECKING, Dict, List, Optional, Set, Tuple
import netaddr import netaddr
from lxml import etree from lxml import etree
@ -17,28 +17,29 @@ except ImportError:
try: try:
from emanesh import shell from emanesh import shell
except ImportError: except ImportError:
shell = None
logging.debug("compatible emane python bindings not installed") logging.debug("compatible emane python bindings not installed")
if TYPE_CHECKING: if TYPE_CHECKING:
from core.emane.emanemanager import EmaneManager from core.emane.emanemanager import EmaneManager
DEFAULT_PORT = 47_000 DEFAULT_PORT: int = 47_000
MAC_COMPONENT_INDEX = 1 MAC_COMPONENT_INDEX: int = 1
EMANE_RFPIPE = "rfpipemaclayer" EMANE_RFPIPE: str = "rfpipemaclayer"
EMANE_80211 = "ieee80211abgmaclayer" EMANE_80211: str = "ieee80211abgmaclayer"
EMANE_TDMA = "tdmaeventschedulerradiomodel" EMANE_TDMA: str = "tdmaeventschedulerradiomodel"
SINR_TABLE = "NeighborStatusTable" SINR_TABLE: str = "NeighborStatusTable"
NEM_SELF = 65535 NEM_SELF: int = 65535
class LossTable: class LossTable:
def __init__(self, losses: Dict[float, float]) -> None: def __init__(self, losses: Dict[float, float]) -> None:
self.losses = losses self.losses: Dict[float, float] = losses
self.sinrs = sorted(self.losses.keys()) self.sinrs: List[float] = sorted(self.losses.keys())
self.loss_lookup = {} self.loss_lookup: Dict[int, float] = {}
for index, value in enumerate(self.sinrs): for index, value in enumerate(self.sinrs):
self.loss_lookup[index] = self.losses[value] self.loss_lookup[index] = self.losses[value]
self.mac_id = None self.mac_id: Optional[str] = None
def get_loss(self, sinr: float) -> float: def get_loss(self, sinr: float) -> float:
index = self._get_index(sinr) index = self._get_index(sinr)
@ -54,11 +55,11 @@ class LossTable:
class EmaneLink: class EmaneLink:
def __init__(self, from_nem: int, to_nem: int, sinr: float) -> None: def __init__(self, from_nem: int, to_nem: int, sinr: float) -> None:
self.from_nem = from_nem self.from_nem: int = from_nem
self.to_nem = to_nem self.to_nem: int = to_nem
self.sinr = sinr self.sinr: float = sinr
self.last_seen = None self.last_seen: Optional[float] = None
self.updated = False self.updated: bool = False
self.touch() self.touch()
def update(self, sinr: float) -> None: def update(self, sinr: float) -> None:
@ -78,9 +79,11 @@ class EmaneLink:
class EmaneClient: class EmaneClient:
def __init__(self, address: str) -> None: def __init__(self, address: str) -> None:
self.address = address self.address: str = address
self.client = shell.ControlPortClient(self.address, DEFAULT_PORT) self.client: shell.ControlPortClient = shell.ControlPortClient(
self.nems = {} self.address, DEFAULT_PORT
)
self.nems: Dict[int, LossTable] = {}
self.setup() self.setup()
def setup(self) -> None: def setup(self) -> None:
@ -174,15 +177,15 @@ class EmaneClient:
class EmaneLinkMonitor: class EmaneLinkMonitor:
def __init__(self, emane_manager: "EmaneManager") -> None: def __init__(self, emane_manager: "EmaneManager") -> None:
self.emane_manager = emane_manager self.emane_manager: "EmaneManager" = emane_manager
self.clients = [] self.clients: List[EmaneClient] = []
self.links = {} self.links: Dict[Tuple[int, int], EmaneLink] = {}
self.complete_links = set() self.complete_links: Set[Tuple[int, int]] = set()
self.loss_threshold = None self.loss_threshold: Optional[int] = None
self.link_interval = None self.link_interval: Optional[int] = None
self.link_timeout = None self.link_timeout: Optional[int] = None
self.scheduler = None self.scheduler: Optional[sched.scheduler] = None
self.running = False self.running: bool = False
def start(self) -> None: def start(self) -> None:
self.loss_threshold = int(self.emane_manager.get_config("loss_threshold")) self.loss_threshold = int(self.emane_manager.get_config("loss_threshold"))

View file

@ -16,13 +16,16 @@ from core.emulator.enumerations import (
RegisterTlvs, RegisterTlvs,
TransportType, TransportType,
) )
from core.errors import CoreError
from core.nodes.base import CoreNetworkBase from core.nodes.base import CoreNetworkBase
from core.nodes.interface import CoreInterface from core.nodes.interface import CoreInterface
if TYPE_CHECKING: if TYPE_CHECKING:
from core.emane.emanemodel import EmaneModel
from core.emulator.session import Session from core.emulator.session import Session
from core.location.mobility import WirelessModel from core.location.mobility import WirelessModel, WayPointMobility
OptionalEmaneModel = Optional[EmaneModel]
WirelessModelType = Type[WirelessModel] WirelessModelType = Type[WirelessModel]
try: try:
@ -31,6 +34,7 @@ except ImportError:
try: try:
from emanesh.events import LocationEvent from emanesh.events import LocationEvent
except ImportError: except ImportError:
LocationEvent = None
logging.debug("compatible emane python bindings not installed") logging.debug("compatible emane python bindings not installed")
@ -41,10 +45,10 @@ class EmaneNet(CoreNetworkBase):
Emane controller object that exists in a session. Emane controller object that exists in a session.
""" """
apitype = NodeTypes.EMANE apitype: NodeTypes = NodeTypes.EMANE
linktype = LinkTypes.WIRED linktype: LinkTypes = LinkTypes.WIRED
type = "wlan" type: str = "wlan"
is_emane = True is_emane: bool = True
def __init__( def __init__(
self, self,
@ -55,10 +59,10 @@ class EmaneNet(CoreNetworkBase):
server: DistributedServer = None, server: DistributedServer = None,
) -> None: ) -> None:
super().__init__(session, _id, name, start, server) super().__init__(session, _id, name, start, server)
self.conf = "" self.conf: str = ""
self.nemidmap = {} self.nemidmap: Dict[CoreInterface, int] = {}
self.model = None self.model: "OptionalEmaneModel" = None
self.mobility = None self.mobility: Optional[WayPointMobility] = None
def linkconfig( def linkconfig(
self, netif: CoreInterface, options: LinkOptions, netif2: CoreInterface = None self, netif: CoreInterface, options: LinkOptions, netif2: CoreInterface = None
@ -84,11 +88,11 @@ class EmaneNet(CoreNetworkBase):
def updatemodel(self, config: Dict[str, str]) -> None: def updatemodel(self, config: Dict[str, str]) -> None:
if not self.model: if not self.model:
raise ValueError("no model set to update for node(%s)", self.id) raise CoreError(f"no model set to update for node({self.name})")
logging.info( logging.info(
"node(%s) updating model(%s): %s", self.id, self.model.name, config "node(%s) updating model(%s): %s", self.id, self.model.name, config
) )
self.model.set_configs(config, node_id=self.id) self.model.update_config(config)
def setmodel(self, model: "WirelessModelType", config: Dict[str, str]) -> None: def setmodel(self, model: "WirelessModelType", config: Dict[str, str]) -> None:
""" """

View file

@ -8,11 +8,11 @@ from core.emane import emanemodel
class EmaneRfPipeModel(emanemodel.EmaneModel): class EmaneRfPipeModel(emanemodel.EmaneModel):
# model name # model name
name = "emane_rfpipe" name: str = "emane_rfpipe"
# mac configuration # mac configuration
mac_library = "rfpipemaclayer" mac_library: str = "rfpipemaclayer"
mac_xml = "rfpipemaclayer.xml" mac_xml: str = "rfpipemaclayer.xml"
@classmethod @classmethod
def load(cls, emane_prefix: str) -> None: def load(cls, emane_prefix: str) -> None:

View file

@ -4,6 +4,7 @@ tdma.py: EMANE TDMA model bindings for CORE
import logging import logging
import os import os
from typing import Set
from core import constants, utils from core import constants, utils
from core.config import Configuration from core.config import Configuration
@ -13,18 +14,18 @@ from core.emulator.enumerations import ConfigDataTypes
class EmaneTdmaModel(emanemodel.EmaneModel): class EmaneTdmaModel(emanemodel.EmaneModel):
# model name # model name
name = "emane_tdma" name: str = "emane_tdma"
# mac configuration # mac configuration
mac_library = "tdmaeventschedulerradiomodel" mac_library: str = "tdmaeventschedulerradiomodel"
mac_xml = "tdmaeventschedulerradiomodel.xml" mac_xml: str = "tdmaeventschedulerradiomodel.xml"
# add custom schedule options and ignore it when writing emane xml # add custom schedule options and ignore it when writing emane xml
schedule_name = "schedule" schedule_name: str = "schedule"
default_schedule = os.path.join( default_schedule: str = os.path.join(
constants.CORE_DATA_DIR, "examples", "tdma", "schedule.xml" constants.CORE_DATA_DIR, "examples", "tdma", "schedule.xml"
) )
config_ignore = {schedule_name} config_ignore: Set[str] = {schedule_name}
@classmethod @classmethod
def load(cls, emane_prefix: str) -> None: def load(cls, emane_prefix: str) -> None:

View file

@ -1090,12 +1090,12 @@ class WlanNode(CoreNetwork):
def update_mobility(self, config: Dict[str, str]) -> None: def update_mobility(self, config: Dict[str, str]) -> None:
if not self.mobility: if not self.mobility:
raise ValueError(f"no mobility set to update for node({self.id})") raise CoreError(f"no mobility set to update for node({self.name})")
self.mobility.update_config(config) self.mobility.update_config(config)
def updatemodel(self, config: Dict[str, str]) -> None: def updatemodel(self, config: Dict[str, str]) -> None:
if not self.model: if not self.model:
raise ValueError(f"no model set to update for node({self.id})") raise CoreError(f"no model set to update for node({self.name})")
logging.debug( logging.debug(
"node(%s) updating model(%s): %s", self.id, self.model.name, config "node(%s) updating model(%s): %s", self.id, self.model.name, config
) )