daemon: adjustments to revamp how core nodes are created in session.add_node, nodes now provide a create_options function for node specific options that are type hinted

This commit is contained in:
Blake Harnden 2022-05-25 10:51:42 -07:00
parent 03e646031c
commit 2e3e085522
35 changed files with 646 additions and 478 deletions

View file

@ -17,15 +17,22 @@ from core.api.grpc.services_pb2 import (
ServiceDefaults, ServiceDefaults,
) )
from core.config import ConfigurableOptions from core.config import ConfigurableOptions
from core.emane.nodes import EmaneNet from core.emane.nodes import EmaneNet, EmaneOptions
from core.emulator.data import InterfaceData, LinkData, LinkOptions, NodeOptions from core.emulator.data import InterfaceData, LinkData, LinkOptions
from core.emulator.enumerations import LinkTypes, NodeTypes from core.emulator.enumerations import LinkTypes, NodeTypes
from core.emulator.links import CoreLink from core.emulator.links import CoreLink
from core.emulator.session import Session from core.emulator.session import Session
from core.errors import CoreError from core.errors import CoreError
from core.location.mobility import BasicRangeModel, Ns2ScriptedMobility from core.location.mobility import BasicRangeModel, Ns2ScriptedMobility
from core.nodes.base import CoreNode, CoreNodeBase, NodeBase from core.nodes.base import (
from core.nodes.docker import DockerNode CoreNode,
CoreNodeBase,
CoreNodeOptions,
NodeBase,
NodeOptions,
Position,
)
from core.nodes.docker import DockerNode, DockerOptions
from core.nodes.interface import CoreInterface from core.nodes.interface import CoreInterface
from core.nodes.lxd import LxcNode from core.nodes.lxd import LxcNode
from core.nodes.network import CoreNetwork, CtrlNet, PtpNet, WlanNode from core.nodes.network import CoreNetwork, CtrlNet, PtpNet, WlanNode
@ -55,34 +62,33 @@ class CpuUsage:
return (total_diff - idle_diff) / total_diff return (total_diff - idle_diff) / total_diff
def add_node_data(node_proto: core_pb2.Node) -> Tuple[NodeTypes, int, NodeOptions]: def add_node_data(
_class: Type[NodeBase], node_proto: core_pb2.Node
) -> Tuple[Position, NodeOptions]:
""" """
Convert node protobuf message to data for creating a node. Convert node protobuf message to data for creating a node.
:param _class: node class to create options from
:param node_proto: node proto message :param node_proto: node proto message
:return: node type, id, and options :return: node type, id, and options
""" """
_id = node_proto.id options = _class.create_options()
_type = NodeTypes(node_proto.type) options.icon = node_proto.icon
options = NodeOptions( options.canvas = node_proto.canvas
name=node_proto.name, if isinstance(options, CoreNodeOptions):
model=node_proto.model, options.model = node_proto.model
icon=node_proto.icon, options.services = node_proto.services
image=node_proto.image, options.config_services = node_proto.config_services
services=node_proto.services, if isinstance(options, EmaneOptions):
config_services=node_proto.config_services, options.emane_model = node_proto.emane
canvas=node_proto.canvas, if isinstance(options, DockerOptions):
) options.image = node_proto.image
if node_proto.emane: position = Position()
options.emane = node_proto.emane position.set(node_proto.position.x, node_proto.position.y)
if node_proto.server:
options.server = node_proto.server
position = node_proto.position
options.set_position(position.x, position.y)
if node_proto.HasField("geo"): if node_proto.HasField("geo"):
geo = node_proto.geo geo = node_proto.geo
options.set_location(geo.lat, geo.lon, geo.alt) position.set_geo(geo.lon, geo.lat, geo.alt)
return _type, _id, options return position, options
def link_iface(iface_proto: core_pb2.Interface) -> InterfaceData: def link_iface(iface_proto: core_pb2.Interface) -> InterfaceData:
@ -150,9 +156,17 @@ def create_nodes(
""" """
funcs = [] funcs = []
for node_proto in node_protos: for node_proto in node_protos:
_type, _id, options = add_node_data(node_proto) _type = NodeTypes(node_proto.type)
_class = session.get_node_class(_type) _class = session.get_node_class(_type)
args = (_class, _id, options) position, options = add_node_data(_class, node_proto)
args = (
_class,
node_proto.id or None,
node_proto.name or None,
node_proto.server or None,
position,
options,
)
funcs.append((session.add_node, args, {})) funcs.append((session.add_node, args, {}))
start = time.monotonic() start = time.monotonic()
results, exceptions = utils.threadpool(funcs) results, exceptions = utils.threadpool(funcs)

View file

@ -88,7 +88,12 @@ from core.configservice.base import ConfigServiceBootError
from core.emane.modelmanager import EmaneModelManager from core.emane.modelmanager import EmaneModelManager
from core.emulator.coreemu import CoreEmu from core.emulator.coreemu import CoreEmu
from core.emulator.data import InterfaceData, LinkData, LinkOptions from core.emulator.data import InterfaceData, LinkData, LinkOptions
from core.emulator.enumerations import EventTypes, ExceptionLevels, MessageFlags from core.emulator.enumerations import (
EventTypes,
ExceptionLevels,
MessageFlags,
NodeTypes,
)
from core.emulator.session import NT, Session from core.emulator.session import NT, Session
from core.errors import CoreCommandError, CoreError from core.errors import CoreCommandError, CoreError
from core.location.mobility import BasicRangeModel, Ns2ScriptedMobility from core.location.mobility import BasicRangeModel, Ns2ScriptedMobility
@ -548,9 +553,17 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
""" """
logger.debug("add node: %s", request) logger.debug("add node: %s", request)
session = self.get_session(request.session_id, context) session = self.get_session(request.session_id, context)
_type, _id, options = grpcutils.add_node_data(request.node) _type = NodeTypes(request.node.type)
_class = session.get_node_class(_type) _class = session.get_node_class(_type)
node = session.add_node(_class, _id, options) position, options = grpcutils.add_node_data(_class, request.node)
node = session.add_node(
_class,
request.node.id or None,
request.node.name or None,
request.node.server or None,
position,
options,
)
grpcutils.configure_node(session, request.node, node, context) grpcutils.configure_node(session, request.node, node, context)
source = request.source if request.source else None source = request.source if request.source else None
session.broadcast_node(node, MessageFlags.ADD, source) session.broadcast_node(node, MessageFlags.ADD, source)

View file

@ -603,7 +603,7 @@ class EmaneManager:
node = iface.node node = iface.node
loglevel = str(DEFAULT_LOG_LEVEL) loglevel = str(DEFAULT_LOG_LEVEL)
cfgloglevel = self.session.options.get_int("emane_log_level", 2) cfgloglevel = self.session.options.get_int("emane_log_level", 2)
realtime = self.session.options.get_bool("emane_realtime") realtime = self.session.options.get_bool("emane_realtime", True)
if cfgloglevel: if cfgloglevel:
logger.info("setting user-defined emane log level: %d", cfgloglevel) logger.info("setting user-defined emane log level: %d", cfgloglevel)
loglevel = str(cfgloglevel) loglevel = str(cfgloglevel)

View file

@ -5,13 +5,14 @@ share the same MAC+PHY model.
import logging import logging
import time import time
from dataclasses import dataclass
from typing import TYPE_CHECKING, Callable, Dict, List, Optional, Type, Union from typing import TYPE_CHECKING, Callable, Dict, List, Optional, Type, Union
from core.emulator.data import InterfaceData, LinkData, LinkOptions from core.emulator.data import InterfaceData, LinkData, LinkOptions
from core.emulator.distributed import DistributedServer from core.emulator.distributed import DistributedServer
from core.emulator.enumerations import EventTypes, MessageFlags, RegisterTlvs from core.emulator.enumerations import EventTypes, MessageFlags, RegisterTlvs
from core.errors import CoreCommandError, CoreError from core.errors import CoreCommandError, CoreError
from core.nodes.base import CoreNetworkBase, CoreNode from core.nodes.base import CoreNetworkBase, CoreNode, NodeOptions
from core.nodes.interface import CoreInterface from core.nodes.interface import CoreInterface
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -139,6 +140,12 @@ class TunTap(CoreInterface):
self.node.node_net_client.create_address(self.name, str(ip)) self.node.node_net_client.create_address(self.name, str(ip))
@dataclass
class EmaneOptions(NodeOptions):
emane_model: str = None
"""name of emane model to associate an emane network to"""
class EmaneNet(CoreNetworkBase): class EmaneNet(CoreNetworkBase):
""" """
EMANE node contains NEM configuration and causes connected nodes EMANE node contains NEM configuration and causes connected nodes
@ -152,11 +159,20 @@ class EmaneNet(CoreNetworkBase):
_id: int = None, _id: int = None,
name: str = None, name: str = None,
server: DistributedServer = None, server: DistributedServer = None,
options: EmaneOptions = None,
) -> None: ) -> None:
super().__init__(session, _id, name, server) options = options or EmaneOptions()
super().__init__(session, _id, name, server, options)
self.conf: str = "" self.conf: str = ""
self.wireless_model: Optional["EmaneModel"] = None
self.mobility: Optional[WayPointMobility] = None self.mobility: Optional[WayPointMobility] = None
model_class = self.session.emane.get_model(options.emane_model)
self.wireless_model: Optional["EmaneModel"] = model_class(self.session, self.id)
if self.session.state == EventTypes.RUNTIME_STATE:
self.session.emane.add_node(self)
@classmethod
def create_options(cls) -> EmaneOptions:
return EmaneOptions()
def linkconfig( def linkconfig(
self, iface: CoreInterface, options: LinkOptions, iface2: CoreInterface = None self, iface: CoreInterface, options: LinkOptions, iface2: CoreInterface = None

View file

@ -14,7 +14,7 @@ import tempfile
import threading import threading
import time import time
from pathlib import Path from pathlib import Path
from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Type, TypeVar, Union from typing import Callable, Dict, List, Optional, Set, Tuple, Type, TypeVar, Union
from core import constants, utils from core import constants, utils
from core.configservice.manager import ConfigServiceManager from core.configservice.manager import ConfigServiceManager
@ -29,7 +29,6 @@ from core.emulator.data import (
LinkData, LinkData,
LinkOptions, LinkOptions,
NodeData, NodeData,
NodeOptions,
) )
from core.emulator.distributed import DistributedController from core.emulator.distributed import DistributedController
from core.emulator.enumerations import ( from core.emulator.enumerations import (
@ -44,7 +43,7 @@ from core.errors import CoreError
from core.location.event import EventLoop from core.location.event import EventLoop
from core.location.geo import GeoLocation from core.location.geo import GeoLocation
from core.location.mobility import BasicRangeModel, MobilityManager from core.location.mobility import BasicRangeModel, MobilityManager
from core.nodes.base import CoreNetworkBase, CoreNode, CoreNodeBase, NodeBase from core.nodes.base import CoreNode, CoreNodeBase, NodeBase, NodeOptions, Position
from core.nodes.docker import DockerNode from core.nodes.docker import DockerNode
from core.nodes.interface import DEFAULT_MTU, CoreInterface from core.nodes.interface import DEFAULT_MTU, CoreInterface
from core.nodes.lxd import LxcNode from core.nodes.lxd import LxcNode
@ -476,14 +475,23 @@ class Session:
return _id return _id
def add_node( def add_node(
self, _class: Type[NT], _id: int = None, options: NodeOptions = None self,
_class: Type[NT],
_id: int = None,
name: str = None,
server: str = None,
position: Position = None,
options: NodeOptions = None,
) -> NT: ) -> NT:
""" """
Add a node to the session, based on the provided node data. Add a node to the session, based on the provided node data.
:param _class: node class to create :param _class: node class to create
:param _id: id for node, defaults to None for generated id :param _id: id for node, defaults to None for generated id
:param options: data to create node with :param name: name to assign to node
:param server: distributed server for node, if desired
:param position: geo or x/y/z position to set
:param options: options to create node with
:return: created node :return: created node
:raises core.CoreError: when an invalid node type is given :raises core.CoreError: when an invalid node type is given
""" """
@ -492,89 +500,31 @@ class Session:
enable_rj45 = self.options.get_int("enablerj45") == 1 enable_rj45 = self.options.get_int("enablerj45") == 1
if _class == Rj45Node and not enable_rj45: if _class == Rj45Node and not enable_rj45:
start = False start = False
# generate options if not provided
# determine node id options = options if options else _class.create_options()
if not _id:
_id = self.next_node_id()
# generate name if not provided
if not options:
options = NodeOptions()
options.set_position(0, 0)
name = options.name
if not name:
name = f"{_class.__name__}{_id}"
# verify distributed server # verify distributed server
server = self.distributed.servers.get(options.server) dist_server = None
if options.server is not None and server is None: if server is not None:
raise CoreError(f"invalid distributed server: {options.server}") dist_server = self.distributed.servers.get(server)
if not dist_server:
raise CoreError(f"invalid distributed server: {server}")
# create node # create node
logger.info( node = self.create_node(_class, start, _id, name, dist_server, options)
"creating node(%s) id(%s) name(%s) start(%s)", # set node position
_class.__name__, position = position or Position()
_id, if position.has_geo():
name, self.set_node_geo(node, position.lon, position.lat, position.alt)
start,
)
kwargs = dict(_id=_id, name=name, server=server)
if _class in CONTAINER_NODES:
kwargs["image"] = options.image
kwargs["binds"] = options.binds
kwargs["volumes"] = options.volumes
node = self.create_node(_class, start, **kwargs)
# set node attributes
node.icon = options.icon
node.canvas = options.canvas
# set node position and broadcast it
has_geo = all(i is not None for i in [options.lon, options.lat, options.alt])
if has_geo:
self.set_node_geo(node, options.lon, options.lat, options.alt)
else: else:
self.set_node_pos(node, options.x, options.y) self.set_node_pos(node, position.x, position.y)
# setup default wlan
# add services to needed nodes
if isinstance(node, (CoreNode, PhysicalNode)):
node.model = options.model
if options.legacy or options.services:
logger.debug("set node type: %s", node.model)
self.services.add_services(node, node.model, options.services)
# add config services
config_services = options.config_services
if not options.legacy and not config_services and not node.services:
config_services = self.services.default_services.get(node.model, [])
logger.info("setting node config services: %s", config_services)
for name in config_services:
service_class = self.service_manager.get_service(name)
node.add_config_service(service_class)
# set network mtu, if configured
mtu = self.options.get_int("mtu")
if isinstance(node, CoreNetworkBase) and mtu > 0:
node.mtu = mtu
# ensure default emane configuration
if isinstance(node, EmaneNet) and options.emane:
model_class = self.emane.get_model(options.emane)
node.wireless_model = model_class(self, node.id)
if self.state == EventTypes.RUNTIME_STATE:
self.emane.add_node(node)
# set default wlan config if needed
if isinstance(node, WlanNode): if isinstance(node, WlanNode):
self.mobility.set_model_config(_id, BasicRangeModel.name) self.mobility.set_model_config(self.id, BasicRangeModel.name)
# boot core nodes after runtime
# boot nodes after runtime CoreNodes and PhysicalNodes is_runtime = self.state == EventTypes.RUNTIME_STATE
is_boot_node = isinstance(node, (CoreNode, PhysicalNode)) if is_runtime and isinstance(node, CoreNode):
if self.state == EventTypes.RUNTIME_STATE and is_boot_node:
self.write_nodes() self.write_nodes()
self.add_remove_control_iface(node, remove=False) self.add_remove_control_iface(node, remove=False)
self.boot_node(node) self.boot_node(node)
self.sdt.add_node(node) self.sdt.add_node(node)
return node return node
@ -980,24 +930,39 @@ class Session:
logger.exception("failed to set permission on %s", self.directory) logger.exception("failed to set permission on %s", self.directory)
def create_node( def create_node(
self, _class: Type[NT], start: bool, *args: Any, **kwargs: Any self,
_class: Type[NT],
start: bool,
_id: int = None,
name: str = None,
server: str = None,
options: NodeOptions = None,
) -> NT: ) -> NT:
""" """
Create an emulation node. Create an emulation node.
:param _class: node class to create :param _class: node class to create
:param start: True to start node, False otherwise :param start: True to start node, False otherwise
:param args: list of arguments for the class to create :param _id: id for node, defaults to None for generated id
:param kwargs: dictionary of arguments for the class to create :param name: name to assign to node
:param server: distributed server for node, if desired
:param options: options to create node with
:return: the created node instance :return: the created node instance
:raises core.CoreError: when id of the node to create already exists :raises core.CoreError: when id of the node to create already exists
""" """
with self.nodes_lock: with self.nodes_lock:
node = _class(self, *args, **kwargs) node = _class(self, _id=_id, name=name, server=server, options=options)
if node.id in self.nodes: if node.id in self.nodes:
node.shutdown() node.shutdown()
raise CoreError(f"duplicate node id {node.id} for {node.name}") raise CoreError(f"duplicate node id {node.id} for {node.name}")
self.nodes[node.id] = node self.nodes[node.id] = node
logger.info(
"created node(%s) id(%s) name(%s) start(%s)",
_class.__name__,
node.id,
node.name,
start,
)
if start: if start:
node.startup() node.startup()
return node return node
@ -1219,7 +1184,7 @@ class Session:
funcs = [] funcs = []
start = time.monotonic() start = time.monotonic()
for node in self.nodes.values(): for node in self.nodes.values():
if isinstance(node, (CoreNode, PhysicalNode)): if isinstance(node, CoreNode):
self.add_remove_control_iface(node, remove=False) self.add_remove_control_iface(node, remove=False)
funcs.append((self.boot_node, (node,), {})) funcs.append((self.boot_node, (node,), {}))
results, exceptions = utils.threadpool(funcs) results, exceptions = utils.threadpool(funcs)
@ -1354,21 +1319,18 @@ class Session:
updown_script, updown_script,
server_iface, server_iface,
) )
control_net = self.create_node( options = CtrlNet.create_options()
CtrlNet, options.prefix = prefix
start=False, options.updown_script = updown_script
prefix=prefix, options.serverintf = server_iface
_id=_id, control_net = self.create_node(CtrlNet, False, _id, options=options)
updown_script=updown_script,
serverintf=server_iface,
)
control_net.brname = f"ctrl{net_index}.{self.short_session_id()}" control_net.brname = f"ctrl{net_index}.{self.short_session_id()}"
control_net.startup() control_net.startup()
return control_net return control_net
def add_remove_control_iface( def add_remove_control_iface(
self, self,
node: Union[CoreNode, PhysicalNode], node: CoreNode,
net_index: int = 0, net_index: int = 0,
remove: bool = False, remove: bool = False,
conf_required: bool = True, conf_required: bool = True,

View file

@ -5,6 +5,7 @@ import abc
import logging import logging
import shutil import shutil
import threading import threading
from dataclasses import dataclass, field
from pathlib import Path from pathlib import Path
from threading import RLock from threading import RLock
from typing import TYPE_CHECKING, Dict, List, Optional, Tuple, Type, Union from typing import TYPE_CHECKING, Dict, List, Optional, Tuple, Type, Union
@ -33,6 +34,94 @@ if TYPE_CHECKING:
PRIVATE_DIRS: List[Path] = [Path("/var/run"), Path("/var/log")] PRIVATE_DIRS: List[Path] = [Path("/var/run"), Path("/var/log")]
@dataclass
class Position:
"""
Helper class for Cartesian coordinate position
"""
x: float = 0.0
y: float = 0.0
z: float = 0.0
lon: float = None
lat: float = None
alt: float = None
def set(self, x: float = None, y: float = None, z: float = None) -> bool:
"""
Returns True if the position has actually changed.
:param x: x position
:param y: y position
:param z: z position
:return: True if position changed, False otherwise
"""
if self.x == x and self.y == y and self.z == z:
return False
self.x = x
self.y = y
self.z = z
return True
def get(self) -> Tuple[float, float, float]:
"""
Retrieve x,y,z position.
:return: x,y,z position tuple
"""
return self.x, self.y, self.z
def has_geo(self) -> bool:
return all(x is not None for x in [self.lon, self.lat, self.alt])
def set_geo(self, lon: float, lat: float, alt: float) -> None:
"""
Set geo position lon, lat, alt.
:param lon: longitude value
:param lat: latitude value
:param alt: altitude value
:return: nothing
"""
self.lon = lon
self.lat = lat
self.alt = alt
def get_geo(self) -> Tuple[float, float, float]:
"""
Retrieve current geo position lon, lat, alt.
:return: lon, lat, alt position tuple
"""
return self.lon, self.lat, self.alt
@dataclass
class NodeOptions:
"""
Base options for configuring a node.
"""
canvas: int = None
"""id of canvas for display within gui"""
icon: str = None
"""custom icon for display, None for default"""
@dataclass
class CoreNodeOptions(NodeOptions):
model: str = "PC"
"""model is used for providing a default set of services"""
services: List[str] = field(default_factory=list)
"""services to start within node"""
config_services: List[str] = field(default_factory=list)
"""config services to start within node"""
directory: Path = None
"""directory to define node, defaults to path under the session directory"""
legacy: bool = False
"""legacy nodes default to standard services"""
class NodeBase(abc.ABC): class NodeBase(abc.ABC):
""" """
Base class for CORE nodes (nodes and networks) Base class for CORE nodes (nodes and networks)
@ -44,6 +133,7 @@ class NodeBase(abc.ABC):
_id: int = None, _id: int = None,
name: str = None, name: str = None,
server: "DistributedServer" = None, server: "DistributedServer" = None,
options: NodeOptions = None,
) -> None: ) -> None:
""" """
Creates a NodeBase instance. Creates a NodeBase instance.
@ -53,26 +143,29 @@ class NodeBase(abc.ABC):
:param name: object name :param name: object name
:param server: remote server node :param server: remote server node
will run on, default is None for localhost will run on, default is None for localhost
:param options: options to create node with
""" """
self.session: "Session" = session self.session: "Session" = session
if _id is None: self.id: int = _id if _id is not None else self.session.next_node_id()
_id = session.next_node_id() self.name: str = name or f"{self.__class__.__name__}{self.id}"
self.id: int = _id
self.name: str = name or f"o{self.id}"
self.server: "DistributedServer" = server self.server: "DistributedServer" = server
self.model: Optional[str] = None self.model: Optional[str] = None
self.services: CoreServices = [] self.services: CoreServices = []
self.ifaces: Dict[int, CoreInterface] = {} self.ifaces: Dict[int, CoreInterface] = {}
self.iface_id: int = 0 self.iface_id: int = 0
self.canvas: Optional[int] = None
self.icon: Optional[str] = None
self.position: Position = Position() self.position: Position = Position()
self.up: bool = False self.up: bool = False
self.lock: RLock = RLock() self.lock: RLock = RLock()
self.net_client: LinuxNetClient = get_net_client( self.net_client: LinuxNetClient = get_net_client(
self.session.use_ovs(), self.host_cmd self.session.use_ovs(), self.host_cmd
) )
options = options if options else NodeOptions()
self.canvas: Optional[int] = options.canvas
self.icon: Optional[str] = options.icon
@classmethod
def create_options(cls) -> NodeOptions:
return NodeOptions()
@abc.abstractmethod @abc.abstractmethod
def startup(self) -> None: def startup(self) -> None:
@ -288,6 +381,7 @@ class CoreNodeBase(NodeBase):
_id: int = None, _id: int = None,
name: str = None, name: str = None,
server: "DistributedServer" = None, server: "DistributedServer" = None,
options: NodeOptions = None,
) -> None: ) -> None:
""" """
Create a CoreNodeBase instance. Create a CoreNodeBase instance.
@ -298,7 +392,7 @@ class CoreNodeBase(NodeBase):
:param server: remote server node :param server: remote server node
will run on, default is None for localhost will run on, default is None for localhost
""" """
super().__init__(session, _id, name, server) super().__init__(session, _id, name, server, options)
self.config_services: Dict[str, "ConfigService"] = {} self.config_services: Dict[str, "ConfigService"] = {}
self.directory: Optional[Path] = None self.directory: Optional[Path] = None
self.tmpnodedir: bool = False self.tmpnodedir: bool = False
@ -460,8 +554,8 @@ class CoreNode(CoreNodeBase):
session: "Session", session: "Session",
_id: int = None, _id: int = None,
name: str = None, name: str = None,
directory: Path = None,
server: "DistributedServer" = None, server: "DistributedServer" = None,
options: CoreNodeOptions = None,
) -> None: ) -> None:
""" """
Create a CoreNode instance. Create a CoreNode instance.
@ -469,18 +563,37 @@ class CoreNode(CoreNodeBase):
:param session: core session instance :param session: core session instance
:param _id: object id :param _id: object id
:param name: object name :param name: object name
:param directory: node directory
:param server: remote server node :param server: remote server node
will run on, default is None for localhost will run on, default is None for localhost
:param options: options to create node with
""" """
super().__init__(session, _id, name, server) options = options or CoreNodeOptions()
self.directory: Optional[Path] = directory super().__init__(session, _id, name, server, options)
self.directory: Optional[Path] = options.directory
self.ctrlchnlname: Path = self.session.directory / self.name self.ctrlchnlname: Path = self.session.directory / self.name
self.pid: Optional[int] = None self.pid: Optional[int] = None
self._mounts: List[Tuple[Path, Path]] = [] self._mounts: List[Tuple[Path, Path]] = []
self.node_net_client: LinuxNetClient = self.create_node_net_client( self.node_net_client: LinuxNetClient = self.create_node_net_client(
self.session.use_ovs() self.session.use_ovs()
) )
options = options or CoreNodeOptions()
self.model: Optional[str] = options.model
# setup services
if options.legacy or options.services:
logger.debug("set node type: %s", self.model)
self.session.services.add_services(self, self.model, options.services)
# add config services
config_services = options.config_services
if not options.legacy and not config_services and not options.services:
config_services = self.session.services.default_services.get(self.model, [])
logger.info("setting node config services: %s", config_services)
for name in config_services:
service_class = self.session.service_manager.get_service(name)
self.add_config_service(service_class)
@classmethod
def create_options(cls) -> CoreNodeOptions:
return CoreNodeOptions()
def create_node_net_client(self, use_ovs: bool) -> LinuxNetClient: def create_node_net_client(self, use_ovs: bool) -> LinuxNetClient:
""" """
@ -797,6 +910,7 @@ class CoreNetworkBase(NodeBase):
_id: int, _id: int,
name: str, name: str,
server: "DistributedServer" = None, server: "DistributedServer" = None,
options: NodeOptions = None,
) -> None: ) -> None:
""" """
Create a CoreNetworkBase instance. Create a CoreNetworkBase instance.
@ -806,9 +920,11 @@ class CoreNetworkBase(NodeBase):
:param name: object name :param name: object name
:param server: remote server node :param server: remote server node
will run on, default is None for localhost will run on, default is None for localhost
:param options: options to create node with
""" """
super().__init__(session, _id, name, server) super().__init__(session, _id, name, server, options)
self.mtu: int = DEFAULT_MTU mtu = self.session.options.get_int("mtu")
self.mtu: int = mtu if mtu > 0 else DEFAULT_MTU
self.brname: Optional[str] = None self.brname: Optional[str] = None
self.linked: Dict[CoreInterface, Dict[CoreInterface, bool]] = {} self.linked: Dict[CoreInterface, Dict[CoreInterface, bool]] = {}
self.linked_lock: threading.Lock = threading.Lock() self.linked_lock: threading.Lock = threading.Lock()
@ -839,69 +955,3 @@ class CoreNetworkBase(NodeBase):
iface.net_id = None iface.net_id = None
with self.linked_lock: with self.linked_lock:
del self.linked[iface] del self.linked[iface]
class Position:
"""
Helper class for Cartesian coordinate position
"""
def __init__(self, x: float = None, y: float = None, z: float = None) -> None:
"""
Creates a Position instance.
:param x: x position
:param y: y position
:param z: z position
"""
self.x: float = x
self.y: float = y
self.z: float = z
self.lon: Optional[float] = None
self.lat: Optional[float] = None
self.alt: Optional[float] = None
def set(self, x: float = None, y: float = None, z: float = None) -> bool:
"""
Returns True if the position has actually changed.
:param x: x position
:param y: y position
:param z: z position
:return: True if position changed, False otherwise
"""
if self.x == x and self.y == y and self.z == z:
return False
self.x = x
self.y = y
self.z = z
return True
def get(self) -> Tuple[float, float, float]:
"""
Retrieve x,y,z position.
:return: x,y,z position tuple
"""
return self.x, self.y, self.z
def set_geo(self, lon: float, lat: float, alt: float) -> None:
"""
Set geo position lon, lat, alt.
:param lon: longitude value
:param lat: latitude value
:param alt: altitude value
:return: nothing
"""
self.lon = lon
self.lat = lat
self.alt = alt
def get_geo(self) -> Tuple[float, float, float]:
"""
Retrieve current geo position lon, lat, alt.
:return: lon, lat, alt position tuple
"""
return self.lon, self.lat, self.alt

