daemon: removed nem map from individual emane networks, all nems are stored and generated from the emane manager

This commit is contained in:
Blake Harnden 2020-07-05 21:29:03 -07:00
parent fcda1f9f14
commit 5cc4d92760
9 changed files with 64 additions and 89 deletions

View file

@ -491,10 +491,13 @@ def iface_to_proto(node_id: int, iface: CoreInterface) -> core_pb2.Interface:
) )
def get_nem_id(node: CoreNode, iface_id: int, context: ServicerContext) -> int: def get_nem_id(
session: Session, node: CoreNode, iface_id: int, context: ServicerContext
) -> int:
""" """
Get nem id for a given node and interface id. Get nem id for a given node and interface id.
:param session: session node belongs to
:param node: node to get nem id for :param node: node to get nem id for
:param iface_id: id of interface on node to get nem id for :param iface_id: id of interface on node to get nem id for
:param context: request context :param context: request context
@ -508,7 +511,7 @@ def get_nem_id(node: CoreNode, iface_id: int, context: ServicerContext) -> int:
if not isinstance(net, EmaneNet): if not isinstance(net, EmaneNet):
message = f"{node.name} interface {iface_id} is not an EMANE network" message = f"{node.name} interface {iface_id} is not an EMANE network"
context.abort(grpc.StatusCode.INVALID_ARGUMENT, message) context.abort(grpc.StatusCode.INVALID_ARGUMENT, message)
nem_id = net.getnemid(iface) nem_id = session.emane.get_nem_id(iface)
if nem_id is None: if nem_id is None:
message = f"{node.name} interface {iface_id} nem id does not exist" message = f"{node.name} interface {iface_id} nem id does not exist"
context.abort(grpc.StatusCode.INVALID_ARGUMENT, message) context.abort(grpc.StatusCode.INVALID_ARGUMENT, message)

View file

@ -1551,29 +1551,29 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
logging.debug("emane link: %s", request) logging.debug("emane link: %s", request)
session = self.get_session(request.session_id, context) session = self.get_session(request.session_id, context)
nem1 = request.nem1 nem1 = request.nem1
emane1, iface = session.emane.nemlookup(nem1) iface1 = session.emane.get_iface(nem1)
if not emane1 or not iface: if not iface1:
context.abort(grpc.StatusCode.NOT_FOUND, f"nem one {nem1} not found") context.abort(grpc.StatusCode.NOT_FOUND, f"nem one {nem1} not found")
node1 = iface.node node1 = iface1.node
nem2 = request.nem2 nem2 = request.nem2
emane2, iface = session.emane.nemlookup(nem2) iface2 = session.emane.get_iface(nem2)
if not emane2 or not iface: if not iface2:
context.abort(grpc.StatusCode.NOT_FOUND, f"nem two {nem2} not found") context.abort(grpc.StatusCode.NOT_FOUND, f"nem two {nem2} not found")
node2 = iface.node node2 = iface2.node
if emane1.id == emane2.id: if iface1.net == iface2.net:
if request.linked: if request.linked:
flag = MessageFlags.ADD flag = MessageFlags.ADD
else: else:
flag = MessageFlags.DELETE flag = MessageFlags.DELETE
color = session.get_link_color(emane1.id) color = session.get_link_color(iface1.net.id)
link = LinkData( link = LinkData(
message_type=flag, message_type=flag,
type=LinkTypes.WIRELESS, type=LinkTypes.WIRELESS,
node1_id=node1.id, node1_id=node1.id,
node2_id=node2.id, node2_id=node2.id,
network_id=emane1.id, network_id=iface1.net.id,
color=color, color=color,
) )
session.broadcast_link(link) session.broadcast_link(link)
@ -1796,8 +1796,8 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
for request in request_iterator: for request in request_iterator:
session = self.get_session(request.session_id, context) session = self.get_session(request.session_id, context)
node1 = self.get_node(session, request.node1_id, context, CoreNode) node1 = self.get_node(session, request.node1_id, context, CoreNode)
nem1 = grpcutils.get_nem_id(node1, request.iface1_id, context) nem1 = grpcutils.get_nem_id(session, node1, request.iface1_id, context)
node2 = self.get_node(session, request.node2_id, context, CoreNode) node2 = self.get_node(session, request.node2_id, context, CoreNode)
nem2 = grpcutils.get_nem_id(node2, request.iface2_id, context) nem2 = grpcutils.get_nem_id(session, node2, request.iface2_id, context)
session.emane.publish_pathloss(nem1, nem2, request.rx1, request.rx2) session.emane.publish_pathloss(nem1, nem2, request.rx1, request.rx2)
return EmanePathlossesResponse() return EmanePathlossesResponse()