View file

@ -1,7 +1,7 @@
import json import json
import logging import logging
import shlex import shlex
from dataclasses import dataclass from dataclasses import dataclass, field
from pathlib import Path from pathlib import Path
from tempfile import NamedTemporaryFile from tempfile import NamedTemporaryFile
from typing import TYPE_CHECKING, Dict, List, Tuple from typing import TYPE_CHECKING, Dict, List, Tuple
@ -9,7 +9,7 @@ from typing import TYPE_CHECKING, Dict, List, Tuple
from core.emulator.distributed import DistributedServer from core.emulator.distributed import DistributedServer
from core.errors import CoreCommandError, CoreError from core.errors import CoreCommandError, CoreError
from core.executables import BASH from core.executables import BASH
from core.nodes.base import CoreNode from core.nodes.base import CoreNode, CoreNodeOptions
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -19,6 +19,21 @@ if TYPE_CHECKING:
DOCKER: str = "docker" DOCKER: str = "docker"
@dataclass
class DockerOptions(CoreNodeOptions):
image: str = "ubuntu"
"""image used when creating container"""
binds: List[Tuple[str, str]] = field(default_factory=list)
"""bind mount source and destinations to setup within container"""
volumes: List[Tuple[str, str, bool, bool]] = field(default_factory=list)
"""
volume mount source, destination, unique, delete to setup within container
unique is True for node unique volume naming
delete is True for deleting volume mount during shutdown
"""
@dataclass @dataclass
class DockerVolume: class DockerVolume:
src: str src: str
@ -38,11 +53,8 @@ class DockerNode(CoreNode):
session: "Session", session: "Session",
_id: int = None, _id: int = None,
name: str = None, name: str = None,
directory: str = None,
server: DistributedServer = None, server: DistributedServer = None,
image: str = None, options: DockerOptions = None,
binds: List[Tuple[str, str]] = None,
volumes: List[Tuple[str, str, bool, bool]] = None,
) -> None: ) -> None:
""" """
Create a DockerNode instance. Create a DockerNode instance.
@ -50,22 +62,23 @@ class DockerNode(CoreNode):
:param session: core session instance :param session: core session instance
:param _id: object id :param _id: object id
:param name: object name :param name: object name
:param directory: node directory
:param server: remote server node :param server: remote server node
will run on, default is None for localhost will run on, default is None for localhost
:param image: image to start container with :param options: options for creating node
:param binds: bind mounts to set for the created container
:param volumes: volume mount settings to set for the created container
""" """
super().__init__(session, _id, name, directory, server) options = options or DockerOptions()
self.image: str = image if image is not None else "ubuntu" super().__init__(session, _id, name, server, options)
self.binds: List[Tuple[str, str]] = binds or [] self.image: str = options.image
self.binds: List[Tuple[str, str]] = options.binds
self.volumes: Dict[str, DockerVolume] = {} self.volumes: Dict[str, DockerVolume] = {}
volumes = volumes or [] for src, dst, unique, delete in options.volumes:
for src, dst, unique, delete in volumes:
src_name = self._unique_name(src) if unique else src src_name = self._unique_name(src) if unique else src
self.volumes[src] = DockerVolume(src_name, dst, unique, delete) self.volumes[src] = DockerVolume(src_name, dst, unique, delete)
@classmethod
def create_options(cls) -> DockerOptions:
return DockerOptions()
def _create_cmd(self, args: str, shell: bool = False) -> str: def _create_cmd(self, args: str, shell: bool = False) -> str:
""" """
Create command used to run commands within the context of a node. Create command used to run commands within the context of a node.