View file

@ -10,7 +10,6 @@ from lxml import etree
from core.config import ConfigGroup, Configuration from core.config import ConfigGroup, Configuration
from core.emane import emanemanifest, emanemodel from core.emane import emanemanifest, emanemodel
from core.emane.nodes import EmaneNet
from core.emulator.data import LinkOptions from core.emulator.data import LinkOptions
from core.nodes.interface import CoreInterface from core.nodes.interface import CoreInterface
from core.xml import emanexml from core.xml import emanexml
@ -124,12 +123,11 @@ class EmaneCommEffectModel(emanemodel.EmaneModel):
# TODO: batch these into multiple events per transmission # TODO: batch these into multiple events per transmission
# TODO: may want to split out seconds portion of delay and jitter # TODO: may want to split out seconds portion of delay and jitter
event = CommEffectEvent() event = CommEffectEvent()
emane_node = self.session.get_node(self.id, EmaneNet) nem1 = self.session.emane.get_nem_id(iface)
nemid = emane_node.getnemid(iface) nem2 = self.session.emane.get_nem_id(iface2)
nemid2 = emane_node.getnemid(iface2)
logging.info("sending comm effect event") logging.info("sending comm effect event")
event.append( event.append(
nemid, nem1,
latency=convert_none(options.delay), latency=convert_none(options.delay),
jitter=convert_none(options.jitter), jitter=convert_none(options.jitter),
loss=convert_none(options.loss), loss=convert_none(options.loss),
@ -137,4 +135,4 @@ class EmaneCommEffectModel(emanemodel.EmaneModel):
unicast=int(convert_none(options.bandwidth)), unicast=int(convert_none(options.bandwidth)),
broadcast=int(convert_none(options.bandwidth)), broadcast=int(convert_none(options.bandwidth)),
) )
service.publish(nemid2, event) service.publish(nem2, event)

View file