View file

@ -1,15 +1,16 @@
import json import json
import logging import logging
import time import time
from dataclasses import dataclass, field
from pathlib import Path from pathlib import Path
from tempfile import NamedTemporaryFile from tempfile import NamedTemporaryFile
from typing import TYPE_CHECKING, Callable, Dict, Optional from typing import TYPE_CHECKING, Callable, Dict, List, Optional, Tuple
from core import utils from core import utils
from core.emulator.data import InterfaceData, LinkOptions from core.emulator.data import InterfaceData, LinkOptions
from core.emulator.distributed import DistributedServer from core.emulator.distributed import DistributedServer
from core.errors import CoreCommandError from core.errors import CoreCommandError
from core.nodes.base import CoreNode from core.nodes.base import CoreNode, CoreNodeOptions
from core.nodes.interface import CoreInterface from core.nodes.interface import CoreInterface
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -66,15 +67,29 @@ class LxdClient:
self.run(args) self.run(args)
@dataclass
class LxcOptions(CoreNodeOptions):
image: str = "ubuntu"
"""image used when creating container"""
binds: List[Tuple[str, str]] = field(default_factory=list)
"""bind mount source and destinations to setup within container"""
volumes: List[Tuple[str, str, bool, bool]] = field(default_factory=list)
"""
volume mount source, destination, unique, delete to setup within container
unique is True for node unique volume naming
delete is True for deleting volume mount during shutdown
"""
class LxcNode(CoreNode): class LxcNode(CoreNode):
def __init__( def __init__(
self, self,
session: "Session", session: "Session",
_id: int = None, _id: int = None,
name: str = None, name: str = None,
directory: str = None,
server: DistributedServer = None, server: DistributedServer = None,
image: str = None, options: LxcOptions = None,
) -> None: ) -> None:
""" """
Create a LxcNode instance. Create a LxcNode instance.
@ -82,15 +97,19 @@ class LxcNode(CoreNode):
:param session: core session instance :param session: core session instance
:param _id: object id :param _id: object id
:param name: object name :param name: object name
:param directory: node directory
:param server: remote server node :param server: remote server node
will run on, default is None for localhost will run on, default is None for localhost
:param image: image to start container with :param options: option to create node with
""" """
super().__init__(session, _id, name, directory, server) options = options or LxcOptions()
self.image: str = image if image is not None else "ubuntu" super().__init__(session, _id, name, server, options)
self.image: str = options.image
self.client: Optional[LxdClient] = None self.client: Optional[LxdClient] = None
@classmethod
def create_options(cls) -> LxcOptions:
return LxcOptions()
def alive(self) -> bool: def alive(self) -> bool:
""" """
Check if the node is alive. Check if the node is alive.

View file

@ -4,6 +4,7 @@ Defines network nodes used within core.
import logging import logging
import threading import threading
from dataclasses import dataclass
from pathlib import Path from pathlib import Path
from typing import TYPE_CHECKING, Dict, List, Optional, Type from typing import TYPE_CHECKING, Dict, List, Optional, Type
@ -14,7 +15,7 @@ from core.emulator.data import InterfaceData, LinkData
from core.emulator.enumerations import MessageFlags, NetworkPolicy, RegisterTlvs from core.emulator.enumerations import MessageFlags, NetworkPolicy, RegisterTlvs
from core.errors import CoreCommandError, CoreError from core.errors import CoreCommandError, CoreError
from core.executables import NFTABLES from core.executables import NFTABLES
from core.nodes.base import CoreNetworkBase from core.nodes.base import CoreNetworkBase, NodeOptions
from core.nodes.interface import CoreInterface, GreTap from core.nodes.interface import CoreInterface, GreTap
from core.nodes.netclient import get_net_client from core.nodes.netclient import get_net_client
@ -180,6 +181,12 @@ class NftablesQueue:
nft_queue: NftablesQueue = NftablesQueue() nft_queue: NftablesQueue = NftablesQueue()
@dataclass
class NetworkOptions(NodeOptions):
policy: NetworkPolicy = None
"""allows overriding the network policy, otherwise uses class defined default"""
class CoreNetwork(CoreNetworkBase): class CoreNetwork(CoreNetworkBase):
""" """
Provides linux bridge network functionality for core nodes. Provides linux bridge network functionality for core nodes.
@ -193,7 +200,7 @@ class CoreNetwork(CoreNetworkBase):
_id: int = None, _id: int = None,
name: str = None, name: str = None,
server: "DistributedServer" = None, server: "DistributedServer" = None,
policy: NetworkPolicy = None, options: NetworkOptions = None,
) -> None: ) -> None:
""" """
Creates a CoreNetwork instance. Creates a CoreNetwork instance.
@ -203,18 +210,19 @@ class CoreNetwork(CoreNetworkBase):
:param name: object name :param name: object name
:param server: remote server node :param server: remote server node
will run on, default is None for localhost will run on, default is None for localhost
:param policy: network policy :param options: options to create node with
""" """
super().__init__(session, _id, name, server) options = options or NetworkOptions()
if name is None: super().__init__(session, _id, name, server, options)
name = str(self.id) self.policy: NetworkPolicy = options.policy if options.policy else self.policy
if policy is not None:
self.policy: NetworkPolicy = policy
self.name: Optional[str] = name
sessionid = self.session.short_session_id() sessionid = self.session.short_session_id()
self.brname: str = f"b.{self.id}.{sessionid}" self.brname: str = f"b.{self.id}.{sessionid}"
self.has_nftables_chain: bool = False self.has_nftables_chain: bool = False
@classmethod
def create_options(cls) -> NetworkOptions:
return NetworkOptions()
def host_cmd( def host_cmd(
self, self,
args: str, args: str,
@ -482,6 +490,20 @@ class GreTapBridge(CoreNetwork):
self.add_ips(ips) self.add_ips(ips)
@dataclass
class CtrlNetOptions(NetworkOptions):
prefix: str = None
"""ip4 network prefix to use for generating an address"""
updown_script: str = None
"""script to execute during startup and shutdown"""
serverintf: str = None
"""used to associate an interface with the control network bridge"""
assign_address: bool = True
"""used to determine if a specific address should be assign using hostid"""
hostid: int = None
"""used with assign address to """
class CtrlNet(CoreNetwork): class CtrlNet(CoreNetwork):
""" """
Control network functionality. Control network functionality.
@ -500,36 +522,32 @@ class CtrlNet(CoreNetwork):
def __init__( def __init__(
self, self,
session: "Session", session: "Session",
prefix: str,
_id: int = None, _id: int = None,
name: str = None, name: str = None,
hostid: int = None,
server: "DistributedServer" = None, server: "DistributedServer" = None,
assign_address: bool = True, options: CtrlNetOptions = None,
updown_script: str = None,
serverintf: str = None,
) -> None: ) -> None:
""" """
Creates a CtrlNet instance. Creates a CtrlNet instance.
:param session: core session instance :param session: core session instance
:param _id: node id :param _id: node id
:param name: node namee :param name: node name
:param prefix: control network ipv4 prefix
:param hostid: host id
:param server: remote server node :param server: remote server node
will run on, default is None for localhost will run on, default is None for localhost
:param assign_address: assigned address :param options: node options for creation
:param updown_script: updown script
:param serverintf: server interface
:return:
""" """
self.prefix: netaddr.IPNetwork = netaddr.IPNetwork(prefix).cidr options = options or CtrlNetOptions()
self.hostid: Optional[int] = hostid super().__init__(session, _id, name, server, options)
self.assign_address: bool = assign_address self.prefix: netaddr.IPNetwork = netaddr.IPNetwork(options.prefix).cidr
self.updown_script: Optional[str] = updown_script self.hostid: Optional[int] = options.hostid
self.serverintf: Optional[str] = serverintf self.assign_address: bool = options.assign_address
super().__init__(session, _id, name, server) self.updown_script: Optional[str] = options.updown_script
self.serverintf: Optional[str] = options.serverintf
@classmethod
def create_options(cls) -> CtrlNetOptions:
return CtrlNetOptions()
def add_addresses(self, index: int) -> None: def add_addresses(self, index: int) -> None:
""" """
@ -669,7 +687,7 @@ class WlanNode(CoreNetwork):
_id: int = None, _id: int = None,
name: str = None, name: str = None,
server: "DistributedServer" = None, server: "DistributedServer" = None,
policy: NetworkPolicy = None, options: NetworkOptions = None,
) -> None: ) -> None:
""" """
Create a WlanNode instance. Create a WlanNode instance.
@ -679,9 +697,9 @@ class WlanNode(CoreNetwork):
:param name: node name :param name: node name
:param server: remote server node :param server: remote server node
will run on, default is None for localhost will run on, default is None for localhost
:param policy: wlan policy :param options: options to create node with
""" """
super().__init__(session, _id, name, server, policy) super().__init__(session, _id, name, server, options)
# wireless and mobility models (BasicRangeModel, Ns2WaypointMobility) # wireless and mobility models (BasicRangeModel, Ns2WaypointMobility)
self.wireless_model: Optional[WirelessModel] = None self.wireless_model: Optional[WirelessModel] = None
self.mobility: Optional[WayPointMobility] = None self.mobility: Optional[WayPointMobility] = None

View file

@ -13,7 +13,7 @@ from core.emulator.distributed import DistributedServer
from core.emulator.enumerations import TransportType from core.emulator.enumerations import TransportType
from core.errors import CoreCommandError, CoreError from core.errors import CoreCommandError, CoreError
from core.executables import BASH, TEST, UMOUNT from core.executables import BASH, TEST, UMOUNT
from core.nodes.base import CoreNode, CoreNodeBase from core.nodes.base import CoreNode, CoreNodeBase, CoreNodeOptions, NodeOptions
from core.nodes.interface import CoreInterface from core.nodes.interface import CoreInterface
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -34,6 +34,7 @@ class Rj45Node(CoreNodeBase):
_id: int = None, _id: int = None,
name: str = None, name: str = None,
server: DistributedServer = None, server: DistributedServer = None,
options: NodeOptions = None,
) -> None: ) -> None:
""" """
Create an RJ45Node instance. Create an RJ45Node instance.
@ -43,8 +44,9 @@ class Rj45Node(CoreNodeBase):
:param name: node name :param name: node name
:param server: remote server node :param server: remote server node
will run on, default is None for localhost will run on, default is None for localhost
:param options: option to create node with
""" """
super().__init__(session, _id, name, server) super().__init__(session, _id, name, server, options)
self.iface: CoreInterface = CoreInterface( self.iface: CoreInterface = CoreInterface(
self.iface_id, name, name, session.use_ovs(), node=self, server=server self.iface_id, name, name, session.use_ovs(), node=self, server=server
) )
@ -224,12 +226,12 @@ class PhysicalNode(CoreNode):
session: "Session", session: "Session",
_id: int = None, _id: int = None,
name: str = None, name: str = None,
directory: Path = None,
server: DistributedServer = None, server: DistributedServer = None,
options: CoreNodeOptions = None,
) -> None: ) -> None:
if not self.server: if not self.server:
raise CoreError("physical nodes must be assigned to a remote server") raise CoreError("physical nodes must be assigned to a remote server")
super().__init__(session, _id, name, directory, server) super().__init__(session, _id, name, server, options)
def startup(self) -> None: def startup(self) -> None:
with self.lock: with self.lock:

View file

@ -14,7 +14,7 @@ from core.emulator.data import LinkData, LinkOptions
from core.emulator.enumerations import LinkTypes, MessageFlags from core.emulator.enumerations import LinkTypes, MessageFlags
from core.errors import CoreError from core.errors import CoreError
from core.executables import NFTABLES from core.executables import NFTABLES
from core.nodes.base import CoreNetworkBase from core.nodes.base import CoreNetworkBase, NodeOptions
from core.nodes.interface import CoreInterface from core.nodes.interface import CoreInterface
if TYPE_CHECKING: if TYPE_CHECKING:
@ -108,8 +108,9 @@ class WirelessNode(CoreNetworkBase):
_id: int, _id: int,
name: str, name: str,
server: "DistributedServer" = None, server: "DistributedServer" = None,
options: NodeOptions = None,
): ):
super().__init__(session, _id, name, server) super().__init__(session, _id, name, server, options)
self.bridges: Dict[int, Tuple[CoreInterface, str]] = {} self.bridges: Dict[int, Tuple[CoreInterface, str]] = {}
self.links: Dict[Tuple[int, int], WirelessLink] = {} self.links: Dict[Tuple[int, int], WirelessLink] = {}
self.position_enabled: bool = CONFIG_ENABLED self.position_enabled: bool = CONFIG_ENABLED

View file

@ -8,12 +8,12 @@ import core.nodes.base
import core.nodes.physical import core.nodes.physical
from core import utils from core import utils
from core.config import Configuration from core.config import Configuration
from core.emane.nodes import EmaneNet from core.emane.nodes import EmaneNet, EmaneOptions
from core.emulator.data import InterfaceData, LinkOptions, NodeOptions from core.emulator.data import InterfaceData, LinkOptions
from core.emulator.enumerations import EventTypes, NodeTypes from core.emulator.enumerations import EventTypes, NodeTypes
from core.errors import CoreXmlError from core.errors import CoreXmlError
from core.nodes.base import CoreNodeBase, NodeBase from core.nodes.base import CoreNodeBase, CoreNodeOptions, NodeBase, Position
from core.nodes.docker import DockerNode from core.nodes.docker import DockerNode, DockerOptions
from core.nodes.interface import CoreInterface from core.nodes.interface import CoreInterface
from core.nodes.lxd import LxcNode from core.nodes.lxd import LxcNode
from core.nodes.network import CtrlNet, GreTapBridge, PtpNet, WlanNode from core.nodes.network import CtrlNet, GreTapBridge, PtpNet, WlanNode
@ -802,68 +802,76 @@ class CoreXmlReader:
clazz = device_element.get("class") clazz = device_element.get("class")
image = device_element.get("image") image = device_element.get("image")
server = device_element.get("server") server = device_element.get("server")
options = NodeOptions( canvas = get_int(device_element, "canvas")
name=name, model=model, image=image, icon=icon, server=server
)
node_type = NodeTypes.DEFAULT node_type = NodeTypes.DEFAULT
if clazz == "docker": if clazz == "docker":
node_type = NodeTypes.DOCKER node_type = NodeTypes.DOCKER
elif clazz == "lxc": elif clazz == "lxc":
node_type = NodeTypes.LXC node_type = NodeTypes.LXC
_class = self.session.get_node_class(node_type) _class = self.session.get_node_class(node_type)
options = _class.create_options()
service_elements = device_element.find("services") options.icon = icon
if service_elements is not None: options.canvas = canvas
options.services = [x.get("name") for x in service_elements.iterchildren()] # check for special options
if isinstance(options, CoreNodeOptions):
config_service_elements = device_element.find("configservices") options.model = model
if config_service_elements is not None: service_elements = device_element.find("services")
options.config_services = [ if service_elements is not None:
x.get("name") for x in config_service_elements.iterchildren() options.services.extend(
] x.get("name") for x in service_elements.iterchildren()
)
config_service_elements = device_element.find("configservices")
if config_service_elements is not None:
options.config_services.extend(
x.get("name") for x in config_service_elements.iterchildren()
)
if isinstance(options, DockerOptions):
options.image = image
# get position information
position_element = device_element.find("position") position_element = device_element.find("position")
position = None
if position_element is not None: if position_element is not None:
position = Position()
x = get_float(position_element, "x") x = get_float(position_element, "x")
y = get_float(position_element, "y") y = get_float(position_element, "y")
if all([x, y]): if all([x, y]):
options.set_position(x, y) position.set(x, y)
lat = get_float(position_element, "lat") lat = get_float(position_element, "lat")
lon = get_float(position_element, "lon") lon = get_float(position_element, "lon")
alt = get_float(position_element, "alt") alt = get_float(position_element, "alt")
if all([lat, lon, alt]): if all([lat, lon, alt]):
options.set_location(lat, lon, alt) position.set_geo(lon, lat, alt)
logger.info("reading node id(%s) model(%s) name(%s)", node_id, model, name) logger.info("reading node id(%s) model(%s) name(%s)", node_id, model, name)
self.session.add_node(_class, node_id, options) self.session.add_node(_class, node_id, name, server, position, options)
def read_network(self, network_element: etree.Element) -> None: def read_network(self, network_element: etree.Element) -> None:
node_id = get_int(network_element, "id") node_id = get_int(network_element, "id")
name = network_element.get("name") name = network_element.get("name")
server = network_element.get("server")
node_type = NodeTypes[network_element.get("type")] node_type = NodeTypes[network_element.get("type")]
_class = self.session.get_node_class(node_type) _class = self.session.get_node_class(node_type)
icon = network_element.get("icon") options = _class.create_options()
server = network_element.get("server") options.canvas = get_int(network_element, "canvas")
options = NodeOptions(name=name, icon=icon, server=server) options.icon = network_element.get("icon")
if node_type == NodeTypes.EMANE: if isinstance(options, EmaneOptions):
model = network_element.get("model") options.emane_model = network_element.get("model")
options.emane = model
position_element = network_element.find("position") position_element = network_element.find("position")
position = None
if position_element is not None: if position_element is not None:
position = Position()
x = get_float(position_element, "x") x = get_float(position_element, "x")
y = get_float(position_element, "y") y = get_float(position_element, "y")
if all([x, y]): if all([x, y]):
options.set_position(x, y) position.set(x, y)
lat = get_float(position_element, "lat") lat = get_float(position_element, "lat")
lon = get_float(position_element, "lon") lon = get_float(position_element, "lon")
alt = get_float(position_element, "alt") alt = get_float(position_element, "alt")
if all([lat, lon, alt]): if all([lat, lon, alt]):
options.set_location(lat, lon, alt) position.set_geo(lon, lat, alt)
logger.info( logger.info(
"reading node id(%s) node_type(%s) name(%s)", node_id, node_type, name "reading node id(%s) node_type(%s) name(%s)", node_id, node_type, name
) )
node = self.session.add_node(_class, node_id, options) node = self.session.add_node(_class, node_id, name, server, position, options)
if isinstance(node, WirelessNode): if isinstance(node, WirelessNode):
wireless_element = network_element.find("wireless") wireless_element = network_element.find("wireless")
if wireless_element: if wireless_element:

View file

@ -1,7 +1,7 @@
import logging import logging
from core.emulator.coreemu import CoreEmu from core.emulator.coreemu import CoreEmu
from core.emulator.data import IpPrefixes, NodeOptions from core.emulator.data import IpPrefixes
from core.emulator.enumerations import EventTypes from core.emulator.enumerations import EventTypes
from core.nodes.base import CoreNode from core.nodes.base import CoreNode
from core.nodes.network import SwitchNode from core.nodes.network import SwitchNode
@ -11,13 +11,13 @@ if __name__ == "__main__":
# setup basic network # setup basic network
prefixes = IpPrefixes(ip4_prefix="10.83.0.0/16") prefixes = IpPrefixes(ip4_prefix="10.83.0.0/16")
options = NodeOptions(model=None)
coreemu = CoreEmu() coreemu = CoreEmu()
session = coreemu.create_session() session = coreemu.create_session()
session.set_state(EventTypes.CONFIGURATION_STATE) session.set_state(EventTypes.CONFIGURATION_STATE)
switch = session.add_node(SwitchNode) switch = session.add_node(SwitchNode)
# node one # node one
options = CoreNode.create_options()
options.config_services = ["DefaultRoute", "IPForward"] options.config_services = ["DefaultRoute", "IPForward"]
node1 = session.add_node(CoreNode, options=options) node1 = session.add_node(CoreNode, options=options)
interface = prefixes.create_iface(node1) interface = prefixes.create_iface(node1)