@ -90,7 +90,8 @@ class EmaneManager(ModelManager):
""" """
super().__init__() super().__init__()
self.session: "Session" = session self.session: "Session" = session
self.nems: Dict[int, CoreInterface] = {} self.nems_to_ifaces: Dict[int, CoreInterface] = {}
self.ifaces_to_nems: Dict[CoreInterface, int] = {}
self._emane_nets: Dict[int, EmaneNet] = {} self._emane_nets: Dict[int, EmaneNet] = {}
self._emane_node_lock: threading.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
@ -117,7 +118,7 @@ class EmaneManager(ModelManager):
def next_nem_id(self) -> int: def next_nem_id(self) -> int:
nem_id = int(self.get_config("nem_id_start")) nem_id = int(self.get_config("nem_id_start"))
while nem_id in self.nems: while nem_id in self.nems_to_ifaces:
nem_id += 1 nem_id += 1
return nem_id return nem_id
@ -363,7 +364,7 @@ class EmaneManager(ModelManager):
0, remove=False, conf_required=False 0, remove=False, conf_required=False
) )
nem_id = self.next_nem_id() nem_id = self.next_nem_id()
self.nems[nem_id] = iface self.set_nem(nem_id, iface)
self.write_nem(iface, nem_id) self.write_nem(iface, nem_id)
emanexml.build_platform_xml(self, control_net, emane_net, iface, nem_id) emanexml.build_platform_xml(self, control_net, emane_net, iface, nem_id)
config = self.get_iface_config(emane_net, iface) config = self.get_iface_config(emane_net, iface)
@ -371,6 +372,18 @@ class EmaneManager(ModelManager):
self.start_daemon(iface) self.start_daemon(iface)
self.install_iface(emane_net, iface) self.install_iface(emane_net, iface)
def set_nem(self, nem_id: int, iface: CoreInterface) -> None:
if nem_id in self.nems_to_ifaces:
raise CoreError(f"adding duplicate nem: {nem_id}")
self.nems_to_ifaces[nem_id] = iface
self.ifaces_to_nems[iface] = nem_id
def get_iface(self, nem_id: int) -> Optional[CoreInterface]:
return self.nems_to_ifaces.get(nem_id)
def get_nem_id(self, iface: CoreInterface) -> Optional[int]:
return self.ifaces_to_nems.get(iface)
def write_nem(self, iface: CoreInterface, nem_id: int) -> None: def write_nem(self, iface: CoreInterface, nem_id: int) -> None:
path = os.path.join(self.session.session_dir, "emane_nems") path = os.path.join(self.session.session_dir, "emane_nems")
try: try:
@ -405,7 +418,8 @@ class EmaneManager(ModelManager):
""" """
with self._emane_node_lock: with self._emane_node_lock:
self._emane_nets.clear() self._emane_nets.clear()
self.nems.clear() self.nems_to_ifaces.clear()
self.ifaces_to_nems.clear()
def shutdown(self) -> None: def shutdown(self) -> None:
""" """
@ -448,42 +462,29 @@ class EmaneManager(ModelManager):
model_class = self.models[model_name] model_class = self.models[model_name]
emane_net.setmodel(model_class, config) emane_net.setmodel(model_class, config)
def nemlookup(self, nemid) -> Tuple[Optional[EmaneNet], Optional[CoreInterface]]:
"""
Look for the given numerical NEM ID and return the first matching
EMANE network and NEM interface.
"""
emane_node = None
iface = None
for node_id in self._emane_nets:
emane_node = self._emane_nets[node_id]
iface = emane_node.get_nem_iface(nemid)
if iface is not None:
break
else:
emane_node = None
return emane_node, iface
def get_nem_link( def get_nem_link(
self, nem1: int, nem2: int, flags: MessageFlags = MessageFlags.NONE self, nem1: int, nem2: int, flags: MessageFlags = MessageFlags.NONE
) -> Optional[LinkData]: ) -> Optional[LinkData]:
emane1, iface = self.nemlookup(nem1) iface1 = self.get_iface(nem1)
if not emane1 or not iface: if not iface1:
logging.error("invalid nem: %s", nem1) logging.error("invalid nem: %s", nem1)
return None return None
node1 = iface.node node1 = iface1.node
emane2, iface = self.nemlookup(nem2) iface2 = self.get_iface(nem2)
if not emane2 or not iface: if not iface2:
logging.error("invalid nem: %s", nem2) logging.error("invalid nem: %s", nem2)
return None return None
node2 = iface.node node2 = iface2.node
color = self.session.get_link_color(emane1.id) if iface1.net != iface2.net:
return None
emane_net = iface1.net
color = self.session.get_link_color(emane_net.id)
return LinkData( return LinkData(
message_type=flags, message_type=flags,
type=LinkTypes.WIRELESS, type=LinkTypes.WIRELESS,
node1_id=node1.id, node1_id=node1.id,
node2_id=node2.id, node2_id=node2.id,
network_id=emane1.id, network_id=emane_net.id,
color=color, color=color,
) )
@ -728,7 +729,7 @@ class EmaneManager(ModelManager):
Returns True if successfully parsed and a Node Message was sent. Returns True if successfully parsed and a Node Message was sent.
""" """
# convert nemid to node number # convert nemid to node number
_emanenode, iface = self.nemlookup(nemid) iface = self.get_iface(nemid)
if iface is None: if iface is None:
logging.info("location event for unknown NEM %s", nemid) logging.info("location event for unknown NEM %s", nemid)
return False return False