View file

@ -1,7 +1,7 @@
import logging import logging
from core.emulator.coreemu import CoreEmu from core.emulator.coreemu import CoreEmu
from core.emulator.data import IpPrefixes, NodeOptions from core.emulator.data import IpPrefixes
from core.emulator.enumerations import EventTypes from core.emulator.enumerations import EventTypes
from core.nodes.base import CoreNode from core.nodes.base import CoreNode
from core.nodes.docker import DockerNode from core.nodes.docker import DockerNode
@ -14,9 +14,10 @@ if __name__ == "__main__":
try: try:
prefixes = IpPrefixes(ip4_prefix="10.83.0.0/16") prefixes = IpPrefixes(ip4_prefix="10.83.0.0/16")
options = NodeOptions(model=None, image="ubuntu")
# create node one # create node one
options = DockerNode.create_options()
options.image = "ubuntu"
node1 = session.add_node(DockerNode, options=options) node1 = session.add_node(DockerNode, options=options)
interface1_data = prefixes.create_iface(node1) interface1_data = prefixes.create_iface(node1)

View file

@ -1,7 +1,7 @@
import logging import logging
from core.emulator.coreemu import CoreEmu from core.emulator.coreemu import CoreEmu
from core.emulator.data import IpPrefixes, NodeOptions from core.emulator.data import IpPrefixes
from core.emulator.enumerations import EventTypes from core.emulator.enumerations import EventTypes
from core.nodes.docker import DockerNode from core.nodes.docker import DockerNode
@ -15,9 +15,10 @@ if __name__ == "__main__":
# create nodes and interfaces # create nodes and interfaces
try: try:
prefixes = IpPrefixes(ip4_prefix="10.83.0.0/16") prefixes = IpPrefixes(ip4_prefix="10.83.0.0/16")
options = NodeOptions(model=None, image="ubuntu")
# create node one # create node one
options = DockerNode.create_options()
options.image = "ubuntu"
node1 = session.add_node(DockerNode, options=options) node1 = session.add_node(DockerNode, options=options)
interface1_data = prefixes.create_iface(node1) interface1_data = prefixes.create_iface(node1)

View file

@ -1,9 +1,8 @@
import logging import logging
from core.emulator.coreemu import CoreEmu from core.emulator.coreemu import CoreEmu
from core.emulator.data import IpPrefixes, NodeOptions from core.emulator.data import IpPrefixes
from core.emulator.enumerations import EventTypes from core.emulator.enumerations import EventTypes
from core.nodes.base import CoreNode
from core.nodes.docker import DockerNode from core.nodes.docker import DockerNode
from core.nodes.network import SwitchNode from core.nodes.network import SwitchNode
@ -16,12 +15,15 @@ if __name__ == "__main__":
try: try:
prefixes = IpPrefixes(ip4_prefix="10.83.0.0/16") prefixes = IpPrefixes(ip4_prefix="10.83.0.0/16")
options = NodeOptions(model=None, image="ubuntu")
# create switch # create switch
switch = session.add_node(SwitchNode) switch = session.add_node(SwitchNode)
# node one # node one
options = DockerNode.create_options()
options.image = "core"
options.binds.append(("/tmp/testbind", "/tmp/bind"))
options.volumes.append(("var.log", "/tmp/var.log", True, True))
node1 = session.add_node(DockerNode, options=options) node1 = session.add_node(DockerNode, options=options)
interface1_data = prefixes.create_iface(node1) interface1_data = prefixes.create_iface(node1)
@ -30,16 +32,18 @@ if __name__ == "__main__":
interface2_data = prefixes.create_iface(node2) interface2_data = prefixes.create_iface(node2)
# node three # node three
node_three = session.add_node(CoreNode) # node_three = session.add_node(CoreNode)
interface_three = prefixes.create_iface(node_three) # interface_three = prefixes.create_iface(node_three)
# add links # add links
session.add_link(node1.id, switch.id, interface1_data) session.add_link(node1.id, switch.id, interface1_data)
session.add_link(node2.id, switch.id, interface2_data) session.add_link(node2.id, switch.id, interface2_data)
session.add_link(node_three.id, switch.id, interface_three) # session.add_link(node_three.id, switch.id, interface_three)
# instantiate # instantiate
session.instantiate() session.instantiate()
print(f"{node2.name}: {node2.volumes.values()}")
finally: finally:
input("continue to shutdown") input("continue to shutdown")
coreemu.shutdown() coreemu.shutdown()

View file

@ -1,7 +1,7 @@
import logging import logging
from core.emulator.coreemu import CoreEmu from core.emulator.coreemu import CoreEmu
from core.emulator.data import IpPrefixes, NodeOptions from core.emulator.data import IpPrefixes
from core.emulator.enumerations import EventTypes from core.emulator.enumerations import EventTypes
from core.nodes.base import CoreNode from core.nodes.base import CoreNode
from core.nodes.lxd import LxcNode from core.nodes.lxd import LxcNode
@ -14,9 +14,10 @@ if __name__ == "__main__":
try: try:
prefixes = IpPrefixes(ip4_prefix="10.83.0.0/16") prefixes = IpPrefixes(ip4_prefix="10.83.0.0/16")
options = NodeOptions(image="ubuntu")
# create node one # create node one
options = LxcNode.create_options()
options.image = "ubuntu"
node1 = session.add_node(LxcNode, options=options) node1 = session.add_node(LxcNode, options=options)
interface1_data = prefixes.create_iface(node1) interface1_data = prefixes.create_iface(node1)

View file

@ -1,7 +1,7 @@
import logging import logging
from core.emulator.coreemu import CoreEmu from core.emulator.coreemu import CoreEmu
from core.emulator.data import IpPrefixes, NodeOptions from core.emulator.data import IpPrefixes
from core.emulator.enumerations import EventTypes from core.emulator.enumerations import EventTypes
from core.nodes.lxd import LxcNode from core.nodes.lxd import LxcNode
@ -15,9 +15,10 @@ if __name__ == "__main__":
# create nodes and interfaces # create nodes and interfaces
try: try:
prefixes = IpPrefixes(ip4_prefix="10.83.0.0/16") prefixes = IpPrefixes(ip4_prefix="10.83.0.0/16")
options = NodeOptions(image="ubuntu:18.04")
# create node one # create node one
options = LxcNode.create_options()
options.image = "ubuntu:18.04"
node1 = session.add_node(LxcNode, options=options) node1 = session.add_node(LxcNode, options=options)
interface1_data = prefixes.create_iface(node1) interface1_data = prefixes.create_iface(node1)

View file

@ -1,7 +1,7 @@
import logging import logging
from core.emulator.coreemu import CoreEmu from core.emulator.coreemu import CoreEmu
from core.emulator.data import IpPrefixes, NodeOptions from core.emulator.data import IpPrefixes
from core.emulator.enumerations import EventTypes from core.emulator.enumerations import EventTypes
from core.nodes.base import CoreNode from core.nodes.base import CoreNode
from core.nodes.lxd import LxcNode from core.nodes.lxd import LxcNode
@ -16,12 +16,13 @@ if __name__ == "__main__":
try: try:
prefixes = IpPrefixes(ip4_prefix="10.83.0.0/16") prefixes = IpPrefixes(ip4_prefix="10.83.0.0/16")
options = NodeOptions(image="ubuntu")
# create switch # create switch
switch = session.add_node(SwitchNode) switch = session.add_node(SwitchNode)
# node one # node one
options = LxcNode.create_options()
options.image = "ubuntu"
node1 = session.add_node(LxcNode, options=options) node1 = session.add_node(LxcNode, options=options)
interface1_data = prefixes.create_iface(node1) interface1_data = prefixes.create_iface(node1)

View file

@ -9,7 +9,7 @@ import logging
from core.emane.models.ieee80211abg import EmaneIeee80211abgModel from core.emane.models.ieee80211abg import EmaneIeee80211abgModel
from core.emane.nodes import EmaneNet from core.emane.nodes import EmaneNet
from core.emulator.coreemu import CoreEmu from core.emulator.coreemu import CoreEmu
from core.emulator.data import IpPrefixes, NodeOptions from core.emulator.data import IpPrefixes
from core.emulator.enumerations import EventTypes from core.emulator.enumerations import EventTypes
from core.nodes.base import CoreNode from core.nodes.base import CoreNode
@ -50,11 +50,13 @@ def main(args):
session.set_state(EventTypes.CONFIGURATION_STATE) session.set_state(EventTypes.CONFIGURATION_STATE)
# create local node, switch, and remote nodes # create local node, switch, and remote nodes
options = NodeOptions(model="mdr") options = CoreNode.create_options()
options.set_position(0, 0) options.model = "mdr"
node1 = session.add_node(CoreNode, options=options) node1 = session.add_node(CoreNode, options=options)
emane_net = session.add_node(EmaneNet) options = EmaneNet.create_options()
session.emane.set_model(emane_net, EmaneIeee80211abgModel) options.emane_model = EmaneIeee80211abgModel.name
emane_net = session.add_node(EmaneNet, options=options)
options = CoreNode.create_options()
options.server = server_name options.server = server_name
node2 = session.add_node(CoreNode, options=options) node2 = session.add_node(CoreNode, options=options)

View file

@ -7,7 +7,7 @@ import argparse
import logging import logging
from core.emulator.coreemu import CoreEmu from core.emulator.coreemu import CoreEmu
from core.emulator.data import IpPrefixes, NodeOptions from core.emulator.data import IpPrefixes
from core.emulator.enumerations import EventTypes from core.emulator.enumerations import EventTypes
from core.nodes.lxd import LxcNode from core.nodes.lxd import LxcNode
@ -42,7 +42,8 @@ def main(args):
session.set_state(EventTypes.CONFIGURATION_STATE) session.set_state(EventTypes.CONFIGURATION_STATE)
# create local node, switch, and remote nodes # create local node, switch, and remote nodes
options = NodeOptions(image="ubuntu:18.04") options = LxcNode.create_options()
options.image = "ubuntu:18.04"
node1 = session.add_node(LxcNode, options=options) node1 = session.add_node(LxcNode, options=options)
options.server = server_name options.server = server_name
node2 = session.add_node(LxcNode, options=options) node2 = session.add_node(LxcNode, options=options)

View file

@ -7,7 +7,7 @@ import argparse
import logging import logging
from core.emulator.coreemu import CoreEmu from core.emulator.coreemu import CoreEmu
from core.emulator.data import IpPrefixes, NodeOptions from core.emulator.data import IpPrefixes
from core.emulator.enumerations import EventTypes from core.emulator.enumerations import EventTypes
from core.nodes.base import CoreNode from core.nodes.base import CoreNode
@ -42,10 +42,8 @@ def main(args):
session.set_state(EventTypes.CONFIGURATION_STATE) session.set_state(EventTypes.CONFIGURATION_STATE)
# create local node, switch, and remote nodes # create local node, switch, and remote nodes
options = NodeOptions() node1 = session.add_node(CoreNode)
node1 = session.add_node(CoreNode, options=options) node2 = session.add_node(CoreNode, server=server_name)
options.server = server_name
node2 = session.add_node(CoreNode, options=options)
# create node interfaces and link # create node interfaces and link
interface1_data = prefixes.create_iface(node1) interface1_data = prefixes.create_iface(node1)

View file

@ -7,7 +7,7 @@ import argparse
import logging import logging
from core.emulator.coreemu import CoreEmu from core.emulator.coreemu import CoreEmu
from core.emulator.data import IpPrefixes, NodeOptions from core.emulator.data import IpPrefixes
from core.emulator.enumerations import EventTypes from core.emulator.enumerations import EventTypes
from core.nodes.base import CoreNode from core.nodes.base import CoreNode
from core.nodes.network import SwitchNode from core.nodes.network import SwitchNode
@ -47,7 +47,7 @@ def main(args):
# create local node, switch, and remote nodes # create local node, switch, and remote nodes
node1 = session.add_node(CoreNode) node1 = session.add_node(CoreNode)
switch = session.add_node(SwitchNode) switch = session.add_node(SwitchNode)
options = NodeOptions() options = CoreNode.create_options()
options.server = server_name options.server = server_name
node2 = session.add_node(CoreNode, options=options) node2 = session.add_node(CoreNode, options=options)

View file