View file

@ -52,7 +52,6 @@ class EmaneNet(CoreNetworkBase):
) -> None: ) -> None:
super().__init__(session, _id, name, server) super().__init__(session, _id, name, server)
self.conf: str = "" self.conf: str = ""
self.nemidmap: Dict[CoreInterface, int] = {}
self.model: "OptionalEmaneModel" = None self.model: "OptionalEmaneModel" = None
self.mobility: Optional[WayPointMobility] = None self.mobility: Optional[WayPointMobility] = None
@ -105,32 +104,6 @@ class EmaneNet(CoreNetworkBase):
self.mobility = model(session=self.session, _id=self.id) self.mobility = model(session=self.session, _id=self.id)
self.mobility.update_config(config) self.mobility.update_config(config)
def setnemid(self, iface: CoreInterface, nemid: int) -> None:
"""
Record an interface to numerical ID mapping. The Emane controller
object manages and assigns these IDs for all NEMs.
"""
self.nemidmap[iface] = nemid
def getnemid(self, iface: CoreInterface) -> Optional[int]:
"""
Given an interface, return its numerical ID.
"""
if iface not in self.nemidmap:
return None
else:
return self.nemidmap[iface]
def get_nem_iface(self, nemid: int) -> Optional[CoreInterface]:
"""
Given a numerical NEM ID, return its interface. This returns the
first interface that matches the given NEM ID.
"""
for iface in self.nemidmap:
if self.nemidmap[iface] == nemid:
return iface
return None
def _nem_position( def _nem_position(
self, iface: CoreInterface self, iface: CoreInterface
) -> Optional[Tuple[int, float, float, float]]: ) -> Optional[Tuple[int, float, float, float]]:
@ -140,9 +113,9 @@ class EmaneNet(CoreNetworkBase):
:param iface: interface to get nem emane position for :param iface: interface to get nem emane position for
:return: nem position tuple, None otherwise :return: nem position tuple, None otherwise
""" """
nemid = self.getnemid(iface) nem_id = self.session.emane.get_nem_id(iface)
ifname = iface.localname ifname = iface.localname
if nemid is None: if nem_id is None:
logging.info("nemid for %s is unknown", ifname) logging.info("nemid for %s is unknown", ifname)
return return
node = iface.node node = iface.node
@ -153,7 +126,7 @@ class EmaneNet(CoreNetworkBase):
node.position.set_geo(lon, lat, alt) node.position.set_geo(lon, lat, alt)
# altitude must be an integer or warning is printed # altitude must be an integer or warning is printed
alt = int(round(alt)) alt = int(round(alt))
return nemid, lon, lat, alt return nem_id, lon, lat, alt
def setnemposition(self, iface: CoreInterface) -> None: def setnemposition(self, iface: CoreInterface) -> None:
""" """
@ -164,7 +137,6 @@ class EmaneNet(CoreNetworkBase):
if self.session.emane.service is None: if self.session.emane.service is None:
logging.info("position service not available") logging.info("position service not available")
return return
position = self._nem_position(iface) position = self._nem_position(iface)
if position: if position:
nemid, lon, lat, alt = position nemid, lon, lat, alt = position
@ -195,9 +167,12 @@ class EmaneNet(CoreNetworkBase):
def links(self, flags: MessageFlags = MessageFlags.NONE) -> List[LinkData]: def links(self, flags: MessageFlags = MessageFlags.NONE) -> List[LinkData]:
links = super().links(flags) links = super().links(flags)
# gather current emane links
nem_ids = set(self.nemidmap.values())
emane_manager = self.session.emane emane_manager = self.session.emane
# gather current emane links
nem_ids = set()
for iface in self.get_ifaces():
nem_id = emane_manager.get_nem_id(iface)
nem_ids.add(nem_id)
emane_links = emane_manager.link_monitor.links emane_links = emane_manager.link_monitor.links
considered = set() considered = set()
for link_key in emane_links: for link_key in emane_links:

View file

@ -28,7 +28,7 @@ class EmaneTransportService(CoreService):
emane_net = iface.net emane_net = iface.net
config = emane_manager.get_iface_config(emane_net, iface) config = emane_manager.get_iface_config(emane_net, iface)
if emanexml.is_external(config): if emanexml.is_external(config):
nem_id = emane_net.getnemid(iface) nem_id = emane_manager.get_nem_id(iface)
cfg += f"emanegentransportxml {iface.name}-platform.xml\n" cfg += f"emanegentransportxml {iface.name}-platform.xml\n"
cfg += f"emanetransportd -r -l 0 -d transportdaemon{nem_id}.xml\n" cfg += f"emanetransportd -r -l 0 -d transportdaemon{nem_id}.xml\n"
return cfg return cfg

View file

@ -501,8 +501,8 @@ class CoreXmlWriter:
iface = node.get_iface(iface_data.id) iface = node.get_iface(iface_data.id)
# check if emane interface # check if emane interface
if isinstance(iface.net, EmaneNet): if isinstance(iface.net, EmaneNet):
nem = iface.net.getnemid(iface) nem_id = self.session.emane.get_nem_id(iface)
add_attribute(iface_element, "nem", nem) add_attribute(iface_element, "nem", nem_id)
add_attribute(iface_element, "id", iface_data.id) add_attribute(iface_element, "id", iface_data.id)
add_attribute(iface_element, "name", iface_data.name) add_attribute(iface_element, "name", iface_data.name)
add_attribute(iface_element, "mac", iface_data.mac) add_attribute(iface_element, "mac", iface_data.mac)

View file

@ -9,7 +9,6 @@ from core import utils
from core.emane.nodes import EmaneNet from core.emane.nodes import EmaneNet
from core.executables import IP from core.executables import IP
from core.nodes.base import CoreNodeBase, NodeBase from core.nodes.base import CoreNodeBase, NodeBase
from core.nodes.interface import CoreInterface
if TYPE_CHECKING: if TYPE_CHECKING:
from core.emulator.session import Session from core.emulator.session import Session
@ -38,11 +37,10 @@ def add_mapping(parent_element: etree.Element, maptype: str, mapref: str) -> Non
def add_emane_iface( def add_emane_iface(
host_element: etree.Element, host_element: etree.Element,
iface: CoreInterface, nem_id: int,
platform_name: str = "p1", platform_name: str = "p1",
transport_name: str = "t1", transport_name: str = "t1",
) -> etree.Element: ) -> etree.Element:
nem_id = iface.net.nemidmap[iface]
host_id = host_element.get("id") host_id = host_element.get("id")
# platform data # platform data
@ -158,7 +156,8 @@ class CoreXmlDeployment:
for iface in node.get_ifaces(): for iface in node.get_ifaces():
emane_element = None emane_element = None
if isinstance(iface.net, EmaneNet): if isinstance(iface.net, EmaneNet):
emane_element = add_emane_iface(host_element, iface) nem_id = self.session.emane.get_nem_id(iface)
emane_element = add_emane_iface(host_element, nem_id)
parent_element = host_element parent_element = host_element
if emane_element is not None: if emane_element is not None:

View file

@ -193,7 +193,6 @@ def build_platform_xml(
value = emane_manager.get_config(name) value = emane_manager.get_config(name)
add_param(platform_element, name, value) add_param(platform_element, name, value)
platform_element.append(nem_element) platform_element.append(nem_element)
emane_net.setnemid(iface, nem_id)
mac = _MAC_PREFIX + ":00:00:" mac = _MAC_PREFIX + ":00:00:"
mac += f"{(nem_id >> 8) & 0xFF:02X}:{nem_id & 0xFF:02X}" mac += f"{(nem_id >> 8) & 0xFF:02X}:{nem_id & 0xFF:02X}"
iface.set_mac(mac) iface.set_mac(mac)