@ -2,9 +2,9 @@
from core.emane.models.ieee80211abg import EmaneIeee80211abgModel from core.emane.models.ieee80211abg import EmaneIeee80211abgModel
from core.emane.nodes import EmaneNet from core.emane.nodes import EmaneNet
from core.emulator.coreemu import CoreEmu from core.emulator.coreemu import CoreEmu
from core.emulator.data import IpPrefixes, NodeOptions from core.emulator.data import IpPrefixes
from core.emulator.enumerations import EventTypes from core.emulator.enumerations import EventTypes
from core.nodes.base import CoreNode from core.nodes.base import CoreNode, Position
# ip nerator for example # ip nerator for example
ip_prefixes = IpPrefixes(ip4_prefix="10.0.0.0/24") ip_prefixes = IpPrefixes(ip4_prefix="10.0.0.0/24")
@ -21,14 +21,20 @@ session.location.refscale = 150.0
session.set_state(EventTypes.CONFIGURATION_STATE) session.set_state(EventTypes.CONFIGURATION_STATE)
# create emane # create emane
options = NodeOptions(x=200, y=200, emane=EmaneIeee80211abgModel.name) options = EmaneNet.create_options()
emane = session.add_node(EmaneNet, options=options) options.emane_model = EmaneIeee80211abgModel.name
position = Position(x=200, y=200)
emane = session.add_node(EmaneNet, position=position, options=options)
# create nodes # create nodes
options = NodeOptions(model="mdr", x=100, y=100) options = CoreNode.create_options()
n1 = session.add_node(CoreNode, options=options) options.model = "mdr"
options = NodeOptions(model="mdr", x=300, y=100) position = Position(x=100, y=100)
n2 = session.add_node(CoreNode, options=options) n1 = session.add_node(CoreNode, position=position, options=options)
options = CoreNode.create_options()
options.model = "mdr"
position = Position(x=300, y=100)
n2 = session.add_node(CoreNode, position=position, options=options)
# configure general emane settings # configure general emane settings
config = session.emane.get_configs() config = session.emane.get_configs()

View file

@ -1,8 +1,8 @@
# required imports # required imports
from core.emulator.coreemu import CoreEmu from core.emulator.coreemu import CoreEmu
from core.emulator.data import IpPrefixes, NodeOptions from core.emulator.data import IpPrefixes
from core.emulator.enumerations import EventTypes from core.emulator.enumerations import EventTypes
from core.nodes.base import CoreNode from core.nodes.base import CoreNode, Position
# ip nerator for example # ip nerator for example
ip_prefixes = IpPrefixes(ip4_prefix="10.0.0.0/24") ip_prefixes = IpPrefixes(ip4_prefix="10.0.0.0/24")
@ -15,10 +15,10 @@ session = coreemu.create_session()
session.set_state(EventTypes.CONFIGURATION_STATE) session.set_state(EventTypes.CONFIGURATION_STATE)
# create nodes # create nodes
options = NodeOptions(x=100, y=100) position = Position(x=100, y=100)
n1 = session.add_node(CoreNode, options=options) n1 = session.add_node(CoreNode, position=position)
options = NodeOptions(x=300, y=100) position = Position(x=300, y=100)
n2 = session.add_node(CoreNode, options=options) n2 = session.add_node(CoreNode, position=position)
# link nodes together # link nodes together
iface1 = ip_prefixes.create_iface(n1) iface1 = ip_prefixes.create_iface(n1)

View file

@ -1,8 +1,8 @@
# required imports # required imports
from core.emulator.coreemu import CoreEmu from core.emulator.coreemu import CoreEmu
from core.emulator.data import IpPrefixes, NodeOptions from core.emulator.data import IpPrefixes
from core.emulator.enumerations import EventTypes from core.emulator.enumerations import EventTypes
from core.nodes.base import CoreNode from core.nodes.base import CoreNode, Position
from core.nodes.network import SwitchNode from core.nodes.network import SwitchNode
# ip nerator for example # ip nerator for example
@ -16,14 +16,14 @@ session = coreemu.create_session()
session.set_state(EventTypes.CONFIGURATION_STATE) session.set_state(EventTypes.CONFIGURATION_STATE)
# create switch # create switch
options = NodeOptions(x=200, y=200) position = Position(x=200, y=200)
switch = session.add_node(SwitchNode, options=options) switch = session.add_node(SwitchNode, position=position)
# create nodes # create nodes
options = NodeOptions(x=100, y=100) position = Position(x=100, y=100)
n1 = session.add_node(CoreNode, options=options) n1 = session.add_node(CoreNode, position=position)
options = NodeOptions(x=300, y=100) position = Position(x=300, y=100)
n2 = session.add_node(CoreNode, options=options) n2 = session.add_node(CoreNode, position=position)
# link nodes to switch # link nodes to switch
iface1 = ip_prefixes.create_iface(n1) iface1 = ip_prefixes.create_iface(n1)

View file

@ -2,9 +2,9 @@
import logging import logging
from core.emulator.coreemu import CoreEmu from core.emulator.coreemu import CoreEmu
from core.emulator.data import IpPrefixes, NodeOptions from core.emulator.data import IpPrefixes
from core.emulator.enumerations import EventTypes from core.emulator.enumerations import EventTypes
from core.nodes.base import CoreNode from core.nodes.base import CoreNode, Position
from core.nodes.network import WlanNode from core.nodes.network import WlanNode
# enable info logging # enable info logging
@ -21,14 +21,18 @@ session = coreemu.create_session()
session.set_state(EventTypes.CONFIGURATION_STATE) session.set_state(EventTypes.CONFIGURATION_STATE)
# create wireless # create wireless
options = NodeOptions(x=200, y=200) position = Position(x=200, y=200)
wireless = session.add_node(WlanNode, options=options) wireless = session.add_node(WlanNode, position=position)
# create nodes # create nodes
options = NodeOptions(model="mdr", x=100, y=100) options = CoreNode.create_options()
n1 = session.add_node(CoreNode, options=options) options.model = "mdr"
options = NodeOptions(model="mdr", x=300, y=100) position = Position(x=100, y=100)
n2 = session.add_node(CoreNode, options=options) n1 = session.add_node(CoreNode, position=position, options=options)
options = CoreNode.create_options()
options.model = "mdr"
position = Position(x=300, y=100)
n2 = session.add_node(CoreNode, position=position, options=options)
# link nodes to wireless # link nodes to wireless
iface1 = ip_prefixes.create_iface(n1) iface1 = ip_prefixes.create_iface(n1)

View file

@ -1,9 +1,9 @@
# required imports # required imports
from core.emulator.coreemu import CoreEmu from core.emulator.coreemu import CoreEmu
from core.emulator.data import IpPrefixes, NodeOptions from core.emulator.data import IpPrefixes
from core.emulator.enumerations import EventTypes from core.emulator.enumerations import EventTypes
from core.location.mobility import BasicRangeModel from core.location.mobility import BasicRangeModel
from core.nodes.base import CoreNode from core.nodes.base import CoreNode, Position
from core.nodes.network import WlanNode from core.nodes.network import WlanNode
# ip nerator for example # ip nerator for example
@ -17,14 +17,18 @@ session = coreemu.create_session()
session.set_state(EventTypes.CONFIGURATION_STATE) session.set_state(EventTypes.CONFIGURATION_STATE)
# create wlan # create wlan
options = NodeOptions(x=200, y=200) position = Position(x=200, y=200)
wlan = session.add_node(WlanNode, options=options) wlan = session.add_node(WlanNode, position=position)
# create nodes # create nodes
options = NodeOptions(model="mdr", x=100, y=100) options = CoreNode.create_options()
n1 = session.add_node(CoreNode, options=options) options.model = "mdr"
options = NodeOptions(model="mdr", x=300, y=100) position = Position(x=100, y=100)
n2 = session.add_node(CoreNode, options=options) n1 = session.add_node(CoreNode, position=position, options=options)
options = CoreNode.create_options()
options.model = "mdr"
position = Position(x=300, y=100)
n2 = session.add_node(CoreNode, position=position, options=options)
# configuring wlan # configuring wlan
session.mobility.set_model_config( session.mobility.set_model_config(

View file

@ -16,10 +16,10 @@ from core.emane.models.ieee80211abg import EmaneIeee80211abgModel
from core.emane.models.rfpipe import EmaneRfPipeModel from core.emane.models.rfpipe import EmaneRfPipeModel
from core.emane.models.tdma import EmaneTdmaModel from core.emane.models.tdma import EmaneTdmaModel
from core.emane.nodes import EmaneNet from core.emane.nodes import EmaneNet
from core.emulator.data import IpPrefixes, NodeOptions from core.emulator.data import IpPrefixes
from core.emulator.session import Session from core.emulator.session import Session
from core.errors import CoreCommandError, CoreError from core.errors import CoreCommandError, CoreError
from core.nodes.base import CoreNode from core.nodes.base import CoreNode, Position
_EMANE_MODELS = [ _EMANE_MODELS = [
EmaneIeee80211abgModel, EmaneIeee80211abgModel,
@ -53,19 +53,22 @@ class TestEmane:
""" """
# create emane node for networking the core nodes # create emane node for networking the core nodes
session.set_location(47.57917, -122.13232, 2.00000, 1.0) session.set_location(47.57917, -122.13232, 2.00000, 1.0)
options = NodeOptions() options = EmaneNet.create_options()
options.set_position(80, 50) options.emane_model = EmaneIeee80211abgModel.name
options.emane = EmaneIeee80211abgModel.name position = Position(x=80, y=50)
emane_net1 = session.add_node(EmaneNet, options=options) emane_net1 = session.add_node(EmaneNet, position=position, options=options)
options.emane = EmaneRfPipeModel.name options = EmaneNet.create_options()
emane_net2 = session.add_node(EmaneNet, options=options) options.emane_model = EmaneRfPipeModel.name
position = Position(x=80, y=50)
emane_net2 = session.add_node(EmaneNet, position=position, options=options)
# create nodes # create nodes
options = NodeOptions(model="mdr") options = CoreNode.create_options()
options.set_position(150, 150) options.model = "mdr"
node1 = session.add_node(CoreNode, options=options) position = Position(x=150, y=150)
options.set_position(300, 150) node1 = session.add_node(CoreNode, position=position, options=options)
node2 = session.add_node(CoreNode, options=options) position = Position(x=300, y=150)
node2 = session.add_node(CoreNode, position=position, options=options)
# create interfaces # create interfaces
ip_prefix1 = IpPrefixes("10.0.0.0/24") ip_prefix1 = IpPrefixes("10.0.0.0/24")
@ -100,9 +103,10 @@ class TestEmane:
# create emane node for networking the core nodes # create emane node for networking the core nodes
session.set_location(47.57917, -122.13232, 2.00000, 1.0) session.set_location(47.57917, -122.13232, 2.00000, 1.0)
options = NodeOptions(emane=model.name) options = EmaneNet.create_options()
options.set_position(80, 50) options.emane_model = model.name
emane_network = session.add_node(EmaneNet, options=options) position = Position(x=80, y=50)
emane_network = session.add_node(EmaneNet, position=position, options=options)
# configure tdma # configure tdma
if model == EmaneTdmaModel: if model == EmaneTdmaModel:
@ -111,11 +115,12 @@ class TestEmane:
) )
# create nodes # create nodes
options = NodeOptions(model="mdr") options = CoreNode.create_options()
options.set_position(150, 150) options.model = "mdr"
node1 = session.add_node(CoreNode, options=options) position = Position(x=150, y=150)
options.set_position(300, 150) node1 = session.add_node(CoreNode, position=position, options=options)
node2 = session.add_node(CoreNode, options=options) position = Position(x=300, y=150)
node2 = session.add_node(CoreNode, position=position, options=options)
for i, node in enumerate([node1, node2]): for i, node in enumerate([node1, node2]):
node.setposition(x=150 * (i + 1), y=150) node.setposition(x=150 * (i + 1), y=150)
@ -141,9 +146,10 @@ class TestEmane:
""" """
# create emane node for networking the core nodes # create emane node for networking the core nodes
session.set_location(47.57917, -122.13232, 2.00000, 1.0) session.set_location(47.57917, -122.13232, 2.00000, 1.0)
options = NodeOptions(emane=EmaneIeee80211abgModel.name) options = EmaneNet.create_options()
options.set_position(80, 50) options.emane_model = EmaneIeee80211abgModel.name
emane_network = session.add_node(EmaneNet, options=options) position = Position(x=80, y=50)
emane_network = session.add_node(EmaneNet, position=position, options=options)
config_key = "txpower" config_key = "txpower"
config_value = "10" config_value = "10"
session.emane.set_config( session.emane.set_config(
@ -151,11 +157,12 @@ class TestEmane:
) )
# create nodes # create nodes
options = NodeOptions(model="mdr") options = CoreNode.create_options()
options.set_position(150, 150) options.model = "mdr"
node1 = session.add_node(CoreNode, options=options) position = Position(x=150, y=150)
options.set_position(300, 150) node1 = session.add_node(CoreNode, position=position, options=options)
node2 = session.add_node(CoreNode, options=options) position = Position(x=300, y=150)
node2 = session.add_node(CoreNode, position=position, options=options)
for i, node in enumerate([node1, node2]): for i, node in enumerate([node1, node2]):
node.setposition(x=150 * (i + 1), y=150) node.setposition(x=150 * (i + 1), y=150)
@ -205,14 +212,17 @@ class TestEmane:
self, session: Session, tmpdir: TemporaryFile, ip_prefixes: IpPrefixes self, session: Session, tmpdir: TemporaryFile, ip_prefixes: IpPrefixes
): ):
# create nodes # create nodes
options = NodeOptions(model="mdr", x=50, y=50) options = CoreNode.create_options()
node1 = session.add_node(CoreNode, options=options) options.model = "mdr"
position = Position(x=50, y=50)
node1 = session.add_node(CoreNode, position=position, options=options)
iface1_data = ip_prefixes.create_iface(node1) iface1_data = ip_prefixes.create_iface(node1)
node2 = session.add_node(CoreNode, options=options) node2 = session.add_node(CoreNode, position=position, options=options)
iface2_data = ip_prefixes.create_iface(node2) iface2_data = ip_prefixes.create_iface(node2)
# create emane node # create emane node
options = NodeOptions(model=None, emane=EmaneRfPipeModel.name) options = EmaneNet.create_options()
options.emane_model = EmaneRfPipeModel.name
emane_node = session.add_node(EmaneNet, options=options) emane_node = session.add_node(EmaneNet, options=options)
# create links # create links
@ -255,11 +265,7 @@ class TestEmane:
assert session.get_node(node1.id, CoreNode) assert session.get_node(node1.id, CoreNode)
assert session.get_node(node2.id, CoreNode) assert session.get_node(node2.id, CoreNode)
assert session.get_node(emane_node.id, EmaneNet) assert session.get_node(emane_node.id, EmaneNet)
links = [] assert len(session.link_manager.links()) == 2
for node_id in session.nodes:
node = session.nodes[node_id]
links += node.links()
assert len(links) == 2
config = session.emane.get_config(node1.id, EmaneRfPipeModel.name) config = session.emane.get_config(node1.id, EmaneRfPipeModel.name)
assert config["datarate"] == datarate assert config["datarate"] == datarate
@ -267,14 +273,17 @@ class TestEmane:
self, session: Session, tmpdir: TemporaryFile, ip_prefixes: IpPrefixes self, session: Session, tmpdir: TemporaryFile, ip_prefixes: IpPrefixes
): ):
# create nodes # create nodes
options = NodeOptions(model="mdr", x=50, y=50) options = CoreNode.create_options()
node1 = session.add_node(CoreNode, options=options) options.model = "mdr"
position = Position(x=50, y=50)
node1 = session.add_node(CoreNode, position=position, options=options)
iface1_data = ip_prefixes.create_iface(node1) iface1_data = ip_prefixes.create_iface(node1)
node2 = session.add_node(CoreNode, options=options) node2 = session.add_node(CoreNode, position=position, options=options)
iface2_data = ip_prefixes.create_iface(node2) iface2_data = ip_prefixes.create_iface(node2)
# create emane node # create emane node
options = NodeOptions(model=None, emane=EmaneRfPipeModel.name) options = EmaneNet.create_options()
options.emane_model = EmaneRfPipeModel.name
emane_node = session.add_node(EmaneNet, options=options) emane_node = session.add_node(EmaneNet, options=options)
# create links # create links
@ -318,10 +327,6 @@ class TestEmane:
assert session.get_node(node1.id, CoreNode) assert session.get_node(node1.id, CoreNode)
assert session.get_node(node2.id, CoreNode) assert session.get_node(node2.id, CoreNode)
assert session.get_node(emane_node.id, EmaneNet) assert session.get_node(emane_node.id, EmaneNet)
links = [] assert len(session.link_manager.links()) == 2
for node_id in session.nodes:
node = session.nodes[node_id]
links += node.links()
assert len(links) == 2
config = session.emane.get_config(config_id, EmaneRfPipeModel.name) config = session.emane.get_config(config_id, EmaneRfPipeModel.name)
assert config["datarate"] == datarate assert config["datarate"] == datarate

View file

@ -8,7 +8,7 @@ from typing import List, Type
import pytest import pytest
from core.emulator.data import IpPrefixes, NodeOptions from core.emulator.data import IpPrefixes
from core.emulator.session import Session from core.emulator.session import Session
from core.errors import CoreCommandError from core.errors import CoreCommandError
from core.location.mobility import BasicRangeModel, Ns2ScriptedMobility from core.location.mobility import BasicRangeModel, Ns2ScriptedMobility
@ -75,8 +75,8 @@ class TestCore:
session.mobility.set_model(wlan_node, BasicRangeModel) session.mobility.set_model(wlan_node, BasicRangeModel)
# create nodes # create nodes
options = NodeOptions(model="mdr") options = CoreNode.create_options()
options.set_position(0, 0) options.model = "mdr"
node1 = session.add_node(CoreNode, options=options) node1 = session.add_node(CoreNode, options=options)
node2 = session.add_node(CoreNode, options=options) node2 = session.add_node(CoreNode, options=options)
@ -105,8 +105,8 @@ class TestCore:
session.mobility.set_model(wlan_node, BasicRangeModel) session.mobility.set_model(wlan_node, BasicRangeModel)
# create nodes # create nodes
options = NodeOptions(model="mdr") options = CoreNode.create_options()
options.set_position(0, 0) options.model = "mdr"
node1 = session.add_node(CoreNode, options=options) node1 = session.add_node(CoreNode, options=options)
node2 = session.add_node(CoreNode, options=options) node2 = session.add_node(CoreNode, options=options)

View file

@ -1,4 +1,3 @@
from core.emulator.data import NodeOptions
from core.emulator.session import Session from core.emulator.session import Session
from core.nodes.base import CoreNode from core.nodes.base import CoreNode
from core.nodes.network import HubNode from core.nodes.network import HubNode
@ -12,8 +11,7 @@ class TestDistributed:
# when # when
session.distributed.add_server(server_name, host) session.distributed.add_server(server_name, host)
options = NodeOptions(server=server_name) node = session.add_node(CoreNode, server=server_name)
node = session.add_node(CoreNode, options=options)
session.instantiate() session.instantiate()
# then # then
@ -30,8 +28,7 @@ class TestDistributed:
# when # when
session.distributed.add_server(server_name, host) session.distributed.add_server(server_name, host)
node1 = session.add_node(HubNode) node1 = session.add_node(HubNode)
options = NodeOptions(server=server_name) node2 = session.add_node(HubNode, server=server_name)
node2 = session.add_node(HubNode, options=options)
session.add_link(node1.id, node2.id) session.add_link(node1.id, node2.id)
session.instantiate() session.instantiate()

View file

@ -34,7 +34,7 @@ from core.api.grpc.wrappers import (
) )
from core.emane.models.ieee80211abg import EmaneIeee80211abgModel from core.emane.models.ieee80211abg import EmaneIeee80211abgModel
from core.emane.nodes import EmaneNet from core.emane.nodes import EmaneNet
from core.emulator.data import EventData, IpPrefixes, NodeData, NodeOptions from core.emulator.data import EventData, IpPrefixes, NodeData
from core.emulator.enumerations import EventTypes, ExceptionLevels, MessageFlags from core.emulator.enumerations import EventTypes, ExceptionLevels, MessageFlags
from core.errors import CoreError from core.errors import CoreError
from core.location.mobility import BasicRangeModel, Ns2ScriptedMobility from core.location.mobility import BasicRangeModel, Ns2ScriptedMobility
@ -350,8 +350,7 @@ class TestGrpc:
client = CoreGrpcClient() client = CoreGrpcClient()
session = grpc_server.coreemu.create_session() session = grpc_server.coreemu.create_session()
session.set_state(EventTypes.CONFIGURATION_STATE) session.set_state(EventTypes.CONFIGURATION_STATE)
options = NodeOptions(model="Host") node = session.add_node(CoreNode)
node = session.add_node(CoreNode, options=options)
session.instantiate() session.instantiate()
expected_output = "hello world" expected_output = "hello world"
expected_status = 0 expected_status = 0
@ -369,8 +368,7 @@ class TestGrpc:
client = CoreGrpcClient() client = CoreGrpcClient()
session = grpc_server.coreemu.create_session() session = grpc_server.coreemu.create_session()
session.set_state(EventTypes.CONFIGURATION_STATE) session.set_state(EventTypes.CONFIGURATION_STATE)
options = NodeOptions(model="Host") node = session.add_node(CoreNode)
node = session.add_node(CoreNode, options=options)
session.instantiate() session.instantiate()
# then # then
@ -444,10 +442,12 @@ class TestGrpc:
# given # given
client = CoreGrpcClient() client = CoreGrpcClient()
session = grpc_server.coreemu.create_session() session = grpc_server.coreemu.create_session()
session.set_state(EventTypes.CONFIGURATION_STATE)
switch = session.add_node(SwitchNode) switch = session.add_node(SwitchNode)
node = session.add_node(CoreNode) node = session.add_node(CoreNode)
iface_data = ip_prefixes.create_iface(node) iface_data = ip_prefixes.create_iface(node)
iface, _ = session.add_link(node.id, switch.id, iface_data) iface, _ = session.add_link(node.id, switch.id, iface_data)
session.instantiate()
options = LinkOptions(bandwidth=30000) options = LinkOptions(bandwidth=30000)
assert iface.options.bandwidth != options.bandwidth assert iface.options.bandwidth != options.bandwidth
link = Link(node.id, switch.id, iface1=Interface(id=iface.id), options=options) link = Link(node.id, switch.id, iface1=Interface(id=iface.id), options=options)
@ -535,7 +535,8 @@ class TestGrpc:
client = CoreGrpcClient() client = CoreGrpcClient()
session = grpc_server.coreemu.create_session() session = grpc_server.coreemu.create_session()
session.set_location(47.57917, -122.13232, 2.00000, 1.0) session.set_location(47.57917, -122.13232, 2.00000, 1.0)
options = NodeOptions(emane=EmaneIeee80211abgModel.name) options = EmaneNet.create_options()
options.emane_model = EmaneIeee80211abgModel.name
emane_network = session.add_node(EmaneNet, options=options) emane_network = session.add_node(EmaneNet, options=options)
session.emane.node_models[emane_network.id] = EmaneIeee80211abgModel.name session.emane.node_models[emane_network.id] = EmaneIeee80211abgModel.name
config_key = "bandwidth" config_key = "bandwidth"
@ -565,7 +566,8 @@ class TestGrpc:
client = CoreGrpcClient() client = CoreGrpcClient()
session = grpc_server.coreemu.create_session() session = grpc_server.coreemu.create_session()
session.set_location(47.57917, -122.13232, 2.00000, 1.0) session.set_location(47.57917, -122.13232, 2.00000, 1.0)
options = NodeOptions(emane=EmaneIeee80211abgModel.name) options = EmaneNet.create_options()
options.emane_model = EmaneIeee80211abgModel.name
emane_network = session.add_node(EmaneNet, options=options) emane_network = session.add_node(EmaneNet, options=options)
session.emane.node_models[emane_network.id] = EmaneIeee80211abgModel.name session.emane.node_models[emane_network.id] = EmaneIeee80211abgModel.name
@ -685,7 +687,8 @@ class TestGrpc:
# given # given
client = CoreGrpcClient() client = CoreGrpcClient()
session = grpc_server.coreemu.create_session() session = grpc_server.coreemu.create_session()
options = NodeOptions(legacy=True) options = CoreNode.create_options()
options.legacy = True
node = session.add_node(CoreNode, options=options) node = session.add_node(CoreNode, options=options)
service_name = "DefaultRoute" service_name = "DefaultRoute"
@ -932,6 +935,7 @@ class TestGrpc:
# given # given
client = CoreGrpcClient() client = CoreGrpcClient()
session = grpc_server.coreemu.create_session() session = grpc_server.coreemu.create_session()
session.set_state(EventTypes.CONFIGURATION_STATE)
wlan = session.add_node(WlanNode) wlan = session.add_node(WlanNode)
node1 = session.add_node(CoreNode) node1 = session.add_node(CoreNode)
node2 = session.add_node(CoreNode) node2 = session.add_node(CoreNode)

View file

@ -1,6 +1,6 @@
import pytest import pytest
from core.emulator.data import InterfaceData, NodeOptions from core.emulator.data import InterfaceData
from core.emulator.session import Session from core.emulator.session import Session
from core.errors import CoreError from core.errors import CoreError
from core.nodes.base import CoreNode from core.nodes.base import CoreNode
@ -14,7 +14,8 @@ class TestNodes:
@pytest.mark.parametrize("model", MODELS) @pytest.mark.parametrize("model", MODELS)
def test_node_add(self, session: Session, model: str): def test_node_add(self, session: Session, model: str):
# given # given
options = NodeOptions(model=model) options = CoreNode.create_options()
options.model = model
# when # when
node = session.add_node(CoreNode, options=options) node = session.add_node(CoreNode, options=options)

View file

@ -4,7 +4,7 @@ from xml.etree import ElementTree
import pytest import pytest
from core.emulator.data import IpPrefixes, LinkOptions, NodeOptions from core.emulator.data import IpPrefixes, LinkOptions
from core.emulator.enumerations import EventTypes from core.emulator.enumerations import EventTypes
from core.emulator.session import Session from core.emulator.session import Session
from core.errors import CoreError from core.errors import CoreError
@ -116,8 +116,7 @@ class TestXml:
:param ip_prefixes: generates ip addresses for nodes :param ip_prefixes: generates ip addresses for nodes
""" """
# create nodes # create nodes
options = NodeOptions(model="host") node1 = session.add_node(CoreNode)
node1 = session.add_node(CoreNode, options=options)
node2 = session.add_node(CoreNode) node2 = session.add_node(CoreNode)
# link nodes to ptp net # link nodes to ptp net
@ -180,8 +179,8 @@ class TestXml:
session.mobility.set_model(wlan, BasicRangeModel, {"test": "1"}) session.mobility.set_model(wlan, BasicRangeModel, {"test": "1"})
# create nodes # create nodes
options = NodeOptions(model="mdr") options = CoreNode.create_options()
options.set_position(0, 0) options.model = "mdr"
node1 = session.add_node(CoreNode, options=options) node1 = session.add_node(CoreNode, options=options)
node2 = session.add_node(CoreNode, options=options) node2 = session.add_node(CoreNode, options=options)

View file

@ -1,7 +1,7 @@
# Python API # Python API
* Table of Contents * Table of Contents
{:toc} {:toc}
## Overview ## Overview
@ -21,13 +21,13 @@ When creating nodes of type `core.nodes.base.CoreNode` these are the default mod
and the services they map to. and the services they map to.
* mdr * mdr
* zebra, OSPFv3MDR, IPForward * zebra, OSPFv3MDR, IPForward
* PC * PC
* DefaultRoute * DefaultRoute
* router * router
* zebra, OSPFv2, OSPFv3, IPForward * zebra, OSPFv2, OSPFv3, IPForward
* host * host
* DefaultRoute, SSH * DefaultRoute, SSH
### Interface Helper ### Interface Helper
@ -36,8 +36,10 @@ when creating interface data for nodes. Alternatively one can manually create
a `core.emulator.data.InterfaceData` class instead with appropriate information. a `core.emulator.data.InterfaceData` class instead with appropriate information.
Manually creating interface data: Manually creating interface data:
```python ```python
from core.emulator.data import InterfaceData from core.emulator.data import InterfaceData
# id is optional and will set to the next available id # id is optional and will set to the next available id
# name is optional and will default to eth<id> # name is optional and will default to eth<id>
# mac is optional and will result in a randomly generated mac # mac is optional and will result in a randomly generated mac
@ -52,6 +54,7 @@ iface_data = InterfaceData(
``` ```
Leveraging the interface prefixes helper class: Leveraging the interface prefixes helper class:
```python ```python
from core.emulator.data import IpPrefixes from core.emulator.data import IpPrefixes
@ -69,6 +72,7 @@ iface_data = ip_prefixes.create_iface(
Various events that can occur within a session can be listened to. Various events that can occur within a session can be listened to.
Event types: Event types:
* session - events for changes in session state and mobility start/stop/pause * session - events for changes in session state and mobility start/stop/pause
* node - events for node movements and icon changes * node - events for node movements and icon changes
* link - events for link configuration changes and wireless link add/delete * link - events for link configuration changes and wireless link add/delete
@ -80,6 +84,7 @@ Event types:
def event_listener(event): def event_listener(event):
print(event) print(event)
# add an event listener to event type you want to listen to # add an event listener to event type you want to listen to
# each handler will receive an object unique to that type # each handler will receive an object unique to that type
session.event_handlers.append(event_listener) session.event_handlers.append(event_listener)
@ -95,6 +100,7 @@ session.config_handlers.append(event_listener)
Links can be configured at the time of creation or during runtime. Links can be configured at the time of creation or during runtime.
Currently supported configuration options: Currently supported configuration options:
* bandwidth (bps) * bandwidth (bps)
* delay (us) * delay (us)
* dup (%) * dup (%)
@ -119,12 +125,13 @@ session.update_link(n1_id, n2_id, iface1_id, iface2_id, options)
``` ```
### Peer to Peer Example ### Peer to Peer Example
```python ```python
# required imports # required imports
from core.emulator.coreemu import CoreEmu from core.emulator.coreemu import CoreEmu
from core.emulator.data import IpPrefixes, NodeOptions from core.emulator.data import IpPrefixes
from core.emulator.enumerations import EventTypes from core.emulator.enumerations import EventTypes
from core.nodes.base import CoreNode from core.nodes.base import CoreNode, Position
# ip nerator for example # ip nerator for example
ip_prefixes = IpPrefixes(ip4_prefix="10.0.0.0/24") ip_prefixes = IpPrefixes(ip4_prefix="10.0.0.0/24")
@ -137,10 +144,10 @@ session = coreemu.create_session()
session.set_state(EventTypes.CONFIGURATION_STATE) session.set_state(EventTypes.CONFIGURATION_STATE)
# create nodes # create nodes
options = NodeOptions(x=100, y=100) position = Position(x=100, y=100)
n1 = session.add_node(CoreNode, options=options) n1 = session.add_node(CoreNode, position=position)
options = NodeOptions(x=300, y=100) position = Position(x=300, y=100)
n2 = session.add_node(CoreNode, options=options) n2 = session.add_node(CoreNode, position=position)
# link nodes together # link nodes together
iface1 = ip_prefixes.create_iface(n1) iface1 = ip_prefixes.create_iface(n1)
@ -158,12 +165,13 @@ session.shutdown()
``` ```
### Switch/Hub Example ### Switch/Hub Example
```python ```python
# required imports # required imports
from core.emulator.coreemu import CoreEmu from core.emulator.coreemu import CoreEmu
from core.emulator.data import IpPrefixes, NodeOptions from core.emulator.data import IpPrefixes
from core.emulator.enumerations import EventTypes from core.emulator.enumerations import EventTypes
from core.nodes.base import CoreNode from core.nodes.base import CoreNode, Position
from core.nodes.network import SwitchNode from core.nodes.network import SwitchNode
# ip nerator for example # ip nerator for example
@ -177,14 +185,14 @@ session = coreemu.create_session()
session.set_state(EventTypes.CONFIGURATION_STATE) session.set_state(EventTypes.CONFIGURATION_STATE)
# create switch # create switch
options = NodeOptions(x=200, y=200) position = Position(x=200, y=200)
switch = session.add_node(SwitchNode, options=options) switch = session.add_node(SwitchNode, position=position)
# create nodes # create nodes
options = NodeOptions(x=100, y=100) position = Position(x=100, y=100)
n1 = session.add_node(CoreNode, options=options) n1 = session.add_node(CoreNode, position=position)
options = NodeOptions(x=300, y=100) position = Position(x=300, y=100)
n2 = session.add_node(CoreNode, options=options) n2 = session.add_node(CoreNode, position=position)
# link nodes to switch # link nodes to switch
iface1 = ip_prefixes.create_iface(n1) iface1 = ip_prefixes.create_iface(n1)
@ -203,13 +211,14 @@ session.shutdown()
``` ```
### WLAN Example ### WLAN Example
```python ```python
# required imports # required imports
from core.emulator.coreemu import CoreEmu from core.emulator.coreemu import CoreEmu
from core.emulator.data import IpPrefixes, NodeOptions from core.emulator.data import IpPrefixes
from core.emulator.enumerations import EventTypes from core.emulator.enumerations import EventTypes
from core.location.mobility import BasicRangeModel from core.location.mobility import BasicRangeModel
from core.nodes.base import CoreNode from core.nodes.base import CoreNode, Position
from core.nodes.network import WlanNode from core.nodes.network import WlanNode
# ip nerator for example # ip nerator for example
@ -223,14 +232,16 @@ session = coreemu.create_session()
session.set_state(EventTypes.CONFIGURATION_STATE) session.set_state(EventTypes.CONFIGURATION_STATE)
# create wlan # create wlan
options = NodeOptions(x=200, y=200) position = Position(x=200, y=200)
wlan = session.add_node(WlanNode, options=options) wlan = session.add_node(WlanNode, position=position)
# create nodes # create nodes
options = NodeOptions(model="mdr", x=100, y=100) options = CoreNode.create_options()
n1 = session.add_node(CoreNode, options=options) options.model = "mdr"
options = NodeOptions(model="mdr", x=300, y=100) position = Position(x=100, y=100)
n2 = session.add_node(CoreNode, options=options) n1 = session.add_node(CoreNode, position=position, options=options)
position = Position(x=300, y=100)
n2 = session.add_node(CoreNode, position=position, options=options)
# configuring wlan # configuring wlan
session.mobility.set_model_config(wlan.id, BasicRangeModel.name, { session.mobility.set_model_config(wlan.id, BasicRangeModel.name, {
@ -263,6 +274,7 @@ For EMANE you can import and use one of the existing models and
use its name for configuration. use its name for configuration.
Current models: Current models:
* core.emane.ieee80211abg.EmaneIeee80211abgModel * core.emane.ieee80211abg.EmaneIeee80211abgModel
* core.emane.rfpipe.EmaneRfPipeModel * core.emane.rfpipe.EmaneRfPipeModel
* core.emane.tdma.EmaneTdmaModel * core.emane.tdma.EmaneTdmaModel
@ -281,9 +293,9 @@ will use the defaults. When no configuration is used, the defaults are used.
from core.emane.models.ieee80211abg import EmaneIeee80211abgModel from core.emane.models.ieee80211abg import EmaneIeee80211abgModel
from core.emane.nodes import EmaneNet from core.emane.nodes import EmaneNet
from core.emulator.coreemu import CoreEmu from core.emulator.coreemu import CoreEmu
from core.emulator.data import IpPrefixes, NodeOptions from core.emulator.data import IpPrefixes
from core.emulator.enumerations import EventTypes from core.emulator.enumerations import EventTypes
from core.nodes.base import CoreNode from core.nodes.base import CoreNode, Position
# ip nerator for example # ip nerator for example
ip_prefixes = IpPrefixes(ip4_prefix="10.0.0.0/24") ip_prefixes = IpPrefixes(ip4_prefix="10.0.0.0/24")
@ -300,25 +312,29 @@ session.location.refscale = 150.0
session.set_state(EventTypes.CONFIGURATION_STATE) session.set_state(EventTypes.CONFIGURATION_STATE)
# create emane # create emane
options = NodeOptions(x=200, y=200, emane=EmaneIeee80211abgModel.name) options = EmaneNet.create_options()
emane = session.add_node(EmaneNet, options=options) options.emane_model = EmaneIeee80211abgModel.name
position = Position(x=200, y=200)
emane = session.add_node(EmaneNet, position=position, options=options)
# create nodes # create nodes
options = NodeOptions(model="mdr", x=100, y=100) options = CoreNode.create_options()
n1 = session.add_node(CoreNode, options=options) options.model = "mdr"
options = NodeOptions(model="mdr", x=300, y=100) position = Position(x=100, y=100)
n2 = session.add_node(CoreNode, options=options) n1 = session.add_node(CoreNode, position=position, options=options)
position = Position(x=300, y=100)
n2 = session.add_node(CoreNode, position=position, options=options)
# configure general emane settings # configure general emane settings
config = session.emane.get_configs() config = session.emane.get_configs()
config.update({ config.update({
"eventservicettl": "2" "eventservicettl": "2"
}) })
# configure emane model settings # configure emane model settings
# using a dict mapping currently support values as strings # using a dict mapping currently support values as strings
session.emane.set_model_config(emane.id, EmaneIeee80211abgModel.name, { session.emane.set_model_config(emane.id, EmaneIeee80211abgModel.name, {
"unicastrate": "3", "unicastrate": "3",
}) })
# link nodes to emane # link nodes to emane
@ -338,6 +354,7 @@ session.shutdown()
``` ```
EMANE Model Configuration: EMANE Model Configuration:
```python ```python
from core import utils from core import utils
@ -358,6 +375,7 @@ Configuring the files of a service results in a specific hard coded script being
generated, instead of the default scripts, that may leverage dynamic generation. generated, instead of the default scripts, that may leverage dynamic generation.
The following features can be configured for a service: The following features can be configured for a service:
* configs - files that will be generated * configs - files that will be generated
* dirs - directories that will be mounted unique to the node * dirs - directories that will be mounted unique to the node
* startup - commands to run start a service * startup - commands to run start a service
@ -365,6 +383,7 @@ The following features can be configured for a service:
* shutdown - commands to run to stop a service * shutdown - commands to run to stop a service
Editing service properties: Editing service properties:
```python ```python
# configure a service, for a node, for a given session # configure a service, for a node, for a given session
session.services.set_service(node_id, service_name) session.services.set_service(node_id, service_name)
@ -380,6 +399,7 @@ When editing a service file, it must be the name of `config`
file that the service will generate. file that the service will generate.
Editing a service file: Editing a service file:
```python ```python
# to edit the contents of a generated file you can specify # to edit the contents of a generated file you can specify
# the service, the file name, and its contents # the service, the file name, and its contents
@ -397,10 +417,12 @@ File versions of the network examples can be found
[here](https://github.com/coreemu/core/tree/master/daemon/examples/python). [here](https://github.com/coreemu/core/tree/master/daemon/examples/python).
## Executing Scripts from GUI ## Executing Scripts from GUI
To execute a python script from a GUI you need have the following. To execute a python script from a GUI you need have the following.
The builtin name check here to know it is being executed from the GUI, this can The builtin name check here to know it is being executed from the GUI, this can
be avoided if your script does not use a name check. be avoided if your script does not use a name check.
```python ```python
if __name__ in ["__main__", "__builtin__"]: if __name__ in ["__main__", "__builtin__"]:
main() main()